staging: r8192ee: Add source files for core driver

This part is the equivalent of rtlwifi in the wireless tree. As the changes
needed for the RTL8192EE have not yet been merged, a separate version is still
needed.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Larry Finger
2014-05-21 16:25:33 -05:00
committed by Greg Kroah-Hartman
parent 69c1f05379
commit 78de2c0637
22 changed files with 14270 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __RTL_BASE_H__
#define __RTL_BASE_H__
#include "compat.h"
enum ap_peer {
PEER_UNKNOWN = 0,
PEER_RTL = 1,
PEER_RTL_92SE = 2,
PEER_BROAD = 3,
PEER_RAL = 4,
PEER_ATH = 5,
PEER_CISCO = 6,
PEER_MARV = 7,
PEER_AIRGO = 9,
PEER_MAX = 10,
};
#define RTL_DUMMY_OFFSET 0
#define RTL_DUMMY_UNIT 8
#define RTL_TX_DUMMY_SIZE (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT)
#define RTL_TX_DESC_SIZE 32
#define RTL_TX_HEADER_SIZE (RTL_TX_DESC_SIZE + RTL_TX_DUMMY_SIZE)
#define HT_AMSDU_SIZE_4K 3839
#define HT_AMSDU_SIZE_8K 7935
#define MAX_BIT_RATE_40MHZ_MCS15 300 /* Mbps */
#define MAX_BIT_RATE_40MHZ_MCS7 150 /* Mbps */
#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9 867 /* Mbps */
#define MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS7 650 /* Mbps */
#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS9 780 /* Mbps */
#define MAX_BIT_RATE_LONG_GI_2NSS_80MHZ_MCS7 585 /* Mbps */
#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9 434 /* Mbps */
#define MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS7 325 /* Mbps */
#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS9 390 /* Mbps */
#define MAX_BIT_RATE_LONG_GI_1NSS_80MHZ_MCS7 293 /* Mbps */
#define RTL_RATE_COUNT_LEGACY 12
#define RTL_CHANNEL_COUNT 14
#define FRAME_OFFSET_FRAME_CONTROL 0
#define FRAME_OFFSET_DURATION 2
#define FRAME_OFFSET_ADDRESS1 4
#define FRAME_OFFSET_ADDRESS2 10
#define FRAME_OFFSET_ADDRESS3 16
#define FRAME_OFFSET_SEQUENCE 22
#define FRAME_OFFSET_ADDRESS4 24
#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \
WRITEEF2BYTE(_hdr, _val)
#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val) \
WRITEEF1BYTE(_hdr, _val)
#define SET_80211_HDR_PWR_MGNT(_hdr, _val) \
SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val)
#define SET_80211_HDR_TO_DS(_hdr, _val) \
SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val)
#define SET_80211_PS_POLL_AID(_hdr, _val) \
(*(u16 *)((u8 *)(_hdr) + 2) = _val)
#define SET_80211_PS_POLL_BSSID(_hdr, _val) \
memcpy(((u8 *)(_hdr)) + 4, (u8 *)(_val), ETH_ALEN)
#define SET_80211_PS_POLL_TA(_hdr, _val) \
memcpy(((u8 *)(_hdr)) + 10, (u8 *)(_val), ETH_ALEN)
#define SET_80211_HDR_DURATION(_hdr, _val) \
WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_DURATION, _val)
#define SET_80211_HDR_ADDRESS1(_hdr, _val) \
CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8 *)(_val))
#define SET_80211_HDR_ADDRESS2(_hdr, _val) \
CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8 *)(_val))
#define SET_80211_HDR_ADDRESS3(_hdr, _val) \
CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val))
#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val) \
WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val)
#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val) \
WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val)
#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \
WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val)
#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \
WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val)
#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) \
READEF2BYTE(((u8 *)(__phdr)) + 34)
#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val)
#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \
(GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val))))
int rtl92e_init_core(struct ieee80211_hw *hw);
void rtl92e_deinit_core(struct ieee80211_hw *hw);
void rtl92e_init_rx_config(struct ieee80211_hw *hw);
void rtl92e_init_rfkill(struct ieee80211_hw *hw);
void rtl92e_deinit_rfkill(struct ieee80211_hw *hw);
void rtl92e_watch_dog_timer_callback(unsigned long data);
void rtl92e_deinit_deferred_work(struct ieee80211_hw *hw);
bool rtl92e_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
bool rtl92e_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
u8 rtl92e_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb,
u8 is_tx);
void rtl92e_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb);
void rtl92e_watch_dog_timer_callback(unsigned long data);
int rtl92e_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
int rtl92e_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
int rtl92e_tx_agg_oper(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid);
int rtl92e_rx_agg_start(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid);
int rtl92e_rx_agg_stop(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid);
void rtl92e_watchdog_wq_callback(void *data);
void rtl92e_fwevt_wq_callback(void *data);
void stg_rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc);
int stg_rtl_send_smps_action(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
enum ieee80211_smps_mode smps);
u8 *rtl92e_find_ie(u8 *data, unsigned int len, u8 ie);
void rtl92e_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
u8 rtl92e_tid_to_ac(struct ieee80211_hw *hw, u8 tid);
void rtl92e_easy_concurrent_retrytimer_callback(unsigned long data);
extern struct rtl_global_var global_var;
int rtl_core_module_init(void);
void rtl_core_module_exit(void);
#endif

View File

@@ -0,0 +1,337 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#include "wifi.h"
#include "cam.h"
void rtl92e_cam_reset_sec_info(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->sec.use_defaultkey = false;
rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION;
rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION;
memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN);
memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE);
rtlpriv->sec.pairwise_key = NULL;
}
static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
u8 *mac_addr, u8 *key_cont_128, u16 us_config)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 target_command;
u32 target_content = 0;
u8 entry_i;
RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_DMESG, "Key content:",
key_cont_128, 16);
for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
target_command = entry_i + CAM_CONTENT_COUNT * entry_no;
target_command = target_command | BIT(31) | BIT(16);
if (entry_i == 0) {
target_content = (u32) (*(mac_addr + 0)) << 16 |
(u32) (*(mac_addr + 1)) << 24 | (u32) us_config;
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
target_content);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
target_command);
RT_TRACE(COMP_SEC, DBG_LOUD,
("WRITE %x: %x\n",
rtlpriv->cfg->maps[WCAMI], target_content));
RT_TRACE(COMP_SEC, DBG_LOUD,
("The Key ID is %d\n", entry_no));
RT_TRACE(COMP_SEC, DBG_LOUD,
("WRITE %x: %x\n",
rtlpriv->cfg->maps[RWCAM], target_command));
} else if (entry_i == 1) {
target_content = (u32) (*(mac_addr + 5)) << 24 |
(u32) (*(mac_addr + 4)) << 16 |
(u32) (*(mac_addr + 3)) << 8 |
(u32) (*(mac_addr + 2));
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
target_content);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
target_command);
RT_TRACE(COMP_SEC, DBG_LOUD,
("WRITE A4: %x\n", target_content));
RT_TRACE(COMP_SEC, DBG_LOUD,
("WRITE A0: %x\n", target_command));
} else {
target_content =
(u32) (*(key_cont_128 + (entry_i * 4 - 8) + 3)) <<
24 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 2))
<< 16 |
(u32) (*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8
| (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 0));
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
target_content);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
target_command);
udelay(100);
RT_TRACE(COMP_SEC, DBG_LOUD,
("WRITE A4: %x\n", target_content));
RT_TRACE(COMP_SEC, DBG_LOUD,
("WRITE A0: %x\n", target_command));
}
}
RT_TRACE(COMP_SEC, DBG_LOUD,
("after set key, usconfig:%x\n", us_config));
}
u8 stg_rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
u32 ul_default_key, u8 *key_content)
{
u32 us_config;
struct rtl_priv *rtlpriv = rtl_priv(hw);
RT_TRACE(COMP_SEC, DBG_DMESG,
("EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n",
ul_entry_idx, ul_key_id, ul_enc_alg,
ul_default_key, mac_addr));
if (ul_key_id == TOTAL_CAM_ENTRY) {
RT_TRACE(COMP_ERR, DBG_WARNING,
("ulKeyId exceed!\n"));
return 0;
}
if (ul_default_key == 1)
us_config = CFG_VALID | ((u16) (ul_enc_alg) << 2);
else
us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id;
rtl_cam_program_entry(hw, ul_entry_idx, mac_addr,
(u8 *)key_content, us_config);
RT_TRACE(COMP_SEC, DBG_DMESG, ("end\n"));
return 1;
}
EXPORT_SYMBOL(stg_rtl_cam_add_one_entry);
int stg_rtl_cam_delete_one_entry(struct ieee80211_hw *hw,
u8 *mac_addr, u32 ul_key_id)
{
u32 ul_command;
struct rtl_priv *rtlpriv = rtl_priv(hw);
RT_TRACE(COMP_SEC, DBG_DMESG, ("key_idx:%d\n", ul_key_id));
ul_command = ul_key_id * CAM_CONTENT_COUNT;
ul_command = ul_command | BIT(31) | BIT(16);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
RT_TRACE(COMP_SEC, DBG_DMESG,
("stg_rtl_cam_delete_one_entry(): WRITE A4: %x\n", 0));
RT_TRACE(COMP_SEC, DBG_DMESG,
("stg_rtl_cam_delete_one_entry(): WRITE A0: %x\n",
ul_command));
return 0;
}
EXPORT_SYMBOL(stg_rtl_cam_delete_one_entry);
void stg_rtl_cam_reset_all_entry(struct ieee80211_hw *hw)
{
u32 ul_command;
struct rtl_priv *rtlpriv = rtl_priv(hw);
ul_command = BIT(31) | BIT(30);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
}
EXPORT_SYMBOL(stg_rtl_cam_reset_all_entry);
void stg_rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 ul_command;
u32 ul_content;
u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
switch (rtlpriv->sec.pairwise_enc_algorithm) {
case WEP40_ENCRYPTION:
ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
break;
case WEP104_ENCRYPTION:
ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
break;
case TKIP_ENCRYPTION:
ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
break;
case AESCCMP_ENCRYPTION:
ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
break;
default:
ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
}
ul_content = (uc_index & 3) | ((u16) (ul_enc_algo) << 2);
ul_content |= BIT(15);
ul_command = CAM_CONTENT_COUNT * uc_index;
ul_command = ul_command | BIT(31) | BIT(16);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
RT_TRACE(COMP_SEC, DBG_DMESG,
("stg_rtl_cam_mark_invalid(): WRITE A4: %x\n", ul_content));
RT_TRACE(COMP_SEC, DBG_DMESG,
("stg_rtl_cam_mark_invalid(): WRITE A0: %x\n", ul_command));
}
EXPORT_SYMBOL(stg_rtl_cam_mark_invalid);
void stg_rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 ul_command;
u32 ul_content;
u32 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
u8 entry_i;
switch (rtlpriv->sec.pairwise_enc_algorithm) {
case WEP40_ENCRYPTION:
ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
break;
case WEP104_ENCRYPTION:
ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
break;
case TKIP_ENCRYPTION:
ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
break;
case AESCCMP_ENCRYPTION:
ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
break;
default:
ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
}
for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
if (entry_i == 0) {
ul_content =
(uc_index & 0x03) | ((u16) (ul_encalgo) << 2);
ul_content |= BIT(15);
} else {
ul_content = 0;
}
ul_command = CAM_CONTENT_COUNT * uc_index + entry_i;
ul_command = ul_command | BIT(31) | BIT(16);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
RT_TRACE(COMP_SEC, DBG_LOUD,
("stg_rtl_cam_empty_entry(): WRITE A4: %x\n",
ul_content));
RT_TRACE(COMP_SEC, DBG_LOUD,
("stg_rtl_cam_empty_entry(): WRITE A0: %x\n",
ul_command));
}
}
EXPORT_SYMBOL(stg_rtl_cam_empty_entry);
u8 stg_rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4;
u8 entry_idx = 0;
u8 i, *addr;
if (!sta_addr) {
RT_TRACE(COMP_SEC, DBG_EMERG,
("sta_addr is NULL\n"));
return TOTAL_CAM_ENTRY;
}
/* Does STA already exist? */
for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
if (memcmp(addr, sta_addr, ETH_ALEN) == 0)
return i;
}
/* Get a free CAM entry. */
for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) {
if ((bitmap & BIT(0)) == 0) {
RT_TRACE(COMP_SEC, DBG_EMERG,
("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n",
rtlpriv->sec.hwsec_cam_bitmap, entry_idx));
rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx;
memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx],
sta_addr, ETH_ALEN);
return entry_idx;
}
bitmap = bitmap >> 1;
}
return TOTAL_CAM_ENTRY;
}
EXPORT_SYMBOL(stg_rtl_cam_get_free_entry);
void stg_rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 bitmap;
u8 i, *addr;
if (NULL == sta_addr) {
RT_TRACE(COMP_SEC, DBG_EMERG,
("sta_addr is NULL.\n"));
return;
}
if (is_zero_ether_addr(sta_addr)) {
RT_TRACE(COMP_SEC, DBG_EMERG,
("sta_addr is 00:00:00:00:00:00.\n"));
return;
}
/* Does STA already exist? */
for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i;
if (((bitmap & BIT(0)) == BIT(0)) &&
(memcmp(addr, sta_addr, ETH_ALEN) == 0)) {
/* Remove from HW Security CAM */
memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN);
rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);
pr_info("&&&&&&&&&del entry %d\n", i);
}
}
return;
}
EXPORT_SYMBOL(stg_rtl_cam_del_entry);

View File

