diff options
Diffstat (limited to 'drivers/net/wireless')
44 files changed, 23374 insertions, 0 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 4de4410cd38..b4338f38939 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -279,6 +279,7 @@ source "drivers/net/wireless/libertas/Kconfig"  source "drivers/net/wireless/orinoco/Kconfig"  source "drivers/net/wireless/p54/Kconfig"  source "drivers/net/wireless/rt2x00/Kconfig" +source "drivers/net/wireless/rtlwifi/Kconfig"  source "drivers/net/wireless/wl1251/Kconfig"  source "drivers/net/wireless/wl12xx/Kconfig"  source "drivers/net/wireless/zd1211rw/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 06f8ca26c5c..9760561a27a 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_B43LEGACY)		+= b43legacy/  obj-$(CONFIG_ZD1211RW)		+= zd1211rw/  obj-$(CONFIG_RTL8180)		+= rtl818x/  obj-$(CONFIG_RTL8187)		+= rtl818x/ +obj-$(CONFIG_RTL8192CE)		+= rtlwifi/  # 16-bit wireless PCMCIA client drivers  obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig new file mode 100644 index 00000000000..d712026eb76 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -0,0 +1,15 @@ +config RTL8192CE +	tristate "Realtek RTL8192CE/RTL8188SE Wireless Network Adapter" +	depends on MAC80211 && EXPERIMENTAL +	select FW_LOADER +	select RTLWIFI +	---help--- +	This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe +	wireless network adapters. + +	If you choose to build it as a module, it will be calledrtl8192ce. + +config RTLWIFI +	tristate +	depends on RTL8192CE +	default m diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile new file mode 100644 index 00000000000..2a7a4384f8e --- /dev/null +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -0,0 +1,13 @@ +obj-$(CONFIG_RTLWIFI) 		+= rtlwifi.o +rtlwifi-objs	:=		\ +		base.o		\ +		cam.o		\ +		core.o		\ +		debug.o		\ +		efuse.o		\ +		pci.o		\ +		ps.o		\ +		rc.o		\ +		regd.o + +obj-$(CONFIG_RTL8192CE)		+= rtl8192ce/ diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c new file mode 100644 index 00000000000..9e860ff30b5 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/base.c @@ -0,0 +1,958 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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 "wifi.h" +#include "rc.h" +#include "base.h" +#include "efuse.h" +#include "cam.h" +#include "ps.h" +#include "regd.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) sysfs functions + *7) ... + */ + +/********************************************************* + * + * mac80211 init functions + * + *********************************************************/ +static struct ieee80211_channel rtl_channeltable[] = { +	{.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_rate rtl_ratetable[] = { +	{.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 const struct ieee80211_supported_band rtl_band_2ghz = { +	.band = IEEE80211_BAND_2GHZ, + +	.channels = rtl_channeltable, +	.n_channels = ARRAY_SIZE(rtl_channeltable), + +	.bitrates = rtl_ratetable, +	.n_bitrates = ARRAY_SIZE(rtl_ratetable), + +	.ht_cap = {0}, +}; + +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; + +	/* +	 *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 (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_2T2R) { + +		RT_TRACE(rtlpriv, 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 = MAX_BIT_RATE_40MHZ_MCS15; +	} else if (get_rf_type(rtlphy) == RF_1T1R) { + +		RT_TRACE(rtlpriv, 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 = MAX_BIT_RATE_40MHZ_MCS7; +	} +} + +static void _rtl_init_mac80211(struct ieee80211_hw *hw) +{ +	struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct ieee80211_supported_band *sband; + +	/* <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; + +	/* <5> set hw caps */ +	hw->flags = IEEE80211_HW_SIGNAL_DBM | +	    IEEE80211_HW_RX_INCLUDES_FCS | +	    IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | /*PS*/ +	    /*IEEE80211_HW_SUPPORTS_PS | */ +	    /*IEEE80211_HW_PS_NULLFUNC_STACK | */ +	    /*IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ +	    IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0; + +	hw->wiphy->interface_modes = +	    BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + +	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; +	hw->max_listen_interval = 5; +	hw->max_rate_tries = 4; +	/* hw->max_rates = 1; */ + +	/* <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, +		    rtl_watch_dog_timer_callback, (unsigned long)hw); + +	/* <2> work queue */ +	rtlpriv->works.hw = hw; +	rtlpriv->works.rtl_wq = create_workqueue(rtlpriv->cfg->name); +	INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq, +			  (void *)rtl_watchdog_wq_callback); +	INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, +			  (void *)rtl_ips_nic_off_wq_callback); + +} + +void rtl_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); +} + +void rtl_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 rf on */ +	rtlpriv->rfkill.rfkill_state = 1; + +	radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid); + +	if (valid) { +		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +			 (KERN_INFO "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 rtl_deinit_rfkill(struct ieee80211_hw *hw) +{ +	wiphy_rfkill_stop_polling(hw->wiphy); +} + +int rtl_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; + +	/* <2> rate control register */ +	if (rtl_rate_control_register()) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("rtl: Unable to register rtl_rc," +			  "use default RC !!\n")); +	} else { +		hw->rate_control_algorithm = "rtl_rc"; +	} + +	/* +	 * <3> init CRDA must come after init +	 * mac80211 hw  in _rtl_init_mac80211. +	 */ +	if (rtl_regd_init(hw, rtl_reg_notifier)) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("REGD init failed\n")); +		return 1; +	} else { +		/* CRDA regd hint must after init CRDA */ +		if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2)) { +			RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +				 ("regulatory_hint fail\n")); +		} +	} + +	/* <4> locks */ +	sema_init(&rtlpriv->locks.ips_sem, 1); +	sema_init(&rtlpriv->locks.conf_sem, 1); +	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); + +	rtlmac->link_state = MAC80211_NOLINK; + +	/* <5> init deferred work */ +	_rtl_init_deferred_work(hw); + +	return 0; +} + +void rtl_deinit_core(struct ieee80211_hw *hw) +{ +	 /*RC*/ +	rtl_rate_control_unregister(); +} + +void rtl_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)); +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MGT_FILTER, +				      (u8 *) (&mac->rx_mgt_filter)); +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CTRL_FILTER, +				      (u8 *) (&mac->rx_ctrl_filter)); +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_DATA_FILTER, +				      (u8 *) (&mac->rx_data_filter)); +} + +/********************************************************* + * + * 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 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; + +	tcb_desc->use_shortgi = false; + +	if (!mac->ht_enable) +		return; + +	if (!mac->sgi_40 && !mac->sgi_20) +		return; + +	if ((mac->bw_40 == true) && mac->sgi_40) +		tcb_desc->use_shortgi = true; +	else if ((mac->bw_40 == false) && mac->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 rtl_tcb_desc *tcb_desc) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	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) { +			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; +			} else { +				/* TODO */ +			} +		} +	} + +	if (rtlpriv->dm.b_useramask) { +		/* TODO we will differentiate adhoc and station futrue  */ +		tcb_desc->mac_id = 0; + +		if ((mac->mode == WIRELESS_MODE_N_24G) || +		    (mac->mode == WIRELESS_MODE_N_5G)) { +			tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; +		} 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; +		} +	} + +} + +static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, +				      struct rtl_tcb_desc *tcb_desc) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	tcb_desc->b_packet_bw = false; + +	if (!mac->bw_40 || !mac->ht_enable) +		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->b_packet_bw = true; +} + +static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 hw_rate; + +	if (get_rf_type(rtlphy) == RF_2T2R) +		hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15]; +	else +		hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7]; + +	return hw_rate; +} + +void rtl_get_tcb_desc(struct ieee80211_hw *hw, +		      struct ieee80211_tx_info *info, +		      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 = (struct ieee80211_hdr *)(skb->data); +	struct ieee80211_rate *txrate; +	u16 fc = le16_to_cpu(hdr->frame_control); + +	memset(tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + +	if (ieee80211_is_data(fc)) { +		txrate = ieee80211_get_tx_rate(hw, info); +		tcb_desc->hw_rate = txrate->hw_value; + +		/* +		 *we set data rate RTL_RC_CCK_RATE1M +		 *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 (tcb_desc->hw_rate < rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]) { +			tcb_desc->use_driver_rate = true; +			tcb_desc->ratr_index = 7; + +			tcb_desc->hw_rate = +			    rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; +			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 (rtlmac->ht_enable) { +				tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw); +			} 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, tcb_desc); +		_rtl_query_bandwidth_mode(hw, tcb_desc); +		_rtl_qurey_shortpreamble_mode(hw, tcb_desc, info); +		_rtl_query_shortgi(hw, tcb_desc, info); +		_rtl_query_protection_mode(hw, tcb_desc, info); +	} else { +		tcb_desc->use_driver_rate = true; +		tcb_desc->ratr_index = 7; +		tcb_desc->disable_ratefallback = 1; +		tcb_desc->mac_id = 0; + +		tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; +	} +} +EXPORT_SYMBOL(rtl_get_tcb_desc); + +bool rtl_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); +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); +	u16 fc = le16_to_cpu(hdr->frame_control); + +	if (ieee80211_is_auth(fc)) { +		RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); +		rtl_ips_nic_on(hw); + +		mac->link_state = MAC80211_LINKING; +	} + +	return true; +} + +bool rtl_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 = (struct ieee80211_hdr *)(skb->data); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u16 fc = le16_to_cpu(hdr->frame_control); +	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(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, +				 ("%s ACT_ADDBAREQ From :" MAC_FMT "\n", +				  is_tx ? "Tx" : "Rx", MAC_ARG(hdr->addr2))); +			break; +		case ACT_ADDBARSP: +			RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, +				 ("%s ACT_ADDBARSP From :" MAC_FMT "\n", +				  is_tx ? "Tx" : "Rx", MAC_ARG(hdr->addr2))); +			break; +		case ACT_DELBA: +			RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, +				 ("ACT_ADDBADEL From :" MAC_FMT "\n", +				  MAC_ARG(hdr->addr2))); +			break; +		} +		break; +	default: +		break; +	} + +	return true; +} + +/*should call before software enc*/ +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	u16 fc = le16_to_cpu(hdr->frame_control); +	u16 ether_type; +	u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); +	const struct iphdr *ip; + +	if (!ieee80211_is_data(fc)) +		goto end; + +	if (ieee80211_is_nullfunc(fc)) +		return true; + +	ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len + +			      SNAP_SIZE + PROTOC_TYPE_SIZE); +	ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE); +	ether_type = ntohs(ether_type); + +	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(rtlpriv, (COMP_SEND | COMP_RECV), +					 DBG_DMESG, ("dhcp %s !!\n", +						     (is_tx) ? "Tx" : "Rx")); + +				if (is_tx) { +					rtl_lps_leave(hw); +					ppsc->last_delaylps_stamp_jiffies = +					    jiffies; +				} + +				return true; +			} +		} +	} else if (ETH_P_ARP == ether_type) { +		if (is_tx) { +			rtl_lps_leave(hw); +			ppsc->last_delaylps_stamp_jiffies = jiffies; +		} + +		return true; +	} else if (ETH_P_PAE == ether_type) { +		RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, +			 ("802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx")); + +		if (is_tx) { +			rtl_lps_leave(hw); +			ppsc->last_delaylps_stamp_jiffies = jiffies; +		} + +		return true; +	} else if (0x86DD == ether_type) { +		return true; +	} + +end: +	return false; +} + +/********************************************************* + * + * functions called by core.c + * + *********************************************************/ +int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, u16 tid, u16 *ssn) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_tid_data *tid_data; +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, +		 ("on ra = %pM tid = %d\n", ra, tid)); + +	if (unlikely(tid >= MAX_TID_COUNT)) +		return -EINVAL; + +	if (mac->tids[tid].agg.agg_state != RTL_AGG_OFF) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("Start AGG when state is not RTL_AGG_OFF !\n")); +		return -ENXIO; +	} + +	tid_data = &mac->tids[tid]; +	*ssn = SEQ_TO_SN(tid_data->seq_number); + +	RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, +		 ("HW queue is empty tid:%d\n", tid)); +	tid_data->agg.agg_state = RTL_AGG_ON; + +	ieee80211_start_tx_ba_cb_irqsafe(mac->vif, ra, tid); + +	return 0; +} + +int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 * ra, u16 tid) +{ +	int ssn = -1; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_tid_data *tid_data; + +	if (!ra) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n")); +		return -EINVAL; +	} + +	if (unlikely(tid >= MAX_TID_COUNT)) +		return -EINVAL; + +	if (mac->tids[tid].agg.agg_state != RTL_AGG_ON) +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("Stopping AGG while state not ON or starting\n")); + +	tid_data = &mac->tids[tid]; +	ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; + +	mac->tids[tid].agg.agg_state = RTL_AGG_OFF; + +	ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, ra, tid); + +	return 0; +} + +/********************************************************* + * + * wq & timer callback functions + * + *********************************************************/ +void rtl_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_higher_busytraffic = false; +	bool b_higher_busyrxtraffic = false; +	bool b_higher_busytxtraffic = false; + +	u8 idx = 0; +	u32 rx_cnt_inp4eriod = 0; +	u32 tx_cnt_inp4eriod = 0; +	u32 aver_rx_cnt_inperiod = 0; +	u32 aver_tx_cnt_inperiod = 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> DM */ +	rtlpriv->cfg->ops->dm_watchdog(hw); + +	/* +	 *<3> 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; + +		/* 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; +			else +				b_higher_busytxtraffic = 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) +			rtl_lps_enter(hw); +		else +			rtl_lps_leave(hw); +	} + +	rtlpriv->link_info.num_rx_inperiod = 0; +	rtlpriv->link_info.num_tx_inperiod = 0; + +	rtlpriv->link_info.b_busytraffic = b_busytraffic; +	rtlpriv->link_info.b_higher_busytraffic = b_higher_busytraffic; +	rtlpriv->link_info.b_higher_busyrxtraffic = b_higher_busyrxtraffic; + +} + +void rtl_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)); +} + +/********************************************************* + * + * sysfs functions + * + *********************************************************/ +static ssize_t rtl_show_debug_level(struct device *d, +				    struct device_attribute *attr, char *buf) +{ +	struct ieee80211_hw *hw = dev_get_drvdata(d); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	return sprintf(buf, "0x%08X\n", rtlpriv->dbg.global_debuglevel); +} + +static ssize_t rtl_store_debug_level(struct device *d, +				     struct device_attribute *attr, +				     const char *buf, size_t count) +{ +	struct ieee80211_hw *hw = dev_get_drvdata(d); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	unsigned long val; +	int ret; + +	ret = strict_strtoul(buf, 0, &val); +	if (ret) { +		printk(KERN_DEBUG "%s is not in hex or decimal form.\n", buf); +	} else { +		rtlpriv->dbg.global_debuglevel = val; +		printk(KERN_DEBUG "debuglevel:%x\n", +		       rtlpriv->dbg.global_debuglevel); +	} + +	return strnlen(buf, count); +} + +static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, +		   rtl_show_debug_level, rtl_store_debug_level); + +static struct attribute *rtl_sysfs_entries[] = { + +	&dev_attr_debug_level.attr, + +	NULL +}; + +/* + * "name" is folder name witch will be + * put in device directory like : + * sys/devices/pci0000:00/0000:00:1c.4/ + * 0000:06:00.0/rtl_sysfs + */ +struct attribute_group rtl_attribute_group = { +	.name = "rtlsysfs", +	.attrs = rtl_sysfs_entries, +}; + +MODULE_AUTHOR("lizhaoming	<chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE	<wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger	<Larry.FInger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); + +static int __init rtl_core_module_init(void) +{ +	return 0; +} + +static void __exit rtl_core_module_exit(void) +{ +} + +module_init(rtl_core_module_init); +module_exit(rtl_core_module_exit); diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h new file mode 100644 index 00000000000..3de5a14745f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/base.h @@ -0,0 +1,120 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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__ + +#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 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)		\ +	WRITEEF2BYTE(((u8 *)(_hdr)) + 2, _val) +#define SET_80211_PS_POLL_BSSID(_hdr, _val)		\ +	CP_MACADDR(((u8 *)(_hdr)) + 4, (u8 *)(_val)) +#define SET_80211_PS_POLL_TA(_hdr, _val)		\ +	CP_MACADDR(((u8 *)(_hdr)) + 10, (u8 *)(_val)) + +#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 rtl_init_core(struct ieee80211_hw *hw); +void rtl_deinit_core(struct ieee80211_hw *hw); +void rtl_init_rx_config(struct ieee80211_hw *hw); +void rtl_init_rfkill(struct ieee80211_hw *hw); +void rtl_deinit_rfkill(struct ieee80211_hw *hw); + +void rtl_watch_dog_timer_callback(unsigned long data); +void rtl_deinit_deferred_work(struct ieee80211_hw *hw); + +bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); +bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); +u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); + +void rtl_watch_dog_timer_callback(unsigned long data); +int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, +		     u16 tid, u16 *ssn); +int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid); +void rtl_watchdog_wq_callback(void *data); + +void rtl_get_tcb_desc(struct ieee80211_hw *hw, +		      struct ieee80211_tx_info *info, +		      struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc); + +extern struct attribute_group rtl_attribute_group; +#endif diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c new file mode 100644 index 00000000000..52c9c1367ca --- /dev/null +++ b/drivers/net/wireless/rtlwifi/cam.c @@ -0,0 +1,291 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + *****************************************************************************/ + +#include "wifi.h" +#include "cam.h" + +void rtl_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_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +		 ("key_cont_128:\n %x:%x:%x:%x:%x:%x\n", +		  key_cont_128[0], key_cont_128[1], +		  key_cont_128[2], key_cont_128[3], +		  key_cont_128[4], key_cont_128[5])); + +	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(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("rtl_cam_program_entry(): " +				  "WRITE %x: %x\n", +				  rtlpriv->cfg->maps[WCAMI], target_content)); +			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("The Key ID is %d\n", entry_no)); +			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("rtl_cam_program_entry(): " +				  "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(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("rtl_cam_program_entry(): WRITE A4: %x\n", +				  target_content)); +			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("rtl_cam_program_entry(): 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(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("rtl_cam_program_entry(): WRITE A4: %x\n", +				  target_content)); +			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("rtl_cam_program_entry(): WRITE A0: %x\n", +				  target_command)); +		} +	} + +	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +		 ("after set key, usconfig:%x\n", us_config)); +} + +u8 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(rtlpriv, COMP_SEC, DBG_DMESG, +		 ("EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, " +		  "ulUseDK=%x MacAddr" MAC_FMT "\n", +		  ul_entry_idx, ul_key_id, ul_enc_alg, +		  ul_default_key, MAC_ARG(mac_addr))); + +	if (ul_key_id == TOTAL_CAM_ENTRY) { +		RT_TRACE(rtlpriv, 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(rtlpriv, COMP_SEC, DBG_DMESG, ("<===\n")); + +	return 1; + +} +EXPORT_SYMBOL(rtl_cam_add_one_entry); + +int 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(rtlpriv, 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(rtlpriv, COMP_SEC, DBG_DMESG, +		 ("rtl_cam_delete_one_entry(): WRITE A4: %x\n", 0)); +	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +		 ("rtl_cam_delete_one_entry(): WRITE A0: %x\n", ul_command)); + +	return 0; + +} +EXPORT_SYMBOL(rtl_cam_delete_one_entry); + +void 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(rtl_cam_reset_all_entry); + +void 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(rtlpriv, COMP_SEC, DBG_DMESG, +		 ("rtl_cam_mark_invalid(): WRITE A4: %x\n", ul_content)); +	RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +		 ("rtl_cam_mark_invalid(): WRITE A0: %x\n", ul_command)); +} +EXPORT_SYMBOL(rtl_cam_mark_invalid); + +void 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(rtlpriv, COMP_SEC, DBG_LOUD, +			 ("rtl_cam_empty_entry(): WRITE A4: %x\n", +			  ul_content)); +		RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, +			 ("rtl_cam_empty_entry(): WRITE A0: %x\n", +			  ul_command)); +	} + +} +EXPORT_SYMBOL(rtl_cam_empty_entry); diff --git a/drivers/net/wireless/rtlwifi/cam.h b/drivers/net/wireless/rtlwifi/cam.h new file mode 100644 index 00000000000..dd82f057d53 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/cam.h @@ -0,0 +1,53 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + *****************************************************************************/ + +#ifndef __RTL_CAM_H_ +#define __RTL_CAM_H_ + +#define TOTAL_CAM_ENTRY					32 +#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 + +extern void rtl_cam_reset_all_entry(struct ieee80211_hw *hw); +extern u8 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 rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, +			u32 ul_key_id); +void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index); +void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index); +void rtl_cam_reset_sec_info(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c new file mode 100644 index 00000000000..81b290ff8a9 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/core.c @@ -0,0 +1,1029 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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" + +/*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; +	down(&rtlpriv->locks.conf_sem); +	err = rtlpriv->intf_ops->adapter_start(hw); +	if (err) +		goto out; +	rtl_watch_dog_timer_callback((unsigned long)hw); +out: +	up(&rtlpriv->locks.conf_sem); +	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)); + +	if (is_hal_stop(rtlhal)) +		return; + +	if (unlikely(ppsc->rfpwr_state == ERFOFF)) { +		rtl_ips_nic_on(hw); +		mdelay(1); +	} + +	down(&rtlpriv->locks.conf_sem); + +	mac->link_state = MAC80211_NOLINK; +	memset(mac->bssid, 0, 6); + +	/*reset sec info */ +	rtl_cam_reset_sec_info(hw); + +	rtl_deinit_deferred_work(hw); +	rtlpriv->intf_ops->adapter_stop(hw); + +	up(&rtlpriv->locks.conf_sem); +} + +static int rtl_op_tx(struct ieee80211_hw *hw, 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)); + +	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; + + +	rtlpriv->intf_ops->adapter_tx(hw, skb); + +	return NETDEV_TX_OK; + +err_free: +	dev_kfree_skb_any(skb); +	return NETDEV_TX_OK; +} + +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(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("vif has been set!! mac->vif = 0x%p\n", mac->vif)); +		return -EOPNOTSUPP; +	} + +	rtl_ips_nic_on(hw); + +	down(&rtlpriv->locks.conf_sem); +	switch (vif->type) { +	case NL80211_IFTYPE_STATION: +		if (mac->beacon_enabled == 1) { +			RT_TRACE(rtlpriv, 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(rtlpriv, COMP_MAC80211, DBG_LOUD, +			 ("NL80211_IFTYPE_ADHOC\n")); + +		mac->link_state = MAC80211_LINKED; +		rtlpriv->cfg->ops->set_bcn_reg(hw); +		break; +	case NL80211_IFTYPE_AP: +		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, +			 ("NL80211_IFTYPE_AP\n")); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("operation mode %d is not support!\n", vif->type)); +		err = -EOPNOTSUPP; +		goto out; +	} + +	mac->vif = vif; +	mac->opmode = vif->type; +	rtlpriv->cfg->ops->set_network_type(hw, vif->type); +	memcpy(mac->mac_addr, vif->addr, ETH_ALEN); +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); + +out: +	up(&rtlpriv->locks.conf_sem); +	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)); + +	down(&rtlpriv->locks.conf_sem); + +	/* Free beacon resources */ +	if ((mac->opmode == NL80211_IFTYPE_AP) || +	    (mac->opmode == NL80211_IFTYPE_ADHOC) || +	    (mac->opmode == 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->vif = NULL; +	mac->link_state = MAC80211_NOLINK; +	memset(mac->bssid, 0, 6); +	mac->opmode = NL80211_IFTYPE_UNSPECIFIED; +	rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + +	up(&rtlpriv->locks.conf_sem); +} + + +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; + +	down(&rtlpriv->locks.conf_sem); +	if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {	/*BIT(2)*/ +		RT_TRACE(rtlpriv, 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) +			rtl_ips_nic_off(hw); +		else +			rtl_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)) +			rtl_ips_nic_on(hw); +	} + +	/*For LPS */ +	if (changed & IEEE80211_CONF_CHANGE_PS) { +		if (conf->flags & IEEE80211_CONF_PS) +			rtl_lps_enter(hw); +		else +			rtl_lps_leave(hw); +	} + +	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { +		RT_TRACE(rtlpriv, 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) { +		struct ieee80211_channel *channel = hw->conf.channel; +		u8 wide_chan = (u8) channel->hw_value; + +		/* +		 *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 +		 */ +		switch (hw->conf.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; +			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; + +			/*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; + +			/*wide channel */ +			wide_chan += 2; + +			break; +		default: +			mac->bw_40 = false; +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("switch case not processed\n")); +			break; +		} + +		if (wide_chan <= 0) +			wide_chan = 1; +		rtlphy->current_channel = wide_chan; + +		rtlpriv->cfg->ops->set_channel_access(hw); +		rtlpriv->cfg->ops->switch_channel(hw); +		rtlpriv->cfg->ops->set_bw_mode(hw, +					       hw->conf.channel_type); +	} + +	up(&rtlpriv->locks.conf_sem); + +	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 (!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(rtlpriv, 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(rtlpriv, 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(rtlpriv, COMP_MAC80211, DBG_LOUD, +				 ("Enable receive FCS error frame.\n")); +		} else { +			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACRC32]; +			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, +				 ("Disable receive FCS error frame.\n")); +		} +	} + +	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { +		/* +		 *TODO: BIT(5) is probe response BIT(8) is beacon +		 *TODO: Use define for BIT(5) and BIT(8) +		 */ +		if (*new_flags & FIF_BCN_PRBRESP_PROMISC) +			mac->rx_mgt_filter |= (BIT(5) | BIT(8)); +		else +			mac->rx_mgt_filter &= ~(BIT(5) | BIT(8)); +	} + +	if (changed_flags & FIF_CONTROL) { +		if (*new_flags & FIF_CONTROL) { +			mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; +			mac->rx_ctrl_filter |= RTL_SUPPORTED_CTRL_FILTER; + +			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, +				 ("Enable receive control frame.\n")); +		} else { +			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; +			mac->rx_ctrl_filter &= ~RTL_SUPPORTED_CTRL_FILTER; +			RT_TRACE(rtlpriv, 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(rtlpriv, COMP_MAC80211, DBG_LOUD, +				 ("Enable receive other BSS's frame.\n")); +		} else { +			mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_AAP]; +			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, +				 ("Disable receive other BSS's frame.\n")); +		} +	} + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER, +				      (u8 *) (&mac->rx_mgt_filter)); +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER, +				      (u8 *) (&mac->rx_ctrl_filter)); +} + +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, 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(rtlpriv, 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 = param->cw_min; +	mac->ac[aci].cw_max = param->cw_max; +	mac->ac[aci].tx_op = 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_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	down(&rtlpriv->locks.conf_sem); + +	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(rtlpriv, 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); +			} +		} else { +			if (mac->beacon_enabled == 1) { +				RT_TRACE(rtlpriv, 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(rtlpriv, 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) { +		if (bss_conf->assoc) { +			mac->link_state = MAC80211_LINKED; +			mac->cnt_after_linked = 0; +			mac->assoc_id = bss_conf->aid; +			memcpy(mac->bssid, bss_conf->bssid, 6); + +			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, +				 ("BSS_CHANGED_ASSOC\n")); +		} else { +			if (mac->link_state == MAC80211_LINKED) +				rtl_lps_leave(hw); + +			mac->link_state = MAC80211_NOLINK; +			memset(mac->bssid, 0, 6); + +			/* reset sec info */ +			rtl_cam_reset_sec_info(hw); + +			RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, +				 ("BSS_CHANGED_UN_ASSOC\n")); +		} +	} + +	if (changed & BSS_CHANGED_ERP_CTS_PROT) { +		RT_TRACE(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, COMP_MAC80211, DBG_TRACE, +			 ("BSS_CHANGED_HT\n")); + +		sta = ieee80211_find_sta(mac->vif, mac->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; +		} + +		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) { +		struct ieee80211_sta *sta = NULL; +		u32 basic_rates; +		u8 i; + +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID, +					      (u8 *) bss_conf->bssid); + +		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, +			 (MAC_FMT "\n", MAC_ARG(bss_conf->bssid))); + +		memcpy(mac->bssid, bss_conf->bssid, 6); +		if (is_valid_ether_addr(bss_conf->bssid)) { +			switch (vif->type) { +			case NL80211_IFTYPE_UNSPECIFIED: +				break; +			case NL80211_IFTYPE_ADHOC: +				break; +			case NL80211_IFTYPE_STATION: +				break; +			case NL80211_IFTYPE_AP: +				break; +			default: +				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +					 ("switch case not process\n")); +				break; +			} +			rtlpriv->cfg->ops->set_network_type(hw, vif->type); +		} else +			rtlpriv->cfg->ops->set_network_type(hw, +					NL80211_IFTYPE_UNSPECIFIED); + +		memset(mac->mcs, 0, 16); +		mac->ht_enable = false; +		mac->sgi_40 = false; +		mac->sgi_20 = false; + +		if (!bss_conf->use_short_slot) +			mac->mode = WIRELESS_MODE_B; +		else +			mac->mode = WIRELESS_MODE_G; + +		sta = ieee80211_find_sta(mac->vif, mac->bssid); + +		if (sta) { +			if (sta->ht_cap.ht_supported) { +				mac->mode = WIRELESS_MODE_N_24G; +				mac->ht_enable = true; +			} + +			if (mac->ht_enable) { +				u16 ht_cap = sta->ht_cap.cap; +				memcpy(mac->mcs, (u8 *) (&sta->ht_cap.mcs), 16); + +				for (i = 0; i < 16; i++) +					RT_TRACE(rtlpriv, COMP_MAC80211, +						 DBG_LOUD, ("%x ", +							    mac->mcs[i])); +				RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, +					 ("\n")); + +				if (ht_cap & IEEE80211_HT_CAP_SGI_40) +					mac->sgi_40 = true; + +				if (ht_cap & IEEE80211_HT_CAP_SGI_20) +					mac->sgi_20 = true; + +				/* +				 * for cisco 1252 bw20 it's wrong +				 * if (ht_cap & +				 *     IEEE80211_HT_CAP_SUP_WIDTH_20_40) { +				 *	mac->bw_40 = true; +				 * } +				 */ +			} +		} + +		/*mac80211 just give us CCK rates any time +		 *So we add G rate in basic rates when +		 not in B mode*/ +		if (changed & BSS_CHANGED_BASIC_RATES) { +			if (mac->mode == WIRELESS_MODE_B) +				basic_rates = bss_conf->basic_rates | 0x00f; +			else +				basic_rates = bss_conf->basic_rates | 0xff0; + +			if (!vif) +				goto out; + +			mac->basic_rates = basic_rates; +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, +					(u8 *) (&basic_rates)); + +			if (rtlpriv->dm.b_useramask) +				rtlpriv->cfg->ops->update_rate_mask(hw, 0); +			else +				rtlpriv->cfg->ops->update_rate_table(hw); + +		} +	} + +	/* +	 * For FW LPS: +	 * To tell firmware we have connected +	 * to an AP. For 92SE/CE power save v2. +	 */ +	if (changed & BSS_CHANGED_ASSOC) { +		if (bss_conf->assoc) { +			if (ppsc->b_fwctrl_lps) { +				u8 mstatus = RT_MEDIA_CONNECT; +				rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_H2C_FW_JOINBSSRPT, +						      (u8 *) (&mstatus)); +				ppsc->report_linked = true; +			} +		} else { +			if (ppsc->b_fwctrl_lps) { +				u8 mstatus = RT_MEDIA_DISCONNECT; +				rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_H2C_FW_JOINBSSRPT, +						      (u8 *)(&mstatus)); +				ppsc->report_linked = false; +			} +		} +	} + +out: +	up(&rtlpriv->locks.conf_sem); +} + +static u64 rtl_op_get_tsf(struct ieee80211_hw *hw) +{ +	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, 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 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) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	switch (action) { +	case IEEE80211_AMPDU_TX_START: +		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid)); +		return rtl_tx_agg_start(hw, sta->addr, tid, ssn); +		break; +	case IEEE80211_AMPDU_TX_STOP: +		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid)); +		return rtl_tx_agg_stop(hw, sta->addr, tid); +		break; +	case IEEE80211_AMPDU_TX_OPERATIONAL: +		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid)); +		break; +	case IEEE80211_AMPDU_RX_START: +		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_RX_START:TID:%d\n", tid)); +		break; +	case IEEE80211_AMPDU_RX_STOP: +		RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, +			 ("IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid)); +		break; +	default: +		RT_TRACE(rtlpriv, 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)); + +	mac->act_scanning = true; + +	RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n")); + +	if (mac->link_state == MAC80211_LINKED) { +		rtl_lps_leave(hw); +		mac->link_state = MAC80211_LINKED_SCANNING; +	} else +		rtl_ips_nic_on(hw); + +	rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); +	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP); +} + +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(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n")); + +	rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); +	mac->act_scanning = false; +	if (mac->link_state == MAC80211_LINKED_SCANNING) { +		mac->link_state = MAC80211_LINKED; + +		/* fix fwlps issue */ +		rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + +		if (rtlpriv->dm.b_useramask) +			rtlpriv->cfg->ops->update_rate_mask(hw, 0); +		else +			rtlpriv->cfg->ops->update_rate_table(hw); + +	} + +} + +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); +	struct rtl_mac *mac = rtl_mac(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 }; +	u8 zero_addr[ETH_ALEN] = { 0 }; + +	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("not open hw encryption\n")); +		return -ENOSPC;	/*User disabled HW-crypto */ +	} +	RT_TRACE(rtlpriv, 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; +	rtl_ips_nic_on(hw); +	down(&rtlpriv->locks.conf_sem); +	/* <1> get encryption alg */ +	switch (key->cipher) { +	case WLAN_CIPHER_SUITE_WEP40: +		key_type = WEP40_ENCRYPTION; +		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP40\n")); +		rtlpriv->sec.use_defaultkey = true; +		break; +	case WLAN_CIPHER_SUITE_WEP104: +		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +			 ("alg:WEP104\n")); +		key_type = WEP104_ENCRYPTION; +		rtlpriv->sec.use_defaultkey = true; +		break; +	case WLAN_CIPHER_SUITE_TKIP: +		key_type = TKIP_ENCRYPTION; +		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:TKIP\n")); +		if (mac->opmode == NL80211_IFTYPE_ADHOC) +			rtlpriv->sec.use_defaultkey = true; +		break; +	case WLAN_CIPHER_SUITE_CCMP: +		key_type = AESCCMP_ENCRYPTION; +		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:CCMP\n")); +		if (mac->opmode == NL80211_IFTYPE_ADHOC) +			rtlpriv->sec.use_defaultkey = true; +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("alg_err:%x!!!!:\n", key->cipher)); +		goto out_unlock; +	} +	/* <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); +	if ((!group_key) || (mac->opmode == 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; +		rtlpriv->cfg->ops->enable_hw_sec(hw); +	} +	/* <4> set key based on cmd */ +	switch (cmd) { +	case SET_KEY: +		if (wep_only) { +			RT_TRACE(rtlpriv, 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; +			memcpy(mac_addr, zero_addr, ETH_ALEN); +		} else if (group_key) {	/* group key */ +			RT_TRACE(rtlpriv, 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; +			memcpy(mac_addr, bcast_addr, ETH_ALEN); +		} else {	/* pairwise key */ +			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("set pairwise key\n")); +			if (!sta) { +				RT_ASSERT(false, ("pairwise key withnot" +						  "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]; +			memcpy(mac_addr, sta->addr, ETH_ALEN); +		} +		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; +		break; +	case DISABLE_KEY: +		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +			 ("disable key delete one entry\n")); +		/*set local buf about wep key. */ +		memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); +		rtlpriv->sec.key_len[key_idx] = 0; +		memcpy(mac_addr, zero_addr, ETH_ALEN); +		/* +		 *mac80211 will delete entrys one by one, +		 *so don't use rtl_cam_reset_all_entry +		 *or clear all entry here. +		 */ +		rtl_cam_delete_one_entry(hw, mac_addr, key_idx); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("cmd_err:%x!!!!:\n", cmd)); +	} +out_unlock: +	up(&rtlpriv->locks.conf_sem); +	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; + +	down(&rtlpriv->locks.conf_sem); + +	/*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(rtlpriv, 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); +		} +	} + +	up(&rtlpriv->locks.conf_sem); +} + +const struct ieee80211_ops rtl_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, +	.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, +}; diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h new file mode 100644 index 00000000000..0ef31c3c619 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/core.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * 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 rtl_ops; +#endif diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c new file mode 100644 index 00000000000..5fa73852cb6 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/debug.c @@ -0,0 +1,50 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * 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> + *****************************************************************************/ + +#include "wifi.h" + +void rtl_dbgp_flag_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 i; + +	rtlpriv->dbg.global_debuglevel = DBG_EMERG; + +	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_EFUSE | COMP_QOS | COMP_MAC80211 | COMP_REGD | COMP_CHAN; + +	for (i = 0; i < DBGP_TYPE_MAX; i++) +		rtlpriv->dbg.dbgp_type[i] = 0; + +	/*Init Debug flag enable condition */ +} diff --git a/drivers/net/wireless/rtlwifi/debug.h b/drivers/net/wireless/rtlwifi/debug.h new file mode 100644 index 00000000000..08bdec2ceda --- /dev/null +++ b/drivers/net/wireless/rtlwifi/debug.h @@ -0,0 +1,212 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * 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			0 + +/* + *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 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) + +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)) {			\ +			printk(KERN_DEBUG "%s:%s(): ", KBUILD_MODNAME, \ +			__func__);			\ +			printk fmt;			\ +		} \ +	} while (0); + +#define RT_TRACE(rtlpriv, comp, level, fmt)\ +	do { \ +		if (unlikely(((comp) & rtlpriv->dbg.global_debugcomponents) && \ +			((level) <= rtlpriv->dbg.global_debuglevel))) {\ +			printk(KERN_DEBUG "%s:%s():<%lx-%x> ", KBUILD_MODNAME, \ +			__func__, in_interrupt(), in_atomic());	\ +			printk fmt;				\ +		} \ +	} while (0); + +#define RTPRINT(rtlpriv, dbgtype, dbgflag, printstr)	\ +	do {						\ +		if (unlikely(rtlpriv->dbg.dbgp_type[dbgtype] & dbgflag)) { \ +			printk(KERN_DEBUG "%s: ", KBUILD_MODNAME);	\ +			printk printstr;		\ +		}					\ +	} 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;			\ +			printk(KERN_DEBUG "%s: ", KBUILD_MODNAME);	\ +			printk("In process \"%s\" (pid %i):", current->comm,\ +					current->pid); \ +			printk(_titlestring);		\ +			for (__i = 0; __i < (int)_hexdatalen; __i++) {	\ +				printk("%02X%s", ptr[__i], (((__i + 1) % 4)\ +							== 0) ? "  " : " ");\ +				if (((__i + 1) % 16) == 0)		\ +					printk("\n");			\ +			}				\ +			printk(KERN_DEBUG "\n");			\ +		} \ +	} while (0); + +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ARG(x) \ +	((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2],\ +	((u8 *)(x))[3], ((u8 *)(x))[4], ((u8 *)(x))[5] + +void rtl_dbgp_flag_init(struct ieee80211_hw *hw); +#endif diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c new file mode 100644 index 00000000000..b8433f3a9bc --- /dev/null +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -0,0 +1,1189 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * tmis program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * 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> + * + *****************************************************************************/ + +#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 u8 EFUSE_OOB_PROTECT_BYTES = 15; + +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 read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, +					u8 *pbuf); +static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, +				    u8 *value); +static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, +				    u16 *value); +static void efuse_shadow_read_4byte(struct ieee80211_hw *hw, u16 offset, +				    u32 *value); +static void efuse_shadow_write_1byte(struct ieee80211_hw *hw, u16 offset, +				     u8 value); +static void efuse_shadow_write_2byte(struct ieee80211_hw *hw, u16 offset, +				     u16 value); +static void efuse_shadow_write_4byte(struct ieee80211_hw *hw, u16 offset, +				     u32 value); +static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, +					u8 *data); +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 efuse_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 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; + +	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(efuse_read_1byte); + +void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 bytetemp; +	u8 temp; +	u32 k = 0; + +	RT_TRACE(rtlpriv, 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; +			} +		} +	} + +} + +static void read_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 read_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[EFUSE_MAP_LEN]; +	u8 rtemp8[1]; +	u16 efuse_addr = 0; +	u8 offset, wren; +	u16 i; +	u16 j; +	u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT]; +	u16 efuse_utilized = 0; +	u8 efuse_usage; + +	if ((_offset + _size_byte) > EFUSE_MAP_LEN) { +		RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, +			 ("read_efuse(): Invalid offset(%#x) with read " +			  "bytes(%#x)!!\n", _offset, _size_byte)); +		return; +	} + +	for (i = 0; i < EFUSE_MAX_SECTION; i++) +		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) +			efuse_word[i][j] = 0xFFFF; + +	read_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)) { +		offset = ((*rtemp8 >> 4) & 0x0f); + +		if (offset < EFUSE_MAX_SECTION) { +			wren = (*rtemp8 & 0x0f); +			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)); + +					read_efuse_byte(hw, efuse_addr, rtemp8); +					efuse_addr++; +					efuse_utilized++; +					efuse_word[offset][i] = (*rtemp8 & 0xff); + +					if (efuse_addr >= EFUSE_REAL_CONTENT_LEN) +						break; + +					RTPRINT(rtlpriv, FEEPROM, +						EFUSE_READ_ALL, ("Addr=%d\n", +								 efuse_addr)); + +					read_efuse_byte(hw, efuse_addr, rtemp8); +					efuse_addr++; +					efuse_utilized++; +					efuse_word[offset][i] |= +					    (((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)); +		read_efuse_byte(hw, efuse_addr, rtemp8); +		if (*rtemp8 != 0xFF && (efuse_addr < 512)) { +			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[i][j] & 0xff); +			efuse_tbl[(i * 8) + ((j * 2) + 1)] = +			    ((efuse_word[i][j] >> 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); +} + +bool efuse_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 == true) +			hdr_num++; +	} + +	totalbytes = hdr_num + words_need * 2; +	efuse_used = rtlefuse->efuse_usedbytes; + +	if ((totalbytes + efuse_used) >= +	    (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) +		bresult = false; + +	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, +		 ("efuse_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 efuse_shadow_read(struct ieee80211_hw *hw, u8 type, +		       u16 offset, u32 *value) +{ +	if (type == 1) +		efuse_shadow_read_1byte(hw, offset, (u8 *) value); +	else if (type == 2) +		efuse_shadow_read_2byte(hw, offset, (u16 *) value); +	else if (type == 4) +		efuse_shadow_read_4byte(hw, offset, (u32 *) value); + +} + +void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset, +				u32 value) +{ +	if (type == 1) +		efuse_shadow_write_1byte(hw, offset, (u8) value); +	else if (type == 2) +		efuse_shadow_write_2byte(hw, offset, (u16) value); +	else if (type == 4) +		efuse_shadow_write_4byte(hw, offset, (u32) value); + +} + +bool efuse_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(rtlpriv, COMP_EFUSE, DBG_LOUD, ("--->\n")); + +	if (!efuse_shadow_update_chk(hw)) { +		efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); +		memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], +		       (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +		       rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + +		RT_TRACE(rtlpriv, 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 == true) { + +				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((void *)tmpdata, +			       (void *)(&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(rtlpriv, 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((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], +	       (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +	       rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + +	RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("<---\n")); +	return true; +} + +void rtl_efuse_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 == true) { +		memset((void *)(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]), 128, +		       0xFF); +	} else +		efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); + +	memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], +	       (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +	       rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + +} +EXPORT_SYMBOL(rtl_efuse_shadow_map_update); + +void efuse_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 efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx) +{ +} + +static void efuse_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 efuse_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 efuse_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 efuse_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 efuse_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 efuse_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); + +} + +static int 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; +} + +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(rtlpriv, 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) +{ +	efuse_power_switch(hw, false, true); +	read_efuse(hw, 0, 128, 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 (efuse_one_byte_read(hw, *efuse_addr + 1 + tmpidx, +			    &efuse_data)) { +				tmpdata[tmpidx] = efuse_data; +				if (efuse_data != 0xff) +					bdataempty = true; +			} +		} + +		if (bdataempty == true) +			*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; +	u8 tmpdata[8]; + +	if (data == NULL) +		return false; +	if (offset > 15) +		return false; + +	memset((void *)data, PGPKT_DATA_SIZE * sizeof(u8), 0xff); +	memset((void *)tmpdata, PGPKT_DATA_SIZE * sizeof(u8), 0xff); + +	while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { +		if (readstate & PG_STATE_HEADER) { +			if (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++) { +			u16 address = *efuse_addr + 1 + tmpindex; +			if (efuse_one_byte_read(hw, address, +			     &efuse_data) && (efuse_data != 0xFF)) +				bdataempty = false; +		} + +		if (bdataempty == false) { +			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); +	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((void *)originaldata, 8 * sizeof(u8), 0xff); + +		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 - EFUSE_OOB_PROTECT_BYTES)) { +		RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, +			("efuse_pg_packet_write error\n")); +		return false; +	} + +	target_pkt.offset = offset; +	target_pkt.word_en = word_en; + +	memset((void *)target_pkt.data, 8 * sizeof(u8), 0xFF); + +	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 - EFUSE_OOB_PROTECT_BYTES))) { + +		if (write_state == PG_STATE_HEADER) { +			bdataempty = true; +			badworden = 0x0F; +			RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, +				("efuse PG_STATE_HEADER\n")); + +			if (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 - EFUSE_OOB_PROTECT_BYTES)) { +		RT_TRACE(rtlpriv, 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((void *)tmpdata, PGPKT_DATA_SIZE, 0xff); +	RT_TRACE(rtlpriv, 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]); + +		efuse_one_byte_read(hw, tmpaddr, &tmpdata[0]); +		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]); + +		efuse_one_byte_read(hw, tmpaddr, &tmpdata[2]); +		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]); + +		efuse_one_byte_read(hw, tmpaddr, &tmpdata[4]); +		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]); + +		efuse_one_byte_read(hw, tmpaddr, &tmpdata[6]); +		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); +	u8 tempval; +	u16 tmpV16; + +	if (pwrstate == true) { +		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 == true) { +		if (bwrite == true) { +			tempval = rtl_read_byte(rtlpriv, +						rtlpriv->cfg->maps[EFUSE_TEST] + +						3); +			tempval &= 0x0F; +			tempval |= (VOLTAGE_V25 << 4); +			rtl_write_byte(rtlpriv, +				       rtlpriv->cfg->maps[EFUSE_TEST] + 3, +				       (tempval | 0x80)); +		} + +	} else { +		if (bwrite == true) { +			tempval = rtl_read_byte(rtlpriv, +						rtlpriv->cfg->maps[EFUSE_TEST] + +						3); +			rtl_write_byte(rtlpriv, +				       rtlpriv->cfg->maps[EFUSE_TEST] + 3, +				       (tempval & 0x7F)); +		} + +	} + +} + +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 && 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; +} + +void efuse_reset_loader(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u16 tmp_u2b; + +	tmp_u2b = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN]); +	rtl_write_word(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN], +		       (tmp_u2b & ~(BIT(12)))); +	udelay(10000); +	rtl_write_word(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN], +		       (tmp_u2b | BIT(12))); +	udelay(10000); +} + +bool efuse_program_map(struct ieee80211_hw *hw, char *p_filename, u8 tabletype) +{ +	return true; +} diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h new file mode 100644 index 00000000000..2d39a4df181 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/efuse.h @@ -0,0 +1,124 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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_REAL_CONTENT_LEN		512 +#define EFUSE_MAP_LEN			128 +#define EFUSE_MAX_SECTION		16 +#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 + +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]; +}; + +extern void efuse_initialize(struct ieee80211_hw *hw); +extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address); +extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value); +extern void read_efuse(struct ieee80211_hw *hw, u16 _offset, +		       u16 _size_byte, u8 *pbuf); +extern void efuse_shadow_read(struct ieee80211_hw *hw, u8 type, +			      u16 offset, u32 *value); +extern void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, +			       u16 offset, u32 value); +extern bool efuse_shadow_update(struct ieee80211_hw *hw); +extern bool efuse_shadow_update_chk(struct ieee80211_hw *hw); +extern void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw); +extern void efuse_force_write_vendor_Id(struct ieee80211_hw *hw); +extern void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx); +extern bool efuse_program_map(struct ieee80211_hw *hw, +			      char *p_filename, u8 tabletype); +extern void efuse_reset_loader(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c new file mode 100644 index 00000000000..bf3b5748ee1 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -0,0 +1,1933 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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" + +static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { +	INTEL_VENDOR_ID, +	ATI_VENDOR_ID, +	AMD_VENDOR_ID, +	SIS_VENDOR_ID +}; + +/* 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; + +	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(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} +} + +static bool _rtl_pci_platform_switch_device_pci_aspm( +			struct ieee80211_hw *hw, +			u8 value) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	bool bresult = false; + +	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)); +	u8 buffer; +	bool bresult = false; + +	buffer = value; + +	pci_write_config_byte(rtlpci->pdev, 0x81, value); +	bresult = true; + +	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 (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { +		RT_TRACE(rtlpriv, 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_busnum = pcipriv->ndis_adapter.pcibridge_busnum; +	u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum; +	u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum; +	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 (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { +		RT_TRACE(rtlpriv, 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(rtlpriv, COMP_INIT, DBG_LOUD, +		 ("PlatformEnableASPM():PciBridge busnumber[%x], " +		  "DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n", +		  pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum, +		  (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(200); +} + +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 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(rtlpriv, 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_initialize_adapter_common(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_init_aspm(struct ieee80211_hw *hw) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	/*close ASPM for AMD defaultly */ +	rtlpci->const_amdpci_aspm = 0; + +	/* +	 * ASPM PS mode. +	 * 0 - Disable ASPM, +	 * 1 - Enable ASPM without Clock Req, +	 * 2 - Enable ASPM with Clock Req, +	 * 3 - Alwyas Enable ASPM with Clock Req, +	 * 4 - Always Enable ASPM without Clock Req. +	 * set defult to RTL8192CE:3 RTL8192E:2 +	 * */ +	rtlpci->const_pci_aspm = 3; + +	/*Setting for PCI-E device */ +	rtlpci->const_devicepci_aspm_setting = 0x03; + +	/*Setting for PCI-E bridge */ +	rtlpci->const_hostpci_aspm_setting = 0x02; + +	/* +	 * In Hw/Sw Radio Off situation. +	 * 0 - Default, +	 * 1 - From ASPM setting without low Mac Pwr, +	 * 2 - From ASPM setting with low Mac Pwr, +	 * 3 - Bus D3 +	 * set default to RTL8192CE:0 RTL8192SE:2 +	 */ +	rtlpci->const_hwsw_rfoff_d3 = 0; + +	/* +	 * This setting works for those device with +	 * backdoor ASPM setting such as EPHY setting. +	 * 0 - Not support ASPM, +	 * 1 - Support ASPM, +	 * 2 - According to chipset. +	 */ +	rtlpci->const_support_pciaspm = 1; + +	_rtl_pci_initialize_adapter_common(hw); +} + +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 void _rtl_pci_io_handler_release(struct ieee80211_hw *hw) +{ +} + +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 rtl_tx_desc *entry = &ring->desc[ring->idx]; +		struct sk_buff *skb; +		struct ieee80211_tx_info *info; + +		u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true, +							  HW_DESC_OWN); + +		/* +		 *beacon packet will only use the first +		 *descriptor defautly,and the own may not +		 *be cleared by the hardware +		 */ +		if (own) +			return; +		ring->idx = (ring->idx + 1) % ring->entries; + +		skb = __skb_dequeue(&ring->queue); +		pci_unmap_single(rtlpci->pdev, +				 le32_to_cpu(rtlpriv->cfg->ops-> +					     get_desc((u8 *) entry, true, +						      HW_DESC_TXBUFF_ADDR)), +				 skb->len, PCI_DMA_TODEVICE); + +		RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE, +			 ("new ring->idx:%d, " +			  "free: skb_queue_len:%d, free: seq:%x\n", +			  ring->idx, +			  skb_queue_len(&ring->queue), +			  *(u16 *) (skb->data + 22))); + +		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(rtlpriv, 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)); +		} + +		skb = NULL; +	} + +	if (((rtlpriv->link_info.num_rx_inperiod + +		rtlpriv->link_info.num_tx_inperiod) > 8) || +		(rtlpriv->link_info.num_rx_inperiod > 2)) { +		rtl_lps_leave(hw); +	} +} + +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)); +	int rx_queue_idx = RTL_PCI_RX_MPDU_QUEUE; + +	struct ieee80211_rx_status rx_status = { 0 }; +	unsigned int count = rtlpci->rxringcount; +	u8 own; +	u8 tmp_one; +	u32 bufferaddress; +	bool unicast = false; + +	struct rtl_stats stats = { +		.signal = 0, +		.noise = -98, +		.rate = 0, +	}; + +	/*RX NORMAL PKT */ +	while (count--) { +		/*rx descriptor */ +		struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[ +				rtlpci->rx_ring[rx_queue_idx].idx]; +		/*rx pkt */ +		struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[ +				rtlpci->rx_ring[rx_queue_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; +		} else { +			struct ieee80211_hdr *hdr; +			u16 fc; +			struct sk_buff *new_skb = NULL; + +			rtlpriv->cfg->ops->query_rx_desc(hw, &stats, +							 &rx_status, +							 (u8 *) pdesc, skb); + +			pci_unmap_single(rtlpci->pdev, +					 *((dma_addr_t *) skb->cb), +					 rtlpci->rxbuffersize, +					 PCI_DMA_FROMDEVICE); + +			skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc, +							 false, +							 HW_DESC_RXPKT_LEN)); +			skb_reserve(skb, +				    stats.rx_drvinfo_size + stats.rx_bufshift); + +			/* +			 *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 = (struct ieee80211_hdr *)(skb->data); +			fc = le16_to_cpu(hdr->frame_control); + +			if (!stats.b_crc) { +				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; +					} +				} + +				rtl_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++; +				} + +				if (unlikely(!rtl_action_proc(hw, skb, false))) +					dev_kfree_skb_any(skb); +				else +					ieee80211_rx_irqsafe(hw, skb); +			} else { +				dev_kfree_skb_any(skb); +			} + +			if (((rtlpriv->link_info.num_rx_inperiod + +				rtlpriv->link_info.num_tx_inperiod) > 8) || +				(rtlpriv->link_info.num_rx_inperiod > 2)) { +				rtl_lps_leave(hw); +			} + +			new_skb = dev_alloc_skb(rtlpci->rxbuffersize); +			if (unlikely(!new_skb)) { +				RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), +					 DBG_DMESG, +					 ("can't alloc skb for rx\n")); +				goto done; +			} +			skb = new_skb; +			/*skb->dev = dev; */ + +			rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci-> +							     rx_ring +							     [rx_queue_idx]. +							     idx] = skb; +			*((dma_addr_t *) skb->cb) = +			    pci_map_single(rtlpci->pdev, skb_tail_pointer(skb), +					   rtlpci->rxbuffersize, +					   PCI_DMA_FROMDEVICE); + +		} +done: +		bufferaddress = cpu_to_le32(*((dma_addr_t *) skb->cb)); +		tmp_one = 1; +		rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, +					    HW_DESC_RXBUFF_ADDR, +					    (u8 *)&bufferaddress); +		rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN, +					    (u8 *)&tmp_one); +		rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, +					    HW_DESC_RXPKT_LEN, +					    (u8 *)&rtlpci->rxbuffersize); + +		if (rtlpci->rx_ring[rx_queue_idx].idx == +		    rtlpci->rxringcount - 1) +			rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, +						    HW_DESC_RXERO, +						    (u8 *)&tmp_one); + +		rtlpci->rx_ring[rx_queue_idx].idx = +		    (rtlpci->rx_ring[rx_queue_idx].idx + 1) % +		    rtlpci->rxringcount; +	} + +} + +void _rtl_pci_tx_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	int prio; + +	for (prio = 0; prio < RTL_PCI_MAX_TX_QUEUE_COUNT; prio++) { +		struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio]; + +		while (skb_queue_len(&ring->queue)) { +			struct rtl_tx_desc *entry = &ring->desc[ring->idx]; +			struct sk_buff *skb; +			struct ieee80211_tx_info *info; +			u8 own; + +			/* +			 *beacon packet will only use the first +			 *descriptor defautly, and the own may not +			 *be cleared by the hardware, and +			 *beacon will free in prepare beacon +			 */ +			if (prio == BEACON_QUEUE || prio == TXCMD_QUEUE || +			    prio == HCCA_QUEUE) +				break; + +			own = (u8)rtlpriv->cfg->ops->get_desc((u8 *)entry, +							       true, +							       HW_DESC_OWN); + +			if (own) +				break; + +			skb = __skb_dequeue(&ring->queue); +			pci_unmap_single(rtlpci->pdev, +					 le32_to_cpu(rtlpriv->cfg->ops-> +						     get_desc((u8 *) entry, +						     true, +						     HW_DESC_TXBUFF_ADDR)), +					 skb->len, PCI_DMA_TODEVICE); + +			ring->idx = (ring->idx + 1) % ring->entries; + +			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 && prio != BEACON_QUEUE) { +				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +					 ("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)); +			} + +			skb = NULL; +		} +	} +} + +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)); +	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); + +	/*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(rtlpriv, COMP_INTR, DBG_TRACE, +			 ("beacon ok interrupt!\n")); +	} + +	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER])) { +		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, +			 ("beacon err interrupt!\n")); +	} + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK]) { +		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, +			 ("beacon interrupt!\n")); +	} + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) { +		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, +			 ("prepare beacon for interrupt!\n")); +		tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet); +	} + +	/*<3> Tx related */ +	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TXFOVW])) +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("IMR_TXFOVW!\n")); + +	if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) { +		RT_TRACE(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, 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(rtlpriv, COMP_INTR, DBG_TRACE, +			 ("Vo TX OK interrupt!\n")); +		_rtl_pci_tx_isr(hw, VO_QUEUE); +	} + +	/*<2> Rx related */ +	if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { +		RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n")); +		tasklet_schedule(&rtlpriv->works.irq_tasklet); +	} + +	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("rx descriptor unavailable!\n")); +		tasklet_schedule(&rtlpriv->works.irq_tasklet); +	} + +	if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n")); +		tasklet_schedule(&rtlpriv->works.irq_tasklet); +	} + +	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); +	return IRQ_HANDLED; + +done: +	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); +	return IRQ_HANDLED; +} + +static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) +{ +	_rtl_pci_rx_interrupt(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 = &rtlpci->tx_ring[BEACON_QUEUE]; +	struct ieee80211_hdr *hdr = NULL; +	struct ieee80211_tx_info *info = NULL; +	struct sk_buff *pskb = NULL; +	struct rtl_tx_desc *pdesc = NULL; +	unsigned int queue_index; +	u8 temp_one = 1; + +	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 = (struct ieee80211_hdr *)(pskb->data); +	info = IEEE80211_SKB_CB(pskb); + +	queue_index = BEACON_QUEUE; + +	pdesc = &ring->desc[0]; +	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, +					info, pskb, queue_index); + +	__skb_queue_tail(&ring->queue, pskb); + +	rtlpriv->cfg->ops->set_desc((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)); +	u8 i; + +	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) +		rtlpci->txringcount[i] = RT_TXDESC_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. +	 */ +	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)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	rtlpci->up_first_time = true; +	rtlpci->being_init_adapter = false; + +	rtlhal->hw = hw; +	rtlpci->pdev = pdev; + +	ppsc->b_inactiveps = false; +	ppsc->b_leisure_ps = true; +	ppsc->b_fwctrl_lps = true; +	ppsc->b_reg_fwctrl_lps = 3; +	ppsc->reg_max_lps_awakeintvl = 5; + +	if (ppsc->b_reg_fwctrl_lps == 1) +		ppsc->fwctrl_psmode = FW_PS_MIN_MODE; +	else if (ppsc->b_reg_fwctrl_lps == 2) +		ppsc->fwctrl_psmode = FW_PS_MAX_MODE; +	else if (ppsc->b_reg_fwctrl_lps == 3) +		ppsc->fwctrl_psmode = FW_PS_DTIM_MODE; + +	/*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_desc *ring; +	dma_addr_t dma; +	u32 nextdescaddress; +	int i; + +	ring = pci_alloc_consistent(rtlpci->pdev, +				    sizeof(*ring) * entries, &dma); + +	if (!ring || (unsigned long)ring & 0xFF) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("Cannot allocate TX ring (prio = %d)\n", prio)); +		return -ENOMEM; +	} + +	memset(ring, 0, sizeof(*ring) * entries); +	rtlpci->tx_ring[prio].desc = ring; +	rtlpci->tx_ring[prio].dma = dma; +	rtlpci->tx_ring[prio].idx = 0; +	rtlpci->tx_ring[prio].entries = entries; +	skb_queue_head_init(&rtlpci->tx_ring[prio].queue); + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 ("queue:%d, ring_addr:%p\n", prio, ring)); + +	for (i = 0; i < entries; i++) { +		nextdescaddress = cpu_to_le32((u32) dma + +					      ((i + 1) % entries) * +					      sizeof(*ring)); + +		rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), +					    true, HW_DESC_TX_NEXTDESC_ADDR, +					    (u8 *)&nextdescaddress); +	} + +	return 0; +} + +static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_rx_desc *entry = NULL; +	int i, rx_queue_idx; +	u8 tmp_one = 1; + +	/* +	 *rx_queue_idx 0:RX_MPDU_QUEUE +	 *rx_queue_idx 1:RX_CMD_QUEUE +	 */ +	for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE; +	     rx_queue_idx++) { +		rtlpci->rx_ring[rx_queue_idx].desc = +		    pci_alloc_consistent(rtlpci->pdev, +					 sizeof(*rtlpci->rx_ring[rx_queue_idx]. +						desc) * rtlpci->rxringcount, +					 &rtlpci->rx_ring[rx_queue_idx].dma); + +		if (!rtlpci->rx_ring[rx_queue_idx].desc || +		    (unsigned long)rtlpci->rx_ring[rx_queue_idx].desc & 0xFF) { +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("Cannot allocate RX ring\n")); +			return -ENOMEM; +		} + +		memset(rtlpci->rx_ring[rx_queue_idx].desc, 0, +		       sizeof(*rtlpci->rx_ring[rx_queue_idx].desc) * +		       rtlpci->rxringcount); + +		rtlpci->rx_ring[rx_queue_idx].idx = 0; + +		for (i = 0; i < rtlpci->rxringcount; i++) { +			struct sk_buff *skb = +			    dev_alloc_skb(rtlpci->rxbuffersize); +			u32 bufferaddress; +			entry = &rtlpci->rx_ring[rx_queue_idx].desc[i]; +			if (!skb) +				return 0; + +			/*skb->dev = dev; */ + +			rtlpci->rx_ring[rx_queue_idx].rx_buf[i] = 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 = cpu_to_le32(*((dma_addr_t *)skb->cb)); +			rtlpriv->cfg->ops->set_desc((u8 *)entry, false, +						    HW_DESC_RXBUFF_ADDR, +						    (u8 *)&bufferaddress); +			rtlpriv->cfg->ops->set_desc((u8 *)entry, false, +						    HW_DESC_RXPKT_LEN, +						    (u8 *)&rtlpci-> +						    rxbuffersize); +			rtlpriv->cfg->ops->set_desc((u8 *) entry, false, +						    HW_DESC_RXOWN, +						    (u8 *)&tmp_one); +		} + +		rtlpriv->cfg->ops->set_desc((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]; + +	while (skb_queue_len(&ring->queue)) { +		struct rtl_tx_desc *entry = &ring->desc[ring->idx]; +		struct sk_buff *skb = __skb_dequeue(&ring->queue); + +		pci_unmap_single(rtlpci->pdev, +				 le32_to_cpu(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; +	} + +	pci_free_consistent(rtlpci->pdev, +			    sizeof(*ring->desc) * ring->entries, +			    ring->desc, ring->dma); +	ring->desc = NULL; +} + +static void _rtl_pci_free_rx_ring(struct rtl_pci *rtlpci) +{ +	int i, rx_queue_idx; + +	/*rx_queue_idx 0:RX_MPDU_QUEUE */ +	/*rx_queue_idx 1:RX_CMD_QUEUE */ +	for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE; +	     rx_queue_idx++) { +		for (i = 0; i < rtlpci->rxringcount; i++) { +			struct sk_buff *skb = +			    rtlpci->rx_ring[rx_queue_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); +		} + +		pci_free_consistent(rtlpci->pdev, +				    sizeof(*rtlpci->rx_ring[rx_queue_idx]. +					   desc) * rtlpci->rxringcount, +				    rtlpci->rx_ring[rx_queue_idx].desc, +				    rtlpci->rx_ring[rx_queue_idx].dma); +		rtlpci->rx_ring[rx_queue_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; + +	ret = _rtl_pci_init_rx_ring(hw); +	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: +	_rtl_pci_free_rx_ring(rtlpci); + +	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) +		if (rtlpci->tx_ring[i].desc) +			_rtl_pci_free_tx_ring(hw, i); + +	return 1; +} + +static int _rtl_pci_deinit_trx_ring(struct ieee80211_hw *hw) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u32 i; + +	/*free rx rings */ +	_rtl_pci_free_rx_ring(rtlpci); + +	/*free tx rings */ +	for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) +		_rtl_pci_free_tx_ring(hw, i); + +	return 0; +} + +int rtl_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, rx_queue_idx; +	unsigned long flags; +	u8 tmp_one = 1; + +	/*rx_queue_idx 0:RX_MPDU_QUEUE */ +	/*rx_queue_idx 1:RX_CMD_QUEUE */ +	for (rx_queue_idx = 0; rx_queue_idx < RTL_PCI_MAX_RX_QUEUE; +	     rx_queue_idx++) { +		/* +		 *force the rx_ring[RX_MPDU_QUEUE/ +		 *RX_CMD_QUEUE].idx to the first one +		 */ +		if (rtlpci->rx_ring[rx_queue_idx].desc) { +			struct rtl_rx_desc *entry = NULL; + +			for (i = 0; i < rtlpci->rxringcount; i++) { +				entry = &rtlpci->rx_ring[rx_queue_idx].desc[i]; +				rtlpriv->cfg->ops->set_desc((u8 *) entry, +							    false, +							    HW_DESC_RXOWN, +							    (u8 *)&tmp_one); +			} +			rtlpci->rx_ring[rx_queue_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) { +			struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i]; + +			while (skb_queue_len(&ring->queue)) { +				struct rtl_tx_desc *entry = +				    &ring->desc[ring->idx]; +				struct sk_buff *skb = +				    __skb_dequeue(&ring->queue); + +				pci_unmap_single(rtlpci->pdev, +						 le32_to_cpu(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; +} + +unsigned int _rtl_mac_to_hwqueue(u16 fc, +		unsigned int mac80211_queue_index) +{ +	unsigned int hw_queue_index; + +	if (unlikely(ieee80211_is_beacon(fc))) { +		hw_queue_index = BEACON_QUEUE; +		goto out; +	} + +	if (ieee80211_is_mgmt(fc)) { +		hw_queue_index = MGNT_QUEUE; +		goto out; +	} + +	switch (mac80211_queue_index) { +	case 0: +		hw_queue_index = VO_QUEUE; +		break; +	case 1: +		hw_queue_index = VI_QUEUE; +		break; +	case 2: +		hw_queue_index = BE_QUEUE;; +		break; +	case 3: +		hw_queue_index = BK_QUEUE; +		break; +	default: +		hw_queue_index = BE_QUEUE; +		RT_ASSERT(false, ("QSLT_BE queue, skb_queue:%d\n", +				  mac80211_queue_index)); +		break; +	} + +out: +	return hw_queue_index; +} + +int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +	struct rtl8192_tx_ring *ring; +	struct rtl_tx_desc *pdesc; +	u8 idx; +	unsigned int queue_index, hw_queue; +	unsigned long flags; +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); +	u16 fc = le16_to_cpu(hdr->frame_control); +	u8 *pda_addr = hdr->addr1; +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	/*ssn */ +	u8 *qc = NULL; +	u8 tid = 0; +	u16 seq_number = 0; +	u8 own; +	u8 temp_one = 1; + +	if (ieee80211_is_mgmt(fc)) +		rtl_tx_mgmt_proc(hw, skb); +	rtl_action_proc(hw, skb, true); + +	queue_index = skb_get_queue_mapping(skb); +	hw_queue = _rtl_mac_to_hwqueue(fc, queue_index); + +	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) +		idx = (ring->idx + skb_queue_len(&ring->queue)) % +				ring->entries; +	else +		idx = 0; + +	pdesc = &ring->desc[idx]; +	own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, +			true, HW_DESC_OWN); + +	if ((own == 1) && (hw_queue != BEACON_QUEUE)) { +		RT_TRACE(rtlpriv, 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_nullfunc(fc)) { +	 *      spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); +	 *      return 1; +	 *} +	 */ + +	if (ieee80211_is_data_qos(fc)) { +		qc = ieee80211_get_qos_ctl(hdr); +		tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + +		seq_number = mac->tids[tid].seq_number; +		seq_number &= IEEE80211_SCTL_SEQ; +		/* +		 *hdr->seq_ctrl = hdr->seq_ctrl & +		 *cpu_to_le16(IEEE80211_SCTL_FRAG); +		 *hdr->seq_ctrl |= cpu_to_le16(seq_number); +		 */ + +		seq_number += 1; +	} + +	if (ieee80211_is_data(fc)) +		rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); + +	rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, +					info, skb, hw_queue); + +	__skb_queue_tail(&ring->queue, skb); + +	rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, +				    HW_DESC_OWN, (u8 *)&temp_one); + +	if (!ieee80211_has_morefrags(hdr->frame_control)) { +		if (qc) +			mac->tids[tid].seq_number = seq_number; +	} + +	if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && +	    hw_queue != BEACON_QUEUE) { + +		RT_TRACE(rtlpriv, 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); + +	rtlpriv->cfg->ops->tx_polling(hw, hw_queue); + +	return 0; +} + +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); + +} + +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(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("tx ring initialization failed")); +		return err; +	} + +	return 1; +} + +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_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	int err; + +	rtl_pci_reset_trx_ring(hw); + +	rtlpci->driver_is_goingto_unload = false; +	err = rtlpriv->cfg->ops->hw_init(hw); +	if (err) { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, +			 ("Failed to config hardware!\n")); +		return err; +	} + +	rtlpriv->cfg->ops->enable_interrupt(hw); +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("enable_interrupt OK\n")); + +	rtl_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); + +	rtlpci->up_first_time = false; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("OK\n")); +	return 0; +} + +void rtl_pci_stop(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	unsigned long flags; +	u8 RFInProgressTimeOut = 0; + +	/* +	 *should before disable interrrupt&adapter +	 *and will do it immediately. +	 */ +	set_hal_stop(rtlhal); + +	rtlpriv->cfg->ops->disable_interrupt(hw); + +	spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); +	while (ppsc->rfchange_inprogress) { +		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags); +		if (RFInProgressTimeOut > 100) { +			spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); +			break; +		} +		mdelay(1); +		RFInProgressTimeOut++; +		spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); +	} +	ppsc->rfchange_inprogress = true; +	spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags); + +	rtlpci->driver_is_goingto_unload = true; +	rtlpriv->cfg->ops->hw_disable(hw); +	rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); + +	spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); +	ppsc->rfchange_inprogress = false; +	spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags); + +	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(rtlpriv, COMP_INIT, DBG_DMESG, +				 ("8192 PCI-E is found - " +				  "vid/did=%x/%x\n", venderid, deviceid)); +			rtlhal->hw_type = HARDWARE_TYPE_RTL8192E; +			break; +		case RTL_PCI_REVISION_ID_8192SE: +			RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, +				 ("8192SE is found - " +				  "vid/did=%x/%x\n", venderid, deviceid)); +			rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE; +			break; +		default: +			RT_TRACE(rtlpriv, 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_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(rtlpriv, COMP_INIT, DBG_DMESG, +			 ("8192C PCI-E is found - " +			  "vid/did=%x/%x\n", venderid, deviceid)); +	} else { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("Err: Unknown device -" +			  " vid/did=%x/%x\n", venderid, deviceid)); + +		rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE; +	} + +	/*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_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(rtlpriv, 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.pcibridge_pciehdr_offset = +		    bridge_pdev->pcie_cap; +		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.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(rtlpriv, 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(rtlpriv, 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); + +	return true; +} + +int __devinit 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), &rtl_ops); +	if (!hw) { +		RT_ASSERT(false, +			  ("%s : ieee80211 alloc failed\n", pci_name(pdev))); +		err = -ENOMEM; +		goto fail1; +	} + +	SET_IEEE80211_DEV(hw, &pdev->dev); +	pci_set_drvdata(pdev, hw); + +	rtlpriv = hw->priv; +	pcipriv = (void *)rtlpriv->priv; +	pcipriv->dev.pdev = pdev; + +	/* +	 *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 +	 */ +	rtl_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, 2); +	pmem_len = pci_resource_len(pdev, 2); +	pmem_flags = pci_resource_flags(pdev, 2); + +	/*shared mem start */ +	rtlpriv->io.pci_mem_start = +			(unsigned long)pci_iomap(pdev, 2, pmem_len); +	if (rtlpriv->io.pci_mem_start == 0) { +		RT_ASSERT(false, ("Can't map PCI mem\n")); +		goto fail2; +	} + +	RT_TRACE(rtlpriv, 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); + +	/* init cfg & intf_ops */ +	rtlpriv->rtlhal.interface = INTF_PCI; +	rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); +	rtlpriv->intf_ops = &rtl_pci_ops; + +	/* find adapter */ +	_rtl_pci_find_adapter(pdev, hw); + +	/* 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(rtlpriv, 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 = rtl_init_core(hw); +	if (err) { +		RT_TRACE(rtlpriv, 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(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("Failed to init PCI.\n")); +		goto fail3; +	} + +	err = ieee80211_register_hw(hw); +	if (err) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("Can't register mac80211 hw.\n")); +		goto fail3; +	} else { +		rtlpriv->mac80211.mac80211_registered = 1; +	} + +	err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group); +	if (err) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("failed to create sysfs device attributes\n")); +		goto fail3; +	} + +	/*init rfkill */ +	rtl_init_rfkill(hw); + +	rtlpci = rtl_pcidev(pcipriv); +	err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, +			  IRQF_SHARED, KBUILD_MODNAME, hw); +	if (err) { +		RT_TRACE(rtlpriv, 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); +	rtl_deinit_core(hw); +	_rtl_pci_io_handler_release(hw); +	ieee80211_free_hw(hw); + +	if (rtlpriv->io.pci_mem_start != 0) +		pci_iounmap(pdev, (void *)rtlpriv->io.pci_mem_start); + +fail2: +	pci_release_regions(pdev); + +fail1: + +	pci_disable_device(pdev); + +	return -ENODEV; + +} +EXPORT_SYMBOL(rtl_pci_probe); + +void 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); + +	sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group); + +	/*ieee80211_unregister_hw will call ops_stop */ +	if (rtlmac->mac80211_registered == 1) { +		ieee80211_unregister_hw(hw); +		rtlmac->mac80211_registered = 0; +	} else { +		rtl_deinit_deferred_work(hw); +		rtlpriv->intf_ops->adapter_stop(hw); +	} + +	/*deinit rfkill */ +	rtl_deinit_rfkill(hw); + +	rtl_pci_deinit(hw); +	rtl_deinit_core(hw); +	rtlpriv->cfg->ops->deinit_sw_leds(hw); +	_rtl_pci_io_handler_release(hw); +	rtlpriv->cfg->ops->deinit_sw_vars(hw); + +	if (rtlpci->irq_alloc) { +		free_irq(rtlpci->pdev->irq, hw); +		rtlpci->irq_alloc = 0; +	} + +	if (rtlpriv->io.pci_mem_start != 0) { +		pci_iounmap(pdev, (void *)rtlpriv->io.pci_mem_start); +		pci_release_regions(pdev); +	} + +	pci_disable_device(pdev); +	pci_set_drvdata(pdev, NULL); + +	ieee80211_free_hw(hw); +} +EXPORT_SYMBOL(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 rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ +	pci_save_state(pdev); +	pci_disable_device(pdev); +	pci_set_power_state(pdev, PCI_D3hot); + +	return 0; +} +EXPORT_SYMBOL(rtl_pci_suspend); + +int rtl_pci_resume(struct pci_dev *pdev) +{ +	int ret; + +	pci_set_power_state(pdev, PCI_D0); +	ret = pci_enable_device(pdev); +	if (ret) { +		RT_ASSERT(false, ("ERR: <======\n")); +		return ret; +	} + +	pci_restore_state(pdev); + +	return 0; +} +EXPORT_SYMBOL(rtl_pci_resume); + +struct rtl_intf_ops rtl_pci_ops = { +	.adapter_start = rtl_pci_start, +	.adapter_stop = rtl_pci_stop, +	.adapter_tx = rtl_pci_tx, +	.reset_trx_ring = rtl_pci_reset_trx_ring, + +	.disable_aspm = rtl_pci_disable_aspm, +	.enable_aspm = rtl_pci_enable_aspm, +}; diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h new file mode 100644 index 00000000000..cdde8583ad3 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -0,0 +1,302 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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			64 +#define RTL_PCI_MAX_TX_QUEUE_COUNT		9 + +#define RT_TXDESC_NUM				128 +#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_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	0x092D	/*8192ce */ +#define RTL_PCI_8192DU_DID	0x092D	/*8192ce */ + +/*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_rx_desc { +	u32 dword[8]; +} __attribute__ ((packed)); + +struct rtl_tx_desc { +	u32 dword[16]; +} __attribute__ ((packed)); + +struct rtl_tx_cmd_desc { +	u32 dword[16]; +} __attribute__ ((packed)); + +struct rtl8192_tx_ring { +	struct rtl_tx_desc *desc; +	dma_addr_t dma; +	unsigned int idx; +	unsigned int entries; +	struct sk_buff_head queue; +}; + +struct rtl8192_rx_ring { +	struct rtl_rx_desc *desc; +	dma_addr_t dma; +	unsigned int idx; +	struct sk_buff *rx_buf[RTL_PCI_MAX_RX_COUNT]; +}; + +struct rtl_pci { +	struct pci_dev *pdev; + +	bool driver_is_goingto_unload; +	bool up_first_time; +	bool being_init_adapter; +	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]; + +	/*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; +}; + +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; +}; + +#define rtl_pcipriv(hw)		(((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) +#define rtl_pcidev(pcipriv)	(&((pcipriv)->dev)) + +int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw); + +extern struct rtl_intf_ops rtl_pci_ops; + +int __devinit rtl_pci_probe(struct pci_dev *pdev, +			    const struct pci_device_id *id); +void rtl_pci_disconnect(struct pci_dev *pdev); +int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state); +int rtl_pci_resume(struct pci_dev *pdev); + +static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr) +{ +	return 0xff & readb((u8 *) rtlpriv->io.pci_mem_start + addr); +} + +static inline u16 pci_read16_sync(struct rtl_priv *rtlpriv, u32 addr) +{ +	return readw((u8 *) rtlpriv->io.pci_mem_start + addr); +} + +static inline u32 pci_read32_sync(struct rtl_priv *rtlpriv, u32 addr) +{ +	return readl((u8 *) rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) +{ +	writeb(val, (u8 *) rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write16_async(struct rtl_priv *rtlpriv, +				     u32 addr, u16 val) +{ +	writew(val, (u8 *) rtlpriv->io.pci_mem_start + addr); +} + +static inline void pci_write32_async(struct rtl_priv *rtlpriv, +				     u32 addr, u32 val) +{ +	writel(val, (u8 *) 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/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c new file mode 100644 index 00000000000..fd77cd508f5 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -0,0 +1,492 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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" + +bool 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(rtlpriv, 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> */ +	rtl_watch_dog_timer_callback((unsigned long)hw); + +	return init_status; +} +EXPORT_SYMBOL(rtl_ps_enable_nic); + +bool rtl_ps_disable_nic(struct ieee80211_hw *hw) +{ +	bool status = true; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	/*<1> Stop all timer */ +	rtl_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(rtl_ps_disable_nic); + +bool 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; +	unsigned long flag; + +	/*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_irqsave(&rtlpriv->locks.rf_ps_lock, flag); +		if (ppsc->rfchange_inprogress) { +			spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, +					       flag); + +			RT_TRACE(rtlpriv, 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_irqrestore(&rtlpriv->locks.rf_ps_lock, +					       flag); +			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 == true)) { +			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 == false)) { +			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(rtlpriv, 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_irqsave(&rtlpriv->locks.rf_ps_lock, flag); +		ppsc->rfchange_inprogress = false; +		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); +	} + +	return b_actionallowed; +} +EXPORT_SYMBOL(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_RF_OFF_LEVL_ASPM) && +		    rtlhal->interface == INTF_PCI) { +			rtlpriv->intf_ops->disable_aspm(hw); +			RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +		} +	} + +	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) { +			rtlpriv->intf_ops->enable_aspm(hw); +			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +		} +	} + +	ppsc->b_swrf_processing = false; +} + +void rtl_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(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("not station return\n")); +		return; +	} + +	if (is_hal_stop(rtlhal)) +		return; + +	if (rtlpriv->sec.being_setkey) +		return; + +	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(rtlpriv, COMP_RF, DBG_TRACE, +				 ("IPSEnter(): Turn off RF.\n")); + +			ppsc->inactive_pwrstate = ERFOFF; +			ppsc->b_in_powersavemode = true; + +			/*rtl_pci_reset_trx_ring(hw); */ +			_rtl_ps_inactive_ps(hw); +		} +	} +} + +void rtl_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)); +} + +void rtl_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; + +	down(&rtlpriv->locks.ips_sem); + +	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); +		} +	} + +	up(&rtlpriv->locks.ips_sem); +} + +/*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(rtlpriv, 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.*/ +static 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)); +	u8 rpwm_val, fw_pwrmode; + +	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->b_leisure_ps) && +	     ppsc->report_linked) { +		bool b_fw_current_inps; +		if (ppsc->dot11_psmode == EACTIVE) { +			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +				 ("FW LPS leave ps_mode:%x\n", +				  FW_PS_ACTIVE_MODE)); + +			rpwm_val = 0x0C;	/* RF on */ +			fw_pwrmode = FW_PS_ACTIVE_MODE; +			rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM, +					(u8 *) (&rpwm_val)); +			rtlpriv->cfg->ops->set_hw_reg(hw, +					HW_VAR_H2C_FW_PWRMODE, +					(u8 *) (&fw_pwrmode)); +			b_fw_current_inps = false; + +			rtlpriv->cfg->ops->set_hw_reg(hw, +					HW_VAR_FW_PSMODE_STATUS, +					(u8 *) (&b_fw_current_inps)); + +		} else { +			if (rtl_get_fwlps_doze(hw)) { +				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +						("FW LPS enter ps_mode:%x\n", +						 ppsc->fwctrl_psmode)); + +				rpwm_val = 0x02;	/* RF off */ +				b_fw_current_inps = true; +				rtlpriv->cfg->ops->set_hw_reg(hw, +						HW_VAR_FW_PSMODE_STATUS, +						(u8 *) (&b_fw_current_inps)); +				rtlpriv->cfg->ops->set_hw_reg(hw, +						HW_VAR_H2C_FW_PWRMODE, +						(u8 *) (&ppsc->fwctrl_psmode)); + +				rtlpriv->cfg->ops->set_hw_reg(hw, +						HW_VAR_SET_RPWM, +						(u8 *) (&rpwm_val)); +			} else { +				/* Reset the power save related parameters. */ +				ppsc->dot11_psmode = EACTIVE; +			} +		} +	} +} + +/*Enter the leisure power save mode.*/ +void rtl_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 && ppsc->b_leisure_ps)) +		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); + +	if (ppsc->b_leisure_ps) { +		/* 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(rtlpriv, 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); +} + +/*Leave the leisure power save mode.*/ +void rtl_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 && ppsc->b_leisure_ps) { +		if (ppsc->dot11_psmode != EACTIVE) { + +			/*FIX ME */ +			rtlpriv->cfg->ops->enable_interrupt(hw); + +			if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && +			    RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) && +			    rtlhal->interface == INTF_PCI) { +				rtlpriv->intf_ops->disable_aspm(hw); +				RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM); +			} + +			RT_TRACE(rtlpriv, 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); +} diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h new file mode 100644 index 00000000000..ae56da801a2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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__ + +bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, +			 enum rf_pwrstate state_toset, u32 changesource, +			 bool protect_or_not); +bool rtl_ps_enable_nic(struct ieee80211_hw *hw); +bool rtl_ps_disable_nic(struct ieee80211_hw *hw); +void rtl_ips_nic_off(struct ieee80211_hw *hw); +void rtl_ips_nic_on(struct ieee80211_hw *hw); +void rtl_ips_nic_off_wq_callback(void *data); +void rtl_lps_enter(struct ieee80211_hw *hw); +void rtl_lps_leave(struct ieee80211_hw *hw); +#endif diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c new file mode 100644 index 00000000000..904b8fd01f6 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -0,0 +1,329 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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 + *CCK11M or OFDM_54M based on wireless mode. + */ +static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, +				  struct sk_buff *skb, bool not_data) +{ +	struct rtl_mac *rtlmac = rtl_mac(rtlpriv); + +	/* +	 *mgt use 1M, although we have check it +	 *before this function use rate_control_send_low, +	 *we still check it here +	 */ +	if (not_data) +		return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + +	/* +	 *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 rtl_get_tcb_desc when we check rate is +	 *      1M we will not use FW rate but user rate. +	 */ +	if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true)) { +		return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; +	} else { +		if (rtlmac->mode == WIRELESS_MODE_B) +			return rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; +		else +			return rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; +	} +} + +static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, +				    struct ieee80211_tx_rate *rate, +				    struct ieee80211_tx_rate_control *txrc, +				    u8 tries, u8 rix, int rtsctsenable, +				    bool not_data) +{ +	struct rtl_mac *mac = rtl_mac(rtlpriv); + +	rate->count = tries; +	rate->idx = (rix > 0x2) ? rix : 0x2; + +	if (!not_data) { +		if (txrc->short_preamble) +			rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; +		if (mac->bw_40) +			rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; +		if (mac->sgi_20 || mac->sgi_40) +			rate->flags |= IEEE80211_TX_RC_SHORT_GI; +		if (mac->ht_enable) +			rate->flags |= IEEE80211_TX_RC_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; +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; +	__le16 fc = hdr->frame_control; +	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, skb, not_data); + +	try_per_rate = 1; +	_rtl_rc_rate_set_series(rtlpriv, &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, &rates[i], +						txrc, i, (rix - i), 1, +						not_data); +	} +} + +static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, u16 tid) +{ +	struct rtl_mac *mac = rtl_mac(rtlpriv); + +	if (mac->act_scanning) +		return false; + +	if (mac->cnt_after_linked < 3) +		return false; + +	if (mac->tids[tid].agg.agg_state == RTL_AGG_OFF) +		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; +	__le16 fc; + +	hdr = (struct ieee80211_hdr *)skb->data; +	fc = hdr->frame_control; + +	if (!priv_sta || !ieee80211_is_data(fc)) +		return; + +	if (rtl_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; + +	/* Check if aggregation has to be enabled for this tid */ +	if (conf_is_ht(&mac->hw->conf) && +	    !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { +		if (ieee80211_is_data_qos(fc)) { +			u8 *qc, tid; + +			qc = ieee80211_get_qos_ctl(hdr); +			tid = qc[0] & 0xf; + +			if (_rtl_tx_aggr_check(rtlpriv, tid)) +				ieee80211_start_tx_ba_session(sta, tid); +		} +	} +} + +static void rtl_rate_init(void *ppriv, +			  struct ieee80211_supported_band *sband, +			  struct ieee80211_sta *sta, void *priv_sta) +{ +	struct rtl_priv *rtlpriv = ppriv; +	struct rtl_mac *mac = rtl_mac(rtlpriv); +	u8 is_ht = conf_is_ht(&mac->hw->conf); + +	if ((mac->opmode == NL80211_IFTYPE_STATION) || +	    (mac->opmode == NL80211_IFTYPE_MESH_POINT) || +	    (mac->opmode == NL80211_IFTYPE_ADHOC)) { + +		switch (sband->band) { +		case IEEE80211_BAND_2GHZ: +			rtlpriv->rate_priv->cur_ratetab_idx = +			    RATR_INX_WIRELESS_G; +			if (is_ht) +				rtlpriv->rate_priv->cur_ratetab_idx = +				    RATR_INX_WIRELESS_NGB; +			break; +		case IEEE80211_BAND_5GHZ: +			rtlpriv->rate_priv->cur_ratetab_idx = +			    RATR_INX_WIRELESS_A; +			if (is_ht) +				rtlpriv->rate_priv->cur_ratetab_idx = +				    RATR_INX_WIRELESS_NGB; +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +				 ("Invalid band\n")); +			rtlpriv->rate_priv->cur_ratetab_idx = +			    RATR_INX_WIRELESS_NGB; +			break; +		} + +		RT_TRACE(rtlpriv, COMP_RATE, DBG_DMESG, +			 ("Choosing rate table index: %d\n", +			  rtlpriv->rate_priv->cur_ratetab_idx)); + +	} + +} + +static void rtl_rate_update(void *ppriv, +			    struct ieee80211_supported_band *sband, +			    struct ieee80211_sta *sta, void *priv_sta, +			    u32 changed, +			    enum nl80211_channel_type oper_chan_type) +{ +	struct rtl_priv *rtlpriv = ppriv; +	struct rtl_mac *mac = rtl_mac(rtlpriv); +	struct rtl_hal *rtlhal = rtl_hal(rtlpriv); +	bool oper_cw40 = false, oper_sgi40; +	bool local_cw40 = mac->bw_40; +	bool local_sgi40 = mac->sgi_40; +	u8 is_ht = conf_is_ht(&mac->hw->conf); + +	if (changed & IEEE80211_RC_HT_CHANGED) { +		if (mac->opmode != NL80211_IFTYPE_STATION) +			return; + +		if (rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || +		    rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) +			oper_cw40 = true; + +		oper_sgi40 = mac->sgi_40; + +		if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { +			switch (sband->band) { +			case IEEE80211_BAND_2GHZ: +				rtlpriv->rate_priv->cur_ratetab_idx = +				    RATR_INX_WIRELESS_G; +				if (is_ht) +					rtlpriv->rate_priv->cur_ratetab_idx = +					    RATR_INX_WIRELESS_NGB; +				break; +			case IEEE80211_BAND_5GHZ: +				rtlpriv->rate_priv->cur_ratetab_idx = +				    RATR_INX_WIRELESS_A; +				if (is_ht) +					rtlpriv->rate_priv->cur_ratetab_idx = +					    RATR_INX_WIRELESS_NGB; +				break; +			default: +				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +					 ("Invalid band\n")); +				rtlpriv->rate_priv->cur_ratetab_idx = +				    RATR_INX_WIRELESS_NGB; +				break; +			} +		} +	} +} + +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(struct rtl_rate_priv), gfp); +	if (!rate_priv) { +		RT_TRACE(rtlpriv, 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 = { +	.module = NULL, +	.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, +	.rate_update = rtl_rate_update, +	.tx_status = rtl_tx_status, +	.get_rate = rtl_get_rate, +}; + +int rtl_rate_control_register(void) +{ +	return ieee80211_rate_control_register(&rtl_rate_ops); +} + +void rtl_rate_control_unregister(void) +{ +	ieee80211_rate_control_unregister(&rtl_rate_ops); +} diff --git a/drivers/net/wireless/rtlwifi/rc.h b/drivers/net/wireless/rtlwifi/rc.h new file mode 100644 index 00000000000..b4667c035f0 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rc.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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__ + +struct rtl_rate_priv { +	u8 cur_ratetab_idx; +	u8 ht_cap; +}; + +int rtl_rate_control_register(void); +void rtl_rate_control_unregister(void); +#endif diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c new file mode 100644 index 00000000000..3336ca999df --- /dev/null +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -0,0 +1,400 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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) + +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_global = { +	.n_reg_rules = 3, +	.alpha2 = "99", +	.reg_rules = { +		      RTL819x_2GHZ_CH01_11, +		      RTL819x_2GHZ_CH12_13, +		      RTL819x_2GHZ_CH14, +	} +}; + +static const struct ieee80211_regdomain rtl_regdom_world = { +	.n_reg_rules = 2, +	.alpha2 = "99", +	.reg_rules = { +		      RTL819x_2GHZ_CH01_11, +		      RTL819x_2GHZ_CH12_13, +	} +}; + +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; +	u32 bandwidth = 0; +	int r; + +	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) { +				r = freq_reg_info(wiphy, ch->center_freq, +						  bandwidth, ®_rule); +				if (r) +					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; +	u32 bandwidth = 0; +	int r; + +	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 */ +	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); +	if (!r) { +		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 */ +	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); +	if (!r) { +		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 _rtl_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: +	case COUNTRY_CODE_IC: +		return &rtl_regdom_11; +	case COUNTRY_CODE_ETSI: +	case COUNTRY_CODE_SPAIN: +	case COUNTRY_CODE_FRANCE: +	case COUNTRY_CODE_ISRAEL: +	case COUNTRY_CODE_TELEC_NETGEAR: +		return &rtl_regdom_world; +	case COUNTRY_CODE_MKK: +	case COUNTRY_CODE_MKK1: +	case COUNTRY_CODE_TELEC: +	case COUNTRY_CODE_MIC: +		return &rtl_regdom_global; +	case COUNTRY_CODE_GLOBAL_DOMAIN: +		return &rtl_regdom_global; +	case COUNTRY_CODE_WORLD_WIDE_13: +		return &rtl_regdom_world; +	default: +		return &rtl_regdom_world; +	} +} + +static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, +				struct wiphy *wiphy, +				int (*reg_notifier) (struct wiphy *wiphy, +						     struct regulatory_request * +						     request)) +{ +	const struct ieee80211_regdomain *regd; + +	wiphy->reg_notifier = reg_notifier; +	wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; +	wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; +	wiphy->flags &= ~WIPHY_FLAG_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 rtl_regd_init(struct ieee80211_hw *hw, +		  int (*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; + +	/* force the channel plan to world wide 13 */ +	rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; + +	RT_TRACE(rtlpriv, 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(rtlpriv, COMP_REGD, DBG_DMESG, +			 (KERN_DEBUG "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->isoName[0]; +		rtlpriv->regd.alpha2[1] = country->isoName[1]; +	} else { +		rtlpriv->regd.alpha2[0] = '0'; +		rtlpriv->regd.alpha2[1] = '0'; +	} + +	RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, +		 (KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n", +		  rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1])); + +	_rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier); + +	return 0; +} + +int rtl_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(rtlpriv, COMP_REGD, DBG_LOUD, ("\n")); + +	return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd); +} diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h new file mode 100644 index 00000000000..4cdbc4ae76d --- /dev/null +++ b/drivers/net/wireless/rtlwifi/regd.h @@ -0,0 +1,61 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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__ + +struct country_code_to_enum_rd { +	u16 countrycode; +	const char *isoName; +}; + +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 rtl_regd_init(struct ieee80211_hw *hw, +		  int (*reg_notifier) (struct wiphy *wiphy, +				       struct regulatory_request *request)); +int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/Makefile b/drivers/net/wireless/rtlwifi/rtl8192ce/Makefile new file mode 100644 index 00000000000..f3d7682ff08 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/Makefile @@ -0,0 +1,12 @@ +rtl8192ce-objs :=		\ +	rtl8192c-dm.o		\ +	rtl8192c-fw.o		\ +	rtl8192c-hw.o		\ +	rtl8192c-led.o		\ +	rtl8192c-phy.o		\ +	rtl8192c-rf.o		\ +	rtl8192c-sw.o		\ +	rtl8192c-table.o	\ +	rtl8192c-trx.o + +obj-$(CONFIG_RTL8192CE) += rtl8192ce.o diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-def.h new file mode 100644 index 00000000000..83cd6489529 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-def.h @@ -0,0 +1,257 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92C_DEF_H__ +#define __RTL92C_DEF_H__ + +#define HAL_RETRY_LIMIT_INFRA				48 +#define HAL_RETRY_LIMIT_AP_ADHOC			7 + +#define	PHY_RSSI_SLID_WIN_MAX				100 +#define	PHY_LINKQUALITY_SLID_WIN_MAX			20 +#define	PHY_BEACON_RSSI_SLID_WIN_MAX			10 + +#define RESET_DELAY_8185				20 + +#define RT_IBSS_INT_MASKS	(IMR_BCNINT | IMR_TBDOK | IMR_TBDER) +#define RT_AC_INT_MASKS		(IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK) + +#define NUM_OF_FIRMWARE_QUEUE				10 +#define NUM_OF_PAGES_IN_FW				0x100 +#define NUM_OF_PAGE_IN_FW_QUEUE_BK			0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE			0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI			0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO			0x07 +#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA			0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_CMD			0x0 +#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT			0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH			0x02 +#define NUM_OF_PAGE_IN_FW_QUEUE_BCN			0x2 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB			0xA1 + +#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM			0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM			0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM			0x048 +#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM			0x026 +#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM			0x00 + +#define MAX_LINES_HWCONFIG_TXT				1000 +#define MAX_BYTES_LINE_HWCONFIG_TXT			256 + +#define SW_THREE_WIRE					0 +#define HW_THREE_WIRE					2 + +#define BT_DEMO_BOARD					0 +#define BT_QA_BOARD					1 +#define BT_FPGA						2 + +#define RX_SMOOTH_FACTOR				20 + +#define HAL_PRIME_CHNL_OFFSET_DONT_CARE			0 +#define HAL_PRIME_CHNL_OFFSET_LOWER			1 +#define HAL_PRIME_CHNL_OFFSET_UPPER			2 + +#define MAX_H2C_QUEUE_NUM				10 + +#define RX_MPDU_QUEUE					0 +#define RX_CMD_QUEUE					1 +#define RX_MAX_QUEUE					2 +#define AC2QUEUEID(_AC)					(_AC) + +#define	C2H_RX_CMD_HDR_LEN				8 +#define	GET_C2H_CMD_CMD_LEN(__prxhdr)		\ +	LE_BITS_TO_4BYTE((__prxhdr), 0, 16) +#define	GET_C2H_CMD_ELEMENT_ID(__prxhdr)	\ +	LE_BITS_TO_4BYTE((__prxhdr), 16, 8) +#define	GET_C2H_CMD_CMD_SEQ(__prxhdr)		\ +	LE_BITS_TO_4BYTE((__prxhdr), 24, 7) +#define	GET_C2H_CMD_CONTINUE(__prxhdr)		\ +	LE_BITS_TO_4BYTE((__prxhdr), 31, 1) +#define	GET_C2H_CMD_CONTENT(__prxhdr)		\ +	((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN) + +#define	GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr)	\ +	LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8) +#define	GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr)	\ +	LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8) +#define	GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr)	\ +	LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16) +#define	GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr)	\ +	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5) +#define	GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr)	\ +	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1) +#define	GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr)	\ +	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5) +#define	GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr)	\ +	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1) +#define	GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr)	\ +	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4) +#define	GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr)	\ +	LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12) + +#define CHIP_VER_B			BIT(4) +#define CHIP_92C_BITMASK		BIT(0) +#define CHIP_92C_1T2R			0x03 +#define CHIP_92C			0x01 +#define CHIP_88C			0x00 + +enum version_8192c { +	VERSION_A_CHIP_92C = 0x01, +	VERSION_A_CHIP_88C = 0x00, +	VERSION_B_CHIP_92C = 0x11, +	VERSION_B_CHIP_88C = 0x10, +	VERSION_UNKNOWN = 0x88, +}; + +#define IS_CHIP_VER_B(version)  ((version & CHIP_VER_B) ? true : false) +#define IS_92C_SERIAL(version)  ((version & CHIP_92C_BITMASK) ? true : false) + +enum rtl819x_loopback_e { +	RTL819X_NO_LOOPBACK = 0, +	RTL819X_MAC_LOOPBACK = 1, +	RTL819X_DMA_LOOPBACK = 2, +	RTL819X_CCK_LOOPBACK = 3, +}; + +enum rf_optype { +	RF_OP_BY_SW_3WIRE = 0, +	RF_OP_BY_FW, +	RF_OP_MAX +}; + +enum rf_power_state { +	RF_ON, +	RF_OFF, +	RF_SLEEP, +	RF_SHUT_DOWN, +}; + +enum power_save_mode { +	POWER_SAVE_MODE_ACTIVE, +	POWER_SAVE_MODE_SAVE, +}; + +enum power_polocy_config { +	POWERCFG_MAX_POWER_SAVINGS, +	POWERCFG_GLOBAL_POWER_SAVINGS, +	POWERCFG_LOCAL_POWER_SAVINGS, +	POWERCFG_LENOVO, +}; + +enum interface_select_pci { +	INTF_SEL1_MINICARD = 0, +	INTF_SEL0_PCIE = 1, +	INTF_SEL2_RSV = 2, +	INTF_SEL3_RSV = 3, +}; + +enum hal_fw_c2h_cmd_id { +	HAL_FW_C2H_CMD_Read_MACREG = 0, +	HAL_FW_C2H_CMD_Read_BBREG = 1, +	HAL_FW_C2H_CMD_Read_RFREG = 2, +	HAL_FW_C2H_CMD_Read_EEPROM = 3, +	HAL_FW_C2H_CMD_Read_EFUSE = 4, +	HAL_FW_C2H_CMD_Read_CAM = 5, +	HAL_FW_C2H_CMD_Get_BasicRate = 6, +	HAL_FW_C2H_CMD_Get_DataRate = 7, +	HAL_FW_C2H_CMD_Survey = 8, +	HAL_FW_C2H_CMD_SurveyDone = 9, +	HAL_FW_C2H_CMD_JoinBss = 10, +	HAL_FW_C2H_CMD_AddSTA = 11, +	HAL_FW_C2H_CMD_DelSTA = 12, +	HAL_FW_C2H_CMD_AtimDone = 13, +	HAL_FW_C2H_CMD_TX_Report = 14, +	HAL_FW_C2H_CMD_CCX_Report = 15, +	HAL_FW_C2H_CMD_DTM_Report = 16, +	HAL_FW_C2H_CMD_TX_Rate_Statistics = 17, +	HAL_FW_C2H_CMD_C2HLBK = 18, +	HAL_FW_C2H_CMD_C2HDBG = 19, +	HAL_FW_C2H_CMD_C2HFEEDBACK = 20, +	HAL_FW_C2H_CMD_MAX +}; + +enum rtl_desc_qsel { +	QSLT_BK = 0x2, +	QSLT_BE = 0x0, +	QSLT_VI = 0x5, +	QSLT_VO = 0x7, +	QSLT_BEACON = 0x10, +	QSLT_HIGH = 0x11, +	QSLT_MGNT = 0x12, +	QSLT_CMD = 0x13, +}; + +enum rtl_desc92c_rate { +	DESC92C_RATE1M = 0x00, +	DESC92C_RATE2M = 0x01, +	DESC92C_RATE5_5M = 0x02, +	DESC92C_RATE11M = 0x03, + +	DESC92C_RATE6M = 0x04, +	DESC92C_RATE9M = 0x05, +	DESC92C_RATE12M = 0x06, +	DESC92C_RATE18M = 0x07, +	DESC92C_RATE24M = 0x08, +	DESC92C_RATE36M = 0x09, +	DESC92C_RATE48M = 0x0a, +	DESC92C_RATE54M = 0x0b, + +	DESC92C_RATEMCS0 = 0x0c, +	DESC92C_RATEMCS1 = 0x0d, +	DESC92C_RATEMCS2 = 0x0e, +	DESC92C_RATEMCS3 = 0x0f, +	DESC92C_RATEMCS4 = 0x10, +	DESC92C_RATEMCS5 = 0x11, +	DESC92C_RATEMCS6 = 0x12, +	DESC92C_RATEMCS7 = 0x13, +	DESC92C_RATEMCS8 = 0x14, +	DESC92C_RATEMCS9 = 0x15, +	DESC92C_RATEMCS10 = 0x16, +	DESC92C_RATEMCS11 = 0x17, +	DESC92C_RATEMCS12 = 0x18, +	DESC92C_RATEMCS13 = 0x19, +	DESC92C_RATEMCS14 = 0x1a, +	DESC92C_RATEMCS15 = 0x1b, +	DESC92C_RATEMCS15_SG = 0x1c, +	DESC92C_RATEMCS32 = 0x20, +}; + +struct phy_sts_cck_8192s_t { +	u8 adc_pwdb_X[4]; +	u8 sq_rpt; +	u8 cck_agc_rpt; +}; + +struct h2c_cmd_8192c { +	u8 element_id; +	u32 cmd_len; +	u8 *p_cmdbuffer; +}; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-dm.c new file mode 100644 index 00000000000..4896899394a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-dm.c @@ -0,0 +1,1473 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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 "rtl8192c-reg.h" +#include "rtl8192c-def.h" +#include "rtl8192c-phy.h" +#include "rtl8192c-dm.h" +#include "rtl8192c-fw.h" + +struct dig_t dm_digtable; +static struct ps_t dm_pstable; + +static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = { +	0x7f8001fe, +	0x788001e2, +	0x71c001c7, +	0x6b8001ae, +	0x65400195, +	0x5fc0017f, +	0x5a400169, +	0x55400155, +	0x50800142, +	0x4c000130, +	0x47c0011f, +	0x43c0010f, +	0x40000100, +	0x3c8000f2, +	0x390000e4, +	0x35c000d7, +	0x32c000cb, +	0x300000c0, +	0x2d4000b5, +	0x2ac000ab, +	0x288000a2, +	0x26000098, +	0x24000090, +	0x22000088, +	0x20000080, +	0x1e400079, +	0x1c800072, +	0x1b00006c, +	0x19800066, +	0x18000060, +	0x16c0005b, +	0x15800056, +	0x14400051, +	0x1300004c, +	0x12000048, +	0x11000044, +	0x10000040, +}; + +static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = { +	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, +	{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, +	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, +	{0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, +	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, +	{0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, +	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, +	{0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, +	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, +	{0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, +	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, +	{0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, +	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, +	{0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, +	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, +	{0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, +	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, +	{0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, +	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, +	{0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, +	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, +	{0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, +	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, +	{0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, +	{0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, +	{0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, +	{0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, +	{0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, +	{0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, +	{0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, +	{0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, +	{0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, +	{0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} +}; + +static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = { +	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, +	{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, +	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, +	{0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, +	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, +	{0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, +	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, +	{0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, +	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, +	{0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, +	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, +	{0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, +	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, +	{0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, +	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, +	{0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, +	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, +	{0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, +	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, +	{0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, +	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, +	{0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, +	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, +	{0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, +	{0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, +	{0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, +	{0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, +	{0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, +	{0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, +	{0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, +	{0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, +	{0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, +	{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} +}; + +static void rtl92c_dm_diginit(struct ieee80211_hw *hw) +{ +	dm_digtable.dig_enable_flag = true; +	dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; +	dm_digtable.cur_igvalue = 0x20; +	dm_digtable.pre_igvalue = 0x0; +	dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; +	dm_digtable.presta_connectstate = DIG_STA_DISCONNECT; +	dm_digtable.curmultista_connectstate = DIG_MULTISTA_DISCONNECT; +	dm_digtable.rssi_lowthresh = DM_DIG_THRESH_LOW; +	dm_digtable.rssi_highthresh = DM_DIG_THRESH_HIGH; +	dm_digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW; +	dm_digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH; +	dm_digtable.rx_gain_range_max = DM_DIG_MAX; +	dm_digtable.rx_gain_range_min = DM_DIG_MIN; +	dm_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; +	dm_digtable.backoff_val_range_max = DM_DIG_BACKOFF_MAX; +	dm_digtable.backoff_val_range_min = DM_DIG_BACKOFF_MIN; +	dm_digtable.pre_cck_pd_state = CCK_PD_STAGE_MAX; +	dm_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX; +} + +static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	long rssi_val_min = 0; + +	if ((dm_digtable.curmultista_connectstate == DIG_MULTISTA_CONNECT) && +	    (dm_digtable.cursta_connectctate == DIG_STA_CONNECT)) { +		if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb != 0) +			rssi_val_min = +			    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb > +			     rtlpriv->dm.undecorated_smoothed_pwdb) ? +			    rtlpriv->dm.undecorated_smoothed_pwdb : +			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +		else +			rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb; +	} else if (dm_digtable.cursta_connectctate == DIG_STA_CONNECT || +		   dm_digtable.cursta_connectctate == DIG_STA_BEFORE_CONNECT) { +		rssi_val_min = rtlpriv->dm.undecorated_smoothed_pwdb; +	} else if (dm_digtable.curmultista_connectstate == +		   DIG_MULTISTA_CONNECT) { +		rssi_val_min = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +	} + +	return (u8) rssi_val_min; +} + +static void rtl92c_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) +{ +	u32 ret_value; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt); + +	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD); +	falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16); + +	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD); +	falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff); +	falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16); + +	ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD); +	falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff); +	falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail + +	    falsealm_cnt->cnt_rate_illegal + +	    falsealm_cnt->cnt_crc8_fail + falsealm_cnt->cnt_mcs_fail; + +	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1); +	ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0); +	falsealm_cnt->cnt_cck_fail = ret_value; + +	ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3); +	falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8; +	falsealm_cnt->cnt_all = (falsealm_cnt->cnt_parity_fail + +				 falsealm_cnt->cnt_rate_illegal + +				 falsealm_cnt->cnt_crc8_fail + +				 falsealm_cnt->cnt_mcs_fail + +				 falsealm_cnt->cnt_cck_fail); + +	rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 1); +	rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 0); +	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 0); +	rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 2); + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 ("cnt_parity_fail = %d, cnt_rate_illegal = %d, " +		  "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n", +		  falsealm_cnt->cnt_parity_fail, +		  falsealm_cnt->cnt_rate_illegal, +		  falsealm_cnt->cnt_crc8_fail, falsealm_cnt->cnt_mcs_fail)); + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 ("cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n", +		  falsealm_cnt->cnt_ofdm_fail, +		  falsealm_cnt->cnt_cck_fail, falsealm_cnt->cnt_all)); +} + +static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 value_igi = dm_digtable.cur_igvalue; + +	if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0) +		value_igi--; +	else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH1) +		value_igi += 0; +	else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH2) +		value_igi++; +	else if (rtlpriv->falsealm_cnt.cnt_all >= DM_DIG_FA_TH2) +		value_igi += 2; +	if (value_igi > DM_DIG_FA_UPPER) +		value_igi = DM_DIG_FA_UPPER; +	else if (value_igi < DM_DIG_FA_LOWER) +		value_igi = DM_DIG_FA_LOWER; +	if (rtlpriv->falsealm_cnt.cnt_all > 10000) +		value_igi = 0x32; + +	dm_digtable.cur_igvalue = value_igi; +	rtl92c_dm_write_dig(hw); +} + +static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->falsealm_cnt.cnt_all > dm_digtable.fa_highthresh) { +		if ((dm_digtable.backoff_val - 2) < +		    dm_digtable.backoff_val_range_min) +			dm_digtable.backoff_val = +			    dm_digtable.backoff_val_range_min; +		else +			dm_digtable.backoff_val -= 2; +	} else if (rtlpriv->falsealm_cnt.cnt_all < dm_digtable.fa_lowthresh) { +		if ((dm_digtable.backoff_val + 2) > +		    dm_digtable.backoff_val_range_max) +			dm_digtable.backoff_val = +			    dm_digtable.backoff_val_range_max; +		else +			dm_digtable.backoff_val += 2; +	} + +	if ((dm_digtable.rssi_val_min + 10 - dm_digtable.backoff_val) > +	    dm_digtable.rx_gain_range_max) +		dm_digtable.cur_igvalue = dm_digtable.rx_gain_range_max; +	else if ((dm_digtable.rssi_val_min + 10 - +		  dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min) +		dm_digtable.cur_igvalue = dm_digtable.rx_gain_range_min; +	else +		dm_digtable.cur_igvalue = dm_digtable.rssi_val_min + 10 - +		    dm_digtable.backoff_val; + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 ("rssi_val_min = %x backoff_val %x\n", +		  dm_digtable.rssi_val_min, dm_digtable.backoff_val)); + +	rtl92c_dm_write_dig(hw); +} + +static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) +{ +	static u8 binitialized; /* initialized to false */ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +	bool b_multi_sta = false; + +	if (mac->opmode == NL80211_IFTYPE_ADHOC) +		b_multi_sta = true; + +	if ((b_multi_sta == false) || (dm_digtable.cursta_connectctate != +				       DIG_STA_DISCONNECT)) { +		binitialized = false; +		dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; +		return; +	} else if (binitialized == false) { +		binitialized = true; +		dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; +		dm_digtable.cur_igvalue = 0x20; +		rtl92c_dm_write_dig(hw); +	} + +	if (dm_digtable.curmultista_connectstate == DIG_MULTISTA_CONNECT) { +		if ((rssi_strength < dm_digtable.rssi_lowthresh) && +		    (dm_digtable.dig_ext_port_stage != DIG_EXT_PORT_STAGE_1)) { + +			if (dm_digtable.dig_ext_port_stage == +			    DIG_EXT_PORT_STAGE_2) { +				dm_digtable.cur_igvalue = 0x20; +				rtl92c_dm_write_dig(hw); +			} + +			dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_1; +		} else if (rssi_strength > dm_digtable.rssi_highthresh) { +			dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_2; +			rtl92c_dm_ctrl_initgain_by_fa(hw); +		} +	} else if (dm_digtable.dig_ext_port_stage != DIG_EXT_PORT_STAGE_0) { +		dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; +		dm_digtable.cur_igvalue = 0x20; +		rtl92c_dm_write_dig(hw); +	} + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 ("curmultista_connectstate = " +		  "%x dig_ext_port_stage %x\n", +		  dm_digtable.curmultista_connectstate, +		  dm_digtable.dig_ext_port_stage)); +} + +static void rtl92c_dm_initial_gain_sta(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 ("presta_connectstate = %x," +		  " cursta_connectctate = %x\n", +		  dm_digtable.presta_connectstate, +		  dm_digtable.cursta_connectctate)); + +	if (dm_digtable.presta_connectstate == dm_digtable.cursta_connectctate +	    || dm_digtable.cursta_connectctate == DIG_STA_BEFORE_CONNECT +	    || dm_digtable.cursta_connectctate == DIG_STA_CONNECT) { + +		if (dm_digtable.cursta_connectctate != DIG_STA_DISCONNECT) { +			dm_digtable.rssi_val_min = +			    rtl92c_dm_initial_gain_min_pwdb(hw); +			rtl92c_dm_ctrl_initgain_by_rssi(hw); +		} +	} else { +		dm_digtable.rssi_val_min = 0; +		dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; +		dm_digtable.backoff_val = DM_DIG_BACKOFF_DEFAULT; +		dm_digtable.cur_igvalue = 0x20; +		dm_digtable.pre_igvalue = 0; +		rtl92c_dm_write_dig(hw); +	} +} + +static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (dm_digtable.cursta_connectctate == DIG_STA_CONNECT) { +		dm_digtable.rssi_val_min = rtl92c_dm_initial_gain_min_pwdb(hw); + +		if (dm_digtable.pre_cck_pd_state == CCK_PD_STAGE_LowRssi) { +			if (dm_digtable.rssi_val_min <= 25) +				dm_digtable.cur_cck_pd_state = +				    CCK_PD_STAGE_LowRssi; +			else +				dm_digtable.cur_cck_pd_state = +				    CCK_PD_STAGE_HighRssi; +		} else { +			if (dm_digtable.rssi_val_min <= 20) +				dm_digtable.cur_cck_pd_state = +				    CCK_PD_STAGE_LowRssi; +			else +				dm_digtable.cur_cck_pd_state = +				    CCK_PD_STAGE_HighRssi; +		} +	} else { +		dm_digtable.cur_cck_pd_state = CCK_PD_STAGE_MAX; +	} + +	if (dm_digtable.pre_cck_pd_state != dm_digtable.cur_cck_pd_state) { +		if (dm_digtable.cur_cck_pd_state == CCK_PD_STAGE_LowRssi) { +			if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800) +				dm_digtable.cur_cck_fa_state = +				    CCK_FA_STAGE_High; +			else +				dm_digtable.cur_cck_fa_state = CCK_FA_STAGE_Low; + +			if (dm_digtable.pre_cck_fa_state != +			    dm_digtable.cur_cck_fa_state) { +				if (dm_digtable.cur_cck_fa_state == +				    CCK_FA_STAGE_Low) +					rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, +						      0x83); +				else +					rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, +						      0xcd); + +				dm_digtable.pre_cck_fa_state = +				    dm_digtable.cur_cck_fa_state; +			} + +			rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40); + +			if (IS_92C_SERIAL(rtlhal->version)) +				rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, +					      MASKBYTE2, 0xd7); +		} else { +			rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd); +			rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x47); + +			if (IS_92C_SERIAL(rtlhal->version)) +				rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, +					      MASKBYTE2, 0xd3); +		} +		dm_digtable.pre_cck_pd_state = dm_digtable.cur_cck_pd_state; +	} + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 ("CCKPDStage=%x\n", dm_digtable.cur_cck_pd_state)); + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE, +		 ("is92C=%x\n", IS_92C_SERIAL(rtlhal->version))); +} + +static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	if (mac->act_scanning == true) +		return; + +	if ((mac->link_state > MAC80211_NOLINK) && +	    (mac->link_state < MAC80211_LINKED)) +		dm_digtable.cursta_connectctate = DIG_STA_BEFORE_CONNECT; +	else if (mac->link_state >= MAC80211_LINKED) +		dm_digtable.cursta_connectctate = DIG_STA_CONNECT; +	else +		dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; + +	rtl92c_dm_initial_gain_sta(hw); +	rtl92c_dm_initial_gain_multi_sta(hw); +	rtl92c_dm_cck_packet_detection_thresh(hw); + +	dm_digtable.presta_connectstate = dm_digtable.cursta_connectctate; + +} + +static void rtl92c_dm_dig(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->dm.b_dm_initialgain_enable == false) +		return; +	if (dm_digtable.dig_enable_flag == false) +		return; + +	rtl92c_dm_ctrl_initgain_by_twoport(hw); + +} + +static void rtl92c_dm_init_dynamic_txpower(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.bdynamic_txpower_enable = false; + +	rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; +	rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +} + +static void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	long undecorated_smoothed_pwdb; + +	if (!rtlpriv->dm.bdynamic_txpower_enable) +		return; + +	if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +		return; +	} + +	if ((mac->link_state < MAC80211_LINKED) && +	    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { +		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, +			 ("Not connected to any\n")); + +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + +		rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; +		return; +	} + +	if (mac->link_state >= MAC80211_LINKED) { +		if (mac->opmode == NL80211_IFTYPE_ADHOC) { +			undecorated_smoothed_pwdb = +			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +				 ("AP Client PWDB = 0x%lx\n", +				  undecorated_smoothed_pwdb)); +		} else { +			undecorated_smoothed_pwdb = +			    rtlpriv->dm.undecorated_smoothed_pwdb; +			RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +				 ("STA Default Port PWDB = 0x%lx\n", +				  undecorated_smoothed_pwdb)); +		} +	} else { +		undecorated_smoothed_pwdb = +		    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 ("AP Ext Port PWDB = 0x%lx\n", +			  undecorated_smoothed_pwdb)); +	} + +	if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n")); +	} else if ((undecorated_smoothed_pwdb < +		    (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && +		   (undecorated_smoothed_pwdb >= +		    TX_POWER_NEAR_FIELD_THRESH_LVL1)) { + +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n")); +	} else if (undecorated_smoothed_pwdb < +		   (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { +		rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 ("TXHIGHPWRLEVEL_NORMAL\n")); +	} + +	if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 ("PHY_SetTxPowerLevel8192S() Channel = %d\n", +			  rtlphy->current_channel)); +		rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); +	} + +	rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + +void rtl92c_dm_write_dig(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, +		 ("cur_igvalue = 0x%x, " +		  "pre_igvalue = 0x%x, backoff_val = %d\n", +		  dm_digtable.cur_igvalue, dm_digtable.pre_igvalue, +		  dm_digtable.backoff_val)); + +	if (dm_digtable.pre_igvalue != dm_digtable.cur_igvalue) { +		rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f, +			      dm_digtable.cur_igvalue); +		rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f, +			      dm_digtable.cur_igvalue); + +		dm_digtable.pre_igvalue = dm_digtable.cur_igvalue; +	} +} + +static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	long tmpentry_max_pwdb = 0, tmpentry_min_pwdb = 0xff; + +	u8 h2c_parameter[3] = { 0 }; + +	return; + +	if (tmpentry_max_pwdb != 0) { +		rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = +		    tmpentry_max_pwdb; +	} else { +		rtlpriv->dm.entry_max_undecoratedsmoothed_pwdb = 0; +	} + +	if (tmpentry_min_pwdb != 0xff) { +		rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = +		    tmpentry_min_pwdb; +	} else { +		rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb = 0; +	} + +	h2c_parameter[2] = (u8) (rtlpriv->dm.undecorated_smoothed_pwdb & 0xFF); +	h2c_parameter[0] = 0; + +	rtl92c_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter); +} + +void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	rtlpriv->dm.bcurrent_turbo_edca = false; +	rtlpriv->dm.bis_any_nonbepkts = false; +	rtlpriv->dm.bis_cur_rdlstate = false; +} + +static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	static u64 last_txok_cnt; +	static u64 last_rxok_cnt; +	u64 cur_txok_cnt; +	u64 cur_rxok_cnt; +	u32 edca_be_ul = 0x5ea42b; +	u32 edca_be_dl = 0x5ea42b; + +	if (mac->opmode == NL80211_IFTYPE_ADHOC) +		goto dm_checkedcaturbo_exit; + +	if (mac->link_state != MAC80211_LINKED) { +		rtlpriv->dm.bcurrent_turbo_edca = false; +		return; +	} + +	if (!mac->ht_enable) {	/*FIX MERGE */ +		if (!(edca_be_ul & 0xffff0000)) +			edca_be_ul |= 0x005e0000; + +		if (!(edca_be_dl & 0xffff0000)) +			edca_be_dl |= 0x005e0000; +	} + +	if ((!rtlpriv->dm.bis_any_nonbepkts) && +	    (!rtlpriv->dm.b_disable_framebursting)) { +		cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; +		cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; +		if (cur_rxok_cnt > 4 * cur_txok_cnt) { +			if (!rtlpriv->dm.bis_cur_rdlstate || +			    !rtlpriv->dm.bcurrent_turbo_edca) { +				rtl_write_dword(rtlpriv, +						REG_EDCA_BE_PARAM, +						edca_be_dl); +				rtlpriv->dm.bis_cur_rdlstate = true; +			} +		} else { +			if (rtlpriv->dm.bis_cur_rdlstate || +			    !rtlpriv->dm.bcurrent_turbo_edca) { +				rtl_write_dword(rtlpriv, +						REG_EDCA_BE_PARAM, +						edca_be_ul); +				rtlpriv->dm.bis_cur_rdlstate = false; +			} +		} +		rtlpriv->dm.bcurrent_turbo_edca = true; +	} else { +		if (rtlpriv->dm.bcurrent_turbo_edca) { +			u8 tmp = AC0_BE; +			rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_AC_PARAM, +						      (u8 *) (&tmp)); +			rtlpriv->dm.bcurrent_turbo_edca = false; +		} +	} + +dm_checkedcaturbo_exit: +	rtlpriv->dm.bis_any_nonbepkts = false; +	last_txok_cnt = rtlpriv->stats.txbytesunicast; +	last_rxok_cnt = rtlpriv->stats.rxbytesunicast; +} + +static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw +							     *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 thermalvalue, delta, delta_lck, delta_iqk; +	long ele_a, ele_d, temp_cck, val_x, value32; +	long val_y, ele_c; +	u8 ofdm_index[2], cck_index, ofdm_index_old[2], cck_index_old; +	int i; +	bool is2t = IS_92C_SERIAL(rtlhal->version); +	u8 txpwr_level[2] = {0, 0}; +	u8 ofdm_min_index = 6, rf; + +	rtlpriv->dm.btxpower_trackingInit = true; +	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +		 ("rtl92c_dm_txpower_tracking_callback_thermalmeter\n")); + +	thermalvalue = (u8) rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f); + +	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +		 ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x " +		  "eeprom_thermalmeter 0x%x\n", +		  thermalvalue, rtlpriv->dm.thermalvalue, +		  rtlefuse->eeprom_thermalmeter)); + +	rtl92c_phy_ap_calibrate(hw, (thermalvalue - +				     rtlefuse->eeprom_thermalmeter)); +	if (is2t) +		rf = 2; +	else +		rf = 1; + +	if (thermalvalue) { +		ele_d = rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, +				      MASKDWORD) & MASKOFDM_D; + +		for (i = 0; i < OFDM_TABLE_LENGTH; i++) { +			if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) { +				ofdm_index_old[0] = (u8) i; + +				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +					("Initial pathA ele_d reg0x%x = 0x%lx, " +					 "ofdm_index=0x%x\n", +					 ROFDM0_XATXIQIMBALANCE, +					 ele_d, ofdm_index_old[0])); +				break; +			} +		} + +		if (is2t) { +			ele_d = rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, +					      MASKDWORD) & MASKOFDM_D; + +			for (i = 0; i < OFDM_TABLE_LENGTH; i++) { +				if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) { +					ofdm_index_old[1] = (u8) i; + +					RT_TRACE(rtlpriv, COMP_POWER_TRACKING, +					   DBG_LOUD, +					   ("Initial pathB ele_d reg0x%x = " +					   "0x%lx, ofdm_index=0x%x\n", +					   ROFDM0_XBTXIQIMBALANCE, ele_d, +					   ofdm_index_old[1])); +					break; +				} +			} +		} + +		temp_cck = +		    rtl_get_bbreg(hw, RCCK0_TXFILTER2, MASKDWORD) & MASKCCK; + +		for (i = 0; i < CCK_TABLE_LENGTH; i++) { +			if (rtlpriv->dm.b_cck_inch14) { +				if (memcmp((void *)&temp_cck, +					   (void *)&cckswing_table_ch14[i][2], +					   4) == 0) { +					cck_index_old = (u8) i; + +					RT_TRACE(rtlpriv, COMP_POWER_TRACKING, +						 DBG_LOUD, +						 ("Initial reg0x%x = 0x%lx, " +						  "cck_index=0x%x, ch 14 %d\n", +						  RCCK0_TXFILTER2, temp_cck, +						  cck_index_old, +						  rtlpriv->dm.b_cck_inch14)); +					break; +				} +			} else { +				if (memcmp((void *)&temp_cck, +					   (void *) +					   &cckswing_table_ch1ch13[i][2], +					   4) == 0) { +					cck_index_old = (u8) i; + +					RT_TRACE(rtlpriv, COMP_POWER_TRACKING, +						 DBG_LOUD, +						 ("Initial reg0x%x = 0x%lx, " +						  "cck_index=0x%x, ch14 %d\n", +						  RCCK0_TXFILTER2, temp_cck, +						  cck_index_old, +						  rtlpriv->dm.b_cck_inch14)); +					break; +				} +			} +		} + +		if (!rtlpriv->dm.thermalvalue) { +			rtlpriv->dm.thermalvalue = +			    rtlefuse->eeprom_thermalmeter; +			rtlpriv->dm.thermalvalue_lck = thermalvalue; +			rtlpriv->dm.thermalvalue_iqk = thermalvalue; +			for (i = 0; i < rf; i++) +				rtlpriv->dm.ofdm_index[i] = ofdm_index_old[i]; +			rtlpriv->dm.cck_index = cck_index_old; +		} + +		delta = (thermalvalue > rtlpriv->dm.thermalvalue) ? +		    (thermalvalue - rtlpriv->dm.thermalvalue) : +		    (rtlpriv->dm.thermalvalue - thermalvalue); + +		delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ? +		    (thermalvalue - rtlpriv->dm.thermalvalue_lck) : +		    (rtlpriv->dm.thermalvalue_lck - thermalvalue); + +		delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ? +		    (thermalvalue - rtlpriv->dm.thermalvalue_iqk) : +		    (rtlpriv->dm.thermalvalue_iqk - thermalvalue); + +		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +			("Readback Thermal Meter = 0x%x pre thermal meter 0x%x " +			 "eeprom_thermalmeter 0x%x delta 0x%x " +			 "delta_lck 0x%x delta_iqk 0x%x\n", +			 thermalvalue, rtlpriv->dm.thermalvalue, +			 rtlefuse->eeprom_thermalmeter, delta, delta_lck, +			 delta_iqk)); + +		if (delta_lck > 1) { +			rtlpriv->dm.thermalvalue_lck = thermalvalue; +			rtl92c_phy_lc_calibrate(hw); +		} + +		if (delta > 0 && rtlpriv->dm.txpower_track_control) { +			if (thermalvalue > rtlpriv->dm.thermalvalue) { +				for (i = 0; i < rf; i++) +					rtlpriv->dm.ofdm_index[i] -= delta; +				rtlpriv->dm.cck_index -= delta; +			} else { +				for (i = 0; i < rf; i++) +					rtlpriv->dm.ofdm_index[i] += delta; +				rtlpriv->dm.cck_index += delta; +			} + +			if (is2t) { +				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +					 ("temp OFDM_A_index=0x%x, " +					  "OFDM_B_index=0x%x," +					  "cck_index=0x%x\n", +					  rtlpriv->dm.ofdm_index[0], +					  rtlpriv->dm.ofdm_index[1], +					  rtlpriv->dm.cck_index)); +			} else { +				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +					 ("temp OFDM_A_index=0x%x," +					  "cck_index=0x%x\n", +					  rtlpriv->dm.ofdm_index[0], +					  rtlpriv->dm.cck_index)); +			} + +			if (thermalvalue > rtlefuse->eeprom_thermalmeter) { +				for (i = 0; i < rf; i++) +					ofdm_index[i] = +					    rtlpriv->dm.ofdm_index[i] +					    + 1; +				cck_index = rtlpriv->dm.cck_index + 1; +			} else { +				for (i = 0; i < rf; i++) +					ofdm_index[i] = +					    rtlpriv->dm.ofdm_index[i]; +				cck_index = rtlpriv->dm.cck_index; +			} + +			for (i = 0; i < rf; i++) { +				if (txpwr_level[i] >= 0 && +				    txpwr_level[i] <= 26) { +					if (thermalvalue > +					    rtlefuse->eeprom_thermalmeter) { +						if (delta < 5) +							ofdm_index[i] -= 1; + +						else +							ofdm_index[i] -= 2; +					} else if (delta > 5 && thermalvalue < +						   rtlefuse-> +						   eeprom_thermalmeter) { +						ofdm_index[i] += 1; +					} +				} else if (txpwr_level[i] >= 27 && +					   txpwr_level[i] <= 32 +					   && thermalvalue > +					   rtlefuse->eeprom_thermalmeter) { +					if (delta < 5) +						ofdm_index[i] -= 1; + +					else +						ofdm_index[i] -= 2; +				} else if (txpwr_level[i] >= 32 && +					   txpwr_level[i] <= 38 && +					   thermalvalue > +					   rtlefuse->eeprom_thermalmeter +					   && delta > 5) { +					ofdm_index[i] -= 1; +				} +			} + +			if (txpwr_level[i] >= 0 && txpwr_level[i] <= 26) { +				if (thermalvalue > +				    rtlefuse->eeprom_thermalmeter) { +					if (delta < 5) +						cck_index -= 1; + +					else +						cck_index -= 2; +				} else if (delta > 5 && thermalvalue < +					   rtlefuse->eeprom_thermalmeter) { +					cck_index += 1; +				} +			} else if (txpwr_level[i] >= 27 && +				   txpwr_level[i] <= 32 && +				   thermalvalue > +				   rtlefuse->eeprom_thermalmeter) { +				if (delta < 5) +					cck_index -= 1; + +				else +					cck_index -= 2; +			} else if (txpwr_level[i] >= 32 && +				   txpwr_level[i] <= 38 && +				   thermalvalue > rtlefuse->eeprom_thermalmeter +				   && delta > 5) { +				cck_index -= 1; +			} + +			for (i = 0; i < rf; i++) { +				if (ofdm_index[i] > OFDM_TABLE_SIZE - 1) +					ofdm_index[i] = OFDM_TABLE_SIZE - 1; + +				else if (ofdm_index[i] < ofdm_min_index) +					ofdm_index[i] = ofdm_min_index; +			} + +			if (cck_index > CCK_TABLE_SIZE - 1) +				cck_index = CCK_TABLE_SIZE - 1; +			else if (cck_index < 0) +				cck_index = 0; + +			if (is2t) { +				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +					 ("new OFDM_A_index=0x%x, " +					  "OFDM_B_index=0x%x," +					  "cck_index=0x%x\n", +					  ofdm_index[0], ofdm_index[1], +					  cck_index)); +			} else { +				RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +					 ("new OFDM_A_index=0x%x," +					  "cck_index=0x%x\n", +					  ofdm_index[0], cck_index)); +			} +		} + +		if (rtlpriv->dm.txpower_track_control && delta != 0) { +			ele_d = +			    (ofdmswing_table[ofdm_index[0]] & 0xFFC00000) >> 22; +			val_x = rtlphy->reg_e94; +			val_y = rtlphy->reg_e9c; + +			if (val_x != 0) { +				if ((val_x & 0x00000200) != 0) +					val_x = val_x | 0xFFFFFC00; +				ele_a = ((val_x * ele_d) >> 8) & 0x000003FF; + +				if ((val_y & 0x00000200) != 0) +					val_y = val_y | 0xFFFFFC00; +				ele_c = ((val_y * ele_d) >> 8) & 0x000003FF; + +				value32 = (ele_d << 22) | +				    ((ele_c & 0x3F) << 16) | ele_a; + +				rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, +					      MASKDWORD, value32); + +				value32 = (ele_c & 0x000003C0) >> 6; +				rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, +					      value32); + +				value32 = ((val_x * ele_d) >> 7) & 0x01; +				rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, +					      BIT(31), value32); + +				value32 = ((val_y * ele_d) >> 7) & 0x01; +				rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, +					      BIT(29), value32); +			} else { +				rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, +					      MASKDWORD, +					      ofdmswing_table[ofdm_index[0]]); + +				rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, +					      0x00); +				rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, +					      BIT(31) | BIT(29), 0x00); +			} + +			if (!rtlpriv->dm.b_cck_inch14) { +				rtl_write_byte(rtlpriv, 0xa22, +					       cckswing_table_ch1ch13[cck_index] +					       [0]); +				rtl_write_byte(rtlpriv, 0xa23, +					       cckswing_table_ch1ch13[cck_index] +					       [1]); +				rtl_write_byte(rtlpriv, 0xa24, +					       cckswing_table_ch1ch13[cck_index] +					       [2]); +				rtl_write_byte(rtlpriv, 0xa25, +					       cckswing_table_ch1ch13[cck_index] +					       [3]); +				rtl_write_byte(rtlpriv, 0xa26, +					       cckswing_table_ch1ch13[cck_index] +					       [4]); +				rtl_write_byte(rtlpriv, 0xa27, +					       cckswing_table_ch1ch13[cck_index] +					       [5]); +				rtl_write_byte(rtlpriv, 0xa28, +					       cckswing_table_ch1ch13[cck_index] +					       [6]); +				rtl_write_byte(rtlpriv, 0xa29, +					       cckswing_table_ch1ch13[cck_index] +					       [7]); +			} else { +				rtl_write_byte(rtlpriv, 0xa22, +					       cckswing_table_ch14[cck_index] +					       [0]); +				rtl_write_byte(rtlpriv, 0xa23, +					       cckswing_table_ch14[cck_index] +					       [1]); +				rtl_write_byte(rtlpriv, 0xa24, +					       cckswing_table_ch14[cck_index] +					       [2]); +				rtl_write_byte(rtlpriv, 0xa25, +					       cckswing_table_ch14[cck_index] +					       [3]); +				rtl_write_byte(rtlpriv, 0xa26, +					       cckswing_table_ch14[cck_index] +					       [4]); +				rtl_write_byte(rtlpriv, 0xa27, +					       cckswing_table_ch14[cck_index] +					       [5]); +				rtl_write_byte(rtlpriv, 0xa28, +					       cckswing_table_ch14[cck_index] +					       [6]); +				rtl_write_byte(rtlpriv, 0xa29, +					       cckswing_table_ch14[cck_index] +					       [7]); +			} + +			if (is2t) { +				ele_d = (ofdmswing_table[ofdm_index[1]] & +					 0xFFC00000) >> 22; + +				val_x = rtlphy->reg_eb4; +				val_y = rtlphy->reg_ebc; + +				if (val_x != 0) { +					if ((val_x & 0x00000200) != 0) +						val_x = val_x | 0xFFFFFC00; +					ele_a = ((val_x * ele_d) >> 8) & +					    0x000003FF; + +					if ((val_y & 0x00000200) != 0) +						val_y = val_y | 0xFFFFFC00; +					ele_c = ((val_y * ele_d) >> 8) & +					    0x00003FF; + +					value32 = (ele_d << 22) | +					    ((ele_c & 0x3F) << 16) | ele_a; +					rtl_set_bbreg(hw, +						      ROFDM0_XBTXIQIMBALANCE, +						      MASKDWORD, value32); + +					value32 = (ele_c & 0x000003C0) >> 6; +					rtl_set_bbreg(hw, ROFDM0_XDTXAFE, +						      MASKH4BITS, value32); + +					value32 = ((val_x * ele_d) >> 7) & 0x01; +					rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, +						      BIT(27), value32); + +					value32 = ((val_y * ele_d) >> 7) & 0x01; +					rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, +						      BIT(25), value32); +				} else { +					rtl_set_bbreg(hw, +						      ROFDM0_XBTXIQIMBALANCE, +						      MASKDWORD, +						      ofdmswing_table[ofdm_index +								      [1]]); +					rtl_set_bbreg(hw, ROFDM0_XDTXAFE, +						      MASKH4BITS, 0x00); +					rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, +						      BIT(27) | BIT(25), 0x00); +				} + +			} +		} + +		if (delta_iqk > 3) { +			rtlpriv->dm.thermalvalue_iqk = thermalvalue; +			rtl92c_phy_iq_calibrate(hw, false); +		} + +		if (rtlpriv->dm.txpower_track_control) +			rtlpriv->dm.thermalvalue = thermalvalue; +	} + +	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("<===\n")); + +} + +static void rtl92c_dm_initialize_txpower_tracking_thermalmeter( +						struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.btxpower_tracking = true; +	rtlpriv->dm.btxpower_trackingInit = false; + +	RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +		 ("pMgntInfo->btxpower_tracking = %d\n", +		  rtlpriv->dm.btxpower_tracking)); +} + +static void rtl92c_dm_initialize_txpower_tracking(struct ieee80211_hw *hw) +{ +	rtl92c_dm_initialize_txpower_tracking_thermalmeter(hw); +} + +static void rtl92c_dm_txpower_tracking_directcall(struct ieee80211_hw *hw) +{ +	rtl92c_dm_txpower_tracking_callback_thermalmeter(hw); +} + +static void rtl92c_dm_check_txpower_tracking_thermal_meter( +						struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	static u8 tm_trigger; + +	if (!rtlpriv->dm.btxpower_tracking) +		return; + +	if (!tm_trigger) { +		rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, RFREG_OFFSET_MASK, +			      0x60); +		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +			 ("Trigger 92S Thermal Meter!!\n")); +		tm_trigger = 1; +		return; +	} else { +		RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, +			 ("Schedule TxPowerTracking direct call!!\n")); +		rtl92c_dm_txpower_tracking_directcall(hw); +		tm_trigger = 0; +	} +} + +void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw) +{ +	rtl92c_dm_check_txpower_tracking_thermal_meter(hw); +} + +void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rate_adaptive *p_ra = &(rtlpriv->ra); + +	p_ra->ratr_state = DM_RATR_STA_INIT; +	p_ra->pre_ratr_state = DM_RATR_STA_INIT; + +	if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) +		rtlpriv->dm.b_useramask = true; +	else +		rtlpriv->dm.b_useramask = false; + +} + +static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *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 rate_adaptive *p_ra = &(rtlpriv->ra); +	u32 low_rssithresh_for_ra, high_rssithresh_for_ra; + +	if (is_hal_stop(rtlhal)) { +		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, +			 ("<---- driver is going to unload\n")); +		return; +	} + +	if (!rtlpriv->dm.b_useramask) { +		RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, +			("<---- driver does not control rate adaptive mask\n")); +		return; +	} + +	if (mac->link_state == MAC80211_LINKED) { + +		switch (p_ra->pre_ratr_state) { +		case DM_RATR_STA_HIGH: +			high_rssithresh_for_ra = 50; +			low_rssithresh_for_ra = 20; +			break; +		case DM_RATR_STA_MIDDLE: +			high_rssithresh_for_ra = 55; +			low_rssithresh_for_ra = 20; +			break; +		case DM_RATR_STA_LOW: +			high_rssithresh_for_ra = 50; +			low_rssithresh_for_ra = 25; +			break; +		default: +			high_rssithresh_for_ra = 50; +			low_rssithresh_for_ra = 20; +			break; +		} + +		if (rtlpriv->dm.undecorated_smoothed_pwdb > +		    (long)high_rssithresh_for_ra) +			p_ra->ratr_state = DM_RATR_STA_HIGH; +		else if (rtlpriv->dm.undecorated_smoothed_pwdb > +			 (long)low_rssithresh_for_ra) +			p_ra->ratr_state = DM_RATR_STA_MIDDLE; +		else +			p_ra->ratr_state = DM_RATR_STA_LOW; + +		if (p_ra->pre_ratr_state != p_ra->ratr_state) { +			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, +				 ("RSSI = %ld\n", +				  rtlpriv->dm.undecorated_smoothed_pwdb)); +			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, +				 ("RSSI_LEVEL = %d\n", p_ra->ratr_state)); +			RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, +				 ("PreState = %d, CurState = %d\n", +				  p_ra->pre_ratr_state, p_ra->ratr_state)); + +			rtlpriv->cfg->ops->update_rate_mask(hw, +					p_ra->ratr_state); + +			p_ra->pre_ratr_state = p_ra->ratr_state; +		} +	} +} + +static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw) +{ +	dm_pstable.pre_ccastate = CCA_MAX; +	dm_pstable.cur_ccasate = CCA_MAX; +	dm_pstable.pre_rfstate = RF_MAX; +	dm_pstable.cur_rfstate = RF_MAX; +	dm_pstable.rssi_val_min = 0; +} + +static void rtl92c_dm_1r_cca(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	if (dm_pstable.rssi_val_min != 0) { +		if (dm_pstable.pre_ccastate == CCA_2R) { +			if (dm_pstable.rssi_val_min >= 35) +				dm_pstable.cur_ccasate = CCA_1R; +			else +				dm_pstable.cur_ccasate = CCA_2R; +		} else { +			if (dm_pstable.rssi_val_min <= 30) +				dm_pstable.cur_ccasate = CCA_2R; +			else +				dm_pstable.cur_ccasate = CCA_1R; +		} +	} else { +		dm_pstable.cur_ccasate = CCA_MAX; +	} + +	if (dm_pstable.pre_ccastate != dm_pstable.cur_ccasate) { +		if (dm_pstable.cur_ccasate == CCA_1R) { +			if (get_rf_type(rtlphy) == RF_2T2R) { +				rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, +					      MASKBYTE0, 0x13); +				rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x20); +			} else { +				rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, +					      MASKBYTE0, 0x23); +				rtl_set_bbreg(hw, 0xe70, 0x7fc00000, 0x10c); +			} +		} else { +			rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, +				      0x33); +			rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x63); +		} +		dm_pstable.pre_ccastate = dm_pstable.cur_ccasate; +	} + +	RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, ("CCAStage = %s\n", +					       (dm_pstable.cur_ccasate == +						0) ? "1RCCA" : "2RCCA")); +} + +void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) +{ +	static u8 initialize; +	static u32 reg_874, reg_c70, reg_85c, reg_a74; + +	if (initialize == 0) { +		reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +					 MASKDWORD) & 0x1CC000) >> 14; + +		reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1, +					 MASKDWORD) & BIT(3)) >> 3; + +		reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, +					 MASKDWORD) & 0xFF000000) >> 24; + +		reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) & 0xF000) >> 12; + +		initialize = 1; +	} + +	if (!bforce_in_normal) { +		if (dm_pstable.rssi_val_min != 0) { +			if (dm_pstable.pre_rfstate == RF_NORMAL) { +				if (dm_pstable.rssi_val_min >= 30) +					dm_pstable.cur_rfstate = RF_SAVE; +				else +					dm_pstable.cur_rfstate = RF_NORMAL; +			} else { +				if (dm_pstable.rssi_val_min <= 25) +					dm_pstable.cur_rfstate = RF_NORMAL; +				else +					dm_pstable.cur_rfstate = RF_SAVE; +			} +		} else { +			dm_pstable.cur_rfstate = RF_MAX; +		} +	} else { +		dm_pstable.cur_rfstate = RF_NORMAL; +	} + +	if (dm_pstable.pre_rfstate != dm_pstable.cur_rfstate) { +		if (dm_pstable.cur_rfstate == RF_SAVE) { +			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +				      0x1C0000, 0x2); +			rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), 0); +			rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, +				      0xFF000000, 0x63); +			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +				      0xC000, 0x2); +			rtl_set_bbreg(hw, 0xa74, 0xF000, 0x3); +			rtl_set_bbreg(hw, 0x818, BIT(28), 0x0); +			rtl_set_bbreg(hw, 0x818, BIT(28), 0x1); +		} else { +			rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW, +				      0x1CC000, reg_874); +			rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), +				      reg_c70); +			rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000, +				      reg_85c); +			rtl_set_bbreg(hw, 0xa74, 0xF000, reg_a74); +			rtl_set_bbreg(hw, 0x818, BIT(28), 0x0); +		} + +		dm_pstable.pre_rfstate = dm_pstable.cur_rfstate; +	} +} + +static void rtl92c_dm_dynamic_bb_powersaving(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)); + +	if (((mac->link_state == MAC80211_NOLINK)) && +	    (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { +		dm_pstable.rssi_val_min = 0; +		RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, +			 ("Not connected to any\n")); +	} + +	if (mac->link_state == MAC80211_LINKED) { +		if (mac->opmode == NL80211_IFTYPE_ADHOC) { +			dm_pstable.rssi_val_min = +			    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; +			RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, +				 ("AP Client PWDB = 0x%lx\n", +				  dm_pstable.rssi_val_min)); +		} else { +			dm_pstable.rssi_val_min = +			    rtlpriv->dm.undecorated_smoothed_pwdb; +			RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, +				 ("STA Default Port PWDB = 0x%lx\n", +				  dm_pstable.rssi_val_min)); +		} +	} else { +		dm_pstable.rssi_val_min = +		    rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + +		RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, +			 ("AP Ext Port PWDB = 0x%lx\n", +			  dm_pstable.rssi_val_min)); +	} + +	if (IS_92C_SERIAL(rtlhal->version)) +		rtl92c_dm_1r_cca(hw); +} + +void rtl92c_dm_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER; +	rtl92c_dm_diginit(hw); +	rtl92c_dm_init_dynamic_txpower(hw); +	rtl92c_dm_init_edca_turbo(hw); +	rtl92c_dm_init_rate_adaptive_mask(hw); +	rtl92c_dm_initialize_txpower_tracking(hw); +	rtl92c_dm_init_dynamic_bb_powersaving(hw); +} + +void rtl92c_dm_watchdog(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool b_fw_current_inpsmode = false; +	bool b_fw_ps_awake = true; + +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS, +				      (u8 *) (&b_fw_current_inpsmode)); +	rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON, +				      (u8 *) (&b_fw_ps_awake)); + +	if ((ppsc->rfpwr_state == ERFON) && ((!b_fw_current_inpsmode) && +					     b_fw_ps_awake) +	    && (!ppsc->rfchange_inprogress)) { +		rtl92c_dm_pwdb_monitor(hw); +		rtl92c_dm_dig(hw); +		rtl92c_dm_false_alarm_counter_statistics(hw); +		rtl92c_dm_dynamic_bb_powersaving(hw); +		rtl92c_dm_dynamic_txpower(hw); +		rtl92c_dm_check_txpower_tracking(hw); +		rtl92c_dm_refresh_rate_adaptive_mask(hw); +		rtl92c_dm_check_edca_turbo(hw); +	} +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-dm.h new file mode 100644 index 00000000000..463439e4074 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-dm.h @@ -0,0 +1,196 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef	__RTL92C_DM_H__ +#define __RTL92C_DM_H__ + +#define HAL_DM_DIG_DISABLE			BIT(0) +#define HAL_DM_HIPWR_DISABLE			BIT(1) + +#define OFDM_TABLE_LENGTH			37 +#define CCK_TABLE_LENGTH			33 + +#define OFDM_TABLE_SIZE				37 +#define CCK_TABLE_SIZE				33 + +#define BW_AUTO_SWITCH_HIGH_LOW			25 +#define BW_AUTO_SWITCH_LOW_HIGH			30 + +#define DM_DIG_THRESH_HIGH			40 +#define DM_DIG_THRESH_LOW			35 + +#define DM_FALSEALARM_THRESH_LOW		400 +#define DM_FALSEALARM_THRESH_HIGH		1000 + +#define DM_DIG_MAX				0x3e +#define DM_DIG_MIN				0x1e + +#define DM_DIG_FA_UPPER				0x32 +#define DM_DIG_FA_LOWER				0x20 +#define DM_DIG_FA_TH0				0x20 +#define DM_DIG_FA_TH1				0x100 +#define DM_DIG_FA_TH2				0x200 + +#define DM_DIG_BACKOFF_MAX			12 +#define DM_DIG_BACKOFF_MIN			-4 +#define DM_DIG_BACKOFF_DEFAULT			10 + +#define RXPATHSELECTION_SS_TH_lOW		30 +#define RXPATHSELECTION_DIFF_TH			18 + +#define DM_RATR_STA_INIT			0 +#define DM_RATR_STA_HIGH			1 +#define DM_RATR_STA_MIDDLE			2 +#define DM_RATR_STA_LOW				3 + +#define CTS2SELF_THVAL				30 +#define REGC38_TH				20 + +#define WAIOTTHVal				25 + +#define TXHIGHPWRLEVEL_NORMAL			0 +#define TXHIGHPWRLEVEL_LEVEL1			1 +#define TXHIGHPWRLEVEL_LEVEL2			2 +#define TXHIGHPWRLEVEL_BT1			3 +#define TXHIGHPWRLEVEL_BT2			4 + +#define DM_TYPE_BYFW				0 +#define DM_TYPE_BYDRIVER			1 + +#define TX_POWER_NEAR_FIELD_THRESH_LVL2		74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1		67 + +struct ps_t { +	u8 pre_ccastate; +	u8 cur_ccasate; +	u8 pre_rfstate; +	u8 cur_rfstate; +	long rssi_val_min; +}; + +struct dig_t { +	u8 dig_enable_flag; +	u8 dig_ext_port_stage; +	u32 rssi_lowthresh; +	u32 rssi_highthresh; +	u32 fa_lowthresh; +	u32 fa_highthresh; +	u8 cursta_connectctate; +	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 pre_cck_pd_state; +	u8 cur_cck_pd_state; +	u8 pre_cck_fa_state; +	u8 cur_cck_fa_state; +	u8 pre_ccastate; +	u8 cur_ccasate; +}; + +struct swat_t { +	u8 failure_cnt; +	u8 try_flag; +	u8 stop_trying; +	long pre_rssi; +	long trying_threshold; +	u8 cur_antenna; +	u8 pre_antenna; +}; + +enum tag_dynamic_init_gain_operation_type_definition { +	DIG_TYPE_THRESH_HIGH = 0, +	DIG_TYPE_THRESH_LOW = 1, +	DIG_TYPE_BACKOFF = 2, +	DIG_TYPE_RX_GAIN_MIN = 3, +	DIG_TYPE_RX_GAIN_MAX = 4, +	DIG_TYPE_ENABLE = 5, +	DIG_TYPE_DISABLE = 6, +	DIG_OP_TYPE_MAX +}; + +enum tag_cck_packet_detection_threshold_type_definition { +	CCK_PD_STAGE_LowRssi = 0, +	CCK_PD_STAGE_HighRssi = 1, +	CCK_FA_STAGE_Low = 2, +	CCK_FA_STAGE_High = 3, +	CCK_PD_STAGE_MAX = 4, +}; + +enum dm_1r_cca_e { +	CCA_1R = 0, +	CCA_2R = 1, +	CCA_MAX = 2, +}; + +enum dm_rf_e { +	RF_SAVE = 0, +	RF_NORMAL = 1, +	RF_MAX = 2, +}; + +enum dm_sw_ant_switch_e { +	ANS_ANTENNA_B = 1, +	ANS_ANTENNA_A = 2, +	ANS_ANTENNA_MAX = 3, +}; + +enum dm_dig_ext_port_alg_e { +	DIG_EXT_PORT_STAGE_0 = 0, +	DIG_EXT_PORT_STAGE_1 = 1, +	DIG_EXT_PORT_STAGE_2 = 2, +	DIG_EXT_PORT_STAGE_3 = 3, +	DIG_EXT_PORT_STAGE_MAX = 4, +}; + +enum dm_dig_connect_e { +	DIG_STA_DISCONNECT = 0, +	DIG_STA_CONNECT = 1, +	DIG_STA_BEFORE_CONNECT = 2, +	DIG_MULTISTA_DISCONNECT = 3, +	DIG_MULTISTA_CONNECT = 4, +	DIG_CONNECT_MAX +}; + +extern struct dig_t dm_digtable; +void rtl92c_dm_init(struct ieee80211_hw *hw); +void rtl92c_dm_watchdog(struct ieee80211_hw *hw); +void rtl92c_dm_write_dig(struct ieee80211_hw *hw); +void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw); +void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw); +void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); +void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-fw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-fw.c new file mode 100644 index 00000000000..80ee6ff9d2b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-fw.c @@ -0,0 +1,804 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include <linux/firmware.h> +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "rtl8192c-reg.h" +#include "rtl8192c-def.h" +#include "rtl8192c-fw.h" +#include "rtl8192c-table.h" + +static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) { +		u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +		if (enable) +			value32 |= MCUFWDL_EN; +		else +			value32 &= ~MCUFWDL_EN; +		rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); +	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) { +		u8 tmp; +		if (enable) { + +			tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); +			rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, +				       tmp | 0x04); + +			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); +			rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); + +			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); +			rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); +		} else { + +			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); +			rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); + +			rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00); +		} +	} +} + +static void _rtl92c_fw_block_write(struct ieee80211_hw *hw, +				   const u8 *buffer, u32 size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 blockSize = sizeof(u32); +	u8 *bufferPtr = (u8 *) buffer; +	u32 *pu4BytePtr = (u32 *) buffer; +	u32 i, offset, blockCount, remainSize; + +	blockCount = size / blockSize; +	remainSize = size % blockSize; + +	for (i = 0; i < blockCount; i++) { +		offset = i * blockSize; +		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset), +				*(pu4BytePtr + i)); +	} + +	if (remainSize) { +		offset = blockCount * blockSize; +		bufferPtr += offset; +		for (i = 0; i < remainSize; i++) { +			rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS + +						 offset + i), *(bufferPtr + i)); +		} +	} +} + +static void _rtl92c_fw_page_write(struct ieee80211_hw *hw, +				  u32 page, const u8 *buffer, u32 size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 value8; +	u8 u8page = (u8) (page & 0x07); + +	value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; + +	rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); +	_rtl92c_fw_block_write(hw, buffer, size); +} + +static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen) +{ +	u32 fwlen = *pfwlen; +	u8 remain = (u8) (fwlen % 4); + +	remain = (remain == 0) ? 0 : (4 - remain); + +	while (remain > 0) { +		pfwbuf[fwlen] = 0; +		fwlen++; +		remain--; +	} + +	*pfwlen = fwlen; +} + +static void _rtl92c_write_fw(struct ieee80211_hw *hw, +			     enum version_8192c version, u8 *buffer, u32 size) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	bool is_version_b; +	u8 *bufferPtr = (u8 *) buffer; + +	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size)); + +	is_version_b = IS_CHIP_VER_B(version); +	if (is_version_b) { +		u32 pageNums, remainSize; +		u32 page, offset; + +		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) +			_rtl92c_fill_dummy(bufferPtr, &size); + +		pageNums = size / FW_8192C_PAGE_SIZE; +		remainSize = size % FW_8192C_PAGE_SIZE; + +		if (pageNums > 4) { +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("Page numbers should not greater then 4\n")); +		} + +		for (page = 0; page < pageNums; page++) { +			offset = page * FW_8192C_PAGE_SIZE; +			_rtl92c_fw_page_write(hw, page, (bufferPtr + offset), +					      FW_8192C_PAGE_SIZE); +		} + +		if (remainSize) { +			offset = pageNums * FW_8192C_PAGE_SIZE; +			page = pageNums; +			_rtl92c_fw_page_write(hw, page, (bufferPtr + offset), +					      remainSize); +		} +	} else { +		_rtl92c_fw_block_write(hw, buffer, size); +	} +} + +static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int err = -EIO; +	u32 counter = 0; +	u32 value32; + +	do { +		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) && +		 (!(value32 & FWDL_ChkSum_rpt))); + +	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", +			  value32)); +		goto exit; +	} + +	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +		 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32)); + +	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +	value32 |= MCUFWDL_RDY; +	value32 &= ~WINTINI_RDY; +	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + +	counter = 0; + +	do { +		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); +		if (value32 & WINTINI_RDY) { +			RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +				 ("Polling FW ready success!!" +				 " REG_MCUFWDL:0x%08x .\n", +				 value32)); +			err = 0; +			goto exit; +		} + +		mdelay(FW_8192C_POLLING_DELAY); + +	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT); + +	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +		 ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32)); + +exit: +	return err; +} + +int rtl92c_download_fw(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl92c_firmware_header *pfwheader; +	u8 *pfwdata; +	u32 fwsize; +	int err; +	enum version_8192c version = rtlhal->version; + +	const struct firmware *firmware = NULL; + +	err = request_firmware(&firmware, rtlpriv->cfg->fw_name, +			       rtlpriv->io.dev); +	if (err) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("Failed to request firmware!\n")); +		return 1; +	} + +	if (firmware->size > 0x4000) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("Firmware is too big!\n")); +		release_firmware(firmware); +		return 1; +	} + +	memcpy(rtlhal->pfirmware, firmware->data, firmware->size); +	fwsize = firmware->size; +	release_firmware(firmware); + +	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; +	pfwdata = (u8 *) rtlhal->pfirmware; + +	if (IS_FW_HEADER_EXIST(pfwheader)) { +		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, +			 ("Firmware Version(%d), Signature(%#x),Size(%d)\n", +			  pfwheader->version, pfwheader->signature, +			  (uint)sizeof(struct rtl92c_firmware_header))); + +		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); +		fwsize = fwsize - sizeof(struct rtl92c_firmware_header); +	} + +	_rtl92c_enable_fw_download(hw, true); +	_rtl92c_write_fw(hw, version, pfwdata, fwsize); +	_rtl92c_enable_fw_download(hw, false); + +	err = _rtl92c_fw_free_to_go(hw); +	if (err) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("Firmware is not ready to run!\n")); +	} else { +		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, +			 ("Firmware is ready to run!\n")); +	} + +	return 0; +} + +static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 val_hmetfr, val_mcutst_1; +	bool result = false; + +	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); +	val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum)); + +	if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0) +		result = true; +	return result; +} + +static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, +			      u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 boxnum; +	u16 box_reg, box_extreg; +	u8 u1b_tmp; +	bool isfw_read = false; +	u8 buf_index; +	bool bwrite_sucess = false; +	u8 wait_h2c_limmit = 100; +	u8 wait_writeh2c_limmit = 100; +	u8 boxcontent[4], boxextcontent[2]; +	u32 h2c_waitcounter = 0; +	unsigned long flag; +	u8 idx; + +	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n")); + +	while (true) { +		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); +		if (rtlhal->b_h2c_setinprogress) { +			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +				 ("H2C set in progress! Wait to set.." +				  "element_id(%d).\n", element_id)); + +			while (rtlhal->b_h2c_setinprogress) { +				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, +						       flag); +				h2c_waitcounter++; +				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +					 ("Wait 100 us (%d times)...\n", +					  h2c_waitcounter)); +				udelay(100); + +				if (h2c_waitcounter > 1000) +					return; +				spin_lock_irqsave(&rtlpriv->locks.h2c_lock, +						  flag); +			} +			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); +		} else { +			rtlhal->b_h2c_setinprogress = true; +			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); +			break; +		} +	} + +	while (!bwrite_sucess) { +		wait_writeh2c_limmit--; +		if (wait_writeh2c_limmit == 0) { +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("Write H2C fail because no trigger " +				  "for FW INT!\n")); +			break; +		} + +		boxnum = rtlhal->last_hmeboxnum; +		switch (boxnum) { +		case 0: +			box_reg = REG_HMEBOX_0; +			box_extreg = REG_HMEBOX_EXT_0; +			break; +		case 1: +			box_reg = REG_HMEBOX_1; +			box_extreg = REG_HMEBOX_EXT_1; +			break; +		case 2: +			box_reg = REG_HMEBOX_2; +			box_extreg = REG_HMEBOX_EXT_2; +			break; +		case 3: +			box_reg = REG_HMEBOX_3; +			box_extreg = REG_HMEBOX_EXT_3; +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("switch case not process\n")); +			break; +		} + +		isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum); +		while (!isfw_read) { + +			wait_h2c_limmit--; +			if (wait_h2c_limmit == 0) { +				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +					 ("Wating too long for FW read " +					  "clear HMEBox(%d)!\n", boxnum)); +				break; +			} + +			udelay(10); + +			isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum); +			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF); +			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +				 ("Wating for FW read clear HMEBox(%d)!!! " +				  "0x1BF = %2x\n", boxnum, u1b_tmp)); +		} + +		if (!isfw_read) { +			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +				 ("Write H2C register BOX[%d] fail!!!!! " +				  "Fw do not read.\n", boxnum)); +			break; +		} + +		memset(boxcontent, 0, sizeof(boxcontent)); +		memset(boxextcontent, 0, sizeof(boxextcontent)); +		boxcontent[0] = element_id; +		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +			 ("Write element_id box_reg(%4x) = %2x\n", +			  box_reg, element_id)); + +		switch (cmd_len) { +		case 1: +			boxcontent[0] &= ~(BIT(7)); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer + buf_index, 1); + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		case 2: +			boxcontent[0] &= ~(BIT(7)); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer + buf_index, 2); + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		case 3: +			boxcontent[0] &= ~(BIT(7)); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer + buf_index, 3); + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		case 4: +			boxcontent[0] |= (BIT(7)); +			memcpy((u8 *) (boxextcontent), +			       p_cmdbuffer + buf_index, 2); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer + buf_index + 2, 2); + +			for (idx = 0; idx < 2; idx++) { +				rtl_write_byte(rtlpriv, box_extreg + idx, +					       boxextcontent[idx]); +			} + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		case 5: +			boxcontent[0] |= (BIT(7)); +			memcpy((u8 *) (boxextcontent), +			       p_cmdbuffer + buf_index, 2); +			memcpy((u8 *) (boxcontent) + 1, +			       p_cmdbuffer + buf_index + 2, 3); + +			for (idx = 0; idx < 2; idx++) { +				rtl_write_byte(rtlpriv, box_extreg + idx, +					       boxextcontent[idx]); +			} + +			for (idx = 0; idx < 4; idx++) { +				rtl_write_byte(rtlpriv, box_reg + idx, +					       boxcontent[idx]); +			} +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("switch case not process\n")); +			break; +		} + +		bwrite_sucess = true; + +		rtlhal->last_hmeboxnum = boxnum + 1; +		if (rtlhal->last_hmeboxnum == 4) +			rtlhal->last_hmeboxnum = 0; + +		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, +			 ("pHalData->last_hmeboxnum  = %d\n", +			  rtlhal->last_hmeboxnum)); +	} + +	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); +	rtlhal->b_h2c_setinprogress = false; +	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + +	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n")); +} + +void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, +			 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u32 tmp_cmdbuf[2]; + +	if (rtlhal->bfw_ready == false) { +		RT_ASSERT(false, ("return H2C cmd because of Fw " +				  "download fail!!!\n")); +		return; +	} + +	memset(tmp_cmdbuf, 0, 8); +	memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len); +	_rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); + +	return; +} + +void rtl92c_firmware_selfreset(struct ieee80211_hw *hw) +{ +	u8 u1b_tmp; +	u8 delay = 100; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); +	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + +	while (u1b_tmp & BIT(2)) { +		delay--; +		if (delay == 0) { +			RT_ASSERT(false, ("8051 reset fail.\n")); +			break; +		} +		udelay(50); +		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); +	} +} + +void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 u1_h2c_set_pwrmode[3] = {0}; +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode)); + +	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); +	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1); +	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, +					      ppsc->reg_max_lps_awakeintvl); + +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, +		      "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n", +		      u1_h2c_set_pwrmode, 3); +	rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); + +} + +static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, +				    struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl8192_tx_ring *ring; +	struct rtl_tx_desc *pdesc; +	u8 own; +	unsigned long flags; +	struct sk_buff *pskb = NULL; + +	ring = &rtlpci->tx_ring[BEACON_QUEUE]; + +	pskb = __skb_dequeue(&ring->queue); +	if (pskb) +		kfree_skb(pskb); + +	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + +	pdesc = &ring->desc[0]; +	own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); + +	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); + +	__skb_queue_tail(&ring->queue, skb); + +	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + +	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + +	return true; +} + +#define BEACON_PG		0 /*->1*/ +#define PSPOLL_PG		2 +#define NULL_PG			3 +#define PROBERSP_PG		4 /*->5*/ + +#define TOTAL_RESERVED_PKT_LEN	768 + +static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { +	/* page 0 beacon */ +	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, +	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, +	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, +	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, +	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, +	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, +	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, +	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, +	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 1 beacon */ +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 2  ps-poll */ +	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10, +	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 3  null */ +	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, +	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, +	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 4  probe_resp */ +	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, +	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, +	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, +	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, +	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, +	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, +	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, +	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, +	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, +	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, +	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, +	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +	/* page 5  probe_resp */ +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct sk_buff *skb = NULL; + +	u32 totalpacketlen; +	bool rtstatus; +	u8 u1RsvdPageLoc[3] = {0}; +	bool b_dlok = false; + +	u8 *beacon; +	u8 *p_pspoll; +	u8 *nullfunc; +	u8 *p_probersp; +	/*--------------------------------------------------------- +				(1) beacon +	---------------------------------------------------------*/ +	beacon = &reserved_page_packet[BEACON_PG * 128]; +	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); +	SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + +	/*------------------------------------------------------- +				(2) ps-poll +	--------------------------------------------------------*/ +	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; +	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); +	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); +	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + +	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG); + +	/*-------------------------------------------------------- +				(3) null data +	---------------------------------------------------------*/ +	nullfunc = &reserved_page_packet[NULL_PG * 128]; +	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); +	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); +	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + +	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG); + +	/*--------------------------------------------------------- +				(4) probe response +	----------------------------------------------------------*/ +	p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; +	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); +	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); +	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + +	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG); + +	totalpacketlen = TOTAL_RESERVED_PKT_LEN; + +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, +		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", +		      &reserved_page_packet[0], totalpacketlen); +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, +		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", +		      u1RsvdPageLoc, 3); + + +	skb = dev_alloc_skb(totalpacketlen); +	memcpy((u8 *) skb_put(skb, totalpacketlen), +	       &reserved_page_packet, totalpacketlen); + +	rtstatus = _rtl92c_cmd_send_packet(hw, skb); + +	if (rtstatus) +		b_dlok = true; + +	if (b_dlok) { +		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, +			 ("Set RSVD page location to Fw.\n")); +		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, +				"H2C_RSVDPAGE:\n", +				u1RsvdPageLoc, 3); +		rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE, +				    sizeof(u1RsvdPageLoc), u1RsvdPageLoc); +	} else +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("Set RSVD page location to Fw FAIL!!!!!!.\n")); +} + +void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ +	u8 u1_joinbssrpt_parm[1] = {0}; + +	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); + +	rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-fw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-fw.h new file mode 100644 index 00000000000..3db33bd1466 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-fw.h @@ -0,0 +1,98 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92C__FW__H__ +#define __RTL92C__FW__H__ + +#define FW_8192C_SIZE				0x3000 +#define FW_8192C_START_ADDRESS			0x1000 +#define FW_8192C_END_ADDRESS			0x3FFF +#define FW_8192C_PAGE_SIZE			4096 +#define FW_8192C_POLLING_DELAY			5 +#define FW_8192C_POLLING_TIMEOUT_COUNT		100 + +#define IS_FW_HEADER_EXIST(_pfwhdr)	\ +	((_pfwhdr->signature&0xFFF0) == 0x92C0 ||\ +	(_pfwhdr->signature&0xFFF0) == 0x88C0) + +struct rtl92c_firmware_header { +	u16 signature; +	u8 category; +	u8 function; +	u16 version; +	u8 subversion; +	u8 rsvd1; +	u8 month; +	u8 date; +	u8 hour; +	u8 minute; +	u16 ramcodeSize; +	u16 rsvd2; +	u32 svnindex; +	u32 rsvd3; +	u32 rsvd4; +	u32 rsvd5; +}; + +enum rtl8192c_h2c_cmd { +	H2C_AP_OFFLOAD = 0, +	H2C_SETPWRMODE = 1, +	H2C_JOINBSSRPT = 2, +	H2C_RSVDPAGE = 3, +	H2C_RSSI_REPORT = 5, +	H2C_RA_MASK = 6, +	MAX_H2CCMD +}; + +#define pagenum_128(_len)	(u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0)) + +#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)			\ +	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val)	\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) +#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)		\ +	SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) + +int rtl92c_download_fw(struct ieee80211_hw *hw); +void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, +			 u32 cmd_len, u8 *p_cmdbuffer); +void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); +void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-hw.c new file mode 100644 index 00000000000..c649f655575 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-hw.c @@ -0,0 +1,2173 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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" +#include "../base.h" +#include "../cam.h" +#include "../ps.h" +#include "../pci.h" +#include "rtl8192c-reg.h" +#include "rtl8192c-def.h" +#include "rtl8192c-phy.h" +#include "rtl8192c-dm.h" +#include "rtl8192c-fw.h" +#include "rtl8192c-led.h" +#include "rtl8192c-hw.h" + +#define LLT_CONFIG	5 + +static void _rtl92ce_set_bcn_ctrl_reg(struct ieee80211_hw *hw, +				      u8 set_bits, u8 clear_bits) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtlpci->reg_bcn_ctrl_val |= set_bits; +	rtlpci->reg_bcn_ctrl_val &= ~clear_bits; + +	rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val); +} + +static void _rtl92ce_stop_tx_beacon(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp1byte; + +	tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6))); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64); +	tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); +	tmp1byte &= ~(BIT(0)); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl92ce_resume_tx_beacon(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 tmp1byte; + +	tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2); +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6)); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); +	tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2); +	tmp1byte |= BIT(0); +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte); +} + +static void _rtl92ce_enable_bcn_sub_func(struct ieee80211_hw *hw) +{ +	_rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(1)); +} + +static void _rtl92ce_disable_bcn_sub_func(struct ieee80211_hw *hw) +{ +	_rtl92ce_set_bcn_ctrl_reg(hw, BIT(1), 0); +} + +void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	switch (variable) { +	case HW_VAR_RCR: +		*((u32 *) (val)) = rtlpci->receive_config; +		break; +	case HW_VAR_RF_STATE: +		*((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state; +		break; +	case HW_VAR_FWLPS_RF_ON:{ +			enum rf_pwrstate rfState; +			u32 val_rcr; + +			rtlpriv->cfg->ops->get_hw_reg(hw, +						      HW_VAR_RF_STATE, +						      (u8 *) (&rfState)); +			if (rfState == ERFOFF) { +				*((bool *) (val)) = true; +			} else { +				val_rcr = rtl_read_dword(rtlpriv, REG_RCR); +				val_rcr &= 0x00070000; +				if (val_rcr) +					*((bool *) (val)) = false; +				else +					*((bool *) (val)) = true; +			} +			break; +		} +	case HW_VAR_FW_PSMODE_STATUS: +		*((bool *) (val)) = ppsc->b_fw_current_inpsmode; +		break; +	case HW_VAR_CORRECT_TSF:{ +		u64 tsf; +		u32 *ptsf_low = (u32 *)&tsf; +		u32 *ptsf_high = ((u32 *)&tsf) + 1; + +		*ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4)); +		*ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR); + +		*((u64 *) (val)) = tsf; + +		break; +		} +	case HW_VAR_MGT_FILTER: +		*((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP0); +		break; +	case HW_VAR_CTRL_FILTER: +		*((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP1); +		break; +	case HW_VAR_DATA_FILTER: +		*((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP2); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} +} + +void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) +{ +	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 rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	u8 idx; + +	switch (variable) { +	case HW_VAR_ETHER_ADDR:{ +			for (idx = 0; idx < ETH_ALEN; idx++) { +				rtl_write_byte(rtlpriv, (REG_MACID + idx), +					       val[idx]); +			} +			break; +		} +	case HW_VAR_BASIC_RATE:{ +			u16 b_rate_cfg = ((u16 *) val)[0]; +			u8 rate_index = 0; +			b_rate_cfg = b_rate_cfg & 0x15f; +			b_rate_cfg |= 0x01; +			rtl_write_byte(rtlpriv, REG_RRSR, b_rate_cfg & 0xff); +			rtl_write_byte(rtlpriv, REG_RRSR + 1, +				       (b_rate_cfg >> 8)&0xff); +			while (b_rate_cfg > 0x1) { +				b_rate_cfg = (b_rate_cfg >> 1); +				rate_index++; +			} +			rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, +				       rate_index); +			break; +		} +	case HW_VAR_BSSID:{ +			for (idx = 0; idx < ETH_ALEN; idx++) { +				rtl_write_byte(rtlpriv, (REG_BSSID + idx), +					       val[idx]); +			} +			break; +		} +	case HW_VAR_SIFS:{ +			rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]); +			rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]); + +			rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]); +			rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]); + +			if (!mac->ht_enable) +				rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, +					       0x0e0e); +			else +				rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, +					       *((u16 *) val)); +			break; +		} +	case HW_VAR_SLOT_TIME:{ +			u8 e_aci; + +			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +				 ("HW_VAR_SLOT_TIME %x\n", val[0])); + +			rtl_write_byte(rtlpriv, REG_SLOT, val[0]); + +			for (e_aci = 0; e_aci < AC_MAX; e_aci++) { +				rtlpriv->cfg->ops->set_hw_reg(hw, +							      HW_VAR_AC_PARAM, +							      (u8 *) (&e_aci)); +			} +			break; +		} +	case HW_VAR_ACK_PREAMBLE:{ +			u8 reg_tmp; +			u8 short_preamble = (bool) (*(u8 *) val); +			reg_tmp = (mac->cur_40_prime_sc) << 5; +			if (short_preamble) +				reg_tmp |= 0x80; + +			rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp); +			break; +		} +	case HW_VAR_AMPDU_MIN_SPACE:{ +			u8 min_spacing_to_set; +			u8 sec_min_space; + +			min_spacing_to_set = *((u8 *) val); +			if (min_spacing_to_set <= 7) { +				sec_min_space = 0; + +				if (min_spacing_to_set < sec_min_space) +					min_spacing_to_set = sec_min_space; + +				mac->min_space_cfg = ((mac->min_space_cfg & +						       0xf8) | +						      min_spacing_to_set); + +				*val = min_spacing_to_set; + +				RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +					 ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n", +					  mac->min_space_cfg)); + +				rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, +					       mac->min_space_cfg); +			} +			break; +		} +	case HW_VAR_SHORTGI_DENSITY:{ +			u8 density_to_set; + +			density_to_set = *((u8 *) val); +			mac->min_space_cfg |= (density_to_set << 3); + +			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +				 ("Set HW_VAR_SHORTGI_DENSITY: %#x\n", +				  mac->min_space_cfg)); + +			rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, +				       mac->min_space_cfg); + +			break; +		} +	case HW_VAR_AMPDU_FACTOR:{ +			u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 }; + +			u8 factor_toset; +			u8 *p_regtoset = NULL; +			u8 index = 0; + +			p_regtoset = regtoset_normal; + +			factor_toset = *((u8 *) val); +			if (factor_toset <= 3) { +				factor_toset = (1 << (factor_toset + 2)); +				if (factor_toset > 0xf) +					factor_toset = 0xf; + +				for (index = 0; index < 4; index++) { +					if ((p_regtoset[index] & 0xf0) > +					    (factor_toset << 4)) +						p_regtoset[index] = +						    (p_regtoset[index] & 0x0f) | +						    (factor_toset << 4); + +					if ((p_regtoset[index] & 0x0f) > +					    factor_toset) +						p_regtoset[index] = +						    (p_regtoset[index] & 0xf0) | +						    (factor_toset); + +					rtl_write_byte(rtlpriv, +						       (REG_AGGLEN_LMT + index), +						       p_regtoset[index]); + +				} + +				RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +					 ("Set HW_VAR_AMPDU_FACTOR: %#x\n", +					  factor_toset)); +			} +			break; +		} +	case HW_VAR_AC_PARAM:{ +			u8 e_aci = *((u8 *) val); +			u32 u4b_ac_param = 0; + +			u4b_ac_param |= (u32) mac->ac[e_aci].aifs; +			u4b_ac_param |= ((u32) mac->ac[e_aci].cw_min +					 & 0xF) << AC_PARAM_ECW_MIN_OFFSET; +			u4b_ac_param |= ((u32) mac->ac[e_aci].cw_max & +					 0xF) << AC_PARAM_ECW_MAX_OFFSET; +			u4b_ac_param |= (u32) mac->ac[e_aci].tx_op +			    << AC_PARAM_TXOP_LIMIT_OFFSET; + +			RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, +				 ("queue:%x, ac_param:%x\n", e_aci, +				  u4b_ac_param)); + +			switch (e_aci) { +			case AC1_BK: +				rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, +						u4b_ac_param); +				break; +			case AC0_BE: +				rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, +						u4b_ac_param); +				break; +			case AC2_VI: +				rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, +						u4b_ac_param); +				break; +			case AC3_VO: +				rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, +						u4b_ac_param); +				break; +			default: +				RT_ASSERT(false, +				  ("SetHwReg8185(): invalid aci: %d !\n", +				   e_aci)); +				break; +			} + +			if (rtlpci->acm_method != eAcmWay2_SW) +				rtlpriv->cfg->ops->set_hw_reg(hw, +							      HW_VAR_ACM_CTRL, +							      (u8 *) (&e_aci)); +			break; +		} +	case HW_VAR_ACM_CTRL:{ +			u8 e_aci = *((u8 *) val); +			union aci_aifsn *p_aci_aifsn = +			    (union aci_aifsn *)(&(mac->ac[0].aifs)); +			u8 acm = p_aci_aifsn->f.acm; +			u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL); + +			acm_ctrl = +			    acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1); + +			if (acm) { +				switch (e_aci) { +				case AC0_BE: +					acm_ctrl |= AcmHw_BeqEn; +					break; +				case AC2_VI: +					acm_ctrl |= AcmHw_ViqEn; +					break; +				case AC3_VO: +					acm_ctrl |= AcmHw_VoqEn; +					break; +				default: +					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +						 ("HW_VAR_ACM_CTRL acm set " +						  "failed: eACI is %d\n", acm)); +					break; +				} +			} else { +				switch (e_aci) { +				case AC0_BE: +					acm_ctrl &= (~AcmHw_BeqEn); +					break; +				case AC2_VI: +					acm_ctrl &= (~AcmHw_ViqEn); +					break; +				case AC3_VO: +					acm_ctrl &= (~AcmHw_BeqEn); +					break; +				default: +					RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +						 ("switch case not process\n")); +					break; +				} +			} + +			RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE, +				 ("SetHwReg8190pci(): [HW_VAR_ACM_CTRL] " +				  "Write 0x%X\n", acm_ctrl)); +			rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl); +			break; +		} +	case HW_VAR_RCR:{ +			rtl_write_dword(rtlpriv, REG_RCR, ((u32 *) (val))[0]); +			rtlpci->receive_config = ((u32 *) (val))[0]; +			break; +		} +	case HW_VAR_RETRY_LIMIT:{ +			u8 retry_limit = ((u8 *) (val))[0]; + +			rtl_write_word(rtlpriv, REG_RL, +				       retry_limit << RETRY_LIMIT_SHORT_SHIFT | +				       retry_limit << RETRY_LIMIT_LONG_SHIFT); +			break; +		} +	case HW_VAR_DUAL_TSF_RST: +		rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1))); +		break; +	case HW_VAR_EFUSE_BYTES: +		rtlefuse->efuse_usedbytes = *((u16 *) val); +		break; +	case HW_VAR_EFUSE_USAGE: +		rtlefuse->efuse_usedpercentage = *((u8 *) val); +		break; +	case HW_VAR_IO_CMD: +		rtl92c_phy_set_io_cmd(hw, (*(enum io_type *)val)); +		break; +	case HW_VAR_WPA_CONFIG: +		rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val)); +		break; +	case HW_VAR_SET_RPWM:{ +			u8 rpwm_val; + +			rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM); +			udelay(1); + +			if (rpwm_val & BIT(7)) { +				rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, +					       (*(u8 *) val)); +			} else { +				rtl_write_byte(rtlpriv, REG_PCIE_HRPWM, +					       ((*(u8 *) val) | BIT(7))); +			} + +			break; +		} +	case HW_VAR_H2C_FW_PWRMODE:{ +			u8 psmode = (*(u8 *) val); + +			if ((psmode != FW_PS_ACTIVE_MODE) && +			    (!IS_92C_SERIAL(rtlhal->version))) { +				rtl92c_dm_rf_saving(hw, true); +			} + +			rtl92c_set_fw_pwrmode_cmd(hw, (*(u8 *) val)); +			break; +		} +	case HW_VAR_FW_PSMODE_STATUS: +		ppsc->b_fw_current_inpsmode = *((bool *) val); +		break; +	case HW_VAR_H2C_FW_JOINBSSRPT:{ +			u8 mstatus = (*(u8 *) val); +			u8 tmp_regcr, tmp_reg422; +			bool b_recover = false; + +			if (mstatus == RT_MEDIA_CONNECT) { +				rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, +							      NULL); + +				tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1); +				rtl_write_byte(rtlpriv, REG_CR + 1, +					       (tmp_regcr | BIT(0))); + +				_rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(3)); +				_rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0); + +				tmp_reg422 = +				    rtl_read_byte(rtlpriv, +						  REG_FWHW_TXQ_CTRL + 2); +				if (tmp_reg422 & BIT(6)) +					b_recover = true; +				rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, +					       tmp_reg422 & (~BIT(6))); + +				rtl92c_set_fw_rsvdpagepkt(hw, 0); + +				_rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); +				_rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); + +				if (b_recover) { +					rtl_write_byte(rtlpriv, +						       REG_FWHW_TXQ_CTRL + 2, +						       tmp_reg422); +				} + +				rtl_write_byte(rtlpriv, REG_CR + 1, +					       (tmp_regcr & ~(BIT(0)))); +			} +			rtl92c_set_fw_joinbss_report_cmd(hw, (*(u8 *) val)); + +			break; +		} +	case HW_VAR_AID:{ +			u16 u2btmp; +			u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT); +			u2btmp &= 0xC000; +			rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp | +						mac->assoc_id)); + +			break; +		} +	case HW_VAR_CORRECT_TSF:{ +			u8 btype_ibss = ((u8 *) (val))[0]; + +			/*btype_ibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? +					1 : 0;*/ + +			if (btype_ibss == true) +				_rtl92ce_stop_tx_beacon(hw); + +			_rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(3)); + +			rtl_write_dword(rtlpriv, REG_TSFTR, +					(u32) (mac->tsf & 0xffffffff)); +			rtl_write_dword(rtlpriv, REG_TSFTR + 4, +					(u32) ((mac->tsf >> 32)&0xffffffff)); + +			_rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); + +			if (btype_ibss == true) +				_rtl92ce_resume_tx_beacon(hw); + +			break; + +		} +	case HW_VAR_MGT_FILTER: +		rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *) val); +		break; +	case HW_VAR_CTRL_FILTER: +		rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *) val); +		break; +	case HW_VAR_DATA_FILTER: +		rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *) val); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case " +							"not process\n")); +		break; +	} +} + +static bool _rtl92ce_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	bool status = true; +	long count = 0; +	u32 value = _LLT_INIT_ADDR(address) | +	    _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); + +	rtl_write_dword(rtlpriv, REG_LLT_INIT, value); + +	do { +		value = rtl_read_dword(rtlpriv, REG_LLT_INIT); +		if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) +			break; + +		if (count > POLLING_LLT_THRESHOLD) { +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("Failed to polling write LLT done at " +				  "address %d!\n", address)); +			status = false; +			break; +		} +	} while (++count); + +	return status; +} + +static bool _rtl92ce_llt_table_init(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	unsigned short i; +	u8 txpktbuf_bndy; +	u8 maxPage; +	bool status; + +#if LLT_CONFIG == 1 +	maxPage = 255; +	txpktbuf_bndy = 252; +#elif LLT_CONFIG == 2 +	maxPage = 127; +	txpktbuf_bndy = 124; +#elif LLT_CONFIG == 3 +	maxPage = 255; +	txpktbuf_bndy = 174; +#elif LLT_CONFIG == 4 +	maxPage = 255; +	txpktbuf_bndy = 246; +#elif LLT_CONFIG == 5 +	maxPage = 255; +	txpktbuf_bndy = 246; +#endif + +#if LLT_CONFIG == 1 +	rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x1c); +	rtl_write_dword(rtlpriv, REG_RQPN, 0x80a71c1c); +#elif LLT_CONFIG == 2 +	rtl_write_dword(rtlpriv, REG_RQPN, 0x845B1010); +#elif LLT_CONFIG == 3 +	rtl_write_dword(rtlpriv, REG_RQPN, 0x84838484); +#elif LLT_CONFIG == 4 +	rtl_write_dword(rtlpriv, REG_RQPN, 0x80bd1c1c); +#elif LLT_CONFIG == 5 +	rtl_write_word(rtlpriv, REG_RQPN_NPQ, 0x0000); + +	rtl_write_dword(rtlpriv, REG_RQPN, 0x80b01c29); +#endif + +	rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, (0x27FF0000 | txpktbuf_bndy)); +	rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy); + +	rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); +	rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); + +	rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy); +	rtl_write_byte(rtlpriv, REG_PBP, 0x11); +	rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4); + +	for (i = 0; i < (txpktbuf_bndy - 1); i++) { +		status = _rtl92ce_llt_write(hw, i, i + 1); +		if (true != status) +			return status; +	} + +	status = _rtl92ce_llt_write(hw, (txpktbuf_bndy - 1), 0xFF); +	if (true != status) +		return status; + +	for (i = txpktbuf_bndy; i < maxPage; i++) { +		status = _rtl92ce_llt_write(hw, i, (i + 1)); +		if (true != status) +			return status; +	} + +	status = _rtl92ce_llt_write(hw, maxPage, txpktbuf_bndy); +	if (true != status) +		return status; + +	return true; +} + +static void _rtl92ce_gen_refresh_led_state(struct ieee80211_hw *hw) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); + +	if (rtlpci->up_first_time) +		return; + +	if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) +		rtl92ce_sw_led_on(hw, pLed0); +	else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) +		rtl92ce_sw_led_on(hw, pLed0); +	else +		rtl92ce_sw_led_off(hw, pLed0); + +} + +static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) +{ +	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 char bytetmp; +	unsigned short wordtmp; +	u16 retry; + +	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); +	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); +	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F); + +	bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0); +	udelay(2); + +	rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp); +	udelay(2); + +	bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); +	udelay(2); + +	retry = 0; +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("reg0xec:%x:%x\n", +						rtl_read_dword(rtlpriv, 0xEC), +						bytetmp)); + +	while ((bytetmp & BIT(0)) && retry < 1000) { +		retry++; +		udelay(50); +		bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("reg0xec:%x:%x\n", +							rtl_read_dword(rtlpriv, +								       0xEC), +							bytetmp)); +		udelay(50); +	} + +	rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x1012); + +	rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82); +	udelay(2); + +	rtl_write_word(rtlpriv, REG_CR, 0x2ff); + +	if (_rtl92ce_llt_table_init(hw) == false) +		return false;; + +	rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff); +	rtl_write_byte(rtlpriv, REG_HISRE, 0xff); + +	rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x27ff); + +	wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL); +	wordtmp &= 0xf; +	wordtmp |= 0xF771; +	rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp); + +	rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F); +	rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config); +	rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config); + +	rtl_write_byte(rtlpriv, 0x4d0, 0x0); + +	rtl_write_dword(rtlpriv, REG_BCNQ_DESA, +			((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_MGQ_DESA, +			(u64) rtlpci->tx_ring[MGNT_QUEUE].dma & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_VOQ_DESA, +			(u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_VIQ_DESA, +			(u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_BEQ_DESA, +			(u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_BKQ_DESA, +			(u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_HQ_DESA, +			(u64) rtlpci->tx_ring[HIGH_QUEUE].dma & +			DMA_BIT_MASK(32)); +	rtl_write_dword(rtlpriv, REG_RX_DESA, +			(u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma & +			DMA_BIT_MASK(32)); + +	if (IS_92C_SERIAL(rtlhal->version)) +		rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x77); +	else +		rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x22); + +	rtl_write_dword(rtlpriv, REG_INT_MIG, 0); + +	bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); +	rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6)); +	do { +		retry++; +		bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL); +	} while ((retry < 200) && (bytetmp & BIT(7))); + +	_rtl92ce_gen_refresh_led_state(hw); + +	rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0); + +	return true;; +} + +static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) +{ +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 reg_bw_opmode; +	u32 reg_ratr, reg_prsr; + +	reg_bw_opmode = BW_OPMODE_20MHZ; +	reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | +	    RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; +	reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG; + +	rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8); + +	rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + +	rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr); + +	rtl_write_byte(rtlpriv, REG_SLOT, 0x09); + +	rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, 0x0); + +	rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F80); + +	rtl_write_word(rtlpriv, REG_RL, 0x0707); + +	rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x02012802); + +	rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF); + +	rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000); +	rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504); +	rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); +	rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504); + +	rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); + +	rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); + +	rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff); + +	rtlpci->reg_bcn_ctrl_val = 0x1f; +	rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val); + +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + +	rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff); + +	rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); +	rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + +	rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + +	rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + +	rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); + +	rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); + +	rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x1010); +	rtl_write_word(rtlpriv, REG_MAC_SPEC_SIFS, 0x1010); + +	rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x1010); + +	rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x1010); + +	rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff); +	rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff); + +} + +static void _rtl92ce_enable_aspm_back_door(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	rtl_write_byte(rtlpriv, 0x34b, 0x93); +	rtl_write_word(rtlpriv, 0x350, 0x870c); +	rtl_write_byte(rtlpriv, 0x352, 0x1); + +	if (ppsc->b_support_backdoor) +		rtl_write_byte(rtlpriv, 0x349, 0x1b); +	else +		rtl_write_byte(rtlpriv, 0x349, 0x03); + +	rtl_write_word(rtlpriv, 0x350, 0x2718); +	rtl_write_byte(rtlpriv, 0x352, 0x1); +} + +void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 sec_reg_value; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 ("PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n", +		  rtlpriv->sec.pairwise_enc_algorithm, +		  rtlpriv->sec.group_enc_algorithm)); + +	if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { +		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("not open " +							"hw encryption\n")); +		return; +	} + +	sec_reg_value = SCR_TxEncEnable | SCR_RxDecEnable; + +	if (rtlpriv->sec.use_defaultkey) { +		sec_reg_value |= SCR_TxUseDK; +		sec_reg_value |= SCR_RxUseDK; +	} + +	sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK); + +	rtl_write_byte(rtlpriv, REG_CR + 1, 0x02); + +	RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, +		 ("The SECR-value %x\n", sec_reg_value)); + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value); + +} + +int rtl92ce_hw_init(struct ieee80211_hw *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_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	static bool iqk_initialized; /* initialized to false */ +	bool rtstatus = true; +	bool is92c; +	int err; +	u8 tmp_u1b; + +	rtlpci->being_init_adapter = true; +	rtlpriv->intf_ops->disable_aspm(hw); +	rtstatus = _rtl92ce_init_mac(hw); +	if (rtstatus != true) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Init MAC failed\n")); +		err = 1; +		return err; +	} + +	err = rtl92c_download_fw(hw); +	if (err) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("Failed to download FW. Init HW " +			  "without FW now..\n")); +		err = 1; +		rtlhal->bfw_ready = false; +		return err; +	} else { +		rtlhal->bfw_ready = true; +	} + +	rtlhal->last_hmeboxnum = 0; +	rtl92c_phy_mac_config(hw); +	rtl92c_phy_bb_config(hw); +	rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; +	rtl92c_phy_rf_config(hw); +	rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, +						 RF_CHNLBW, RFREG_OFFSET_MASK); +	rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1, +						 RF_CHNLBW, RFREG_OFFSET_MASK); +	rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1); +	rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1); +	rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); +	_rtl92ce_hw_configure(hw); +	rtl_cam_reset_all_entry(hw); +	rtl92ce_enable_hw_security_config(hw); +	ppsc->rfpwr_state = ERFON; +	tmp_u1b = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG)&(~BIT(3)); +	rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, tmp_u1b); +	tmp_u1b = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL); +	ppsc->rfoff_reason |= (tmp_u1b & BIT(3)) ? 0 : RF_CHANGE_BY_HW; +	if (ppsc->rfoff_reason > RF_CHANGE_BY_PS) +		rtl_ps_set_rf_state(hw, ERFOFF, ppsc->rfoff_reason, true); +	else { +		ppsc->rfpwr_state = ERFON; +		ppsc->rfoff_reason = 0; +		rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON); +	} +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); +	_rtl92ce_enable_aspm_back_door(hw); +	rtlpriv->intf_ops->enable_aspm(hw); +	if (ppsc->rfpwr_state == ERFON) { +		rtl92c_phy_set_rfpath_switch(hw, 1); +		if (iqk_initialized) +			rtl92c_phy_iq_calibrate(hw, true); +		else { +			rtl92c_phy_iq_calibrate(hw, false); +			iqk_initialized = true; +		} + +		rtl92c_dm_check_txpower_tracking(hw); +		rtl92c_phy_lc_calibrate(hw); +	} + +	is92c = IS_92C_SERIAL(rtlhal->version); +	tmp_u1b = efuse_read_1byte(hw, 0x1FA); +	if (!(tmp_u1b & BIT(0))) { +		rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("PA BIAS path A\n")); +	} + +	if (!(tmp_u1b & BIT(1)) && is92c) { +		rtl_set_rfreg(hw, RF90_PATH_B, 0x15, 0x0F, 0x05); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("PA BIAS path B\n")); +	} + +	if (!(tmp_u1b & BIT(4))) { +		tmp_u1b = rtl_read_byte(rtlpriv, 0x16); +		tmp_u1b &= 0x0F; +		rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80); +		udelay(10); +		rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("under 1.5V\n")); +	} +	rtl92c_dm_init(hw); +	rtlpci->being_init_adapter = false; +	return err; +} + +static enum version_8192c _rtl92ce_read_chip_version(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	enum version_8192c version = VERSION_UNKNOWN; +	u32 value32; + +	value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG); +	if (value32 & TRP_VAUX_EN) { +		version = (value32 & TYPE_ID) ? VERSION_A_CHIP_92C : +			   VERSION_A_CHIP_88C; +	} else { +		version = (value32 & TYPE_ID) ? VERSION_B_CHIP_92C : +			   VERSION_B_CHIP_88C; +	} + +	switch (version) { +	case VERSION_B_CHIP_92C: +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Chip Version ID: VERSION_B_CHIP_92C.\n")); +		break; +	case VERSION_B_CHIP_88C: +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Chip Version ID: VERSION_B_CHIP_88C.\n")); +		break; +	case VERSION_A_CHIP_92C: +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Chip Version ID: VERSION_A_CHIP_92C.\n")); +		break; +	case VERSION_A_CHIP_88C: +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Chip Version ID: VERSION_A_CHIP_88C.\n")); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("Chip Version ID: Unknown. Bug?\n")); +		break; +	} + +	switch (version & 0x3) { +	case CHIP_88C: +		rtlphy->rf_type = RF_1T1R; +		break; +	case CHIP_92C: +		rtlphy->rf_type = RF_2T2R; +		break; +	case CHIP_92C_1T2R: +		rtlphy->rf_type = RF_1T2R; +		break; +	default: +		rtlphy->rf_type = RF_1T1R; +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("ERROR RF_Type is set!!")); +		break; +	} + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 ("Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ? +		  "RF_2T2R" : "RF_1T1R")); + +	return version; +} + +static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, +				     enum nl80211_iftype type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u8 bt_msr = rtl_read_byte(rtlpriv, MSR); +	enum led_ctl_mode ledaction = LED_CTL_NO_LINK; +	bt_msr &= 0xfc; + +	if (type == NL80211_IFTYPE_UNSPECIFIED || +	    type == NL80211_IFTYPE_STATION) { +		_rtl92ce_stop_tx_beacon(hw); +		_rtl92ce_enable_bcn_sub_func(hw); +	} else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) { +		_rtl92ce_resume_tx_beacon(hw); +		_rtl92ce_disable_bcn_sub_func(hw); +	} else { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("Set HW_VAR_MEDIA_STATUS: " +			  "No such media status(%x).\n", type)); +	} + +	switch (type) { +	case NL80211_IFTYPE_UNSPECIFIED: +		bt_msr |= MSR_NOLINK; +		ledaction = LED_CTL_LINK; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Set Network type to NO LINK!\n")); +		break; +	case NL80211_IFTYPE_ADHOC: +		bt_msr |= MSR_ADHOC; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Set Network type to Ad Hoc!\n")); +		break; +	case NL80211_IFTYPE_STATION: +		bt_msr |= MSR_INFRA; +		ledaction = LED_CTL_LINK; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Set Network type to STA!\n")); +		break; +	case NL80211_IFTYPE_AP: +		bt_msr |= MSR_AP; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Set Network type to AP!\n")); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("Network type %d not support!\n", type)); +		return 1; +		break; + +	} + +	rtl_write_byte(rtlpriv, (MSR), bt_msr); +	rtlpriv->cfg->ops->led_control(hw, ledaction); +	if ((bt_msr & 0xfc) == MSR_AP) +		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); +	else +		rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); +	return 0; +} + +static void _rtl92ce_set_check_bssid(struct ieee80211_hw *hw, +				     enum nl80211_iftype type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); +	u8 filterout_non_associated_bssid = false; + +	switch (type) { +	case NL80211_IFTYPE_ADHOC: +	case NL80211_IFTYPE_STATION: +		filterout_non_associated_bssid = true; +		break; +	case NL80211_IFTYPE_UNSPECIFIED: +	case NL80211_IFTYPE_AP: +	default: +		break; +	} + +	if (filterout_non_associated_bssid == true) { +		reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); +		rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, +					      (u8 *) (®_rcr)); +		_rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); +	} else if (filterout_non_associated_bssid == false) { +		reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); +		_rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0); +		rtlpriv->cfg->ops->set_hw_reg(hw, +					      HW_VAR_RCR, (u8 *) (®_rcr)); +	} +} + +int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ +	if (_rtl92ce_set_media_status(hw, type)) +		return -EOPNOTSUPP; +	_rtl92ce_set_check_bssid(hw, type); +	return 0; +} + +void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	u32 u4b_ac_param; + +	rtl92c_dm_init_edca_turbo(hw); + +	u4b_ac_param = (u32) mac->ac[aci].aifs; +	u4b_ac_param |= +	    ((u32) mac->ac[aci].cw_min & 0xF) << AC_PARAM_ECW_MIN_OFFSET; +	u4b_ac_param |= +	    ((u32) mac->ac[aci].cw_max & 0xF) << AC_PARAM_ECW_MAX_OFFSET; +	u4b_ac_param |= (u32) mac->ac[aci].tx_op << AC_PARAM_TXOP_LIMIT_OFFSET; +	RT_TRACE(rtlpriv, COMP_QOS, DBG_DMESG, +		 ("queue:%x, ac_param:%x aifs:%x cwmin:%x cwmax:%x txop:%x\n", +		  aci, u4b_ac_param, mac->ac[aci].aifs, mac->ac[aci].cw_min, +		  mac->ac[aci].cw_max, mac->ac[aci].tx_op)); +	switch (aci) { +	case AC1_BK: +		rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param); +		break; +	case AC0_BE: +		rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); +		break; +	case AC2_VI: +		rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param); +		break; +	case AC3_VO: +		rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param); +		break; +	default: +		RT_ASSERT(false, ("invalid aci: %d !\n", aci)); +		break; +	} +} + +void rtl92ce_enable_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); +	rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); +	rtlpci->irq_enabled = true; +} + +void rtl92ce_disable_interrupt(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED); +	rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); +	rtlpci->irq_enabled = false; +} + +static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 u1b_tmp; + +	rtlpriv->intf_ops->enable_aspm(hw); +	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); +	rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); +	rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00); +	rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE0); +	if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->bfw_ready) +		rtl92c_firmware_selfreset(hw); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, 0x51); +	rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); +	rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000); +	u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL); +	rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | +			(u1b_tmp << 8)); +	rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790); +	rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080); +	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); +	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); +	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); +	rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); +	rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10); +} + +void rtl92ce_card_disable(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	enum nl80211_iftype opmode; + +	mac->link_state = MAC80211_NOLINK; +	opmode = NL80211_IFTYPE_UNSPECIFIED; +	_rtl92ce_set_media_status(hw, opmode); +	if (rtlpci->driver_is_goingto_unload || +	    ppsc->rfoff_reason > RF_CHANGE_BY_PS) +		rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF); +	RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); +	_rtl92ce_poweroff_adapter(hw); +} + +void rtl92ce_interrupt_recognized(struct ieee80211_hw *hw, +				  u32 *p_inta, u32 *p_intb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	*p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0]; +	rtl_write_dword(rtlpriv, ISR, *p_inta); + +	/* +	 * *p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1]; +	 * rtl_write_dword(rtlpriv, ISR + 4, *p_intb); +	 */ +} + +void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw) +{ + +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u16 bcn_interval, atim_window; + +	bcn_interval = mac->beacon_interval; +	atim_window = 2;	/*FIX MERGE */ +	rtl92ce_disable_interrupt(hw); +	rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); +	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); +	rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f); +	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18); +	rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18); +	rtl_write_byte(rtlpriv, 0x606, 0x30); +	rtl92ce_enable_interrupt(hw); +} + +void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u16 bcn_interval = mac->beacon_interval; + +	RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, +		 ("beacon_interval:%d\n", bcn_interval)); +	rtl92ce_disable_interrupt(hw); +	rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); +	rtl92ce_enable_interrupt(hw); +} + +void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, +				   u32 add_msr, u32 rm_msr) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, +		 ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); +	if (add_msr) +		rtlpci->irq_mask[0] |= add_msr; +	if (rm_msr) +		rtlpci->irq_mask[0] &= (~rm_msr); +	rtl92ce_disable_interrupt(hw); +	rtl92ce_enable_interrupt(hw); +} + +static u8 _rtl92c_get_chnl_group(u8 chnl) +{ +	u8 group; + +	if (chnl < 3) +		group = 0; +	else if (chnl < 9) +		group = 1; +	else +		group = 2; +	return group; +} + +static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, +						 bool autoload_fail, +						 u8 *hwinfo) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 rf_path, index, tempval; +	u16 i; + +	for (rf_path = 0; rf_path < 2; rf_path++) { +		for (i = 0; i < 3; i++) { +			if (!autoload_fail) { +				rtlefuse-> +				    eeprom_chnlarea_txpwr_cck[rf_path][i] = +				    hwinfo[EEPROM_TXPOWERCCK + rf_path * 3 + i]; +				rtlefuse-> +				    eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = +				    hwinfo[EEPROM_TXPOWERHT40_1S + rf_path * 3 + +					   i]; +			} else { +				rtlefuse-> +				    eeprom_chnlarea_txpwr_cck[rf_path][i] = +				    EEPROM_DEFAULT_TXPOWERLEVEL; +				rtlefuse-> +				    eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] = +				    EEPROM_DEFAULT_TXPOWERLEVEL; +			} +		} +	} + +	for (i = 0; i < 3; i++) { +		if (!autoload_fail) +			tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i]; +		else +			tempval = EEPROM_DEFAULT_HT40_2SDIFF; +		rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_A][i] = +		    (tempval & 0xf); +		rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[RF90_PATH_B][i] = +		    ((tempval & 0xf0) >> 4); +	} + +	for (rf_path = 0; rf_path < 2; rf_path++) +		for (i = 0; i < 3; i++) +			RTPRINT(rtlpriv, FINIT, INIT_EEPROM, +				("RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path, +				 i, +				 rtlefuse-> +				 eeprom_chnlarea_txpwr_cck[rf_path][i])); +	for (rf_path = 0; rf_path < 2; rf_path++) +		for (i = 0; i < 3; i++) +			RTPRINT(rtlpriv, FINIT, INIT_EEPROM, +				("RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n", +				 rf_path, i, +				 rtlefuse-> +				 eeprom_chnlarea_txpwr_ht40_1s[rf_path][i])); +	for (rf_path = 0; rf_path < 2; rf_path++) +		for (i = 0; i < 3; i++) +			RTPRINT(rtlpriv, FINIT, INIT_EEPROM, +				("RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n", +				 rf_path, i, +				 rtlefuse-> +				 eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path] +				 [i])); + +	for (rf_path = 0; rf_path < 2; rf_path++) { +		for (i = 0; i < 14; i++) { +			index = _rtl92c_get_chnl_group((u8) i); + +			rtlefuse->txpwrlevel_cck[rf_path][i] = +			    rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][index]; +			rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = +			    rtlefuse-> +			    eeprom_chnlarea_txpwr_ht40_1s[rf_path][index]; + +			if ((rtlefuse-> +			     eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - +			     rtlefuse-> +			     eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][index]) +			    > 0) { +				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = +				    rtlefuse-> +				    eeprom_chnlarea_txpwr_ht40_1s[rf_path] +				    [index] - +				    rtlefuse-> +				    eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path] +				    [index]; +			} else { +				rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; +			} +		} + +		for (i = 0; i < 14; i++) { +			RTPRINT(rtlpriv, FINIT, INIT_TxPower, +				("RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = " +				 "[0x%x / 0x%x / 0x%x]\n", rf_path, i, +				 rtlefuse->txpwrlevel_cck[rf_path][i], +				 rtlefuse->txpwrlevel_ht40_1s[rf_path][i], +				 rtlefuse->txpwrlevel_ht40_2s[rf_path][i])); +		} +	} + +	for (i = 0; i < 3; i++) { +		if (!autoload_fail) { +			rtlefuse->eeprom_pwrlimit_ht40[i] = +			    hwinfo[EEPROM_TXPWR_GROUP + i]; +			rtlefuse->eeprom_pwrlimit_ht20[i] = +			    hwinfo[EEPROM_TXPWR_GROUP + 3 + i]; +		} else { +			rtlefuse->eeprom_pwrlimit_ht40[i] = 0; +			rtlefuse->eeprom_pwrlimit_ht20[i] = 0; +		} +	} + +	for (rf_path = 0; rf_path < 2; rf_path++) { +		for (i = 0; i < 14; i++) { +			index = _rtl92c_get_chnl_group((u8) i); + +			if (rf_path == RF90_PATH_A) { +				rtlefuse->pwrgroup_ht20[rf_path][i] = +				    (rtlefuse->eeprom_pwrlimit_ht20[index] +				     & 0xf); +				rtlefuse->pwrgroup_ht40[rf_path][i] = +				    (rtlefuse->eeprom_pwrlimit_ht40[index] +				     & 0xf); +			} else if (rf_path == RF90_PATH_B) { +				rtlefuse->pwrgroup_ht20[rf_path][i] = +				    ((rtlefuse->eeprom_pwrlimit_ht20[index] +				      & 0xf0) >> 4); +				rtlefuse->pwrgroup_ht40[rf_path][i] = +				    ((rtlefuse->eeprom_pwrlimit_ht40[index] +				      & 0xf0) >> 4); +			} + +			RTPRINT(rtlpriv, FINIT, INIT_TxPower, +				("RF-%d pwrgroup_ht20[%d] = 0x%x\n", +				 rf_path, i, +				 rtlefuse->pwrgroup_ht20[rf_path][i])); +			RTPRINT(rtlpriv, FINIT, INIT_TxPower, +				("RF-%d pwrgroup_ht40[%d] = 0x%x\n", +				 rf_path, i, +				 rtlefuse->pwrgroup_ht40[rf_path][i])); +		} +	} + +	for (i = 0; i < 14; i++) { +		index = _rtl92c_get_chnl_group((u8) i); + +		if (!autoload_fail) +			tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index]; +		else +			tempval = EEPROM_DEFAULT_HT20_DIFF; + +		rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF); +		rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] = +		    ((tempval >> 4) & 0xF); + +		if (rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] & BIT(3)) +			rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] |= 0xF0; + +		if (rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] & BIT(3)) +			rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] |= 0xF0; + +		index = _rtl92c_get_chnl_group((u8) i); + +		if (!autoload_fail) +			tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index]; +		else +			tempval = EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF; + +		rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = (tempval & 0xF); +		rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] = +		    ((tempval >> 4) & 0xF); +	} + +	rtlefuse->legacy_ht_txpowerdiff = +	    rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7]; + +	for (i = 0; i < 14; i++) +		RTPRINT(rtlpriv, FINIT, INIT_TxPower, +			("RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i, +			 rtlefuse->txpwr_ht20diff[RF90_PATH_A][i])); +	for (i = 0; i < 14; i++) +		RTPRINT(rtlpriv, FINIT, INIT_TxPower, +			("RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i, +			 rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i])); +	for (i = 0; i < 14; i++) +		RTPRINT(rtlpriv, FINIT, INIT_TxPower, +			("RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i, +			 rtlefuse->txpwr_ht20diff[RF90_PATH_B][i])); +	for (i = 0; i < 14; i++) +		RTPRINT(rtlpriv, FINIT, INIT_TxPower, +			("RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i, +			 rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i])); + +	if (!autoload_fail) +		rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7); +	else +		rtlefuse->eeprom_regulatory = 0; +	RTPRINT(rtlpriv, FINIT, INIT_TxPower, +		("eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory)); + +	if (!autoload_fail) { +		rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A]; +		rtlefuse->eeprom_tssi[RF90_PATH_B] = hwinfo[EEPROM_TSSI_B]; +	} else { +		rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI; +		rtlefuse->eeprom_tssi[RF90_PATH_B] = EEPROM_DEFAULT_TSSI; +	} +	RTPRINT(rtlpriv, FINIT, INIT_TxPower, +		("TSSI_A = 0x%x, TSSI_B = 0x%x\n", +		 rtlefuse->eeprom_tssi[RF90_PATH_A], +		 rtlefuse->eeprom_tssi[RF90_PATH_B])); + +	if (!autoload_fail) +		tempval = hwinfo[EEPROM_THERMAL_METER]; +	else +		tempval = EEPROM_DEFAULT_THERMALMETER; +	rtlefuse->eeprom_thermalmeter = (tempval & 0x1f); + +	if (rtlefuse->eeprom_thermalmeter == 0x1f || autoload_fail) +		rtlefuse->b_apk_thermalmeterignore = true; + +	rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter; +	RTPRINT(rtlpriv, FINIT, INIT_TxPower, +		("thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter)); +} + +static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u16 i, usvalue; +	u8 hwinfo[HWSET_MAX_SIZE]; +	u16 eeprom_id; + +	if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) { +		rtl_efuse_shadow_map_update(hw); + +		memcpy((void *)hwinfo, +		       (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], +		       HWSET_MAX_SIZE); +	} else if (rtlefuse->epromtype == EEPROM_93C46) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("RTL819X Not boot from eeprom, check it !!")); +	} + +	RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("MAP\n"), +		      hwinfo, HWSET_MAX_SIZE); + +	eeprom_id = *((u16 *)&hwinfo[0]); +	if (eeprom_id != RTL8190_EEPROM_ID) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("EEPROM ID(%#x) is invalid!!\n", eeprom_id)); +		rtlefuse->autoload_failflag = true; +	} else { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); +		rtlefuse->autoload_failflag = false; +	} + +	if (rtlefuse->autoload_failflag == true) +		return; + +	for (i = 0; i < 6; i += 2) { +		usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i]; +		*((u16 *) (&rtlefuse->dev_addr[i])) = usvalue; +	} + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, +		 (MAC_FMT "\n", MAC_ARG(rtlefuse->dev_addr))); + +	_rtl92ce_read_txpower_info_from_hwpg(hw, +					     rtlefuse->autoload_failflag, +					     hwinfo); + +	rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; +	rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; +	rtlefuse->b_txpwr_fromeprom = true; +	rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID]; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, +		 ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid)); + +	if (rtlhal->oem_id == RT_CID_DEFAULT) { +		switch (rtlefuse->eeprom_oemid) { +		case EEPROM_CID_DEFAULT: +			if (rtlefuse->eeprom_did == 0x8176) { +				if ((rtlefuse->eeprom_svid == 0x103C && +				     rtlefuse->eeprom_smid == 0x1629)) +					rtlhal->oem_id = RT_CID_819x_HP; +				else +					rtlhal->oem_id = RT_CID_DEFAULT; +			} else { +				rtlhal->oem_id = RT_CID_DEFAULT; +			} +			break; +		case EEPROM_CID_TOSHIBA: +			rtlhal->oem_id = RT_CID_TOSHIBA; +			break; +		case EEPROM_CID_QMI: +			rtlhal->oem_id = RT_CID_819x_QMI; +			break; +		case EEPROM_CID_WHQL: +		default: +			rtlhal->oem_id = RT_CID_DEFAULT; +			break; + +		} +	} + +} + +static void _rtl92ce_hal_customized_behavior(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)); + +	switch (rtlhal->oem_id) { +	case RT_CID_819x_HP: +		pcipriv->ledctl.bled_opendrain = true; +		break; +	case RT_CID_819x_Lenovo: +	case RT_CID_DEFAULT: +	case RT_CID_TOSHIBA: +	case RT_CID_CCX: +	case RT_CID_819x_Acer: +	case RT_CID_WHQL: +	default: +		break; +	} +	RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, +		 ("RT Customized ID: 0x%02X\n", rtlhal->oem_id)); +} + +void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 tmp_u1b; + +	rtlhal->version = _rtl92ce_read_chip_version(hw); +	if (get_rf_type(rtlphy) == RF_1T1R) +		rtlpriv->dm.brfpath_rxenable[0] = true; +	else +		rtlpriv->dm.brfpath_rxenable[0] = +		    rtlpriv->dm.brfpath_rxenable[1] = true; +	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("VersionID = 0x%4x\n", +						rtlhal->version)); +	tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); +	if (tmp_u1b & BIT(4)) { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n")); +		rtlefuse->epromtype = EEPROM_93C46; +	} else { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n")); +		rtlefuse->epromtype = EEPROM_BOOT_EFUSE; +	} +	if (tmp_u1b & BIT(5)) { +		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n")); +		rtlefuse->autoload_failflag = false; +		_rtl92ce_read_adapter_info(hw); +	} else { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); +	} + +	_rtl92ce_hal_customized_behavior(hw); +} + +void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + +	u32 ratr_value = (u32) mac->basic_rates; +	u8 *p_mcsrate = mac->mcs; +	u8 ratr_index = 0; +	u8 b_nmode = mac->ht_enable; +	u8 mimo_ps = 1; +	u16 shortgi_rate; +	u32 tmp_ratr_value; +	u8 b_curtxbw_40mhz = mac->bw_40; +	u8 b_curshortgi_40mhz = mac->sgi_40; +	u8 b_curshortgi_20mhz = mac->sgi_20; +	enum wireless_mode wirelessmode = mac->mode; + +	ratr_value |= EF2BYTE((*(u16 *) (p_mcsrate))) << 12; + +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		if (ratr_value & 0x0000000c) +			ratr_value &= 0x0000000d; +		else +			ratr_value &= 0x0000000f; +		break; +	case WIRELESS_MODE_G: +		ratr_value &= 0x00000FF5; +		break; +	case WIRELESS_MODE_N_24G: +	case WIRELESS_MODE_N_5G: +		b_nmode = 1; +		if (mimo_ps == 0) { +			ratr_value &= 0x0007F005; +		} else { +			u32 ratr_mask; + +			if (get_rf_type(rtlphy) == RF_1T2R || +			    get_rf_type(rtlphy) == RF_1T1R) +				ratr_mask = 0x000ff005; +			else +				ratr_mask = 0x0f0ff005; + +			ratr_value &= ratr_mask; +		} +		break; +	default: +		if (rtlphy->rf_type == RF_1T2R) +			ratr_value &= 0x000ff0ff; +		else +			ratr_value &= 0x0f0ff0ff; + +		break; +	} + +	ratr_value &= 0x0FFFFFFF; + +	if (b_nmode && ((b_curtxbw_40mhz && +			 b_curshortgi_40mhz) || (!b_curtxbw_40mhz && +						 b_curshortgi_20mhz))) { + +		ratr_value |= 0x10000000; +		tmp_ratr_value = (ratr_value >> 12); + +		for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { +			if ((1 << shortgi_rate) & tmp_ratr_value) +				break; +		} + +		shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | +		    (shortgi_rate << 4) | (shortgi_rate); +	} + +	rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); + +	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, +		 ("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0))); +} + +void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u32 ratr_bitmap = (u32) mac->basic_rates; +	u8 *p_mcsrate = mac->mcs; +	u8 ratr_index; +	u8 b_curtxbw_40mhz = mac->bw_40; +	u8 b_curshortgi_40mhz = mac->sgi_40; +	u8 b_curshortgi_20mhz = mac->sgi_20; +	enum wireless_mode wirelessmode = mac->mode; +	bool b_shortgi = false; +	u8 rate_mask[5]; +	u8 macid = 0; +	u8 mimops = 1; + +	ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12); +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		ratr_index = RATR_INX_WIRELESS_B; +		if (ratr_bitmap & 0x0000000c) +			ratr_bitmap &= 0x0000000d; +		else +			ratr_bitmap &= 0x0000000f; +		break; +	case WIRELESS_MODE_G: +		ratr_index = RATR_INX_WIRELESS_GB; + +		if (rssi_level == 1) +			ratr_bitmap &= 0x00000f00; +		else if (rssi_level == 2) +			ratr_bitmap &= 0x00000ff0; +		else +			ratr_bitmap &= 0x00000ff5; +		break; +	case WIRELESS_MODE_A: +		ratr_index = RATR_INX_WIRELESS_A; +		ratr_bitmap &= 0x00000ff0; +		break; +	case WIRELESS_MODE_N_24G: +	case WIRELESS_MODE_N_5G: +		ratr_index = RATR_INX_WIRELESS_NGB; + +		if (mimops == 0) { +			if (rssi_level == 1) +				ratr_bitmap &= 0x00070000; +			else if (rssi_level == 2) +				ratr_bitmap &= 0x0007f000; +			else +				ratr_bitmap &= 0x0007f005; +		} else { +			if (rtlphy->rf_type == RF_1T2R || +			    rtlphy->rf_type == RF_1T1R) { +				if (b_curtxbw_40mhz) { +					if (rssi_level == 1) +						ratr_bitmap &= 0x000f0000; +					else if (rssi_level == 2) +						ratr_bitmap &= 0x000ff000; +					else +						ratr_bitmap &= 0x000ff015; +				} else { +					if (rssi_level == 1) +						ratr_bitmap &= 0x000f0000; +					else if (rssi_level == 2) +						ratr_bitmap &= 0x000ff000; +					else +						ratr_bitmap &= 0x000ff005; +				} +			} else { +				if (b_curtxbw_40mhz) { +					if (rssi_level == 1) +						ratr_bitmap &= 0x0f0f0000; +					else if (rssi_level == 2) +						ratr_bitmap &= 0x0f0ff000; +					else +						ratr_bitmap &= 0x0f0ff015; +				} else { +					if (rssi_level == 1) +						ratr_bitmap &= 0x0f0f0000; +					else if (rssi_level == 2) +						ratr_bitmap &= 0x0f0ff000; +					else +						ratr_bitmap &= 0x0f0ff005; +				} +			} +		} + +		if ((b_curtxbw_40mhz && b_curshortgi_40mhz) || +		    (!b_curtxbw_40mhz && b_curshortgi_20mhz)) { + +			if (macid == 0) +				b_shortgi = true; +			else if (macid == 1) +				b_shortgi = false; +		} +		break; +	default: +		ratr_index = RATR_INX_WIRELESS_NGB; + +		if (rtlphy->rf_type == RF_1T2R) +			ratr_bitmap &= 0x000ff0ff; +		else +			ratr_bitmap &= 0x0f0ff0ff; +		break; +	} +	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, +		 ("ratr_bitmap :%x\n", ratr_bitmap)); +	*(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | +				       (ratr_index << 28)); +	rate_mask[4] = macid | (b_shortgi ? 0x20 : 0x00) | 0x80; +	RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("Rate_index:%x, " +						 "ratr_val:%x, %x:%x:%x:%x:%x\n", +						 ratr_index, ratr_bitmap, +						 rate_mask[0], rate_mask[1], +						 rate_mask[2], rate_mask[3], +						 rate_mask[4])); +	rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); +} + +void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u16 sifs_timer; + +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME, +				      (u8 *)&mac->slot_time); +	if (!mac->ht_enable) +		sifs_timer = 0x0a0a; +	else +		sifs_timer = 0x1010; +	rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); +} + +bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; +	u8 u1tmp; +	bool b_actuallyset = false; +	unsigned long flag; + +	if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter)) +		return false; + +	if (ppsc->b_swrf_processing) +		return false; + +	spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); +	if (ppsc->rfchange_inprogress) { +		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); +		return false; +	} else { +		ppsc->rfchange_inprogress = true; +		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); +	} + +	cur_rfstate = ppsc->rfpwr_state; + +	if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && +	    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { +		rtlpriv->intf_ops->disable_aspm(hw); +		RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +	} + +	rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv, +		       REG_MAC_PINMUX_CFG)&~(BIT(3))); + +	u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL); +	e_rfpowerstate_toset = (u1tmp & BIT(3)) ? ERFON : ERFOFF; + +	if ((ppsc->b_hwradiooff == true) && (e_rfpowerstate_toset == ERFON)) { +		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +			 ("GPIOChangeRF  - HW Radio ON, RF ON\n")); + +		e_rfpowerstate_toset = ERFON; +		ppsc->b_hwradiooff = false; +		b_actuallyset = true; +	} else if ((ppsc->b_hwradiooff == false) +		   && (e_rfpowerstate_toset == ERFOFF)) { +		RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +			 ("GPIOChangeRF  - HW Radio OFF, RF OFF\n")); + +		e_rfpowerstate_toset = ERFOFF; +		ppsc->b_hwradiooff = true; +		b_actuallyset = true; +	} + +	if (b_actuallyset) { +		if (e_rfpowerstate_toset == ERFON) { +			if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && +			    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { +				rtlpriv->intf_ops->disable_aspm(hw); +				RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +			} +		} + +		spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); +		ppsc->rfchange_inprogress = false; +		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + +		if (e_rfpowerstate_toset == ERFOFF) { +			if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { +				rtlpriv->intf_ops->enable_aspm(hw); +				RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +			} +		} + +	} else if (e_rfpowerstate_toset == ERFOFF || cur_rfstate == ERFOFF) { +		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) +			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); + +		if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { +			rtlpriv->intf_ops->enable_aspm(hw); +			RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); +		} + +		spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); +		ppsc->rfchange_inprogress = false; +		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); +	} else { +		spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); +		ppsc->rfchange_inprogress = false; +		spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); +	} + +	*valid = 1; +	return !ppsc->b_hwradiooff; + +} + +void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, +		     u8 *p_macaddr, bool is_group, u8 enc_algo, +		     bool is_wepkey, bool clear_all) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 *macaddr = p_macaddr; +	u32 entry_id = 0; +	bool is_pairwise = false; + +	static u8 cam_const_addr[4][6] = { +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x03} +	}; +	static u8 cam_const_broad[] = { +		0xff, 0xff, 0xff, 0xff, 0xff, 0xff +	}; + +	if (clear_all) { +		u8 idx = 0; +		u8 cam_offset = 0; +		u8 clear_number = 5; + +		RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("clear_all\n")); + +		for (idx = 0; idx < clear_number; idx++) { +			rtl_cam_mark_invalid(hw, cam_offset + idx); +			rtl_cam_empty_entry(hw, cam_offset + idx); + +			if (idx < 5) { +				memset(rtlpriv->sec.key_buf[idx], 0, +				       MAX_KEY_LEN); +				rtlpriv->sec.key_len[idx] = 0; +			} +		} + +	} else { +		switch (enc_algo) { +		case WEP40_ENCRYPTION: +			enc_algo = CAM_WEP40; +			break; +		case WEP104_ENCRYPTION: +			enc_algo = CAM_WEP104; +			break; +		case TKIP_ENCRYPTION: +			enc_algo = CAM_TKIP; +			break; +		case AESCCMP_ENCRYPTION: +			enc_algo = CAM_AES; +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case " +					"not process\n")); +			enc_algo = CAM_TKIP; +			break; +		} + +		if (is_wepkey || rtlpriv->sec.use_defaultkey) { +			macaddr = cam_const_addr[key_index]; +			entry_id = key_index; +		} else { +			if (is_group) { +				macaddr = cam_const_broad; +				entry_id = key_index; +			} else { +				key_index = PAIRWISE_KEYIDX; +				entry_id = CAM_PAIRWISE_KEY_POSITION; +				is_pairwise = true; +			} +		} + +		if (rtlpriv->sec.key_len[key_index] == 0) { +			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("delete one entry\n")); +			rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); +		} else { +			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, +				 ("The insert KEY length is %d\n", +				  rtlpriv->sec.key_len[PAIRWISE_KEYIDX])); +			RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, +				 ("The insert KEY  is %x %x\n", +				  rtlpriv->sec.key_buf[0][0], +				  rtlpriv->sec.key_buf[0][1])); + +			RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +				 ("add one entry\n")); +			if (is_pairwise) { +				RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, +					      "Pairwiase Key content :", +					      rtlpriv->sec.pairwise_key, +					      rtlpriv->sec. +					      key_len[PAIRWISE_KEYIDX]); + +				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +					 ("set Pairwiase key\n")); + +				rtl_cam_add_one_entry(hw, macaddr, key_index, +						      entry_id, enc_algo, +						      CAM_CONFIG_NO_USEDK, +						      rtlpriv->sec. +						      key_buf[key_index]); +			} else { +				RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, +					 ("set group key\n")); + +				if (mac->opmode == NL80211_IFTYPE_ADHOC) { +					rtl_cam_add_one_entry(hw, +						rtlefuse->dev_addr, +						PAIRWISE_KEYIDX, +						CAM_PAIRWISE_KEY_POSITION, +						enc_algo, +						CAM_CONFIG_NO_USEDK, +						rtlpriv->sec.key_buf +						[entry_id]); +				} + +				rtl_cam_add_one_entry(hw, macaddr, key_index, +						entry_id, enc_algo, +						CAM_CONFIG_NO_USEDK, +						rtlpriv->sec.key_buf[entry_id]); +			} + +		} +	} +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-hw.h new file mode 100644 index 00000000000..305c819c8c7 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-hw.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92CE_HW_H__ +#define __RTL92CE_HW_H__ + +void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw); +void rtl92ce_interrupt_recognized(struct ieee80211_hw *hw, +				  u32 *p_inta, u32 *p_intb); +int rtl92ce_hw_init(struct ieee80211_hw *hw); +void rtl92ce_card_disable(struct ieee80211_hw *hw); +void rtl92ce_enable_interrupt(struct ieee80211_hw *hw); +void rtl92ce_disable_interrupt(struct ieee80211_hw *hw); +int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci); +void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw); +void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw); +void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, +				   u32 add_msr, u32 rm_msr); +void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); +void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw); +void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); +void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw); +bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); +void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw); +void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, +		     u8 *p_macaddr, bool is_group, u8 enc_algo, +		     bool is_wepkey, bool clear_all); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-led.c new file mode 100644 index 00000000000..60910842157 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-led.c @@ -0,0 +1,144 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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 "../pci.h" +#include "rtl8192c-reg.h" +#include "rtl8192c-led.h" + +void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ +	u8 ledcfg; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, +		 ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin)); + +	ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + +	switch (pled->ledpin) { +	case LED_PIN_GPIO0: +		break; +	case LED_PIN_LED0: +		rtl_write_byte(rtlpriv, +			       REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6)); +		break; +	case LED_PIN_LED1: +		rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} +	pled->b_ledon = true; +} + +void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	u8 ledcfg; + +	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, +		 ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin)); + +	ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + +	switch (pled->ledpin) { +	case LED_PIN_GPIO0: +		break; +	case LED_PIN_LED0: +		ledcfg &= 0xf0; +		if (pcipriv->ledctl.bled_opendrain == true) +			rtl_write_byte(rtlpriv, REG_LEDCFG2, +				       (ledcfg | BIT(1) | BIT(5) | BIT(6))); +		else +			rtl_write_byte(rtlpriv, REG_LEDCFG2, +				       (ledcfg | BIT(3) | BIT(5) | BIT(6))); +		break; +	case LED_PIN_LED1: +		ledcfg &= 0x0f; +		rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} +	pled->b_ledon = false; +} + +void rtl92ce_init_sw_leds(struct ieee80211_hw *hw) +{ +} + +void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw) +{ +} + +void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, +				    enum led_ctl_mode ledaction) +{ +	struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); +	struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0); +	switch (ledaction) { +	case LED_CTL_POWER_ON: +	case LED_CTL_LINK: +	case LED_CTL_NO_LINK: +		rtl92ce_sw_led_on(hw, pLed0); +		break; +	case LED_CTL_POWER_OFF: +		rtl92ce_sw_led_off(hw, pLed0); +		break; +	default: +		break; +	} +} + +void rtl92ce_led_control(struct ieee80211_hw *hw, +			enum led_ctl_mode ledaction) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + +	if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && +	    (ledaction == LED_CTL_TX || +	     ledaction == LED_CTL_RX || +	     ledaction == LED_CTL_SITE_SURVEY || +	     ledaction == LED_CTL_LINK || +	     ledaction == LED_CTL_NO_LINK || +	     ledaction == LED_CTL_START_TO_LINK || +	     ledaction == LED_CTL_POWER_ON)) { +		return; +	} +	RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", +				ledaction)); +	_rtl92ce_sw_led_control(hw, ledaction); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-led.h new file mode 100644 index 00000000000..10da3018f4b --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-led.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92CE_LED_H__ +#define __RTL92CE_LED_H__ + +void rtl92ce_init_sw_leds(struct ieee80211_hw *hw); +void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw); +void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); +void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, +				    enum led_ctl_mode ledaction); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-phy.c new file mode 100644 index 00000000000..13d7b387a96 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-phy.c @@ -0,0 +1,2676 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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 "../pci.h" +#include "../ps.h" +#include "rtl8192c-reg.h" +#include "rtl8192c-def.h" +#include "rtl8192c-phy.h" +#include "rtl8192c-rf.h" +#include "rtl8192c-dm.h" +#include "rtl8192c-table.h" + +static u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, +					 enum radio_path rfpath, u32 offset); +static void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, +					   enum radio_path rfpath, u32 offset, +					   u32 data); +static u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, +				      enum radio_path rfpath, u32 offset); +static void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, +					enum radio_path rfpath, u32 offset, +					u32 data); +static u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask); +static bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); +static bool _rtl92c_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, +						  u8 configtype); +static bool _rtl92c_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, +						    u8 configtype); +static void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); +static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, +					     u32 cmdtableidx, u32 cmdtablesz, +					     enum swchnlcmd_id cmdid, u32 para1, +					     u32 para2, u32 msdelay); +static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, +					     u8 channel, u8 *stage, u8 *step, +					     u32 *delay); +static u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, +				       enum wireless_mode wirelessmode, +				       long power_indbm); +static bool _rtl92c_phy_config_rf_external_pa(struct ieee80211_hw *hw, +					      enum radio_path rfpath); +static long _rtl92c_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, +					 enum wireless_mode wirelessmode, +					 u8 txpwridx); +u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 returnvalue, originalvalue, bitshift; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), " +					       "bitmask(%#x)\n", regaddr, +					       bitmask)); +	originalvalue = rtl_read_dword(rtlpriv, regaddr); +	bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); +	returnvalue = (originalvalue & bitmask) >> bitshift; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("BBR MASK=0x%x " +					       "Addr[0x%x]=0x%x\n", bitmask, +					       regaddr, originalvalue)); + +	return returnvalue; + +} + +void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, +			   u32 regaddr, u32 bitmask, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 originalvalue, bitshift; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," +					       " data(%#x)\n", regaddr, bitmask, +					       data)); + +	if (bitmask != MASKDWORD) { +		originalvalue = rtl_read_dword(rtlpriv, regaddr); +		bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); +		data = ((originalvalue & (~bitmask)) | (data << bitshift)); +	} + +	rtl_write_dword(rtlpriv, regaddr, data); + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," +					       " data(%#x)\n", regaddr, bitmask, +					       data)); + +} + +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, +			    enum radio_path rfpath, u32 regaddr, u32 bitmask) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 original_value, readback_value, bitshift; +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	unsigned long flags; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), " +					       "rfpath(%#x), bitmask(%#x)\n", +					       regaddr, rfpath, bitmask)); + +	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + +	if (rtlphy->rf_mode != RF_OP_BY_FW) { +		original_value = _rtl92c_phy_rf_serial_read(hw, +							    rfpath, regaddr); +	} else { +		original_value = _rtl92c_phy_fw_rf_serial_read(hw, +							       rfpath, regaddr); +	} + +	bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); +	readback_value = (original_value & bitmask) >> bitshift; + +	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 ("regaddr(%#x), rfpath(%#x), " +		  "bitmask(%#x), original_value(%#x)\n", +		  regaddr, rfpath, bitmask, original_value)); + +	return readback_value; +} + +void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw, +			   enum radio_path rfpath, +			   u32 regaddr, u32 bitmask, u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 original_value, bitshift; +	unsigned long flags; + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, +		 ("regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", +		  regaddr, bitmask, data, rfpath)); + +	spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + +	if (rtlphy->rf_mode != RF_OP_BY_FW) { +		if (bitmask != RFREG_OFFSET_MASK) { +			original_value = _rtl92c_phy_rf_serial_read(hw, +								    rfpath, +								    regaddr); +			bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); +			data = +			    ((original_value & (~bitmask)) | +			     (data << bitshift)); +		} + +		_rtl92c_phy_rf_serial_write(hw, rfpath, regaddr, data); +	} else { +		if (bitmask != RFREG_OFFSET_MASK) { +			original_value = _rtl92c_phy_fw_rf_serial_read(hw, +								       rfpath, +								       regaddr); +			bitshift = _rtl92c_phy_calculate_bit_shift(bitmask); +			data = +			    ((original_value & (~bitmask)) | +			     (data << bitshift)); +		} +		_rtl92c_phy_fw_rf_serial_write(hw, rfpath, regaddr, data); +	} + +	spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), " +					       "bitmask(%#x), data(%#x), " +					       "rfpath(%#x)\n", regaddr, +					       bitmask, data, rfpath)); +} + +static u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, +					 enum radio_path rfpath, u32 offset) +{ +	RT_ASSERT(false, ("deprecated!\n")); +	return 0; +} + +static void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, +					   enum radio_path rfpath, u32 offset, +					   u32 data) +{ +	RT_ASSERT(false, ("deprecated!\n")); +} + +static u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, +				      enum radio_path rfpath, u32 offset) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; +	u32 newoffset; +	u32 tmplong, tmplong2; +	u8 rfpi_enable = 0; +	u32 retvalue; + +	offset &= 0x3f; +	newoffset = offset; +	if (RT_CANNOT_IO(hw)) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("return all one\n")); +		return 0xFFFFFFFF; +	} +	tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD); +	if (rfpath == RF90_PATH_A) +		tmplong2 = tmplong; +	else +		tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD); +	tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) | +	    (newoffset << 23) | BLSSIREADEDGE; +	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, +		      tmplong & (~BLSSIREADEDGE)); +	mdelay(1); +	rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); +	mdelay(1); +	rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, +		      tmplong | BLSSIREADEDGE); +	mdelay(1); +	if (rfpath == RF90_PATH_A) +		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, +						 BIT(8)); +	else if (rfpath == RF90_PATH_B) +		rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1, +						 BIT(8)); +	if (rfpi_enable) +		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi, +					 BLSSIREADBACKDATA); +	else +		retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback, +					 BLSSIREADBACKDATA); +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFR-%d Addr[0x%x]=0x%x\n", +					       rfpath, pphyreg->rflssi_readback, +					       retvalue)); +	return retvalue; +} + +static void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, +					enum radio_path rfpath, u32 offset, +					u32 data) +{ +	u32 data_and_addr; +	u32 newoffset; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath]; + +	if (RT_CANNOT_IO(hw)) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("stop\n")); +		return; +	} +	offset &= 0x3f; +	newoffset = offset; +	data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff; +	rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr); +	RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFW-%d Addr[0x%x]=0x%x\n", +					       rfpath, pphyreg->rf3wire_offset, +					       data_and_addr)); +} + +static u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask) +{ +	u32 i; + +	for (i = 0; i <= 31; i++) { +		if (((bitmask >> i) & 0x1) == 1) +			break; +	} +	return i; +} + +static void _rtl92c_phy_bb_config_1t(struct ieee80211_hw *hw) +{ +	rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2); +	rtl_set_bbreg(hw, RFPGA1_TXINFO, 0x300033, 0x200022); +	rtl_set_bbreg(hw, RCCK0_AFESETTING, MASKBYTE3, 0x45); +	rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x23); +	rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, 0x30, 0x1); +	rtl_set_bbreg(hw, 0xe74, 0x0c000000, 0x2); +	rtl_set_bbreg(hw, 0xe78, 0x0c000000, 0x2); +	rtl_set_bbreg(hw, 0xe7c, 0x0c000000, 0x2); +	rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2); +	rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2); +} + +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	bool is92c = IS_92C_SERIAL(rtlhal->version); +	bool rtstatus = _rtl92c_phy_config_mac_with_headerfile(hw); + +	if (is92c) +		rtl_write_byte(rtlpriv, 0x14, 0x71); +	return rtstatus; +} + +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw) +{ +	bool rtstatus = true; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u16 regval; +	u32 regvaldw; +	u8 b_reg_hwparafile = 1; + +	_rtl92c_phy_init_bb_rf_register_definition(hw); +	regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); +	rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, +		       regval | BIT(13) | BIT(0) | BIT(1)); +	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); +	rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); +	rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, +		       FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | +		       FEN_BB_GLB_RSTn | FEN_BBRSTB); +	rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); +	regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); +	rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); +	if (b_reg_hwparafile == 1) +		rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); +	return rtstatus; +} + +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw) +{ +	return rtl92c_phy_rf6052_config(hw); +} + +static bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	bool rtstatus; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("==>\n")); +	rtstatus = _rtl92c_phy_config_bb_with_headerfile(hw, +						 BASEBAND_CONFIG_PHY_REG); +	if (rtstatus != true) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Write BB Reg Fail!!")); +		return false; +	} +	if (rtlphy->rf_type == RF_1T2R) { +		_rtl92c_phy_bb_config_1t(hw); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Config to 1T!!\n")); +	} +	if (rtlefuse->autoload_failflag == false) { +		rtlphy->pwrgroup_cnt = 0; +		rtstatus = _rtl92c_phy_config_bb_with_pgheaderfile(hw, +						   BASEBAND_CONFIG_PHY_REG); +	} +	if (rtstatus != true) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("BB_PG Reg Fail!!")); +		return false; +	} +	rtstatus = _rtl92c_phy_config_bb_with_headerfile(hw, +						 BASEBAND_CONFIG_AGC_TAB); +	if (rtstatus != true) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("AGC Table Fail\n")); +		return false; +	} +	rtlphy->bcck_high_power = (bool) (rtl_get_bbreg(hw, +						RFPGA0_XA_HSSIPARAMETER2, +						0x200)); +	return true; +} + +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; +	u32 arraylength; +	u32 *ptrarray; + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Read Rtl819XMACPHY_Array\n")); +	arraylength = MAC_2T_ARRAYLENGTH; +	ptrarray = RTL8192CEMAC_2T_ARRAY; +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +		 ("Img:RTL8192CEMAC_2T_ARRAY\n")); +	for (i = 0; i < arraylength; i = i + 2) +		rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]); +	return true; +} + +void rtl92c_phy_config_bb_external_pa(struct ieee80211_hw *hw) +{ +} + +static bool _rtl92c_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, +						  u8 configtype) +{ +	int i; +	u32 *phy_regarray_table; +	u32 *agctab_array_table; +	u16 phy_reg_arraylen, agctab_arraylen; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (IS_92C_SERIAL(rtlhal->version)) { +		agctab_arraylen = AGCTAB_2TARRAYLENGTH; +		agctab_array_table = RTL8192CEAGCTAB_2TARRAY; +		phy_reg_arraylen = PHY_REG_2TARRAY_LENGTH; +		phy_regarray_table = RTL8192CEPHY_REG_2TARRAY; +	} else { +		agctab_arraylen = AGCTAB_1TARRAYLENGTH; +		agctab_array_table = RTL8192CEAGCTAB_1TARRAY; +		phy_reg_arraylen = PHY_REG_1TARRAY_LENGTH; +		phy_regarray_table = RTL8192CEPHY_REG_1TARRAY; +	} +	if (configtype == BASEBAND_CONFIG_PHY_REG) { +		for (i = 0; i < phy_reg_arraylen; i = i + 2) { +			if (phy_regarray_table[i] == 0xfe) +				mdelay(50); +			else if (phy_regarray_table[i] == 0xfd) +				mdelay(5); +			else if (phy_regarray_table[i] == 0xfc) +				mdelay(1); +			else if (phy_regarray_table[i] == 0xfb) +				udelay(50); +			else if (phy_regarray_table[i] == 0xfa) +				udelay(5); +			else if (phy_regarray_table[i] == 0xf9) +				udelay(1); +			rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD, +				      phy_regarray_table[i + 1]); +			udelay(1); +			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +				 ("The phy_regarray_table[0] is %x" +				  " Rtl819XPHY_REGArray[1] is %x\n", +				  phy_regarray_table[i], +				  phy_regarray_table[i + 1])); +		} +		rtl92c_phy_config_bb_external_pa(hw); +	} else if (configtype == BASEBAND_CONFIG_AGC_TAB) { +		for (i = 0; i < agctab_arraylen; i = i + 2) { +			rtl_set_bbreg(hw, agctab_array_table[i], MASKDWORD, +				      agctab_array_table[i + 1]); +			udelay(1); +			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +				 ("The agctab_array_table[0] is " +				  "%x Rtl819XPHY_REGArray[1] is %x\n", +				  agctab_array_table[i], +				  agctab_array_table[i + 1])); +		} +	} +	return true; +} + +static void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, +						   u32 regaddr, u32 bitmask, +						   u32 data) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	if (regaddr == RTXAGC_A_RATE18_06) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] = +		    data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][0])); +	} +	if (regaddr == RTXAGC_A_RATE54_24) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] = +		    data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][1])); +	} +	if (regaddr == RTXAGC_A_CCK1_MCS32) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] = +		    data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][6])); +	} +	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][7] = +		    data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][7])); +	} +	if (regaddr == RTXAGC_A_MCS03_MCS00) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] = +		    data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][2])); +	} +	if (regaddr == RTXAGC_A_MCS07_MCS04) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] = +		    data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][3])); +	} +	if (regaddr == RTXAGC_A_MCS11_MCS08) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] = +		    data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][4])); +	} +	if (regaddr == RTXAGC_A_MCS15_MCS12) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] = +		    data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][5])); +	} +	if (regaddr == RTXAGC_B_RATE18_06) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][8] = +		    data; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][8])); +	} +	if (regaddr == RTXAGC_B_RATE54_24) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][9] = +		    data; + +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][9])); +	} + +	if (regaddr == RTXAGC_B_CCK1_55_MCS32) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][14] = +		    data; + +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][14])); +	} + +	if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][15] = +		    data; + +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][15])); +	} + +	if (regaddr == RTXAGC_B_MCS03_MCS00) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][10] = +		    data; + +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][10])); +	} + +	if (regaddr == RTXAGC_B_MCS07_MCS04) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][11] = +		    data; + +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][11])); +	} + +	if (regaddr == RTXAGC_B_MCS11_MCS08) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][12] = +		    data; + +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][12])); +	} + +	if (regaddr == RTXAGC_B_MCS15_MCS12) { +		rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][13] = +		    data; + +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n", +			  rtlphy->pwrgroup_cnt, +			  rtlphy->mcs_txpwrlevel_origoffset[rtlphy-> +							    pwrgroup_cnt][13])); + +		rtlphy->pwrgroup_cnt++; +	} +} + +static bool _rtl92c_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, +						    u8 configtype) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int i; +	u32 *phy_regarray_table_pg; +	u16 phy_regarray_pg_len; + +	phy_regarray_pg_len = PHY_REG_ARRAY_PGLENGTH; +	phy_regarray_table_pg = RTL8192CEPHY_REG_ARRAY_PG; + +	if (configtype == BASEBAND_CONFIG_PHY_REG) { +		for (i = 0; i < phy_regarray_pg_len; i = i + 3) { +			if (phy_regarray_table_pg[i] == 0xfe) +				mdelay(50); +			else if (phy_regarray_table_pg[i] == 0xfd) +				mdelay(5); +			else if (phy_regarray_table_pg[i] == 0xfc) +				mdelay(1); +			else if (phy_regarray_table_pg[i] == 0xfb) +				udelay(50); +			else if (phy_regarray_table_pg[i] == 0xfa) +				udelay(5); +			else if (phy_regarray_table_pg[i] == 0xf9) +				udelay(1); + +			_rtl92c_store_pwrIndex_diffrate_offset(hw, +					       phy_regarray_table_pg[i], +					       phy_regarray_table_pg[i + 1], +					       phy_regarray_table_pg[i + 2]); +		} +	} else { + +		RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, +			 ("configtype != BaseBand_Config_PHY_REG\n")); +	} +	return true; +} + +static bool _rtl92c_phy_config_rf_external_pa(struct ieee80211_hw *hw, +					      enum radio_path rfpath) +{ +	return true; +} + +bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, +					  enum radio_path rfpath) +{ + +	int i; +	bool rtstatus = true; +	u32 *radioa_array_table; +	u32 *radiob_array_table; +	u16 radioa_arraylen, radiob_arraylen; +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (IS_92C_SERIAL(rtlhal->version)) { +		radioa_arraylen = RADIOA_2TARRAYLENGTH; +		radioa_array_table = RTL8192CERADIOA_2TARRAY; +		radiob_arraylen = RADIOB_2TARRAYLENGTH; +		radiob_array_table = RTL8192CE_RADIOB_2TARRAY; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Radio_A:RTL8192CERADIOA_2TARRAY\n")); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Radio_B:RTL8192CE_RADIOB_2TARRAY\n")); +	} else { +		radioa_arraylen = RADIOA_1TARRAYLENGTH; +		radioa_array_table = RTL8192CE_RADIOA_1TARRAY; +		radiob_arraylen = RADIOB_1TARRAYLENGTH; +		radiob_array_table = RTL8192CE_RADIOB_1TARRAY; +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Radio_A:RTL8192CE_RADIOA_1TARRAY\n")); +		RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +			 ("Radio_B:RTL8192CE_RADIOB_1TARRAY\n")); +	} +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Radio No %x\n", rfpath)); +	rtstatus = true; +	switch (rfpath) { +	case RF90_PATH_A: +		for (i = 0; i < radioa_arraylen; i = i + 2) { +			if (radioa_array_table[i] == 0xfe) +				mdelay(50); +			else if (radioa_array_table[i] == 0xfd) +				mdelay(5); +			else if (radioa_array_table[i] == 0xfc) +				mdelay(1); +			else if (radioa_array_table[i] == 0xfb) +				udelay(50); +			else if (radioa_array_table[i] == 0xfa) +				udelay(5); +			else if (radioa_array_table[i] == 0xf9) +				udelay(1); +			else { +				rtl_set_rfreg(hw, rfpath, radioa_array_table[i], +					      RFREG_OFFSET_MASK, +					      radioa_array_table[i + 1]); +				udelay(1); +			} +		} +		_rtl92c_phy_config_rf_external_pa(hw, rfpath); +		break; +	case RF90_PATH_B: +		for (i = 0; i < radiob_arraylen; i = i + 2) { +			if (radiob_array_table[i] == 0xfe) { +				mdelay(50); +			} else if (radiob_array_table[i] == 0xfd) +				mdelay(5); +			else if (radiob_array_table[i] == 0xfc) +				mdelay(1); +			else if (radiob_array_table[i] == 0xfb) +				udelay(50); +			else if (radiob_array_table[i] == 0xfa) +				udelay(5); +			else if (radiob_array_table[i] == 0xf9) +				udelay(1); +			else { +				rtl_set_rfreg(hw, rfpath, radiob_array_table[i], +					      RFREG_OFFSET_MASK, +					      radiob_array_table[i + 1]); +				udelay(1); +			} +		} +		break; +	case RF90_PATH_C: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	case RF90_PATH_D: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} +	return true; +} + +void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	rtlphy->default_initialgain[0] = +	    (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0); +	rtlphy->default_initialgain[1] = +	    (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0); +	rtlphy->default_initialgain[2] = +	    (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0); +	rtlphy->default_initialgain[3] = +	    (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0); + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +		 ("Default initial gain (c50=0x%x, " +		  "c58=0x%x, c60=0x%x, c68=0x%x\n", +		  rtlphy->default_initialgain[0], +		  rtlphy->default_initialgain[1], +		  rtlphy->default_initialgain[2], +		  rtlphy->default_initialgain[3])); + +	rtlphy->framesync = (u8) rtl_get_bbreg(hw, +					       ROFDM0_RXDETECTOR3, MASKBYTE0); +	rtlphy->framesync_c34 = rtl_get_bbreg(hw, +					      ROFDM0_RXDETECTOR2, MASKDWORD); + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +		 ("Default framesync (0x%x) = 0x%x\n", +		  ROFDM0_RXDETECTOR3, rtlphy->framesync)); +} + +static void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW; +	rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW; +	rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW; + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB; +	rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB; +	rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB; + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE; + +	rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE; +	rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE; + +	rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset = +	    RFPGA0_XA_LSSIPARAMETER; +	rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset = +	    RFPGA0_XB_LSSIPARAMETER; + +	rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER; +	rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER; +	rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER; +	rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER; + +	rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE; +	rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE; +	rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE; +	rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE; + +	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1; +	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1; + +	rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2; +	rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2; + +	rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control = +	    RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control = +	    RFPGA0_XAB_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control = +	    RFPGA0_XCD_SWITCHCONTROL; +	rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control = +	    RFPGA0_XCD_SWITCHCONTROL; + +	rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1; +	rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1; +	rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1; +	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1; + +	rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2; +	rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2; +	rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2; +	rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2; + +	rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance = +	    ROFDM0_XARXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance = +	    ROFDM0_XBRXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance = +	    ROFDM0_XCRXIQIMBANLANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance = +	    ROFDM0_XDRXIQIMBALANCE; + +	rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE; +	rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE; +	rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE; +	rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE; + +	rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance = +	    ROFDM0_XATXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance = +	    ROFDM0_XBTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance = +	    ROFDM0_XCTXIQIMBALANCE; +	rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance = +	    ROFDM0_XDTXIQIMBALANCE; + +	rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE; +	rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE; +	rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE; +	rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE; + +	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback = +	    RFPGA0_XA_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback = +	    RFPGA0_XB_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback = +	    RFPGA0_XC_LSSIREADBACK; +	rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback = +	    RFPGA0_XD_LSSIREADBACK; + +	rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi = +	    TRANSCEIVEA_HSPI_READBACK; +	rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi = +	    TRANSCEIVEB_HSPI_READBACK; + +} + +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 txpwr_level; +	long txpwr_dbm; + +	txpwr_level = rtlphy->cur_cck_txpwridx; +	txpwr_dbm = _rtl92c_phy_txpwr_idx_to_dbm(hw, +						 WIRELESS_MODE_B, txpwr_level); +	txpwr_level = rtlphy->cur_ofdm24g_txpwridx + +	    rtlefuse->legacy_ht_txpowerdiff; +	if (_rtl92c_phy_txpwr_idx_to_dbm(hw, +					 WIRELESS_MODE_G, +					 txpwr_level) > txpwr_dbm) +		txpwr_dbm = +		    _rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, +						 txpwr_level); +	txpwr_level = rtlphy->cur_ofdm24g_txpwridx; +	if (_rtl92c_phy_txpwr_idx_to_dbm(hw, +					 WIRELESS_MODE_N_24G, +					 txpwr_level) > txpwr_dbm) +		txpwr_dbm = +		    _rtl92c_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, +						 txpwr_level); +	*powerlevel = txpwr_dbm; +} + +static void _rtl92c_get_txpower_index(struct ieee80211_hw *hw, u8 channel, +				      u8 *cckpowerlevel, u8 *ofdmpowerlevel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 index = (channel - 1); + +	cckpowerlevel[RF90_PATH_A] = +	    rtlefuse->txpwrlevel_cck[RF90_PATH_A][index]; +	cckpowerlevel[RF90_PATH_B] = +	    rtlefuse->txpwrlevel_cck[RF90_PATH_B][index]; +	if (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_1T1R) { +		ofdmpowerlevel[RF90_PATH_A] = +		    rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index]; +		ofdmpowerlevel[RF90_PATH_B] = +		    rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index]; +	} else if (get_rf_type(rtlphy) == RF_2T2R) { +		ofdmpowerlevel[RF90_PATH_A] = +		    rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_A][index]; +		ofdmpowerlevel[RF90_PATH_B] = +		    rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_B][index]; +	} +} + +static void _rtl92c_ccxpower_index_check(struct ieee80211_hw *hw, +					 u8 channel, u8 *cckpowerlevel, +					 u8 *ofdmpowerlevel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; +	rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; +} + +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) +{ +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 cckpowerlevel[2], ofdmpowerlevel[2]; + +	if (rtlefuse->b_txpwr_fromeprom == false) +		return; +	_rtl92c_get_txpower_index(hw, channel, +				  &cckpowerlevel[0], &ofdmpowerlevel[0]); +	_rtl92c_ccxpower_index_check(hw, +				     channel, &cckpowerlevel[0], +				     &ofdmpowerlevel[0]); +	rtl92c_phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]); +	rtl92c_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], channel); +} + +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 idx; +	u8 rf_path; + +	u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw, +						      WIRELESS_MODE_B, +						      power_indbm); +	u8 ofdmtxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw, +						       WIRELESS_MODE_N_24G, +						       power_indbm); +	if (ofdmtxpwridx - rtlefuse->legacy_ht_txpowerdiff > 0) +		ofdmtxpwridx -= rtlefuse->legacy_ht_txpowerdiff; +	else +		ofdmtxpwridx = 0; +	RT_TRACE(rtlpriv, COMP_TXAGC, DBG_TRACE, +		 ("%lx dBm, ccktxpwridx = %d, ofdmtxpwridx = %d\n", +		  power_indbm, ccktxpwridx, ofdmtxpwridx)); +	for (idx = 0; idx < 14; idx++) { +		for (rf_path = 0; rf_path < 2; rf_path++) { +			rtlefuse->txpwrlevel_cck[rf_path][idx] = ccktxpwridx; +			rtlefuse->txpwrlevel_ht40_1s[rf_path][idx] = +			    ofdmtxpwridx; +			rtlefuse->txpwrlevel_ht40_2s[rf_path][idx] = +			    ofdmtxpwridx; +		} +	} +	rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); +	return true; +} + +void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval) +{ +} + +static u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, +				       enum wireless_mode wirelessmode, +				       long power_indbm) +{ +	u8 txpwridx; +	long offset; + +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		offset = -7; +		break; +	case WIRELESS_MODE_G: +	case WIRELESS_MODE_N_24G: +		offset = -8; +		break; +	default: +		offset = -8; +		break; +	} + +	if ((power_indbm - offset) > 0) +		txpwridx = (u8) ((power_indbm - offset) * 2); +	else +		txpwridx = 0; + +	if (txpwridx > MAX_TXPWR_IDX_NMODE_92S) +		txpwridx = MAX_TXPWR_IDX_NMODE_92S; + +	return txpwridx; +} + +static long _rtl92c_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw, +					 enum wireless_mode wirelessmode, +					 u8 txpwridx) +{ +	long offset; +	long pwrout_dbm; + +	switch (wirelessmode) { +	case WIRELESS_MODE_B: +		offset = -7; +		break; +	case WIRELESS_MODE_G: +	case WIRELESS_MODE_N_24G: +		offset = -8; +		break; +	default: +		offset = -8; +		break; +	} +	pwrout_dbm = txpwridx / 2 + offset; +	return pwrout_dbm; +} + +void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	enum io_type iotype; + +	if (!is_hal_stop(rtlhal)) { +		switch (operation) { +		case SCAN_OPT_BACKUP: +			iotype = IO_CMD_PAUSE_DM_BY_SCAN; +			rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_IO_CMD, +						      (u8 *)&iotype); + +			break; +		case SCAN_OPT_RESTORE: +			iotype = IO_CMD_RESUME_DM_BY_SCAN; +			rtlpriv->cfg->ops->set_hw_reg(hw, +						      HW_VAR_IO_CMD, +						      (u8 *)&iotype); +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("Unknown Scan Backup operation.\n")); +			break; +		} +	} +} + +void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	u8 reg_bw_opmode; +	u8 reg_prsr_rsc; + +	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, +		 ("Switch to %s bandwidth\n", +		  rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? +		  "20MHz" : "40MHz")) + +	    if (is_hal_stop(rtlhal)) +		return; + +	reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); +	reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); + +	switch (rtlphy->current_chan_bw) { +	case HT_CHANNEL_WIDTH_20: +		reg_bw_opmode |= BW_OPMODE_20MHZ; +		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); +		break; + +	case HT_CHANNEL_WIDTH_20_40: +		reg_bw_opmode &= ~BW_OPMODE_20MHZ; +		rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); + +		reg_prsr_rsc = +		    (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5); +		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); +		break; + +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); +		break; +	} + +	switch (rtlphy->current_chan_bw) { +	case HT_CHANNEL_WIDTH_20: +		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); +		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); +		rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); +		break; +	case HT_CHANNEL_WIDTH_20_40: +		rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); +		rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); +		rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, +			      (mac->cur_40_prime_sc >> 1)); +		rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); +		rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0); +		rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), +			      (mac->cur_40_prime_sc == +			       HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); +		break; +	} +	rtl92c_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); +	rtlphy->set_bwmode_inprogress = false; +	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); +} + +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, +			    enum nl80211_channel_type ch_type) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	u8 tmp_bw = rtlphy->current_chan_bw; + +	if (rtlphy->set_bwmode_inprogress) +		return; +	rtlphy->set_bwmode_inprogress = true; +	if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) +		rtl92c_phy_set_bw_mode_callback(hw); +	else { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +			 ("FALSE driver sleep or unload\n")); +		rtlphy->set_bwmode_inprogress = false; +		rtlphy->current_chan_bw = tmp_bw; +	} +} + +void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 delay; + +	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, +		 ("switch to channel%d\n", rtlphy->current_channel)); +	if (is_hal_stop(rtlhal)) +		return; +	do { +		if (!rtlphy->sw_chnl_inprogress) +			break; +		if (!_rtl92c_phy_sw_chnl_step_by_step +		    (hw, rtlphy->current_channel, &rtlphy->sw_chnl_stage, +		     &rtlphy->sw_chnl_step, &delay)) { +			if (delay > 0) +				mdelay(delay); +			else +				continue; +		} else +			rtlphy->sw_chnl_inprogress = false; +		break; +	} while (true); +	RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); +} + +u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (rtlphy->sw_chnl_inprogress) +		return 0; +	if (rtlphy->set_bwmode_inprogress) +		return 0; +	RT_ASSERT((rtlphy->current_channel <= 14), +		  ("WIRELESS_MODE_G but channel>14")); +	rtlphy->sw_chnl_inprogress = true; +	rtlphy->sw_chnl_stage = 0; +	rtlphy->sw_chnl_step = 0; +	if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { +		rtl92c_phy_sw_chnl_callback(hw); +		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, +			 ("sw_chnl_inprogress false schdule workitem\n")); +		rtlphy->sw_chnl_inprogress = false; +	} else { +		RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD, +			 ("sw_chnl_inprogress false driver sleep or" +			  " unload\n")); +		rtlphy->sw_chnl_inprogress = false; +	} +	return 1; +} + +static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, +					     u8 channel, u8 *stage, u8 *step, +					     u32 *delay) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct swchnlcmd precommoncmd[MAX_PRECMD_CNT]; +	u32 precommoncmdcnt; +	struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT]; +	u32 postcommoncmdcnt; +	struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT]; +	u32 rfdependcmdcnt; +	struct swchnlcmd *currentcmd = NULL; +	u8 rfpath; +	u8 num_total_rfpath = rtlphy->num_total_rfpath; + +	precommoncmdcnt = 0; +	_rtl92c_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, +					 MAX_PRECMD_CNT, +					 CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0); +	_rtl92c_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++, +					 MAX_PRECMD_CNT, CMDID_END, 0, 0, 0); + +	postcommoncmdcnt = 0; + +	_rtl92c_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++, +					 MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0); + +	rfdependcmdcnt = 0; + +	RT_ASSERT((channel >= 1 && channel <= 14), +		  ("illegal channel for Zebra: %d\n", channel)); + +	_rtl92c_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, +					 MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG, +					 RF_CHNLBW, channel, 10); + +	_rtl92c_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++, +					 MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, +					 0); + +	do { +		switch (*stage) { +		case 0: +			currentcmd = &precommoncmd[*step]; +			break; +		case 1: +			currentcmd = &rfdependcmd[*step]; +			break; +		case 2: +			currentcmd = &postcommoncmd[*step]; +			break; +		} + +		if (currentcmd->cmdid == CMDID_END) { +			if ((*stage) == 2) { +				return true; +			} else { +				(*stage)++; +				(*step) = 0; +				continue; +			} +		} + +		switch (currentcmd->cmdid) { +		case CMDID_SET_TXPOWEROWER_LEVEL: +			rtl92c_phy_set_txpower_level(hw, channel); +			break; +		case CMDID_WRITEPORT_ULONG: +			rtl_write_dword(rtlpriv, currentcmd->para1, +					currentcmd->para2); +			break; +		case CMDID_WRITEPORT_USHORT: +			rtl_write_word(rtlpriv, currentcmd->para1, +				       (u16) currentcmd->para2); +			break; +		case CMDID_WRITEPORT_UCHAR: +			rtl_write_byte(rtlpriv, currentcmd->para1, +				       (u8) currentcmd->para2); +			break; +		case CMDID_RF_WRITEREG: +			for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) { +				rtlphy->rfreg_chnlval[rfpath] = +				    ((rtlphy->rfreg_chnlval[rfpath] & +				      0xfffffc00) | currentcmd->para2); + +				rtl_set_rfreg(hw, (enum radio_path)rfpath, +					      currentcmd->para1, +					      RFREG_OFFSET_MASK, +					      rtlphy->rfreg_chnlval[rfpath]); +			} +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("switch case not process\n")); +			break; +		} + +		break; +	} while (true); + +	(*delay) = currentcmd->msdelay; +	(*step)++; +	return false; +} + +static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, +					     u32 cmdtableidx, u32 cmdtablesz, +					     enum swchnlcmd_id cmdid, +					     u32 para1, u32 para2, u32 msdelay) +{ +	struct swchnlcmd *pcmd; + +	if (cmdtable == NULL) { +		RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); +		return false; +	} + +	if (cmdtableidx >= cmdtablesz) +		return false; + +	pcmd = cmdtable + cmdtableidx; +	pcmd->cmdid = cmdid; +	pcmd->para1 = para1; +	pcmd->para2 = para2; +	pcmd->msdelay = msdelay; +	return true; +} + +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath) +{ +	return true; +} + +static u8 _rtl92c_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb) +{ +	u32 reg_eac, reg_e94, reg_e9c, reg_ea4; +	u8 result = 0x00; + +	rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1f); +	rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c1f); +	rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140102); +	rtl_set_bbreg(hw, 0xe3c, MASKDWORD, +		      config_pathb ? 0x28160202 : 0x28160502); + +	if (config_pathb) { +		rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x10008c22); +		rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x10008c22); +		rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140102); +		rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x28160202); +	} + +	rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x001028d1); +	rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000); +	rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000); + +	mdelay(IQK_DELAY_TIME); + +	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); +	reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD); +	reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD); +	reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD); + +	if (!(reg_eac & BIT(28)) && +	    (((reg_e94 & 0x03FF0000) >> 16) != 0x142) && +	    (((reg_e9c & 0x03FF0000) >> 16) != 0x42)) +		result |= 0x01; +	else +		return result; + +	if (!(reg_eac & BIT(27)) && +	    (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) && +	    (((reg_eac & 0x03FF0000) >> 16) != 0x36)) +		result |= 0x02; +	return result; +} + +static u8 _rtl92c_phy_path_b_iqk(struct ieee80211_hw *hw) +{ +	u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc; +	u8 result = 0x00; + +	rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002); +	rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000); +	mdelay(IQK_DELAY_TIME); +	reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD); +	reg_eb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD); +	reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); +	reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); +	reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); +	if (!(reg_eac & BIT(31)) && +	    (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && +	    (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) +		result |= 0x01; +	else +		return result; + +	if (!(reg_eac & BIT(30)) && +	    (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && +	    (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) +		result |= 0x02; +	return result; +} + +static void _rtl92c_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, +					       bool b_iqk_ok, long result[][8], +					       u8 final_candidate, bool btxonly) +{ +	u32 oldval_0, x, tx0_a, reg; +	long y, tx0_c; + +	if (final_candidate == 0xFF) +		return; +	else if (b_iqk_ok) { +		oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, +					  MASKDWORD) >> 22) & 0x3FF; +		x = result[final_candidate][0]; +		if ((x & 0x00000200) != 0) +			x = x | 0xFFFFFC00; +		tx0_a = (x * oldval_0) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31), +			      ((x * oldval_0 >> 7) & 0x1)); +		y = result[final_candidate][1]; +		if ((y & 0x00000200) != 0) +			y = y | 0xFFFFFC00; +		tx0_c = (y * oldval_0) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000, +			      ((tx0_c & 0x3C0) >> 6)); +		rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000, +			      (tx0_c & 0x3F)); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29), +			      ((y * oldval_0 >> 7) & 0x1)); +		if (btxonly) +			return; +		reg = result[final_candidate][2]; +		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg); +		reg = result[final_candidate][3] & 0x3F; +		rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg); +		reg = (result[final_candidate][3] >> 6) & 0xF; +		rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg); +	} +} + +static void _rtl92c_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw, +					       bool b_iqk_ok, long result[][8], +					       u8 final_candidate, bool btxonly) +{ +	u32 oldval_1, x, tx1_a, reg; +	long y, tx1_c; + +	if (final_candidate == 0xFF) +		return; +	else if (b_iqk_ok) { +		oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, +					  MASKDWORD) >> 22) & 0x3FF; +		x = result[final_candidate][4]; +		if ((x & 0x00000200) != 0) +			x = x | 0xFFFFFC00; +		tx1_a = (x * oldval_1) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, 0x3FF, tx1_a); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(27), +			      ((x * oldval_1 >> 7) & 0x1)); +		y = result[final_candidate][5]; +		if ((y & 0x00000200) != 0) +			y = y | 0xFFFFFC00; +		tx1_c = (y * oldval_1) >> 8; +		rtl_set_bbreg(hw, ROFDM0_XDTXAFE, 0xF0000000, +			      ((tx1_c & 0x3C0) >> 6)); +		rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, 0x003F0000, +			      (tx1_c & 0x3F)); +		rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(25), +			      ((y * oldval_1 >> 7) & 0x1)); +		if (btxonly) +			return; +		reg = result[final_candidate][6]; +		rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0x3FF, reg); +		reg = result[final_candidate][7] & 0x3F; +		rtl_set_bbreg(hw, ROFDM0_XBRXIQIMBALANCE, 0xFC00, reg); +		reg = (result[final_candidate][7] >> 6) & 0xF; +		rtl_set_bbreg(hw, ROFDM0_AGCRSSITABLE, 0x0000F000, reg); +	} +} + +static void _rtl92c_phy_save_adda_registers(struct ieee80211_hw *hw, +					    u32 *addareg, u32 *addabackup, +					    u32 registernum) +{ +	u32 i; + +	for (i = 0; i < registernum; i++) +		addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD); +} + +static void _rtl92c_phy_save_mac_registers(struct ieee80211_hw *hw, +					   u32 *macreg, u32 *macbackup) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; + +	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) +		macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]); +	macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]); +} + +static void _rtl92c_phy_reload_adda_registers(struct ieee80211_hw *hw, +					      u32 *addareg, u32 *addabackup, +					      u32 regiesternum) +{ +	u32 i; + +	for (i = 0; i < regiesternum; i++) +		rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]); +} + +static void _rtl92c_phy_reload_mac_registers(struct ieee80211_hw *hw, +					     u32 *macreg, u32 *macbackup) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; + +	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) +		rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]); +	rtl_write_dword(rtlpriv, macreg[i], macbackup[i]); +} + +static void _rtl92c_phy_path_adda_on(struct ieee80211_hw *hw, +				     u32 *addareg, bool is_patha_on, bool is2t) +{ +	u32 pathOn; +	u32 i; + +	pathOn = is_patha_on ? 0x04db25a4 : 0x0b1b25a4; +	if (false == is2t) { +		pathOn = 0x0bdb25a0; +		rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0); +	} else { +		rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathOn); +	} + +	for (i = 1; i < IQK_ADDA_REG_NUM; i++) +		rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathOn); +} + +static void _rtl92c_phy_mac_setting_calibration(struct ieee80211_hw *hw, +						u32 *macreg, u32 *macbackup) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 i; + +	rtl_write_byte(rtlpriv, macreg[0], 0x3F); + +	for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) +		rtl_write_byte(rtlpriv, macreg[i], +			       (u8) (macbackup[i] & (~BIT(3)))); +	rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5)))); +} + +static void _rtl92c_phy_path_a_standby(struct ieee80211_hw *hw) +{ +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0); +	rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); +} + +static void _rtl92c_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode) +{ +	u32 mode; + +	mode = pi_mode ? 0x01000100 : 0x01000000; +	rtl_set_bbreg(hw, 0x820, MASKDWORD, mode); +	rtl_set_bbreg(hw, 0x828, MASKDWORD, mode); +} + +static bool _rtl92c_phy_simularity_compare(struct ieee80211_hw *hw, +					   long result[][8], u8 c1, u8 c2) +{ +	u32 i, j, diff, simularity_bitmap, bound; +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	u8 final_candidate[2] = { 0xFF, 0xFF }; +	bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version); + +	if (is2t) +		bound = 8; +	else +		bound = 4; + +	simularity_bitmap = 0; + +	for (i = 0; i < bound; i++) { +		diff = (result[c1][i] > result[c2][i]) ? +		    (result[c1][i] - result[c2][i]) : +		    (result[c2][i] - result[c1][i]); + +		if (diff > MAX_TOLERANCE) { +			if ((i == 2 || i == 6) && !simularity_bitmap) { +				if (result[c1][i] + result[c1][i + 1] == 0) +					final_candidate[(i / 4)] = c2; +				else if (result[c2][i] + result[c2][i + 1] == 0) +					final_candidate[(i / 4)] = c1; +				else +					simularity_bitmap = simularity_bitmap | +					    (1 << i); +			} else +				simularity_bitmap = +				    simularity_bitmap | (1 << i); +		} +	} + +	if (simularity_bitmap == 0) { +		for (i = 0; i < (bound / 4); i++) { +			if (final_candidate[i] != 0xFF) { +				for (j = i * 4; j < (i + 1) * 4 - 2; j++) +					result[3][j] = +					    result[final_candidate[i]][j]; +				bresult = false; +			} +		} +		return bresult; +	} else if (!(simularity_bitmap & 0x0F)) { +		for (i = 0; i < 4; i++) +			result[3][i] = result[c1][i]; +		return false; +	} else if (!(simularity_bitmap & 0xF0) && is2t) { +		for (i = 4; i < 8; i++) +			result[3][i] = result[c1][i]; +		return false; +	} else { +		return false; +	} + +} + +static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, +				     long result[][8], u8 t, bool is2t) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 i; +	u8 patha_ok, pathb_ok; +	u32 adda_reg[IQK_ADDA_REG_NUM] = { +		0x85c, 0xe6c, 0xe70, 0xe74, +		0xe78, 0xe7c, 0xe80, 0xe84, +		0xe88, 0xe8c, 0xed0, 0xed4, +		0xed8, 0xedc, 0xee0, 0xeec +	}; + +	u32 iqk_mac_reg[IQK_MAC_REG_NUM] = { +		0x522, 0x550, 0x551, 0x040 +	}; + +	const u32 retrycount = 2; + +	u32 bbvalue; + +	if (t == 0) { +		bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD); + +		_rtl92c_phy_save_adda_registers(hw, adda_reg, +						rtlphy->adda_backup, 16); +		_rtl92c_phy_save_mac_registers(hw, iqk_mac_reg, +					       rtlphy->iqk_mac_backup); +	} +	_rtl92c_phy_path_adda_on(hw, adda_reg, true, is2t); +	if (t == 0) { +		rtlphy->b_rfpi_enable = (u8) rtl_get_bbreg(hw, +						   RFPGA0_XA_HSSIPARAMETER1, +						   BIT(8)); +	} +	if (!rtlphy->b_rfpi_enable) +		_rtl92c_phy_pi_mode_switch(hw, true); +	if (t == 0) { +		rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD); +		rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD); +		rtlphy->reg_874 = rtl_get_bbreg(hw, 0x874, MASKDWORD); +	} +	rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600); +	rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4); +	rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000); +	if (is2t) { +		rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000); +		rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000); +	} +	_rtl92c_phy_mac_setting_calibration(hw, iqk_mac_reg, +					    rtlphy->iqk_mac_backup); +	rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x00080000); +	if (is2t) +		rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x00080000); +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000); +	rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00); +	rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800); +	for (i = 0; i < retrycount; i++) { +		patha_ok = _rtl92c_phy_path_a_iqk(hw, is2t); +		if (patha_ok == 0x03) { +			result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & +					0x3FF0000) >> 16; +			result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & +					0x3FF0000) >> 16; +			result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) & +					0x3FF0000) >> 16; +			result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) & +					0x3FF0000) >> 16; +			break; +		} else if (i == (retrycount - 1) && patha_ok == 0x01) +			result[t][0] = (rtl_get_bbreg(hw, 0xe94, +						      MASKDWORD) & 0x3FF0000) >> +						      16; +		result[t][1] = +		    (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; + +	} + +	if (is2t) { +		_rtl92c_phy_path_a_standby(hw); +		_rtl92c_phy_path_adda_on(hw, adda_reg, false, is2t); +		for (i = 0; i < retrycount; i++) { +			pathb_ok = _rtl92c_phy_path_b_iqk(hw); +			if (pathb_ok == 0x03) { +				result[t][4] = (rtl_get_bbreg(hw, +						      0xeb4, +						      MASKDWORD) & +						0x3FF0000) >> 16; +				result[t][5] = +				    (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & +				     0x3FF0000) >> 16; +				result[t][6] = +				    (rtl_get_bbreg(hw, 0xec4, MASKDWORD) & +				     0x3FF0000) >> 16; +				result[t][7] = +				    (rtl_get_bbreg(hw, 0xecc, MASKDWORD) & +				     0x3FF0000) >> 16; +				break; +			} else if (i == (retrycount - 1) && pathb_ok == 0x01) { +				result[t][4] = (rtl_get_bbreg(hw, +						      0xeb4, +						      MASKDWORD) & +						0x3FF0000) >> 16; +			} +			result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) & +					0x3FF0000) >> 16; +		} +	} +	rtl_set_bbreg(hw, 0xc04, MASKDWORD, rtlphy->reg_c04); +	rtl_set_bbreg(hw, 0x874, MASKDWORD, rtlphy->reg_874); +	rtl_set_bbreg(hw, 0xc08, MASKDWORD, rtlphy->reg_c08); +	rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0); +	rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3); +	if (is2t) +		rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3); +	if (t != 0) { +		if (!rtlphy->b_rfpi_enable) +			_rtl92c_phy_pi_mode_switch(hw, false); +		_rtl92c_phy_reload_adda_registers(hw, adda_reg, +						  rtlphy->adda_backup, 16); +		_rtl92c_phy_reload_mac_registers(hw, iqk_mac_reg, +						 rtlphy->iqk_mac_backup); +	} +} + +static void _rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) +{ +	u8 tmpreg; +	u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	tmpreg = rtl_read_byte(rtlpriv, 0xd03); + +	if ((tmpreg & 0x70) != 0) +		rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F); +	else +		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + +	if ((tmpreg & 0x70) != 0) { +		rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS); + +		if (is2t) +			rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00, +						  MASK12BITS); + +		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, +			      (rf_a_mode & 0x8FFFF) | 0x10000); + +		if (is2t) +			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS, +				      (rf_b_mode & 0x8FFFF) | 0x10000); +	} +	lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS); + +	rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, lc_cal | 0x08000); + +	mdelay(100); + +	if ((tmpreg & 0x70) != 0) { +		rtl_write_byte(rtlpriv, 0xd03, tmpreg); +		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode); + +		if (is2t) +			rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS, +				      rf_b_mode); +	} else { +		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +	} +} + +static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, +				     char delta, bool is2t) +{ +	/* This routine is deliberately dummied out for later fixes */ +#if 0 +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + +	u32 reg_d[PATH_NUM]; +	u32 tmpreg, index, offset, path, i, pathbound = PATH_NUM, apkbound; + +	u32 bb_backup[APK_BB_REG_NUM]; +	u32 bb_reg[APK_BB_REG_NUM] = { +		0x904, 0xc04, 0x800, 0xc08, 0x874 +	}; +	u32 bb_ap_mode[APK_BB_REG_NUM] = { +		0x00000020, 0x00a05430, 0x02040000, +		0x000800e4, 0x00204000 +	}; +	u32 bb_normal_ap_mode[APK_BB_REG_NUM] = { +		0x00000020, 0x00a05430, 0x02040000, +		0x000800e4, 0x22204000 +	}; + +	u32 afe_backup[APK_AFE_REG_NUM]; +	u32 afe_reg[APK_AFE_REG_NUM] = { +		0x85c, 0xe6c, 0xe70, 0xe74, 0xe78, +		0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, +		0xed0, 0xed4, 0xed8, 0xedc, 0xee0, +		0xeec +	}; + +	u32 mac_backup[IQK_MAC_REG_NUM]; +	u32 mac_reg[IQK_MAC_REG_NUM] = { +		0x522, 0x550, 0x551, 0x040 +	}; + +	u32 apk_rf_init_value[PATH_NUM][APK_BB_REG_NUM] = { +		{0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c}, +		{0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e} +	}; + +	u32 apk_normal_rf_init_value[PATH_NUM][APK_BB_REG_NUM] = { +		{0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, +		{0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c} +	}; + +	u32 apk_rf_value_0[PATH_NUM][APK_BB_REG_NUM] = { +		{0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d}, +		{0x5201a, 0x52019, 0x52016, 0x52033, 0x52050} +	}; + +	u32 apk_normal_rf_value_0[PATH_NUM][APK_BB_REG_NUM] = { +		{0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, +		{0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a} +	}; + +	u32 afe_on_off[PATH_NUM] = { +		0x04db25a4, 0x0b1b25a4 +	}; + +	u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; + +	u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 }; + +	u32 apk_value[PATH_NUM] = { 0x92fc0000, 0x12fc0000 }; + +	u32 apk_normal_value[PATH_NUM] = { 0x92680000, 0x12680000 }; + +	const char apk_delta_mapping[APK_BB_REG_NUM][13] = { +		{-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, +		{-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, +		{-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, +		{-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6}, +		{-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0} +	}; + +	const u32 apk_normal_setting_value_1[13] = { +		0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28, +		0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3, +		0x12680000, 0x00880000, 0x00880000 +	}; + +	const u32 apk_normal_setting_value_2[16] = { +		0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3, +		0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025, +		0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008, +		0x00050006 +	}; + +	const u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; + +	long bb_offset, delta_v, delta_offset; + +	if (!is2t) +		pathbound = 1; + +	for (index = 0; index < PATH_NUM; index++) { +		apk_offset[index] = apk_normal_offset[index]; +		apk_value[index] = apk_normal_value[index]; +		afe_on_off[index] = 0x6fdb25a4; +	} + +	for (index = 0; index < APK_BB_REG_NUM; index++) { +		for (path = 0; path < pathbound; path++) { +			apk_rf_init_value[path][index] = +			    apk_normal_rf_init_value[path][index]; +			apk_rf_value_0[path][index] = +			    apk_normal_rf_value_0[path][index]; +		} +		bb_ap_mode[index] = bb_normal_ap_mode[index]; + +		apkbound = 6; +	} + +	for (index = 0; index < APK_BB_REG_NUM; index++) { +		if (index == 0) +			continue; +		bb_backup[index] = rtl_get_bbreg(hw, bb_reg[index], MASKDWORD); +	} + +	_rtl92c_phy_save_mac_registers(hw, mac_reg, mac_backup); + +	_rtl92c_phy_save_adda_registers(hw, afe_reg, afe_backup, 16); + +	for (path = 0; path < pathbound; path++) { +		if (path == RF90_PATH_A) { +			offset = 0xb00; +			for (index = 0; index < 11; index++) { +				rtl_set_bbreg(hw, offset, MASKDWORD, +					      apk_normal_setting_value_1 +					      [index]); + +				offset += 0x04; +			} + +			rtl_set_bbreg(hw, 0xb98, MASKDWORD, 0x12680000); + +			offset = 0xb68; +			for (; index < 13; index++) { +				rtl_set_bbreg(hw, offset, MASKDWORD, +					      apk_normal_setting_value_1 +					      [index]); + +				offset += 0x04; +			} + +			rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x40000000); + +			offset = 0xb00; +			for (index = 0; index < 16; index++) { +				rtl_set_bbreg(hw, offset, MASKDWORD, +					      apk_normal_setting_value_2 +					      [index]); + +				offset += 0x04; +			} +			rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000); +		} else if (path == RF90_PATH_B) { +			offset = 0xb70; +			for (index = 0; index < 10; index++) { +				rtl_set_bbreg(hw, offset, MASKDWORD, +					      apk_normal_setting_value_1 +					      [index]); + +				offset += 0x04; +			} +			rtl_set_bbreg(hw, 0xb28, MASKDWORD, 0x12680000); +			rtl_set_bbreg(hw, 0xb98, MASKDWORD, 0x12680000); + +			offset = 0xb68; +			index = 11; +			for (; index < 13; index++) { +				rtl_set_bbreg(hw, offset, MASKDWORD, +					      apk_normal_setting_value_1 +					      [index]); + +				offset += 0x04; +			} + +			rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x40000000); + +			offset = 0xb60; +			for (index = 0; index < 16; index++) { +				rtl_set_bbreg(hw, offset, MASKDWORD, +					      apk_normal_setting_value_2 +					      [index]); + +				offset += 0x04; +			} +			rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000); +		} + +		reg_d[path] = rtl_get_rfreg(hw, (enum radio_path)path, +					    0xd, MASKDWORD); + +		for (index = 0; index < APK_AFE_REG_NUM; index++) +			rtl_set_bbreg(hw, afe_reg[index], MASKDWORD, +				      afe_on_off[path]); + +		if (path == RF90_PATH_A) { +			for (index = 0; index < APK_BB_REG_NUM; index++) { +				if (index == 0) +					continue; +				rtl_set_bbreg(hw, bb_reg[index], MASKDWORD, +					      bb_ap_mode[index]); +			} +		} + +		_rtl92c_phy_mac_setting_calibration(hw, mac_reg, mac_backup); + +		if (path == 0) { +			rtl_set_rfreg(hw, RF90_PATH_B, 0x0, MASKDWORD, 0x10000); +		} else { +			rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASKDWORD, +				      0x10000); +			rtl_set_rfreg(hw, RF90_PATH_A, 0x10, MASKDWORD, +				      0x1000f); +			rtl_set_rfreg(hw, RF90_PATH_A, 0x11, MASKDWORD, +				      0x20103); +		} + +		delta_offset = ((delta + 14) / 2); +		if (delta_offset < 0) +			delta_offset = 0; +		else if (delta_offset > 12) +			delta_offset = 12; + +		for (index = 0; index < APK_BB_REG_NUM; index++) { +			if (index != 1) +				continue; + +			tmpreg = apk_rf_init_value[path][index]; + +			if (!rtlefuse->b_apk_thermalmeterignore) { +				bb_offset = (tmpreg & 0xF0000) >> 16; + +				if (!(tmpreg & BIT(15))) +					bb_offset = -bb_offset; + +				delta_v = +				    apk_delta_mapping[index][delta_offset]; + +				bb_offset += delta_v; + +				if (bb_offset < 0) { +					tmpreg = tmpreg & (~BIT(15)); +					bb_offset = -bb_offset; +				} else { +					tmpreg = tmpreg | BIT(15); +				} + +				tmpreg = +				    (tmpreg & 0xFFF0FFFF) | (bb_offset << 16); +			} + +			rtl_set_rfreg(hw, (enum radio_path)path, 0xc, +				      MASKDWORD, 0x8992e); +			rtl_set_rfreg(hw, (enum radio_path)path, 0x0, +				      MASKDWORD, apk_rf_value_0[path][index]); +			rtl_set_rfreg(hw, (enum radio_path)path, 0xd, +				      MASKDWORD, tmpreg); + +			i = 0; +			do { +				rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80000000); +				rtl_set_bbreg(hw, apk_offset[path], +					      MASKDWORD, apk_value[0]); +				RTPRINT(rtlpriv, FINIT, INIT_IQK, +					("PHY_APCalibrate() offset 0x%x " +					 "value 0x%x\n", +					 apk_offset[path], +					 rtl_get_bbreg(hw, apk_offset[path], +						       MASKDWORD))); + +				mdelay(3); + +				rtl_set_bbreg(hw, apk_offset[path], +					      MASKDWORD, apk_value[1]); +				RTPRINT(rtlpriv, FINIT, INIT_IQK, +					("PHY_APCalibrate() offset 0x%x " +					 "value 0x%x\n", +					 apk_offset[path], +					 rtl_get_bbreg(hw, apk_offset[path], +						       MASKDWORD))); + +				mdelay(20); + +				rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x00000000); + +				if (path == RF90_PATH_A) +					tmpreg = rtl_get_bbreg(hw, 0xbd8, +							       0x03E00000); +				else +					tmpreg = rtl_get_bbreg(hw, 0xbd8, +							       0xF8000000); + +				RTPRINT(rtlpriv, FINIT, INIT_IQK, +					("PHY_APCalibrate() offset " +					 "0xbd8[25:21] %x\n", tmpreg)); + +				i++; + +			} while (tmpreg > apkbound && i < 4); + +			apk_result[path][index] = tmpreg; +		} +	} + +	_rtl92c_phy_reload_mac_registers(hw, mac_reg, mac_backup); + +	for (index = 0; index < APK_BB_REG_NUM; index++) { +		if (index == 0) +			continue; +		rtl_set_bbreg(hw, bb_reg[index], MASKDWORD, bb_backup[index]); +	} + +	_rtl92c_phy_reload_adda_registers(hw, afe_reg, afe_backup, 16); + +	for (path = 0; path < pathbound; path++) { +		rtl_set_rfreg(hw, (enum radio_path)path, 0xd, +			      MASKDWORD, reg_d[path]); + +		if (path == RF90_PATH_B) { +			rtl_set_rfreg(hw, RF90_PATH_A, 0x10, MASKDWORD, +				      0x1000f); +			rtl_set_rfreg(hw, RF90_PATH_A, 0x11, MASKDWORD, +				      0x20101); +		} + +		if (apk_result[path][1] > 6) +			apk_result[path][1] = 6; +	} + +	for (path = 0; path < pathbound; path++) { +		rtl_set_rfreg(hw, (enum radio_path)path, 0x3, MASKDWORD, +			      ((apk_result[path][1] << 15) | +			       (apk_result[path][1] << 10) | +			       (apk_result[path][1] << 5) | +			       apk_result[path][1])); + +		if (path == RF90_PATH_A) +			rtl_set_rfreg(hw, (enum radio_path)path, 0x4, MASKDWORD, +				      ((apk_result[path][1] << 15) | +				       (apk_result[path][1] << 10) | +				       (0x00 << 5) | 0x05)); +		else +			rtl_set_rfreg(hw, (enum radio_path)path, 0x4, MASKDWORD, +				      ((apk_result[path][1] << 15) | +				       (apk_result[path][1] << 10) | +				       (0x02 << 5) | 0x05)); + +		rtl_set_rfreg(hw, (enum radio_path)path, 0xe, MASKDWORD, +			      ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | +			       0x08)); + +	} + +	rtlphy->b_apk_done = true; +#endif +} + +static void _rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, +					  bool bmain, bool is2t) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (is_hal_stop(rtlhal)) { +		rtl_set_bbreg(hw, REG_LEDCFG0, BIT(23), 0x01); +		rtl_set_bbreg(hw, rFPGA0_XAB_RFPARAMETER, BIT(13), 0x01); +	} +	if (is2t) { +		if (bmain) +			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, +				      BIT(5) | BIT(6), 0x1); +		else +			rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, +				      BIT(5) | BIT(6), 0x2); +	} else { +		if (bmain) +			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x2); +		else +			rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1); + +	} +} + +#undef IQK_ADDA_REG_NUM +#undef IQK_DELAY_TIME + +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	long result[4][8]; +	u8 i, final_candidate; +	bool b_patha_ok, b_pathb_ok; +	long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, +	    reg_ecc, reg_tmp = 0; +	bool is12simular, is13simular, is23simular; +	bool b_start_conttx = false, b_singletone = false; +	u32 iqk_bb_reg[10] = { +		ROFDM0_XARXIQIMBALANCE, +		ROFDM0_XBRXIQIMBALANCE, +		ROFDM0_ECCATHRESHOLD, +		ROFDM0_AGCRSSITABLE, +		ROFDM0_XATXIQIMBALANCE, +		ROFDM0_XBTXIQIMBALANCE, +		ROFDM0_XCTXIQIMBALANCE, +		ROFDM0_XCTXAFE, +		ROFDM0_XDTXAFE, +		ROFDM0_RXIQEXTANTA +	}; + +	if (b_recovery) { +		_rtl92c_phy_reload_adda_registers(hw, +						  iqk_bb_reg, +						  rtlphy->iqk_bb_backup, 10); +		return; +	} +	if (b_start_conttx || b_singletone) +		return; +	for (i = 0; i < 8; i++) { +		result[0][i] = 0; +		result[1][i] = 0; +		result[2][i] = 0; +		result[3][i] = 0; +	} +	final_candidate = 0xff; +	b_patha_ok = false; +	b_pathb_ok = false; +	is12simular = false; +	is23simular = false; +	is13simular = false; +	for (i = 0; i < 3; i++) { +		if (IS_92C_SERIAL(rtlhal->version)) +			_rtl92c_phy_iq_calibrate(hw, result, i, true); +		else +			_rtl92c_phy_iq_calibrate(hw, result, i, false); +		if (i == 1) { +			is12simular = _rtl92c_phy_simularity_compare(hw, +								     result, 0, +								     1); +			if (is12simular) { +				final_candidate = 0; +				break; +			} +		} +		if (i == 2) { +			is13simular = _rtl92c_phy_simularity_compare(hw, +								     result, 0, +								     2); +			if (is13simular) { +				final_candidate = 0; +				break; +			} +			is23simular = _rtl92c_phy_simularity_compare(hw, +								     result, 1, +								     2); +			if (is23simular) +				final_candidate = 1; +			else { +				for (i = 0; i < 8; i++) +					reg_tmp += result[3][i]; + +				if (reg_tmp != 0) +					final_candidate = 3; +				else +					final_candidate = 0xFF; +			} +		} +	} +	for (i = 0; i < 4; i++) { +		reg_e94 = result[i][0]; +		reg_e9c = result[i][1]; +		reg_ea4 = result[i][2]; +		reg_eac = result[i][3]; +		reg_eb4 = result[i][4]; +		reg_ebc = result[i][5]; +		reg_ec4 = result[i][6]; +		reg_ecc = result[i][7]; +	} +	if (final_candidate != 0xff) { +		rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; +		rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; +		reg_ea4 = result[final_candidate][2]; +		reg_eac = result[final_candidate][3]; +		rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; +		rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; +		reg_ec4 = result[final_candidate][6]; +		reg_ecc = result[final_candidate][7]; +		b_patha_ok = b_pathb_ok = true; +	} else { +		rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; +		rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0; +	} +	if (reg_e94 != 0) /*&&(reg_ea4 != 0) */ +		_rtl92c_phy_path_a_fill_iqk_matrix(hw, b_patha_ok, result, +						   final_candidate, +						   (reg_ea4 == 0)); +	if (IS_92C_SERIAL(rtlhal->version)) { +		if (reg_eb4 != 0) /*&&(reg_ec4 != 0) */ +			_rtl92c_phy_path_b_fill_iqk_matrix(hw, b_pathb_ok, +							   result, +							   final_candidate, +							   (reg_ec4 == 0)); +	} +	_rtl92c_phy_save_adda_registers(hw, iqk_bb_reg, +					rtlphy->iqk_bb_backup, 10); +} + +void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); +	bool b_start_conttx = false, b_singletone = false; + +	if (b_start_conttx || b_singletone) +		return; +	if (IS_92C_SERIAL(rtlhal->version)) +		_rtl92c_phy_lc_calibrate(hw, true); +	else +		_rtl92c_phy_lc_calibrate(hw, false); +} + +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (rtlphy->b_apk_done) +		return; +	if (IS_92C_SERIAL(rtlhal->version)) +		_rtl92c_phy_ap_calibrate(hw, delta, true); +	else +		_rtl92c_phy_ap_calibrate(hw, delta, false); +} + +void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain) +{ +	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + +	if (IS_92C_SERIAL(rtlhal->version)) +		_rtl92c_phy_set_rfpath_switch(hw, bmain, true); +	else +		_rtl92c_phy_set_rfpath_switch(hw, bmain, false); +} + +bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	bool b_postprocessing = false; + +	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +		 ("-->IO Cmd(%#x), set_io_inprogress(%d)\n", +		  iotype, rtlphy->set_io_inprogress)); +	do { +		switch (iotype) { +		case IO_CMD_RESUME_DM_BY_SCAN: +			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +				 ("[IO CMD] Resume DM after scan.\n")); +			b_postprocessing = true; +			break; +		case IO_CMD_PAUSE_DM_BY_SCAN: +			RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +				 ("[IO CMD] Pause DM before scan.\n")); +			b_postprocessing = true; +			break; +		default: +			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +				 ("switch case not process\n")); +			break; +		} +	} while (false); +	if (b_postprocessing && !rtlphy->set_io_inprogress) { +		rtlphy->set_io_inprogress = true; +		rtlphy->current_io_type = iotype; +	} else { +		return false; +	} +	rtl92c_phy_set_io(hw); +	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, ("<--IO Type(%#x)\n", iotype)); +	return true; +} + +void rtl92c_phy_set_io(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +		 ("--->Cmd(%#x), set_io_inprogress(%d)\n", +		  rtlphy->current_io_type, rtlphy->set_io_inprogress)); +	switch (rtlphy->current_io_type) { +	case IO_CMD_RESUME_DM_BY_SCAN: +		dm_digtable.cur_igvalue = rtlphy->initgain_backup.xaagccore1; +		rtl92c_dm_write_dig(hw); +		rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); +		break; +	case IO_CMD_PAUSE_DM_BY_SCAN: +		rtlphy->initgain_backup.xaagccore1 = dm_digtable.cur_igvalue; +		dm_digtable.cur_igvalue = 0x17; +		rtl92c_dm_write_dig(hw); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		break; +	} +	rtlphy->set_io_inprogress = false; +	RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, +		 ("<---(%#x)\n", rtlphy->current_io_type)); +} + +void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); +	rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); +	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +} + +static void _rtl92ce_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ +	u32 u4b_tmp; +	u8 delay = 5; +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); +	rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); +	rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); +	u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); +	while (u4b_tmp != 0 && delay > 0) { +		rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); +		rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); +		rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); +		u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); +		delay--; +	} +	if (delay == 0) { +		rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); +		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); +		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); +		rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); +		RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, +			 ("Switch RF timeout !!!.\n")); +		return; +	} +	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); +	rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} + +static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, +					    enum rf_pwrstate rfpwr_state) +{ +	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_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool bresult = true; +	u8 i, queue_id; +	struct rtl8192_tx_ring *ring = NULL; + +	ppsc->set_rfpowerstate_inprogress = true; +	switch (rfpwr_state) { +	case ERFON:{ +			if ((ppsc->rfpwr_state == ERFOFF) && +			    RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) { +				bool rtstatus; +				u32 InitializeCount = 0; +				do { +					InitializeCount++; +					RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +						 ("IPS Set eRf nic enable\n")); +					rtstatus = rtl_ps_enable_nic(hw); +				} while ((rtstatus != true) +					 && (InitializeCount < 10)); +				RT_CLEAR_PS_LEVEL(ppsc, +						  RT_RF_OFF_LEVL_HALT_NIC); +			} else { +				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +					 ("Set ERFON sleeped:%d ms\n", +					  jiffies_to_msecs(jiffies - +						   ppsc-> +						   last_sleep_jiffies))); +				ppsc->last_awake_jiffies = jiffies; +				rtl92ce_phy_set_rf_on(hw); +			} +			if (mac->link_state == MAC80211_LINKED) { +				rtlpriv->cfg->ops->led_control(hw, +							       LED_CTL_LINK); +			} else { +				rtlpriv->cfg->ops->led_control(hw, +							       LED_CTL_NO_LINK); +			} +			break; +		} +	case ERFOFF:{ +			for (queue_id = 0, i = 0; +			     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { +				ring = &pcipriv->dev.tx_ring[queue_id]; +				if (skb_queue_len(&ring->queue) == 0 || +				    queue_id == BEACON_QUEUE) { +					queue_id++; +					continue; +				} else { +					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +						 ("eRf Off/Sleep: %d times " +						  "TcbBusyQueue[%d] " +						  "=%d before doze!\n", (i + 1), +						  queue_id, +						  skb_queue_len(&ring->queue))); +					udelay(10); +					i++; +				} +				if (i >= MAX_DOZE_WAITING_TIMES_9x) { +					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +						 ("\nERFOFF: %d times " +						  "TcbBusyQueue[%d] = %d !\n", +						  MAX_DOZE_WAITING_TIMES_9x, +						  queue_id, +						  skb_queue_len(&ring->queue))); +					break; +				} +			} +			if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { +				RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +					 ("IPS Set eRf nic disable\n")); +				rtl_ps_disable_nic(hw); +				RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); +			} else { +				if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) { +					rtlpriv->cfg->ops->led_control(hw, +							       LED_CTL_NO_LINK); +				} else { +					rtlpriv->cfg->ops->led_control(hw, +							     LED_CTL_POWER_OFF); +				} +			} +			break; +		} +	case ERFSLEEP:{ +			if (ppsc->rfpwr_state == ERFOFF) +				break; +			for (queue_id = 0, i = 0; +			     queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { +				ring = &pcipriv->dev.tx_ring[queue_id]; +				if (skb_queue_len(&ring->queue) == 0) { +					queue_id++; +					continue; +				} else { +					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +						 ("eRf Off/Sleep: %d times " +						  "TcbBusyQueue[%d] =%d before " +						  "doze!\n", (i + 1), queue_id, +						  skb_queue_len(&ring->queue))); +					udelay(10); +					i++; +				} +				if (i >= MAX_DOZE_WAITING_TIMES_9x) { +					RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, +						 ("\n ERFSLEEP: %d times " +						  "TcbBusyQueue[%d] = %d !\n", +						  MAX_DOZE_WAITING_TIMES_9x, +						  queue_id, +						  skb_queue_len(&ring->queue))); +					break; +				} +			} +			RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, +				 ("Set ERFSLEEP awaked:%d ms\n", +				  jiffies_to_msecs(jiffies - +						   ppsc->last_awake_jiffies))); +			ppsc->last_sleep_jiffies = jiffies; +			_rtl92ce_phy_set_rf_sleep(hw); +			break; +		} +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("switch case not process\n")); +		bresult = false; +		break; +	} +	if (bresult) +		ppsc->rfpwr_state = rfpwr_state; +	ppsc->set_rfpowerstate_inprogress = false; +	return bresult; +} + +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, +				   enum rf_pwrstate rfpwr_state) +{ +	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool bresult = false; + +	if (rfpwr_state == ppsc->rfpwr_state) +		return bresult; +	bresult = _rtl92ce_phy_set_rf_power_state(hw, rfpwr_state); +	return bresult; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-phy.h new file mode 100644 index 00000000000..ca4daee6e9a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-phy.h @@ -0,0 +1,237 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92C_PHY_H__ +#define __RTL92C_PHY_H__ + +#define MAX_PRECMD_CNT			16 +#define MAX_RFDEPENDCMD_CNT		16 +#define MAX_POSTCMD_CNT			16 + +#define MAX_DOZE_WAITING_TIMES_9x	64 + +#define RT_CANNOT_IO(hw)		false +#define HIGHPOWER_RADIOA_ARRAYLEN	22 + +#define MAX_TOLERANCE			5 +#define	IQK_DELAY_TIME			1 + +#define	APK_BB_REG_NUM			5 +#define	APK_AFE_REG_NUM			16 +#define	APK_CURVE_REG_NUM		4 +#define	PATH_NUM			2 + +#define LOOP_LIMIT			5 +#define MAX_STALL_TIME			50 +#define AntennaDiversityValue		0x80 +#define MAX_TXPWR_IDX_NMODE_92S		63 +#define Reset_Cnt_Limit			3 + +#define IQK_ADDA_REG_NUM		16 +#define IQK_MAC_REG_NUM			4 + +#define RF90_PATH_MAX			2 +#define CHANNEL_MAX_NUMBER		14 +#define CHANNEL_GROUP_MAX		3 + +#define CT_OFFSET_MAC_ADDR		0X16 + +#define CT_OFFSET_CCK_TX_PWR_IDX	0x5A +#define CT_OFFSET_HT401S_TX_PWR_IDX	0x60 +#define CT_OFFSET_HT402S_TX_PWR_IDX_DIF	0x66 +#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF	0x69 +#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF	0x6C + +#define CT_OFFSET_HT40_MAX_PWR_OFFSET	0x6F +#define CT_OFFSET_HT20_MAX_PWR_OFFSET	0x72 + +#define CT_OFFSET_CHANNEL_PLAH		0x75 +#define CT_OFFSET_THERMAL_METER		0x78 +#define CT_OFFSET_RF_OPTION		0x79 +#define CT_OFFSET_VERSION		0x7E +#define CT_OFFSET_CUSTOMER_ID		0x7F + +#define RTL92C_MAX_PATH_NUM		2 +#define CHANNEL_MAX_NUMBER		14 +#define CHANNEL_GROUP_MAX		3 + +enum swchnlcmd_id { +	CMDID_END, +	CMDID_SET_TXPOWEROWER_LEVEL, +	CMDID_BBREGWRITE10, +	CMDID_WRITEPORT_ULONG, +	CMDID_WRITEPORT_USHORT, +	CMDID_WRITEPORT_UCHAR, +	CMDID_RF_WRITEREG, +}; + +struct swchnlcmd { +	enum swchnlcmd_id cmdid; +	u32 para1; +	u32 para2; +	u32 msdelay; +}; + +enum hw90_block_e { +	HW90_BLOCK_MAC = 0, +	HW90_BLOCK_PHY0 = 1, +	HW90_BLOCK_PHY1 = 2, +	HW90_BLOCK_RF = 3, +	HW90_BLOCK_MAXIMUM = 4, +}; + +enum baseband_config_type { +	BASEBAND_CONFIG_PHY_REG = 0, +	BASEBAND_CONFIG_AGC_TAB = 1, +}; + +enum ra_offset_area { +	RA_OFFSET_LEGACY_OFDM1, +	RA_OFFSET_LEGACY_OFDM2, +	RA_OFFSET_HT_OFDM1, +	RA_OFFSET_HT_OFDM2, +	RA_OFFSET_HT_OFDM3, +	RA_OFFSET_HT_OFDM4, +	RA_OFFSET_HT_CCK, +}; + +enum antenna_path { +	ANTENNA_NONE, +	ANTENNA_D, +	ANTENNA_C, +	ANTENNA_CD, +	ANTENNA_B, +	ANTENNA_BD, +	ANTENNA_BC, +	ANTENNA_BCD, +	ANTENNA_A, +	ANTENNA_AD, +	ANTENNA_AC, +	ANTENNA_ACD, +	ANTENNA_AB, +	ANTENNA_ABD, +	ANTENNA_ABC, +	ANTENNA_ABCD +}; + +struct r_antenna_select_ofdm { +	u32 r_tx_antenna:4; +	u32 r_ant_l:4; +	u32 r_ant_non_ht:4; +	u32 r_ant_ht1:4; +	u32 r_ant_ht2:4; +	u32 r_ant_ht_s1:4; +	u32 r_ant_non_ht_s1:4; +	u32 ofdm_txsc:2; +	u32 reserved:2; +}; + +struct r_antenna_select_cck { +	u8 r_cckrx_enable_2:2; +	u8 r_cckrx_enable:2; +	u8 r_ccktx_enable:4; +}; + +struct efuse_contents { +	u8 mac_addr[ETH_ALEN]; +	u8 cck_tx_power_idx[6]; +	u8 ht40_1s_tx_power_idx[6]; +	u8 ht40_2s_tx_power_idx_diff[3]; +	u8 ht20_tx_power_idx_diff[3]; +	u8 ofdm_tx_power_idx_diff[3]; +	u8 ht40_max_power_offset[3]; +	u8 ht20_max_power_offset[3]; +	u8 channel_plan; +	u8 thermal_meter; +	u8 rf_option[5]; +	u8 version; +	u8 oem_id; +	u8 regulatory; +}; + +struct tx_power_struct { +	u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 legacy_ht_txpowerdiff; +	u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER]; +	u8 pwrgroup_cnt; +	u32 mcs_original_offset[4][16]; +}; + +extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, +				   u32 regaddr, u32 bitmask); +extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, +				  u32 regaddr, u32 bitmask, u32 data); +extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, +				   enum radio_path rfpath, u32 regaddr, +				   u32 bitmask); +extern void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw, +				  enum radio_path rfpath, u32 regaddr, +				  u32 bitmask, u32 data); +extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); +extern bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, +						 enum radio_path rfpath); +extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, +					 long *powerlevel); +extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, +					  long power_indbm); +extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, +					     u8 operation); +extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, +				   enum nl80211_channel_type ch_type); +extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, +					 u16 beaconinterval); +void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); +void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); +void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); +bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, +					  enum radio_path rfpath); +extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, +					      u32 rfpath); +bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +extern bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, +					  enum rf_pwrstate rfpwr_state); +void rtl92c_phy_config_bb_external_pa(struct ieee80211_hw *hw); +void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw); +bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); +void rtl92c_phy_set_io(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-reg.h new file mode 100644 index 00000000000..875d5146522 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-reg.h @@ -0,0 +1,2065 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92C_REG_H__ +#define __RTL92C_REG_H__ + +#define REG_SYS_ISO_CTRL			0x0000 +#define REG_SYS_FUNC_EN				0x0002 +#define REG_APS_FSMCO				0x0004 +#define REG_SYS_CLKR				0x0008 +#define REG_9346CR				0x000A +#define REG_EE_VPD				0x000C +#define REG_AFE_MISC				0x0010 +#define REG_SPS0_CTRL				0x0011 +#define REG_SPS_OCP_CFG				0x0018 +#define REG_RSV_CTRL				0x001C +#define REG_RF_CTRL				0x001F +#define REG_LDOA15_CTRL				0x0020 +#define REG_LDOV12D_CTRL			0x0021 +#define REG_LDOHCI12_CTRL			0x0022 +#define REG_LPLDO_CTRL				0x0023 +#define REG_AFE_XTAL_CTRL			0x0024 +#define REG_AFE_PLL_CTRL			0x0028 +#define REG_EFUSE_CTRL				0x0030 +#define REG_EFUSE_TEST				0x0034 +#define REG_PWR_DATA				0x0038 +#define REG_CAL_TIMER				0x003C +#define REG_ACLK_MON				0x003E +#define REG_GPIO_MUXCFG				0x0040 +#define REG_GPIO_IO_SEL				0x0042 +#define REG_MAC_PINMUX_CFG			0x0043 +#define REG_GPIO_PIN_CTRL			0x0044 +#define REG_GPIO_INTM				0x0048 +#define REG_LEDCFG0				0x004C +#define REG_LEDCFG1				0x004D +#define REG_LEDCFG2				0x004E +#define REG_LEDCFG3				0x004F +#define REG_FSIMR				0x0050 +#define REG_FSISR				0x0054 + +#define REG_MCUFWDL				0x0080 + +#define REG_HMEBOX_EXT_0			0x0088 +#define REG_HMEBOX_EXT_1			0x008A +#define REG_HMEBOX_EXT_2			0x008C +#define REG_HMEBOX_EXT_3			0x008E + +#define REG_BIST_SCAN				0x00D0 +#define REG_BIST_RPT				0x00D4 +#define REG_BIST_ROM_RPT			0x00D8 +#define REG_USB_SIE_INTF			0x00E0 +#define REG_PCIE_MIO_INTF			0x00E4 +#define REG_PCIE_MIO_INTD			0x00E8 +#define REG_HPON_FSM				0x00EC +#define REG_SYS_CFG				0x00F0 + +#define REG_CR					0x0100 +#define REG_PBP					0x0104 +#define REG_TRXDMA_CTRL				0x010C +#define REG_TRXFF_BNDY				0x0114 +#define REG_TRXFF_STATUS			0x0118 +#define REG_RXFF_PTR				0x011C +#define REG_HIMR				0x0120 +#define REG_HISR				0x0124 +#define REG_HIMRE				0x0128 +#define REG_HISRE				0x012C +#define REG_CPWM				0x012F +#define REG_FWIMR				0x0130 +#define REG_FWISR				0x0134 +#define REG_PKTBUF_DBG_CTRL			0x0140 +#define REG_PKTBUF_DBG_DATA_L			0x0144 +#define REG_PKTBUF_DBG_DATA_H			0x0148 + +#define REG_TC0_CTRL				0x0150 +#define REG_TC1_CTRL				0x0154 +#define REG_TC2_CTRL				0x0158 +#define REG_TC3_CTRL				0x015C +#define REG_TC4_CTRL				0x0160 +#define REG_TCUNIT_BASE				0x0164 +#define REG_MBIST_START				0x0174 +#define REG_MBIST_DONE				0x0178 +#define REG_MBIST_FAIL				0x017C +#define REG_C2HEVT_MSG_NORMAL			0x01A0 +#define REG_C2HEVT_MSG_TEST			0x01B8 +#define REG_C2HEVT_CLEAR			0x01BF +#define REG_MCUTST_1				0x01c0 +#define REG_FMETHR				0x01C8 +#define REG_HMETFR				0x01CC +#define REG_HMEBOX_0				0x01D0 +#define REG_HMEBOX_1				0x01D4 +#define REG_HMEBOX_2				0x01D8 +#define REG_HMEBOX_3				0x01DC + +#define REG_LLT_INIT				0x01E0 +#define REG_BB_ACCEESS_CTRL			0x01E8 +#define REG_BB_ACCESS_DATA			0x01EC + +#define REG_RQPN				0x0200 +#define REG_FIFOPAGE				0x0204 +#define REG_TDECTRL				0x0208 +#define REG_TXDMA_OFFSET_CHK			0x020C +#define REG_TXDMA_STATUS			0x0210 +#define REG_RQPN_NPQ				0x0214 + +#define REG_RXDMA_AGG_PG_TH			0x0280 +#define REG_RXPKT_NUM				0x0284 +#define REG_RXDMA_STATUS			0x0288 + +#define	REG_PCIE_CTRL_REG			0x0300 +#define	REG_INT_MIG				0x0304 +#define	REG_BCNQ_DESA				0x0308 +#define	REG_HQ_DESA				0x0310 +#define	REG_MGQ_DESA				0x0318 +#define	REG_VOQ_DESA				0x0320 +#define	REG_VIQ_DESA				0x0328 +#define	REG_BEQ_DESA				0x0330 +#define	REG_BKQ_DESA				0x0338 +#define	REG_RX_DESA				0x0340 +#define	REG_DBI					0x0348 +#define	REG_MDIO				0x0354 +#define	REG_DBG_SEL				0x0360 +#define	REG_PCIE_HRPWM				0x0361 +#define	REG_PCIE_HCPWM				0x0363 +#define	REG_UART_CTRL				0x0364 +#define	REG_UART_TX_DESA			0x0370 +#define	REG_UART_RX_DESA			0x0378 + +#define	REG_HDAQ_DESA_NODEF			0x0000 +#define	REG_CMDQ_DESA_NODEF			0x0000 + +#define REG_VOQ_INFORMATION			0x0400 +#define REG_VIQ_INFORMATION			0x0404 +#define REG_BEQ_INFORMATION			0x0408 +#define REG_BKQ_INFORMATION			0x040C +#define REG_MGQ_INFORMATION			0x0410 +#define REG_HGQ_INFORMATION			0x0414 +#define REG_BCNQ_INFORMATION			0x0418 + +#define REG_CPU_MGQ_INFORMATION			0x041C +#define REG_FWHW_TXQ_CTRL			0x0420 +#define REG_HWSEQ_CTRL				0x0423 +#define REG_TXPKTBUF_BCNQ_BDNY			0x0424 +#define REG_TXPKTBUF_MGQ_BDNY			0x0425 +#define REG_MULTI_BCNQ_EN			0x0426 +#define REG_MULTI_BCNQ_OFFSET			0x0427 +#define REG_SPEC_SIFS				0x0428 +#define REG_RL					0x042A +#define REG_DARFRC				0x0430 +#define REG_RARFRC				0x0438 +#define REG_RRSR				0x0440 +#define REG_ARFR0				0x0444 +#define REG_ARFR1				0x0448 +#define REG_ARFR2				0x044C +#define REG_ARFR3				0x0450 +#define REG_AGGLEN_LMT				0x0458 +#define REG_AMPDU_MIN_SPACE			0x045C +#define REG_TXPKTBUF_WMAC_LBK_BF_HD		0x045D +#define REG_FAST_EDCA_CTRL			0x0460 +#define REG_RD_RESP_PKT_TH			0x0463 +#define REG_INIRTS_RATE_SEL			0x0480 +#define REG_INIDATA_RATE_SEL			0x0484 +#define REG_POWER_STATUS			0x04A4 +#define REG_POWER_STAGE1			0x04B4 +#define REG_POWER_STAGE2			0x04B8 +#define REG_PKT_LIFE_TIME			0x04C0 +#define REG_STBC_SETTING			0x04C4 +#define REG_PROT_MODE_CTRL			0x04C8 +#define REG_BAR_MODE_CTRL			0x04CC +#define REG_RA_TRY_RATE_AGG_LMT			0x04CF +#define REG_NQOS_SEQ				0x04DC +#define REG_QOS_SEQ				0x04DE +#define REG_NEED_CPU_HANDLE			0x04E0 +#define REG_PKT_LOSE_RPT			0x04E1 +#define REG_PTCL_ERR_STATUS			0x04E2 +#define REG_DUMMY				0x04FC + +#define REG_EDCA_VO_PARAM			0x0500 +#define REG_EDCA_VI_PARAM			0x0504 +#define REG_EDCA_BE_PARAM			0x0508 +#define REG_EDCA_BK_PARAM			0x050C +#define REG_BCNTCFG				0x0510 +#define REG_PIFS				0x0512 +#define REG_RDG_PIFS				0x0513 +#define REG_SIFS_CTX				0x0514 +#define REG_SIFS_TRX				0x0516 +#define REG_AGGR_BREAK_TIME			0x051A +#define REG_SLOT				0x051B +#define REG_TX_PTCL_CTRL			0x0520 +#define REG_TXPAUSE				0x0522 +#define REG_DIS_TXREQ_CLR			0x0523 +#define REG_RD_CTRL				0x0524 +#define REG_TBTT_PROHIBIT			0x0540 +#define REG_RD_NAV_NXT				0x0544 +#define REG_NAV_PROT_LEN			0x0546 +#define REG_BCN_CTRL				0x0550 +#define REG_USTIME_TSF				0x0551 +#define REG_MBID_NUM				0x0552 +#define REG_DUAL_TSF_RST			0x0553 +#define REG_BCN_INTERVAL			0x0554 +#define REG_MBSSID_BCN_SPACE			0x0554 +#define REG_DRVERLYINT				0x0558 +#define REG_BCNDMATIM				0x0559 +#define REG_ATIMWND				0x055A +#define REG_BCN_MAX_ERR				0x055D +#define REG_RXTSF_OFFSET_CCK			0x055E +#define REG_RXTSF_OFFSET_OFDM			0x055F +#define REG_TSFTR				0x0560 +#define REG_INIT_TSFTR				0x0564 +#define REG_PSTIMER				0x0580 +#define REG_TIMER0				0x0584 +#define REG_TIMER1				0x0588 +#define REG_ACMHWCTRL				0x05C0 +#define REG_ACMRSTCTRL				0x05C1 +#define REG_ACMAVG				0x05C2 +#define REG_VO_ADMTIME				0x05C4 +#define REG_VI_ADMTIME				0x05C6 +#define REG_BE_ADMTIME				0x05C8 +#define REG_EDCA_RANDOM_GEN			0x05CC +#define REG_SCH_TXCMD				0x05D0 + +#define REG_APSD_CTRL				0x0600 +#define REG_BWOPMODE				0x0603 +#define REG_TCR					0x0604 +#define REG_RCR					0x0608 +#define REG_RX_PKT_LIMIT			0x060C +#define REG_RX_DLK_TIME				0x060D +#define REG_RX_DRVINFO_SZ			0x060F + +#define REG_MACID				0x0610 +#define REG_BSSID				0x0618 +#define REG_MAR					0x0620 +#define REG_MBIDCAMCFG				0x0628 + +#define REG_USTIME_EDCA				0x0638 +#define REG_MAC_SPEC_SIFS			0x063A +#define REG_RESP_SIFS_CCK			0x063C +#define REG_RESP_SIFS_OFDM			0x063E +#define REG_ACKTO				0x0640 +#define REG_CTS2TO				0x0641 +#define REG_EIFS				0x0642 + +#define REG_NAV_CTRL				0x0650 +#define REG_BACAMCMD				0x0654 +#define REG_BACAMCONTENT			0x0658 +#define REG_LBDLY				0x0660 +#define REG_FWDLY				0x0661 +#define REG_RXERR_RPT				0x0664 +#define REG_WMAC_TRXPTCL_CTL			0x0668 + +#define REG_CAMCMD				0x0670 +#define REG_CAMWRITE				0x0674 +#define REG_CAMREAD				0x0678 +#define REG_CAMDBG				0x067C +#define REG_SECCFG				0x0680 + +#define REG_WOW_CTRL				0x0690 +#define REG_PSSTATUS				0x0691 +#define REG_PS_RX_INFO				0x0692 +#define REG_LPNAV_CTRL				0x0694 +#define REG_WKFMCAM_CMD				0x0698 +#define REG_WKFMCAM_RWD				0x069C +#define REG_RXFLTMAP0				0x06A0 +#define REG_RXFLTMAP1				0x06A2 +#define REG_RXFLTMAP2				0x06A4 +#define REG_BCN_PSR_RPT				0x06A8 +#define REG_CALB32K_CTRL			0x06AC +#define REG_PKT_MON_CTRL			0x06B4 +#define REG_BT_COEX_TABLE			0x06C0 +#define REG_WMAC_RESP_TXINFO			0x06D8 + +#define REG_USB_INFO				0xFE17 +#define REG_USB_SPECIAL_OPTION			0xFE55 +#define REG_USB_DMA_AGG_TO			0xFE5B +#define REG_USB_AGG_TO				0xFE5C +#define REG_USB_AGG_TH				0xFE5D + +#define REG_TEST_USB_TXQS			0xFE48 +#define REG_TEST_SIE_VID			0xFE60 +#define REG_TEST_SIE_PID			0xFE62 +#define REG_TEST_SIE_OPTIONAL			0xFE64 +#define REG_TEST_SIE_CHIRP_K			0xFE65 +#define REG_TEST_SIE_PHY			0xFE66 +#define REG_TEST_SIE_MAC_ADDR			0xFE70 +#define REG_TEST_SIE_STRING			0xFE80 + +#define REG_NORMAL_SIE_VID			0xFE60 +#define REG_NORMAL_SIE_PID			0xFE62 +#define REG_NORMAL_SIE_OPTIONAL			0xFE64 +#define REG_NORMAL_SIE_EP			0xFE65 +#define REG_NORMAL_SIE_PHY			0xFE68 +#define REG_NORMAL_SIE_MAC_ADDR			0xFE70 +#define REG_NORMAL_SIE_STRING			0xFE80 + +#define	CR9346					REG_9346CR +#define	MSR					(REG_CR + 2) +#define	ISR					REG_HISR +#define	TSFR					REG_TSFTR + +#define	MACIDR0					REG_MACID +#define	MACIDR4					(REG_MACID + 4) + +#define PBP					REG_PBP + +#define	IDR0					MACIDR0 +#define	IDR4					MACIDR4 + +#define	UNUSED_REGISTER				0x1BF +#define	DCAM					UNUSED_REGISTER +#define	PSR					UNUSED_REGISTER +#define BBADDR					UNUSED_REGISTER +#define	PHYDATAR				UNUSED_REGISTER + +#define	INVALID_BBRF_VALUE			0x12345678 + +#define	MAX_MSS_DENSITY_2T			0x13 +#define	MAX_MSS_DENSITY_1T			0x0A + +#define	CMDEEPROM_EN				BIT(5) +#define	CMDEEPROM_SEL				BIT(4) +#define	CMD9346CR_9356SEL			BIT(4) +#define	AUTOLOAD_EEPROM				(CMDEEPROM_EN|CMDEEPROM_SEL) +#define	AUTOLOAD_EFUSE				CMDEEPROM_EN + +#define	GPIOSEL_GPIO				0 +#define	GPIOSEL_ENBT				BIT(5) + +#define	GPIO_IN					REG_GPIO_PIN_CTRL +#define	GPIO_OUT				(REG_GPIO_PIN_CTRL+1) +#define	GPIO_IO_SEL				(REG_GPIO_PIN_CTRL+2) +#define	GPIO_MOD				(REG_GPIO_PIN_CTRL+3) + +#define	MSR_NOLINK				0x00 +#define	MSR_ADHOC				0x01 +#define	MSR_INFRA				0x02 +#define	MSR_AP					0x03 + +#define	RRSR_RSC_OFFSET				21 +#define	RRSR_SHORT_OFFSET			23 +#define	RRSR_RSC_BW_40M				0x600000 +#define	RRSR_RSC_UPSUBCHNL			0x400000 +#define	RRSR_RSC_LOWSUBCHNL			0x200000 +#define	RRSR_SHORT				0x800000 +#define	RRSR_1M					BIT(0) +#define	RRSR_2M					BIT(1) +#define	RRSR_5_5M				BIT(2) +#define	RRSR_11M				BIT(3) +#define	RRSR_6M					BIT(4) +#define	RRSR_9M					BIT(5) +#define	RRSR_12M				BIT(6) +#define	RRSR_18M				BIT(7) +#define	RRSR_24M				BIT(8) +#define	RRSR_36M				BIT(9) +#define	RRSR_48M				BIT(10) +#define	RRSR_54M				BIT(11) +#define	RRSR_MCS0				BIT(12) +#define	RRSR_MCS1				BIT(13) +#define	RRSR_MCS2				BIT(14) +#define	RRSR_MCS3				BIT(15) +#define	RRSR_MCS4				BIT(16) +#define	RRSR_MCS5				BIT(17) +#define	RRSR_MCS6				BIT(18) +#define	RRSR_MCS7				BIT(19) +#define	BRSR_ACKSHORTPMB			BIT(23) + +#define	RATR_1M					0x00000001 +#define	RATR_2M					0x00000002 +#define	RATR_55M				0x00000004 +#define	RATR_11M				0x00000008 +#define	RATR_6M					0x00000010 +#define	RATR_9M					0x00000020 +#define	RATR_12M				0x00000040 +#define	RATR_18M				0x00000080 +#define	RATR_24M				0x00000100 +#define	RATR_36M				0x00000200 +#define	RATR_48M				0x00000400 +#define	RATR_54M				0x00000800 +#define	RATR_MCS0				0x00001000 +#define	RATR_MCS1				0x00002000 +#define	RATR_MCS2				0x00004000 +#define	RATR_MCS3				0x00008000 +#define	RATR_MCS4				0x00010000 +#define	RATR_MCS5				0x00020000 +#define	RATR_MCS6				0x00040000 +#define	RATR_MCS7				0x00080000 +#define	RATR_MCS8				0x00100000 +#define	RATR_MCS9				0x00200000 +#define	RATR_MCS10				0x00400000 +#define	RATR_MCS11				0x00800000 +#define	RATR_MCS12				0x01000000 +#define	RATR_MCS13				0x02000000 +#define	RATR_MCS14				0x04000000 +#define	RATR_MCS15				0x08000000 + +#define RATE_1M					BIT(0) +#define RATE_2M					BIT(1) +#define RATE_5_5M				BIT(2) +#define RATE_11M				BIT(3) +#define RATE_6M					BIT(4) +#define RATE_9M					BIT(5) +#define RATE_12M				BIT(6) +#define RATE_18M				BIT(7) +#define RATE_24M				BIT(8) +#define RATE_36M				BIT(9) +#define RATE_48M				BIT(10) +#define RATE_54M				BIT(11) +#define RATE_MCS0				BIT(12) +#define RATE_MCS1				BIT(13) +#define RATE_MCS2				BIT(14) +#define RATE_MCS3				BIT(15) +#define RATE_MCS4				BIT(16) +#define RATE_MCS5				BIT(17) +#define RATE_MCS6				BIT(18) +#define RATE_MCS7				BIT(19) +#define RATE_MCS8				BIT(20) +#define RATE_MCS9				BIT(21) +#define RATE_MCS10				BIT(22) +#define RATE_MCS11				BIT(23) +#define RATE_MCS12				BIT(24) +#define RATE_MCS13				BIT(25) +#define RATE_MCS14				BIT(26) +#define RATE_MCS15				BIT(27) + +#define	RATE_ALL_CCK		(RATR_1M | RATR_2M | RATR_55M | RATR_11M) +#define	RATE_ALL_OFDM_AG	(RATR_6M | RATR_9M | RATR_12M | RATR_18M \ +				| RATR_24M | RATR_36M | RATR_48M | RATR_54M) +#define	RATE_ALL_OFDM_1SS	(RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \ +				RATR_MCS3 | RATR_MCS4 | RATR_MCS5 | \ +				RATR_MCS6 | RATR_MCS7) +#define	RATE_ALL_OFDM_2SS	(RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \ +				RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \ +				RATR_MCS14 | RATR_MCS15) + +#define	BW_OPMODE_20MHZ				BIT(2) +#define	BW_OPMODE_5G				BIT(1) +#define	BW_OPMODE_11J				BIT(0) + +#define	CAM_VALID				BIT(15) +#define	CAM_NOTVALID				0x0000 +#define	CAM_USEDK				BIT(5) + +#define	CAM_NONE				0x0 +#define	CAM_WEP40				0x01 +#define	CAM_TKIP				0x02 +#define	CAM_AES					0x04 +#define	CAM_WEP104				0x05 + +#define	TOTAL_CAM_ENTRY				32 +#define	HALF_CAM_ENTRY				16 + +#define	CAM_WRITE				BIT(16) +#define	CAM_READ				0x00000000 +#define	CAM_POLLINIG				BIT(31) + +#define	SCR_USEDK				0x01 +#define	SCR_TXSEC_ENABLE			0x02 +#define	SCR_RXSEC_ENABLE			0x04 + +#define	WOW_PMEN				BIT(0) +#define	WOW_WOMEN				BIT(1) +#define	WOW_MAGIC				BIT(2) +#define	WOW_UWF					BIT(3) + +#define	IMR8190_DISABLED			0x0 +#define	IMR_BCNDMAINT6				BIT(31) +#define	IMR_BCNDMAINT5				BIT(30) +#define	IMR_BCNDMAINT4				BIT(29) +#define	IMR_BCNDMAINT3				BIT(28) +#define	IMR_BCNDMAINT2				BIT(27) +#define	IMR_BCNDMAINT1				BIT(26) +#define	IMR_BCNDOK8				BIT(25) +#define	IMR_BCNDOK7				BIT(24) +#define	IMR_BCNDOK6				BIT(23) +#define	IMR_BCNDOK5				BIT(22) +#define	IMR_BCNDOK4				BIT(21) +#define	IMR_BCNDOK3				BIT(20) +#define	IMR_BCNDOK2				BIT(19) +#define	IMR_BCNDOK1				BIT(18) +#define	IMR_TIMEOUT2				BIT(17) +#define	IMR_TIMEOUT1				BIT(16) +#define	IMR_TXFOVW				BIT(15) +#define	IMR_PSTIMEOUT				BIT(14) +#define	IMR_BCNINT				BIT(13) +#define	IMR_RXFOVW				BIT(12) +#define	IMR_RDU					BIT(11) +#define	IMR_ATIMEND				BIT(10) +#define	IMR_BDOK				BIT(9) +#define	IMR_HIGHDOK				BIT(8) +#define	IMR_TBDOK				BIT(7) +#define	IMR_MGNTDOK				BIT(6) +#define	IMR_TBDER				BIT(5) +#define	IMR_BKDOK				BIT(4) +#define	IMR_BEDOK				BIT(3) +#define	IMR_VIDOK				BIT(2) +#define	IMR_VODOK				BIT(1) +#define	IMR_ROK					BIT(0) + +#define	IMR_TXERR				BIT(11) +#define	IMR_RXERR				BIT(10) +#define	IMR_C2HCMD				BIT(9) +#define	IMR_CPWM				BIT(8) +#define	IMR_OCPINT				BIT(1) +#define	IMR_WLANOFF				BIT(0) + +#define	HWSET_MAX_SIZE				128 + +#define	EEPROM_DEFAULT_TSSI			0x0 +#define EEPROM_DEFAULT_TXPOWERDIFF		0x0 +#define EEPROM_DEFAULT_CRYSTALCAP		0x5 +#define EEPROM_DEFAULT_BOARDTYPE		0x02 +#define EEPROM_DEFAULT_TXPOWER			0x1010 +#define	EEPROM_DEFAULT_HT2T_TXPWR		0x10 + +#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3 +#define	EEPROM_DEFAULT_THERMALMETER		0x12 +#define	EEPROM_DEFAULT_ANTTXPOWERDIFF		0x0 +#define	EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP	0x5 +#define	EEPROM_DEFAULT_TXPOWERLEVEL		0x22 +#define	EEPROM_DEFAULT_HT40_2SDIFF		0x0 +#define EEPROM_DEFAULT_HT20_DIFF		2 +#define	EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF	0x3 +#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET	0 +#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET	0 + +#define RF_OPTION1				0x79 +#define RF_OPTION2				0x7A +#define RF_OPTION3				0x7B +#define RF_OPTION4				0x7C + +#define EEPROM_DEFAULT_PID			0x1234 +#define EEPROM_DEFAULT_VID			0x5678 +#define EEPROM_DEFAULT_CUSTOMERID		0xAB +#define EEPROM_DEFAULT_SUBCUSTOMERID		0xCD +#define EEPROM_DEFAULT_VERSION			0 + +#define	EEPROM_CHANNEL_PLAN_FCC			0x0 +#define	EEPROM_CHANNEL_PLAN_IC			0x1 +#define	EEPROM_CHANNEL_PLAN_ETSI		0x2 +#define	EEPROM_CHANNEL_PLAN_SPAIN		0x3 +#define	EEPROM_CHANNEL_PLAN_FRANCE		0x4 +#define	EEPROM_CHANNEL_PLAN_MKK			0x5 +#define	EEPROM_CHANNEL_PLAN_MKK1		0x6 +#define	EEPROM_CHANNEL_PLAN_ISRAEL		0x7 +#define	EEPROM_CHANNEL_PLAN_TELEC		0x8 +#define	EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN	0x9 +#define	EEPROM_CHANNEL_PLAN_WORLD_WIDE_13	0xA +#define	EEPROM_CHANNEL_PLAN_NCC			0xB +#define	EEPROM_CHANNEL_PLAN_BY_HW_MASK		0x80 + +#define EEPROM_CID_DEFAULT			0x0 +#define EEPROM_CID_TOSHIBA			0x4 +#define	EEPROM_CID_CCX				0x10 +#define	EEPROM_CID_QMI				0x0D +#define EEPROM_CID_WHQL				0xFE + +#define	RTL8192_EEPROM_ID			0x8129 + +#define RTL8190_EEPROM_ID			0x8129 +#define EEPROM_HPON				0x02 +#define EEPROM_CLK				0x06 +#define EEPROM_TESTR				0x08 + +#define EEPROM_VID				0x0A +#define EEPROM_DID				0x0C +#define EEPROM_SVID				0x0E +#define EEPROM_SMID				0x10 + +#define EEPROM_MAC_ADDR				0x16 + +#define EEPROM_CCK_TX_PWR_INX			0x5A +#define EEPROM_HT40_1S_TX_PWR_INX		0x60 +#define EEPROM_HT40_2S_TX_PWR_INX_DIFF		0x66 +#define EEPROM_HT20_TX_PWR_INX_DIFF		0x69 +#define EEPROM_OFDM_TX_PWR_INX_DIFF		0x6C +#define EEPROM_HT40_MAX_PWR_OFFSET		0x6F +#define EEPROM_HT20_MAX_PWR_OFFSET		0x72 + +#define EEPROM_TSSI_A				0x76 +#define EEPROM_TSSI_B				0x77 +#define EEPROM_THERMAL_METER			0x78 +#define EEPROM_XTAL_K				0x78 +#define EEPROM_RF_OPT1				0x79 +#define EEPROM_RF_OPT2				0x7A +#define EEPROM_RF_OPT3				0x7B +#define EEPROM_RF_OPT4				0x7C +#define EEPROM_CHANNEL_PLAN			0x7D +#define EEPROM_VERSION				0x7E +#define EEPROM_CUSTOMER_ID			0x7F + +#define EEPROM_PWRDIFF				0x54 + +#define EEPROM_TXPOWERCCK			0x5A +#define	EEPROM_TXPOWERHT40_1S			0x60 +#define	EEPROM_TXPOWERHT40_2SDIFF		0x66 +#define EEPROM_TXPOWERHT20DIFF			0x69 +#define EEPROM_TXPOWER_OFDMDIFF			0x6C + +#define	EEPROM_TXPWR_GROUP			0x6F + +#define EEPROM_TSSI_A				0x76 +#define EEPROM_TSSI_B				0x77 +#define EEPROM_THERMAL_METER			0x78 + +#define EEPROM_CHANNELPLAN			0x75 + +#define RF_OPTION1				0x79 +#define RF_OPTION2				0x7A +#define RF_OPTION3				0x7B +#define RF_OPTION4				0x7C + +#define	STOPBECON				BIT(6) +#define	STOPHIGHT				BIT(5) +#define	STOPMGT					BIT(4) +#define	STOPVO					BIT(3) +#define	STOPVI					BIT(2) +#define	STOPBE					BIT(1) +#define	STOPBK					BIT(0) + +#define	RCR_APPFCS				BIT(31) +#define	RCR_APP_MIC				BIT(30) +#define	RCR_APP_ICV				BIT(29) +#define	RCR_APP_PHYST_RXFF			BIT(28) +#define	RCR_APP_BA_SSN				BIT(27) +#define	RCR_ENMBID				BIT(24) +#define	RCR_LSIGEN				BIT(23) +#define	RCR_MFBEN				BIT(22) +#define	RCR_HTC_LOC_CTRL			BIT(14) +#define	RCR_AMF					BIT(13) +#define	RCR_ACF					BIT(12) +#define	RCR_ADF					BIT(11) +#define	RCR_AICV				BIT(9) +#define	RCR_ACRC32				BIT(8) +#define	RCR_CBSSID_BCN				BIT(7) +#define	RCR_CBSSID_DATA				BIT(6) +#define	RCR_CBSSID				RCR_CBSSID_DATA +#define	RCR_APWRMGT				BIT(5) +#define	RCR_ADD3				BIT(4) +#define	RCR_AB					BIT(3) +#define	RCR_AM					BIT(2) +#define	RCR_APM					BIT(1) +#define	RCR_AAP					BIT(0) +#define	RCR_MXDMA_OFFSET			8 +#define	RCR_FIFO_OFFSET				13 + +#define RSV_CTRL				0x001C +#define RD_CTRL					0x0524 + +#define REG_USB_INFO				0xFE17 +#define REG_USB_SPECIAL_OPTION			0xFE55 +#define REG_USB_DMA_AGG_TO			0xFE5B +#define REG_USB_AGG_TO				0xFE5C +#define REG_USB_AGG_TH				0xFE5D + +#define REG_USB_VID				0xFE60 +#define REG_USB_PID				0xFE62 +#define REG_USB_OPTIONAL			0xFE64 +#define REG_USB_CHIRP_K				0xFE65 +#define REG_USB_PHY				0xFE66 +#define REG_USB_MAC_ADDR			0xFE70 +#define REG_USB_HRPWM				0xFE58 +#define REG_USB_HCPWM				0xFE57 + +#define SW18_FPWM				BIT(3) + +#define ISO_MD2PP				BIT(0) +#define ISO_UA2USB				BIT(1) +#define ISO_UD2CORE				BIT(2) +#define ISO_PA2PCIE				BIT(3) +#define ISO_PD2CORE				BIT(4) +#define ISO_IP2MAC				BIT(5) +#define ISO_DIOP				BIT(6) +#define ISO_DIOE				BIT(7) +#define ISO_EB2CORE				BIT(8) +#define ISO_DIOR				BIT(9) + +#define PWC_EV25V				BIT(14) +#define PWC_EV12V				BIT(15) + +#define FEN_BBRSTB				BIT(0) +#define FEN_BB_GLB_RSTn				BIT(1) +#define FEN_USBA				BIT(2) +#define FEN_UPLL				BIT(3) +#define FEN_USBD				BIT(4) +#define FEN_DIO_PCIE				BIT(5) +#define FEN_PCIEA				BIT(6) +#define FEN_PPLL				BIT(7) +#define FEN_PCIED				BIT(8) +#define FEN_DIOE				BIT(9) +#define FEN_CPUEN				BIT(10) +#define FEN_DCORE				BIT(11) +#define FEN_ELDR				BIT(12) +#define FEN_DIO_RF				BIT(13) +#define FEN_HWPDN				BIT(14) +#define FEN_MREGEN				BIT(15) + +#define PFM_LDALL				BIT(0) +#define PFM_ALDN				BIT(1) +#define PFM_LDKP				BIT(2) +#define PFM_WOWL				BIT(3) +#define EnPDN					BIT(4) +#define PDN_PL					BIT(5) +#define APFM_ONMAC				BIT(8) +#define APFM_OFF				BIT(9) +#define APFM_RSM				BIT(10) +#define AFSM_HSUS				BIT(11) +#define AFSM_PCIE				BIT(12) +#define APDM_MAC				BIT(13) +#define APDM_HOST				BIT(14) +#define APDM_HPDN				BIT(15) +#define RDY_MACON				BIT(16) +#define SUS_HOST				BIT(17) +#define ROP_ALD					BIT(20) +#define ROP_PWR					BIT(21) +#define ROP_SPS					BIT(22) +#define SOP_MRST				BIT(25) +#define SOP_FUSE				BIT(26) +#define SOP_ABG					BIT(27) +#define SOP_AMB					BIT(28) +#define SOP_RCK					BIT(29) +#define SOP_A8M					BIT(30) +#define XOP_BTCK				BIT(31) + +#define ANAD16V_EN				BIT(0) +#define ANA8M					BIT(1) +#define MACSLP					BIT(4) +#define LOADER_CLK_EN				BIT(5) +#define _80M_SSC_DIS				BIT(7) +#define _80M_SSC_EN_HO				BIT(8) +#define PHY_SSC_RSTB				BIT(9) +#define SEC_CLK_EN				BIT(10) +#define MAC_CLK_EN				BIT(11) +#define SYS_CLK_EN				BIT(12) +#define RING_CLK_EN				BIT(13) + +#define	BOOT_FROM_EEPROM			BIT(4) +#define	EEPROM_EN				BIT(5) + +#define AFE_BGEN				BIT(0) +#define AFE_MBEN				BIT(1) +#define MAC_ID_EN				BIT(7) + +#define WLOCK_ALL				BIT(0) +#define WLOCK_00				BIT(1) +#define WLOCK_04				BIT(2) +#define WLOCK_08				BIT(3) +#define WLOCK_40				BIT(4) +#define R_DIS_PRST_0				BIT(5) +#define R_DIS_PRST_1				BIT(6) +#define LOCK_ALL_EN				BIT(7) + +#define RF_EN					BIT(0) +#define RF_RSTB					BIT(1) +#define RF_SDMRSTB				BIT(2) + +#define LDA15_EN				BIT(0) +#define LDA15_STBY				BIT(1) +#define LDA15_OBUF				BIT(2) +#define LDA15_REG_VOS				BIT(3) +#define _LDA15_VOADJ(x)				(((x) & 0x7) << 4) + +#define LDV12_EN				BIT(0) +#define LDV12_SDBY				BIT(1) +#define LPLDO_HSM				BIT(2) +#define LPLDO_LSM_DIS				BIT(3) +#define _LDV12_VADJ(x)				(((x) & 0xF) << 4) + +#define XTAL_EN					BIT(0) +#define XTAL_BSEL				BIT(1) +#define _XTAL_BOSC(x)				(((x) & 0x3) << 2) +#define _XTAL_CADJ(x)				(((x) & 0xF) << 4) +#define XTAL_GATE_USB				BIT(8) +#define _XTAL_USB_DRV(x)			(((x) & 0x3) << 9) +#define XTAL_GATE_AFE				BIT(11) +#define _XTAL_AFE_DRV(x)			(((x) & 0x3) << 12) +#define XTAL_RF_GATE				BIT(14) +#define _XTAL_RF_DRV(x)				(((x) & 0x3) << 15) +#define XTAL_GATE_DIG				BIT(17) +#define _XTAL_DIG_DRV(x)			(((x) & 0x3) << 18) +#define XTAL_BT_GATE				BIT(20) +#define _XTAL_BT_DRV(x)				(((x) & 0x3) << 21) +#define _XTAL_GPIO(x)				(((x) & 0x7) << 23) + +#define CKDLY_AFE				BIT(26) +#define CKDLY_USB				BIT(27) +#define CKDLY_DIG				BIT(28) +#define CKDLY_BT				BIT(29) + +#define APLL_EN					BIT(0) +#define APLL_320_EN				BIT(1) +#define APLL_FREF_SEL				BIT(2) +#define APLL_EDGE_SEL				BIT(3) +#define APLL_WDOGB				BIT(4) +#define APLL_LPFEN				BIT(5) + +#define APLL_REF_CLK_13MHZ			0x1 +#define APLL_REF_CLK_19_2MHZ			0x2 +#define APLL_REF_CLK_20MHZ			0x3 +#define APLL_REF_CLK_25MHZ			0x4 +#define APLL_REF_CLK_26MHZ			0x5 +#define APLL_REF_CLK_38_4MHZ			0x6 +#define APLL_REF_CLK_40MHZ			0x7 + +#define APLL_320EN				BIT(14) +#define APLL_80EN				BIT(15) +#define APLL_1MEN				BIT(24) + +#define ALD_EN					BIT(18) +#define EF_PD					BIT(19) +#define EF_FLAG					BIT(31) + +#define EF_TRPT					BIT(7) +#define LDOE25_EN				BIT(31) + +#define RSM_EN					BIT(0) +#define Timer_EN				BIT(4) + +#define TRSW0EN					BIT(2) +#define TRSW1EN					BIT(3) +#define EROM_EN					BIT(4) +#define EnBT					BIT(5) +#define EnUart					BIT(8) +#define Uart_910				BIT(9) +#define EnPMAC					BIT(10) +#define SIC_SWRST				BIT(11) +#define EnSIC					BIT(12) +#define SIC_23					BIT(13) +#define EnHDP					BIT(14) +#define SIC_LBK					BIT(15) + +#define LED0PL					BIT(4) +#define LED1PL					BIT(12) +#define LED0DIS					BIT(7) + +#define MCUFWDL_EN				BIT(0) +#define MCUFWDL_RDY				BIT(1) +#define FWDL_ChkSum_rpt				BIT(2) +#define MACINI_RDY				BIT(3) +#define BBINI_RDY				BIT(4) +#define RFINI_RDY				BIT(5) +#define WINTINI_RDY				BIT(6) +#define CPRST					BIT(23) + +#define XCLK_VLD				BIT(0) +#define ACLK_VLD				BIT(1) +#define UCLK_VLD				BIT(2) +#define PCLK_VLD				BIT(3) +#define PCIRSTB					BIT(4) +#define V15_VLD					BIT(5) +#define TRP_B15V_EN				BIT(7) +#define SIC_IDLE				BIT(8) +#define BD_MAC2					BIT(9) +#define BD_MAC1					BIT(10) +#define IC_MACPHY_MODE				BIT(11) +#define PAD_HWPD_IDN				BIT(22) +#define TRP_VAUX_EN				BIT(23) +#define TRP_BT_EN				BIT(24) +#define BD_PKG_SEL				BIT(25) +#define BD_HCI_SEL				BIT(26) +#define TYPE_ID					BIT(27) + +#define CHIP_VER_RTL_MASK			0xF000 +#define CHIP_VER_RTL_SHIFT			12 + +#define REG_LBMODE				(REG_CR + 3) + +#define HCI_TXDMA_EN				BIT(0) +#define HCI_RXDMA_EN				BIT(1) +#define TXDMA_EN				BIT(2) +#define RXDMA_EN				BIT(3) +#define PROTOCOL_EN				BIT(4) +#define SCHEDULE_EN				BIT(5) +#define MACTXEN					BIT(6) +#define MACRXEN					BIT(7) +#define ENSWBCN					BIT(8) +#define ENSEC					BIT(9) + +#define _NETTYPE(x)				(((x) & 0x3) << 16) +#define MASK_NETTYPE				0x30000 +#define NT_NO_LINK				0x0 +#define NT_LINK_AD_HOC				0x1 +#define NT_LINK_AP				0x2 +#define NT_AS_AP				0x3 + +#define _LBMODE(x)				(((x) & 0xF) << 24) +#define MASK_LBMODE				0xF000000 +#define LOOPBACK_NORMAL				0x0 +#define LOOPBACK_IMMEDIATELY			0xB +#define LOOPBACK_MAC_DELAY			0x3 +#define LOOPBACK_PHY				0x1 +#define LOOPBACK_DMA				0x7 + +#define GET_RX_PAGE_SIZE(value)		((value) & 0xF) +#define GET_TX_PAGE_SIZE(value)		(((value) & 0xF0) >> 4) +#define _PSRX_MASK				0xF +#define _PSTX_MASK				0xF0 +#define _PSRX(x)				(x) +#define _PSTX(x)				((x) << 4) + +#define PBP_64					0x0 +#define PBP_128					0x1 +#define PBP_256					0x2 +#define PBP_512					0x3 +#define PBP_1024				0x4 + +#define RXDMA_ARBBW_EN				BIT(0) +#define RXSHFT_EN				BIT(1) +#define RXDMA_AGG_EN				BIT(2) +#define QS_VO_QUEUE				BIT(8) +#define QS_VI_QUEUE				BIT(9) +#define QS_BE_QUEUE				BIT(10) +#define QS_BK_QUEUE				BIT(11) +#define QS_MANAGER_QUEUE			BIT(12) +#define QS_HIGH_QUEUE				BIT(13) + +#define HQSEL_VOQ				BIT(0) +#define HQSEL_VIQ				BIT(1) +#define HQSEL_BEQ				BIT(2) +#define HQSEL_BKQ				BIT(3) +#define HQSEL_MGTQ				BIT(4) +#define HQSEL_HIQ				BIT(5) + +#define _TXDMA_HIQ_MAP(x)			(((x)&0x3) << 14) +#define _TXDMA_MGQ_MAP(x)			(((x)&0x3) << 12) +#define _TXDMA_BKQ_MAP(x)			(((x)&0x3) << 10) +#define _TXDMA_BEQ_MAP(x)			(((x)&0x3) <<  8) +#define _TXDMA_VIQ_MAP(x)			(((x)&0x3) <<  6) +#define _TXDMA_VOQ_MAP(x)			(((x)&0x3) <<  4) + +#define QUEUE_LOW				1 +#define QUEUE_NORMAL				2 +#define QUEUE_HIGH				3 + +#define _LLT_NO_ACTIVE				0x0 +#define _LLT_WRITE_ACCESS			0x1 +#define _LLT_READ_ACCESS			0x2 + +#define _LLT_INIT_DATA(x)			((x) & 0xFF) +#define _LLT_INIT_ADDR(x)			(((x) & 0xFF) << 8) +#define _LLT_OP(x)				(((x) & 0x3) << 30) +#define _LLT_OP_VALUE(x)			(((x) >> 30) & 0x3) + +#define BB_WRITE_READ_MASK			(BIT(31) | BIT(30)) +#define BB_WRITE_EN				BIT(30) +#define BB_READ_EN				BIT(31) + +#define _HPQ(x)					((x) & 0xFF) +#define _LPQ(x)					(((x) & 0xFF) << 8) +#define _PUBQ(x)				(((x) & 0xFF) << 16) +#define _NPQ(x)					((x) & 0xFF) + +#define HPQ_PUBLIC_DIS				BIT(24) +#define LPQ_PUBLIC_DIS				BIT(25) +#define LD_RQPN					BIT(31) + +#define BCN_VALID				BIT(16) +#define BCN_HEAD(x)				(((x) & 0xFF) << 8) +#define	BCN_HEAD_MASK				0xFF00 + +#define BLK_DESC_NUM_SHIFT			4 +#define BLK_DESC_NUM_MASK			0xF + +#define DROP_DATA_EN				BIT(9) + +#define EN_AMPDU_RTY_NEW			BIT(7) + +#define _INIRTSMCS_SEL(x)			((x) & 0x3F) + +#define _SPEC_SIFS_CCK(x)			((x) & 0xFF) +#define _SPEC_SIFS_OFDM(x)			(((x) & 0xFF) << 8) + +#define RATE_REG_BITMAP_ALL			0xFFFFF + +#define _RRSC_BITMAP(x)				((x) & 0xFFFFF) + +#define _RRSR_RSC(x)				(((x) & 0x3) << 21) +#define RRSR_RSC_RESERVED			0x0 +#define RRSR_RSC_UPPER_SUBCHANNEL		0x1 +#define RRSR_RSC_LOWER_SUBCHANNEL		0x2 +#define RRSR_RSC_DUPLICATE_MODE			0x3 + +#define USE_SHORT_G1				BIT(20) + +#define _AGGLMT_MCS0(x)				((x) & 0xF) +#define _AGGLMT_MCS1(x)				(((x) & 0xF) << 4) +#define _AGGLMT_MCS2(x)				(((x) & 0xF) << 8) +#define _AGGLMT_MCS3(x)				(((x) & 0xF) << 12) +#define _AGGLMT_MCS4(x)				(((x) & 0xF) << 16) +#define _AGGLMT_MCS5(x)				(((x) & 0xF) << 20) +#define _AGGLMT_MCS6(x)				(((x) & 0xF) << 24) +#define _AGGLMT_MCS7(x)				(((x) & 0xF) << 28) + +#define	RETRY_LIMIT_SHORT_SHIFT			8 +#define	RETRY_LIMIT_LONG_SHIFT			0 + +#define _DARF_RC1(x)				((x) & 0x1F) +#define _DARF_RC2(x)				(((x) & 0x1F) << 8) +#define _DARF_RC3(x)				(((x) & 0x1F) << 16) +#define _DARF_RC4(x)				(((x) & 0x1F) << 24) +#define _DARF_RC5(x)				((x) & 0x1F) +#define _DARF_RC6(x)				(((x) & 0x1F) << 8) +#define _DARF_RC7(x)				(((x) & 0x1F) << 16) +#define _DARF_RC8(x)				(((x) & 0x1F) << 24) + +#define _RARF_RC1(x)				((x) & 0x1F) +#define _RARF_RC2(x)				(((x) & 0x1F) << 8) +#define _RARF_RC3(x)				(((x) & 0x1F) << 16) +#define _RARF_RC4(x)				(((x) & 0x1F) << 24) +#define _RARF_RC5(x)				((x) & 0x1F) +#define _RARF_RC6(x)				(((x) & 0x1F) << 8) +#define _RARF_RC7(x)				(((x) & 0x1F) << 16) +#define _RARF_RC8(x)				(((x) & 0x1F) << 24) + +#define AC_PARAM_TXOP_LIMIT_OFFSET		16 +#define AC_PARAM_ECW_MAX_OFFSET			12 +#define AC_PARAM_ECW_MIN_OFFSET			8 +#define AC_PARAM_AIFS_OFFSET			0 + +#define _AIFS(x)				(x) +#define _ECW_MAX_MIN(x)				((x) << 8) +#define _TXOP_LIMIT(x)				((x) << 16) + +#define _BCNIFS(x)				((x) & 0xFF) +#define _BCNECW(x)				((((x) & 0xF)) << 8) + +#define _LRL(x)					((x) & 0x3F) +#define _SRL(x)					(((x) & 0x3F) << 8) + +#define _SIFS_CCK_CTX(x)			((x) & 0xFF) +#define _SIFS_CCK_TRX(x)			(((x) & 0xFF) << 8); + +#define _SIFS_OFDM_CTX(x)			((x) & 0xFF) +#define _SIFS_OFDM_TRX(x)			(((x) & 0xFF) << 8); + +#define _TBTT_PROHIBIT_HOLD(x)			(((x) & 0xFF) << 8) + +#define DIS_EDCA_CNT_DWN			BIT(11) + +#define EN_MBSSID				BIT(1) +#define EN_TXBCN_RPT				BIT(2) +#define	EN_BCN_FUNCTION				BIT(3) + +#define TSFTR_RST				BIT(0) +#define TSFTR1_RST				BIT(1) + +#define STOP_BCNQ				BIT(6) + +#define	DIS_TSF_UDT0_NORMAL_CHIP		BIT(4) +#define	DIS_TSF_UDT0_TEST_CHIP			BIT(5) + +#define	AcmHw_HwEn				BIT(0) +#define	AcmHw_BeqEn				BIT(1) +#define	AcmHw_ViqEn				BIT(2) +#define	AcmHw_VoqEn				BIT(3) +#define	AcmHw_BeqStatus				BIT(4) +#define	AcmHw_ViqStatus				BIT(5) +#define	AcmHw_VoqStatus				BIT(6) + +#define APSDOFF					BIT(6) +#define APSDOFF_STATUS				BIT(7) + +#define BW_20MHZ				BIT(2) + +#define RATE_BITMAP_ALL				0xFFFFF + +#define RATE_RRSR_CCK_ONLY_1M			0xFFFF1 + +#define TSFRST					BIT(0) +#define DIS_GCLK				BIT(1) +#define PAD_SEL					BIT(2) +#define PWR_ST					BIT(6) +#define PWRBIT_OW_EN				BIT(7) +#define ACRC					BIT(8) +#define CFENDFORM				BIT(9) +#define ICV					BIT(10) + +#define AAP					BIT(0) +#define APM					BIT(1) +#define AM					BIT(2) +#define AB					BIT(3) +#define ADD3					BIT(4) +#define APWRMGT					BIT(5) +#define CBSSID					BIT(6) +#define CBSSID_DATA				BIT(6) +#define CBSSID_BCN				BIT(7) +#define ACRC32					BIT(8) +#define AICV					BIT(9) +#define ADF					BIT(11) +#define ACF					BIT(12) +#define AMF					BIT(13) +#define HTC_LOC_CTRL				BIT(14) +#define UC_DATA_EN				BIT(16) +#define BM_DATA_EN				BIT(17) +#define MFBEN					BIT(22) +#define LSIGEN					BIT(23) +#define EnMBID					BIT(24) +#define APP_BASSN				BIT(27) +#define APP_PHYSTS				BIT(28) +#define APP_ICV					BIT(29) +#define APP_MIC					BIT(30) +#define APP_FCS					BIT(31) + +#define _MIN_SPACE(x)				((x) & 0x7) +#define _SHORT_GI_PADDING(x)			(((x) & 0x1F) << 3) + +#define RXERR_TYPE_OFDM_PPDU			0 +#define RXERR_TYPE_OFDM_FALSE_ALARM		1 +#define	RXERR_TYPE_OFDM_MPDU_OK			2 +#define RXERR_TYPE_OFDM_MPDU_FAIL		3 +#define RXERR_TYPE_CCK_PPDU			4 +#define RXERR_TYPE_CCK_FALSE_ALARM		5 +#define RXERR_TYPE_CCK_MPDU_OK			6 +#define RXERR_TYPE_CCK_MPDU_FAIL		7 +#define RXERR_TYPE_HT_PPDU			8 +#define RXERR_TYPE_HT_FALSE_ALARM		9 +#define RXERR_TYPE_HT_MPDU_TOTAL		10 +#define RXERR_TYPE_HT_MPDU_OK			11 +#define RXERR_TYPE_HT_MPDU_FAIL			12 +#define RXERR_TYPE_RX_FULL_DROP			15 + +#define RXERR_COUNTER_MASK			0xFFFFF +#define RXERR_RPT_RST				BIT(27) +#define _RXERR_RPT_SEL(type)			((type) << 28) + +#define	SCR_TxUseDK				BIT(0) +#define	SCR_RxUseDK				BIT(1) +#define	SCR_TxEncEnable				BIT(2) +#define	SCR_RxDecEnable				BIT(3) +#define	SCR_SKByA2				BIT(4) +#define	SCR_NoSKMC				BIT(5) +#define SCR_TXBCUSEDK				BIT(6) +#define SCR_RXBCUSEDK				BIT(7) + +#define USB_IS_HIGH_SPEED			0 +#define USB_IS_FULL_SPEED			1 +#define USB_SPEED_MASK				BIT(5) + +#define USB_NORMAL_SIE_EP_MASK			0xF +#define USB_NORMAL_SIE_EP_SHIFT			4 + +#define USB_TEST_EP_MASK			0x30 +#define USB_TEST_EP_SHIFT			4 + +#define USB_AGG_EN				BIT(3) + +#define MAC_ADDR_LEN				6 +#define LAST_ENTRY_OF_TX_PKT_BUFFER		255 + +#define POLLING_LLT_THRESHOLD			20 +#define POLLING_READY_TIMEOUT_COUNT		1000 + +#define	MAX_MSS_DENSITY_2T			0x13 +#define	MAX_MSS_DENSITY_1T			0x0A + +#define EPROM_CMD_OPERATING_MODE_MASK	((1<<7)|(1<<6)) +#define EPROM_CMD_CONFIG			0x3 +#define EPROM_CMD_LOAD				1 + +#define	HWSET_MAX_SIZE_92S		HWSET_MAX_SIZE + +#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT(2) + +#define	RPMAC_RESET				0x100 +#define	RPMAC_TXSTART				0x104 +#define	RPMAC_TXLEGACYSIG			0x108 +#define	RPMAC_TXHTSIG1				0x10c +#define	RPMAC_TXHTSIG2				0x110 +#define	RPMAC_PHYDEBUG				0x114 +#define	RPMAC_TXPACKETNUM			0x118 +#define	RPMAC_TXIDLE				0x11c +#define	RPMAC_TXMACHEADER0			0x120 +#define	RPMAC_TXMACHEADER1			0x124 +#define	RPMAC_TXMACHEADER2			0x128 +#define	RPMAC_TXMACHEADER3			0x12c +#define	RPMAC_TXMACHEADER4			0x130 +#define	RPMAC_TXMACHEADER5			0x134 +#define	RPMAC_TXDADATYPE			0x138 +#define	RPMAC_TXRANDOMSEED			0x13c +#define	RPMAC_CCKPLCPPREAMBLE			0x140 +#define	RPMAC_CCKPLCPHEADER			0x144 +#define	RPMAC_CCKCRC16				0x148 +#define	RPMAC_OFDMRXCRC32OK			0x170 +#define	RPMAC_OFDMRXCRC32Er			0x174 +#define	RPMAC_OFDMRXPARITYER			0x178 +#define	RPMAC_OFDMRXCRC8ER			0x17c +#define	RPMAC_CCKCRXRC16ER			0x180 +#define	RPMAC_CCKCRXRC32ER			0x184 +#define	RPMAC_CCKCRXRC32OK			0x188 +#define	RPMAC_TXSTATUS				0x18c + +#define	RFPGA0_RFMOD				0x800 + +#define	RFPGA0_TXINFO				0x804 +#define	RFPGA0_PSDFUNCTION			0x808 + +#define	RFPGA0_TXGAINSTAGE			0x80c + +#define	RFPGA0_RFTIMING1			0x810 +#define	RFPGA0_RFTIMING2			0x814 + +#define	RFPGA0_XA_HSSIPARAMETER1		0x820 +#define	RFPGA0_XA_HSSIPARAMETER2		0x824 +#define	RFPGA0_XB_HSSIPARAMETER1		0x828 +#define	RFPGA0_XB_HSSIPARAMETER2		0x82c + +#define	RFPGA0_XA_LSSIPARAMETER			0x840 +#define	RFPGA0_XB_LSSIPARAMETER			0x844 + +#define	RFPGA0_RFWAKEUPPARAMETER		0x850 +#define	RFPGA0_RFSLEEPUPPARAMETER		0x854 + +#define	RFPGA0_XAB_SWITCHCONTROL		0x858 +#define	RFPGA0_XCD_SWITCHCONTROL		0x85c + +#define	RFPGA0_XA_RFINTERFACEOE			0x860 +#define	RFPGA0_XB_RFINTERFACEOE			0x864 + +#define	RFPGA0_XAB_RFINTERFACESW		0x870 +#define	RFPGA0_XCD_RFINTERFACESW		0x874 + +#define	rFPGA0_XAB_RFPARAMETER			0x878 +#define	rFPGA0_XCD_RFPARAMETER			0x87c + +#define	RFPGA0_ANALOGPARAMETER1			0x880 +#define	RFPGA0_ANALOGPARAMETER2			0x884 +#define	RFPGA0_ANALOGPARAMETER3			0x888 +#define	RFPGA0_ANALOGPARAMETER4			0x88c + +#define	RFPGA0_XA_LSSIREADBACK			0x8a0 +#define	RFPGA0_XB_LSSIREADBACK			0x8a4 +#define	RFPGA0_XC_LSSIREADBACK			0x8a8 +#define	RFPGA0_XD_LSSIREADBACK			0x8ac + +#define	RFPGA0_PSDREPORT			0x8b4 +#define	TRANSCEIVEA_HSPI_READBACK		0x8b8 +#define	TRANSCEIVEB_HSPI_READBACK		0x8bc +#define	RFPGA0_XAB_RFINTERFACERB		0x8e0 +#define	RFPGA0_XCD_RFINTERFACERB		0x8e4 + +#define	RFPGA1_RFMOD				0x900 + +#define	RFPGA1_TXBLOCK				0x904 +#define	RFPGA1_DEBUGSELECT			0x908 +#define	RFPGA1_TXINFO				0x90c + +#define	RCCK0_SYSTEM				0xa00 + +#define	RCCK0_AFESETTING			0xa04 +#define	RCCK0_CCA				0xa08 + +#define	RCCK0_RXAGC1				0xa0c +#define	RCCK0_RXAGC2				0xa10 + +#define	RCCK0_RXHP				0xa14 + +#define	RCCK0_DSPPARAMETER1			0xa18 +#define	RCCK0_DSPPARAMETER2			0xa1c + +#define	RCCK0_TXFILTER1				0xa20 +#define	RCCK0_TXFILTER2				0xa24 +#define	RCCK0_DEBUGPORT				0xa28 +#define	RCCK0_FALSEALARMREPORT			0xa2c +#define	RCCK0_TRSSIREPORT			0xa50 +#define	RCCK0_RXREPORT				0xa54 +#define	RCCK0_FACOUNTERLOWER			0xa5c +#define	RCCK0_FACOUNTERUPPER			0xa58 + +#define	ROFDM0_LSTF				0xc00 + +#define	ROFDM0_TRXPATHENABLE			0xc04 +#define	ROFDM0_TRMUXPAR				0xc08 +#define	ROFDM0_TRSWISOLATION			0xc0c + +#define	ROFDM0_XARXAFE				0xc10 +#define	ROFDM0_XARXIQIMBALANCE			0xc14 +#define	ROFDM0_XBRXAFE				0xc18 +#define	ROFDM0_XBRXIQIMBALANCE			0xc1c +#define	ROFDM0_XCRXAFE				0xc20 +#define	ROFDM0_XCRXIQIMBANLANCE			0xc24 +#define	ROFDM0_XDRXAFE				0xc28 +#define	ROFDM0_XDRXIQIMBALANCE			0xc2c + +#define	ROFDM0_RXDETECTOR1			0xc30 +#define	ROFDM0_RXDETECTOR2			0xc34 +#define	ROFDM0_RXDETECTOR3			0xc38 +#define	ROFDM0_RXDETECTOR4			0xc3c + +#define	ROFDM0_RXDSP				0xc40 +#define	ROFDM0_CFOANDDAGC			0xc44 +#define	ROFDM0_CCADROPTHRESHOLD			0xc48 +#define	ROFDM0_ECCATHRESHOLD			0xc4c + +#define	ROFDM0_XAAGCCORE1			0xc50 +#define	ROFDM0_XAAGCCORE2			0xc54 +#define	ROFDM0_XBAGCCORE1			0xc58 +#define	ROFDM0_XBAGCCORE2			0xc5c +#define	ROFDM0_XCAGCCORE1			0xc60 +#define	ROFDM0_XCAGCCORE2			0xc64 +#define	ROFDM0_XDAGCCORE1			0xc68 +#define	ROFDM0_XDAGCCORE2			0xc6c + +#define	ROFDM0_AGCPARAMETER1			0xc70 +#define	ROFDM0_AGCPARAMETER2			0xc74 +#define	ROFDM0_AGCRSSITABLE			0xc78 +#define	ROFDM0_HTSTFAGC				0xc7c + +#define	ROFDM0_XATXIQIMBALANCE			0xc80 +#define	ROFDM0_XATXAFE				0xc84 +#define	ROFDM0_XBTXIQIMBALANCE			0xc88 +#define	ROFDM0_XBTXAFE				0xc8c +#define	ROFDM0_XCTXIQIMBALANCE			0xc90 +#define	ROFDM0_XCTXAFE				0xc94 +#define	ROFDM0_XDTXIQIMBALANCE			0xc98 +#define	ROFDM0_XDTXAFE				0xc9c + +#define ROFDM0_RXIQEXTANTA			0xca0 + +#define	ROFDM0_RXHPPARAMETER			0xce0 +#define	ROFDM0_TXPSEUDONOISEWGT			0xce4 +#define	ROFDM0_FRAMESYNC			0xcf0 +#define	ROFDM0_DFSREPORT			0xcf4 +#define	ROFDM0_TXCOEFF1				0xca4 +#define	ROFDM0_TXCOEFF2				0xca8 +#define	ROFDM0_TXCOEFF3				0xcac +#define	ROFDM0_TXCOEFF4				0xcb0 +#define	ROFDM0_TXCOEFF5				0xcb4 +#define	ROFDM0_TXCOEFF6				0xcb8 + +#define	ROFDM1_LSTF				0xd00 +#define	ROFDM1_TRXPATHENABLE			0xd04 + +#define	ROFDM1_CF0				0xd08 +#define	ROFDM1_CSI1				0xd10 +#define	ROFDM1_SBD				0xd14 +#define	ROFDM1_CSI2				0xd18 +#define	ROFDM1_CFOTRACKING			0xd2c +#define	ROFDM1_TRXMESAURE1			0xd34 +#define	ROFDM1_INTFDET				0xd3c +#define	ROFDM1_PSEUDONOISESTATEAB		0xd50 +#define	ROFDM1_PSEUDONOISESTATECD		0xd54 +#define	ROFDM1_RXPSEUDONOISEWGT			0xd58 + +#define	ROFDM_PHYCOUNTER1			0xda0 +#define	ROFDM_PHYCOUNTER2			0xda4 +#define	ROFDM_PHYCOUNTER3			0xda8 + +#define	ROFDM_SHORTCFOAB			0xdac +#define	ROFDM_SHORTCFOCD			0xdb0 +#define	ROFDM_LONGCFOAB				0xdb4 +#define	ROFDM_LONGCFOCD				0xdb8 +#define	ROFDM_TAILCF0AB				0xdbc +#define	ROFDM_TAILCF0CD				0xdc0 +#define	ROFDM_PWMEASURE1			0xdc4 +#define	ROFDM_PWMEASURE2			0xdc8 +#define	ROFDM_BWREPORT				0xdcc +#define	ROFDM_AGCREPORT				0xdd0 +#define	ROFDM_RXSNR				0xdd4 +#define	ROFDM_RXEVMCSI				0xdd8 +#define	ROFDM_SIGREPORT				0xddc + +#define	RTXAGC_A_RATE18_06			0xe00 +#define	RTXAGC_A_RATE54_24			0xe04 +#define	RTXAGC_A_CCK1_MCS32			0xe08 +#define	RTXAGC_A_MCS03_MCS00			0xe10 +#define	RTXAGC_A_MCS07_MCS04			0xe14 +#define	RTXAGC_A_MCS11_MCS08			0xe18 +#define	RTXAGC_A_MCS15_MCS12			0xe1c + +#define	RTXAGC_B_RATE18_06			0x830 +#define	RTXAGC_B_RATE54_24			0x834 +#define	RTXAGC_B_CCK1_55_MCS32			0x838 +#define	RTXAGC_B_MCS03_MCS00			0x83c +#define	RTXAGC_B_MCS07_MCS04			0x848 +#define	RTXAGC_B_MCS11_MCS08			0x84c +#define	RTXAGC_B_MCS15_MCS12			0x868 +#define	RTXAGC_B_CCK11_A_CCK2_11		0x86c + +#define	RZEBRA1_HSSIENABLE			0x0 +#define	RZEBRA1_TRXENABLE1			0x1 +#define	RZEBRA1_TRXENABLE2			0x2 +#define	RZEBRA1_AGC				0x4 +#define	RZEBRA1_CHARGEPUMP			0x5 +#define	RZEBRA1_CHANNEL				0x7 + +#define	RZEBRA1_TXGAIN				0x8 +#define	RZEBRA1_TXLPF				0x9 +#define	RZEBRA1_RXLPF				0xb +#define	RZEBRA1_RXHPFCORNER			0xc + +#define	RGLOBALCTRL				0 +#define	RRTL8256_TXLPF				19 +#define	RRTL8256_RXLPF				11 +#define	RRTL8258_TXLPF				0x11 +#define	RRTL8258_RXLPF				0x13 +#define	RRTL8258_RSSILPF			0xa + +#define	RF_AC					0x00 + +#define	RF_IQADJ_G1				0x01 +#define	RF_IQADJ_G2				0x02 +#define	RF_POW_TRSW				0x05 + +#define	RF_GAIN_RX				0x06 +#define	RF_GAIN_TX				0x07 + +#define	RF_TXM_IDAC				0x08 +#define	RF_BS_IQGEN				0x0F + +#define	RF_MODE1				0x10 +#define	RF_MODE2				0x11 + +#define	RF_RX_AGC_HP				0x12 +#define	RF_TX_AGC				0x13 +#define	RF_BIAS					0x14 +#define	RF_IPA					0x15 +#define	RF_POW_ABILITY				0x17 +#define	RF_MODE_AG				0x18 +#define	RRFCHANNEL				0x18 +#define	RF_CHNLBW				0x18 +#define	RF_TOP					0x19 + +#define	RF_RX_G1				0x1A +#define	RF_RX_G2				0x1B + +#define	RF_RX_BB2				0x1C +#define	RF_RX_BB1				0x1D + +#define	RF_RCK1					0x1E +#define	RF_RCK2					0x1F + +#define	RF_TX_G1				0x20 +#define	RF_TX_G2				0x21 +#define	RF_TX_G3				0x22 + +#define	RF_TX_BB1				0x23 +#define	RF_T_METER				0x24 + +#define	RF_SYN_G1				0x25 +#define	RF_SYN_G2				0x26 +#define	RF_SYN_G3				0x27 +#define	RF_SYN_G4				0x28 +#define	RF_SYN_G5				0x29 +#define	RF_SYN_G6				0x2A +#define	RF_SYN_G7				0x2B +#define	RF_SYN_G8				0x2C + +#define	RF_RCK_OS				0x30 +#define	RF_TXPA_G1				0x31 +#define	RF_TXPA_G2				0x32 +#define	RF_TXPA_G3				0x33 + +#define	BBBRESETB				0x100 +#define	BGLOBALRESETB				0x200 +#define	BOFDMTXSTART				0x4 +#define	BCCKTXSTART				0x8 +#define	BCRC32DEBUG				0x100 +#define	BPMACLOOPBACK				0x10 +#define	BTXLSIG					0xffffff +#define	BOFDMTXRATE				0xf +#define	BOFDMTXRESERVED				0x10 +#define	BOFDMTXLENGTH				0x1ffe0 +#define	BOFDMTXPARITY				0x20000 +#define	BTXHTSIG1				0xffffff +#define	BTXHTMCSRATE				0x7f +#define	BTXHTBW					0x80 +#define	BTXHTLENGTH				0xffff00 +#define	BTXHTSIG2				0xffffff +#define	BTXHTSMOOTHING				0x1 +#define	BTXHTSOUNDING				0x2 +#define	BTXHTRESERVED				0x4 +#define	BTXHTAGGREATION				0x8 +#define	BTXHTSTBC				0x30 +#define	BTXHTADVANCECODING			0x40 +#define	BTXHTSHORTGI				0x80 +#define	BTXHTNUMBERHT_LT	F		0x300 +#define	BTXHTCRC8				0x3fc00 +#define	BCOUNTERRESET				0x10000 +#define	BNUMOFOFDMTX				0xffff +#define	BNUMOFCCKTX				0xffff0000 +#define	BTXIDLEINTERVAL				0xffff +#define	BOFDMSERVICE				0xffff0000 +#define	BTXMACHEADER				0xffffffff +#define	BTXDATAINIT				0xff +#define	BTXHTMODE				0x100 +#define	BTXDATATYPE				0x30000 +#define	BTXRANDOMSEED				0xffffffff +#define	BCCKTXPREAMBLE				0x1 +#define	BCCKTXSFD				0xffff0000 +#define	BCCKTXSIG				0xff +#define	BCCKTXSERVICE				0xff00 +#define	BCCKLENGTHEXT				0x8000 +#define	BCCKTXLENGHT				0xffff0000 +#define	BCCKTXCRC16				0xffff +#define	BCCKTXSTATUS				0x1 +#define	BOFDMTXSTATUS				0x2 +#define IS_BB_REG_OFFSET_92S(_Offset)		\ +	((_Offset >= 0x800) && (_Offset <= 0xfff)) + +#define	BRFMOD					0x1 +#define	BJAPANMODE				0x2 +#define	BCCKTXSC				0x30 +#define	BCCKEN					0x1000000 +#define	BOFDMEN					0x2000000 + +#define	BOFDMRXADCPHASE				0x10000 +#define	BOFDMTXDACPHASE				0x40000 +#define	BXATXAGC				0x3f + +#define	BXBTXAGC				0xf00 +#define	BXCTXAGC				0xf000 +#define	BXDTXAGC				0xf0000 + +#define	BPASTART				0xf0000000 +#define	BTRSTART				0x00f00000 +#define	BRFSTART				0x0000f000 +#define	BBBSTART				0x000000f0 +#define	BBBCCKSTART				0x0000000f +#define	BPAEND					0xf +#define	BTREND					0x0f000000 +#define	BRFEND					0x000f0000 +#define	BCCAMASK				0x000000f0 +#define	BR2RCCAMASK				0x00000f00 +#define	BHSSI_R2TDELAY				0xf8000000 +#define	BHSSI_T2RDELAY				0xf80000 +#define	BCONTXHSSI				0x400 +#define	BIGFROMCCK				0x200 +#define	BAGCADDRESS				0x3f +#define	BRXHPTX					0x7000 +#define	BRXHP2RX				0x38000 +#define	BRXHPCCKINI				0xc0000 +#define	BAGCTXCODE				0xc00000 +#define	BAGCRXCODE				0x300000 + +#define	B3WIREDATALENGTH			0x800 +#define	B3WIREADDREAALENGTH			0x400 + +#define	B3WIRERFPOWERDOWN			0x1 +#define	B5GPAPEPOLARITY				0x40000000 +#define	B2GPAPEPOLARITY				0x80000000 +#define	BRFSW_TXDEFAULTANT			0x3 +#define	BRFSW_TXOPTIONANT			0x30 +#define	BRFSW_RXDEFAULTANT			0x300 +#define	BRFSW_RXOPTIONANT			0x3000 +#define	BRFSI_3WIREDATA				0x1 +#define	BRFSI_3WIRECLOCK			0x2 +#define	BRFSI_3WIRELOAD				0x4 +#define	BRFSI_3WIRERW				0x8 +#define	BRFSI_3WIRE				0xf + +#define	BRFSI_RFENV				0x10 + +#define	BRFSI_TRSW				0x20 +#define	BRFSI_TRSWB				0x40 +#define	BRFSI_ANTSW				0x100 +#define	BRFSI_ANTSWB				0x200 +#define	BRFSI_PAPE				0x400 +#define	BRFSI_PAPE5G				0x800 +#define	BBANDSELECT				0x1 +#define	BHTSIG2_GI				0x80 +#define	BHTSIG2_SMOOTHING			0x01 +#define	BHTSIG2_SOUNDING			0x02 +#define	BHTSIG2_AGGREATON			0x08 +#define	BHTSIG2_STBC				0x30 +#define	BHTSIG2_ADVCODING			0x40 +#define	BHTSIG2_NUMOFHTLTF			0x300 +#define	BHTSIG2_CRC8				0x3fc +#define	BHTSIG1_MCS				0x7f +#define	BHTSIG1_BANDWIDTH			0x80 +#define	BHTSIG1_HTLENGTH			0xffff +#define	BLSIG_RATE				0xf +#define	BLSIG_RESERVED				0x10 +#define	BLSIG_LENGTH				0x1fffe +#define	BLSIG_PARITY				0x20 +#define	BCCKRXPHASE				0x4 + +#define	BLSSIREADADDRESS			0x7f800000 +#define	BLSSIREADEDGE				0x80000000 + +#define	BLSSIREADBACKDATA			0xfffff + +#define	BLSSIREADOKFLAG				0x1000 +#define	BCCKSAMPLERATE				0x8 +#define	BREGULATOR0STANDBY			0x1 +#define	BREGULATORPLLSTANDBY			0x2 +#define	BREGULATOR1STANDBY			0x4 +#define	BPLLPOWERUP				0x8 +#define	BDPLLPOWERUP				0x10 +#define	BDA10POWERUP				0x20 +#define	BAD7POWERUP				0x200 +#define	BDA6POWERUP				0x2000 +#define	BXTALPOWERUP				0x4000 +#define	B40MDCLKPOWERUP				0x8000 +#define	BDA6DEBUGMODE				0x20000 +#define	BDA6SWING				0x380000 + +#define	BADCLKPHASE				0x4000000 +#define	B80MCLKDELAY				0x18000000 +#define	BAFEWATCHDOGENABLE			0x20000000 + +#define	BXTALCAP01				0xc0000000 +#define	BXTALCAP23				0x3 +#define	BXTALCAP92X				0x0f000000 +#define BXTALCAP				0x0f000000 + +#define	BINTDIFCLKENABLE			0x400 +#define	BEXTSIGCLKENABLE			0x800 +#define	BBANDGAP_MBIAS_POWERUP			0x10000 +#define	BAD11SH_GAIN				0xc0000 +#define	BAD11NPUT_RANGE				0x700000 +#define	BAD110P_CURRENT				0x3800000 +#define	BLPATH_LOOPBACK				0x4000000 +#define	BQPATH_LOOPBACK				0x8000000 +#define	BAFE_LOOPBACK				0x10000000 +#define	BDA10_SWING				0x7e0 +#define	BDA10_REVERSE				0x800 +#define	BDA_CLK_SOURCE				0x1000 +#define	BDA7INPUT_RANGE				0x6000 +#define	BDA7_GAIN				0x38000 +#define	BDA7OUTPUT_CM_MODE			0x40000 +#define	BDA7INPUT_CM_MODE			0x380000 +#define	BDA7CURRENT				0xc00000 +#define	BREGULATOR_ADJUST			0x7000000 +#define	BAD11POWERUP_ATTX			0x1 +#define	BDA10PS_ATTX				0x10 +#define	BAD11POWERUP_ATRX			0x100 +#define	BDA10PS_ATRX				0x1000 +#define	BCCKRX_AGC_FORMAT			0x200 +#define	BPSDFFT_SAMPLE_POINT			0xc000 +#define	BPSD_AVERAGE_NUM			0x3000 +#define	BIQPATH_CONTROL				0xc00 +#define	BPSD_FREQ				0x3ff +#define	BPSD_ANTENNA_PATH			0x30 +#define	BPSD_IQ_SWITCH				0x40 +#define	BPSD_RX_TRIGGER				0x400000 +#define	BPSD_TX_TRIGGER				0x80000000 +#define	BPSD_SINE_TONE_SCALE			0x7f000000 +#define	BPSD_REPORT				0xffff + +#define	BOFDM_TXSC				0x30000000 +#define	BCCK_TXON				0x1 +#define	BOFDM_TXON				0x2 +#define	BDEBUG_PAGE				0xfff +#define	BDEBUG_ITEM				0xff +#define	BANTL					0x10 +#define	BANT_NONHT				0x100 +#define	BANT_HT1				0x1000 +#define	BANT_HT2				0x10000 +#define	BANT_HT1S1				0x100000 +#define	BANT_NONHTS1				0x1000000 + +#define	BCCK_BBMODE				0x3 +#define	BCCK_TXPOWERSAVING			0x80 +#define	BCCK_RXPOWERSAVING			0x40 + +#define	BCCK_SIDEBAND				0x10 + +#define	BCCK_SCRAMBLE				0x8 +#define	BCCK_ANTDIVERSITY			0x8000 +#define	BCCK_CARRIER_RECOVERY			0x4000 +#define	BCCK_TXRATE				0x3000 +#define	BCCK_DCCANCEL				0x0800 +#define	BCCK_ISICANCEL				0x0400 +#define	BCCK_MATCH_FILTER			0x0200 +#define	BCCK_EQUALIZER				0x0100 +#define	BCCK_PREAMBLE_DETECT			0x800000 +#define	BCCK_FAST_FALSECCA			0x400000 +#define	BCCK_CH_ESTSTART			0x300000 +#define	BCCK_CCA_COUNT				0x080000 +#define	BCCK_CS_LIM				0x070000 +#define	BCCK_BIST_MODE				0x80000000 +#define	BCCK_CCAMASK				0x40000000 +#define	BCCK_TX_DAC_PHASE			0x4 +#define	BCCK_RX_ADC_PHASE			0x20000000 +#define	BCCKR_CP_MODE				0x0100 +#define	BCCK_TXDC_OFFSET			0xf0 +#define	BCCK_RXDC_OFFSET			0xf +#define	BCCK_CCA_MODE				0xc000 +#define	BCCK_FALSECS_LIM			0x3f00 +#define	BCCK_CS_RATIO				0xc00000 +#define	BCCK_CORGBIT_SEL			0x300000 +#define	BCCK_PD_LIM				0x0f0000 +#define	BCCK_NEWCCA				0x80000000 +#define	BCCK_RXHP_OF_IG				0x8000 +#define	BCCK_RXIG				0x7f00 +#define	BCCK_LNA_POLARITY			0x800000 +#define	BCCK_RX1ST_BAIN				0x7f0000 +#define	BCCK_RF_EXTEND				0x20000000 +#define	BCCK_RXAGC_SATLEVEL			0x1f000000 +#define	BCCK_RXAGC_SATCOUNT			0xe0 +#define	bCCKRxRFSettle				0x1f +#define	BCCK_FIXED_RXAGC			0x8000 +#define	BCCK_ANTENNA_POLARITY			0x2000 +#define	BCCK_TXFILTER_TYPE			0x0c00 +#define	BCCK_RXAGC_REPORTTYPE			0x0300 +#define	BCCK_RXDAGC_EN				0x80000000 +#define	BCCK_RXDAGC_PERIOD			0x20000000 +#define	BCCK_RXDAGC_SATLEVEL			0x1f000000 +#define	BCCK_TIMING_RECOVERY			0x800000 +#define	BCCK_TXC0				0x3f0000 +#define	BCCK_TXC1				0x3f000000 +#define	BCCK_TXC2				0x3f +#define	BCCK_TXC3				0x3f00 +#define	BCCK_TXC4				0x3f0000 +#define	BCCK_TXC5				0x3f000000 +#define	BCCK_TXC6				0x3f +#define	BCCK_TXC7				0x3f00 +#define	BCCK_DEBUGPORT				0xff0000 +#define	BCCK_DAC_DEBUG				0x0f000000 +#define	BCCK_FALSEALARM_ENABLE			0x8000 +#define	BCCK_FALSEALARM_READ			0x4000 +#define	BCCK_TRSSI				0x7f +#define	BCCK_RXAGC_REPORT			0xfe +#define	BCCK_RXREPORT_ANTSEL			0x80000000 +#define	BCCK_RXREPORT_MFOFF			0x40000000 +#define	BCCK_RXREPORT_SQLOSS			0x20000000 +#define	BCCK_RXREPORT_PKTLOSS			0x10000000 +#define	BCCK_RXREPORT_LOCKEDBIT			0x08000000 +#define	BCCK_RXREPORT_RATEERROR			0x04000000 +#define	BCCK_RXREPORT_RXRATE			0x03000000 +#define	BCCK_RXFA_COUNTER_LOWER			0xff +#define	BCCK_RXFA_COUNTER_UPPER			0xff000000 +#define	BCCK_RXHPAGC_START			0xe000 +#define	BCCK_RXHPAGC_FINAL			0x1c00 +#define	BCCK_RXFALSEALARM_ENABLE		0x8000 +#define	BCCK_FACOUNTER_FREEZE			0x4000 +#define	BCCK_TXPATH_SEL				0x10000000 +#define	BCCK_DEFAULT_RXPATH			0xc000000 +#define	BCCK_OPTION_RXPATH			0x3000000 + +#define	BNUM_OFSTF				0x3 +#define	BSHIFT_L				0xc0 +#define	BGI_TH					0xc +#define	BRXPATH_A				0x1 +#define	BRXPATH_B				0x2 +#define	BRXPATH_C				0x4 +#define	BRXPATH_D				0x8 +#define	BTXPATH_A				0x1 +#define	BTXPATH_B				0x2 +#define	BTXPATH_C				0x4 +#define	BTXPATH_D				0x8 +#define	BTRSSI_FREQ				0x200 +#define	BADC_BACKOFF				0x3000 +#define	BDFIR_BACKOFF				0xc000 +#define	BTRSSI_LATCH_PHASE			0x10000 +#define	BRX_LDC_OFFSET				0xff +#define	BRX_QDC_OFFSET				0xff00 +#define	BRX_DFIR_MODE				0x1800000 +#define	BRX_DCNF_TYPE				0xe000000 +#define	BRXIQIMB_A				0x3ff +#define	BRXIQIMB_B				0xfc00 +#define	BRXIQIMB_C				0x3f0000 +#define	BRXIQIMB_D				0xffc00000 +#define	BDC_DC_NOTCH				0x60000 +#define	BRXNB_NOTCH				0x1f000000 +#define	BPD_TH					0xf +#define	BPD_TH_OPT2				0xc000 +#define	BPWED_TH				0x700 +#define	BIFMF_WIN_L				0x800 +#define	BPD_OPTION				0x1000 +#define	BMF_WIN_L				0xe000 +#define	BBW_SEARCH_L				0x30000 +#define	BWIN_ENH_L				0xc0000 +#define	BBW_TH					0x700000 +#define	BED_TH2					0x3800000 +#define	BBW_OPTION				0x4000000 +#define	BRADIO_TH				0x18000000 +#define	BWINDOW_L				0xe0000000 +#define	BSBD_OPTION				0x1 +#define	BFRAME_TH				0x1c +#define	BFS_OPTION				0x60 +#define	BDC_SLOPE_CHECK				0x80 +#define	BFGUARD_COUNTER_DC_L			0xe00 +#define	BFRAME_WEIGHT_SHORT			0x7000 +#define	BSUB_TUNE				0xe00000 +#define	BFRAME_DC_LENGTH			0xe000000 +#define	BSBD_START_OFFSET			0x30000000 +#define	BFRAME_TH_2				0x7 +#define	BFRAME_GI2_TH				0x38 +#define	BGI2_SYNC_EN				0x40 +#define	BSARCH_SHORT_EARLY			0x300 +#define	BSARCH_SHORT_LATE			0xc00 +#define	BSARCH_GI2_LATE				0x70000 +#define	BCFOANTSUM				0x1 +#define	BCFOACC					0x2 +#define	BCFOSTARTOFFSET				0xc +#define	BCFOLOOPBACK				0x70 +#define	BCFOSUMWEIGHT				0x80 +#define	BDAGCENABLE				0x10000 +#define	BTXIQIMB_A				0x3ff +#define	BTXIQIMB_b				0xfc00 +#define	BTXIQIMB_C				0x3f0000 +#define	BTXIQIMB_D				0xffc00000 +#define	BTXIDCOFFSET				0xff +#define	BTXIQDCOFFSET				0xff00 +#define	BTXDFIRMODE				0x10000 +#define	BTXPESUDO_NOISEON			0x4000000 +#define	BTXPESUDO_NOISE_A			0xff +#define	BTXPESUDO_NOISE_B			0xff00 +#define	BTXPESUDO_NOISE_C			0xff0000 +#define	BTXPESUDO_NOISE_D			0xff000000 +#define	BCCA_DROPOPTION				0x20000 +#define	BCCA_DROPTHRES				0xfff00000 +#define	BEDCCA_H				0xf +#define	BEDCCA_L				0xf0 +#define	BLAMBDA_ED				0x300 +#define	BRX_INITIALGAIN				0x7f +#define	BRX_ANTDIV_EN				0x80 +#define	BRX_AGC_ADDRESS_FOR_LNA			0x7f00 +#define	BRX_HIGHPOWER_FLOW			0x8000 +#define	BRX_AGC_FREEZE_THRES			0xc0000 +#define	BRX_FREEZESTEP_AGC1			0x300000 +#define	BRX_FREEZESTEP_AGC2			0xc00000 +#define	BRX_FREEZESTEP_AGC3			0x3000000 +#define	BRX_FREEZESTEP_AGC0			0xc000000 +#define	BRXRSSI_CMP_EN				0x10000000 +#define	BRXQUICK_AGCEN				0x20000000 +#define	BRXAGC_FREEZE_THRES_MODE		0x40000000 +#define	BRX_OVERFLOW_CHECKTYPE			0x80000000 +#define	BRX_AGCSHIFT				0x7f +#define	BTRSW_TRI_ONLY				0x80 +#define	BPOWER_THRES				0x300 +#define	BRXAGC_EN				0x1 +#define	BRXAGC_TOGETHER_EN			0x2 +#define	BRXAGC_MIN				0x4 +#define	BRXHP_INI				0x7 +#define	BRXHP_TRLNA				0x70 +#define	BRXHP_RSSI				0x700 +#define	BRXHP_BBP1				0x7000 +#define	BRXHP_BBP2				0x70000 +#define	BRXHP_BBP3				0x700000 +#define	BRSSI_H					0x7f0000 +#define	BRSSI_GEN				0x7f000000 +#define	BRXSETTLE_TRSW				0x7 +#define	BRXSETTLE_LNA				0x38 +#define	BRXSETTLE_RSSI				0x1c0 +#define	BRXSETTLE_BBP				0xe00 +#define	BRXSETTLE_RXHP				0x7000 +#define	BRXSETTLE_ANTSW_RSSI			0x38000 +#define	BRXSETTLE_ANTSW				0xc0000 +#define	BRXPROCESS_TIME_DAGC			0x300000 +#define	BRXSETTLE_HSSI				0x400000 +#define	BRXPROCESS_TIME_BBPPW			0x800000 +#define	BRXANTENNA_POWER_SHIFT			0x3000000 +#define	BRSSI_TABLE_SELECT			0xc000000 +#define	BRXHP_FINAL				0x7000000 +#define	BRXHPSETTLE_BBP				0x7 +#define	BRXHTSETTLE_HSSI			0x8 +#define	BRXHTSETTLE_RXHP			0x70 +#define	BRXHTSETTLE_BBPPW			0x80 +#define	BRXHTSETTLE_IDLE			0x300 +#define	BRXHTSETTLE_RESERVED			0x1c00 +#define	BRXHT_RXHP_EN				0x8000 +#define	BRXAGC_FREEZE_THRES			0x30000 +#define	BRXAGC_TOGETHEREN			0x40000 +#define	BRXHTAGC_MIN				0x80000 +#define	BRXHTAGC_EN				0x100000 +#define	BRXHTDAGC_EN				0x200000 +#define	BRXHT_RXHP_BBP				0x1c00000 +#define	BRXHT_RXHP_FINAL			0xe0000000 +#define	BRXPW_RADIO_TH				0x3 +#define	BRXPW_RADIO_EN				0x4 +#define	BRXMF_HOLD				0x3800 +#define	BRXPD_DELAY_TH1				0x38 +#define	BRXPD_DELAY_TH2				0x1c0 +#define	BRXPD_DC_COUNT_MAX			0x600 +#define	BRXPD_DELAY_TH				0x8000 +#define	BRXPROCESS_DELAY			0xf0000 +#define	BRXSEARCHRANGE_GI2_EARLY		0x700000 +#define	BRXFRAME_FUARD_COUNTER_L		0x3800000 +#define	BRXSGI_GUARD_L				0xc000000 +#define	BRXSGI_SEARCH_L				0x30000000 +#define	BRXSGI_TH				0xc0000000 +#define	BDFSCNT0				0xff +#define	BDFSCNT1				0xff00 +#define	BDFSFLAG				0xf0000 +#define	BMF_WEIGHT_SUM				0x300000 +#define	BMINIDX_TH				0x7f000000 +#define	BDAFORMAT				0x40000 +#define	BTXCH_EMU_ENABLE			0x01000000 +#define	BTRSW_ISOLATION_A			0x7f +#define	BTRSW_ISOLATION_B			0x7f00 +#define	BTRSW_ISOLATION_C			0x7f0000 +#define	BTRSW_ISOLATION_D			0x7f000000 +#define	BEXT_LNA_GAIN				0x7c00 + +#define	BSTBC_EN				0x4 +#define	BANTENNA_MAPPING			0x10 +#define	BNSS					0x20 +#define	BCFO_ANTSUM_ID				0x200 +#define	BPHY_COUNTER_RESET			0x8000000 +#define	BCFO_REPORT_GET				0x4000000 +#define	BOFDM_CONTINUE_TX			0x10000000 +#define	BOFDM_SINGLE_CARRIER			0x20000000 +#define	BOFDM_SINGLE_TONE			0x40000000 +#define	BHT_DETECT				0x100 +#define	BCFOEN					0x10000 +#define	BCFOVALUE				0xfff00000 +#define	BSIGTONE_RE				0x3f +#define	BSIGTONE_IM				0x7f00 +#define	BCOUNTER_CCA				0xffff +#define	BCOUNTER_PARITYFAIL			0xffff0000 +#define	BCOUNTER_RATEILLEGAL			0xffff +#define	BCOUNTER_CRC8FAIL			0xffff0000 +#define	BCOUNTER_MCSNOSUPPORT			0xffff +#define	BCOUNTER_FASTSYNC			0xffff +#define	BSHORTCFO				0xfff +#define	BSHORTCFOT_LENGTH			12 +#define	BSHORTCFOF_LENGTH			11 +#define	BLONGCFO				0x7ff +#define	BLONGCFOT_LENGTH			11 +#define	BLONGCFOF_LENGTH			11 +#define	BTAILCFO				0x1fff +#define	BTAILCFOT_LENGTH			13 +#define	BTAILCFOF_LENGTH			12 +#define	BNOISE_EN_PWDB				0xffff +#define	BCC_POWER_DB				0xffff0000 +#define	BMOISE_PWDB				0xffff +#define	BPOWERMEAST_LENGTH			10 +#define	BPOWERMEASF_LENGTH			3 +#define	BRX_HT_BW				0x1 +#define	BRXSC					0x6 +#define	BRX_HT					0x8 +#define	BNB_INTF_DET_ON				0x1 +#define	BINTF_WIN_LEN_CFG			0x30 +#define	BNB_INTF_TH_CFG				0x1c0 +#define	BRFGAIN					0x3f +#define	BTABLESEL				0x40 +#define	BTRSW					0x80 +#define	BRXSNR_A				0xff +#define	BRXSNR_B				0xff00 +#define	BRXSNR_C				0xff0000 +#define	BRXSNR_D				0xff000000 +#define	BSNR_EVMT_LENGTH			8 +#define	BSNR_EVMF_LENGTH			1 +#define	BCSI1ST					0xff +#define	BCSI2ND					0xff00 +#define	BRXEVM1ST				0xff0000 +#define	BRXEVM2ND				0xff000000 +#define	BSIGEVM					0xff +#define	BPWDB					0xff00 +#define	BSGIEN					0x10000 + +#define	BSFACTOR_QMA1				0xf +#define	BSFACTOR_QMA2				0xf0 +#define	BSFACTOR_QMA3				0xf00 +#define	BSFACTOR_QMA4				0xf000 +#define	BSFACTOR_QMA5				0xf0000 +#define	BSFACTOR_QMA6				0xf0000 +#define	BSFACTOR_QMA7				0xf00000 +#define	BSFACTOR_QMA8				0xf000000 +#define	BSFACTOR_QMA9				0xf0000000 +#define	BCSI_SCHEME				0x100000 + +#define	BNOISE_LVL_TOP_SET			0x3 +#define	BCHSMOOTH				0x4 +#define	BCHSMOOTH_CFG1				0x38 +#define	BCHSMOOTH_CFG2				0x1c0 +#define	BCHSMOOTH_CFG3				0xe00 +#define	BCHSMOOTH_CFG4				0x7000 +#define	BMRCMODE				0x800000 +#define	BTHEVMCFG				0x7000000 + +#define	BLOOP_FIT_TYPE				0x1 +#define	BUPD_CFO				0x40 +#define	BUPD_CFO_OFFDATA			0x80 +#define	BADV_UPD_CFO				0x100 +#define	BADV_TIME_CTRL				0x800 +#define	BUPD_CLKO				0x1000 +#define	BFC					0x6000 +#define	BTRACKING_MODE				0x8000 +#define	BPHCMP_ENABLE				0x10000 +#define	BUPD_CLKO_LTF				0x20000 +#define	BCOM_CH_CFO				0x40000 +#define	BCSI_ESTI_MODE				0x80000 +#define	BADV_UPD_EQZ				0x100000 +#define	BUCHCFG					0x7000000 +#define	BUPDEQZ					0x8000000 + +#define	BRX_PESUDO_NOISE_ON			0x20000000 +#define	BRX_PESUDO_NOISE_A			0xff +#define	BRX_PESUDO_NOISE_B			0xff00 +#define	BRX_PESUDO_NOISE_C			0xff0000 +#define	BRX_PESUDO_NOISE_D			0xff000000 +#define	BRX_PESUDO_NOISESTATE_A			0xffff +#define	BRX_PESUDO_NOISESTATE_B			0xffff0000 +#define	BRX_PESUDO_NOISESTATE_C			0xffff +#define	BRX_PESUDO_NOISESTATE_D			0xffff0000 + +#define	BZEBRA1_HSSIENABLE			0x8 +#define	BZEBRA1_TRXCONTROL			0xc00 +#define	BZEBRA1_TRXGAINSETTING			0x07f +#define	BZEBRA1_RXCOUNTER			0xc00 +#define	BZEBRA1_TXCHANGEPUMP			0x38 +#define	BZEBRA1_RXCHANGEPUMP			0x7 +#define	BZEBRA1_CHANNEL_NUM			0xf80 +#define	BZEBRA1_TXLPFBW				0x400 +#define	BZEBRA1_RXLPFBW				0x600 + +#define	BRTL8256REG_MODE_CTRL1			0x100 +#define	BRTL8256REG_MODE_CTRL0			0x40 +#define	BRTL8256REG_TXLPFBW			0x18 +#define	BRTL8256REG_RXLPFBW			0x600 + +#define	BRTL8258_TXLPFBW			0xc +#define	BRTL8258_RXLPFBW			0xc00 +#define	BRTL8258_RSSILPFBW			0xc0 + +#define	BBYTE0					0x1 +#define	BBYTE1					0x2 +#define	BBYTE2					0x4 +#define	BBYTE3					0x8 +#define	BWORD0					0x3 +#define	BWORD1					0xc +#define	BWORD					0xf + +#define	MASKBYTE0				0xff +#define	MASKBYTE1				0xff00 +#define	MASKBYTE2				0xff0000 +#define	MASKBYTE3				0xff000000 +#define	MASKHWORD				0xffff0000 +#define	MASKLWORD				0x0000ffff +#define	MASKDWORD				0xffffffff +#define	MASK12BITS				0xfff +#define	MASKH4BITS				0xf0000000 +#define MASKOFDM_D				0xffc00000 +#define	MASKCCK					0x3f3f3f3f + +#define	MASK4BITS				0x0f +#define	MASK20BITS				0xfffff +#define RFREG_OFFSET_MASK			0xfffff + +#define	BENABLE					0x1 +#define	BDISABLE				0x0 + +#define	LEFT_ANTENNA				0x0 +#define	RIGHT_ANTENNA				0x1 + +#define	TCHECK_TXSTATUS				500 +#define	TUPDATE_RXCOUNTER			100 + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-rf.c new file mode 100644 index 00000000000..a2d58df5d3a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-rf.c @@ -0,0 +1,523 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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 "rtl8192c-reg.h" +#include "rtl8192c-def.h" +#include "rtl8192c-phy.h" +#include "rtl8192c-rf.h" +#include "rtl8192c-dm.h" + +static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw); + +void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	switch (bandwidth) { +	case HT_CHANNEL_WIDTH_20: +		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & +					     0xfffff3ff) | 0x0400); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, +			      rtlphy->rfreg_chnlval[0]); +		break; +	case HT_CHANNEL_WIDTH_20_40: +		rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] & +					     0xfffff3ff)); +		rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK, +			      rtlphy->rfreg_chnlval[0]); +		break; +	default: +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("unknown bandwidth: %#X\n", bandwidth)); +		break; +	} +} + +void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, +				       u8 *ppowerlevel) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u32 tx_agc[2] = {0, 0}, tmpval; +	bool turbo_scanoff = false; +	u8 idx1, idx2; +	u8 *ptr; + +	if (rtlefuse->eeprom_regulatory != 0) +		turbo_scanoff = true; + +	if (mac->act_scanning == true) { +		tx_agc[RF90_PATH_A] = 0x3f3f3f3f; +		tx_agc[RF90_PATH_B] = 0x3f3f3f3f; + +		if (turbo_scanoff) { +			for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { +				tx_agc[idx1] = ppowerlevel[idx1] | +				    (ppowerlevel[idx1] << 8) | +				    (ppowerlevel[idx1] << 16) | +				    (ppowerlevel[idx1] << 24); +			} +		} +	} else { +		for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { +			tx_agc[idx1] = ppowerlevel[idx1] | +			    (ppowerlevel[idx1] << 8) | +			    (ppowerlevel[idx1] << 16) | +			    (ppowerlevel[idx1] << 24); +		} + +		if (rtlefuse->eeprom_regulatory == 0) { +			tmpval = +			    (rtlphy->mcs_txpwrlevel_origoffset[0][6]) + +			    (rtlphy->mcs_txpwrlevel_origoffset[0][7] << +			     8); +			tx_agc[RF90_PATH_A] += tmpval; + +			tmpval = (rtlphy->mcs_txpwrlevel_origoffset[0][14]) + +				 (rtlphy->mcs_txpwrlevel_origoffset[0][15] << +				 24); +			tx_agc[RF90_PATH_B] += tmpval; +		} +	} + +	for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) { +		ptr = (u8 *) (&(tx_agc[idx1])); +		for (idx2 = 0; idx2 < 4; idx2++) { +			if (*ptr > RF6052_MAX_TX_PWR) +				*ptr = RF6052_MAX_TX_PWR; +			ptr++; +		} +	} + +	tmpval = tx_agc[RF90_PATH_A] & 0xff; +	rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval); + +	RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +		("CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, +		 RTXAGC_A_CCK1_MCS32)); + +	tmpval = tx_agc[RF90_PATH_A] >> 8; + +	if (mac->mode == WIRELESS_MODE_B) +		tmpval = tmpval & 0xff00ffff; + +	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); + +	RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +		("CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval, +		 RTXAGC_B_CCK11_A_CCK2_11)); + +	tmpval = tx_agc[RF90_PATH_B] >> 24; +	rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval); + +	RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +		("CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, +		 RTXAGC_B_CCK11_A_CCK2_11)); + +	tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff; +	rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval); + +	RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +		("CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval, +		 RTXAGC_B_CCK1_55_MCS32)); +} + +static void rtl92c_phy_get_power_base(struct ieee80211_hw *hw, +				      u8 *ppowerlevel, u8 channel, +				      u32 *ofdmbase, u32 *mcsbase) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u32 powerBase0, powerBase1; +	u8 legacy_pwrdiff, ht20_pwrdiff; +	u8 i, powerlevel[2]; + +	for (i = 0; i < 2; i++) { +		powerlevel[i] = ppowerlevel[i]; +		legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1]; +		powerBase0 = powerlevel[i] + legacy_pwrdiff; + +		powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | +		    (powerBase0 << 8) | powerBase0; +		*(ofdmbase + i) = powerBase0; +		RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +			(" [OFDM power base index rf(%c) = 0x%x]\n", +			 ((i == 0) ? 'A' : 'B'), *(ofdmbase + i))); +	} + +	for (i = 0; i < 2; i++) { +		if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) { +			ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1]; +			powerlevel[i] += ht20_pwrdiff; +		} +		powerBase1 = powerlevel[i]; +		powerBase1 = (powerBase1 << 24) | +		    (powerBase1 << 16) | (powerBase1 << 8) | powerBase1; + +		*(mcsbase + i) = powerBase1; + +		RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +			(" [MCS power base index rf(%c) = 0x%x]\n", +			 ((i == 0) ? 'A' : 'B'), *(mcsbase + i))); +	} +} + +static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, +						       u8 channel, u8 index, +						       u32 *powerBase0, +						       u32 *powerBase1, +						       u32 *p_outwriteval) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); +	u8 i, chnlgroup, pwr_diff_limit[4]; +	u32 writeVal, customer_limit, rf; + +	for (rf = 0; rf < 2; rf++) { +		switch (rtlefuse->eeprom_regulatory) { +		case 0: +			chnlgroup = 0; + +			writeVal = +			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index + +			    (rf ? 8 : 0)] +			    + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				("RTK better performance, " +				 "writeVal(%c) = 0x%x\n", +				 ((rf == 0) ? 'A' : 'B'), writeVal)); +			break; +		case 1: +			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { +				writeVal = ((index < 2) ? powerBase0[rf] : +					    powerBase1[rf]); + +				RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +					("Realtek regulatory, 40MHz, " +					 "writeVal(%c) = 0x%x\n", +					 ((rf == 0) ? 'A' : 'B'), writeVal)); +			} else { +				if (rtlphy->pwrgroup_cnt == 1) +					chnlgroup = 0; +				if (rtlphy->pwrgroup_cnt >= 3) { +					if (channel <= 3) +						chnlgroup = 0; +					else if (channel >= 4 && channel <= 9) +						chnlgroup = 1; +					else if (channel > 9) +						chnlgroup = 2; +					if (rtlphy->pwrgroup_cnt == 4) +						chnlgroup++; +				} + +				writeVal = +				    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] +				    [index + (rf ? 8 : 0)] + ((index < 2) ? +							      powerBase0[rf] : +							      powerBase1[rf]); + +				RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +					("Realtek regulatory, 20MHz, " +					 "writeVal(%c) = 0x%x\n", +					 ((rf == 0) ? 'A' : 'B'), writeVal)); +			} +			break; +		case 2: +			writeVal = +			    ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				("Better regulatory, " +				 "writeVal(%c) = 0x%x\n", +				 ((rf == 0) ? 'A' : 'B'), writeVal)); +			break; +		case 3: +			chnlgroup = 0; + +			if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) { +				RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +					("customer's limit, 40MHz " +					 "rf(%c) = 0x%x\n", +					 ((rf == 0) ? 'A' : 'B'), +					 rtlefuse->pwrgroup_ht40[rf][channel - +								     1])); +			} else { +				RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +					("customer's limit, 20MHz " +					 "rf(%c) = 0x%x\n", +					 ((rf == 0) ? 'A' : 'B'), +					 rtlefuse->pwrgroup_ht20[rf][channel - +								     1])); +			} +			for (i = 0; i < 4; i++) { +				pwr_diff_limit[i] = +				    (u8) ((rtlphy->mcs_txpwrlevel_origoffset +					  [chnlgroup][index + +					  (rf ? 8 : 0)] & (0x7f << (i * 8))) >> +					  (i * 8)); + +				if (rtlphy->current_chan_bw == +				    HT_CHANNEL_WIDTH_20_40) { +					if (pwr_diff_limit[i] > +					    rtlefuse-> +					    pwrgroup_ht40[rf][channel - 1]) +						pwr_diff_limit[i] = +						    rtlefuse->pwrgroup_ht40[rf] +						    [channel - 1]; +				} else { +					if (pwr_diff_limit[i] > +					    rtlefuse-> +					    pwrgroup_ht20[rf][channel - 1]) +						pwr_diff_limit[i] = +						    rtlefuse->pwrgroup_ht20[rf] +						    [channel - 1]; +				} +			} + +			customer_limit = (pwr_diff_limit[3] << 24) | +			    (pwr_diff_limit[2] << 16) | +			    (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				("Customer's limit rf(%c) = 0x%x\n", +				 ((rf == 0) ? 'A' : 'B'), customer_limit)); + +			writeVal = customer_limit + +			    ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				("Customer, writeVal rf(%c)= 0x%x\n", +				 ((rf == 0) ? 'A' : 'B'), writeVal)); +			break; +		default: +			chnlgroup = 0; +			writeVal = +			    rtlphy->mcs_txpwrlevel_origoffset[chnlgroup] +			    [index + (rf ? 8 : 0)] +			    + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); + +			RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +				("RTK better performance, writeVal " +				 "rf(%c) = 0x%x\n", +				 ((rf == 0) ? 'A' : 'B'), writeVal)); +			break; +		} + +		if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) +			writeVal = writeVal - 0x06060606; +		else if (rtlpriv->dm.dynamic_txhighpower_lvl == +			 TXHIGHPWRLEVEL_BT2) +			writeVal = writeVal - 0x0c0c0c0c; +		*(p_outwriteval + rf) = writeVal; +	} +} + +static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw, +					 u8 index, u32 *pValue) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	u16 regoffset_a[6] = { +		RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24, +		RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04, +		RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12 +	}; +	u16 regoffset_b[6] = { +		RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24, +		RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04, +		RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12 +	}; +	u8 i, rf, pwr_val[4]; +	u32 writeVal; +	u16 regoffset; + +	for (rf = 0; rf < 2; rf++) { +		writeVal = pValue[rf]; +		for (i = 0; i < 4; i++) { +			pwr_val[i] = (u8) ((writeVal & (0x7f << +							(i * 8))) >> (i * 8)); + +			if (pwr_val[i] > RF6052_MAX_TX_PWR) +				pwr_val[i] = RF6052_MAX_TX_PWR; +		} +		writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) | +		    (pwr_val[1] << 8) | pwr_val[0]; + +		if (rf == 0) +			regoffset = regoffset_a[index]; +		else +			regoffset = regoffset_b[index]; +		rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal); + +		RTPRINT(rtlpriv, FPHY, PHY_TXPWR, +			("Set 0x%x = %08x\n", regoffset, writeVal)); + +		if (((get_rf_type(rtlphy) == RF_2T2R) && +		     (regoffset == RTXAGC_A_MCS15_MCS12 || +		      regoffset == RTXAGC_B_MCS15_MCS12)) || +		    ((get_rf_type(rtlphy) != RF_2T2R) && +		     (regoffset == RTXAGC_A_MCS07_MCS04 || +		      regoffset == RTXAGC_B_MCS07_MCS04))) { + +			writeVal = pwr_val[3]; +			if (regoffset == RTXAGC_A_MCS15_MCS12 || +			    regoffset == RTXAGC_A_MCS07_MCS04) +				regoffset = 0xc90; +			if (regoffset == RTXAGC_B_MCS15_MCS12 || +			    regoffset == RTXAGC_B_MCS07_MCS04) +				regoffset = 0xc98; + +			for (i = 0; i < 3; i++) { +				writeVal = (writeVal > 6) ? (writeVal - 6) : 0; +				rtl_write_byte(rtlpriv, (u32) (regoffset + i), +					       (u8) writeVal); +			} +		} +	} +} + +void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, +					u8 *ppowerlevel, u8 channel) +{ +	u32 writeVal[2], powerBase0[2], powerBase1[2]; +	u8 index; + +	rtl92c_phy_get_power_base(hw, ppowerlevel, +				  channel, &powerBase0[0], &powerBase1[0]); + +	for (index = 0; index < 6; index++) { +		_rtl92c_get_txpower_writeval_by_regulatory(hw, +							   channel, index, +							   &powerBase0[0], +							   &powerBase1[0], +							   &writeVal[0]); + +		_rtl92c_write_ofdm_power_reg(hw, index, &writeVal[0]); +	} +} + +bool rtl92c_phy_rf6052_config(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); + +	if (rtlphy->rf_type == RF_1T1R) +		rtlphy->num_total_rfpath = 1; +	else +		rtlphy->num_total_rfpath = 2; + +	return _rtl92c_phy_rf6052_config_parafile(hw); +} + +static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u32 u4_regvalue; +	u8 rfpath; +	bool rtstatus; +	struct bb_reg_def *pphyreg; + +	for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { + +		pphyreg = &rtlphy->phyreg_def[rfpath]; + +		switch (rfpath) { +		case RF90_PATH_A: +		case RF90_PATH_C: +			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, +						    BRFSI_RFENV); +			break; +		case RF90_PATH_B: +		case RF90_PATH_D: +			u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs, +						    BRFSI_RFENV << 16); +			break; +		} + +		rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1); +		udelay(1); + +		rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1); +		udelay(1); + +		rtl_set_bbreg(hw, pphyreg->rfhssi_para2, +			      B3WIREADDREAALENGTH, 0x0); +		udelay(1); + +		rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0); +		udelay(1); + +		switch (rfpath) { +		case RF90_PATH_A: +			rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, +					(enum radio_path) rfpath); +			break; +		case RF90_PATH_B: +			rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, +					(enum radio_path) rfpath); +			break; +		case RF90_PATH_C: +			break; +		case RF90_PATH_D: +			break; +		} + +		switch (rfpath) { +		case RF90_PATH_A: +		case RF90_PATH_C: +			rtl_set_bbreg(hw, pphyreg->rfintfs, +				      BRFSI_RFENV, u4_regvalue); +			break; +		case RF90_PATH_B: +		case RF90_PATH_D: +			rtl_set_bbreg(hw, pphyreg->rfintfs, +				      BRFSI_RFENV << 16, u4_regvalue); +			break; +		} + +		if (rtstatus != true) { +			RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, +				 ("Radio[%d] Fail!!", rfpath)); +			return false; +		} + +	} + +	RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("<---\n")); +	return rtstatus; +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-rf.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-rf.h new file mode 100644 index 00000000000..d3014f99bb7 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-rf.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92C_RF_H__ +#define __RTL92C_RF_H__ + +#define RF6052_MAX_TX_PWR		0x3F +#define RF6052_MAX_REG			0x3F +#define RF6052_MAX_PATH			2 + +extern void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, +					    u8 bandwidth); +extern void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, +					      u8 *ppowerlevel); +extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, +					       u8 *ppowerlevel, u8 channel); +extern bool rtl92c_phy_rf6052_config(struct ieee80211_hw *hw); +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-sw.c new file mode 100644 index 00000000000..3cdca006be2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-sw.c @@ -0,0 +1,280 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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 "../pci.h" +#include "rtl8192c-reg.h" +#include "rtl8192c-def.h" +#include "rtl8192c-phy.h" +#include "rtl8192c-dm.h" +#include "rtl8192c-hw.h" +#include "rtl8192c-sw.h" +#include "rtl8192c-trx.h" +#include "rtl8192c-led.h" + +int rtl92c_init_sw_vars(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + +	rtlpriv->dm.b_dm_initialgain_enable = 1; +	rtlpriv->dm.dm_flag = 0; +	rtlpriv->dm.b_disable_framebursting = 0;; +	rtlpriv->dm.thermalvalue = 0; +	rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); + +	rtlpci->receive_config = (RCR_APPFCS | +				  RCR_AMF | +				  RCR_ADF | +				  RCR_APP_MIC | +				  RCR_APP_ICV | +				  RCR_AICV | +				  RCR_ACRC32 | +				  RCR_AB | +				  RCR_AM | +				  RCR_APM | +				  RCR_APP_PHYST_RXFF | RCR_HTC_LOC_CTRL | 0); + +	rtlpci->irq_mask[0] = +	    (u32) (IMR_ROK | +		   IMR_VODOK | +		   IMR_VIDOK | +		   IMR_BEDOK | +		   IMR_BKDOK | +		   IMR_MGNTDOK | +		   IMR_HIGHDOK | IMR_BDOK | IMR_RDU | IMR_RXFOVW | 0); + +	rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0); + +	rtlpriv->rtlhal.pfirmware = (u8 *) vmalloc(0x4000); +	if (!rtlpriv->rtlhal.pfirmware) { +		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, +			 ("Can't alloc buffer for fw.\n")); +		return 1; +	} + +	return 0; +} + +void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); + +	if (rtlpriv->rtlhal.pfirmware) { +		vfree(rtlpriv->rtlhal.pfirmware); +		rtlpriv->rtlhal.pfirmware = NULL; +	} +} + +static struct rtl_hal_ops rtl8192ce_hal_ops = { +	.init_sw_vars = rtl92c_init_sw_vars, +	.deinit_sw_vars = rtl92c_deinit_sw_vars, +	.read_eeprom_info = rtl92ce_read_eeprom_info, +	.interrupt_recognized = rtl92ce_interrupt_recognized, +	.hw_init = rtl92ce_hw_init, +	.hw_disable = rtl92ce_card_disable, +	.enable_interrupt = rtl92ce_enable_interrupt, +	.disable_interrupt = rtl92ce_disable_interrupt, +	.set_network_type = rtl92ce_set_network_type, +	.set_qos = rtl92ce_set_qos, +	.set_bcn_reg = rtl92ce_set_beacon_related_registers, +	.set_bcn_intv = rtl92ce_set_beacon_interval, +	.update_interrupt_mask = rtl92ce_update_interrupt_mask, +	.get_hw_reg = rtl92ce_get_hw_reg, +	.set_hw_reg = rtl92ce_set_hw_reg, +	.update_rate_table = rtl92ce_update_hal_rate_table, +	.update_rate_mask = rtl92ce_update_hal_rate_mask, +	.fill_tx_desc = rtl92ce_tx_fill_desc, +	.fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc, +	.query_rx_desc = rtl92ce_rx_query_desc, +	.set_channel_access = rtl92ce_update_channel_access_setting, +	.radio_onoff_checking = rtl92ce_gpio_radio_on_off_checking, +	.set_bw_mode = rtl92c_phy_set_bw_mode, +	.switch_channel = rtl92c_phy_sw_chnl, +	.dm_watchdog = rtl92c_dm_watchdog, +	.scan_operation_backup = rtl92c_phy_scan_operation_backup, +	.set_rf_power_state = rtl92c_phy_set_rf_power_state, +	.led_control = rtl92ce_led_control, +	.set_desc = rtl92ce_set_desc, +	.get_desc = rtl92ce_get_desc, +	.tx_polling = rtl92ce_tx_polling, +	.enable_hw_sec = rtl92ce_enable_hw_security_config, +	.set_key = rtl92ce_set_key, +	.init_sw_leds = rtl92ce_init_sw_leds, +	.deinit_sw_leds = rtl92ce_deinit_sw_leds, +	.get_bbreg = rtl92c_phy_query_bb_reg, +	.set_bbreg = rtl92c_phy_set_bb_reg, +	.get_rfreg = rtl92c_phy_query_rf_reg, +	.set_rfreg = rtl92c_phy_set_rf_reg, +}; + +static struct rtl_mod_params rtl92ce_mod_params = { +	.sw_crypto = 0, +}; + +static struct rtl_hal_cfg rtl92ce_hal_cfg = { +	.name = "rtl92c_pci", +	.fw_name = "rtlwifi/rtl8192cfw.bin", +	.ops = &rtl8192ce_hal_ops, +	.mod_params = &rtl92ce_mod_params, + +	.maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, +	.maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN, +	.maps[SYS_CLK] = REG_SYS_CLKR, +	.maps[MAC_RCR_AM] = AM, +	.maps[MAC_RCR_AB] = AB, +	.maps[MAC_RCR_ACRC32] = ACRC32, +	.maps[MAC_RCR_ACF] = ACF, +	.maps[MAC_RCR_AAP] = AAP, + +	.maps[EFUSE_TEST] = REG_EFUSE_TEST, +	.maps[EFUSE_CTRL] = REG_EFUSE_CTRL, +	.maps[EFUSE_CLK] = 0, +	.maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL, +	.maps[EFUSE_PWC_EV12V] = PWC_EV12V, +	.maps[EFUSE_FEN_ELDR] = FEN_ELDR, +	.maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, +	.maps[EFUSE_ANA8M] = EFUSE_ANA8M, +	.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, + +	.maps[RWCAM] = REG_CAMCMD, +	.maps[WCAMI] = REG_CAMWRITE, +	.maps[RCAMO] = REG_CAMREAD, +	.maps[CAMDBG] = REG_CAMDBG, +	.maps[SECR] = REG_SECCFG, +	.maps[SEC_CAM_NONE] = CAM_NONE, +	.maps[SEC_CAM_WEP40] = CAM_WEP40, +	.maps[SEC_CAM_TKIP] = CAM_TKIP, +	.maps[SEC_CAM_AES] = CAM_AES, +	.maps[SEC_CAM_WEP104] = CAM_WEP104, + +	.maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6, +	.maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5, +	.maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4, +	.maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3, +	.maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2, +	.maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1, +	.maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, +	.maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7, +	.maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6, +	.maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5, +	.maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4, +	.maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3, +	.maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2, +	.maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1, +	.maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2, +	.maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1, + +	.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW, +	.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT, +	.maps[RTL_IMR_BcnInt] = IMR_BCNINT, +	.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW, +	.maps[RTL_IMR_RDU] = IMR_RDU, +	.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND, +	.maps[RTL_IMR_BDOK] = IMR_BDOK, +	.maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK, +	.maps[RTL_IMR_TBDER] = IMR_TBDER, +	.maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK, +	.maps[RTL_IMR_TBDOK] = IMR_TBDOK, +	.maps[RTL_IMR_BKDOK] = IMR_BKDOK, +	.maps[RTL_IMR_BEDOK] = IMR_BEDOK, +	.maps[RTL_IMR_VIDOK] = IMR_VIDOK, +	.maps[RTL_IMR_VODOK] = IMR_VODOK, +	.maps[RTL_IMR_ROK] = IMR_ROK, +	.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), + +	.maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M, +	.maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M, +	.maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M, +	.maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M, +	.maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M, +	.maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M, +	.maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M, +	.maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M, +	.maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M, +	.maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M, +	.maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M, +	.maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M, + +	.maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7, +	.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, +}; + +static struct pci_device_id rtl92ce_pci_ids[] __devinitdata = { +	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)}, +	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)}, +	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)}, +	{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8176, rtl92ce_hal_cfg)}, +	{}, +}; + +MODULE_DEVICE_TABLE(pci, rtl92ce_pci_ids); + +MODULE_AUTHOR("lizhaoming	<chaoming_li@realsil.com.cn>"); +MODULE_AUTHOR("Realtek WlanFAE	<wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger	<Larry.Finger@lwfinger.net>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless"); +MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin"); + +module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444); +MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); + +static struct pci_driver rtl92ce_driver = { +	.name = KBUILD_MODNAME, +	.id_table = rtl92ce_pci_ids, +	.probe = rtl_pci_probe, +	.remove = rtl_pci_disconnect, + +#ifdef CONFIG_PM +	.suspend = rtl_pci_suspend, +	.resume = rtl_pci_resume, +#endif + +}; + +static int __init rtl92ce_module_init(void) +{ +	int ret; + +	ret = pci_register_driver(&rtl92ce_driver); +	if (ret) +		RT_ASSERT(false, (": No device found\n")); + +	return ret; +} + +static void __exit rtl92ce_module_exit(void) +{ +	pci_unregister_driver(&rtl92ce_driver); +} + +module_init(rtl92ce_module_init); +module_exit(rtl92ce_module_exit); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-sw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-sw.h new file mode 100644 index 00000000000..de1198c38d4 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-sw.h @@ -0,0 +1,37 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92CE_SW_H__ +#define __RTL92CE_SW_H__ + +int rtl92c_init_sw_vars(struct ieee80211_hw *hw); +void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw); +void rtl92c_init_var_map(struct ieee80211_hw *hw); + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-table.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-table.c new file mode 100644 index 00000000000..2a9bbbe691a --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-table.c @@ -0,0 +1,1224 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on  2010/ 5/18,  1:41 + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#include "rtl8192c-table.h" + + +u32 RTL8192CEPHY_REG_2TARRAY[PHY_REG_2TARRAY_LENGTH] = { +	0x024, 0x0011800f, +	0x028, 0x00ffdb83, +	0x800, 0x80040002, +	0x804, 0x00000003, +	0x808, 0x0000fc00, +	0x80c, 0x0000000a, +	0x810, 0x10005388, +	0x814, 0x020c3d10, +	0x818, 0x02200385, +	0x81c, 0x00000000, +	0x820, 0x01000100, +	0x824, 0x00390004, +	0x828, 0x01000100, +	0x82c, 0x00390004, +	0x830, 0x27272727, +	0x834, 0x27272727, +	0x838, 0x27272727, +	0x83c, 0x27272727, +	0x840, 0x00010000, +	0x844, 0x00010000, +	0x848, 0x27272727, +	0x84c, 0x27272727, +	0x850, 0x00000000, +	0x854, 0x00000000, +	0x858, 0x569a569a, +	0x85c, 0x0c1b25a4, +	0x860, 0x66e60230, +	0x864, 0x061f0130, +	0x868, 0x27272727, +	0x86c, 0x2b2b2b27, +	0x870, 0x07000700, +	0x874, 0x22184000, +	0x878, 0x08080808, +	0x87c, 0x00000000, +	0x880, 0xc0083070, +	0x884, 0x000004d5, +	0x888, 0x00000000, +	0x88c, 0xcc0000c0, +	0x890, 0x00000800, +	0x894, 0xfffffffe, +	0x898, 0x40302010, +	0x89c, 0x00706050, +	0x900, 0x00000000, +	0x904, 0x00000023, +	0x908, 0x00000000, +	0x90c, 0x81121313, +	0xa00, 0x00d047c8, +	0xa04, 0x80ff000c, +	0xa08, 0x8c838300, +	0xa0c, 0x2e68120f, +	0xa10, 0x9500bb78, +	0xa14, 0x11144028, +	0xa18, 0x00881117, +	0xa1c, 0x89140f00, +	0xa20, 0x1a1b0000, +	0xa24, 0x090e1317, +	0xa28, 0x00000204, +	0xa2c, 0x00d30000, +	0xa70, 0x101fbf00, +	0xa74, 0x00000007, +	0xc00, 0x48071d40, +	0xc04, 0x03a05633, +	0xc08, 0x000000e4, +	0xc0c, 0x6c6c6c6c, +	0xc10, 0x08800000, +	0xc14, 0x40000100, +	0xc18, 0x08800000, +	0xc1c, 0x40000100, +	0xc20, 0x00000000, +	0xc24, 0x00000000, +	0xc28, 0x00000000, +	0xc2c, 0x00000000, +	0xc30, 0x69e9ac44, +	0xc34, 0x469652cf, +	0xc38, 0x49795994, +	0xc3c, 0x0a97971c, +	0xc40, 0x1f7c403f, +	0xc44, 0x000100b7, +	0xc48, 0xec020107, +	0xc4c, 0x007f037f, +	0xc50, 0x69543420, +	0xc54, 0x43bc0094, +	0xc58, 0x69543420, +	0xc5c, 0x433c0094, +	0xc60, 0x00000000, +	0xc64, 0x5116848b, +	0xc68, 0x47c00bff, +	0xc6c, 0x00000036, +	0xc70, 0x2c7f000d, +	0xc74, 0x018610db, +	0xc78, 0x0000001f, +	0xc7c, 0x00b91612, +	0xc80, 0x40000100, +	0xc84, 0x20f60000, +	0xc88, 0x40000100, +	0xc8c, 0x20200000, +	0xc90, 0x00121820, +	0xc94, 0x00000000, +	0xc98, 0x00121820, +	0xc9c, 0x00007f7f, +	0xca0, 0x00000000, +	0xca4, 0x00000080, +	0xca8, 0x00000000, +	0xcac, 0x00000000, +	0xcb0, 0x00000000, +	0xcb4, 0x00000000, +	0xcb8, 0x00000000, +	0xcbc, 0x28000000, +	0xcc0, 0x00000000, +	0xcc4, 0x00000000, +	0xcc8, 0x00000000, +	0xccc, 0x00000000, +	0xcd0, 0x00000000, +	0xcd4, 0x00000000, +	0xcd8, 0x64b22427, +	0xcdc, 0x00766932, +	0xce0, 0x00222222, +	0xce4, 0x00000000, +	0xce8, 0x37644302, +	0xcec, 0x2f97d40c, +	0xd00, 0x00080740, +	0xd04, 0x00020403, +	0xd08, 0x0000907f, +	0xd0c, 0x20010201, +	0xd10, 0xa0633333, +	0xd14, 0x3333bc43, +	0xd18, 0x7a8f5b6b, +	0xd2c, 0xcc979975, +	0xd30, 0x00000000, +	0xd34, 0x80608000, +	0xd38, 0x00000000, +	0xd3c, 0x00027293, +	0xd40, 0x00000000, +	0xd44, 0x00000000, +	0xd48, 0x00000000, +	0xd4c, 0x00000000, +	0xd50, 0x6437140a, +	0xd54, 0x00000000, +	0xd58, 0x00000000, +	0xd5c, 0x30032064, +	0xd60, 0x4653de68, +	0xd64, 0x04518a3c, +	0xd68, 0x00002101, +	0xd6c, 0x2a201c16, +	0xd70, 0x1812362e, +	0xd74, 0x322c2220, +	0xd78, 0x000e3c24, +	0xe00, 0x2a2a2a2a, +	0xe04, 0x2a2a2a2a, +	0xe08, 0x03902a2a, +	0xe10, 0x2a2a2a2a, +	0xe14, 0x2a2a2a2a, +	0xe18, 0x2a2a2a2a, +	0xe1c, 0x2a2a2a2a, +	0xe28, 0x00000000, +	0xe30, 0x1000dc1f, +	0xe34, 0x10008c1f, +	0xe38, 0x02140102, +	0xe3c, 0x681604c2, +	0xe40, 0x01007c00, +	0xe44, 0x01004800, +	0xe48, 0xfb000000, +	0xe4c, 0x000028d1, +	0xe50, 0x1000dc1f, +	0xe54, 0x10008c1f, +	0xe58, 0x02140102, +	0xe5c, 0x28160d05, +	0xe60, 0x00000010, +	0xe68, 0x001b25a4, +	0xe6c, 0x63db25a4, +	0xe70, 0x63db25a4, +	0xe74, 0x0c1b25a4, +	0xe78, 0x0c1b25a4, +	0xe7c, 0x0c1b25a4, +	0xe80, 0x0c1b25a4, +	0xe84, 0x63db25a4, +	0xe88, 0x0c1b25a4, +	0xe8c, 0x63db25a4, +	0xed0, 0x63db25a4, +	0xed4, 0x63db25a4, +	0xed8, 0x63db25a4, +	0xedc, 0x001b25a4, +	0xee0, 0x001b25a4, +	0xeec, 0x6fdb25a4, +	0xf14, 0x00000003, +	0xf4c, 0x00000000, +	0xf00, 0x00000300, +}; + +u32 RTL8192CEPHY_REG_1TARRAY[PHY_REG_1TARRAY_LENGTH] = { +	0x024, 0x0011800f, +	0x028, 0x00ffdb83, +	0x800, 0x80040000, +	0x804, 0x00000001, +	0x808, 0x0000fc00, +	0x80c, 0x0000000a, +	0x810, 0x10005388, +	0x814, 0x020c3d10, +	0x818, 0x02200385, +	0x81c, 0x00000000, +	0x820, 0x01000100, +	0x824, 0x00390004, +	0x828, 0x00000000, +	0x82c, 0x00000000, +	0x830, 0x00000000, +	0x834, 0x00000000, +	0x838, 0x00000000, +	0x83c, 0x00000000, +	0x840, 0x00010000, +	0x844, 0x00000000, +	0x848, 0x00000000, +	0x84c, 0x00000000, +	0x850, 0x00000000, +	0x854, 0x00000000, +	0x858, 0x569a569a, +	0x85c, 0x001b25a4, +	0x860, 0x66e60230, +	0x864, 0x061f0130, +	0x868, 0x00000000, +	0x86c, 0x32323200, +	0x870, 0x07000700, +	0x874, 0x22004000, +	0x878, 0x00000808, +	0x87c, 0x00000000, +	0x880, 0xc0083070, +	0x884, 0x000004d5, +	0x888, 0x00000000, +	0x88c, 0xccc000c0, +	0x890, 0x00000800, +	0x894, 0xfffffffe, +	0x898, 0x40302010, +	0x89c, 0x00706050, +	0x900, 0x00000000, +	0x904, 0x00000023, +	0x908, 0x00000000, +	0x90c, 0x81121111, +	0xa00, 0x00d047c8, +	0xa04, 0x80ff000c, +	0xa08, 0x8c838300, +	0xa0c, 0x2e68120f, +	0xa10, 0x9500bb78, +	0xa14, 0x11144028, +	0xa18, 0x00881117, +	0xa1c, 0x89140f00, +	0xa20, 0x1a1b0000, +	0xa24, 0x090e1317, +	0xa28, 0x00000204, +	0xa2c, 0x00d30000, +	0xa70, 0x101fbf00, +	0xa74, 0x00000007, +	0xc00, 0x48071d40, +	0xc04, 0x03a05611, +	0xc08, 0x000000e4, +	0xc0c, 0x6c6c6c6c, +	0xc10, 0x08800000, +	0xc14, 0x40000100, +	0xc18, 0x08800000, +	0xc1c, 0x40000100, +	0xc20, 0x00000000, +	0xc24, 0x00000000, +	0xc28, 0x00000000, +	0xc2c, 0x00000000, +	0xc30, 0x69e9ac44, +	0xc34, 0x469652cf, +	0xc38, 0x49795994, +	0xc3c, 0x0a97971c, +	0xc40, 0x1f7c403f, +	0xc44, 0x000100b7, +	0xc48, 0xec020107, +	0xc4c, 0x007f037f, +	0xc50, 0x69543420, +	0xc54, 0x43bc0094, +	0xc58, 0x69543420, +	0xc5c, 0x433c0094, +	0xc60, 0x00000000, +	0xc64, 0x5116848b, +	0xc68, 0x47c00bff, +	0xc6c, 0x00000036, +	0xc70, 0x2c7f000d, +	0xc74, 0x018610db, +	0xc78, 0x0000001f, +	0xc7c, 0x00b91612, +	0xc80, 0x40000100, +	0xc84, 0x20f60000, +	0xc88, 0x40000100, +	0xc8c, 0x20200000, +	0xc90, 0x00121820, +	0xc94, 0x00000000, +	0xc98, 0x00121820, +	0xc9c, 0x00007f7f, +	0xca0, 0x00000000, +	0xca4, 0x00000080, +	0xca8, 0x00000000, +	0xcac, 0x00000000, +	0xcb0, 0x00000000, +	0xcb4, 0x00000000, +	0xcb8, 0x00000000, +	0xcbc, 0x28000000, +	0xcc0, 0x00000000, +	0xcc4, 0x00000000, +	0xcc8, 0x00000000, +	0xccc, 0x00000000, +	0xcd0, 0x00000000, +	0xcd4, 0x00000000, +	0xcd8, 0x64b22427, +	0xcdc, 0x00766932, +	0xce0, 0x00222222, +	0xce4, 0x00000000, +	0xce8, 0x37644302, +	0xcec, 0x2f97d40c, +	0xd00, 0x00080740, +	0xd04, 0x00020401, +	0xd08, 0x0000907f, +	0xd0c, 0x20010201, +	0xd10, 0xa0633333, +	0xd14, 0x3333bc43, +	0xd18, 0x7a8f5b6b, +	0xd2c, 0xcc979975, +	0xd30, 0x00000000, +	0xd34, 0x80608000, +	0xd38, 0x00000000, +	0xd3c, 0x00027293, +	0xd40, 0x00000000, +	0xd44, 0x00000000, +	0xd48, 0x00000000, +	0xd4c, 0x00000000, +	0xd50, 0x6437140a, +	0xd54, 0x00000000, +	0xd58, 0x00000000, +	0xd5c, 0x30032064, +	0xd60, 0x4653de68, +	0xd64, 0x04518a3c, +	0xd68, 0x00002101, +	0xd6c, 0x2a201c16, +	0xd70, 0x1812362e, +	0xd74, 0x322c2220, +	0xd78, 0x000e3c24, +	0xe00, 0x2a2a2a2a, +	0xe04, 0x2a2a2a2a, +	0xe08, 0x03902a2a, +	0xe10, 0x2a2a2a2a, +	0xe14, 0x2a2a2a2a, +	0xe18, 0x2a2a2a2a, +	0xe1c, 0x2a2a2a2a, +	0xe28, 0x00000000, +	0xe30, 0x1000dc1f, +	0xe34, 0x10008c1f, +	0xe38, 0x02140102, +	0xe3c, 0x681604c2, +	0xe40, 0x01007c00, +	0xe44, 0x01004800, +	0xe48, 0xfb000000, +	0xe4c, 0x000028d1, +	0xe50, 0x1000dc1f, +	0xe54, 0x10008c1f, +	0xe58, 0x02140102, +	0xe5c, 0x28160d05, +	0xe60, 0x00000010, +	0xe68, 0x001b25a4, +	0xe6c, 0x631b25a0, +	0xe70, 0x631b25a0, +	0xe74, 0x081b25a0, +	0xe78, 0x081b25a0, +	0xe7c, 0x081b25a0, +	0xe80, 0x081b25a0, +	0xe84, 0x631b25a0, +	0xe88, 0x081b25a0, +	0xe8c, 0x631b25a0, +	0xed0, 0x631b25a0, +	0xed4, 0x631b25a0, +	0xed8, 0x631b25a0, +	0xedc, 0x001b25a0, +	0xee0, 0x001b25a0, +	0xeec, 0x6b1b25a0, +	0xf14, 0x00000003, +	0xf4c, 0x00000000, +	0xf00, 0x00000300, +}; + +u32 RTL8192CEPHY_REG_ARRAY_PG[PHY_REG_ARRAY_PGLENGTH] = { +	0xe00, 0xffffffff, 0x0a0c0c0c, +	0xe04, 0xffffffff, 0x02040608, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x0a0c0d0e, +	0xe14, 0xffffffff, 0x02040608, +	0xe18, 0xffffffff, 0x0a0c0d0e, +	0xe1c, 0xffffffff, 0x02040608, +	0x830, 0xffffffff, 0x0a0c0c0c, +	0x834, 0xffffffff, 0x02040608, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x0a0c0d0e, +	0x848, 0xffffffff, 0x02040608, +	0x84c, 0xffffffff, 0x0a0c0d0e, +	0x868, 0xffffffff, 0x02040608, +	0xe00, 0xffffffff, 0x00000000, +	0xe04, 0xffffffff, 0x00000000, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x00000000, +	0xe14, 0xffffffff, 0x00000000, +	0xe18, 0xffffffff, 0x00000000, +	0xe1c, 0xffffffff, 0x00000000, +	0x830, 0xffffffff, 0x00000000, +	0x834, 0xffffffff, 0x00000000, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x00000000, +	0x848, 0xffffffff, 0x00000000, +	0x84c, 0xffffffff, 0x00000000, +	0x868, 0xffffffff, 0x00000000, +	0xe00, 0xffffffff, 0x04040404, +	0xe04, 0xffffffff, 0x00020204, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x06060606, +	0xe14, 0xffffffff, 0x00020406, +	0xe18, 0xffffffff, 0x06060606, +	0xe1c, 0xffffffff, 0x00020406, +	0x830, 0xffffffff, 0x04040404, +	0x834, 0xffffffff, 0x00020204, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x06060606, +	0x848, 0xffffffff, 0x00020406, +	0x84c, 0xffffffff, 0x06060606, +	0x868, 0xffffffff, 0x00020406, +	0xe00, 0xffffffff, 0x00000000, +	0xe04, 0xffffffff, 0x00000000, +	0xe08, 0x0000ff00, 0x00000000, +	0x86c, 0xffffff00, 0x00000000, +	0xe10, 0xffffffff, 0x00000000, +	0xe14, 0xffffffff, 0x00000000, +	0xe18, 0xffffffff, 0x00000000, +	0xe1c, 0xffffffff, 0x00000000, +	0x830, 0xffffffff, 0x00000000, +	0x834, 0xffffffff, 0x00000000, +	0x838, 0xffffff00, 0x00000000, +	0x86c, 0x000000ff, 0x00000000, +	0x83c, 0xffffffff, 0x00000000, +	0x848, 0xffffffff, 0x00000000, +	0x84c, 0xffffffff, 0x00000000, +	0x868, 0xffffffff, 0x00000000, +}; + +u32 RTL8192CERADIOA_2TARRAY[RADIOA_2TARRAYLENGTH] = { +	0x000, 0x00030159, +	0x001, 0x00031284, +	0x002, 0x00098000, +	0x003, 0x00018c63, +	0x004, 0x000210e7, +	0x009, 0x0002044f, +	0x00a, 0x0001adb0, +	0x00b, 0x00054867, +	0x00c, 0x0008992e, +	0x00d, 0x0000e52c, +	0x00e, 0x00039ce7, +	0x00f, 0x00000451, +	0x019, 0x00000000, +	0x01a, 0x00010255, +	0x01b, 0x00060a00, +	0x01c, 0x000fc378, +	0x01d, 0x000a1250, +	0x01e, 0x0004445f, +	0x01f, 0x00080001, +	0x020, 0x0000b614, +	0x021, 0x0006c000, +	0x022, 0x00000000, +	0x023, 0x00001558, +	0x024, 0x00000060, +	0x025, 0x00000483, +	0x026, 0x0004f000, +	0x027, 0x000ec7d9, +	0x028, 0x000977c0, +	0x029, 0x00004783, +	0x02a, 0x00000001, +	0x02b, 0x00021334, +	0x02a, 0x00000000, +	0x02b, 0x00000054, +	0x02a, 0x00000001, +	0x02b, 0x00000808, +	0x02b, 0x00053333, +	0x02c, 0x0000000c, +	0x02a, 0x00000002, +	0x02b, 0x00000808, +	0x02b, 0x0005b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000003, +	0x02b, 0x00000808, +	0x02b, 0x00063333, +	0x02c, 0x0000000d, +	0x02a, 0x00000004, +	0x02b, 0x00000808, +	0x02b, 0x0006b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000005, +	0x02b, 0x00000808, +	0x02b, 0x00073333, +	0x02c, 0x0000000d, +	0x02a, 0x00000006, +	0x02b, 0x00000709, +	0x02b, 0x0005b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000007, +	0x02b, 0x00000709, +	0x02b, 0x00063333, +	0x02c, 0x0000000d, +	0x02a, 0x00000008, +	0x02b, 0x0000060a, +	0x02b, 0x0004b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000009, +	0x02b, 0x0000060a, +	0x02b, 0x00053333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000a, +	0x02b, 0x0000060a, +	0x02b, 0x0005b333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000b, +	0x02b, 0x0000060a, +	0x02b, 0x00063333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000c, +	0x02b, 0x0000060a, +	0x02b, 0x0006b333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000d, +	0x02b, 0x0000060a, +	0x02b, 0x00073333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000e, +	0x02b, 0x0000050b, +	0x02b, 0x00066666, +	0x02c, 0x0000001a, +	0x02a, 0x000e0000, +	0x010, 0x0004000f, +	0x011, 0x000e31fc, +	0x010, 0x0006000f, +	0x011, 0x000ff9f8, +	0x010, 0x0002000f, +	0x011, 0x000203f9, +	0x010, 0x0003000f, +	0x011, 0x000ff500, +	0x010, 0x00000000, +	0x011, 0x00000000, +	0x010, 0x0008000f, +	0x011, 0x0003f100, +	0x010, 0x0009000f, +	0x011, 0x00023100, +	0x012, 0x00032000, +	0x012, 0x00071000, +	0x012, 0x000b0000, +	0x012, 0x000fc000, +	0x013, 0x000287af, +	0x013, 0x000244b7, +	0x013, 0x000204ab, +	0x013, 0x0001c49f, +	0x013, 0x00018493, +	0x013, 0x00014297, +	0x013, 0x00010295, +	0x013, 0x0000c298, +	0x013, 0x0000819c, +	0x013, 0x000040a8, +	0x013, 0x0000001c, +	0x014, 0x0001944c, +	0x014, 0x00059444, +	0x014, 0x0009944c, +	0x014, 0x000d9444, +	0x015, 0x0000f424, +	0x015, 0x0004f424, +	0x015, 0x0008f424, +	0x015, 0x000cf424, +	0x016, 0x000e0330, +	0x016, 0x000a0330, +	0x016, 0x00060330, +	0x016, 0x00020330, +	0x000, 0x00010159, +	0x018, 0x0000f401, +	0x0fe, 0x00000000, +	0x0fe, 0x00000000, +	0x01f, 0x00080003, +	0x0fe, 0x00000000, +	0x0fe, 0x00000000, +	0x01e, 0x00044457, +	0x01f, 0x00080000, +	0x000, 0x00030159, +}; + +u32 RTL8192CE_RADIOB_2TARRAY[RADIOB_2TARRAYLENGTH] = { +	0x000, 0x00030159, +	0x001, 0x00031284, +	0x002, 0x00098000, +	0x003, 0x00018c63, +	0x004, 0x000210e7, +	0x009, 0x0002044f, +	0x00a, 0x0001adb0, +	0x00b, 0x00054867, +	0x00c, 0x0008992e, +	0x00d, 0x0000e52c, +	0x00e, 0x00039ce7, +	0x00f, 0x00000451, +	0x012, 0x00032000, +	0x012, 0x00071000, +	0x012, 0x000b0000, +	0x012, 0x000fc000, +	0x013, 0x000287af, +	0x013, 0x000244b7, +	0x013, 0x000204ab, +	0x013, 0x0001c49f, +	0x013, 0x00018493, +	0x013, 0x00014297, +	0x013, 0x00010295, +	0x013, 0x0000c298, +	0x013, 0x0000819c, +	0x013, 0x000040a8, +	0x013, 0x0000001c, +	0x014, 0x0001944c, +	0x014, 0x00059444, +	0x014, 0x0009944c, +	0x014, 0x000d9444, +	0x015, 0x0000f424, +	0x015, 0x0004f424, +	0x015, 0x0008f424, +	0x015, 0x000cf424, +	0x016, 0x000e0330, +	0x016, 0x000a0330, +	0x016, 0x00060330, +	0x016, 0x00020330, +}; + +u32 RTL8192CE_RADIOA_1TARRAY[RADIOA_1TARRAYLENGTH] = { +	0x000, 0x00030159, +	0x001, 0x00031284, +	0x002, 0x00098000, +	0x003, 0x00018c63, +	0x004, 0x000210e7, +	0x009, 0x0002044f, +	0x00a, 0x0001adb0, +	0x00b, 0x00054867, +	0x00c, 0x0008992e, +	0x00d, 0x0000e52c, +	0x00e, 0x00039ce7, +	0x00f, 0x00000451, +	0x019, 0x00000000, +	0x01a, 0x00010255, +	0x01b, 0x00060a00, +	0x01c, 0x000fc378, +	0x01d, 0x000a1250, +	0x01e, 0x0004445f, +	0x01f, 0x00080001, +	0x020, 0x0000b614, +	0x021, 0x0006c000, +	0x022, 0x00000000, +	0x023, 0x00001558, +	0x024, 0x00000060, +	0x025, 0x00000483, +	0x026, 0x0004f000, +	0x027, 0x000ec7d9, +	0x028, 0x000977c0, +	0x029, 0x00004783, +	0x02a, 0x00000001, +	0x02b, 0x00021334, +	0x02a, 0x00000000, +	0x02b, 0x00000054, +	0x02a, 0x00000001, +	0x02b, 0x00000808, +	0x02b, 0x00053333, +	0x02c, 0x0000000c, +	0x02a, 0x00000002, +	0x02b, 0x00000808, +	0x02b, 0x0005b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000003, +	0x02b, 0x00000808, +	0x02b, 0x00063333, +	0x02c, 0x0000000d, +	0x02a, 0x00000004, +	0x02b, 0x00000808, +	0x02b, 0x0006b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000005, +	0x02b, 0x00000808, +	0x02b, 0x00073333, +	0x02c, 0x0000000d, +	0x02a, 0x00000006, +	0x02b, 0x00000709, +	0x02b, 0x0005b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000007, +	0x02b, 0x00000709, +	0x02b, 0x00063333, +	0x02c, 0x0000000d, +	0x02a, 0x00000008, +	0x02b, 0x0000060a, +	0x02b, 0x0004b333, +	0x02c, 0x0000000d, +	0x02a, 0x00000009, +	0x02b, 0x0000060a, +	0x02b, 0x00053333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000a, +	0x02b, 0x0000060a, +	0x02b, 0x0005b333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000b, +	0x02b, 0x0000060a, +	0x02b, 0x00063333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000c, +	0x02b, 0x0000060a, +	0x02b, 0x0006b333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000d, +	0x02b, 0x0000060a, +	0x02b, 0x00073333, +	0x02c, 0x0000000d, +	0x02a, 0x0000000e, +	0x02b, 0x0000050b, +	0x02b, 0x00066666, +	0x02c, 0x0000001a, +	0x02a, 0x000e0000, +	0x010, 0x0004000f, +	0x011, 0x000e31fc, +	0x010, 0x0006000f, +	0x011, 0x000ff9f8, +	0x010, 0x0002000f, +	0x011, 0x000203f9, +	0x010, 0x0003000f, +	0x011, 0x000ff500, +	0x010, 0x00000000, +	0x011, 0x00000000, +	0x010, 0x0008000f, +	0x011, 0x0003f100, +	0x010, 0x0009000f, +	0x011, 0x00023100, +	0x012, 0x00032000, +	0x012, 0x00071000, +	0x012, 0x000b0000, +	0x012, 0x000fc000, +	0x013, 0x000287af, +	0x013, 0x000244b7, +	0x013, 0x000204ab, +	0x013, 0x0001c49f, +	0x013, 0x00018493, +	0x013, 0x00014297, +	0x013, 0x00010295, +	0x013, 0x0000c298, +	0x013, 0x0000819c, +	0x013, 0x000040a8, +	0x013, 0x0000001c, +	0x014, 0x0001944c, +	0x014, 0x00059444, +	0x014, 0x0009944c, +	0x014, 0x000d9444, +	0x015, 0x0000f424, +	0x015, 0x0004f424, +	0x015, 0x0008f424, +	0x015, 0x000cf424, +	0x016, 0x000e0330, +	0x016, 0x000a0330, +	0x016, 0x00060330, +	0x016, 0x00020330, +	0x000, 0x00010159, +	0x018, 0x0000f401, +	0x0fe, 0x00000000, +	0x0fe, 0x00000000, +	0x01f, 0x00080003, +	0x0fe, 0x00000000, +	0x0fe, 0x00000000, +	0x01e, 0x00044457, +	0x01f, 0x00080000, +	0x000, 0x00030159, +}; + +u32 RTL8192CE_RADIOB_1TARRAY[RADIOB_1TARRAYLENGTH] = { +	0x0, +}; + +u32 RTL8192CEMAC_2T_ARRAY[MAC_2T_ARRAYLENGTH] = { +	0x420, 0x00000080, +	0x423, 0x00000000, +	0x430, 0x00000000, +	0x431, 0x00000000, +	0x432, 0x00000000, +	0x433, 0x00000001, +	0x434, 0x00000004, +	0x435, 0x00000005, +	0x436, 0x00000006, +	0x437, 0x00000007, +	0x438, 0x00000000, +	0x439, 0x00000000, +	0x43a, 0x00000000, +	0x43b, 0x00000001, +	0x43c, 0x00000004, +	0x43d, 0x00000005, +	0x43e, 0x00000006, +	0x43f, 0x00000007, +	0x440, 0x0000005d, +	0x441, 0x00000001, +	0x442, 0x00000000, +	0x444, 0x00000015, +	0x445, 0x000000f0, +	0x446, 0x0000000f, +	0x447, 0x00000000, +	0x458, 0x00000041, +	0x459, 0x000000a8, +	0x45a, 0x00000072, +	0x45b, 0x000000b9, +	0x460, 0x00000088, +	0x461, 0x00000088, +	0x462, 0x00000006, +	0x463, 0x00000003, +	0x4c8, 0x00000004, +	0x4c9, 0x00000008, +	0x4cc, 0x00000002, +	0x4cd, 0x00000028, +	0x4ce, 0x00000001, +	0x500, 0x00000026, +	0x501, 0x000000a2, +	0x502, 0x0000002f, +	0x503, 0x00000000, +	0x504, 0x00000028, +	0x505, 0x000000a3, +	0x506, 0x0000005e, +	0x507, 0x00000000, +	0x508, 0x0000002b, +	0x509, 0x000000a4, +	0x50a, 0x0000005e, +	0x50b, 0x00000000, +	0x50c, 0x0000004f, +	0x50d, 0x000000a4, +	0x50e, 0x00000000, +	0x50f, 0x00000000, +	0x512, 0x0000001c, +	0x514, 0x0000000a, +	0x515, 0x00000010, +	0x516, 0x0000000a, +	0x517, 0x00000010, +	0x51a, 0x00000016, +	0x524, 0x0000000f, +	0x525, 0x0000004f, +	0x546, 0x00000020, +	0x547, 0x00000000, +	0x559, 0x00000002, +	0x55a, 0x00000002, +	0x55d, 0x000000ff, +	0x605, 0x00000030, +	0x608, 0x0000000e, +	0x609, 0x0000002a, +	0x652, 0x00000020, +	0x63c, 0x0000000a, +	0x63d, 0x0000000a, +	0x700, 0x00000021, +	0x701, 0x00000043, +	0x702, 0x00000065, +	0x703, 0x00000087, +	0x708, 0x00000021, +	0x709, 0x00000043, +	0x70a, 0x00000065, +	0x70b, 0x00000087, +}; + +u32 RTL8192CEAGCTAB_2TARRAY[AGCTAB_2TARRAYLENGTH] = { +	0xc78, 0x7b000001, +	0xc78, 0x7b010001, +	0xc78, 0x7b020001, +	0xc78, 0x7b030001, +	0xc78, 0x7b040001, +	0xc78, 0x7b050001, +	0xc78, 0x7a060001, +	0xc78, 0x79070001, +	0xc78, 0x78080001, +	0xc78, 0x77090001, +	0xc78, 0x760a0001, +	0xc78, 0x750b0001, +	0xc78, 0x740c0001, +	0xc78, 0x730d0001, +	0xc78, 0x720e0001, +	0xc78, 0x710f0001, +	0xc78, 0x70100001, +	0xc78, 0x6f110001, +	0xc78, 0x6e120001, +	0xc78, 0x6d130001, +	0xc78, 0x6c140001, +	0xc78, 0x6b150001, +	0xc78, 0x6a160001, +	0xc78, 0x69170001, +	0xc78, 0x68180001, +	0xc78, 0x67190001, +	0xc78, 0x661a0001, +	0xc78, 0x651b0001, +	0xc78, 0x641c0001, +	0xc78, 0x631d0001, +	0xc78, 0x621e0001, +	0xc78, 0x611f0001, +	0xc78, 0x60200001, +	0xc78, 0x49210001, +	0xc78, 0x48220001, +	0xc78, 0x47230001, +	0xc78, 0x46240001, +	0xc78, 0x45250001, +	0xc78, 0x44260001, +	0xc78, 0x43270001, +	0xc78, 0x42280001, +	0xc78, 0x41290001, +	0xc78, 0x402a0001, +	0xc78, 0x262b0001, +	0xc78, 0x252c0001, +	0xc78, 0x242d0001, +	0xc78, 0x232e0001, +	0xc78, 0x222f0001, +	0xc78, 0x21300001, +	0xc78, 0x20310001, +	0xc78, 0x06320001, +	0xc78, 0x05330001, +	0xc78, 0x04340001, +	0xc78, 0x03350001, +	0xc78, 0x02360001, +	0xc78, 0x01370001, +	0xc78, 0x00380001, +	0xc78, 0x00390001, +	0xc78, 0x003a0001, +	0xc78, 0x003b0001, +	0xc78, 0x003c0001, +	0xc78, 0x003d0001, +	0xc78, 0x003e0001, +	0xc78, 0x003f0001, +	0xc78, 0x7b400001, +	0xc78, 0x7b410001, +	0xc78, 0x7b420001, +	0xc78, 0x7b430001, +	0xc78, 0x7b440001, +	0xc78, 0x7b450001, +	0xc78, 0x7a460001, +	0xc78, 0x79470001, +	0xc78, 0x78480001, +	0xc78, 0x77490001, +	0xc78, 0x764a0001, +	0xc78, 0x754b0001, +	0xc78, 0x744c0001, +	0xc78, 0x734d0001, +	0xc78, 0x724e0001, +	0xc78, 0x714f0001, +	0xc78, 0x70500001, +	0xc78, 0x6f510001, +	0xc78, 0x6e520001, +	0xc78, 0x6d530001, +	0xc78, 0x6c540001, +	0xc78, 0x6b550001, +	0xc78, 0x6a560001, +	0xc78, 0x69570001, +	0xc78, 0x68580001, +	0xc78, 0x67590001, +	0xc78, 0x665a0001, +	0xc78, 0x655b0001, +	0xc78, 0x645c0001, +	0xc78, 0x635d0001, +	0xc78, 0x625e0001, +	0xc78, 0x615f0001, +	0xc78, 0x60600001, +	0xc78, 0x49610001, +	0xc78, 0x48620001, +	0xc78, 0x47630001, +	0xc78, 0x46640001, +	0xc78, 0x45650001, +	0xc78, 0x44660001, +	0xc78, 0x43670001, +	0xc78, 0x42680001, +	0xc78, 0x41690001, +	0xc78, 0x406a0001, +	0xc78, 0x266b0001, +	0xc78, 0x256c0001, +	0xc78, 0x246d0001, +	0xc78, 0x236e0001, +	0xc78, 0x226f0001, +	0xc78, 0x21700001, +	0xc78, 0x20710001, +	0xc78, 0x06720001, +	0xc78, 0x05730001, +	0xc78, 0x04740001, +	0xc78, 0x03750001, +	0xc78, 0x02760001, +	0xc78, 0x01770001, +	0xc78, 0x00780001, +	0xc78, 0x00790001, +	0xc78, 0x007a0001, +	0xc78, 0x007b0001, +	0xc78, 0x007c0001, +	0xc78, 0x007d0001, +	0xc78, 0x007e0001, +	0xc78, 0x007f0001, +	0xc78, 0x3800001e, +	0xc78, 0x3801001e, +	0xc78, 0x3802001e, +	0xc78, 0x3803001e, +	0xc78, 0x3804001e, +	0xc78, 0x3805001e, +	0xc78, 0x3806001e, +	0xc78, 0x3807001e, +	0xc78, 0x3808001e, +	0xc78, 0x3c09001e, +	0xc78, 0x3e0a001e, +	0xc78, 0x400b001e, +	0xc78, 0x440c001e, +	0xc78, 0x480d001e, +	0xc78, 0x4c0e001e, +	0xc78, 0x500f001e, +	0xc78, 0x5210001e, +	0xc78, 0x5611001e, +	0xc78, 0x5a12001e, +	0xc78, 0x5e13001e, +	0xc78, 0x6014001e, +	0xc78, 0x6015001e, +	0xc78, 0x6016001e, +	0xc78, 0x6217001e, +	0xc78, 0x6218001e, +	0xc78, 0x6219001e, +	0xc78, 0x621a001e, +	0xc78, 0x621b001e, +	0xc78, 0x621c001e, +	0xc78, 0x621d001e, +	0xc78, 0x621e001e, +	0xc78, 0x621f001e, +}; + +u32 RTL8192CEAGCTAB_1TARRAY[AGCTAB_1TARRAYLENGTH] = { +	0xc78, 0x7b000001, +	0xc78, 0x7b010001, +	0xc78, 0x7b020001, +	0xc78, 0x7b030001, +	0xc78, 0x7b040001, +	0xc78, 0x7b050001, +	0xc78, 0x7a060001, +	0xc78, 0x79070001, +	0xc78, 0x78080001, +	0xc78, 0x77090001, +	0xc78, 0x760a0001, +	0xc78, 0x750b0001, +	0xc78, 0x740c0001, +	0xc78, 0x730d0001, +	0xc78, 0x720e0001, +	0xc78, 0x710f0001, +	0xc78, 0x70100001, +	0xc78, 0x6f110001, +	0xc78, 0x6e120001, +	0xc78, 0x6d130001, +	0xc78, 0x6c140001, +	0xc78, 0x6b150001, +	0xc78, 0x6a160001, +	0xc78, 0x69170001, +	0xc78, 0x68180001, +	0xc78, 0x67190001, +	0xc78, 0x661a0001, +	0xc78, 0x651b0001, +	0xc78, 0x641c0001, +	0xc78, 0x631d0001, +	0xc78, 0x621e0001, +	0xc78, 0x611f0001, +	0xc78, 0x60200001, +	0xc78, 0x49210001, +	0xc78, 0x48220001, +	0xc78, 0x47230001, +	0xc78, 0x46240001, +	0xc78, 0x45250001, +	0xc78, 0x44260001, +	0xc78, 0x43270001, +	0xc78, 0x42280001, +	0xc78, 0x41290001, +	0xc78, 0x402a0001, +	0xc78, 0x262b0001, +	0xc78, 0x252c0001, +	0xc78, 0x242d0001, +	0xc78, 0x232e0001, +	0xc78, 0x222f0001, +	0xc78, 0x21300001, +	0xc78, 0x20310001, +	0xc78, 0x06320001, +	0xc78, 0x05330001, +	0xc78, 0x04340001, +	0xc78, 0x03350001, +	0xc78, 0x02360001, +	0xc78, 0x01370001, +	0xc78, 0x00380001, +	0xc78, 0x00390001, +	0xc78, 0x003a0001, +	0xc78, 0x003b0001, +	0xc78, 0x003c0001, +	0xc78, 0x003d0001, +	0xc78, 0x003e0001, +	0xc78, 0x003f0001, +	0xc78, 0x7b400001, +	0xc78, 0x7b410001, +	0xc78, 0x7b420001, +	0xc78, 0x7b430001, +	0xc78, 0x7b440001, +	0xc78, 0x7b450001, +	0xc78, 0x7a460001, +	0xc78, 0x79470001, +	0xc78, 0x78480001, +	0xc78, 0x77490001, +	0xc78, 0x764a0001, +	0xc78, 0x754b0001, +	0xc78, 0x744c0001, +	0xc78, 0x734d0001, +	0xc78, 0x724e0001, +	0xc78, 0x714f0001, +	0xc78, 0x70500001, +	0xc78, 0x6f510001, +	0xc78, 0x6e520001, +	0xc78, 0x6d530001, +	0xc78, 0x6c540001, +	0xc78, 0x6b550001, +	0xc78, 0x6a560001, +	0xc78, 0x69570001, +	0xc78, 0x68580001, +	0xc78, 0x67590001, +	0xc78, 0x665a0001, +	0xc78, 0x655b0001, +	0xc78, 0x645c0001, +	0xc78, 0x635d0001, +	0xc78, 0x625e0001, +	0xc78, 0x615f0001, +	0xc78, 0x60600001, +	0xc78, 0x49610001, +	0xc78, 0x48620001, +	0xc78, 0x47630001, +	0xc78, 0x46640001, +	0xc78, 0x45650001, +	0xc78, 0x44660001, +	0xc78, 0x43670001, +	0xc78, 0x42680001, +	0xc78, 0x41690001, +	0xc78, 0x406a0001, +	0xc78, 0x266b0001, +	0xc78, 0x256c0001, +	0xc78, 0x246d0001, +	0xc78, 0x236e0001, +	0xc78, 0x226f0001, +	0xc78, 0x21700001, +	0xc78, 0x20710001, +	0xc78, 0x06720001, +	0xc78, 0x05730001, +	0xc78, 0x04740001, +	0xc78, 0x03750001, +	0xc78, 0x02760001, +	0xc78, 0x01770001, +	0xc78, 0x00780001, +	0xc78, 0x00790001, +	0xc78, 0x007a0001, +	0xc78, 0x007b0001, +	0xc78, 0x007c0001, +	0xc78, 0x007d0001, +	0xc78, 0x007e0001, +	0xc78, 0x007f0001, +	0xc78, 0x3800001e, +	0xc78, 0x3801001e, +	0xc78, 0x3802001e, +	0xc78, 0x3803001e, +	0xc78, 0x3804001e, +	0xc78, 0x3805001e, +	0xc78, 0x3806001e, +	0xc78, 0x3807001e, +	0xc78, 0x3808001e, +	0xc78, 0x3c09001e, +	0xc78, 0x3e0a001e, +	0xc78, 0x400b001e, +	0xc78, 0x440c001e, +	0xc78, 0x480d001e, +	0xc78, 0x4c0e001e, +	0xc78, 0x500f001e, +	0xc78, 0x5210001e, +	0xc78, 0x5611001e, +	0xc78, 0x5a12001e, +	0xc78, 0x5e13001e, +	0xc78, 0x6014001e, +	0xc78, 0x6015001e, +	0xc78, 0x6016001e, +	0xc78, 0x6217001e, +	0xc78, 0x6218001e, +	0xc78, 0x6219001e, +	0xc78, 0x621a001e, +	0xc78, 0x621b001e, +	0xc78, 0x621c001e, +	0xc78, 0x621d001e, +	0xc78, 0x621e001e, +	0xc78, 0x621f001e, +}; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-table.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-table.h new file mode 100644 index 00000000000..3a6e8b6aeee --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-table.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on  2010/ 5/18,  1:41 + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92CE_TABLE__H_ +#define __RTL92CE_TABLE__H_ + +#include <linux/types.h> + +#define PHY_REG_2TARRAY_LENGTH	374 +extern u32 RTL8192CEPHY_REG_2TARRAY[PHY_REG_2TARRAY_LENGTH]; +#define PHY_REG_1TARRAY_LENGTH	374 +extern u32 RTL8192CEPHY_REG_1TARRAY[PHY_REG_1TARRAY_LENGTH]; +#define PHY_REG_ARRAY_PGLENGTH	192 +extern u32 RTL8192CEPHY_REG_ARRAY_PG[PHY_REG_ARRAY_PGLENGTH]; +#define RADIOA_2TARRAYLENGTH	282 +extern u32 RTL8192CERADIOA_2TARRAY[RADIOA_2TARRAYLENGTH]; +#define RADIOB_2TARRAYLENGTH	78 +extern u32 RTL8192CE_RADIOB_2TARRAY[RADIOB_2TARRAYLENGTH]; +#define RADIOA_1TARRAYLENGTH	282 +extern u32 RTL8192CE_RADIOA_1TARRAY[RADIOA_1TARRAYLENGTH]; +#define RADIOB_1TARRAYLENGTH	1 +extern u32 RTL8192CE_RADIOB_1TARRAY[RADIOB_1TARRAYLENGTH]; +#define MAC_2T_ARRAYLENGTH	162 +extern u32 RTL8192CEMAC_2T_ARRAY[MAC_2T_ARRAYLENGTH]; +#define AGCTAB_2TARRAYLENGTH	320 +extern u32 RTL8192CEAGCTAB_2TARRAY[AGCTAB_2TARRAYLENGTH]; +#define AGCTAB_1TARRAYLENGTH	320 +extern u32 RTL8192CEAGCTAB_1TARRAY[AGCTAB_1TARRAYLENGTH]; + +#endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-trx.c new file mode 100644 index 00000000000..cf35418c8af --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-trx.c @@ -0,0 +1,1031 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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 "../pci.h" +#include "../base.h" +#include "rtl8192c-reg.h" +#include "rtl8192c-def.h" +#include "rtl8192c-phy.h" +#include "rtl8192c-trx.h" +#include "rtl8192c-led.h" + +static enum rtl_desc_qsel _rtl92ce_map_hwqueue_to_fwqueue(u16 fc, +							  unsigned int +							  skb_queue) +{ +	enum rtl_desc_qsel qsel; + +	if (unlikely(ieee80211_is_beacon(fc))) { +		qsel = QSLT_BEACON; +		return qsel; +	} + +	if (ieee80211_is_mgmt(fc)) { +		qsel = QSLT_MGNT; +		return qsel; +	} + +	switch (skb_queue) { +	case VO_QUEUE: +		qsel = QSLT_VO; +		break; +	case VI_QUEUE: +		qsel = QSLT_VI; +		break; +	case BE_QUEUE: +		qsel = QSLT_BE; +		break; +	case BK_QUEUE: +		qsel = QSLT_BK; +		break; +	default: +		qsel = QSLT_BE; +		RT_ASSERT(false, ("BE queue, skb_queue:%d," +				  " set qsel = 0x%X\n", skb_queue, QSLT_BE)); +		break; +	} +	return qsel; +} + +static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) +{ +	int rate_idx; + +	if (first_ampdu) { +		if (false == isht) { +			switch (desc_rate) { +			case DESC92C_RATE1M: +				rate_idx = 0; +				break; +			case DESC92C_RATE2M: +				rate_idx = 1; +				break; +			case DESC92C_RATE5_5M: +				rate_idx = 2; +				break; +			case DESC92C_RATE11M: +				rate_idx = 3; +				break; +			case DESC92C_RATE6M: +				rate_idx = 4; +				break; +			case DESC92C_RATE9M: +				rate_idx = 5; +				break; +			case DESC92C_RATE12M: +				rate_idx = 6; +				break; +			case DESC92C_RATE18M: +				rate_idx = 7; +				break; +			case DESC92C_RATE24M: +				rate_idx = 8; +				break; +			case DESC92C_RATE36M: +				rate_idx = 9; +				break; +			case DESC92C_RATE48M: +				rate_idx = 10; +				break; +			case DESC92C_RATE54M: +				rate_idx = 11; +				break; +			default: +				rate_idx = 0; +				break; +			} +		} else { +			rate_idx = 11; +		} + +		return rate_idx; +	} + +	switch (desc_rate) { +	case DESC92C_RATE1M: +		rate_idx = 0; +		break; +	case DESC92C_RATE2M: +		rate_idx = 1; +		break; +	case DESC92C_RATE5_5M: +		rate_idx = 2; +		break; +	case DESC92C_RATE11M: +		rate_idx = 3; +		break; +	case DESC92C_RATE6M: +		rate_idx = 4; +		break; +	case DESC92C_RATE9M: +		rate_idx = 5; +		break; +	case DESC92C_RATE12M: +		rate_idx = 6; +		break; +	case DESC92C_RATE18M: +		rate_idx = 7; +		break; +	case DESC92C_RATE24M: +		rate_idx = 8; +		break; +	case DESC92C_RATE36M: +		rate_idx = 9; +		break; +	case DESC92C_RATE48M: +		rate_idx = 10; +		break; +	case DESC92C_RATE54M: +		rate_idx = 11; +		break; +	default: +		rate_idx = 11; +		break; +	} +	return rate_idx; +} + +static u8 _rtl92c_query_rxpwrpercentage(char antpower) +{ +	if ((antpower <= -100) || (antpower >= 20)) +		return 0; +	else if (antpower >= 0) +		return 100; +	else +		return 100 + antpower; +} + +static u8 _rtl92c_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; +} + +static long _rtl92ce_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; +} + +static long _rtl92ce_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; +} + +static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, +				       struct rtl_stats *pstats, +				       struct rx_desc_92c *pdesc, +				       struct rx_fwinfo_92c *p_drvinfo, +				       bool bpacket_match_bssid, +				       bool bpacket_toself, +				       bool b_packet_beacon) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct phy_sts_cck_8192s_t *cck_buf; +	s8 rx_pwr_all, rx_pwr[4]; +	u8 rf_rx_num, evm, pwdb_all; +	u8 i, max_spatial_stream; +	u32 rssi, total_rssi; +	bool is_cck_rate; + +	is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); +	pstats->b_packet_matchbssid = bpacket_match_bssid; +	pstats->b_packet_toself = bpacket_toself; +	pstats->b_is_cck = is_cck_rate; +	pstats->b_packet_beacon = b_packet_beacon; +	pstats->b_is_cck = is_cck_rate; +	pstats->rx_mimo_signalquality[0] = -1; +	pstats->rx_mimo_signalquality[1] = -1; + +	if (is_cck_rate) { +		u8 report, cck_highpwr; +		cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; + +		cck_highpwr = (u8) rtl_get_bbreg(hw, +					 RFPGA0_XA_HSSIPARAMETER2, +					 BIT(9)); +		if (!cck_highpwr) { +			u8 cck_agc_rpt = cck_buf->cck_agc_rpt; +			report = cck_buf->cck_agc_rpt & 0xc0; +			report = report >> 6; +			switch (report) { +			case 0x3: +				rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); +				break; +			case 0x2: +				rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); +				break; +			case 0x1: +				rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); +				break; +			case 0x0: +				rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); +				break; +			} +		} else { +			u8 cck_agc_rpt = cck_buf->cck_agc_rpt; +			report = p_drvinfo->cfosho[0] & 0x60; +			report = report >> 5; +			switch (report) { +			case 0x3: +				rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1); +				break; +			case 0x2: +				rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1); +				break; +			case 0x1: +				rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1); +				break; +			case 0x0: +				rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1); +				break; +			} +		} + +		pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all); +		pstats->rx_pwdb_all = pwdb_all; +		pstats->recvsignalpower = rx_pwr_all; + +		if (bpacket_match_bssid) { +			u8 sq; +			if (pstats->rx_pwdb_all > 40) +				sq = 100; +			else { +				sq = cck_buf->sq_rpt; +				if (sq > 64) +					sq = 0; +				else if (sq < 20) +					sq = 100; +				else +					sq = ((64 - sq) * 100) / 44; +			} + +			pstats->signalquality = sq; +			pstats->rx_mimo_signalquality[0] = sq; +			pstats->rx_mimo_signalquality[1] = -1; +		} +	} else { +		rtlpriv->dm.brfpath_rxenable[0] = +		    rtlpriv->dm.brfpath_rxenable[1] = true; +		for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { +			if (rtlpriv->dm.brfpath_rxenable[i]) +				rf_rx_num++; + +			rx_pwr[i] = +			    ((p_drvinfo->gain_trsw[i] & 0x3f) * 2) - 110; +			rssi = _rtl92c_query_rxpwrpercentage(rx_pwr[i]); +			total_rssi += rssi; +			rtlpriv->stats.rx_snr_db[i] = +			    (long)(p_drvinfo->rxsnr[i] / 2); + +			if (bpacket_match_bssid) +				pstats->rx_mimo_signalstrength[i] = (u8) rssi; +		} + +		rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; +		pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all); +		pstats->rx_pwdb_all = pwdb_all; +		pstats->rxpower = rx_pwr_all; +		pstats->recvsignalpower = rx_pwr_all; + +		if (pdesc->rxht && pdesc->rxmcs >= DESC92C_RATEMCS8 && +		    pdesc->rxmcs <= DESC92C_RATEMCS15) +			max_spatial_stream = 2; +		else +			max_spatial_stream = 1; + +		for (i = 0; i < max_spatial_stream; i++) { +			evm = _rtl92c_evm_db_to_percentage(p_drvinfo->rxevm[i]); + +			if (bpacket_match_bssid) { +				if (i == 0) +					pstats->signalquality = +					    (u8) (evm & 0xff); +				pstats->rx_mimo_signalquality[i] = +				    (u8) (evm & 0xff); +			} +		} +	} + +	if (is_cck_rate) +		pstats->signalstrength = +		    (u8) (_rtl92ce_signal_scale_mapping(hw, pwdb_all)); +	else if (rf_rx_num != 0) +		pstats->signalstrength = +		    (u8) (_rtl92ce_signal_scale_mapping +			  (hw, total_rssi /= rf_rx_num)); +} + +static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw, +		struct rtl_stats *pstats) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_phy *rtlphy = &(rtlpriv->phy); +	u8 rfpath; +	u32 last_rssi, tmpval; + +	if (pstats->b_packet_toself || pstats->b_packet_beacon) { +		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 += pstats->signalstrength; +		rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi. +						index++] = +		    pstats->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 = +		    _rtl92ce_translate_todbm(hw, (u8) tmpval); +		pstats->rssi = rtlpriv->stats.signal_strength; +	} + +	if (!pstats->b_is_cck && pstats->b_packet_toself) { +		for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; +		     rfpath++) { + +			if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath)) +				continue; + +			if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { +				rtlpriv->stats.rx_rssi_percentage[rfpath] = +				    pstats->rx_mimo_signalstrength[rfpath]; + +			} + +			if (pstats->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)) + +				     (pstats->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)) + +				     (pstats->rx_mimo_signalstrength[rfpath])) / +				    (RX_SMOOTH_FACTOR); +			} + +		} +	} +} + +static void _rtl92ce_update_rxsignalstatistics(struct ieee80211_hw *hw, +					       struct rtl_stats *pstats) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	int weighting; + +	if (rtlpriv->stats.recv_signal_power == 0) +		rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; + +	if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) +		weighting = 5; + +	else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) +		weighting = (-5); + +	rtlpriv->stats.recv_signal_power = +	    (rtlpriv->stats.recv_signal_power * 5 + +	     pstats->recvsignalpower + weighting) / 6; +} + +static void _rtl92ce_process_pwdb(struct ieee80211_hw *hw, +		struct rtl_stats *pstats) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	long undecorated_smoothed_pwdb; + +	if (mac->opmode == NL80211_IFTYPE_ADHOC) { +		return; +	} else { +		undecorated_smoothed_pwdb = +		    rtlpriv->dm.undecorated_smoothed_pwdb; +	} + +	if (pstats->b_packet_toself || pstats->b_packet_beacon) { +		if (undecorated_smoothed_pwdb < 0) +			undecorated_smoothed_pwdb = pstats->rx_pwdb_all; + +		if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { +			undecorated_smoothed_pwdb = +			    (((undecorated_smoothed_pwdb) * +			      (RX_SMOOTH_FACTOR - 1)) + +			     (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + +			undecorated_smoothed_pwdb = undecorated_smoothed_pwdb +			    + 1; +		} else { +			undecorated_smoothed_pwdb = +			    (((undecorated_smoothed_pwdb) * +			      (RX_SMOOTH_FACTOR - 1)) + +			     (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); +		} + +		rtlpriv->dm.undecorated_smoothed_pwdb = +		    undecorated_smoothed_pwdb; +		_rtl92ce_update_rxsignalstatistics(hw, pstats); +	} +} + +static void _rtl92ce_process_ui_link_quality(struct ieee80211_hw *hw, +					     struct rtl_stats *pstats) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	u32 last_evm, n_spatialstream, tmpval; + +	if (pstats->signalquality != 0) { +		if (pstats->b_packet_toself || pstats->b_packet_beacon) { + +			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 += +			    pstats->signalquality; +			rtlpriv->stats.ui_link_quality.elements[rtlpriv->stats. +								ui_link_quality. +								index++] = +			    pstats->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_spatialstream = 0; n_spatialstream < 2; +			     n_spatialstream++) { +				if (pstats-> +				    rx_mimo_signalquality[n_spatialstream] != +				    -1) { +					if (rtlpriv->stats. +					    rx_evm_percentage[n_spatialstream] +					    == 0) { +						rtlpriv->stats. +						   rx_evm_percentage +						   [n_spatialstream] = +						   pstats->rx_mimo_signalquality +						   [n_spatialstream]; +					} + +					rtlpriv->stats. +					    rx_evm_percentage[n_spatialstream] = +					    ((rtlpriv-> +					      stats.rx_evm_percentage +					      [n_spatialstream] * +					      (RX_SMOOTH_FACTOR - 1)) + +					     (pstats-> +					      rx_mimo_signalquality +					      [n_spatialstream] * 1)) / +					    (RX_SMOOTH_FACTOR); +				} +			} +		} +	} else { +		; +	} +} + +static void _rtl92ce_process_phyinfo(struct ieee80211_hw *hw, +				     u8 *buffer, +				     struct rtl_stats *pcurrent_stats) +{ + +	if (!pcurrent_stats->b_packet_matchbssid && +	    !pcurrent_stats->b_packet_beacon) +		return; + +	_rtl92ce_process_ui_rssi(hw, pcurrent_stats); +	_rtl92ce_process_pwdb(hw, pcurrent_stats); +	_rtl92ce_process_ui_link_quality(hw, pcurrent_stats); +} + +static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw, +					       struct sk_buff *skb, +					       struct rtl_stats *pstats, +					       struct rx_desc_92c *pdesc, +					       struct rx_fwinfo_92c *p_drvinfo) +{ +	struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); +	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + +	struct ieee80211_hdr *hdr; +	u8 *tmp_buf; +	u8 *praddr; +	u8 *psaddr; +	u16 fc, type; +	bool b_packet_matchbssid, b_packet_toself, b_packet_beacon; + +	tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; + +	hdr = (struct ieee80211_hdr *)tmp_buf; +	fc = le16_to_cpu(hdr->frame_control); +	type = WLAN_FC_GET_TYPE(fc); +	praddr = hdr->addr1; +	psaddr = hdr->addr2; + +	b_packet_matchbssid = +	    ((IEEE80211_FTYPE_CTL != type) && +	     (!compare_ether_addr(mac->bssid, +				  (fc & IEEE80211_FCTL_TODS) ? +				  hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ? +				  hdr->addr2 : hdr->addr3)) && +	     (!pstats->b_hwerror) && (!pstats->b_crc) && (!pstats->b_icv)); + +	b_packet_toself = b_packet_matchbssid && +	    (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + +	if (ieee80211_is_beacon(fc)) +		b_packet_beacon = true; + +	_rtl92ce_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, +				   b_packet_matchbssid, b_packet_toself, +				   b_packet_beacon); + +	_rtl92ce_process_phyinfo(hw, tmp_buf, pstats); +} + +bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, +			   struct rtl_stats *stats, +			   struct ieee80211_rx_status *rx_status, +			   u8 *p_desc, struct sk_buff *skb) +{ +	struct rx_fwinfo_92c *p_drvinfo; +	struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc; + +	u32 phystatus = GET_RX_DESC_PHYST(pdesc); +	stats->length = (u16) GET_RX_DESC_PKT_LEN(pdesc); +	stats->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) * +	    RX_DRV_INFO_SIZE_UNIT; +	stats->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03); +	stats->b_icv = (u16) GET_RX_DESC_ICV(pdesc); +	stats->b_crc = (u16) GET_RX_DESC_CRC32(pdesc); +	stats->b_hwerror = (stats->b_crc | stats->b_icv); +	stats->decrypted = !GET_RX_DESC_SWDEC(pdesc); +	stats->rate = (u8) GET_RX_DESC_RXMCS(pdesc); +	stats->b_shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc); +	stats->b_isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1); +	stats->b_isampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) +				   && (GET_RX_DESC_FAGGR(pdesc) == 1)); +	stats->timestamp_low = GET_RX_DESC_TSFL(pdesc); +	stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc); + +	rx_status->freq = hw->conf.channel->center_freq; +	rx_status->band = hw->conf.channel->band; + +	if (GET_RX_DESC_CRC32(pdesc)) +		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + +	if (!GET_RX_DESC_SWDEC(pdesc)) +		rx_status->flag |= RX_FLAG_DECRYPTED; + +	if (GET_RX_DESC_BW(pdesc)) +		rx_status->flag |= RX_FLAG_40MHZ; + +	if (GET_RX_DESC_RXHT(pdesc)) +		rx_status->flag |= RX_FLAG_HT; + +	rx_status->flag |= RX_FLAG_TSFT; + +	if (stats->decrypted) +		rx_status->flag |= RX_FLAG_DECRYPTED; + +	rx_status->rate_idx = _rtl92ce_rate_mapping((bool) +						    GET_RX_DESC_RXHT(pdesc), +						    (u8) +						    GET_RX_DESC_RXMCS(pdesc), +						    (bool) +						    GET_RX_DESC_PAGGR(pdesc)); + +	rx_status->mactime = GET_RX_DESC_TSFL(pdesc); +	if (phystatus == true) { +		p_drvinfo = (struct rx_fwinfo_92c *)(skb->data + +						     stats->rx_bufshift); + +		_rtl92ce_translate_rx_signal_stuff(hw, +						   skb, stats, pdesc, +						   p_drvinfo); +	} + +	/*rx_status->qual = stats->signal; */ +	rx_status->signal = stats->rssi + 10; +	/*rx_status->noise = -stats->noise; */ + +	return true; +} + +void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, +			  struct ieee80211_hdr *hdr, u8 *pdesc_tx, +			  struct ieee80211_tx_info *info, struct sk_buff *skb, +			  unsigned int queue_index) +{ +	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_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); +	bool b_defaultadapter = true; + +	struct ieee80211_sta *sta = ieee80211_find_sta(mac->vif, mac->bssid); + +	u8 *pdesc = (u8 *) pdesc_tx; +	struct rtl_tcb_desc tcb_desc; +	u8 *qc = ieee80211_get_qos_ctl(hdr); +	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; +	u16 seq_number; +	u16 fc = le16_to_cpu(hdr->frame_control); +	u8 rate_flag = info->control.rates[0].flags; + +	enum rtl_desc_qsel fw_qsel = +	    _rtl92ce_map_hwqueue_to_fwqueue(le16_to_cpu(hdr->frame_control), +					    queue_index); + +	bool b_firstseg = ((hdr->seq_ctrl & +			    cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); + +	bool b_lastseg = ((hdr->frame_control & +			   cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); + +	dma_addr_t mapping = pci_map_single(rtlpci->pdev, +					    skb->data, skb->len, +					    PCI_DMA_TODEVICE); + +	seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + +	rtl_get_tcb_desc(hw, info, skb, &tcb_desc); + +	CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c)); + +	if (b_firstseg) { +		SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + +		SET_TX_DESC_TX_RATE(pdesc, tcb_desc.hw_rate); + +		if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble) +			SET_TX_DESC_DATA_SHORTGI(pdesc, 1); + +		if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && +		    info->flags & IEEE80211_TX_CTL_AMPDU) { +			SET_TX_DESC_AGG_BREAK(pdesc, 1); +			SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); +		} +		SET_TX_DESC_SEQ(pdesc, seq_number); + +		SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc.b_rts_enable && +						!tcb_desc. +						b_cts_enable) ? 1 : 0)); +		SET_TX_DESC_HW_RTS_ENABLE(pdesc, +					  ((tcb_desc.b_rts_enable +					    || tcb_desc.b_cts_enable) ? 1 : 0)); +		SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc.b_cts_enable) ? 1 : 0)); +		SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc.b_rts_stbc) ? 1 : 0)); + +		SET_TX_DESC_RTS_RATE(pdesc, tcb_desc.rts_rate); +		SET_TX_DESC_RTS_BW(pdesc, 0); +		SET_TX_DESC_RTS_SC(pdesc, tcb_desc.rts_sc); +		SET_TX_DESC_RTS_SHORT(pdesc, +				      ((tcb_desc.rts_rate <= DESC92C_RATE54M) ? +				      (tcb_desc.b_rts_use_shortpreamble ? 1 : 0) +				      : (tcb_desc.b_rts_use_shortgi ? 1 : 0))); + +		if (mac->bw_40) { +			if (tcb_desc.b_packet_bw) { +				SET_TX_DESC_DATA_BW(pdesc, 1); +				SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); +			} else { +				SET_TX_DESC_DATA_BW(pdesc, 0); + +				if (rate_flag & IEEE80211_TX_RC_DUP_DATA) { +					SET_TX_DESC_TX_SUB_CARRIER(pdesc, +							mac->cur_40_prime_sc); +				} +			} +		} else { +			SET_TX_DESC_DATA_BW(pdesc, 0); +			SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); +		} + +		SET_TX_DESC_LINIP(pdesc, 0); +		SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); + +		if (sta) { +			u8 ampdu_density = sta->ht_cap.ampdu_density; +			SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); +		} + +		if (info->control.hw_key) { +			struct ieee80211_key_conf *keyconf = +			    info->control.hw_key; + +			switch (keyconf->cipher) { +			case WLAN_CIPHER_SUITE_WEP40: +			case WLAN_CIPHER_SUITE_WEP104: +			case WLAN_CIPHER_SUITE_TKIP: +				SET_TX_DESC_SEC_TYPE(pdesc, 0x1); +				break; +			case WLAN_CIPHER_SUITE_CCMP: +				SET_TX_DESC_SEC_TYPE(pdesc, 0x3); +				break; +			default: +				SET_TX_DESC_SEC_TYPE(pdesc, 0x0); +				break; + +			} +		} + +		SET_TX_DESC_PKT_ID(pdesc, 0); +		SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + +		SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); +		SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); +		SET_TX_DESC_DISABLE_FB(pdesc, 0); +		SET_TX_DESC_USE_RATE(pdesc, tcb_desc.use_driver_rate ? 1 : 0); + +		if (ieee80211_is_data_qos(fc)) { +			if (mac->rdg_en) { +				RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, +					 ("Enable RDG function.\n")); +				SET_TX_DESC_RDG_ENABLE(pdesc, 1); +				SET_TX_DESC_HTC(pdesc, 1); +			} +		} +	} + +	SET_TX_DESC_FIRST_SEG(pdesc, (b_firstseg ? 1 : 0)); +	SET_TX_DESC_LAST_SEG(pdesc, (b_lastseg ? 1 : 0)); + +	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); + +	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + +	if (rtlpriv->dm.b_useramask) { +		SET_TX_DESC_RATE_ID(pdesc, tcb_desc.ratr_index); +		SET_TX_DESC_MACID(pdesc, tcb_desc.mac_id); +	} else { +		SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc.ratr_index); +		SET_TX_DESC_MACID(pdesc, tcb_desc.ratr_index); +	} + +	if ((!ieee80211_is_data_qos(fc)) && ppsc->b_leisure_ps && +	    ppsc->b_fwctrl_lps) { +		SET_TX_DESC_HWSEQ_EN(pdesc, 1); +		SET_TX_DESC_PKT_ID(pdesc, 8); + +		if (!b_defaultadapter) +			SET_TX_DESC_QOS(pdesc, 1); +	} + +	SET_TX_DESC_MORE_FRAG(pdesc, (b_lastseg ? 0 : 1)); + +	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || +	    is_broadcast_ether_addr(ieee80211_get_DA(hdr))) { +		SET_TX_DESC_BMC(pdesc, 1); +	} + +	RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, ("\n")); +} + +void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, +			     u8 *pdesc, bool b_firstseg, +			     bool b_lastseg, struct sk_buff *skb) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); +	u8 fw_queue = QSLT_BEACON; + +	dma_addr_t mapping = pci_map_single(rtlpci->pdev, +					    skb->data, skb->len, +					    PCI_DMA_TODEVICE); + +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); +	u16 fc = le16_to_cpu(hdr->frame_control); + +	CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE); + +	if (b_firstseg) +		SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); + +	SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); + +	SET_TX_DESC_SEQ(pdesc, 0); + +	SET_TX_DESC_LINIP(pdesc, 0); + +	SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue); + +	SET_TX_DESC_FIRST_SEG(pdesc, 1); +	SET_TX_DESC_LAST_SEG(pdesc, 1); + +	SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len)); + +	SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + +	SET_TX_DESC_RATE_ID(pdesc, 7); +	SET_TX_DESC_MACID(pdesc, 0); + +	SET_TX_DESC_OWN(pdesc, 1); + +	SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len)); + +	SET_TX_DESC_FIRST_SEG(pdesc, 1); +	SET_TX_DESC_LAST_SEG(pdesc, 1); + +	SET_TX_DESC_OFFSET(pdesc, 0x20); + +	SET_TX_DESC_USE_RATE(pdesc, 1); + +	if (!ieee80211_is_data_qos(fc)) { +		SET_TX_DESC_HWSEQ_EN(pdesc, 1); +		SET_TX_DESC_PKT_ID(pdesc, 8); +	} + +	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, +		      "H2C Tx Cmd Content\n", +		      pdesc, TX_DESC_SIZE); +} + +void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val) +{ +	if (istx == true) { +		switch (desc_name) { +		case HW_DESC_OWN: +			SET_TX_DESC_OWN(pdesc, 1); +			break; +		case HW_DESC_TX_NEXTDESC_ADDR: +			SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); +			break; +		default: +			RT_ASSERT(false, ("ERR txdesc :%d" +					  " not process\n", desc_name)); +			break; +		} +	} else { +		switch (desc_name) { +		case HW_DESC_RXOWN: +			SET_RX_DESC_OWN(pdesc, 1); +			break; +		case HW_DESC_RXBUFF_ADDR: +			SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *) val); +			break; +		case HW_DESC_RXPKT_LEN: +			SET_RX_DESC_PKT_LEN(pdesc, *(u32 *) val); +			break; +		case HW_DESC_RXERO: +			SET_RX_DESC_EOR(pdesc, 1); +			break; +		default: +			RT_ASSERT(false, ("ERR rxdesc :%d " +					  "not process\n", desc_name)); +			break; +		} +	} +} + +u32 rtl92ce_get_desc(u8 *p_desc, bool istx, u8 desc_name) +{ +	u32 ret = 0; + +	if (istx == true) { +		switch (desc_name) { +		case HW_DESC_OWN: +			ret = GET_TX_DESC_OWN(p_desc); +			break; +		case HW_DESC_TXBUFF_ADDR: +			ret = GET_TX_DESC_TX_BUFFER_ADDRESS(p_desc); +			break; +		default: +			RT_ASSERT(false, ("ERR txdesc :%d " +					  "not process\n", desc_name)); +			break; +		} +	} else { +		struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc; +		switch (desc_name) { +		case HW_DESC_OWN: +			ret = GET_RX_DESC_OWN(pdesc); +			break; +		case HW_DESC_RXPKT_LEN: +			ret = GET_RX_DESC_PKT_LEN(pdesc); +			break; +		default: +			RT_ASSERT(false, ("ERR rxdesc :%d " +					  "not process\n", desc_name)); +			break; +		} +	} +	return ret; +} + +void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue) +{ +	struct rtl_priv *rtlpriv = rtl_priv(hw); +	if (hw_queue == BEACON_QUEUE) { +		rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4)); +	} else { +		rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, +			       BIT(0) << (hw_queue)); +	} +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-trx.h new file mode 100644 index 00000000000..91e13c33351 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rtl8192c-trx.h @@ -0,0 +1,714 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <wlanfae@realtek.com> + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Larry Finger <Larry.Finger@lwfinger.net> + * + *****************************************************************************/ + +#ifndef __RTL92CE_TRX_H__ +#define __RTL92CE_TRX_H__ + +#define TX_DESC_SIZE				64 +#define TX_DESC_AGGR_SUBFRAME_SIZE		32 + +#define RX_DESC_SIZE				32 +#define RX_DRV_INFO_SIZE_UNIT			8 + +#define	TX_DESC_NEXT_DESC_OFFSET		40 +#define USB_HWDESC_HEADER_LEN			32 +#define CRCLENGTH				4 + +#define SET_TX_DESC_PKT_SIZE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val) +#define SET_TX_DESC_OFFSET(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val) +#define SET_TX_DESC_BMC(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val) +#define SET_TX_DESC_HTC(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val) +#define SET_TX_DESC_LAST_SEG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val) +#define SET_TX_DESC_FIRST_SEG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val) +#define SET_TX_DESC_LINIP(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val) +#define SET_TX_DESC_NO_ACM(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val) +#define SET_TX_DESC_GF(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_TX_DESC_OWN(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_TX_DESC_PKT_SIZE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 0, 16) +#define GET_TX_DESC_OFFSET(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 16, 8) +#define GET_TX_DESC_BMC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 24, 1) +#define GET_TX_DESC_HTC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 25, 1) +#define GET_TX_DESC_LAST_SEG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_TX_DESC_FIRST_SEG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_TX_DESC_LINIP(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_TX_DESC_NO_ACM(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_TX_DESC_GF(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_TX_DESC_OWN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_TX_DESC_MACID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 5, __val) +#define SET_TX_DESC_AGG_BREAK(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 5, 1, __val) +#define SET_TX_DESC_BK(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 6, 1, __val) +#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 7, 1, __val) +#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val) +#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val) +#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val) +#define SET_TX_DESC_PIFS(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val) +#define SET_TX_DESC_RATE_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 4, __val) +#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 20, 1, __val) +#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val) +#define SET_TX_DESC_SEC_TYPE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val) +#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 8, __val) + +#define GET_TX_DESC_MACID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 0, 5) +#define GET_TX_DESC_AGG_ENABLE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 5, 1) +#define GET_TX_DESC_AGG_BREAK(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 6, 1) +#define GET_TX_DESC_RDG_ENABLE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 7, 1) +#define GET_TX_DESC_QUEUE_SEL(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 8, 5) +#define GET_TX_DESC_RDG_NAV_EXT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 13, 1) +#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1) +#define GET_TX_DESC_PIFS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1) +#define GET_TX_DESC_RATE_ID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4) +#define GET_TX_DESC_NAV_USE_HDR(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+4, 20, 1) +#define GET_TX_DESC_EN_DESC_ID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 21, 1) +#define GET_TX_DESC_SEC_TYPE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 22, 2) +#define GET_TX_DESC_PKT_OFFSET(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 24, 8) + +#define SET_TX_DESC_RTS_RC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 6, __val) +#define SET_TX_DESC_DATA_RC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 6, 6, __val) +#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val) +#define SET_TX_DESC_MORE_FRAG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val) +#define SET_TX_DESC_RAW(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val) +#define SET_TX_DESC_CCX(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val) +#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val) +#define SET_TX_DESC_ANTSEL_A(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 1, __val) +#define SET_TX_DESC_ANTSEL_B(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 25, 1, __val) +#define SET_TX_DESC_TX_ANT_CCK(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 26, 2, __val) +#define SET_TX_DESC_TX_ANTL(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 28, 2, __val) +#define SET_TX_DESC_TX_ANT_HT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+8, 30, 2, __val) + +#define GET_TX_DESC_RTS_RC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 0, 6) +#define GET_TX_DESC_DATA_RC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 6, 6) +#define GET_TX_DESC_BAR_RTY_TH(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 14, 2) +#define GET_TX_DESC_MORE_FRAG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 17, 1) +#define GET_TX_DESC_RAW(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 18, 1) +#define GET_TX_DESC_CCX(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 19, 1) +#define GET_TX_DESC_AMPDU_DENSITY(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+8, 20, 3) +#define GET_TX_DESC_ANTSEL_A(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 24, 1) +#define GET_TX_DESC_ANTSEL_B(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 25, 1) +#define GET_TX_DESC_TX_ANT_CCK(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 26, 2) +#define GET_TX_DESC_TX_ANTL(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 28, 2) +#define GET_TX_DESC_TX_ANT_HT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 30, 2) + +#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 8, __val) +#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 8, __val) +#define SET_TX_DESC_SEQ(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 12, __val) +#define SET_TX_DESC_PKT_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+12, 28, 4, __val) + +#define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+12, 0, 8) +#define GET_TX_DESC_TAIL_PAGE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 8, 8) +#define GET_TX_DESC_SEQ(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 16, 12) +#define GET_TX_DESC_PKT_ID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 28, 4) + +#define SET_TX_DESC_RTS_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 5, __val) +#define SET_TX_DESC_AP_DCFE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 5, 1, __val) +#define SET_TX_DESC_QOS(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 6, 1, __val) +#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 7, 1, __val) +#define SET_TX_DESC_USE_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 1, __val) +#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 9, 1, __val) +#define SET_TX_DESC_DISABLE_FB(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 10, 1, __val) +#define SET_TX_DESC_CTS2SELF(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 11, 1, __val) +#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 12, 1, __val) +#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 1, __val) +#define SET_TX_DESC_PORT_ID(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 14, 1, __val) +#define SET_TX_DESC_WAIT_DCTS(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 1, __val) +#define SET_TX_DESC_CTS2AP_EN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 19, 1, __val) +#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 20, 2, __val) +#define SET_TX_DESC_TX_STBC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 22, 2, __val) +#define SET_TX_DESC_DATA_SHORT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 1, __val) +#define SET_TX_DESC_DATA_BW(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 25, 1, __val) +#define SET_TX_DESC_RTS_SHORT(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 26, 1, __val) +#define SET_TX_DESC_RTS_BW(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 27, 1, __val) +#define SET_TX_DESC_RTS_SC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 28, 2, __val) +#define SET_TX_DESC_RTS_STBC(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+16, 30, 2, __val) + +#define GET_TX_DESC_RTS_RATE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 0, 5) +#define GET_TX_DESC_AP_DCFE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 5, 1) +#define GET_TX_DESC_QOS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 6, 1) +#define GET_TX_DESC_HWSEQ_EN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 7, 1) +#define GET_TX_DESC_USE_RATE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 8, 1) +#define GET_TX_DESC_DISABLE_RTS_FB(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+16, 9, 1) +#define GET_TX_DESC_DISABLE_FB(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 10, 1) +#define GET_TX_DESC_CTS2SELF(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 11, 1) +#define GET_TX_DESC_RTS_ENABLE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 12, 1) +#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+16, 13, 1) +#define GET_TX_DESC_PORT_ID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 14, 1) +#define GET_TX_DESC_WAIT_DCTS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 18, 1) +#define GET_TX_DESC_CTS2AP_EN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 19, 1) +#define GET_TX_DESC_TX_SUB_CARRIER(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+16, 20, 2) +#define GET_TX_DESC_TX_STBC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 22, 2) +#define GET_TX_DESC_DATA_SHORT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 24, 1) +#define GET_TX_DESC_DATA_BW(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 25, 1) +#define GET_TX_DESC_RTS_SHORT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 26, 1) +#define GET_TX_DESC_RTS_BW(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 27, 1) +#define GET_TX_DESC_RTS_SC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 28, 2) +#define GET_TX_DESC_RTS_STBC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 30, 2) + +#define SET_TX_DESC_TX_RATE(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 6, __val) +#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 6, 1, __val) +#define SET_TX_DESC_CCX_TAG(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val) +#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 5, __val) +#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val) +#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 17, 1, __val) +#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 18, 6, __val) +#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 8, __val) + +#define GET_TX_DESC_TX_RATE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+20, 0, 6) +#define GET_TX_DESC_DATA_SHORTGI(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+20, 6, 1) +#define GET_TX_DESC_CCX_TAG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+20, 7, 1) +#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+20, 8, 5) +#define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+20, 13, 4) +#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+20, 17, 1) +#define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+20, 18, 6) +#define GET_TX_DESC_USB_TXAGG_NUM(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+20, 24, 8) + +#define SET_TX_DESC_TXAGC_A(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 5, __val) +#define SET_TX_DESC_TXAGC_B(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 5, 5, __val) +#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 10, 1, __val) +#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 11, 5, __val) +#define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 4, __val) +#define SET_TX_DESC_MCSG2_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 20, 4, __val) +#define SET_TX_DESC_MCSG3_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 24, 4, __val) +#define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 28, 4, __val) + +#define GET_TX_DESC_TXAGC_A(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+24, 0, 5) +#define GET_TX_DESC_TXAGC_B(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+24, 5, 5) +#define GET_TX_DESC_USE_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 10, 1) +#define GET_TX_DESC_MAX_AGG_NUM(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 11, 5) +#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 16, 4) +#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 20, 4) +#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 24, 4) +#define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+24, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val) +#define SET_TX_DESC_MCSG4_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 16, 4, __val) +#define SET_TX_DESC_MCSG5_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 20, 4, __val) +#define SET_TX_DESC_MCSG6_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 24, 4, __val) +#define SET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 28, 4, __val) + +#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 0, 16) +#define GET_TX_DESC_MCSG4_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 16, 4) +#define GET_TX_DESC_MCSG5_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 20, 4) +#define GET_TX_DESC_MCSG6_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 24, 4) +#define GET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 28, 4) + +#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 32, __val) +#define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \ +	SET_BITS_TO_LE_4BYTE(__pdesc+36, 0, 32, __val) + +#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+32, 0, 32) +#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc)	\ +	LE_BITS_TO_4BYTE(__pdesc+36, 0, 32) + +#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val)	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val) +#define SET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc, __val) \ +	SET_BITS_TO_LE_4BYTE(__pdesc+44, 0, 32, __val) + +#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+40, 0, 32) +#define GET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc)	\ +	LE_BITS_TO_4BYTE(__pdesc+44, 0, 32) + +#define GET_RX_DESC_PKT_LEN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 0, 14) +#define GET_RX_DESC_CRC32(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 14, 1) +#define GET_RX_DESC_ICV(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 15, 1) +#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc, 16, 4) +#define GET_RX_DESC_SECURITY(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 20, 3) +#define GET_RX_DESC_QOS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 23, 1) +#define GET_RX_DESC_SHIFT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 24, 2) +#define GET_RX_DESC_PHYST(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 26, 1) +#define GET_RX_DESC_SWDEC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 27, 1) +#define GET_RX_DESC_LS(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc, 28, 1) +#define GET_RX_DESC_FS(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc, 29, 1) +#define GET_RX_DESC_EOR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 30, 1) +#define GET_RX_DESC_OWN(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc, 31, 1) + +#define SET_RX_DESC_PKT_LEN(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val) +#define SET_RX_DESC_EOR(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val) +#define SET_RX_DESC_OWN(__pdesc, __val)			\ +	SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val) + +#define GET_RX_DESC_MACID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 0, 5) +#define GET_RX_DESC_TID(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 5, 4) +#define GET_RX_DESC_HWRSVD(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 9, 5) +#define GET_RX_DESC_PAGGR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 14, 1) +#define GET_RX_DESC_FAGGR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 15, 1) +#define GET_RX_DESC_A1_FIT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 16, 4) +#define GET_RX_DESC_A2_FIT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 20, 4) +#define GET_RX_DESC_PAM(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 24, 1) +#define GET_RX_DESC_PWR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 25, 1) +#define GET_RX_DESC_MD(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 26, 1) +#define GET_RX_DESC_MF(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 27, 1) +#define GET_RX_DESC_TYPE(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+4, 28, 2) +#define GET_RX_DESC_MC(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 30, 1) +#define GET_RX_DESC_BC(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+4, 31, 1) +#define GET_RX_DESC_SEQ(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 0, 12) +#define GET_RX_DESC_FRAG(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 12, 4) +#define GET_RX_DESC_NEXT_PKT_LEN(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+8, 16, 14) +#define GET_RX_DESC_NEXT_IND(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 30, 1) +#define GET_RX_DESC_RSVD(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+8, 31, 1) + +#define GET_RX_DESC_RXMCS(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 0, 6) +#define GET_RX_DESC_RXHT(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 6, 1) +#define GET_RX_DESC_SPLCP(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 8, 1) +#define GET_RX_DESC_BW(__pdesc)				\ +	LE_BITS_TO_4BYTE(__pdesc+12, 9, 1) +#define GET_RX_DESC_HTC(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 10, 1) +#define GET_RX_DESC_HWPC_ERR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 14, 1) +#define GET_RX_DESC_HWPC_IND(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 15, 1) +#define GET_RX_DESC_IV0(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+12, 16, 16) + +#define GET_RX_DESC_IV1(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+16, 0, 32) +#define GET_RX_DESC_TSFL(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+20, 0, 32) + +#define GET_RX_DESC_BUFF_ADDR(__pdesc)			\ +	LE_BITS_TO_4BYTE(__pdesc+24, 0, 32) +#define GET_RX_DESC_BUFF_ADDR64(__pdesc)		\ +	LE_BITS_TO_4BYTE(__pdesc+28, 0, 32) + +#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val)		\ +	SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val) +#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) 	\ +	SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val) + +#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)	\ +do {							\ +	if (_size > TX_DESC_NEXT_DESC_OFFSET)		\ +		memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);	\ +	else						\ +		memset((void *)__pdesc, 0, _size);	\ +} while (0); + +#define RX_HAL_IS_CCK_RATE(_pdesc)\ +	(_pdesc->rxmcs == DESC92C_RATE1M ||		\ +	 _pdesc->rxmcs == DESC92C_RATE2M ||		\ +	 _pdesc->rxmcs == DESC92C_RATE5_5M ||		\ +	 _pdesc->rxmcs == DESC92C_RATE11M) + +struct rx_fwinfo_92c { +	u8 gain_trsw[4]; +	u8 pwdb_all; +	u8 cfosho[4]; +	u8 cfotail[4]; +	char rxevm[2]; +	char rxsnr[4]; +	u8 pdsnr[2]; +	u8 csi_current[2]; +	u8 csi_target[2]; +	u8 sigevm; +	u8 max_ex_pwr; +	u8 ex_intf_flag:1; +	u8 sgi_en:1; +	u8 rxsc:2; +	u8 reserve:4; +} __attribute__ ((packed)); + +struct tx_desc_92c { +	u32 pktsize:16; +	u32 offset:8; +	u32 bmc:1; +	u32 htc:1; +	u32 lastseg:1; +	u32 firstseg:1; +	u32 linip:1; +	u32 noacm:1; +	u32 gf:1; +	u32 own:1; + +	u32 macid:5; +	u32 agg_en:1; +	u32 bk:1; +	u32 rdg_en:1; +	u32 queuesel:5; +	u32 rd_nav_ext:1; +	u32 lsig_txop_en:1; +	u32 pifs:1; +	u32 rateid:4; +	u32 nav_usehdr:1; +	u32 en_descid:1; +	u32 sectype:2; +	u32 pktoffset:8; + +	u32 rts_rc:6; +	u32 data_rc:6; +	u32 rsvd0:2; +	u32 bar_retryht:2; +	u32 rsvd1:1; +	u32 morefrag:1; +	u32 raw:1; +	u32 ccx:1; +	u32 ampdudensity:3; +	u32 rsvd2:1; +	u32 ant_sela:1; +	u32 ant_selb:1; +	u32 txant_cck:2; +	u32 txant_l:2; +	u32 txant_ht:2; + +	u32 nextheadpage:8; +	u32 tailpage:8; +	u32 seq:12; +	u32 pktid:4; + +	u32 rtsrate:5; +	u32 apdcfe:1; +	u32 qos:1; +	u32 hwseq_enable:1; +	u32 userrate:1; +	u32 dis_rtsfb:1; +	u32 dis_datafb:1; +	u32 cts2self:1; +	u32 rts_en:1; +	u32 hwrts_en:1; +	u32 portid:1; +	u32 rsvd3:3; +	u32 waitdcts:1; +	u32 cts2ap_en:1; +	u32 txsc:2; +	u32 stbc:2; +	u32 txshort:1; +	u32 txbw:1; +	u32 rtsshort:1; +	u32 rtsbw:1; +	u32 rtssc:2; +	u32 rtsstbc:2; + +	u32 txrate:6; +	u32 shortgi:1; +	u32 ccxt:1; +	u32 txrate_fb_lmt:5; +	u32 rtsrate_fb_lmt:4; +	u32 retrylmt_en:1; +	u32 txretrylmt:6; +	u32 usb_txaggnum:8; + +	u32 txagca:5; +	u32 txagcb:5; +	u32 usemaxlen:1; +	u32 maxaggnum:5; +	u32 mcsg1maxlen:4; +	u32 mcsg2maxlen:4; +	u32 mcsg3maxlen:4; +	u32 mcs7sgimaxlen:4; + +	u32 txbuffersize:16; +	u32 mcsg4maxlen:4; +	u32 mcsg5maxlen:4; +	u32 mcsg6maxlen:4; +	u32 mcsg15sgimaxlen:4; + +	u32 txbuffaddr; +	u32 txbufferaddr64; +	u32 nextdescaddress; +	u32 nextdescaddress64; + +	u32 reserve_pass_pcie_mm_limit[4]; +} __attribute__ ((packed)); + +struct rx_desc_92c { +	u32 length:14; +	u32 crc32:1; +	u32 icverror:1; +	u32 drv_infosize:4; +	u32 security:3; +	u32 qos:1; +	u32 shift:2; +	u32 phystatus:1; +	u32 swdec:1; +	u32 lastseg:1; +	u32 firstseg:1; +	u32 eor:1; +	u32 own:1; + +	u32 macid:5; +	u32 tid:4; +	u32 hwrsvd:5; +	u32 paggr:1; +	u32 faggr:1; +	u32 a1_fit:4; +	u32 a2_fit:4; +	u32 pam:1; +	u32 pwr:1; +	u32 moredata:1; +	u32 morefrag:1; +	u32 type:2; +	u32 mc:1; +	u32 bc:1; + +	u32 seq:12; +	u32 frag:4; +	u32 nextpktlen:14; +	u32 nextind:1; +	u32 rsvd:1; + +	u32 rxmcs:6; +	u32 rxht:1; +	u32 amsdu:1; +	u32 splcp:1; +	u32 bandwidth:1; +	u32 htc:1; +	u32 tcpchk_rpt:1; +	u32 ipcchk_rpt:1; +	u32 tcpchk_valid:1; +	u32 hwpcerr:1; +	u32 hwpcind:1; +	u32 iv0:16; + +	u32 iv1; + +	u32 tsfl; + +	u32 bufferaddress; +	u32 bufferaddress64; + +} __attribute__ ((packed)); + +void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, +			  struct ieee80211_hdr *hdr, +			  u8 *pdesc, struct ieee80211_tx_info *info, +			  struct sk_buff *skb, unsigned int qsel); +bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, +			   struct rtl_stats *stats, +			   struct ieee80211_rx_status *rx_status, +			   u8 *pdesc, struct sk_buff *skb); +void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); +u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name); +void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue); +void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, +			     bool b_firstseg, bool b_lastseg, +			     struct sk_buff *skb); +#endif diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h new file mode 100644 index 00000000000..0dd6824b194 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -0,0 +1,1532 @@ +/****************************************************************************** + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae <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/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 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 + +/*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 + +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 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, + +	/*keep it last*/ +	HARDWARE_TYPE_NUM +}; + +enum scan_operation_backup_opt { +	SCAN_OPT_BACKUP = 0, +	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_DM_BY_SCAN = 0, +	IO_CMD_RESUME_DM_BY_SCAN = 1, +}; + +enum hw_variables { +	HW_VAR_ETHER_ADDR, +	HW_VAR_MULTICAST_REG, +	HW_VAR_BASIC_RATE, +	HW_VAR_BSSID, +	HW_VAR_MEDIA_STATUS, +	HW_VAR_SECURITY_CONF, +	HW_VAR_BEACON_INTERVAL, +	HW_VAR_ATIM_WINDOW, +	HW_VAR_LISTEN_INTERVAL, +	HW_VAR_CS_COUNTER, +	HW_VAR_DEFAULTKEY0, +	HW_VAR_DEFAULTKEY1, +	HW_VAR_DEFAULTKEY2, +	HW_VAR_DEFAULTKEY3, +	HW_VAR_SIFS, +	HW_VAR_DIFS, +	HW_VAR_EIFS, +	HW_VAR_SLOT_TIME, +	HW_VAR_ACK_PREAMBLE, +	HW_VAR_CW_CONFIG, +	HW_VAR_CW_VALUES, +	HW_VAR_RATE_FALLBACK_CONTROL, +	HW_VAR_CONTENTION_WINDOW, +	HW_VAR_RETRY_COUNT, +	HW_VAR_TR_SWITCH, +	HW_VAR_COMMAND, +	HW_VAR_WPA_CONFIG, +	HW_VAR_AMPDU_MIN_SPACE, +	HW_VAR_SHORTGI_DENSITY, +	HW_VAR_AMPDU_FACTOR, +	HW_VAR_MCS_RATE_AVAILABLE, +	HW_VAR_AC_PARAM, +	HW_VAR_ACM_CTRL, +	HW_VAR_DIS_Req_Qsize, +	HW_VAR_CCX_CHNL_LOAD, +	HW_VAR_CCX_NOISE_HISTOGRAM, +	HW_VAR_CCX_CLM_NHM, +	HW_VAR_TxOPLimit, +	HW_VAR_TURBO_MODE, +	HW_VAR_RF_STATE, +	HW_VAR_RF_OFF_BY_HW, +	HW_VAR_BUS_SPEED, +	HW_VAR_SET_DEV_POWER, + +	HW_VAR_RCR, +	HW_VAR_RATR_0, +	HW_VAR_RRSR, +	HW_VAR_CPU_RST, +	HW_VAR_CECHK_BSSID, +	HW_VAR_LBK_MODE, +	HW_VAR_AES_11N_FIX, +	HW_VAR_USB_RX_AGGR, +	HW_VAR_USER_CONTROL_TURBO_MODE, +	HW_VAR_RETRY_LIMIT, +	HW_VAR_INIT_TX_RATE, +	HW_VAR_TX_RATE_REG, +	HW_VAR_EFUSE_USAGE, +	HW_VAR_EFUSE_BYTES, +	HW_VAR_AUTOLOAD_STATUS, +	HW_VAR_RF_2R_DISABLE, +	HW_VAR_SET_RPWM, +	HW_VAR_H2C_FW_PWRMODE, +	HW_VAR_H2C_FW_JOINBSSRPT, +	HW_VAR_FW_PSMODE_STATUS, +	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, + +	HW_VAR_MRC, + +	HW_VAR_MGT_FILTER, +	HW_VAR_CTRL_FILTER, +	HW_VAR_DATA_FILTER, +}; + +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, +}; + +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, +}; + +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, +}; + +enum ht_channel_width { +	HT_CHANNEL_WIDTH_20 = 0, +	HT_CHANNEL_WIDTH_20_40 = 1, +}; + +/* 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, +}; + +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, + +	/*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, + +	/*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_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_IBSS_INT_MASKS,	/*(RTL_IMR_BcnInt|RTL_IMR_TBDOK|RTL_IMR_TBDER)*/ + +	/*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, + +	/*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, +}; + +/*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 +}; + +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_A = 8, +}; + +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, +}; + +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]; +} __attribute__ ((packed)); + +struct rtl_info_element { +	u8 id; +	u8 len; +	u8 data[0]; +} __attribute__ ((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]; +} __attribute__ ((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; +} __attribute__ ((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 false_alarm_statistics { +	u32 cnt_parity_fail; +	u32 cnt_rate_illegal; +	u32 cnt_crc8_fail; +	u32 cnt_mcs_fail; +	u32 cnt_ofdm_fail; +	u32 cnt_cck_fail; +	u32 cnt_all; +}; + +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; + +	/*Transformed, in dbm. Beautified signal +	   strength for UI, not correct. */ +	long signal_strength; + +	u8 rx_rssi_percentage[4]; +	u8 rx_evm_percentage[2]; + +	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_ra40m; +	u32 low_rssi_thresh_for_ra40M; +	u8 low2high_rssi_thresh_for_ra20m; +	u32 low_rssi_thresh_for_ra20M; +	u32 upper_rssi_threshold_ratr; +	u32 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; +}; + +struct regd_pair_mapping { +	u16 reg_dmnenum; +	u16 reg_5ghz_ctl; +	u16 reg_2ghz_ctl; +}; + +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 */ +}; + +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; + +	/*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 b_rfpi_enable; + +	u8 pwrgroup_cnt; +	u8 bcck_high_power; +	/* 3 groups of pwr diff by rates*/ +	u32 mcs_txpwrlevel_origoffset[4][16]; +	u8 default_initialgain[4]; + +	/*the current Tx power level*/ +	u8 cur_cck_txpwridx; +	u8 cur_ofdm24g_txpwridx; + +	u32 rfreg_chnlval[2]; +	bool b_apk_done; + +	/*fsync*/ +	u8 framesync; +	u32 framesync_c34; + +	u8 num_total_rfpath; +}; + +#define MAX_TID_COUNT				9 +#define RTL_AGG_OFF				0 +#define RTL_AGG_ON				1 +#define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA		2 +#define RTL_AGG_EMPTYING_HW_QUEUE_DELBA		3 + +struct rtl_ht_agg { +	u16 txq_id; +	u16 wait_for_ba; +	u16 start_idx; +	u64 bitmap; +	u32 rate_n_flags; +	u8 agg_state; +}; + +struct rtl_tid_data { +	u16 seq_number; +	struct rtl_ht_agg agg; +}; + +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 */ +	struct rtl_tid_data tids[MAX_TID_COUNT]; +	enum rtl_link_state link_state; + +	int n_channels; +	int n_bitrates; + +	/*filters */ +	u32 rx_conf; +	u16 rx_mgt_filter; +	u16 rx_ctrl_filter; +	u16 rx_data_filter; + +	bool act_scanning; +	u8 cnt_after_linked; + +	 /*RDG*/ bool rdg_en; + +	 /*AP*/ u8 bssid[6]; +	u8 mcs[16];	/*16 bytes mcs for HT rates.*/ +	u32 basic_rates; /*b/g rates*/ +	u8 ht_enable; +	u8 sgi_40; +	u8 sgi_20; +	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; +	u64 tsf; +	u8 retry_short; +	u8 retry_long; +	u16 assoc_id; + +	 /*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; + +	enum intf_type interface; +	u16 hw_type;		/*92c or 92d or 92s and so on */ +	u8 oem_id; +	u8 version;		/*version of chip */ +	u8 state;		/*stop 0, start 1 */ + +	/*firmware */ +	u8 *pfirmware; +	bool b_h2c_setinprogress; +	u8 last_hmeboxnum; +	bool bfw_ready; +	/*Reserve page start offset except beacon in TxQ. */ +	u8 fw_rsvdpage_startoffset; +}; + +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; + +	/*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_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]; + +	u8 thermalvalue_iqk; +	u8 thermalvalue_lck; +	u8 thermalvalue; +	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; + +	char ofdm_index[2]; +	char cck_index; +}; + +#define	EFUSE_MAX_LOGICAL_SIZE			 128 + +struct rtl_efuse { +	bool bautoLoad_ok; +	bool bootfromefuse; +	u16 max_physical_size; +	u8 contents[EFUSE_MAX_LOGICAL_SIZE]; + +	u8 efuse_map[2][EFUSE_MAX_LOGICAL_SIZE]; +	u16 efuse_usedbytes; +	u8 efuse_usedpercentage; + +	u8 autoload_failflag; + +	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]; + +	bool b_txpwr_fromeprom; +	u8 eeprom_tssi[2]; +	u8 eeprom_pwrlimit_ht20[3]; +	u8 eeprom_pwrlimit_ht40[3]; +	u8 eeprom_chnlarea_txpwr_cck[2][3]; +	u8 eeprom_chnlarea_txpwr_ht40_1s[2][3]; +	u8 eeprom_chnlarea_txpwr_ht40_2sdiif[2][3]; +	u8 txpwrlevel_cck[2][14]; +	u8 txpwrlevel_ht40_1s[2][14];	/*For HT 40MHZ pwr */ +	u8 txpwrlevel_ht40_2s[2][14];	/*For HT 40MHZ pwr */ + +	/*For power group */ +	u8 pwrgroup_ht20[2][14]; +	u8 pwrgroup_ht40[2][14]; + +	char txpwr_ht20diff[2][14];	/*HT 20<->40 Pwr diff */ +	u8 txpwr_legacyhtdiff[2][14];	/*For HT<->legacy pwr diff */ + +	u8 eeprom_regulatory; +	u8 eeprom_thermalmeter; +	/*ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */ +	u8 thermalmeter[2]; + +	u8 legacy_ht_txpowerdiff;	/*Legacy to HT rate power diff */ +	bool b_apk_thermalmeterignore; +}; + +struct rtl_ps_ctl { +	bool set_rfpowerstate_inprogress; +	bool b_in_powersavemode; +	bool rfchange_inprogress; +	bool b_swrf_processing; +	bool b_hwradiooff; + +	u32 last_sleep_jiffies; +	u32 last_awake_jiffies; +	u32 last_delaylps_stamp_jiffies; + +	/* +	 * 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_leisure_ps; +	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; + +	/*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 */ +}; + +struct rtl_stats { +	u32 mac_time[2]; +	s8 rssi; +	u8 signal; +	u8 noise; +	u16 rate;		/*in 100 kbps */ +	u8 received_channel; +	u8 control; +	u8 mask; +	u8 freq; +	u16 len; +	u64 tsf; +	u32 beacon_time; +	u8 nic_type; +	u16 length; +	u8 signalquality;	/*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; + +	u8 rx_drvinfo_size; +	u8 rx_bufshift; +	bool b_isampdu; +	bool rx_is40Mhzpacket; +	u32 rx_pwdb_all; +	u8 rx_mimo_signalstrength[4];	/*in 0~100 index */ +	s8 rx_mimo_signalquality[2]; +	bool b_packet_matchbssid; +	bool b_is_cck; +	bool b_packet_toself; +	bool b_packet_beacon;	/*for rssi */ +	char cck_adc_pwdb[4];	/*for rx path selection */ +}; + +struct rt_link_detect { +	u32 num_tx_in4period[4]; +	u32 num_rx_in4period[4]; + +	u32 num_tx_inperiod; +	u32 num_rx_inperiod; + +	bool b_busytraffic; +	bool b_higher_busytraffic; +	bool b_higher_busyrxtraffic; +}; + +struct rtl_tcb_desc { +	u8 b_packet_bw:1; +	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; +}; + +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 (*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_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_table) (struct ieee80211_hw *hw); +	void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); +	void (*fill_tx_desc) (struct ieee80211_hw *hw, +			      struct ieee80211_hdr *hdr, u8 *pdesc_tx, +			      struct ieee80211_tx_info *info, +			      struct sk_buff *skb, unsigned int queue_index); +	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 *stats, +			       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) (u8 *pdesc, bool istx, u8 desc_name, u8 *val); +	 u32(*get_desc) (u8 *pdesc, bool istx, u8 desc_name); +	void (*tx_polling) (struct ieee80211_hw *hw, unsigned int 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); +	void (*deinit_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); +}; + +struct rtl_intf_ops { +	/*com */ +	int (*adapter_start) (struct ieee80211_hw *hw); +	void (*adapter_stop) (struct ieee80211_hw *hw); + +	int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb); +	int (*reset_trx_ring) (struct ieee80211_hw *hw); + +	/*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 */ +	int sw_crypto; +}; + +struct rtl_hal_cfg { +	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 { +	/*sem */ +	struct semaphore ips_sem; +	struct semaphore conf_sem; + +	/*spin lock */ +	spinlock_t irq_th_lock; +	spinlock_t h2c_lock; +	spinlock_t rf_ps_lock; +	spinlock_t rf_lock; +	spinlock_t lps_lock; +}; + +struct rtl_works { +	struct ieee80211_hw *hw; + +	/*timer */ +	struct timer_list watchdog_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; +}; + +struct rtl_debug { +	u32 dbgp_type[DBGP_TYPE_MAX]; +	u32 global_debuglevel; +	u64 global_debugcomponents; +}; + +struct rtl_priv { +	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 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; + +	/* +	 *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; + +	/*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)) + +/**************************************** +	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 */ +#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))) +#define READEF2BYTE(_ptr)	\ +	EF2BYTE(*((u16 *)(_ptr))) +#define READEF4BYTE(_ptr)	\ +	EF4BYTE(*((u32 *)(_ptr))) + +/* Write data to memory */ +#define WRITEEF1BYTE(_ptr, _val)	\ +	(*((u8 *)(_ptr))) = EF1BYTE(_val) +#define WRITEEF2BYTE(_ptr, _val)	\ +	(*((u16 *)(_ptr))) = EF2BYTE(_val) +#define WRITEEF4BYTE(_ptr, _val)	\ +	(*((u32 *)(_ptr))) = EF4BYTE(_val) + +/*Example: +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))) + +/*Example: +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(*((u32 *)(__pstart)))) +#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \ +	(EF2BYTE(*((u16 *)(__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)) = EF4BYTE \ +	( \ +		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)) = EF2BYTE \ +	( \ +		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)) \ +	); + +/**************************************** +	mem access macro define end +****************************************/ + +#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)	((fc) & IEEE80211_FCTL_VERS) +#define WLAN_FC_GET_TYPE(fc)	((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc)	((fc) & IEEE80211_FCTL_STYPE) +#define WLAN_FC_MORE_DATA(fc)	((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) +/*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]) + +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); +} + +static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) +{ +	rtlpriv->io.write16_async(rtlpriv, addr, val16); +} + +static inline void rtl_write_dword(struct rtl_priv *rtlpriv, +				   u32 addr, u32 val32) +{ +	rtlpriv->io.write32_async(rtlpriv, addr, val32); +} + +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 *)(hw)->priv)->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; +} + +#endif  |