diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2010-12-08 11:12:31 -0600 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-12-15 16:17:49 -0500 |
commit | 0c8173385e549f95cd80c3fff5aab87b4f881d8d (patch) | |
tree | eb818f70ed027eecbc5e170b046aa0d785168d43 /drivers/net/wireless | |
parent | 412b31334b831a8c2909afaca017c5a236ac2dd0 (diff) |
rtl8192ce: Add new driver
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
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)) || < |