@@ -0,0 +1,52 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __RTL_CAM_H_
#define __RTL_CAM_H_
#define CAM_CONTENT_COUNT 8
#define CFG_DEFAULT_KEY BIT(5)
#define CFG_VALID BIT(15)
#define PAIRWISE_KEYIDX 0
#define CAM_PAIRWISE_KEY_POSITION 4
#define CAM_CONFIG_USEDK 1
#define CAM_CONFIG_NO_USEDK 0
void stg_rtl_cam_reset_all_entry(struct ieee80211_hw *hw);
u8 stg_rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
u32 ul_default_key, u8 *key_content);
int stg_rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
u32 ul_key_id);
void stg_rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index);
void stg_rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index);
void rtl92e_cam_reset_sec_info(struct ieee80211_hw *hw);
u8 stg_rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr);
void stg_rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr);
#endif

View File

@@ -0,0 +1,70 @@
#ifndef __RTL_COMPAT_H__
#define __RTL_COMPAT_H__
#define RX_FLAG_MACTIME_MPDU RX_FLAG_MACTIME_START
#define IEEE80211_KEY_FLAG_SW_MGMT IEEE80211_KEY_FLAG_SW_MGMT_TX
struct ieee80211_mgmt_compat {
__le16 frame_control;
__le16 duration;
u8 da[6];
u8 sa[6];
u8 bssid[6];
__le16 seq_ctrl;
union {
struct {
u8 category;
union {
struct {
u8 action_code;
u8 dialog_token;
u8 status_code;
u8 variable[0];
} __packed wme_action;
struct {
u8 action_code;
u8 dialog_token;
__le16 capab;
__le16 timeout;
__le16 start_seq_num;
} __packed addba_req;
struct{
u8 action_code;
u8 dialog_token;
__le16 status;
__le16 capab;
__le16 timeout;
} __packed addba_resp;
struct {
u8 action_code;
__le16 params;
__le16 reason_code;
} __packed delba;
struct {
u8 action_code;
/* capab_info for open and confirm,
* reason for close
*/
__le16 aux;
/* Followed in plink_confirm by status
* code, AID and supported rates,
* and directly by supported rates in
* plink_open and plink_close
*/
u8 variable[0];
} __packed plink_action;
struct {
u8 action_code;
u8 variable[0];
} __packed mesh_action;
struct {
u8 action;
u8 smps_control;
} __packed ht_smps;
} u;
} __packed action;
} u;
} __packed;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* Tmis program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* Tme full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __RTL_CORE_H__
#define __RTL_CORE_H__
#define RTL_SUPPORTED_FILTERS \
(FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | FIF_CONTROL | \
FIF_OTHER_BSS | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC)
#define RTL_SUPPORTED_CTRL_FILTER 0xFF
extern const struct ieee80211_ops rtl92e_ops;
#endif

View File

