Return-path: Received: from mail-iy0-f174.google.com ([209.85.210.174]:36440 "EHLO mail-iy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751236Ab1A3SL7 (ORCPT ); Sun, 30 Jan 2011 13:11:59 -0500 Received: by iyj18 with SMTP id 18so4171095iyj.19 for ; Sun, 30 Jan 2011 10:11:58 -0800 (PST) From: Larry.Finger@lwfinger.net To: linville@tuxdriver.com Cc: linux-wireless@vger.kernel.org, Larry Finger , george0505 , 'Zhaoming_Li' Subject: [RFC/RFT 3/8] rtl8192cu: Add new driver code - Part 2 Date: Sun, 30 Jan 2011 12:11:35 -0600 Message-Id: <1296411100-5675-4-git-send-email-Larry.Finger@lwfinger.net> In-Reply-To: <1296411100-5675-1-git-send-email-Larry.Finger@lwfinger.net> References: <1296411100-5675-1-git-send-email-Larry.Finger@lwfinger.net> Sender: linux-wireless-owner@vger.kernel.org List-ID: From: Larry Finger Signed-off-by: Larry Finger Cc: george0505 Cc: 'Zhaoming_Li' --- drivers/net/wireless/rtlwifi/rtl8192cu/fw.c | 685 ++++++++++++++++ drivers/net/wireless/rtlwifi/rtl8192cu/fw.h | 97 +++ drivers/net/wireless/rtlwifi/rtl8192cu/led.c | 143 ++++ drivers/net/wireless/rtlwifi/rtl8192cu/led.h | 38 + drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 1135 ++++++++++++++++++++++++++ drivers/net/wireless/rtlwifi/rtl8192cu/mac.h | 180 ++++ 6 files changed, 2278 insertions(+), 0 deletions(-) create mode 100644 drivers/net/wireless/rtlwifi/rtl8192cu/fw.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8192cu/fw.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8192cu/led.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8192cu/led.h create mode 100644 drivers/net/wireless/rtlwifi/rtl8192cu/mac.c create mode 100644 drivers/net/wireless/rtlwifi/rtl8192cu/mac.h diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/fw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/fw.c new file mode 100644 index 0000000..d65a9a3 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/fw.c @@ -0,0 +1,685 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + *****************************************************************************/ + +#include +#include "../wifi.h" +#include "../pci.h" +#include "../base.h" +#include "reg.h" +#include "def.h" +#include "fw.h" + +static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) { + u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + if (enable) + value32 |= MCUFWDL_EN; + else + value32 &= ~MCUFWDL_EN; + rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) { + u8 tmp; + if (enable) { + tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, + tmp | 0x04); + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01); + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2); + rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7); + } else { + tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL); + rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe); + rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00); + } + } +} + +static void _rtl92c_fw_block_write(struct ieee80211_hw *hw, + const u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 blockSize = sizeof(u32); + u8 *bufferPtr = (u8 *) buffer; + u32 *pu4BytePtr = (u32 *) buffer; + u32 i, offset, blockCount, remainSize; + + blockCount = size / blockSize; + remainSize = size % blockSize; + for (i = 0; i < blockCount; i++) { + offset = i * blockSize; + rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset), + *(pu4BytePtr + i)); + } + if (remainSize) { + offset = blockCount * blockSize; + bufferPtr += offset; + for (i = 0; i < remainSize; i++) { + rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS + + offset + i), *(bufferPtr + i)); + } + } +} + +static void _rtl92c_fw_page_write(struct ieee80211_hw *hw, + u32 page, const u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value8; + u8 u8page = (u8) (page & 0x07); + + value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page; + rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8); + _rtl92c_fw_block_write(hw, buffer, size); +} + +static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen) +{ + u32 fwlen = *pfwlen; + u8 remain = (u8) (fwlen % 4); + + remain = (remain == 0) ? 0 : (4 - remain); + while (remain > 0) { + pfwbuf[fwlen] = 0; + fwlen++; + remain--; + } + *pfwlen = fwlen; +} + +static void _rtl92c_write_fw(struct ieee80211_hw *hw, u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 *bufferPtr = (u8 *) buffer; + enum version_8192c version = rtlhal->version; + + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size)); + if (IS_NORMAL_CHIP(version)) { + u32 pageNums, remainSize; + u32 page, offset; + + if (IS_HARDWARE_TYPE_8192CE(rtlhal)) + _rtl92c_fill_dummy(bufferPtr, &size); + pageNums = size / FW_8192C_PAGE_SIZE; + remainSize = size % FW_8192C_PAGE_SIZE; + if (pageNums > 4) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Page numbers should not greater then 4\n")); + } + for (page = 0; page < pageNums; page++) { + offset = page * FW_8192C_PAGE_SIZE; + _rtl92c_fw_page_write(hw, page, (bufferPtr + offset), + FW_8192C_PAGE_SIZE); + } + if (remainSize) { + offset = pageNums * FW_8192C_PAGE_SIZE; + page = pageNums; + _rtl92c_fw_page_write(hw, page, (bufferPtr + offset), + remainSize); + } + } else { + _rtl92c_fw_block_write(hw, buffer, size); + } +} + +static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int err = -EIO; + u32 counter = 0; + u32 value32; + + do { + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) && + (!(value32 & FWDL_ChkSum_rpt))); + if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", + value32)); + goto exit; + } + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32)); + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + value32 |= MCUFWDL_RDY; + value32 &= ~WINTINI_RDY; + rtl_write_dword(rtlpriv, REG_MCUFWDL, value32); + counter = 0; + do { + value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL); + if (value32 & WINTINI_RDY) { + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + ("Polling FW ready success!!" + " REG_MCUFWDL:0x%08x.\n", + value32)); + err = 0; + goto exit; + } + mdelay(FW_8192C_POLLING_DELAY); + } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT); + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32)); +exit: + return err; +} + +int rtl92c_download_fw(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl92c_firmware_header *pfwheader; + u8 *pfwdata; + u32 fwsize; + int err; + const struct firmware *firmware; + + printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n", + rtlpriv->cfg->fw_name); + err = request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev); + if (err) { + printk(KERN_ERR "rtl8192cu: Firmware loading failed\n"); + return 1; + } + if (firmware->size > 0x4000) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is too big!\n")); + release_firmware(firmware); + return 1; + } + memcpy(rtlhal->pfirmware, firmware->data, firmware->size); + fwsize = firmware->size; + release_firmware(firmware); + pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; + pfwdata = (u8 *) rtlhal->pfirmware; + if (IS_FW_HEADER_EXIST(pfwheader)) { + RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, + ("Firmware Version(%d), Signature(%#x),Size(%d)\n", + pfwheader->version, pfwheader->signature, + (int)sizeof(struct rtl92c_firmware_header))); + rtlhal->fw_version = pfwheader->version; + pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header); + fwsize = fwsize - sizeof(struct rtl92c_firmware_header); + } + _rtl92c_enable_fw_download(hw, true); + _rtl92c_write_fw(hw, pfwdata, fwsize); + _rtl92c_enable_fw_download(hw, false); + err = _rtl92c_fw_free_to_go(hw); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is not ready to run!\n")); + } else { + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + ("Firmware is ready to run!\n")); + } + return 0; +} + +static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 val_hmetfr, val_mcutst_1; + bool result = false; + + val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR); + val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum)); + if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0) + result = true; + return result; +} + +static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u8 boxnum; + u16 box_reg = 0, box_extreg = 0; + u8 u1b_tmp; + bool isfw_read = false; + u8 buf_index = 0; + bool bwrite_sucess = false; + u8 wait_h2c_limmit = 100; + u8 wait_writeh2c_limmit = 100; + u8 boxcontent[4], boxextcontent[2]; + u32 h2c_waitcounter = 0; + unsigned long flag; + u8 idx = 0; + + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n")); + while (true) { + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + if (rtlhal->b_h2c_setinprogress) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("H2C set in progress! Wait to set.." + "element_id(%d).\n", element_id)); + while (rtlhal->b_h2c_setinprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, + flag); + h2c_waitcounter++; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Wait 100 us (%d times)...\n", + h2c_waitcounter)); + udelay(100); + if (h2c_waitcounter > 1000) + return; + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, + flag); + } + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + } else { + rtlhal->b_h2c_setinprogress = true; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + break; + } + } + while (!bwrite_sucess) { + wait_writeh2c_limmit--; + if (wait_writeh2c_limmit == 0) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Write H2C fail because no trigger " + "for FW INT!\n")); + break; + } + boxnum = rtlhal->last_hmeboxnum; + switch (boxnum) { + case 0: + box_reg = REG_HMEBOX_0; + box_extreg = REG_HMEBOX_EXT_0; + break; + case 1: + box_reg = REG_HMEBOX_1; + box_extreg = REG_HMEBOX_EXT_1; + break; + case 2: + box_reg = REG_HMEBOX_2; + box_extreg = REG_HMEBOX_EXT_2; + break; + case 3: + box_reg = REG_HMEBOX_3; + box_extreg = REG_HMEBOX_EXT_3; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum); + while (!isfw_read) { + wait_h2c_limmit--; + if (wait_h2c_limmit == 0) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Wating too long for FW read " + "clear HMEBox(%d)!\n", boxnum)); + break; + } + udelay(10); + isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum); + u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Wating for FW read clear HMEBox(%d)!!! " + "0x1BF = %2x\n", boxnum, u1b_tmp)); + } + if (!isfw_read) { + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Write H2C register BOX[%d] fail!!!!! " + "Fw do not read.\n", boxnum)); + break; + } + memset(boxcontent, 0, sizeof(boxcontent)); + memset(boxextcontent, 0, sizeof(boxextcontent)); + boxcontent[0] = element_id; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("Write element_id box_reg(%4x) = %2x\n", + box_reg, element_id)); + switch (cmd_len) { + case 1: + boxcontent[0] &= ~(BIT(7)); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer + buf_index, 1); + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + case 2: + boxcontent[0] &= ~(BIT(7)); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer + buf_index, 2); + for (idx = 0; idx < 4; idx++) { + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + } + break; + case 3: + boxcontent[0] &= ~(BIT(7)); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer + buf_index, 3); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + case 4: + boxcontent[0] |= (BIT(7)); + memcpy((u8 *) (boxextcontent), + p_cmdbuffer + buf_index, 2); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer + buf_index + 2, 2); + for (idx = 0; idx < 2; idx++) + rtl_write_byte(rtlpriv, box_extreg + idx, + boxextcontent[idx]); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + case 5: + boxcontent[0] |= (BIT(7)); + memcpy((u8 *) (boxextcontent), + p_cmdbuffer + buf_index, 2); + memcpy((u8 *) (boxcontent) + 1, + p_cmdbuffer + buf_index + 2, 3); + for (idx = 0; idx < 2; idx++) + rtl_write_byte(rtlpriv, box_extreg + idx, + boxextcontent[idx]); + for (idx = 0; idx < 4; idx++) + rtl_write_byte(rtlpriv, box_reg + idx, + boxcontent[idx]); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + bwrite_sucess = true; + rtlhal->last_hmeboxnum = boxnum + 1; + if (rtlhal->last_hmeboxnum == 4) + rtlhal->last_hmeboxnum = 0; + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, + ("pHalData->last_hmeboxnum = %d\n", + rtlhal->last_hmeboxnum)); + } + spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag); + rtlhal->b_h2c_setinprogress = false; + spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag); + RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n")); +} + +void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, + u8 element_id, u32 cmd_len, u8 *p_cmdbuffer) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 tmp_cmdbuf[2]; + + if (rtlhal->bfw_ready == false) { + RT_ASSERT(false, ("return H2C cmd because of Fw " + "download fail!!!\n")); + return; + } + memset(tmp_cmdbuf, 0, 8); + memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len); + _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf); + return; +} + +void rtl92c_firmware_selfreset(struct ieee80211_hw *hw) +{ + u8 u1b_tmp; + u8 delay = 100; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20); + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + while (u1b_tmp & BIT(2)) { + delay--; + if (delay == 0) { + RT_ASSERT(false, ("8051 reset fail.\n")); + break; + } + udelay(50); + u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); + } +} + +void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 u1_h2c_set_pwrmode[3] = { 0 }; + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode)); + SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode); + SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1); + SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode, + ppsc->reg_max_lps_awakeintvl); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n", + u1_h2c_set_pwrmode, 3); + rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode); +} + +#define BEACON_PG 0 /* ->1 */ +#define PSPOLL_PG 2 +#define NULL_PG 3 +#define PROBERSP_PG 4 /* ->5 */ + +#define TOTAL_RESERVED_PKT_LEN 768 + +static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { + /* page 0 beacon */ + 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, + 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, + 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, + 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, + 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, + 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, + 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 1 beacon */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 2 ps-poll */ + 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 3 null */ + 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 4 probe_resp */ + 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10, + 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42, + 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00, + 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00, + 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69, + 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C, + 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96, + 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A, + 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C, + 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02, + 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* page 5 probe_resp */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct sk_buff *skb = NULL; + u32 totalpacketlen; + bool rtstatus; + u8 u1RsvdPageLoc[3] = { 0 }; + bool b_dlok = false; + u8 *beacon; + u8 *p_pspoll; + u8 *nullfunc; + u8 *p_probersp; + + /*--------------------------------------------------------- + (1) beacon + ---------------------------------------------------------*/ + beacon = &reserved_page_packet[BEACON_PG * 128]; + SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr); + SET_80211_HDR_ADDRESS3(beacon, mac->bssid); + /*------------------------------------------------------- + (2) ps-poll + --------------------------------------------------------*/ + p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; + SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); + SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG); + /*-------------------------------------------------------- + (3) null data + ---------------------------------------------------------*/ + nullfunc = &reserved_page_packet[NULL_PG * 128]; + SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid); + SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr); + SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid); + SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG); + /*--------------------------------------------------------- + (4) probe response + ----------------------------------------------------------*/ + p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; + SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG); + totalpacketlen = TOTAL_RESERVED_PKT_LEN; + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, + "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", + &reserved_page_packet[0], totalpacketlen); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n", + u1RsvdPageLoc, 3); + skb = dev_alloc_skb(totalpacketlen); + memcpy((u8 *) skb_put(skb, totalpacketlen), + &reserved_page_packet, totalpacketlen); + rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb); + if (rtstatus) + b_dlok = true; + if (b_dlok) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("Set RSVD page location to Fw.\n")); + RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, + "H2C_RSVDPAGE:\n", + u1RsvdPageLoc, 3); + rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE, + sizeof(u1RsvdPageLoc), u1RsvdPageLoc); + } else { + RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, + ("Set RSVD page location to Fw FAIL!!!!!!.\n")); + } +} + +void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus) +{ + u8 u1_joinbssrpt_parm[1] = { 0 }; + + SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus); + rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/fw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/fw.h new file mode 100644 index 0000000..158459f --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/fw.h @@ -0,0 +1,97 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + *****************************************************************************/ + +#ifndef __RTL92C__FW__H__ +#define __RTL92C__FW__H__ + +#define FW_8192C_SIZE 0x3000 +#define FW_8192C_START_ADDRESS 0x1000 +#define FW_8192C_END_ADDRESS 0x3FFF +#define FW_8192C_PAGE_SIZE 4096 +#define FW_8192C_POLLING_DELAY 5 +#define FW_8192C_POLLING_TIMEOUT_COUNT 100 + +#define IS_FW_HEADER_EXIST(_pfwhdr) \ + ((_pfwhdr->signature&0xFFF0) == 0x92C0 ||\ + (_pfwhdr->signature&0xFFF0) == 0x88C0) + +struct rtl92c_firmware_header { + u16 signature; + u8 category; + u8 function; + u16 version; + u8 subversion; + u8 rsvd1; + u8 month; + u8 date; + u8 hour; + u8 minute; + u16 ramcodeSize; + u16 rsvd2; + u32 svnindex; + u32 rsvd3; + u32 rsvd4; + u32 rsvd5; +}; + +enum rtl8192c_h2c_cmd { + H2C_AP_OFFLOAD = 0, + H2C_SETPWRMODE = 1, + H2C_JOINBSSRPT = 2, + H2C_RSVDPAGE = 3, + H2C_RSSI_REPORT = 5, + H2C_RA_MASK = 6, + MAX_H2CCMD +}; + +#define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0)) + +#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) +#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val) +#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \ + SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val) + +int rtl92c_download_fw(struct ieee80211_hw *hw); +void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); +void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); +void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); +void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); +void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/led.c b/drivers/net/wireless/rtlwifi/rtl8192cu/led.c new file mode 100644 index 0000000..92ebfb1 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/led.c @@ -0,0 +1,143 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + *****************************************************************************/ + +#include "../wifi.h" +#include "../usb.h" +#include "reg.h" +#include "led.h" + +static void _rtl92cu_init_led(struct ieee80211_hw *hw, + struct rtl_led *pled, enum rtl_led_pin ledpin) +{ + pled->hw = hw; + pled->ledpin = ledpin; + pled->b_ledon = false; +} + +static void _rtl92cu_deInit_led(struct rtl_led *pled) +{ +} + +void rtl92cu_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + u8 ledcfg; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin)); + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + rtl_write_byte(rtlpriv, + REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6)); + break; + case LED_PIN_LED1: + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + pled->b_ledon = true; +} + +void rtl92cu_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_usb_priv *usbpriv = rtl_usbpriv(hw); + u8 ledcfg; + + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, + ("LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin)); + ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); + switch (pled->ledpin) { + case LED_PIN_GPIO0: + break; + case LED_PIN_LED0: + ledcfg &= 0xf0; + if (usbpriv->ledctl.bled_opendrain == true) + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(1) | BIT(5) | BIT(6))); + else + rtl_write_byte(rtlpriv, REG_LEDCFG2, + (ledcfg | BIT(3) | BIT(5) | BIT(6))); + break; + case LED_PIN_LED1: + ledcfg &= 0x0f; + rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("switch case not process\n")); + break; + } + pled->b_ledon = false; +} + +void rtl92cu_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_usb_priv *usbpriv = rtl_usbpriv(hw); + _rtl92cu_init_led(hw, &(usbpriv->ledctl.sw_led0), LED_PIN_LED0); + _rtl92cu_init_led(hw, &(usbpriv->ledctl.sw_led1), LED_PIN_LED1); +} + +void rtl92cu_deinit_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_usb_priv *usbpriv = rtl_usbpriv(hw); + _rtl92cu_deInit_led(&(usbpriv->ledctl.sw_led0)); + _rtl92cu_deInit_led(&(usbpriv->ledctl.sw_led1)); +} + +static void _rtl92cu_sw_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ +} + +void rtl92cu_led_control(struct ieee80211_hw *hw, + enum led_ctl_mode ledaction) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + + if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) && + (ledaction == LED_CTL_TX || + ledaction == LED_CTL_RX || + ledaction == LED_CTL_SITE_SURVEY || + ledaction == LED_CTL_LINK || + ledaction == LED_CTL_NO_LINK || + ledaction == LED_CTL_START_TO_LINK || + ledaction == LED_CTL_POWER_ON)) { + return; + } + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", + ledaction)); + _rtl92cu_sw_led_control(hw, ledaction); +} + diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/led.h b/drivers/net/wireless/rtlwifi/rtl8192cu/led.h new file mode 100644 index 0000000..9b816c9 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/led.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + *****************************************************************************/ + +#ifndef __RTL92CU_LED_H__ +#define __RTL92CU_LED_H__ + +void rtl92cu_init_sw_leds(struct ieee80211_hw *hw); +void rtl92cu_deinit_sw_leds(struct ieee80211_hw *hw); +void rtl92cu_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92cu_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92cu_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); + +#endif + diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c new file mode 100644 index 0000000..7a9bc91 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -0,0 +1,1135 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * +****************************************************************************/ +#include + +#include "../wifi.h" +#include "../pci.h" +#include "../usb.h" +#include "../ps.h" +#include "../cam.h" +#include "reg.h" +#include "def.h" +#include "phy.h" +#include "rf.h" +#include "dm.h" +#include "mac.h" + +/* macro to shorten lines */ + +#define LINK_Q ui_link_quality +#define RX_EVM rx_evm_percentage +#define RX_SIGQ rx_mimo_signalquality + + +void rtl92c_read_chip_version(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + enum version_8192c chip_version = VERSION_UNKNOWN; + u32 value32; + + value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG); + if (value32 & TRP_VAUX_EN) { + chip_version = (value32 & TYPE_ID) ? VERSION_TEST_CHIP_92C : + VERSION_TEST_CHIP_88C; + } else { + /* Normal mass production chip. */ + chip_version = NORMAL_CHIP; + chip_version |= ((value32 & TYPE_ID) ? CHIP_92C : 0); + chip_version |= ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0); + /* RTL8723 with BT function. */ + chip_version |= ((value32 & BT_FUNC) ? CHIP_8723 : 0); + if (IS_VENDOR_UMC(chip_version)) + chip_version |= ((value32 & CHIP_VER_RTL_MASK) ? + CHIP_VENDOR_UMC_B_CUT : 0); + if (IS_92C_SERIAL(chip_version)) { + value32 = rtl_read_dword(rtlpriv, REG_HPON_FSM); + chip_version |= ((CHIP_BONDING_IDENTIFIER(value32) == + CHIP_BONDING_92C_1T2R) ? CHIP_92C_1T2R : 0); + } else if (IS_8723_SERIES(chip_version)) { + value32 = rtl_read_dword(rtlpriv, REG_GPIO_OUTSTS); + chip_version |= ((value32 & RF_RL_ID) ? + CHIP_8723_DRV_REV : 0); + } + } + rtlhal->version = (enum version_8192c)chip_version; + switch (rtlhal->version) { + case VERSION_NORMAL_TSMC_CHIP_92C_1T2R: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_B_CHIP_92C.\n")); + break; + case VERSION_NORMAL_TSMC_CHIP_92C: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMAL_TSMC_CHIP_92C.\n")); + break; + case VERSION_NORMAL_TSMC_CHIP_88C: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMAL_TSMC_CHIP_88C.\n")); + break; + case VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMAL_UMC_CHIP_i" + "92C_1T2R_A_CUT.\n")); + break; + case VERSION_NORMAL_UMC_CHIP_92C_A_CUT: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMAL_UMC_CHIP_" + "92C_A_CUT.\n")); + break; + case VERSION_NORMAL_UMC_CHIP_88C_A_CUT: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMAL_UMC_CHIP" + "_88C_A_CUT.\n")); + break; + case VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMAL_UMC_CHIP" + "_92C_1T2R_B_CUT.\n")); + break; + case VERSION_NORMAL_UMC_CHIP_92C_B_CUT: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMAL_UMC_CHIP" + "_92C_B_CUT.\n")); + break; + case VERSION_NORMAL_UMC_CHIP_88C_B_CUT: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMAL_UMC_CHIP" + "_88C_B_CUT.\n")); + break; + case VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMA_UMC_CHIP" + "_8723_1T1R_A_CUT.\n")); + break; + case VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_NORMA_UMC_CHIP" + "_8723_1T1R_B_CUT.\n")); + break; + case VERSION_TEST_CHIP_92C: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_TEST_CHIP_92C.\n")); + break; + case VERSION_TEST_CHIP_88C: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: VERSION_TEST_CHIP_88C.\n")); + break; + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + ("Chip Version ID: ???????????????.\n")); + break; + } + if (IS_92C_SERIAL(rtlhal->version)) + rtlphy->rf_type = + (IS_92C_1T2R(rtlhal->version)) ? RF_1T2R : RF_2T2R; + else + rtlphy->rf_type = RF_1T1R; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ? + "RF_2T2R" : "RF_1T1R")); + if (get_rf_type(rtlphy) == RF_1T1R) + rtlpriv->dm.brfpath_rxenable[0] = true; + else + rtlpriv->dm.brfpath_rxenable[0] = + rtlpriv->dm.brfpath_rxenable[1] = true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("VersionID = 0x%4x\n", + rtlhal->version)); +} + +/** + * writeLLT - LLT table write access + * @io: io callback + * @address: LLT logical address. + * @data: LLT data content + * + * Realtek hardware access function. + * + */ +bool rtl92c_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool status = true; + long count = 0; + u32 value = _LLT_INIT_ADDR(address) | + _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); + + rtl_write_dword(rtlpriv, REG_LLT_INIT, value); + do { + value = rtl_read_dword(rtlpriv, REG_LLT_INIT); + if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) + break; + if (count > POLLING_LLT_THRESHOLD) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Failed to polling write LLT done at" + " address %d! _LLT_OP_VALUE(%x)\n", + address, _LLT_OP_VALUE(value))); + status = false; + break; + } + } while (++count); + return status; +} +/** + * rtl92c_init_LLT_table - Init LLT table + * @io: io callback + * @boundary: + * + * Realtek hardware access function. + * + */ +bool rtl92c_init_llt_table(struct ieee80211_hw *hw, u32 boundary) +{ + bool rst = true; + u32 i; + + for (i = 0; i < (boundary - 1); i++) { + rst = rtl92c_llt_write(hw, i , i + 1); + if (true != rst) { + printk(KERN_ERR "===> %s #1 fail\n", __func__); + return rst; + } + } + /* end of list */ + rst = rtl92c_llt_write(hw, (boundary - 1), 0xFF); + if (true != rst) { + printk(KERN_ERR "===> %s #2 fail\n", __func__); + return rst; + } + /* Make the other pages as ring buffer + * This ring buffer is used as beacon buffer if we config this MAC + * as two MAC transfer. + * Otherwise used as local loopback buffer. + */ + for (i = boundary; i < LLT_LAST_ENTRY_OF_TX_PKT_BUFFER; i++) { + rst = rtl92c_llt_write(hw, i, (i + 1)); + if (true != rst) { + printk(KERN_ERR "===> %s #3 fail\n", __func__); + return rst; + } + } + /* Let last entry point to the start entry of ring buffer */ + rst = rtl92c_llt_write(hw, LLT_LAST_ENTRY_OF_TX_PKT_BUFFER, boundary); + if (true != rst) { + printk(KERN_ERR "===> %s #4 fail\n", __func__); + return rst; + } + return rst; +} +void rtl92c_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + u8 *macaddr = p_macaddr; + u32 entry_id = 0; + bool is_pairwise = false; + static u8 cam_const_addr[4][6] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} + }; + static u8 cam_const_broad[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + if (clear_all) { + u8 idx = 0; + u8 cam_offset = 0; + u8 clear_number = 5; + + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("clear_all\n")); + for (idx = 0; idx < clear_number; idx++) { + rtl_cam_mark_invalid(hw, cam_offset + idx); + rtl_cam_empty_entry(hw, cam_offset + idx); + if (idx < 5) { + memset(rtlpriv->sec.key_buf[idx], 0, + MAX_KEY_LEN); + rtlpriv->sec.key_len[idx] = 0; + } + } + } else { + switch (enc_algo) { + case WEP40_ENCRYPTION: + enc_algo = CAM_WEP40; + break; + case WEP104_ENCRYPTION: + enc_algo = CAM_WEP104; + break; + case TKIP_ENCRYPTION: + enc_algo = CAM_TKIP; + break; + case AESCCMP_ENCRYPTION: + enc_algo = CAM_AES; + break; + default: + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("iillegal switch case\n")); + enc_algo = CAM_TKIP; + break; + } + if (is_wepkey || rtlpriv->sec.use_defaultkey) { + macaddr = cam_const_addr[key_index]; + entry_id = key_index; + } else { + if (is_group) { + macaddr = cam_const_broad; + entry_id = key_index; + } else { + key_index = PAIRWISE_KEYIDX; + entry_id = CAM_PAIRWISE_KEY_POSITION; + is_pairwise = true; + } + } + if (rtlpriv->sec.key_len[key_index] == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("delete one entry\n")); + rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The insert KEY length is %d\n", + rtlpriv->sec.key_len[PAIRWISE_KEYIDX])); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("The insert KEY is %x %x\n", + rtlpriv->sec.key_buf[0][0], + rtlpriv->sec.key_buf[0][1])); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("add one entry\n")); + if (is_pairwise) { + RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD, + "Pairwiase Key content :", + rtlpriv->sec.pairwise_key, + rtlpriv->sec. + key_len[PAIRWISE_KEYIDX]); + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set Pairwiase key\n")); + + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec. + key_buf[key_index]); + } else { + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set group key\n")); + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + rtl_cam_add_one_entry(hw, + rtlefuse->dev_addr, + PAIRWISE_KEYIDX, + CAM_PAIRWISE_KEY_POSITION, + enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf + [entry_id]); + } + rtl_cam_add_one_entry(hw, macaddr, key_index, + entry_id, enc_algo, + CAM_CONFIG_NO_USEDK, + rtlpriv->sec.key_buf[entry_id]); + } + } + } +} + +u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return rtl_read_dword(rtlpriv, REG_TXDMA_STATUS); +} + +void rtl92c_enable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + if (IS_HARDWARE_TYPE_8192CE(rtlhal)) { + rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & + 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & + 0xFFFFFFFF); + rtlpci->irq_enabled = true; + } else { + rtl_write_dword(rtlpriv, REG_HIMR, rtlusb->irq_mask[0] & + 0xFFFFFFFF); + rtl_write_dword(rtlpriv, REG_HIMRE, rtlusb->irq_mask[1] & + 0xFFFFFFFF); + rtlusb->irq_enabled = true; + } +} + +void rtl92c_init_interrupt(struct ieee80211_hw *hw) +{ + rtl92c_enable_interrupt(hw); +} + +void rtl92c_disable_interrupt(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); + + rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED); + rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); + if (IS_HARDWARE_TYPE_8192CE(rtlhal)) + rtlpci->irq_enabled = false; + else if (IS_HARDWARE_TYPE_8192CU(rtlhal)) + rtlusb->irq_enabled = false; +} + +void rtl92c_set_qos(struct ieee80211_hw *hw, int aci) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + u32 u4b_ac_param; + + rtl92c_dm_init_edca_turbo(hw); + u4b_ac_param = (u32) mac->ac[aci].aifs; + u4b_ac_param |= + ((u32) mac->ac[aci].cw_min & 0xF) << AC_PARAM_ECW_MIN_OFFSET; + u4b_ac_param |= + ((u32) mac->ac[aci].cw_max & 0xF) << AC_PARAM_ECW_MAX_OFFSET; + u4b_ac_param |= (u32) mac->ac[aci].tx_op << AC_PARAM_TXOP_LIMIT_OFFSET; + RT_TRACE(rtlpriv, COMP_QOS, DBG_LOUD, + ("queue:%x, ac_param:%x\n", aci, u4b_ac_param)); + switch (aci) { + case AC1_BK: + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param); + break; + case AC0_BE: + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); + break; + case AC2_VI: + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param); + break; + case AC3_VO: + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param); + break; + default: + RT_ASSERT(false, ("invalid aci: %d !\n", aci)); + break; + } +} + +/*------------------------------------------------------------------------- + * HW MAC Address + *-------------------------------------------------------------------------*/ +void rtl92c_set_mac_addr(struct ieee80211_hw *hw, const u8 *addr) +{ + u32 i; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + for (i = 0 ; i < ETH_ALEN ; i++) + rtl_write_byte(rtlpriv, (REG_MACID + i), *(addr+i)); + + RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, ("MAC Address: %02X-%02X-%02X-" + "%02X-%02X-%02X\n", + rtl_read_byte(rtlpriv, REG_MACID), + rtl_read_byte(rtlpriv, REG_MACID+1), + rtl_read_byte(rtlpriv, REG_MACID+2), + rtl_read_byte(rtlpriv, REG_MACID+3), + rtl_read_byte(rtlpriv, REG_MACID+4), + rtl_read_byte(rtlpriv, REG_MACID+5))); +} + +void rtl92c_init_driver_info_size(struct ieee80211_hw *hw, u8 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, size); +} + +int rtl92c_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) +{ + u8 value; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + value = NT_NO_LINK; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("Set Network type to NO LINK!\n")); + break; + case NL80211_IFTYPE_ADHOC: + value = NT_LINK_AD_HOC; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("Set Network type to Ad Hoc!\n")); + break; + case NL80211_IFTYPE_STATION: + value = NT_LINK_AP; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("Set Network type to STA!\n")); + break; + case NL80211_IFTYPE_AP: + value = NT_AS_AP; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("Set Network type to AP!\n")); + break; + default: + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("Network type %d not support!\n", type)); + return -EOPNOTSUPP; + } + rtl_write_byte(rtlpriv, (REG_CR + 2), value); + return 0; +} + +void rtl92c_init_network_type(struct ieee80211_hw *hw) +{ + rtl92c_set_network_type(hw, NL80211_IFTYPE_UNSPECIFIED); +} + +void rtl92c_init_adaptive_ctrl(struct ieee80211_hw *hw) +{ + u16 value16; + u32 value32; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* Response Rate Set */ + value32 = rtl_read_dword(rtlpriv, REG_RRSR); + value32 &= ~RATE_BITMAP_ALL; + value32 |= RATE_RRSR_CCK_ONLY_1M; + rtl_write_dword(rtlpriv, REG_RRSR, value32); + /* SIFS (used in NAV) */ + value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10); + rtl_write_word(rtlpriv, REG_SPEC_SIFS, value16); + /* Retry Limit */ + value16 = _LRL(0x30) | _SRL(0x30); + rtl_write_dword(rtlpriv, REG_RL, value16); +} + +void rtl92c_init_rate_fallback(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* Set Data Auto Rate Fallback Retry Count register. */ + rtl_write_dword(rtlpriv, REG_DARFRC, 0x00000000); + rtl_write_dword(rtlpriv, REG_DARFRC+4, 0x10080404); + rtl_write_dword(rtlpriv, REG_RARFRC, 0x04030201); + rtl_write_dword(rtlpriv, REG_RARFRC+4, 0x08070605); +} + +static void rtl92c_set_cck_sifs(struct ieee80211_hw *hw, u8 trx_sifs, + u8 ctx_sifs) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_SIFS_CCK, trx_sifs); + rtl_write_byte(rtlpriv, (REG_SIFS_CCK + 1), ctx_sifs); +} + +static void rtl92c_set_ofdm_sifs(struct ieee80211_hw *hw, u8 trx_sifs, + u8 ctx_sifs) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_SIFS_OFDM, trx_sifs); + rtl_write_byte(rtlpriv, (REG_SIFS_OFDM + 1), ctx_sifs); +} + +void rtl92c_init_edca_param(struct ieee80211_hw *hw, + u16 queue, u16 txop, u8 cw_min, u8 cw_max, u8 aifs) +{ + /* sequence: VO, VI, BE, BK ==> the same as 92C hardware design. + * referenc : enum nl80211_txq_q or ieee80211_set_wmm_default function. + */ + u32 value; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + value = (u32)aifs; + value |= ((u32)cw_min & 0xF) << 8; + value |= ((u32)cw_max & 0xF) << 12; + value |= (u32)txop << 16; + /* 92C hardware register sequence is the same as queue number. */ + rtl_write_dword(rtlpriv, (REG_EDCA_VO_PARAM + (queue * 4)), value); +} + +void rtl92c_init_edca(struct ieee80211_hw *hw) +{ + u16 value16; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + /* disable EDCCA count down, to reduce collison and retry */ + value16 = rtl_read_word(rtlpriv, REG_RD_CTRL); + value16 |= DIS_EDCA_CNT_DWN; + rtl_write_word(rtlpriv, REG_RD_CTRL, value16); + /* Update SIFS timing. ?????????? + * pHalData->SifsTime = 0x0e0e0a0a; */ + rtl92c_set_cck_sifs(hw, 0xa, 0xa); + rtl92c_set_ofdm_sifs(hw, 0xe, 0xe); + /* Set CCK/OFDM SIFS to be 10us. */ + rtl_write_word(rtlpriv, REG_SIFS_CCK, 0x0a0a); + rtl_write_word(rtlpriv, REG_SIFS_OFDM, 0x1010); + rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0204); + rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x014004); + /* TXOP */ + rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, 0x005EA42B); + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0x0000A44F); + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x005EA324); + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x002FA226); + /* PIFS */ + rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); + /* AGGR BREAK TIME Register */ + rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0040); + rtl_write_byte(rtlpriv, REG_BCNDMATIM, 0x02); + rtl_write_byte(rtlpriv, REG_ATIMWND, 0x02); +} + +void rtl92c_init_ampdu_aggregation(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x99997631); + rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); + /* init AMPDU aggregation number, tuning for Tx's TP, */ + rtl_write_word(rtlpriv, 0x4CA, 0x0708); +} + +void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw, bool infra_mode) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xFF); +} + +void rtl92c_init_rdg_setting(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_RD_CTRL, 0xFF); + rtl_write_word(rtlpriv, REG_RD_NAV_NXT, 0x200); + rtl_write_byte(rtlpriv, REG_RD_RESP_PKT_TH, 0x05); +} + +void rtl92c_init_retry_function(struct ieee80211_hw *hw) +{ + u8 value8; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + value8 = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL); + value8 |= EN_AMPDU_RTY_NEW; + rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL, value8); + /* Set ACK timeout */ + rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); +} + +void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw, + enum version_8192c version) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + rtl_write_word(rtlpriv, REG_TBTT_PROHIBIT, 0x6404);/* ms */ + rtl_write_byte(rtlpriv, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);/*ms*/ + rtl_write_byte(rtlpriv, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); + if (IS_NORMAL_CHIP(rtlhal->version)) + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660F); + else + rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF); +} + +void rtl92c_disable_fast_edca(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_FAST_EDCA_CTRL, 0); +} + +void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u8 value = is2T ? MAX_MSS_DENSITY_2T : MAX_MSS_DENSITY_1T; + + rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, value); +} + +u16 rtl92c_get_mgt_filter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return rtl_read_word(rtlpriv, REG_RXFLTMAP0); +} + +void rtl92c_set_mgt_filter(struct ieee80211_hw *hw, u16 filter) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_RXFLTMAP0, filter); +} + +u16 rtl92c_get_ctrl_filter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return rtl_read_word(rtlpriv, REG_RXFLTMAP1); +} + +void rtl92c_set_ctrl_filter(struct ieee80211_hw *hw, u16 filter) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_RXFLTMAP1, filter); +} + +u16 rtl92c_get_data_filter(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + return rtl_read_word(rtlpriv, REG_RXFLTMAP2); +} + +void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_word(rtlpriv, REG_RXFLTMAP2, filter); +} +/*==============================================================*/ + +static u8 _rtl92c_query_rxpwrpercentage(char antpower) +{ + if ((antpower <= -100) || (antpower >= 20)) + return 0; + else if (antpower >= 0) + return 100; + else + return 100 + antpower; +} + +static u8 _rtl92c_evm_db_to_percentage(char value) +{ + char ret_val; + + ret_val = value; + if (ret_val >= 0) + ret_val = 0; + if (ret_val <= -33) + ret_val = -33; + ret_val = 0 - ret_val; + ret_val *= 3; + if (ret_val == 99) + ret_val = 100; + return ret_val; +} + +static long _rtl92c_translate_todbm(struct ieee80211_hw *hw, + u8 signal_strength_index) +{ + long signal_power; + + signal_power = (long)((signal_strength_index + 1) >> 1); + signal_power -= 95; + return signal_power; +} + +static long _rtl92c_signal_scale_mapping(struct ieee80211_hw *hw, + long currsig) +{ + long retsig; + + if (currsig >= 61 && currsig <= 100) + retsig = 90 + ((currsig - 60) / 4); + else if (currsig >= 41 && currsig <= 60) + retsig = 78 + ((currsig - 40) / 2); + else if (currsig >= 31 && currsig <= 40) + retsig = 66 + (currsig - 30); + else if (currsig >= 21 && currsig <= 30) + retsig = 54 + (currsig - 20); + else if (currsig >= 5 && currsig <= 20) + retsig = 42 + (((currsig - 5) * 2) / 3); + else if (currsig == 4) + retsig = 36; + else if (currsig == 3) + retsig = 27; + else if (currsig == 2) + retsig = 18; + else if (currsig == 1) + retsig = 9; + else + retsig = currsig; + return retsig; +} + +static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw, + struct rtl_stats *pstats, + struct rx_desc_92c *pdesc, + struct rx_fwinfo_92c *p_drvinfo, + bool bpacket_match_bssid, + bool bpacket_toself, + bool b_packet_beacon) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct phy_sts_cck_8192s_t *cck_buf; + s8 rx_pwr_all = 0, rx_pwr[4]; + u8 rf_rx_num = 0, evm, pwdb_all; + u8 i, max_spatial_stream; + u32 rssi, total_rssi = 0; + bool b_in_powersavemode = false; + bool is_cck_rate; + + is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); + pstats->b_packet_matchbssid = bpacket_match_bssid; + pstats->b_packet_toself = bpacket_toself; + pstats->b_is_cck = is_cck_rate; + pstats->b_packet_beacon = b_packet_beacon; + pstats->b_is_cck = is_cck_rate; + pstats->RX_SIGQ[0] = -1; + pstats->RX_SIGQ[1] = -1; + if (is_cck_rate) { + u8 report, cck_highpwr; + cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; + if (!b_in_powersavemode) + cck_highpwr = rtlphy->bcck_high_power; + else + cck_highpwr = false; + if (!cck_highpwr) { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = cck_buf->cck_agc_rpt & 0xc0; + report = report >> 6; + switch (report) { + case 0x3: + rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); + break; + } + } else { + u8 cck_agc_rpt = cck_buf->cck_agc_rpt; + report = p_drvinfo->cfosho[0] & 0x60; + report = report >> 5; + switch (report) { + case 0x3: + rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x2: + rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x1: + rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1); + break; + case 0x0: + rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1); + break; + } + } + pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->recvsignalpower = rx_pwr_all; + if (bpacket_match_bssid) { + u8 sq; + if (pstats->rx_pwdb_all > 40) + sq = 100; + else { + sq = cck_buf->sq_rpt; + if (sq > 64) + sq = 0; + else if (sq < 20) + sq = 100; + else + sq = ((64 - sq) * 100) / 44; + } + pstats->signalquality = sq; + pstats->RX_SIGQ[0] = sq; + pstats->RX_SIGQ[1] = -1; + } + } else { + rtlpriv->dm.brfpath_rxenable[0] = + rtlpriv->dm.brfpath_rxenable[1] = true; + for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { + if (rtlpriv->dm.brfpath_rxenable[i]) + rf_rx_num++; + rx_pwr[i] = + ((p_drvinfo->gain_trsw[i] & 0x3f) * 2) - 110; + rssi = _rtl92c_query_rxpwrpercentage(rx_pwr[i]); + total_rssi += rssi; + rtlpriv->stats.rx_snr_db[i] = + (long)(p_drvinfo->rxsnr[i] / 2); + + if (bpacket_match_bssid) + pstats->rx_mimo_signalstrength[i] = (u8) rssi; + } + rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; + pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all); + pstats->rx_pwdb_all = pwdb_all; + pstats->rxpower = rx_pwr_all; + pstats->recvsignalpower = rx_pwr_all; + if (pdesc->rxht && pdesc->rxmcs >= DESC92C_RATEMCS8 && + pdesc->rxmcs <= DESC92C_RATEMCS15) + max_spatial_stream = 2; + else + max_spatial_stream = 1; + for (i = 0; i < max_spatial_stream; i++) { + evm = _rtl92c_evm_db_to_percentage(p_drvinfo->rxevm[i]); + if (bpacket_match_bssid) { + if (i == 0) + pstats->signalquality = + (u8) (evm & 0xff); + pstats->RX_SIGQ[i] = + (u8) (evm & 0xff); + } + } + } + if (is_cck_rate) + pstats->signalstrength = + (u8) (_rtl92c_signal_scale_mapping(hw, pwdb_all)); + else if (rf_rx_num != 0) + pstats->signalstrength = + (u8) (_rtl92c_signal_scale_mapping + (hw, total_rssi /= rf_rx_num)); +} + +static void _rtl92c_process_ui_rssi(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + u8 rfpath; + u32 last_rssi, tmpval; + + if (pstats->b_packet_toself || pstats->b_packet_beacon) { + rtlpriv->stats.rssi_calculate_cnt++; + if (rtlpriv->stats.ui_rssi.total_num++ >= + PHY_RSSI_SLID_WIN_MAX) { + rtlpriv->stats.ui_rssi.total_num = + PHY_RSSI_SLID_WIN_MAX; + last_rssi = + rtlpriv->stats.ui_rssi.elements[rtlpriv-> + stats.ui_rssi.index]; + rtlpriv->stats.ui_rssi.total_val -= last_rssi; + } + rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength; + rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi. + index++] = pstats->signalstrength; + if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX) + rtlpriv->stats.ui_rssi.index = 0; + tmpval = rtlpriv->stats.ui_rssi.total_val / + rtlpriv->stats.ui_rssi.total_num; + rtlpriv->stats.signal_strength = + _rtl92c_translate_todbm(hw, (u8) tmpval); + pstats->rssi = rtlpriv->stats.signal_strength; + } + if (!pstats->b_is_cck && pstats->b_packet_toself) { + for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; + rfpath++) { + if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath)) + continue; + if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + pstats->rx_mimo_signalstrength[rfpath]; + } + if (pstats->rx_mimo_signalstrength[rfpath] > + rtlpriv->stats.rx_rssi_percentage[rfpath]) { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats. + rx_rssi_percentage[rfpath] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + + rtlpriv->stats.rx_rssi_percentage[rfpath] = + rtlpriv->stats.rx_rssi_percentage[rfpath] + + 1; + } else { + rtlpriv->stats.rx_rssi_percentage[rfpath] = + ((rtlpriv->stats. + rx_rssi_percentage[rfpath] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_mimo_signalstrength[rfpath])) / + (RX_SMOOTH_FACTOR); + } + } + } +} + +static void _rtl92c_update_rxsignalstatistics(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + int weighting = 0; + + if (rtlpriv->stats.recv_signal_power == 0) + rtlpriv->stats.recv_signal_power = pstats->recvsignalpower; + if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power) + weighting = 5; + else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power) + weighting = (-5); + rtlpriv->stats.recv_signal_power = + (rtlpriv->stats.recv_signal_power * 5 + + pstats->recvsignalpower + weighting) / 6; +} + +static void _rtl92c_process_pwdb(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb = 0; + + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + return; + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + } + if (pstats->b_packet_toself || pstats->b_packet_beacon) { + if (undecorated_smoothed_pwdb < 0) + undecorated_smoothed_pwdb = pstats->rx_pwdb_all; + if (pstats->rx_pwdb_all > (u32) undecorated_smoothed_pwdb) { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + undecorated_smoothed_pwdb = undecorated_smoothed_pwdb + + 1; + } else { + undecorated_smoothed_pwdb = + (((undecorated_smoothed_pwdb) * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR); + } + rtlpriv->dm.undecorated_smoothed_pwdb = + undecorated_smoothed_pwdb; + _rtl92c_update_rxsignalstatistics(hw, pstats); + } +} + +static void _rtl92c_process_LINK_Q(struct ieee80211_hw *hw, + struct rtl_stats *pstats) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 last_evm = 0, n_stream, tmpval; + + if (pstats->signalquality != 0) { + if (pstats->b_packet_toself || pstats->b_packet_beacon) { + if (rtlpriv->stats.LINK_Q.total_num++ >= + PHY_LINKQUALITY_SLID_WIN_MAX) { + rtlpriv->stats.LINK_Q.total_num = + PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = + rtlpriv->stats.LINK_Q.elements + [rtlpriv->stats.LINK_Q.index]; + rtlpriv->stats.LINK_Q.total_val -= + last_evm; + } + rtlpriv->stats.LINK_Q.total_val += + pstats->signalquality; + rtlpriv->stats.LINK_Q.elements + [rtlpriv->stats.LINK_Q.index++] = + pstats->signalquality; + if (rtlpriv->stats.LINK_Q.index >= + PHY_LINKQUALITY_SLID_WIN_MAX) + rtlpriv->stats.LINK_Q.index = 0; + tmpval = rtlpriv->stats.LINK_Q.total_val / + rtlpriv->stats.LINK_Q.total_num; + rtlpriv->stats.signal_quality = tmpval; + rtlpriv->stats.last_sigstrength_inpercent = tmpval; + for (n_stream = 0; n_stream < 2; + n_stream++) { + if (pstats->RX_SIGQ[n_stream] != -1) { + if (!rtlpriv->stats.RX_EVM[n_stream]) { + rtlpriv->stats.RX_EVM[n_stream] + = pstats->RX_SIGQ[n_stream]; + } + rtlpriv->stats.RX_EVM[n_stream] = + ((rtlpriv->stats.RX_EVM + [n_stream] * + (RX_SMOOTH_FACTOR - 1)) + + (pstats->RX_SIGQ + [n_stream] * 1)) / + (RX_SMOOTH_FACTOR); + } + } + } + } else { + ; + } +} + +static void _rtl92c_process_phyinfo(struct ieee80211_hw *hw, + u8 *buffer, + struct rtl_stats *pcurrent_stats) +{ + if (!pcurrent_stats->b_packet_matchbssid && + !pcurrent_stats->b_packet_beacon) + return; + _rtl92c_process_ui_rssi(hw, pcurrent_stats); + _rtl92c_process_pwdb(hw, pcurrent_stats); + _rtl92c_process_LINK_Q(hw, pcurrent_stats); +} + +void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_stats *pstats, + struct rx_desc_92c *pdesc, + struct rx_fwinfo_92c *p_drvinfo) +{ + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct ieee80211_hdr *hdr; + u8 *tmp_buf; + u8 *praddr; + u8 *psaddr; + u16 fc, type; + bool b_packet_matchbssid, b_packet_toself, b_packet_beacon; + + tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift; + hdr = (struct ieee80211_hdr *)tmp_buf; + fc = le16_to_cpu(hdr->frame_control); + type = WLAN_FC_GET_TYPE(fc); + praddr = hdr->addr1; + psaddr = hdr->addr2; + b_packet_matchbssid = + ((IEEE80211_FTYPE_CTL != type) && + (!compare_ether_addr(mac->bssid, + (fc & IEEE80211_FCTL_TODS) ? + hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ? + hdr->addr2 : hdr->addr3)) && + (!pstats->b_hwerror) && (!pstats->b_crc) && (!pstats->b_icv)); + + b_packet_toself = b_packet_matchbssid && + (!compare_ether_addr(praddr, rtlefuse->dev_addr)); + if (ieee80211_is_beacon(fc)) + b_packet_beacon = true; + _rtl92c_query_rxphystatus(hw, pstats, pdesc, p_drvinfo, + b_packet_matchbssid, b_packet_toself, + b_packet_beacon); + _rtl92c_process_phyinfo(hw, tmp_buf, pstats); +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h new file mode 100644 index 0000000..774bba2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h @@ -0,0 +1,180 @@ +/****************************************************************************** + * + * Copyright(c) 2009-2010 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * wlanfae + * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, + * Hsinchu 300, Taiwan. + * + * Created on 2010/ 10/27, 13:00 + *****************************************************************************/ + +#ifndef __RTL92C_MAC_H__ +#define __RTL92C_MAC_H__ + +#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 +#define DRIVER_EARLY_INT_TIME 0x05 +#define BCN_DMA_ATIME_INT_TIME 0x02 + +void rtl92c_read_chip_version(struct ieee80211_hw *hw); +bool rtl92c_llt_write(struct ieee80211_hw *hw, u32 address, u32 data); +bool rtl92c_init_llt_table(struct ieee80211_hw *hw, u32 boundary); +void rtl92c_set_key(struct ieee80211_hw *hw, u32 key_index, + u8 *p_macaddr, bool is_group, u8 enc_algo, + bool is_wepkey, bool clear_all); +void rtl92c_enable_interrupt(struct ieee80211_hw *hw); +void rtl92c_disable_interrupt(struct ieee80211_hw *hw); +void rtl92c_set_qos(struct ieee80211_hw *hw, int aci); + + +/*--------------------------------------------------------------- + * Hardware init functions + *---------------------------------------------------------------*/ +void rtl92c_set_mac_addr(struct ieee80211_hw *hw, const u8 *addr); +void rtl92c_init_interrupt(struct ieee80211_hw *hw); +void rtl92c_init_driver_info_size(struct ieee80211_hw *hw, u8 size); + +int rtl92c_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92c_init_network_type(struct ieee80211_hw *hw); +void rtl92c_init_adaptive_ctrl(struct ieee80211_hw *hw); +void rtl92c_init_rate_fallback(struct ieee80211_hw *hw); + +void rtl92c_init_edca_param(struct ieee80211_hw *hw, + u16 queue, + u16 txop, + u8 ecwmax, + u8 ecwmin, + u8 aifs); + +void rtl92c_init_edca(struct ieee80211_hw *hw); +void rtl92c_init_ampdu_aggregation(struct ieee80211_hw *hw); +void rtl92c_init_beacon_max_error(struct ieee80211_hw *hw, bool infra_mode); +void rtl92c_init_rdg_setting(struct ieee80211_hw *hw); +void rtl92c_init_retry_function(struct ieee80211_hw *hw); + +void rtl92c_init_beacon_parameters(struct ieee80211_hw *hw, + enum version_8192c version); + +void rtl92c_disable_fast_edca(struct ieee80211_hw *hw); +void rtl92c_set_min_space(struct ieee80211_hw *hw, bool is2T); + +/* For filter */ +u16 rtl92c_get_mgt_filter(struct ieee80211_hw *hw); +void rtl92c_set_mgt_filter(struct ieee80211_hw *hw, u16 filter); +u16 rtl92c_get_ctrl_filter(struct ieee80211_hw *hw); +void rtl92c_set_ctrl_filter(struct ieee80211_hw *hw, u16 filter); +u16 rtl92c_get_data_filter(struct ieee80211_hw *hw); +void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter); + + +u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw); + + +#define RX_HAL_IS_CCK_RATE(_pdesc)\ + (_pdesc->rxmcs == DESC92C_RATE1M ||\ + _pdesc->rxmcs == DESC92C_RATE2M ||\ + _pdesc->rxmcs == DESC92C_RATE5_5M ||\ + _pdesc->rxmcs == DESC92C_RATE11M) + +struct rx_fwinfo_92c { + u8 gain_trsw[4]; + u8 pwdb_all; + u8 cfosho[4]; + u8 cfotail[4]; + char rxevm[2]; + char rxsnr[4]; + u8 pdsnr[2]; + u8 csi_current[2]; + u8 csi_target[2]; + u8 sigevm; + u8 max_ex_pwr; + u8 ex_intf_flag:1; + u8 sgi_en:1; + u8 rxsc:2; + u8 reserve:4; +} __packed; + +struct rx_desc_92c { + u32 length:14; + u32 crc32:1; + u32 icverror:1; + u32 drv_infosize:4; + u32 security:3; + u32 qos:1; + u32 shift:2; + u32 phystatus:1; + u32 swdec:1; + u32 lastseg:1; + u32 firstseg:1; + u32 eor:1; + u32 own:1; + u32 macid:5; + u32 tid:4; + u32 hwrsvd:5; + u32 paggr:1; + u32 faggr:1; + u32 a1_fit:4; + u32 a2_fit:4; + u32 pam:1; + u32 pwr:1; + u32 moredata:1; + u32 morefrag:1; + u32 type:2; + u32 mc:1; + u32 bc:1; + u32 seq:12; + u32 frag:4; + u32 nextpktlen:14; + u32 nextind:1; + u32 rsvd:1; + u32 rxmcs:6; + u32 rxht:1; + u32 amsdu:1; + u32 splcp:1; + u32 bandwidth:1; + u32 htc:1; + u32 tcpchk_rpt:1; + u32 ipcchk_rpt:1; + u32 tcpchk_valid:1; + u32 hwpcerr:1; + u32 hwpcind:1; + u32 iv0:16; + u32 iv1; + u32 tsfl; + u32 bufferaddress; + u32 bufferaddress64; +} __packed; + +enum rtl_desc_qsel rtl92c_map_hwqueue_to_fwqueue(u16 fc, + unsigned int + skb_queue); +void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct rtl_stats *pstats, + struct rx_desc_92c *pdesc, + struct rx_fwinfo_92c *p_drvinfo); + +/*--------------------------------------------------------------- + * Card disable functions + *---------------------------------------------------------------*/ + + + +#endif -- 1.7.1