@@ -0,0 +1,978 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* Tmis program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#include "wifi.h"
#include "cam.h"
#define GET_INODE_DATA(__node) PDE_DATA(__node)
void rtl92e_dbgp_flag_init(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 i;
rtlpriv->dbg.global_debuglevel = DBG_DMESG;
rtlpriv->dbg.global_debugcomponents =
COMP_ERR |
COMP_FW |
COMP_INIT |
COMP_RECV |
COMP_SEND |
COMP_MLME |
COMP_SCAN |
COMP_INTR |
COMP_LED |
COMP_SEC |
COMP_BEACON |
COMP_RATE |
COMP_RXDESC |
COMP_DIG |
COMP_TXAGC |
COMP_POWER |
COMP_POWER_TRACKING |
COMP_BB_POWERSAVING |
COMP_SWAS |
COMP_RF |
COMP_TURBO |
COMP_RATR |
COMP_CMD |
COMP_EASY_CONCURRENT |
COMP_EFUSE |
COMP_QOS | COMP_MAC80211 | COMP_REGD |
COMP_CHAN |
COMP_BT_COEXIST |
COMP_IQK |
0;
for (i = 0; i < DBGP_TYPE_MAX; i++)
rtlpriv->dbg.dbgp_type[i] = 0;
/*Init Debug flag enable condition */
}
static struct proc_dir_entry *proc_topdir;
static int rtl_proc_get_mac_0(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i, n, page;
int max = 0xff;
page = 0x000;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_read_dword(rtlpriv, (page | n)));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_mac_0(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_mac_0, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_mac_0 = {
.open = dl_proc_open_mac_0,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_mac_1(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i, n, page;
int max = 0xff;
page = 0x100;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_read_dword(rtlpriv, (page | n)));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_mac_1(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_mac_1, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_mac_1 = {
.open = dl_proc_open_mac_1,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_mac_2(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i, n, page;
int max = 0xff;
page = 0x200;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_read_dword(rtlpriv, (page | n)));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_mac_2(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_mac_2, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_mac_2 = {
.open = dl_proc_open_mac_2,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_mac_3(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i, n, page;
int max = 0xff;
page = 0x300;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_read_dword(rtlpriv, (page | n)));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_mac_3(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_mac_3, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_mac_3 = {
.open = dl_proc_open_mac_3,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_mac_4(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i, n, page;
int max = 0xff;
page = 0x400;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_read_dword(rtlpriv, (page | n)));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_mac_4(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_mac_4, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_mac_4 = {
.open = dl_proc_open_mac_4,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_mac_5(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i, n, page;
int max = 0xff;
page = 0x500;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_read_dword(rtlpriv, (page | n)));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_mac_5(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_mac_5, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_mac_5 = {
.open = dl_proc_open_mac_5,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_mac_6(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i, n, page;
int max = 0xff;
page = 0x600;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_read_dword(rtlpriv, (page | n)));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_mac_6(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_mac_6, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_mac_6 = {
.open = dl_proc_open_mac_6,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_mac_7(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i, n, page;
int max = 0xff;
page = 0x700;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_read_dword(rtlpriv, (page | n)));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_mac_7(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_mac_7, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_mac_7 = {
.open = dl_proc_open_mac_7,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_bb_8(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n, page;
int max = 0xff;
page = 0x800;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_get_bbreg(hw, (page | n), 0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_bb_8(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_bb_8, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_bb_8 = {
.open = dl_proc_open_bb_8,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_bb_9(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n, page;
int max = 0xff;
page = 0x900;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_get_bbreg(hw, (page | n), 0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_bb_9(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_bb_9, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_bb_9 = {
.open = dl_proc_open_bb_9,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_bb_a(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n, page;
int max = 0xff;
page = 0xa00;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_get_bbreg(hw, (page | n), 0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_bb_a(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_bb_a, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_bb_a = {
.open = dl_proc_open_bb_a,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_bb_b(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n, page;
int max = 0xff;
page = 0xb00;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_get_bbreg(hw, (page | n), 0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_bb_b(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_bb_b, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_bb_b = {
.open = dl_proc_open_bb_b,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_bb_c(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n, page;
int max = 0xff;
page = 0xc00;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_get_bbreg(hw, (page | n), 0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_bb_c(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_bb_c, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_bb_c = {
.open = dl_proc_open_bb_c,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_bb_d(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n, page;
int max = 0xff;
page = 0xd00;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_get_bbreg(hw, (page | n), 0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_bb_d(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_bb_d, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_bb_d = {
.open = dl_proc_open_bb_d,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_bb_e(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n, page;
int max = 0xff;
page = 0xe00;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_get_bbreg(hw, (page | n), 0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_bb_e(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_bb_e, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_bb_e = {
.open = dl_proc_open_bb_e,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_bb_f(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n, page;
int max = 0xff;
page = 0xf00;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n + page);
for (i = 0; i < 4 && n <= max; i++, n += 4)
seq_printf(m, "%8.8x ",
rtl_get_bbreg(hw, (page | n), 0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_bb_f(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_bb_f, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_bb_f = {
.open = dl_proc_open_bb_f,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_reg_rf_a(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n;
int max = 0x40;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n);
for (i = 0; i < 4 && n <= max; n += 1, i++)
seq_printf(m, "%8.8x ",
rtl_get_rfreg(hw, RF90_PATH_A, n, 0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_rf_a(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_reg_rf_a, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_rf_a = {
.open = dl_proc_open_rf_a,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_reg_rf_b(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
int i, n;
int max = 0x40;
for (n = 0; n <= max; ) {
seq_printf(m, "\n%8.8x ", n);
for (i = 0; i < 4 && n <= max; n += 1, i++)
seq_printf(m, "%8.8x ",
rtl_get_rfreg(hw, RF90_PATH_B, n,
0xffffffff));
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_rf_b(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_reg_rf_b, GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_rf_b = {
.open = dl_proc_open_rf_b,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_cam_register_1(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 target_cmd = 0;
u32 target_val = 0;
u8 entry_i = 0;
u32 ulstatus;
int i = 100, j = 0;
/* This dump the current register page */
seq_puts(m,
"\n#################### SECURITY CAM (0-10) ##################\n ");
for (j = 0; j < 11; j++) {
seq_printf(m, "\nD: %2x > ", j);
for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
/* polling bit, and No Write enable, and address */
target_cmd = entry_i + CAM_CONTENT_COUNT * j;
target_cmd = target_cmd | BIT(31);
/* Check polling bit is clear */
while ((i--) >= 0) {
ulstatus = rtl_read_dword(rtlpriv,
rtlpriv->cfg->maps[RWCAM]);
if (ulstatus & BIT(31))
continue;
else
break;
}
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
target_cmd);
target_val = rtl_read_dword(rtlpriv,
rtlpriv->cfg->maps[RCAMO]);
seq_printf(m, "%8.8x ", target_val);
}
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_cam_1(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_cam_register_1,
GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_cam_1 = {
.open = dl_proc_open_cam_1,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_cam_register_2(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 target_cmd = 0;
u32 target_val = 0;
u8 entry_i = 0;
u32 ulstatus;
int i = 100, j = 0;
/* This dump the current register page */
seq_puts(m,
"\n################### SECURITY CAM (11-21) ##################\n ");
for (j = 11; j < 22; j++) {
seq_printf(m, "\nD: %2x > ", j);
for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
target_cmd = entry_i + CAM_CONTENT_COUNT * j;
target_cmd = target_cmd | BIT(31);
while ((i--) >= 0) {
ulstatus = rtl_read_dword(rtlpriv,
rtlpriv->cfg->maps[RWCAM]);
if (ulstatus & BIT(31))
continue;
else
break;
}
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
target_cmd);
target_val = rtl_read_dword(rtlpriv,
rtlpriv->cfg->maps[RCAMO]);
seq_printf(m, "%8.8x ", target_val);
}
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_cam_2(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_cam_register_2,
GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_cam_2 = {
.open = dl_proc_open_cam_2,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int rtl_proc_get_cam_register_3(struct seq_file *m, void *v)
{
struct ieee80211_hw *hw = m->private;
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 target_cmd = 0;
u32 target_val = 0;
u8 entry_i = 0;
u32 ulstatus;
int i = 100, j = 0;
/* This dump the current register page */
seq_puts(m,
"\n################### SECURITY CAM (22-31) ##################\n ");
for (j = 22; j < TOTAL_CAM_ENTRY; j++) {
seq_printf(m, "\nD: %2x > ", j);
for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
target_cmd = entry_i+CAM_CONTENT_COUNT*j;
target_cmd = target_cmd | BIT(31);
while ((i--) >= 0) {
ulstatus = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM]);
if (ulstatus & BIT(31))
continue;
else
break;
}
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
target_cmd);
target_val = rtl_read_dword(rtlpriv,
rtlpriv->cfg->maps[RCAMO]);
seq_printf(m, "%8.8x ", target_val);
}
}
seq_puts(m, "\n");
return 0;
}
static int dl_proc_open_cam_3(struct inode *inode, struct file *file)
{
return single_open(file, rtl_proc_get_cam_register_3,
GET_INODE_DATA(inode));
}
static const struct file_operations file_ops_cam_3 = {
.open = dl_proc_open_cam_3,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
void rtl_proc_add_one(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
struct proc_dir_entry *entry;
snprintf(rtlpriv->dbg.proc_name, 18, "%x-%x-%x-%x-%x-%x",
rtlefuse->dev_addr[0], rtlefuse->dev_addr[1],
rtlefuse->dev_addr[2], rtlefuse->dev_addr[3],
rtlefuse->dev_addr[4], rtlefuse->dev_addr[5]);
rtlpriv->dbg.proc_dir = proc_mkdir(rtlpriv->dbg.proc_name, proc_topdir);
if (!rtlpriv->dbg.proc_dir) {
RT_TRACE(COMP_INIT, DBG_EMERG,
("Unable to init /proc/net/%s/%s\n",
rtlpriv->cfg->name,
rtlpriv->dbg.proc_name));
return;
}
entry = proc_create_data("mac-0", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_mac_0, hw);
if (!entry)
RT_TRACE(COMP_INIT, DBG_EMERG,
("Unable to initialize /proc/net/%s/%s/mac-0\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("mac-1", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_mac_1, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/mac-1\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("mac-2", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_mac_2, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/mac-2\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("mac-3", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_mac_3, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/mac-3\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("mac-4", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_mac_4, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/mac-4\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("mac-5", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_mac_5, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/mac-5\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("mac-6", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_mac_6, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/mac-6\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("mac-7", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_mac_7, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/mac-7\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("bb-8", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_bb_8, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/bb-8\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("bb-9", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_bb_9, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/bb-9\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("bb-a", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_bb_a, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/bb-a\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("bb-b", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_bb_b, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/bb-b\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("bb-c", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_bb_c, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/bb-c\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("bb-d", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_bb_d, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/bb-d\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("bb-e", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_bb_e, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/bb-e\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("bb-f", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_bb_f, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/bb-f\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("rf-a", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_rf_a, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/rf-a\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("rf-b", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_rf_b, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/rf-b\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("cam-1", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_cam_1, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/cam-1\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("cam-2", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_cam_2, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/cam-2\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
entry = proc_create_data("cam-3", S_IFREG | S_IRUGO,
rtlpriv->dbg.proc_dir, &file_ops_cam_3, hw);
if (!entry)
RT_TRACE(COMP_INIT, COMP_ERR,
("Unable to initialize /proc/net/%s/%s/cam-3\n",
rtlpriv->cfg->name, rtlpriv->dbg.proc_name));
}
void rtl_proc_remove_one(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
if (rtlpriv->dbg.proc_dir) {
remove_proc_entry("mac-0", rtlpriv->dbg.proc_dir);
remove_proc_entry("mac-1", rtlpriv->dbg.proc_dir);
remove_proc_entry("mac-2", rtlpriv->dbg.proc_dir);
remove_proc_entry("mac-3", rtlpriv->dbg.proc_dir);
remove_proc_entry("mac-4", rtlpriv->dbg.proc_dir);
remove_proc_entry("mac-5", rtlpriv->dbg.proc_dir);
remove_proc_entry("mac-6", rtlpriv->dbg.proc_dir);
remove_proc_entry("mac-7", rtlpriv->dbg.proc_dir);
remove_proc_entry("bb-8", rtlpriv->dbg.proc_dir);
remove_proc_entry("bb-9", rtlpriv->dbg.proc_dir);
remove_proc_entry("bb-a", rtlpriv->dbg.proc_dir);
remove_proc_entry("bb-b", rtlpriv->dbg.proc_dir);
remove_proc_entry("bb-c", rtlpriv->dbg.proc_dir);
remove_proc_entry("bb-d", rtlpriv->dbg.proc_dir);
remove_proc_entry("bb-e", rtlpriv->dbg.proc_dir);
remove_proc_entry("bb-f", rtlpriv->dbg.proc_dir);
remove_proc_entry("rf-a", rtlpriv->dbg.proc_dir);
remove_proc_entry("rf-b", rtlpriv->dbg.proc_dir);
remove_proc_entry("cam-1", rtlpriv->dbg.proc_dir);
remove_proc_entry("cam-2", rtlpriv->dbg.proc_dir);
remove_proc_entry("cam-3", rtlpriv->dbg.proc_dir);
remove_proc_entry(rtlpriv->dbg.proc_name, proc_topdir);
rtlpriv->dbg.proc_dir = NULL;
}
}
void rtl_proc_add_topdir(void)
{
proc_topdir = proc_mkdir("rtlwifi", init_net.proc_net);
}
void rtl_proc_remove_topdir(void)
{
if (proc_topdir)
remove_proc_entry("rtlwifi", init_net.proc_net);
}

View File

@@ -0,0 +1,221 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* Tmis program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* Tmis program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* Tme full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __RTL_DEBUG_H__
#define __RTL_DEBUG_H__
/*--------------------------------------------------------------
Debug level
--------------------------------------------------------------*/
/*
*Fatal bug.
*For example, Tx/Rx/IO locked up,
*memory access violation,
*resource allocation failed,
*unexpected HW behavior, HW BUG
*and so on.
*/
#define DBG_EMERG 1
/*
*Abnormal, rare, or unexpeted cases.
*For example, Packet/IO Ctl canceled,
*device suprisely unremoved and so on.
*/
#define DBG_WARNING 2
/*
*Normal case driver developer should
*open, we can see link status like
*assoc/AddBA/DHCP/adapter start and
*so on basic and useful infromations.
*/
#define DBG_DMESG 3
/*
*Normal case with useful information
*about current SW or HW state.
*For example, Tx/Rx descriptor to fill,
*Tx/Rx descriptor completed status,
*SW protocol state change, dynamic
*mechanism state change and so on.
*/
#define DBG_LOUD 4
/*
*Normal case with detail execution
*flow or information.
*/
#define DBG_TRACE 5
/*--------------------------------------------------------------
Define the rt_trace components
--------------------------------------------------------------*/
#define COMP_ERR BIT(0)
#define COMP_FW BIT(1)
#define COMP_INIT BIT(2) /*For init/deinit */
#define COMP_RECV BIT(3) /*For Rx. */
#define COMP_SEND BIT(4) /*For Tx. */
#define COMP_MLME BIT(5) /*For MLME. */
#define COMP_SCAN BIT(6) /*For Scan. */
#define COMP_INTR BIT(7) /*For interrupt Related. */
#define COMP_LED BIT(8) /*For LED. */
#define COMP_SEC BIT(9) /*For sec. */
#define COMP_BEACON BIT(10) /*For beacon. */
#define COMP_RATE BIT(11) /*For rate. */
#define COMP_RXDESC BIT(12) /*For rx desc. */
#define COMP_DIG BIT(13) /*For DIG */
#define COMP_TXAGC BIT(14) /*For Tx power */
#define COMP_HIPWR BIT(15) /*For High Power Mechanism */
#define COMP_POWER BIT(16) /*For lps/ips/aspm. */
#define COMP_POWER_TRACKING BIT(17) /*For TX POWER TRACKING */
#define COMP_BB_POWERSAVING BIT(18)
#define COMP_SWAS BIT(19) /*For SW Antenna Switch */
#define COMP_RF BIT(20) /*For RF. */
#define COMP_TURBO BIT(21) /*For EDCA TURBO. */
#define COMP_RATR BIT(22)
#define COMP_CMD BIT(23)
#define COMP_EFUSE BIT(24)
#define COMP_QOS BIT(25)
#define COMP_MAC80211 BIT(26)
#define COMP_REGD BIT(27)
#define COMP_CHAN BIT(28)
#define COMP_EASY_CONCURRENT BIT(29)
#define COMP_BT_COEXIST BIT(30)
#define COMP_IQK BIT(31)
/*--------------------------------------------------------------
Define the rt_print components
--------------------------------------------------------------*/
/* Define EEPROM and EFUSE check module bit*/
#define EEPROM_W BIT(0)
#define EFUSE_PG BIT(1)
#define EFUSE_READ_ALL BIT(2)
/* Define init check for module bit*/
#define INIT_EEPROM BIT(0)
#define INIT_TxPower BIT(1)
#define INIT_IQK BIT(2)
#define INIT_RF BIT(3)
/* Define PHY-BB/RF/MAC check module bit */
#define PHY_BBR BIT(0)
#define PHY_BBW BIT(1)
#define PHY_RFR BIT(2)
#define PHY_RFW BIT(3)
#define PHY_MACR BIT(4)
#define PHY_MACW BIT(5)
#define PHY_ALLR BIT(6)
#define PHY_ALLW BIT(7)
#define PHY_TXPWR BIT(8)
#define PHY_PWRDIFF BIT(9)
/* Define Dynamic Mechanism check module bit --> FDM */
#define WA_IOT BIT(0)
#define DM_PWDB BIT(1)
#define DM_MONITOR BIT(2)
#define DM_DIG BIT(3)
#define DM_EDCA_TURBO BIT(4)
enum dbgp_flag_e {
FQOS = 0,
FTX = 1,
FRX = 2,
FSEC = 3,
FMGNT = 4,
FMLME = 5,
FRESOURCE = 6,
FBEACON = 7,
FISR = 8,
FPHY = 9,
FMP = 10,
FEEPROM = 11,
FPWR = 12,
FDM = 13,
FDBGCtrl = 14,
FC2H = 15,
FBT = 16,
FINIT = 17,
FIOCTL = 18,
DBGP_TYPE_MAX
};
#define RT_ASSERT(_exp , fmt) \
do { \
if (!(_exp)) { \
pr_debug("%s:%s(): ", KBUILD_MODNAME, \
__func__); \
pr_cont fmt; \
} \
} while (0)
#define RT_TRACE(comp, level, fmt)\
do { \
if (unlikely(((comp) & rtlpriv->dbg.global_debugcomponents) && \
((level) <= rtlpriv->dbg.global_debuglevel))) {\
pr_debug("%s-%d:%s():<%lx> ", \
KBUILD_MODNAME, \
rtlpriv->rtlhal.interfaceindex, __func__, \
in_interrupt()); \
pr_cont fmt; \
} \
} while (0)
#define RTPRINT(rtlpriv, dbgtype, dbgflag, fmt, ...) \
do { \
if (unlikely(rtlpriv->dbg.dbgp_type[dbgtype] & dbgflag)) { \
pr_debug(KBUILD_MODNAME ": " fmt, \
##__VA_ARGS__); \
} \
} while (0)
#define RT_PRINT_DATA(rtlpriv, _comp, _level, _titlestring, _hexdata, \
_hexdatalen) \
do {\
if (unlikely(((_comp) & rtlpriv->dbg.global_debugcomponents) &&\
(_level <= rtlpriv->dbg.global_debuglevel))) { \
int __i; \
u8 *ptr = (u8 *)_hexdata; \
pr_debug("%s: ", KBUILD_MODNAME); \
pr_cont("In process \"%s\" (pid %i):", \
current->comm, \
current->pid); \
pr_cont(_titlestring); \
for (__i = 0; __i < (int)_hexdatalen; __i++) { \
pr_cont("%02X%s", ptr[__i], (((__i + 1) % 4) \
== 0) ? " " : " ");\
if (((__i + 1) % 16) == 0) \
pr_cont("\n"); \
} \
pr_cont("\n"); \
} \
} while (0)
void rtl92e_dbgp_flag_init(struct ieee80211_hw *hw);
void rtl_proc_add_one(struct ieee80211_hw *hw);
void rtl_proc_remove_one(struct ieee80211_hw *hw);
void rtl_proc_add_topdir(void);
void rtl_proc_remove_topdir(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __RTL_EFUSE_H_
#define __RTL_EFUSE_H_
#define EFUSE_IC_ID_OFFSET 506
/*
#define EFUSE_REAL_CONTENT_LEN 512
#define EFUSE_MAP_LEN 128
#define EFUSE_MAX_SECTION 16
#define EFUSE_MAX_WORD_UNIT 4
#define EFUSE_IC_ID_OFFSET 506
*/
#define EFUSE_MAX_WORD_UNIT 4
#define EFUSE_INIT_MAP 0
#define EFUSE_MODIFY_MAP 1
#define PG_STATE_HEADER 0x01
#define PG_STATE_WORD_0 0x02
#define PG_STATE_WORD_1 0x04
#define PG_STATE_WORD_2 0x08
#define PG_STATE_WORD_3 0x10
#define PG_STATE_DATA 0x20
#define PG_SWBYTE_H 0x01
#define PG_SWBYTE_L 0x02
#define _POWERON_DELAY_
#define _PRE_EXECUTE_READ_CMD_
#define EFUSE_REPEAT_THRESHOLD_ 3
#define EFUSE_ERROE_HANDLE 1
struct efuse_map {
u8 offset;
u8 word_start;
u8 byte_start;
u8 byte_cnts;
};
struct pgpkt_struct {
u8 offset;
u8 word_en;
u8 data[8];
};
enum efuse_data_item {
EFUSE_CHIP_ID = 0,
EFUSE_LDO_SETTING,
EFUSE_CLK_SETTING,
EFUSE_SDIO_SETTING,
EFUSE_CCCR,
EFUSE_SDIO_MODE,
EFUSE_OCR,
EFUSE_F0CIS,
EFUSE_F1CIS,
EFUSE_MAC_ADDR,
EFUSE_EEPROM_VER,
EFUSE_CHAN_PLAN,
EFUSE_TXPW_TAB
};
enum {
VOLTAGE_V25 = 0x03,
LDOE25_SHIFT = 28,
};
struct efuse_priv {
u8 id[2];
u8 ldo_setting[2];
u8 clk_setting[2];
u8 cccr;
u8 sdio_mode;
u8 ocr[3];
u8 cis0[17];
u8 cis1[48];
u8 mac_addr[6];
u8 eeprom_verno;
u8 channel_plan;
u8 tx_power_b[14];
u8 tx_power_g[14];
};
void read92e_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf);
void efuse92e_initialize(struct ieee80211_hw *hw);
u8 stg_efuse_read_1byte(struct ieee80211_hw *hw, u16 address);
int stg_efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data);
void efuse92e_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value);
void read92e_efuse(struct ieee80211_hw *hw, u16 _offset,
u16 _size_byte, u8 *pbuf);
void efuse92e_shadow_read(struct ieee80211_hw *hw, u8 type,
u16 offset, u32 *value);
void efuse92e_shadow_write(struct ieee80211_hw *hw, u8 type,
u16 offset, u32 value);
bool efuse92e_shadow_update(struct ieee80211_hw *hw);
bool efuse92e_shadow_update_chk(struct ieee80211_hw *hw);
void stg_rtl_efuse92e_shadow_map_update(struct ieee80211_hw *hw);
void efuse92e_force_write_vendor_Id(struct ieee80211_hw *hw);
void efuse92e_re_pg_section(struct ieee80211_hw *hw, u8 section_idx);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,342 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __RTL_PCI_H__
#define __RTL_PCI_H__
#include <linux/pci.h>
/*
1: MSDU packet queue,
2: Rx Command Queue
*/
#define RTL_PCI_RX_MPDU_QUEUE 0
#define RTL_PCI_RX_CMD_QUEUE 1
#define RTL_PCI_MAX_RX_QUEUE 2
#define RTL_PCI_MAX_RX_COUNT 512/*64*/
#define RTL_PCI_MAX_TX_QUEUE_COUNT 9
#define RT_TXDESC_NUM 128
#define TX_DESC_NUM_92E 512
#define RT_TXDESC_NUM_BE_QUEUE 256
#define BK_QUEUE 0
#define BE_QUEUE 1
#define VI_QUEUE 2
#define VO_QUEUE 3
#define BEACON_QUEUE 4
#define TXCMD_QUEUE 5
#define MGNT_QUEUE 6
#define HIGH_QUEUE 7
#define HCCA_QUEUE 8
#define RTL_PCI_DEVICE(vend, dev, cfg) \
.vendor = (vend), \
.device = (dev), \
.subvendor = PCI_ANY_ID, \
.subdevice = PCI_ANY_ID,\
.driver_data = (kernel_ulong_t)&(cfg)
#define INTEL_VENDOR_ID 0x8086
#define SIS_VENDOR_ID 0x1039
#define ATI_VENDOR_ID 0x1002
#define ATI_DEVICE_ID 0x7914
#define AMD_VENDOR_ID 0x1022
#define PCI_MAX_BRIDGE_NUMBER 255
#define PCI_MAX_DEVICES 32
#define PCI_MAX_FUNCTION 8
#define PCI_CONF_ADDRESS 0x0CF8 /*PCI Configuration Space Address */
#define PCI_CONF_DATA 0x0CFC /*PCI Configuration Space Data */
#define PCI_CLASS_BRIDGE_DEV 0x06
#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04
#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10
#define PCI_CAP_ID_EXP 0x10
#define U1DONTCARE 0xFF
#define U2DONTCARE 0xFFFF
#define U4DONTCARE 0xFFFFFFFF
#define RTL_PCI_8192_DID 0x8192 /*8192 PCI-E */
#define RTL_PCI_8192SE_DID 0x8192 /*8192 SE */
#define RTL_PCI_8174_DID 0x8174 /*8192 SE */
#define RTL_PCI_8173_DID 0x8173 /*8191 SE Crab */
#define RTL_PCI_8172_DID 0x8172 /*8191 SE RE */
#define RTL_PCI_8171_DID 0x8171 /*8191 SE Unicron */
#define RTL_PCI_0045_DID 0x0045 /*8190 PCI for Ceraga */
#define RTL_PCI_0046_DID 0x0046 /*8190 Cardbus for Ceraga */
#define RTL_PCI_0044_DID 0x0044 /*8192e PCIE for Ceraga */
#define RTL_PCI_0047_DID 0x0047 /*8192e Express Card for Ceraga */
#define RTL_PCI_700F_DID 0x700F
#define RTL_PCI_701F_DID 0x701F
#define RTL_PCI_DLINK_DID 0x3304
#define RTL_PCI_8723AE_DID 0x8723 /*8723e */
#define RTL_PCI_8192CET_DID 0x8191 /*8192ce */
#define RTL_PCI_8192CE_DID 0x8178 /*8192ce */
#define RTL_PCI_8191CE_DID 0x8177 /*8192ce */
#define RTL_PCI_8188CE_DID 0x8176 /*8192ce */
#define RTL_PCI_8192CU_DID 0x8191 /*8192ce */
#define RTL_PCI_8192DE_DID 0x8193 /*8192de */
#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/
#define RTL_PCI_8188EE_DID 0x8179 /*8188ee*/
#define RTL_PCI_8723BE_DID 0xB723 /*8723be*/
#define RTL_PCI_8192EE_DID 0x818B /*8192ee*/
#define RTL_PCI_8821AE_DID 0x8821 /*8821ae*/
#define RTL_PCI_8812AE_DID 0x8812 /*8812ae*/
/*8192 support 16 pages of IO registers*/
#define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000
#define RTL_MEM_MAPPED_IO_RANGE_8192PCIE 0x4000
#define RTL_MEM_MAPPED_IO_RANGE_8192SE 0x4000
#define RTL_MEM_MAPPED_IO_RANGE_8192CE 0x4000
#define RTL_MEM_MAPPED_IO_RANGE_8192DE 0x4000
#define RTL_PCI_REVISION_ID_8190PCI 0x00
#define RTL_PCI_REVISION_ID_8192PCIE 0x01
#define RTL_PCI_REVISION_ID_8192SE 0x10
#define RTL_PCI_REVISION_ID_8192CE 0x1
#define RTL_PCI_REVISION_ID_8192DE 0x0
#define RTL_DEFAULT_HARDWARE_TYPE HARDWARE_TYPE_RTL8192CE
enum pci_bridge_vendor {
PCI_BRIDGE_VENDOR_INTEL = 0x0, /*0b'0000,0001 */
PCI_BRIDGE_VENDOR_ATI, /*0b'0000,0010*/
PCI_BRIDGE_VENDOR_AMD, /*0b'0000,0100*/
PCI_BRIDGE_VENDOR_SIS, /*0b'0000,1000*/
PCI_BRIDGE_VENDOR_UNKNOWN, /*0b'0100,0000*/
PCI_BRIDGE_VENDOR_MAX,
};
struct rtl_pci_capabilities_header {
u8 capability_id;
u8 next;
};
/* In new TRX flow, Buffer_desc is new concept
* But TX wifi info == TX descriptor in old flow
* RX wifi info == RX descriptor in old flow */
struct rtl_tx_buffer_desc {
#if (RTL8192EE_SEG_NUM == 2)
u32 dword[2*(DMA_IS_64BIT + 1)*8]; /*seg = 8*/
#elif (RTL8192EE_SEG_NUM == 1)
u32 dword[2*(DMA_IS_64BIT + 1)*4]; /*seg = 4*/
#elif (RTL8192EE_SEG_NUM == 0)
u32 dword[2*(DMA_IS_64BIT + 1)*2]; /*seg = 2*/
#endif
} __packed;
struct rtl_tx_desc {/*old: tx desc new: tx wifi info*/
u32 dword[16];
} __packed;
struct rtl_rx_buffer_desc { /*rx buffer desc*/
u32 dword[2];
} __packed;
struct rtl_rx_desc { /*old: rx desc new: rx wifi info*/
u32 dword[8];
} __packed;
struct rtl_tx_cmd_desc {
u32 dword[16];
} __packed;
struct rtl8192_tx_ring {
struct rtl_tx_desc *desc; /*tx desc / tx wifi info*/
dma_addr_t dma; /*tx desc dma memory / tx wifi info dma memory*/
unsigned int idx;
unsigned int entries;
struct sk_buff_head queue;
/*add for new trx flow*/
struct rtl_tx_buffer_desc *buffer_desc; /*tx buffer descriptor*/
dma_addr_t buffer_desc_dma; /*tx bufferd desc dma memory*/
u16 avl_desc; /* available_desc_to_write */
u16 cur_tx_wp; /* current_tx_write_point */
u16 cur_tx_rp; /* current_tx_read_point */
};
struct rtl8192_rx_ring {
struct rtl_rx_desc *desc;/*for old trx flow, not uesd in new trx*/
/*dma matches either 'desc' or 'buffer_desc'*/
dma_addr_t dma;
unsigned int idx;
struct sk_buff *rx_buf[RTL_PCI_MAX_RX_COUNT];
/*add for new trx flow*/
struct rtl_rx_buffer_desc *buffer_desc; /*rx buffer descriptor*/
u16 next_rx_rp; /* next_rx_read_point */
};
struct rtl_pci {
struct pci_dev *pdev;
bool irq_enabled;
/*Tx */
struct rtl8192_tx_ring tx_ring[RTL_PCI_MAX_TX_QUEUE_COUNT];
int txringcount[RTL_PCI_MAX_TX_QUEUE_COUNT];
u32 transmit_config;
/*Rx */
struct rtl8192_rx_ring rx_ring[RTL_PCI_MAX_RX_QUEUE];
int rxringcount;
u16 rxbuffersize;
u32 receive_config;
/*irq */
u8 irq_alloc;
u32 irq_mask[2];
u32 sys_irq_mask;
/*Bcn control register setting */
u32 reg_bcn_ctrl_val;
/*ASPM*/ u8 const_pci_aspm;
u8 const_amdpci_aspm;
u8 const_hwsw_rfoff_d3;
u8 const_support_pciaspm;
/*pci-e bridge */
u8 const_hostpci_aspm_setting;
/*pci-e device */
u8 const_devicepci_aspm_setting;
/*If it supports ASPM, Offset[560h] = 0x40,
otherwise Offset[560h] = 0x00. */
bool b_support_aspm;
bool b_support_backdoor;
/*QOS & EDCA */
enum acm_method acm_method;
u16 shortretry_limit;
u16 longretry_limit;
/* MSI support */
bool msi_support;
bool using_msi;
};
struct mp_adapter {
u8 linkctrl_reg;
u8 busnumber;
u8 devnumber;
u8 funcnumber;
u8 pcibridge_busnum;
u8 pcibridge_devnum;
u8 pcibridge_funcnum;
u8 pcibridge_vendor;
u16 pcibridge_vendorid;
u16 pcibridge_deviceid;
u32 pcicfg_addrport;
u8 num4bytes;
u8 pcibridge_pciehdr_offset;
u8 pcibridge_linkctrlreg;
bool amd_l1_patch;
};
struct rtl_pci_priv {
struct rtl_pci dev;
struct mp_adapter ndis_adapter;
struct rtl_led_ctl ledctl;
struct bt_coexist_info btcoexist;
};
#define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv))
#define rtl_pcidev(pcipriv) (&((pcipriv)->dev))
int rtl92e_pci_reset_trx_ring(struct ieee80211_hw *hw);
extern struct rtl_intf_ops rtl92e_pci_ops;
int stg_rtl_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
void stg_rtl_pci_disconnect(struct pci_dev *pdev);
int stg_rtl_pci_suspend(struct device *dev);
int stg_rtl_pci_resume(struct device *dev);
static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
{
return 0xff & readb((u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
}
static inline u16 pci_read16_sync(struct rtl_priv *rtlpriv, u32 addr)
{
return readw((u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
}
static inline u32 pci_read32_sync(struct rtl_priv *rtlpriv, u32 addr)
{
return readl((u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
}
static inline void pci_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val)
{
writeb(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
}
static inline void pci_write16_async(struct rtl_priv *rtlpriv,
u32 addr, u16 val)
{
writew(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
}
static inline void pci_write32_async(struct rtl_priv *rtlpriv,
u32 addr, u32 val)
{
writel(val, (u8 __iomem *)rtlpriv->io.pci_mem_start + addr);
}
static inline void rtl_pci_raw_write_port_ulong(u32 port, u32 val)
{
outl(val, port);
}
static inline void rtl_pci_raw_write_port_uchar(u32 port, u8 val)
{
outb(val, port);
}
static inline void rtl_pci_raw_read_port_uchar(u32 port, u8 *pval)
{
*pval = inb(port);
}
static inline void rtl_pci_raw_read_port_ushort(u32 port, u16 *pval)
{
*pval = inw(port);
}
static inline void rtl_pci_raw_read_port_ulong(u32 port, u32 *pval)
{
*pval = inl(port);
}
#endif

View File

@@ -0,0 +1,983 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#include "wifi.h"
#include "base.h"
#include "ps.h"
#include "btcoexist/rtl_btc.h"
bool stg_rtl_ps_enable_nic(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
bool init_status = true;
/*<1> reset trx ring */
if (rtlhal->interface == INTF_PCI)
rtlpriv->intf_ops->reset_trx_ring(hw);
if (is_hal_stop(rtlhal))
RT_TRACE(COMP_ERR, DBG_WARNING, ("Driver is already down!\n"));
/*<2> Enable Adapter */
rtlpriv->cfg->ops->hw_init(hw);
RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
/*init_status = false; */
/*<3> Enable Interrupt */
rtlpriv->cfg->ops->enable_interrupt(hw);
/*<enable timer> */
rtl92e_watch_dog_timer_callback((unsigned long)hw);
return init_status;
}
EXPORT_SYMBOL(stg_rtl_ps_enable_nic);
bool stg_rtl_ps_disable_nic(struct ieee80211_hw *hw)
{
bool status = true;
struct rtl_priv *rtlpriv = rtl_priv(hw);
/*<1> Stop all timer */
rtl92e_deinit_deferred_work(hw);
/*<2> Disable Interrupt */
rtlpriv->cfg->ops->disable_interrupt(hw);
/*<3> Disable Adapter */
rtlpriv->cfg->ops->hw_disable(hw);
return status;
}
EXPORT_SYMBOL(stg_rtl_ps_disable_nic);
bool stg_rtl_ps_set_rf_state(struct ieee80211_hw *hw,
enum rf_pwrstate state_toset,
u32 changesource, bool protect_or_not)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
enum rf_pwrstate rtstate;
bool b_actionallowed = false;
u16 rfwait_cnt = 0;
/*protect_or_not = true; */
if (protect_or_not)
goto no_protect;
/*
*Only one thread can change
*the RF state at one time, and others
*should wait to be executed.
*/
while (true) {
spin_lock(&rtlpriv->locks.rf_ps_lock);
if (ppsc->rfchange_inprogress) {
spin_unlock(&rtlpriv->locks.rf_ps_lock);
RT_TRACE(COMP_ERR, DBG_WARNING,
("RF Change in progress! Wait to set..state_toset(%d)\n",
state_toset));
/* Set RF after the previous action is done. */
while (ppsc->rfchange_inprogress) {
rfwait_cnt++;
mdelay(1);
/*
*Wait too long, return false to avoid
*to be stuck here.
*/
if (rfwait_cnt > 100)
return false;
}
} else {
ppsc->rfchange_inprogress = true;
spin_unlock(&rtlpriv->locks.rf_ps_lock);
break;
}
}
no_protect:
rtstate = ppsc->rfpwr_state;
switch (state_toset) {
case ERFON:
ppsc->rfoff_reason &= (~changesource);
if ((changesource == RF_CHANGE_BY_HW) &&
(ppsc->b_hwradiooff)) {
ppsc->b_hwradiooff = false;
}
if (!ppsc->rfoff_reason) {
ppsc->rfoff_reason = 0;
b_actionallowed = true;
}
break;
case ERFOFF:
if ((changesource == RF_CHANGE_BY_HW) &&
(!ppsc->b_hwradiooff)) {
ppsc->b_hwradiooff = true;
}
ppsc->rfoff_reason |= changesource;
b_actionallowed = true;
break;
case ERFSLEEP:
ppsc->rfoff_reason |= changesource;
b_actionallowed = true;
break;
default:
RT_TRACE(COMP_ERR, DBG_EMERG, ("switch case not process\n"));
break;
}
if (b_actionallowed)
rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
if (!protect_or_not) {
spin_lock(&rtlpriv->locks.rf_ps_lock);
ppsc->rfchange_inprogress = false;
spin_unlock(&rtlpriv->locks.rf_ps_lock);
}
return b_actionallowed;
}
EXPORT_SYMBOL(stg_rtl_ps_set_rf_state);
static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
ppsc->b_swrf_processing = true;
if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) {
if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
rtlhal->interface == INTF_PCI) {
rtlpriv->intf_ops->disable_aspm(hw);
RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
}
}
stg_rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
RF_CHANGE_BY_IPS, false);
if (ppsc->inactive_pwrstate == ERFOFF &&
rtlhal->interface == INTF_PCI) {
if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
!RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
rtlpriv->intf_ops->enable_aspm(hw);
RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
}
}
ppsc->b_swrf_processing = false;
}
void rtl92e_ips_nic_off_wq_callback(void *data)
{
struct rtl_works *rtlworks =
container_of_dwork_rtl(data, struct rtl_works, ips_nic_off_wq);
struct ieee80211_hw *hw = rtlworks->hw;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
enum rf_pwrstate rtstate;
if (mac->opmode != NL80211_IFTYPE_STATION) {
RT_TRACE(COMP_ERR, DBG_WARNING, ("not station return\n"));
return;
}
if (mac->p2p_in_use)
return;
if (mac->link_state > MAC80211_NOLINK)
return;
if (is_hal_stop(rtlhal))
return;
if (rtlpriv->sec.being_setkey)
return;
if (rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps)
rtlpriv->cfg->ops->bt_turn_off_bt_coexist_before_enter_lps(hw);
if (ppsc->b_inactiveps) {
rtstate = ppsc->rfpwr_state;
/*
*Do not enter IPS in the following conditions:
*(1) RF is already OFF or Sleep
*(2) b_swrf_processing (indicates the IPS is still under going)
*(3) Connectted (only disconnected can trigger IPS)
*(4) IBSS (send Beacon)
*(5) AP mode (send Beacon)
*(6) monitor mode (rcv packet)
*/
if (rtstate == ERFON &&
!ppsc->b_swrf_processing &&
(mac->link_state == MAC80211_NOLINK) &&
!mac->act_scanning) {
RT_TRACE(COMP_RF, DBG_LOUD,
("IPSEnter(): Turn off RF.\n"));
ppsc->inactive_pwrstate = ERFOFF;
ppsc->b_in_powersavemode = true;
/* call before RF off */
if (rtlpriv->cfg->ops->get_btc_status())
rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
ppsc->inactive_pwrstate);
/*rtl92e_pci_reset_trx_ring(hw); */
_rtl_ps_inactive_ps(hw);
}
}
}
void rtl92e_ips_nic_off(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
/*
*because when link with ap, mac80211 will ask us
*to disable nic quickly after scan before linking,
*this will cause link failed, so we delay 100ms here
*/
queue_delayed_work(rtlpriv->works.rtl_wq,
&rtlpriv->works.ips_nic_off_wq, MSECS(100));
}
/* NOTICE: any opmode should exc nic_on, or disable without
* nic_on may something wrong, like adhoc TP*/
void rtl92e_ips_nic_on(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
enum rf_pwrstate rtstate;
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
spin_lock(&rtlpriv->locks.ips_lock);
if (ppsc->b_inactiveps) {
rtstate = ppsc->rfpwr_state;
if (rtstate != ERFON &&
!ppsc->b_swrf_processing &&
ppsc->rfoff_reason <= RF_CHANGE_BY_IPS) {
ppsc->inactive_pwrstate = ERFON;
ppsc->b_in_powersavemode = false;
_rtl_ps_inactive_ps(hw);
/* call after RF on */
if (rtlpriv->cfg->ops->get_btc_status())
rtlpriv->btcoexist.btc_ops->btc_ips_notify(rtlpriv,
ppsc->inactive_pwrstate);
}
}
spin_unlock(&rtlpriv->locks.ips_lock);
}
/*for FW LPS*/
/*
*Determine if we can set Fw into PS mode
*in current condition.Return true if it
*can enter PS mode.
*/
static bool rtl_get_fwlps_doze(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
u32 ps_timediff;
ps_timediff = jiffies_to_msecs(jiffies -
ppsc->last_delaylps_stamp_jiffies);
if (ps_timediff < 2000) {
RT_TRACE(COMP_POWER, DBG_LOUD,
("Delay enter Fw LPS for DHCP, ARP, or EAPOL exchanging state\n"));
return false;
}
if (mac->link_state != MAC80211_LINKED)
return false;
if (mac->opmode == NL80211_IFTYPE_ADHOC)
return false;
return true;
}
/* Change current and default preamble mode.*/
void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
bool enter_fwlps;
if (mac->opmode == NL80211_IFTYPE_ADHOC)
return;
if (mac->link_state != MAC80211_LINKED)
return;
if (ppsc->dot11_psmode == rt_psmode)
return;
/* Update power save mode configured. */
ppsc->dot11_psmode = rt_psmode;
/*
*<FW control LPS>
*1. Enter PS mode
* Set RPWM to Fw to turn RF off and send H2C fw_pwrmode
* cmd to set Fw into PS mode.
*2. Leave PS mode
* Send H2C fw_pwrmode cmd to Fw to set Fw into Active
* mode and set RPWM to turn RF on.
*/
if ((ppsc->b_fwctrl_lps) && ppsc->report_linked) {
if (ppsc->dot11_psmode == EACTIVE) {
RT_TRACE(COMP_RF, DBG_DMESG,
("FW LPS leave ps_mode:%x\n",
FW_PS_ACTIVE_MODE));
enter_fwlps = false;
ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
ppsc->smart_ps = 0;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_LPS_ACTION,
(u8 *)(&enter_fwlps));
if (ppsc->p2p_ps_info.opp_ps)
rtl92e_p2p_ps_cmd(hw , P2P_PS_ENABLE);
if (rtlpriv->cfg->ops->get_btc_status())
rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode);
} else {
if (rtl_get_fwlps_doze(hw)) {
RT_TRACE(COMP_RF, DBG_DMESG,
("FW LPS enter ps_mode:%x\n",
ppsc->fwctrl_psmode));
if (rtlpriv->cfg->ops->get_btc_status())
rtlpriv->btcoexist.btc_ops->btc_lps_notify(rtlpriv, rt_psmode);
enter_fwlps = true;
ppsc->pwr_mode = ppsc->fwctrl_psmode;
ppsc->smart_ps = 2;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_FW_LPS_ACTION,
(u8 *)(&enter_fwlps));
} else {
/* Reset the power save related parameters. */
ppsc->dot11_psmode = EACTIVE;
}
}
}
}
/*Enter the leisure power save mode.*/
void rtl92e_lps_enter(struct ieee80211_hw *hw)
{
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_priv *rtlpriv = rtl_priv(hw);
unsigned long flag;
if (!ppsc->b_fwctrl_lps)
return;
if (rtlpriv->sec.being_setkey)
return;
if (rtlpriv->link_info.b_busytraffic)
return;
/*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
if (mac->cnt_after_linked < 5)
return;
if (mac->opmode == NL80211_IFTYPE_ADHOC)
return;
if (mac->link_state != MAC80211_LINKED)
return;
spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
/* Idle for a while if we connect to AP a while ago. */
if (mac->cnt_after_linked >= 2) {
if (ppsc->dot11_psmode == EACTIVE) {
RT_TRACE(COMP_POWER, DBG_LOUD,
("Enter 802.11 power save mode...\n"));
rtl_lps_set_psmode(hw, EAUTOPS);
}
}
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
}
EXPORT_SYMBOL(rtl92e_lps_enter);
/*Leave the leisure power save mode.*/
void rtl92e_lps_leave(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
unsigned long flag;
spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
if (ppsc->b_fwctrl_lps) {
if (ppsc->dot11_psmode != EACTIVE) {
if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
rtlhal->interface == INTF_PCI) {
rtlpriv->intf_ops->disable_aspm(hw);
RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
}
RT_TRACE(COMP_POWER, DBG_LOUD,
("Busy Traffic,Leave 802.11 power save..\n"));
rtl_lps_set_psmode(hw, EACTIVE);
}
}
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
}
EXPORT_SYMBOL(rtl92e_lps_leave);
/* For sw LPS*/
void rtl92e_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct ieee80211_hdr *hdr = (void *)data;
struct ieee80211_tim_ie *tim_ie;
u8 *tim;
u8 tim_len;
bool u_buffed;
bool m_buffed;
if (mac->opmode != NL80211_IFTYPE_STATION)
return;
if (!rtlpriv->psc.b_swctrl_lps)
return;
if (rtlpriv->mac80211.link_state != MAC80211_LINKED)
return;
if (!rtlpriv->psc.sw_ps_enabled)
return;
if (rtlpriv->psc.b_fwctrl_lps)
return;
if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
return;
/* check if this really is a beacon */
if (!ieee80211_is_beacon(hdr->frame_control))
return;
/* min. beacon length + FCS_LEN */
if (len <= 40 + FCS_LEN)
return;
/* and only beacons from the associated BSSID, please */
if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
return;
rtlpriv->psc.last_beacon = jiffies;
tim = rtl92e_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
if (!tim)
return;
if (tim[1] < sizeof(*tim_ie))
return;
tim_len = tim[1];
tim_ie = (struct ieee80211_tim_ie *)&tim[2];
if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period))
rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
/* Check whenever the PHY can be turned off again. */
/* 1. What about buffered unicast traffic for our AID? */
u_buffed = ieee80211_check_tim(tim_ie, tim_len,
rtlpriv->mac80211.assoc_id);
/* 2. Maybe the AP wants to send multicast/broadcast data? */
m_buffed = tim_ie->bitmap_ctrl & 0x01;
rtlpriv->psc.multi_buffered = m_buffed;
/* unicast will process by mac80211 through
* set ~IEEE80211_CONF_PS, So we just check
* multicast frames here */
if (!m_buffed) {/*&&) { !rtlpriv->psc.tx_doing) { */
/* back to low-power land. and delay is
* prevent null power save frame tx fail */
queue_delayed_work(rtlpriv->works.rtl_wq,
&rtlpriv->works.ps_work, MSECS(5));
} else {
RT_TRACE(COMP_POWER, DBG_DMESG,
("u_bufferd: %x, m_buffered: %x\n",
u_buffed, m_buffed));
}
}
void rtl92e_swlps_rf_awake(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
unsigned long flag;
if (!rtlpriv->psc.b_swctrl_lps)
return;
if (mac->link_state != MAC80211_LINKED)
return;
if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
rtlpriv->intf_ops->disable_aspm(hw);
RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
}
spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
stg_rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false);
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
}
void rtl92e_swlps_rfon_wq_callback(void *data)
{
struct rtl_works *rtlworks =
container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq);
struct ieee80211_hw *hw = rtlworks->hw;
rtl92e_swlps_rf_awake(hw);
}
void rtl92e_swlps_rf_sleep(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
unsigned long flag;
u8 sleep_intv;
if (!rtlpriv->psc.sw_ps_enabled)
return;
if ((rtlpriv->sec.being_setkey) ||
(mac->opmode == NL80211_IFTYPE_ADHOC))
return;
/*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5))
return;
if (rtlpriv->link_info.b_busytraffic)
return;
spin_lock(&rtlpriv->locks.rf_ps_lock);
if (rtlpriv->psc.rfchange_inprogress) {
spin_unlock(&rtlpriv->locks.rf_ps_lock);
return;
}
spin_unlock(&rtlpriv->locks.rf_ps_lock);
spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
stg_rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS , false);
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
!RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
rtlpriv->intf_ops->enable_aspm(hw);
RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
}
/* here is power save alg, when this beacon is DTIM
* we will set sleep time to dtim_period * n;
* when this beacon is not DTIM, we will set sleep
* time to sleep_intv = rtlpriv->psc.dtim_counter or
* MAX_SW_LPS_SLEEP_INTV(default set to 5) */
if (rtlpriv->psc.dtim_counter == 0) {
if (hw->conf.ps_dtim_period == 1)
sleep_intv = hw->conf.ps_dtim_period * 2;
else
sleep_intv = hw->conf.ps_dtim_period;
} else {
sleep_intv = rtlpriv->psc.dtim_counter;
}
if (sleep_intv > MAX_SW_LPS_SLEEP_INTV)
sleep_intv = MAX_SW_LPS_SLEEP_INTV;
/* this print should always be dtim_conter = 0 &
* sleep = dtim_period, that meaons, we should
* awake before every dtim */
RT_TRACE(COMP_POWER, DBG_DMESG,
("dtim_counter:%x will sleep :%d beacon_intv\n",
rtlpriv->psc.dtim_counter, sleep_intv));
/* we tested that 40ms is enough for sw & hw sw delay */
queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq,
MSECS(sleep_intv*mac->vif->bss_conf.beacon_int-40));
}
void rtl92e_swlps_wq_callback(void *data)
{
struct rtl_works *rtlworks =
container_of_dwork_rtl(data, struct rtl_works, ps_work);
struct ieee80211_hw *hw = rtlworks->hw;
struct rtl_priv *rtlpriv = rtl_priv(hw);
bool ps = false;
ps = (hw->conf.flags & IEEE80211_CONF_PS);
/* we can sleep after ps null send ok */
if (rtlpriv->psc.state_inap) {
rtl92e_swlps_rf_sleep(hw);
if (rtlpriv->psc.state && !ps) {
rtlpriv->psc.sleep_ms =
jiffies_to_msecs(jiffies -
rtlpriv->psc.last_action);
}
if (ps)
rtlpriv->psc.last_slept = jiffies;
rtlpriv->psc.last_action = jiffies;
rtlpriv->psc.state = ps;
}
}
static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_mgmt *mgmt = (void *)data;
struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
u8 *pos, *end, *ie;
u16 noa_len;
static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
u8 noa_num, index , i, noa_index = 0;
bool find_p2p_ie = false , find_p2p_ps_ie = false;
pos = (u8 *)mgmt->u.beacon.variable;
end = data + len;
ie = NULL;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
return;
if (pos[0] == 221 && pos[1] > 4) {
if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
ie = pos + 2+4;
break;
}
}
pos += 2 + pos[1];
}
if (ie == NULL)
return;
find_p2p_ie = true;
/*to find noa ie*/
while (ie + 1 < end) {
noa_len = READEF2BYTE((__le16 *)&ie[1]);
if (ie + 3 + ie[1] > end)
return;
if (ie[0] == 12) {
find_p2p_ps_ie = true;
if ((noa_len - 2) % 13 != 0) {
RT_TRACE(COMP_INIT, DBG_LOUD,
("P2P notice of absence: invalid length%d\n",
noa_len));
return;
} else {
noa_num = (noa_len - 2) / 13;
}
noa_index = ie[3];
if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
RT_TRACE(COMP_FW, DBG_LOUD,
("update NOA ie.\n"));
p2pinfo->noa_index = noa_index;
p2pinfo->opp_ps = (ie[4] >> 7);
p2pinfo->ctwindow = ie[4] & 0x7F;
p2pinfo->noa_num = noa_num;
index = 5;
for (i = 0; i < noa_num; i++) {
p2pinfo->noa_count_type[i] =
READEF1BYTE(ie+index);
index += 1;
p2pinfo->noa_duration[i] =
READEF4BYTE((__le32 *)ie+index);
index += 4;
p2pinfo->noa_interval[i] =
READEF4BYTE((__le32 *)ie+index);
index += 4;
p2pinfo->noa_start_time[i] =
READEF4BYTE((__le32 *)ie+index);
index += 4;
}
if (p2pinfo->opp_ps == 1) {
p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
/* Driver should wait LPS
* entering CTWindow*/
if (rtlpriv->psc.b_fw_current_inpsmode) {
rtl92e_p2p_ps_cmd(hw,
P2P_PS_ENABLE);
}
} else if (p2pinfo->noa_num > 0) {
p2pinfo->p2p_ps_mode = P2P_PS_NOA;
rtl92e_p2p_ps_cmd(hw, P2P_PS_ENABLE);
} else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE);
}
}
break;
}
ie += 3 + noa_len;
}
if (find_p2p_ie) {
if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
(!find_p2p_ps_ie))
rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE);
}
}
static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_mgmt *mgmt = (void *)data;
struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
bool find_p2p_ie = false, find_p2p_ps_ie = false;
u8 noa_num, index, i, noa_index = 0;
u8 *pos, *end, *ie;
u16 noa_len;
static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
pos = (u8 *)&mgmt->u.action.category;
end = data + len;
ie = NULL;
if (pos[0] == 0x7f) {
if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0)
ie = pos + 3+4;
}
if (ie == NULL)
return;
find_p2p_ie = true;
RT_TRACE(COMP_FW, DBG_LOUD, ("action frame find P2P IE.\n"));
/*to find noa ie*/
while (ie + 1 < end) {
noa_len = READEF2BYTE((__le16 *)&ie[1]);
if (ie + 3 + ie[1] > end)
return;
if (ie[0] == 12) {
RT_TRACE(COMP_FW, DBG_LOUD, ("find NOA IE\n"));
RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ",
ie, noa_len);
find_p2p_ps_ie = true;
if ((noa_len - 2) % 13 != 0) {
RT_TRACE(COMP_FW, DBG_LOUD,
("P2P notice of absence: invalid length%d\n",
noa_len));
return;
} else {
noa_num = (noa_len - 2) / 13;
}
noa_index = ie[3];
if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
P2P_PS_NONE ||
noa_index != p2pinfo->noa_index) {
p2pinfo->noa_index = noa_index;
p2pinfo->opp_ps = (ie[4] >> 7);
p2pinfo->ctwindow = ie[4] & 0x7F;
p2pinfo->noa_num = noa_num;
index = 5;
for (i = 0; i < noa_num; i++) {
p2pinfo->noa_count_type[i] =
READEF1BYTE(ie+index);
index += 1;
p2pinfo->noa_duration[i] =
READEF4BYTE((__le32 *)ie+index);
index += 4;
p2pinfo->noa_interval[i] =
READEF4BYTE((__le32 *)ie+index);
index += 4;
p2pinfo->noa_start_time[i] =
READEF4BYTE((__le32 *)ie+index);
index += 4;
}
if (p2pinfo->opp_ps == 1) {
p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
/* Driver should wait LPS
* entering CTWindow */
if (rtlpriv->psc.b_fw_current_inpsmode) {
rtl92e_p2p_ps_cmd(hw,
P2P_PS_ENABLE);
}
} else if (p2pinfo->noa_num > 0) {
p2pinfo->p2p_ps_mode = P2P_PS_NOA;
rtl92e_p2p_ps_cmd(hw, P2P_PS_ENABLE);
} else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
rtl92e_p2p_ps_cmd(hw, P2P_PS_DISABLE);
}
}
break;
}
ie += 3 + noa_len;
}
}
void rtl92e_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
RT_TRACE(COMP_FW, DBG_LOUD, ("p2p state %x\n", p2p_ps_state));
switch (p2p_ps_state) {
case P2P_PS_DISABLE:
p2pinfo->p2p_ps_state = p2p_ps_state;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
(u8 *)(&p2p_ps_state));
p2pinfo->noa_index = 0;
p2pinfo->ctwindow = 0;
p2pinfo->opp_ps = 0;
p2pinfo->noa_num = 0;
p2pinfo->p2p_ps_mode = P2P_PS_NONE;
if (rtlps->b_fw_current_inpsmode) {
if (rtlps->smart_ps == 0) {
rtlps->smart_ps = 2;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_PWRMODE,
(u8 *)(&rtlps->pwr_mode));
}
}
break;
case P2P_PS_ENABLE:
if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
p2pinfo->p2p_ps_state = p2p_ps_state;
if (p2pinfo->ctwindow > 0) {
if (rtlps->smart_ps != 0) {
rtlps->smart_ps = 0;
rtlpriv->cfg->ops->set_hw_reg(
hw, HW_VAR_H2C_FW_PWRMODE,
(u8 *)(&rtlps->pwr_mode));
}
}
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
(u8 *)(&p2p_ps_state));
}
break;
case P2P_PS_SCAN:
case P2P_PS_SCAN_DONE:
case P2P_PS_ALLSTASLEEP:
if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
p2pinfo->p2p_ps_state = p2p_ps_state;
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
(u8 *)(&p2p_ps_state));
}
break;
default:
break;
}
RT_TRACE(COMP_FW, DBG_LOUD, (" ctwindow %x oppps %x\n",
p2pinfo->ctwindow , p2pinfo->opp_ps));
RT_TRACE(COMP_FW, DBG_LOUD,
("count %x duration %x index %x interval %x start time %x noa num %x\n",
p2pinfo->noa_count_type[0],
p2pinfo->noa_duration[0],
p2pinfo->noa_index,
p2pinfo->noa_interval[0],
p2pinfo->noa_start_time[0],
p2pinfo->noa_num));
RT_TRACE(COMP_FW, DBG_LOUD, ("end\n"));
}
void rtl92e_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct ieee80211_hdr *hdr = (void *)data;
if (!mac->p2p)
return;
if (mac->link_state != MAC80211_LINKED)
return;
/* min. beacon length + FCS_LEN */
if (len <= 40 + FCS_LEN)
return;
/* and only beacons from the associated BSSID, please */
if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
return;
/* check if this really is a beacon */
if (!(ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control) ||
ieee80211_is_action(hdr->frame_control)))
return;
if (ieee80211_is_action(hdr->frame_control))
rtl_p2p_action_ie(hw , data , len - FCS_LEN);
else
rtl_p2p_noa_ie(hw , data , len - FCS_LEN);
}

View File

@@ -0,0 +1,52 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __REALTEK_RTL_PCI_PS_H__
#define __REALTEK_RTL_PCI_PS_H__
#define MAX_SW_LPS_SLEEP_INTV 5
bool stg_rtl_ps_set_rf_state(struct ieee80211_hw *hw,
enum rf_pwrstate state_toset, u32 changesource,
bool protect_or_not);
bool stg_rtl_ps_enable_nic(struct ieee80211_hw *hw);
bool stg_rtl_ps_disable_nic(struct ieee80211_hw *hw);
void rtl92e_ips_nic_off(struct ieee80211_hw *hw);
void rtl92e_ips_nic_on(struct ieee80211_hw *hw);
void rtl92e_ips_nic_off_wq_callback(void *data);
void rtl92e_lps_enter(struct ieee80211_hw *hw);
void rtl92e_lps_leave(struct ieee80211_hw *hw);
void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode);
void rtl92e_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len);
void rtl92e_swlps_wq_callback(void *data);
void rtl92e_swlps_rfon_wq_callback(void *data);
void rtl92e_swlps_rf_awake(struct ieee80211_hw *hw);
void rtl92e_swlps_rf_sleep(struct ieee80211_hw *hw);
void rtl92e_p2p_ps_cmd(struct ieee80211_hw *hw , u8 p2p_ps_state);
void rtl92e_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
#endif

View File

@@ -0,0 +1,288 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#include "wifi.h"
#include "base.h"
#include "rc.h"
/*
*Finds the highest rate index we can use
*if skb is special data like DHCP/EAPOL, we set should
*it to lowest rate CCK_1M, otherwise we set rate to
*highest rate based on wireless mode used for iwconfig
*show Tx rate.
*/
static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
struct ieee80211_sta *sta,
struct sk_buff *skb, bool not_data)
{
struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_sta_info *sta_entry = NULL;
u8 wireless_mode = 0;
/*
*this rate is no use for true rate, firmware
*will control rate at all it just used for
*1.show in iwconfig in B/G mode
*2.in stg_rtl_get_tcb_desc when we check rate is
* 1M we will not use FW rate but user rate.
*/
if (sta) {
sta_entry = (struct rtl_sta_info *)sta->drv_priv;
wireless_mode = sta_entry->wireless_mode;
}
if (rtl92e_is_special_data(rtlpriv->mac80211.hw, skb, true) ||
not_data) {
return 0;
} else {
if (rtlhal->current_bandtype == BAND_ON_2_4G) {
if (wireless_mode == WIRELESS_MODE_B) {
return B_MODE_MAX_RIX;
} else if (wireless_mode == WIRELESS_MODE_G) {
return G_MODE_MAX_RIX;
} else if (wireless_mode == WIRELESS_MODE_N_24G) {
if (get_rf_type(rtlphy) != RF_2T2R)
return N_MODE_MCS7_RIX;
else
return N_MODE_MCS15_RIX;
} else if (wireless_mode == WIRELESS_MODE_AC_24G) {
return AC_MODE_MCS9_RIX;
} else {
return 0;
}
} else {
if (wireless_mode == WIRELESS_MODE_A) {
return A_MODE_MAX_RIX;
} else if (wireless_mode == WIRELESS_MODE_N_5G) {
if (get_rf_type(rtlphy) != RF_2T2R)
return N_MODE_MCS7_RIX;
else
return N_MODE_MCS15_RIX;
} else if (wireless_mode == WIRELESS_MODE_AC_5G) {
return AC_MODE_MCS9_RIX;
} else {
return 0;
}
}
}
}
static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
struct ieee80211_sta *sta,
struct ieee80211_tx_rate *rate,
struct ieee80211_tx_rate_control *txrc,
u8 tries, char rix, int rtsctsenable,
bool not_data)
{
struct rtl_mac *mac = rtl_mac(rtlpriv);
u8 sgi_20 = 0, sgi_40 = 0, sgi_80 = 0;
if (sta) {
sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80;
}
rate->count = tries;
rate->idx = rix >= 0x00 ? rix : 0x00;
if (!not_data) {
if (txrc->short_preamble)
rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC) {
if (sta && (sta->ht_cap.cap &
IEEE80211_HT_CAP_SUP_WIDTH_20_40))
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (sta && (sta->vht_cap.vht_supported))
rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
} else {
if (mac->bw_40)
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (mac->bw_80)
rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
}
if (sgi_20 || sgi_40 || sgi_80)
rate->flags |= IEEE80211_TX_RC_SHORT_GI;
if (sta && sta->ht_cap.ht_supported)
rate->flags |= IEEE80211_TX_RC_MCS;
if (sta && sta->vht_cap.vht_supported)
rate->flags |= IEEE80211_TX_RC_VHT_MCS;
}
}
static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta,
void *priv_sta,
struct ieee80211_tx_rate_control *txrc)
{
struct rtl_priv *rtlpriv = ppriv;
struct sk_buff *skb = txrc->skb;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rates = tx_info->control.rates;
__le16 fc = rtl_get_fc(skb);
u8 try_per_rate, i, rix;
bool not_data = !ieee80211_is_data(fc);
if (rate_control_send_low(sta, priv_sta, txrc))
return;
rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data);
try_per_rate = 1;
_rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc,
try_per_rate, rix, 1, not_data);
if (!not_data) {
for (i = 1; i < 4; i++)
_rtl_rc_rate_set_series(rtlpriv, sta, &rates[i],
txrc, i, (rix - i), 1,
not_data);
}
}
static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv,
struct rtl_sta_info *sta_entry, u16 tid)
{
struct rtl_mac *mac = rtl_mac(rtlpriv);
if (mac->act_scanning)
return false;
if (mac->opmode == NL80211_IFTYPE_STATION &&
mac->cnt_after_linked < 3)
return false;
if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP)
return true;
return false;
}
/*mac80211 Rate Control callbacks*/
static void rtl_tx_status(void *ppriv,
struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta,
struct sk_buff *skb)
{
struct rtl_priv *rtlpriv = ppriv;
struct rtl_mac *mac = rtl_mac(rtlpriv);
struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
__le16 fc = rtl_get_fc(skb);
struct rtl_sta_info *sta_entry;
if (!priv_sta || !ieee80211_is_data(fc))
return;
if (rtl92e_is_special_data(mac->hw, skb, true))
return;
if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
return;
if (sta) {
/* Check if aggregation has to be enabled for this tid */
sta_entry = (struct rtl_sta_info *)sta->drv_priv;
if ((sta->ht_cap.ht_supported) &&
!(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
if (ieee80211_is_data_qos(fc)) {
u8 tid = rtl_get_tid(skb);
if (_rtl_tx_aggr_check(rtlpriv, sta_entry,
tid)) {
sta_entry->tids[tid].agg.agg_state =
RTL_AGG_PROGRESS;
ieee80211_start_tx_ba_session(sta, tid,
5000);
}
}
}
}
}
static void rtl_rate_init(void *ppriv,
struct ieee80211_supported_band *sband,
struct cfg80211_chan_def *chandef,
struct ieee80211_sta *sta, void *priv_sta)
{
}
static void *rtl_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
return rtlpriv;
}
static void rtl_rate_free(void *rtlpriv)
{
return;
}
static void *rtl_rate_alloc_sta(void *ppriv,
struct ieee80211_sta *sta, gfp_t gfp)
{
struct rtl_priv *rtlpriv = ppriv;
struct rtl_rate_priv *rate_priv;
rate_priv = kzalloc(sizeof(*rate_priv), gfp);
if (!rate_priv) {
RT_TRACE(COMP_ERR, DBG_EMERG,
("Unable to allocate private rc structure\n"));
return NULL;
}
rtlpriv->rate_priv = rate_priv;
return rate_priv;
}
static void rtl_rate_free_sta(void *rtlpriv,
struct ieee80211_sta *sta, void *priv_sta)
{
struct rtl_rate_priv *rate_priv = priv_sta;
kfree(rate_priv);
}
static struct rate_control_ops rtl_rate_ops = {
.name = "rtl_rc",
.alloc = rtl_rate_alloc,
.free = rtl_rate_free,
.alloc_sta = rtl_rate_alloc_sta,
.free_sta = rtl_rate_free_sta,
.rate_init = rtl_rate_init,
.tx_status = rtl_tx_status,
.get_rate = rtl_get_rate,
};
int rtl92e_rate_control_register(void)
{
return ieee80211_rate_control_register(&rtl_rate_ops);
}
void rtl92e_rate_control_unregister(void)
{
ieee80211_rate_control_unregister(&rtl_rate_ops);
}

View File

@@ -0,0 +1,47 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __RTL_RC_H__
#define __RTL_RC_H__
#define B_MODE_MAX_RIX 3
#define G_MODE_MAX_RIX 11
#define A_MODE_MAX_RIX 7
/* in mac80211 mcs0-mcs15 is idx0-idx15*/
#define N_MODE_MCS7_RIX 7
#define N_MODE_MCS15_RIX 15
#define AC_MODE_MCS7_RIX 7
#define AC_MODE_MCS8_RIX 8
#define AC_MODE_MCS9_RIX 9
struct rtl_rate_priv {
u8 ht_cap;
};
int rtl92e_rate_control_register(void);
void rtl92e_rate_control_unregister(void);
#endif

View File

@@ -0,0 +1,448 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#include "wifi.h"
#include "regd.h"
static struct country_code_to_enum_rd allcountries[] = {
{COUNTRY_CODE_FCC, "US"},
{COUNTRY_CODE_IC, "US"},
{COUNTRY_CODE_ETSI, "EC"},
{COUNTRY_CODE_SPAIN, "EC"},
{COUNTRY_CODE_FRANCE, "EC"},
{COUNTRY_CODE_MKK, "JP"},
{COUNTRY_CODE_MKK1, "JP"},
{COUNTRY_CODE_ISRAEL, "EC"},
{COUNTRY_CODE_TELEC, "JP"},
{COUNTRY_CODE_MIC, "JP"},
{COUNTRY_CODE_GLOBAL_DOMAIN, "JP"},
{COUNTRY_CODE_WORLD_WIDE_13, "EC"},
{COUNTRY_CODE_TELEC_NETGEAR, "EC"},
};
/*
*Only these channels all allow active
*scan on all world regulatory domains
*/
#define RTL819x_2GHZ_CH01_11 \
REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
/*
*We enable active scan on these a case
*by case basis by regulatory domain
*/
#define RTL819x_2GHZ_CH12_13 \
REG_RULE(2467-10, 2472+10, 40, 0, 20,\
NL80211_RRF_PASSIVE_SCAN)
#define RTL819x_2GHZ_CH14 \
REG_RULE(2484-10, 2484+10, 40, 0, 20, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_OFDM)
/* 5G chan 36 - chan 64*/
#define RTL819x_5GHZ_5150_5350 \
REG_RULE(5150-10, 5350+10, 80, 0, 30, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
/* 5G chan 100 - chan 165*/
#define RTL819x_5GHZ_5470_5850 \
REG_RULE(5470-10, 5850+10, 80, 0, 30, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
/* 5G chan 149 - chan 165*/
#define RTL819x_5GHZ_5725_5850 \
REG_RULE(5725-10, 5850+10, 80, 0, 30, \
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_IBSS)
#define RTL819x_5GHZ_ALL \
(RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
static const struct ieee80211_regdomain rtl_regdom_11 = {
.n_reg_rules = 1,
.alpha2 = "99",
.reg_rules = {
RTL819x_2GHZ_CH01_11,
}
};
static const struct ieee80211_regdomain rtl_regdom_12_13 = {
.n_reg_rules = 2,
.alpha2 = "99",
.reg_rules = {
RTL819x_2GHZ_CH01_11,
RTL819x_2GHZ_CH12_13,
}
};
static const struct ieee80211_regdomain rtl_regdom_no_midband = {
.n_reg_rules = 3,
.alpha2 = "99",
.reg_rules = {
RTL819x_2GHZ_CH01_11,
RTL819x_5GHZ_5150_5350,
RTL819x_5GHZ_5725_5850,
}
};
static const struct ieee80211_regdomain rtl_regdom_60_64 = {
.n_reg_rules = 3,
.alpha2 = "99",
.reg_rules = {
RTL819x_2GHZ_CH01_11,
RTL819x_2GHZ_CH12_13,
RTL819x_5GHZ_5725_5850,
}
};
static const struct ieee80211_regdomain rtl_regdom_14_60_64 = {
.n_reg_rules = 4,
.alpha2 = "99",
.reg_rules = {
RTL819x_2GHZ_CH01_11,
RTL819x_2GHZ_CH12_13,
RTL819x_2GHZ_CH14,
RTL819x_5GHZ_5725_5850,
}
};
static const struct ieee80211_regdomain rtl_regdom_14 = {
.n_reg_rules = 3,
.alpha2 = "99",
.reg_rules = {
RTL819x_2GHZ_CH01_11,
RTL819x_2GHZ_CH12_13,
RTL819x_2GHZ_CH14,
}
};
static bool _rtl_is_radar_freq(u16 center_freq)
{
return center_freq >= 5260 && center_freq <= 5700;
}
static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator)
{
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
const struct ieee80211_reg_rule *reg_rule;
struct ieee80211_channel *ch;
unsigned int i;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!wiphy->bands[band])
continue;
sband = wiphy->bands[band];
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
if (_rtl_is_radar_freq(ch->center_freq) ||
(ch->flags & IEEE80211_CHAN_RADAR))
continue;
if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
reg_rule = freq_reg_info(wiphy,
ch->center_freq);
if (IS_ERR(reg_rule))
continue;
/*
*If 11d had a rule for this channel ensure
*we enable adhoc/beaconing if it allows us to
*use it. Note that we would have disabled it
*by applying our static world regdomain by
*default during init, prior to calling our
*regulatory_hint().
*/
if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
if (!(reg_rule->flags &
NL80211_RRF_PASSIVE_SCAN))
ch->flags &=
~IEEE80211_CHAN_PASSIVE_SCAN;
} else {
if (ch->beacon_found)
ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN);
}
}
}
}
/* Allows active scan scan on Ch 12 and 13 */
static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator
initiator)
{
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
const struct ieee80211_reg_rule *reg_rule;
if (!wiphy->bands[IEEE80211_BAND_2GHZ])
return;
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
/*
*If no country IE has been received always enable active scan
*on these channels. This is only done for specific regulatory SKUs
*/
if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
ch = &sband->channels[11]; /* CH 12 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
ch = &sband->channels[12]; /* CH 13 */
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
return;
}
/*
*If a country IE has been recieved check its rule for this
*channel first before enabling active scan. The passive scan
*would have been enforced by the initial processing of our
*custom regulatory domain.
*/
ch = &sband->channels[11]; /* CH 12 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
}
ch = &sband->channels[12]; /* CH 13 */
reg_rule = freq_reg_info(wiphy, ch->center_freq);
if (!IS_ERR(reg_rule)) {
if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
}
}
/*
*Always apply Radar/DFS rules on
*freq range 5260 MHz - 5700 MHz
*/
static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy)
{
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
unsigned int i;
if (!wiphy->bands[IEEE80211_BAND_5GHZ])
return;
sband = wiphy->bands[IEEE80211_BAND_5GHZ];
for (i = 0; i < sband->n_channels; i++) {
ch = &sband->channels[i];
if (!_rtl_is_radar_freq(ch->center_freq))
continue;
/*
*We always enable radar detection/DFS on this
*frequency range. Additionally we also apply on
*this frequency range:
*- If STA mode does not yet have DFS supports disable
* active scanning
*- If adhoc mode does not support DFS yet then disable
* adhoc in the frequency.
*- If AP mode does not yet support radar detection/DFS
*do not allow AP mode
*/
if (!(ch->flags & IEEE80211_CHAN_DISABLED))
ch->flags |= IEEE80211_CHAN_RADAR |
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_PASSIVE_SCAN;
}
}
static void _rtl_reg_apply_world_flags(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator,
struct rtl_regulatory *reg)
{
_rtl_reg_apply_beaconing_flags(wiphy, initiator);
_rtl_reg_apply_active_scan_flags(wiphy, initiator);
return;
}
static void _rtl_dump_channel_map(struct wiphy *wiphy)
{
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
unsigned int i;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!wiphy->bands[band])
continue;
sband = wiphy->bands[band];
for (i = 0; i < sband->n_channels; i++)
ch = &sband->channels[i];
}
}
static int _rtl92e_reg_notifier_apply(struct wiphy *wiphy,
struct regulatory_request *request,
struct rtl_regulatory *reg)
{
/* We always apply this */
_rtl_reg_apply_radar_flags(wiphy);
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_DRIVER:
case NL80211_REGDOM_SET_BY_CORE:
case NL80211_REGDOM_SET_BY_USER:
break;
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
_rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
break;
}
_rtl_dump_channel_map(wiphy);
return 0;
}
static const struct ieee80211_regdomain *_rtl_regdomain_select(
struct rtl_regulatory *reg)
{
switch (reg->country_code) {
case COUNTRY_CODE_FCC:
return &rtl_regdom_no_midband;
case COUNTRY_CODE_IC:
return &rtl_regdom_11;
case COUNTRY_CODE_ETSI:
case COUNTRY_CODE_TELEC_NETGEAR:
return &rtl_regdom_60_64;
case COUNTRY_CODE_SPAIN:
case COUNTRY_CODE_FRANCE:
case COUNTRY_CODE_ISRAEL:
case COUNTRY_CODE_WORLD_WIDE_13:
return &rtl_regdom_12_13;
case COUNTRY_CODE_MKK:
case COUNTRY_CODE_MKK1:
case COUNTRY_CODE_TELEC:
case COUNTRY_CODE_MIC:
return &rtl_regdom_14_60_64;
case COUNTRY_CODE_GLOBAL_DOMAIN:
return &rtl_regdom_14;
default:
return &rtl_regdom_no_midband;
}
}
static int _rtl92e_regd_init_wiphy(struct rtl_regulatory *reg,
struct wiphy *wiphy,
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *
request))
{
const struct ieee80211_regdomain *regd;
wiphy->reg_notifier = reg_notifier;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
regd = _rtl_regdomain_select(reg);
wiphy_apply_custom_regulatory(wiphy, regd);
_rtl_reg_apply_radar_flags(wiphy);
_rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
return 0;
}
static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
{
int i;
for (i = 0; i < ARRAY_SIZE(allcountries); i++) {
if (allcountries[i].countrycode == countrycode)
return &allcountries[i];
}
return NULL;
}
int rtl92e_regd_init(struct ieee80211_hw *hw,
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request))
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct wiphy *wiphy = hw->wiphy;
struct country_code_to_enum_rd *country = NULL;
if (wiphy == NULL || &rtlpriv->regd == NULL)
return -EINVAL;
/* init country_code from efuse channel plan */
rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan;
RT_TRACE(COMP_REGD, DBG_TRACE,
(KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n",
rtlpriv->regd.country_code));
if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) {
RT_TRACE(COMP_REGD, DBG_DMESG,
("rtl: EEPROM indicates invalid contry code world wide 13 should be used\n"));
rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
}
country = _rtl_regd_find_country(rtlpriv->regd.country_code);
if (country) {
rtlpriv->regd.alpha2[0] = country->iso_name[0];
rtlpriv->regd.alpha2[1] = country->iso_name[1];
} else {
rtlpriv->regd.alpha2[0] = '0';
rtlpriv->regd.alpha2[1] = '0';
}
RT_TRACE(COMP_REGD, DBG_TRACE,
(KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n",
rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1]));
_rtl92e_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier);
return 0;
}
void rtl92e_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct rtl_priv *rtlpriv = rtl_priv(hw);
RT_TRACE(COMP_REGD, DBG_LOUD, ("\n"));
_rtl92e_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
}

View File

@@ -0,0 +1,63 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __RTL_REGD_H__
#define __RTL_REGD_H__
/* for kernel 3.14 , both value are changed to IEEE80211_CHAN_NO_IR*/
#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR
#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR
struct country_code_to_enum_rd {
u16 countrycode;
const char *iso_name;
};
enum country_code_type_t {
COUNTRY_CODE_FCC = 0,
COUNTRY_CODE_IC = 1,
COUNTRY_CODE_ETSI = 2,
COUNTRY_CODE_SPAIN = 3,
COUNTRY_CODE_FRANCE = 4,
COUNTRY_CODE_MKK = 5,
COUNTRY_CODE_MKK1 = 6,
COUNTRY_CODE_ISRAEL = 7,
COUNTRY_CODE_TELEC = 8,
COUNTRY_CODE_MIC = 9,
COUNTRY_CODE_GLOBAL_DOMAIN = 10,
COUNTRY_CODE_WORLD_WIDE_13 = 11,
COUNTRY_CODE_TELEC_NETGEAR = 12,
/*add new channel plan above this line */
COUNTRY_CODE_MAX
};
int rtl92e_regd_init(struct ieee80211_hw *hw,
void (*reg_notifier)(struct wiphy *wiphy,
struct regulatory_request *request));
void rtl92e_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request);
#endif

View File

@@ -0,0 +1,290 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#include "wifi.h"
#include "stats.h"
u8 stg_rtl_query_rxpwrpercentage(char antpower)
{
if ((antpower <= -100) || (antpower >= 20))
return 0;
else if (antpower >= 0)
return 100;
else
return 100 + antpower;
}
EXPORT_SYMBOL(stg_rtl_query_rxpwrpercentage);
u8 stg_rtl_evm_db_to_percentage(char value)
{
char ret_val;
ret_val = value;
if (ret_val >= 0)
ret_val = 0;
if (ret_val <= -33)
ret_val = -33;
ret_val = 0 - ret_val;
ret_val *= 3;
if (ret_val == 99)
ret_val = 100;
return ret_val;
}
EXPORT_SYMBOL(stg_rtl_evm_db_to_percentage);
u8 rtl_evm_dbm_jaguar(char value)
{
char ret_val;
ret_val = value;
/* -33dB~0dB to 33dB ~ 0dB*/
if (ret_val == -128)
ret_val = 127;
else if (ret_val < 0)
ret_val = 0 - ret_val;
ret_val = ret_val >> 1;
return ret_val;
}
EXPORT_SYMBOL(rtl_evm_dbm_jaguar);
static long rtl_translate_todbm(struct ieee80211_hw *hw,
u8 signal_strength_index)
{
long signal_power;
signal_power = (long)((signal_strength_index + 1) >> 1);
signal_power -= 95;
return signal_power;
}
long stg_rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig)
{
long retsig;
if (currsig >= 61 && currsig <= 100)
retsig = 90 + ((currsig - 60) / 4);
else if (currsig >= 41 && currsig <= 60)
retsig = 78 + ((currsig - 40) / 2);
else if (currsig >= 31 && currsig <= 40)
retsig = 66 + (currsig - 30);
else if (currsig >= 21 && currsig <= 30)
retsig = 54 + (currsig - 20);
else if (currsig >= 5 && currsig <= 20)
retsig = 42 + (((currsig - 5) * 2) / 3);
else if (currsig == 4)
retsig = 36;
else if (currsig == 3)
retsig = 27;
else if (currsig == 2)
retsig = 18;
else if (currsig == 1)
retsig = 9;
else
retsig = currsig;
return retsig;
}
EXPORT_SYMBOL(stg_rtl_signal_scale_mapping);
static void rtl_process_ui_rssi(struct ieee80211_hw *hw, struct rtl_stats *pstatus)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
u8 rfpath;
u32 last_rssi, tmpval;
if (!pstatus->b_packet_toself && !pstatus->b_packet_beacon)
return;
rtlpriv->stats.pwdb_all_cnt += pstatus->rx_pwdb_all;
rtlpriv->stats.rssi_calculate_cnt++;
if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) {
rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX;
last_rssi = rtlpriv->stats.ui_rssi.elements[
rtlpriv->stats.ui_rssi.index];
rtlpriv->stats.ui_rssi.total_val -= last_rssi;
}
rtlpriv->stats.ui_rssi.total_val += pstatus->signalstrength;
rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] =
pstatus->signalstrength;
if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
rtlpriv->stats.ui_rssi.index = 0;
tmpval = rtlpriv->stats.ui_rssi.total_val /
rtlpriv->stats.ui_rssi.total_num;
rtlpriv->stats.signal_strength = rtl_translate_todbm(hw,
(u8) tmpval);
pstatus->rssi = rtlpriv->stats.signal_strength;
if (pstatus->b_is_cck)
return;
for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
rfpath++) {
if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
rtlpriv->stats.rx_rssi_percentage[rfpath] =
pstatus->rx_mimo_signalstrength[rfpath];
}
if (pstatus->rx_mimo_signalstrength[rfpath] >
rtlpriv->stats.rx_rssi_percentage[rfpath]) {
rtlpriv->stats.rx_rssi_percentage[rfpath] =
((rtlpriv->stats.rx_rssi_percentage[rfpath] *
(RX_SMOOTH_FACTOR - 1)) +
(pstatus->rx_mimo_signalstrength[rfpath])) /
(RX_SMOOTH_FACTOR);
rtlpriv->stats.rx_rssi_percentage[rfpath] =
rtlpriv->stats.rx_rssi_percentage[rfpath] + 1;
} else {
rtlpriv->stats.rx_rssi_percentage[rfpath] =
((rtlpriv->stats.rx_rssi_percentage[rfpath] *
(RX_SMOOTH_FACTOR - 1)) +
(pstatus->rx_mimo_signalstrength[rfpath])) /
(RX_SMOOTH_FACTOR);
}
rtlpriv->stats.rx_snr_db[rfpath] = pstatus->rx_snr[rfpath];
rtlpriv->stats.rx_evm_dbm[rfpath] =
pstatus->rx_mimo_evm_dbm[rfpath];
rtlpriv->stats.rx_cfo_short[rfpath] =
pstatus->cfo_short[rfpath];
rtlpriv->stats.rx_cfo_tail[rfpath] = pstatus->cfo_tail[rfpath];
}
}
static void rtl_update_rxsignalstatistics(struct ieee80211_hw *hw,
struct rtl_stats *pstatus)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
int weighting = 0;
if (rtlpriv->stats.recv_signal_power == 0)
rtlpriv->stats.recv_signal_power = pstatus->recvsignalpower;
if (pstatus->recvsignalpower > rtlpriv->stats.recv_signal_power)
weighting = 5;
else if (pstatus->recvsignalpower < rtlpriv->stats.recv_signal_power)
weighting = (-5);
rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power *
5 + pstatus->recvsignalpower + weighting) / 6;
}
static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_sta_info *drv_priv = NULL;
struct ieee80211_sta *sta = NULL;
long undecorated_smoothed_pwdb;
rcu_read_lock();
if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
sta = rtl_find_sta(hw, pstatus->psaddr);
/* adhoc or ap mode */
if (sta) {
drv_priv = (struct rtl_sta_info *)sta->drv_priv;
undecorated_smoothed_pwdb =
drv_priv->rssi_stat.undecorated_smoothed_pwdb;
} else {
undecorated_smoothed_pwdb =
rtlpriv->dm.undecorated_smoothed_pwdb;
}
if (undecorated_smoothed_pwdb < 0)
undecorated_smoothed_pwdb = pstatus->rx_pwdb_all;
if (pstatus->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) {
undecorated_smoothed_pwdb = (((undecorated_smoothed_pwdb) *
(RX_SMOOTH_FACTOR - 1)) +
(pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
undecorated_smoothed_pwdb = undecorated_smoothed_pwdb + 1;
} else {
undecorated_smoothed_pwdb = (((undecorated_smoothed_pwdb) *
(RX_SMOOTH_FACTOR - 1)) +
(pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
}
if (sta) {
drv_priv->rssi_stat.undecorated_smoothed_pwdb =
undecorated_smoothed_pwdb;
} else {
rtlpriv->dm.undecorated_smoothed_pwdb = undecorated_smoothed_pwdb;
}
rcu_read_unlock();
rtl_update_rxsignalstatistics(hw, pstatus);
}
static void rtl_process_ui_link_quality(struct ieee80211_hw *hw,
struct rtl_stats *pstatus)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 last_evm, n_stream, tmpval;
if (pstatus->signalquality == 0)
return;
if (rtlpriv->stats.ui_link_quality.total_num++ >=
PHY_LINKQUALITY_SLID_WIN_MAX) {
rtlpriv->stats.ui_link_quality.total_num =
PHY_LINKQUALITY_SLID_WIN_MAX;
last_evm = rtlpriv->stats.ui_link_quality.elements[
rtlpriv->stats.ui_link_quality.index];
rtlpriv->stats.ui_link_quality.total_val -= last_evm;
}
rtlpriv->stats.ui_link_quality.total_val += pstatus->signalquality;
rtlpriv->stats.ui_link_quality.elements[
rtlpriv->stats.ui_link_quality.index++] =
pstatus->signalquality;
if (rtlpriv->stats.ui_link_quality.index >=
PHY_LINKQUALITY_SLID_WIN_MAX)
rtlpriv->stats.ui_link_quality.index = 0;
tmpval = rtlpriv->stats.ui_link_quality.total_val /
rtlpriv->stats.ui_link_quality.total_num;
rtlpriv->stats.signal_quality = tmpval;
rtlpriv->stats.last_sigstrength_inpercent = tmpval;
for (n_stream = 0; n_stream < 2; n_stream++) {
if (pstatus->rx_mimo_signalquality[n_stream] != -1) {
if (rtlpriv->stats.rx_evm_percentage[n_stream] == 0) {
rtlpriv->stats.rx_evm_percentage[n_stream] =
pstatus->rx_mimo_signalquality[n_stream];
}
rtlpriv->stats.rx_evm_percentage[n_stream] =
((rtlpriv->stats.rx_evm_percentage[n_stream]
* (RX_SMOOTH_FACTOR - 1)) +
(pstatus->rx_mimo_signalquality[n_stream] * 1)) /
(RX_SMOOTH_FACTOR);
}
}
}
void stg_rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer,
struct rtl_stats *pstatus)
{
if (!pstatus->b_packet_matchbssid)
return;
rtl_process_ui_rssi(hw, pstatus);
rtl_process_pwdb(hw, pstatus);
rtl_process_ui_link_quality(hw, pstatus);
}
EXPORT_SYMBOL(stg_rtl_process_phyinfo);

View File

@@ -0,0 +1,43 @@
/******************************************************************************
*
* Copyright(c) 2009-2010 Realtek Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
*
*****************************************************************************/
#ifndef __RTL_STATS_H__
#define __RTL_STATS_H__
#define PHY_RSSI_SLID_WIN_MAX 100
#define PHY_LINKQUALITY_SLID_WIN_MAX 20
#define PHY_BEACON_RSSI_SLID_WIN_MAX 10
/* Rx smooth factor */
#define RX_SMOOTH_FACTOR 20
u8 stg_rtl_query_rxpwrpercentage(char antpower);
u8 stg_rtl_evm_db_to_percentage(char value);
u8 rtl_evm_dbm_jaguar(char value);
long stg_rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig);
void stg_rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer,
struct rtl_stats *pstatus);
#endif

File diff suppressed because it is too large Load Diff