Commit 09505184 authored by Larry Finger's avatar Larry Finger

staging: rtl8192e: Remove files that are not used

For the most part, these extra files came from the previous version
of the RTL8192E driver.
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
parent 9de9f962
/*
* Cryptographic API.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#ifndef _CRYPTO_INTERNAL_H
#define _CRYPTO_INTERNAL_H
#include <linux/version.h>
#include "rtl_crypto.h"
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/hardirq.h>
#include <linux/sched.h>
#include <asm/kmap_types.h>
extern enum km_type crypto_km_types[];
static inline enum km_type crypto_kmap_type(int out)
{
return crypto_km_types[(in_softirq() ? 2 : 0) + out];
}
static inline void *crypto_kmap(struct page *page, int out)
{
return kmap_atomic(page, crypto_kmap_type(out));
}
static inline void crypto_kunmap(void *vaddr, int out)
{
kunmap_atomic(vaddr, crypto_kmap_type(out));
}
static inline void crypto_yield(struct crypto_tfm *tfm)
{
if (!in_softirq())
cond_resched();
}
static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm)
{
return (void *)&tfm[1];
}
struct crypto_alg *crypto_alg_lookup(const char *name);
#ifdef CONFIG_KMOD
void crypto_alg_autoload(const char *name);
struct crypto_alg *crypto_alg_mod_lookup(const char *name);
#else
static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
{
return crypto_alg_lookup(name);
}
#endif
static inline int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
{
return 0;
}
static inline void crypto_free_hmac_block(struct crypto_tfm *tfm)
{ }
#ifdef CONFIG_PROC_FS
void __init crypto_init_proc(void);
#else
static inline void crypto_init_proc(void)
{ }
#endif
int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_digest_ops(struct crypto_tfm *tfm);
int crypto_init_cipher_ops(struct crypto_tfm *tfm);
int crypto_init_compress_ops(struct crypto_tfm *tfm);
void crypto_exit_digest_ops(struct crypto_tfm *tfm);
void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
void crypto_exit_compress_ops(struct crypto_tfm *tfm);
#endif /* _CRYPTO_INTERNAL_H */
#ifndef __KMAP_TYPES_H
#define __KMAP_TYPES_H
enum km_type {
KM_BOUNCE_READ,
KM_SKB_SUNRPC_DATA,
KM_SKB_DATA_SOFTIRQ,
KM_USER0,
KM_USER1,
KM_BH_IRQ,
KM_SOFTIRQ0,
KM_SOFTIRQ1,
KM_TYPE_NR
};
#define _ASM_KMAP_TYPES_H
#endif
/*
This files contains card eeprom (93c46 or 93c56) programming routines,
memory is addressed by 16 bits words.
This is part of rtl8180 OpenSource driver.
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the
official realtek driver.
Parts of this driver are based on the rtl8180 driver skeleton
from Patric Schenke & Andres Salomon.
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
We want to tanks the Authors of those projects and the Ndiswrapper
project Authors.
*/
#include "r8180_93cx6.h"
static void eprom_cs(struct r8192_priv *priv, short bit)
{
if (bit)
write_nic_byte(priv, EPROM_CMD,
(1<<EPROM_CS_SHIFT) |
read_nic_byte(priv, EPROM_CMD)); //enable EPROM
else
write_nic_byte(priv, EPROM_CMD, read_nic_byte(priv, EPROM_CMD)
&~(1<<EPROM_CS_SHIFT)); //disable EPROM
udelay(EPROM_DELAY);
}
static void eprom_ck_cycle(struct r8192_priv *priv)
{
write_nic_byte(priv, EPROM_CMD,
(1<<EPROM_CK_SHIFT) | read_nic_byte(priv, EPROM_CMD));
udelay(EPROM_DELAY);
write_nic_byte(priv, EPROM_CMD,
read_nic_byte(priv, EPROM_CMD) & ~(1<<EPROM_CK_SHIFT));
udelay(EPROM_DELAY);
}
static void eprom_w(struct r8192_priv *priv, short bit)
{
if (bit)
write_nic_byte(priv, EPROM_CMD, (1<<EPROM_W_SHIFT) |
read_nic_byte(priv, EPROM_CMD));
else
write_nic_byte(priv, EPROM_CMD, read_nic_byte(priv, EPROM_CMD)
&~(1<<EPROM_W_SHIFT));
udelay(EPROM_DELAY);
}
static short eprom_r(struct r8192_priv *priv)
{
short bit;
bit = (read_nic_byte(priv, EPROM_CMD) & (1<<EPROM_R_SHIFT));
udelay(EPROM_DELAY);
if (bit)
return 1;
return 0;
}
static void eprom_send_bits_string(struct r8192_priv *priv, short b[], int len)
{
int i;
for (i = 0; i < len; i++) {
eprom_w(priv, b[i]);
eprom_ck_cycle(priv);
}
}
u32 eprom_read(struct r8192_priv *priv, u32 addr)
{
short read_cmd[] = {1, 1, 0};
short addr_str[8];
int i;
int addr_len;
u32 ret;
ret = 0;
//enable EPROM programming
write_nic_byte(priv, EPROM_CMD,
(EPROM_CMD_PROGRAM<<EPROM_CMD_OPERATING_MODE_SHIFT));
udelay(EPROM_DELAY);
if (priv->epromtype == EPROM_93c56) {
addr_str[7] = addr & 1;
addr_str[6] = addr & (1<<1);
addr_str[5] = addr & (1<<2);
addr_str[4] = addr & (1<<3);
addr_str[3] = addr & (1<<4);
addr_str[2] = addr & (1<<5);
addr_str[1] = addr & (1<<6);
addr_str[0] = addr & (1<<7);
addr_len = 8;
} else {
addr_str[5] = addr & 1;
addr_str[4] = addr & (1<<1);
addr_str[3] = addr & (1<<2);
addr_str[2] = addr & (1<<3);
addr_str[1] = addr & (1<<4);
addr_str[0] = addr & (1<<5);
addr_len = 6;
}
eprom_cs(priv, 1);
eprom_ck_cycle(priv);
eprom_send_bits_string(priv, read_cmd, 3);
eprom_send_bits_string(priv, addr_str, addr_len);
//keep chip pin D to low state while reading.
//I'm unsure if it is necessary, but anyway shouldn't hurt
eprom_w(priv, 0);
for (i = 0; i < 16; i++) {
//eeprom needs a clk cycle between writing opcode&adr
//and reading data. (eeprom outs a dummy 0)
eprom_ck_cycle(priv);
ret |= (eprom_r(priv)<<(15-i));
}
eprom_cs(priv, 0);
eprom_ck_cycle(priv);
//disable EPROM programming
write_nic_byte(priv, EPROM_CMD,
(EPROM_CMD_NORMAL<<EPROM_CMD_OPERATING_MODE_SHIFT));
return ret;
}
/* r8180_93cx6.h - 93c46 or 93c56 eeprom card programming routines
*
* This is part of rtl8187 OpenSource driver
* Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
* Released under the terms of GPL (General Public Licence)
* Parts of this driver are based on the GPL part of the official realtek driver
*
* Parts of this driver are based on the rtl8180 driver skeleton from
* Patric Schenke & Andres Salomon.
*
* Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
*
* We want to thank the authors of the above mentioned projects and to
* the authors of the Ndiswrapper project.
*/
#include "r8192E.h"
#include "r8192E_hw.h"
#define EPROM_DELAY 10
#define EPROM_ANAPARAM_ADDRLWORD 0xd
#define EPROM_ANAPARAM_ADDRHWORD 0xe
#define EPROM_RFCHIPID 0x6
#define EPROM_TXPW_BASE 0x05
#define EPROM_RFCHIPID_RTL8225U 5
#define EPROM_RF_PARAM 0x4
#define EPROM_CONFIG2 0xc
#define EPROM_VERSION 0x1E
#define MAC_ADR 0x7
#define CIS 0x18
#define EPROM_TXPW0 0x16
#define EPROM_TXPW2 0x1b
#define EPROM_TXPW1 0x3d
/* Reads a 16 bits word. */
u32 eprom_read(struct r8192_priv *priv, u32 addr);
This source diff could not be displayed because it is too large. You can view the blob instead.
/******************************************************************************
* Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
******************************************************************************/
#ifndef __INC_HAL8190Pci_FW_IMG_H
#define __INC_HAL8190Pci_FW_IMG_H
/*Created on 2008/12/ 3, 3:26*/
#include <linux/types.h>
#define BootArrayLengthPci 344
extern u8 Rtl8190PciFwBootArray[BootArrayLengthPci];
#define MainArrayLengthPci 55388
extern u8 Rtl8190PciFwMainArray[MainArrayLengthPci];
#define DataArrayLengthPci 2960
extern u8 Rtl8190PciFwDataArray[DataArrayLengthPci];
#define PHY_REGArrayLengthPci 280
extern u32 Rtl8190PciPHY_REGArray[PHY_REGArrayLengthPci];
#define PHY_REG_1T2RArrayLengthPci 280
extern u32 Rtl8190PciPHY_REG_1T2RArray[PHY_REG_1T2RArrayLengthPci];
#define RadioA_ArrayLengthPci 246
extern u32 Rtl8190PciRadioA_Array[RadioA_ArrayLengthPci] ;
#define RadioB_ArrayLengthPci 78
extern u32 Rtl8190PciRadioB_Array[RadioB_ArrayLengthPci] ;
#define RadioC_ArrayLengthPci 246
extern u32 Rtl8190PciRadioC_Array[RadioC_ArrayLengthPci] ;
#define RadioD_ArrayLengthPci 78
extern u32 Rtl8190PciRadioD_Array[RadioD_ArrayLengthPci] ;
#define MACPHY_ArrayLengthPci 18
extern u32 Rtl8190PciMACPHY_Array[MACPHY_ArrayLengthPci] ;
#define MACPHY_Array_PGLengthPci 21
extern u32 Rtl8190PciMACPHY_Array_PG[MACPHY_Array_PGLengthPci] ;
#define AGCTAB_ArrayLengthPci 384
extern u32 Rtl8190PciAGCTAB_Array[AGCTAB_ArrayLengthPci] ;
#endif
/*
This is part of the rtl8192 driver
released under the GPL (See file COPYING for details).
This files contains programming code for the rtl8256
radio frontend.
*Many* thanks to Realtek Corp. for their great support!
*/
#include "r8192E.h"
#include "r8192E_hw.h"
#include "r819xE_phyreg.h"
#include "r819xE_phy.h"
#include "r8190_rtl8256.h"
/*--------------------------------------------------------------------------
* Overview: set RF band width (20M or 40M)
* Input: struct net_device* dev
* WIRELESS_BANDWIDTH_E Bandwidth //20M or 40M
* Output: NONE
* Return: NONE
* Note: 8226 support both 20M and 40 MHz
*---------------------------------------------------------------------------*/
void PHY_SetRF8256Bandwidth(struct r8192_priv *priv, HT_CHANNEL_WIDTH Bandwidth) //20M or 40M
{
u8 eRFPath;
//for(eRFPath = RF90_PATH_A; eRFPath <pHalData->NumTotalRFPath; eRFPath++)
for(eRFPath = 0; eRFPath <priv->NumTotalRFPath; eRFPath++)
{
if (!rtl8192_phy_CheckIsLegalRFPath(priv, eRFPath))
continue;
switch(Bandwidth)
{
case HT_CHANNEL_WIDTH_20:
if(priv->card_8192_version == VERSION_8190_BD || priv->card_8192_version == VERSION_8190_BE)// 8256 D-cut, E-cut, xiong: consider it later!
{
rtl8192_phy_SetRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, 0x0b, bMask12Bits, 0x100); //phy para:1ba
rtl8192_phy_SetRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, 0x2c, bMask12Bits, 0x3d7);
rtl8192_phy_SetRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, 0x0e, bMask12Bits, 0x021);
//cosa add for sd3's request 01/23/2008
//rtl8192_phy_SetRFReg(dev, (RF90_RADIO_PATH_E)eRFPath, 0x14, bMask12Bits, 0x5ab);
}
else
{
RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown hardware version\n");
}
break;
case HT_CHANNEL_WIDTH_20_40:
if(priv->card_8192_version == VERSION_8190_BD ||priv->card_8192_version == VERSION_8190_BE)// 8256 D-cut, E-cut, xiong: consider it later!
{
rtl8192_phy_SetRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, 0x0b, bMask12Bits, 0x300); //phy para:3ba
rtl8192_phy_SetRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, 0x2c, bMask12Bits, 0x3ff);
rtl8192_phy_SetRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, 0x0e, bMask12Bits, 0x0e1);
}
else
{
RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown hardware version\n");
}
break;
default:
RT_TRACE(COMP_ERR, "PHY_SetRF8256Bandwidth(): unknown Bandwidth: %#X\n",Bandwidth );
break;
}
}
}
/*--------------------------------------------------------------------------
* Overview: Interface to config 8256
* Input: struct net_device* dev
* Output: NONE
* Return: NONE
*---------------------------------------------------------------------------*/
RT_STATUS PHY_RF8256_Config(struct r8192_priv *priv)
{
// Initialize general global value
//
RT_STATUS rtStatus = RT_STATUS_SUCCESS;
// TODO: Extend RF_PATH_C and RF_PATH_D in the future
priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH;
// Config BB and RF
rtStatus = phy_RF8256_Config_ParaFile(priv);
return rtStatus;
}
/*--------------------------------------------------------------------------
* Overview: Interface to config 8256
* Input: struct net_device* dev
* Output: NONE
* Return: NONE
*---------------------------------------------------------------------------*/
RT_STATUS phy_RF8256_Config_ParaFile(struct r8192_priv *priv)
{
u32 u4RegValue = 0;
u8 eRFPath;
RT_STATUS rtStatus = RT_STATUS_SUCCESS;
BB_REGISTER_DEFINITION_T *pPhyReg;
u32 RegOffSetToBeCheck = 0x3;
u32 RegValueToBeCheck = 0x7f1;
u32 RF3_Final_Value = 0;
u8 ConstRetryTimes = 5, RetryTimes = 5;
u8 ret = 0;
//3//-----------------------------------------------------------------
//3// <2> Initialize RF
//3//-----------------------------------------------------------------
for(eRFPath = (RF90_RADIO_PATH_E)RF90_PATH_A; eRFPath <priv->NumTotalRFPath; eRFPath++)
{
if (!rtl8192_phy_CheckIsLegalRFPath(priv, eRFPath))
continue;
pPhyReg = &priv->PHYRegDef[eRFPath];
/*----Store original RFENV control type----*/
switch(eRFPath)
{
case RF90_PATH_A:
case RF90_PATH_C:
u4RegValue = rtl8192_QueryBBReg(priv, pPhyReg->rfintfs, bRFSI_RFENV);
break;
case RF90_PATH_B :
case RF90_PATH_D:
u4RegValue = rtl8192_QueryBBReg(priv, pPhyReg->rfintfs, bRFSI_RFENV<<16);
break;
}
/*----Set RF_ENV enable----*/
rtl8192_setBBreg(priv, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1);
/*----Set RF_ENV output high----*/
rtl8192_setBBreg(priv, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
/* Set bit number of Address and Data for RF register */
rtl8192_setBBreg(priv, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); // Set 0 to 4 bits for Z-serial and set 1 to 6 bits for 8258
rtl8192_setBBreg(priv, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); // Set 0 to 12 bits for Z-serial and 8258, and set 1 to 14 bits for ???
rtl8192_phy_SetRFReg(priv, (RF90_RADIO_PATH_E) eRFPath, 0x0, bMask12Bits, 0xbf);
/*----Check RF block (for FPGA platform only)----*/
// TODO: this function should be removed on ASIC , Emily 2007.2.2
rtStatus = rtl8192_phy_checkBBAndRF(priv, HW90_BLOCK_RF, (RF90_RADIO_PATH_E)eRFPath);
if(rtStatus!= RT_STATUS_SUCCESS)
{
RT_TRACE(COMP_ERR, "PHY_RF8256_Config():Check Radio[%d] Fail!!\n", eRFPath);
goto phy_RF8256_Config_ParaFile_Fail;
}
RetryTimes = ConstRetryTimes;
RF3_Final_Value = 0;
/*----Initialize RF fom connfiguration file----*/
switch(eRFPath)
{
case RF90_PATH_A:
while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0)
{
ret = rtl8192_phy_ConfigRFWithHeaderFile(priv,(RF90_RADIO_PATH_E)eRFPath);
RF3_Final_Value = rtl8192_phy_QueryRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits);
RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value);
RetryTimes--;
}
break;
case RF90_PATH_B:
while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0)
{
ret = rtl8192_phy_ConfigRFWithHeaderFile(priv,(RF90_RADIO_PATH_E)eRFPath);
RF3_Final_Value = rtl8192_phy_QueryRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits);
RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value);
RetryTimes--;
}
break;
case RF90_PATH_C:
while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0)
{
ret = rtl8192_phy_ConfigRFWithHeaderFile(priv,(RF90_RADIO_PATH_E)eRFPath);
RF3_Final_Value = rtl8192_phy_QueryRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits);
RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value);
RetryTimes--;
}
break;
case RF90_PATH_D:
while(RF3_Final_Value!=RegValueToBeCheck && RetryTimes!=0)
{
ret = rtl8192_phy_ConfigRFWithHeaderFile(priv,(RF90_RADIO_PATH_E)eRFPath);
RF3_Final_Value = rtl8192_phy_QueryRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, RegOffSetToBeCheck, bMask12Bits);
RT_TRACE(COMP_RF, "RF %d %d register final value: %x\n", eRFPath, RegOffSetToBeCheck, RF3_Final_Value);
RetryTimes--;
}
break;
}
/*----Restore RFENV control type----*/;
switch(eRFPath)
{
case RF90_PATH_A:
case RF90_PATH_C:
rtl8192_setBBreg(priv, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue);
break;
case RF90_PATH_B :
case RF90_PATH_D:
rtl8192_setBBreg(priv, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue);
break;
}
if(ret){
RT_TRACE(COMP_ERR, "phy_RF8256_Config_ParaFile():Radio[%d] Fail!!", eRFPath);
goto phy_RF8256_Config_ParaFile_Fail;
}
}
RT_TRACE(COMP_PHY, "PHY Initialization Success\n") ;
return RT_STATUS_SUCCESS;
phy_RF8256_Config_ParaFile_Fail:
RT_TRACE(COMP_ERR, "PHY Initialization failed\n") ;
return RT_STATUS_FAILURE;
}
void PHY_SetRF8256CCKTxPower(struct r8192_priv *priv, u8 powerlevel)
{
u32 TxAGC=0;
TxAGC = powerlevel;
if(priv->bDynamicTxLowPower == true)//cosa 04282008 for cck long range
{
if(priv->CustomerID == RT_CID_819x_Netcore)
TxAGC = 0x22;
else
TxAGC += priv->CckPwEnl;
}
if(TxAGC > 0x24)
TxAGC = 0x24;
rtl8192_setBBreg(priv, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC);
}
void PHY_SetRF8256OFDMTxPower(struct r8192_priv *priv, u8 powerlevel)
{
u32 writeVal, powerBase0, powerBase1, writeVal_tmp;
u8 index = 0;
u16 RegOffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c};
u8 byte0, byte1, byte2, byte3;
powerBase0 = powerlevel + priv->LegacyHTTxPowerDiff; //OFDM rates
powerBase0 = (powerBase0<<24) | (powerBase0<<16) |(powerBase0<<8) |powerBase0;
powerBase1 = powerlevel; //MCS rates
powerBase1 = (powerBase1<<24) | (powerBase1<<16) |(powerBase1<<8) |powerBase1;
for(index=0; index<6; index++)
{
writeVal = priv->MCSTxPowerLevelOriginalOffset[index] + ((index<2)?powerBase0:powerBase1);
byte0 = (u8)(writeVal & 0x7f);
byte1 = (u8)((writeVal & 0x7f00)>>8);
byte2 = (u8)((writeVal & 0x7f0000)>>16);
byte3 = (u8)((writeVal & 0x7f000000)>>24);
if(byte0 > 0x24) // Max power index = 0x24
byte0 = 0x24;
if(byte1 > 0x24)
byte1 = 0x24;
if(byte2 > 0x24)
byte2 = 0x24;
if(byte3 > 0x24)
byte3 = 0x24;
if(index == 3)
{
writeVal_tmp = (byte3<<24) | (byte2<<16) |(byte1<<8) |byte0;
priv->Pwr_Track = writeVal_tmp;
}
if(priv->bDynamicTxHighPower == true) //Add by Jacken 2008/03/06 //when DM implement, add this
{
writeVal = 0x03030303;
}
else
{
writeVal = (byte3<<24) | (byte2<<16) |(byte1<<8) |byte0;
}
rtl8192_setBBreg(priv, RegOffset[index], 0x7f7f7f7f, writeVal);
}
}
#define MAX_DOZE_WAITING_TIMES_9x 64
static void r8192e_drain_tx_queues(struct r8192_priv *priv)
{
u8 i, QueueID;
for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; )
{
struct rtl8192_tx_ring *ring = &priv->tx_ring[QueueID];
if(skb_queue_len(&ring->queue) == 0)
{
QueueID++;
continue;
}
udelay(10);
i++;
if (i >= MAX_DOZE_WAITING_TIMES_9x)
{
RT_TRACE(COMP_POWER, "r8192e_drain_tx_queues() timeout queue %d\n", QueueID);
break;
}
}
}
static bool SetRFPowerState8190(struct r8192_priv *priv,
RT_RF_POWER_STATE eRFPowerState)
{
PRT_POWER_SAVE_CONTROL pPSC = &priv->PowerSaveControl;
bool bResult = true;
if (eRFPowerState == priv->eRFPowerState &&
priv->bHwRfOffAction == 0) {
bResult = false;
goto out;
}
switch( eRFPowerState )
{
case eRfOn:
// turn on RF
if ((priv->eRFPowerState == eRfOff) &&
RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC))
{
/*
* The current RF state is OFF and the RF OFF level
* is halting the NIC, re-initialize the NIC.
*/
if (!NicIFEnableNIC(priv)) {
RT_TRACE(COMP_ERR, "%s(): NicIFEnableNIC failed\n",__FUNCTION__);
bResult = false;
goto out;
}
RT_CLEAR_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC);
} else {
write_nic_byte(priv, ANAPAR, 0x37);//160MHz
mdelay(1);
//enable clock 80/88 MHz
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter1, 0x4, 0x1); // 0x880[2]
priv->bHwRfOffAction = 0;
//RF-A, RF-B
//enable RF-Chip A/B
rtl8192_setBBreg(priv, rFPGA0_XA_RFInterfaceOE, BIT4, 0x1); // 0x860[4]
//analog to digital on
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter4, 0x300, 0x3);// 0x88c[9:8]
//digital to analog on
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter1, 0x18, 0x3); // 0x880[4:3]
//rx antenna on
rtl8192_setBBreg(priv, rOFDM0_TRxPathEnable, 0x3, 0x3);// 0xc04[1:0]
//rx antenna on
rtl8192_setBBreg(priv, rOFDM1_TRxPathEnable, 0x3, 0x3);// 0xd04[1:0]
//analog to digital part2 on
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter1, 0x60, 0x3); // 0x880[6:5]
}
break;
//
// In current solution, RFSleep=RFOff in order to save power under 802.11 power save.
// By Bruce, 2008-01-16.
//
case eRfSleep:
// HW setting had been configured with deeper mode.
if(priv->eRFPowerState == eRfOff)
break;
r8192e_drain_tx_queues(priv);
PHY_SetRtl8192eRfOff(priv);
break;
case eRfOff:
//
// Disconnect with Any AP or STA.
//
r8192e_drain_tx_queues(priv);
if (pPSC->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC && !RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC))
{
/* Disable all components. */
NicIFDisableNIC(priv);
RT_SET_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC);
}
else if (!(pPSC->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC))
{
/* Normal case - IPS should go to this. */
PHY_SetRtl8192eRfOff(priv);
}
break;
default:
bResult = false;
RT_TRACE(COMP_ERR, "SetRFPowerState8190(): unknow state to set: 0x%X!!!\n", eRFPowerState);
break;
}
if(bResult)
{
// Update current RF state variable.
priv->eRFPowerState = eRFPowerState;
}
out:
return bResult;
}
static void MgntDisconnectIBSS(struct r8192_priv *priv)
{
u8 i;
bool bFilterOutNonAssociatedBSSID = false;
priv->ieee80211->state = IEEE80211_NOLINK;
for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i]= 0x55;
priv->OpMode = RT_OP_MODE_NO_LINK;
write_nic_word(priv, BSSIDR, ((u16*)priv->ieee80211->current_network.bssid)[0]);
write_nic_dword(priv, BSSIDR+2, ((u32*)(priv->ieee80211->current_network.bssid+2))[0]);
{
RT_OP_MODE OpMode = priv->OpMode;
u8 btMsr = read_nic_byte(priv, MSR);
btMsr &= 0xfc;
switch(OpMode)
{
case RT_OP_MODE_INFRASTRUCTURE:
btMsr |= MSR_LINK_MANAGED;
break;
case RT_OP_MODE_IBSS:
btMsr |= MSR_LINK_ADHOC;
// led link set separate
break;
case RT_OP_MODE_AP:
btMsr |= MSR_LINK_MASTER;
break;
default:
btMsr |= MSR_LINK_NONE;
break;
}
write_nic_byte(priv, MSR, btMsr);
}
ieee80211_stop_send_beacons(priv->ieee80211);
// If disconnect, clear RCR CBSSID bit
bFilterOutNonAssociatedBSSID = false;
{
u32 RegRCR, Type;
Type = bFilterOutNonAssociatedBSSID;
RegRCR = read_nic_dword(priv, RCR);
priv->ReceiveConfig = RegRCR;
if (Type == true)
RegRCR |= (RCR_CBSSID);
else if (Type == false)
RegRCR &= (~RCR_CBSSID);
{
write_nic_dword(priv, RCR, RegRCR);
priv->ReceiveConfig = RegRCR;
}
}
notify_wx_assoc_event(priv->ieee80211);
}
static void MlmeDisassociateRequest(struct r8192_priv *priv, u8 *asSta,
u8 asRsn)
{
u8 i;
RemovePeerTS(priv->ieee80211, asSta);
SendDisassociation( priv->ieee80211, asSta, asRsn );
if(memcpy(priv->ieee80211->current_network.bssid,asSta,6) == NULL)
{
//ShuChen TODO: change media status.
//ShuChen TODO: What to do when disassociate.
priv->ieee80211->state = IEEE80211_NOLINK;
for(i=0;i<6;i++) priv->ieee80211->current_network.bssid[i] = 0x22;
priv->OpMode = RT_OP_MODE_NO_LINK;
{
RT_OP_MODE OpMode = priv->OpMode;
u8 btMsr = read_nic_byte(priv, MSR);
btMsr &= 0xfc;
switch(OpMode)
{
case RT_OP_MODE_INFRASTRUCTURE:
btMsr |= MSR_LINK_MANAGED;
break;
case RT_OP_MODE_IBSS:
btMsr |= MSR_LINK_ADHOC;
// led link set separate
break;
case RT_OP_MODE_AP:
btMsr |= MSR_LINK_MASTER;
break;
default:
btMsr |= MSR_LINK_NONE;
break;
}
write_nic_byte(priv, MSR, btMsr);
}
ieee80211_disassociate(priv->ieee80211);
write_nic_word(priv, BSSIDR, ((u16*)priv->ieee80211->current_network.bssid)[0]);
write_nic_dword(priv, BSSIDR+2, ((u32*)(priv->ieee80211->current_network.bssid+2))[0]);
}
}
static void MgntDisconnectAP(struct r8192_priv *priv, u8 asRsn)
{
bool bFilterOutNonAssociatedBSSID = false;
u32 RegRCR, Type;
/* If disconnect, clear RCR CBSSID bit */
bFilterOutNonAssociatedBSSID = false;
Type = bFilterOutNonAssociatedBSSID;
RegRCR = read_nic_dword(priv, RCR);
priv->ReceiveConfig = RegRCR;
if (Type == true)
RegRCR |= (RCR_CBSSID);
else if (Type == false)
RegRCR &= (~RCR_CBSSID);
write_nic_dword(priv, RCR, RegRCR);
priv->ReceiveConfig = RegRCR;
MlmeDisassociateRequest(priv, priv->ieee80211->current_network.bssid, asRsn);
priv->ieee80211->state = IEEE80211_NOLINK;
}
static bool MgntDisconnect(struct r8192_priv *priv, u8 asRsn)
{
// In adhoc mode, update beacon frame.
if( priv->ieee80211->state == IEEE80211_LINKED )
{
if( priv->ieee80211->iw_mode == IW_MODE_ADHOC )
{
MgntDisconnectIBSS(priv);
}
if( priv->ieee80211->iw_mode == IW_MODE_INFRA )
{
// We clear key here instead of MgntDisconnectAP() because that
// MgntActSet_802_11_DISASSOCIATE() is an interface called by OS,
// e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is
// used to handle disassociation related things to AP, e.g. send Disassoc
// frame to AP. 2005.01.27, by rcnjko.
MgntDisconnectAP(priv, asRsn);
}
}
return true;
}
//
// Description:
// Chang RF Power State.
// Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE.
//
// Assumption:
// PASSIVE LEVEL.
//
bool MgntActSet_RF_State(struct r8192_priv *priv, RT_RF_POWER_STATE StateToSet,
RT_RF_CHANGE_SOURCE ChangeSource)
{
bool bActionAllowed = false;
bool bConnectBySSID = false;
RT_RF_POWER_STATE rtState;
RT_TRACE(COMP_POWER, "===>MgntActSet_RF_State(): StateToSet(%d)\n",StateToSet);
spin_lock(&priv->rf_ps_lock);
rtState = priv->eRFPowerState;
switch(StateToSet)
{
case eRfOn:
priv->RfOffReason &= (~ChangeSource);
if (!priv->RfOffReason)
{
priv->RfOffReason = 0;
bActionAllowed = true;
if(rtState == eRfOff && ChangeSource >=RF_CHANGE_BY_HW )
{
bConnectBySSID = true;
}
}
else
RT_TRACE(COMP_POWER, "MgntActSet_RF_State - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n", priv->RfOffReason, ChangeSource);
break;
case eRfOff:
if (priv->RfOffReason > RF_CHANGE_BY_IPS)
{
// Disconnect to current BSS when radio off. Asked by QuanTa.
MgntDisconnect(priv, disas_lv_ss);
}
priv->RfOffReason |= ChangeSource;
bActionAllowed = true;
break;
case eRfSleep:
priv->RfOffReason |= ChangeSource;
bActionAllowed = true;
break;
}
if (bActionAllowed)
{
RT_TRACE(COMP_POWER, "MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, priv->RfOffReason);
// Config HW to the specified mode.
SetRFPowerState8190(priv, StateToSet);
}
else
{
RT_TRACE(COMP_POWER, "MgntActSet_RF_State(): Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n", StateToSet, ChangeSource, priv->RfOffReason);
}
// Release RF spinlock
spin_unlock(&priv->rf_ps_lock);
RT_TRACE(COMP_POWER, "<===MgntActSet_RF_State()\n");
return bActionAllowed;
}
/* r8190_rtl8256.h - rtl8256 radio frontend
*
* This is part of the rtl8180-sa2400 driver
* released under the GPL (See file COPYING for details).
* Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
*
* Many thanks to Realtek Corp. for their great support!
*/
#ifndef RTL8225_H
#define RTL8225_H
#define RTL819X_TOTAL_RF_PATH 2 /* for 8192E */
void PHY_SetRF8256Bandwidth(struct r8192_priv *priv,
HT_CHANNEL_WIDTH Bandwidth);
RT_STATUS PHY_RF8256_Config(struct r8192_priv *priv);
RT_STATUS phy_RF8256_Config_ParaFile(struct r8192_priv *priv);
void PHY_SetRF8256CCKTxPower(struct r8192_priv *priv, u8 powerlevel);
void PHY_SetRF8256OFDMTxPower(struct r8192_priv *priv, u8 powerlevel);
bool MgntActSet_RF_State(struct r8192_priv *priv,
RT_RF_POWER_STATE StateToSet,
RT_RF_CHANGE_SOURCE ChangeSource);
#endif /* RTL8225_H */
/*
This is part of rtl8187 OpenSource driver.
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the
official realtek driver
Parts of this driver are based on the rtl8192 driver skeleton
from Patric Schenke & Andres Salomon
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
We want to tanks the Authors of those projects and the Ndiswrapper
project Authors.
*/
#ifndef R819xU_H
#define R819xU_H
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/rtnetlink.h> //for rtnl_lock()
#include <linux/wireless.h>
#include <linux/timer.h>
#include <linux/proc_fs.h> // Necessary because we use the proc fs
#include <linux/if_arp.h>
#include <linux/random.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include "ieee80211/rtl819x_HT.h"
#include "ieee80211/ieee80211.h"
#define RTL819xE_MODULE_NAME "rtl819xE"
#define FALSE 0
#define TRUE 1
#define MAX_KEY_LEN 61
#define KEY_BUF_SIZE 5
#define BIT0 0x00000001
#define BIT1 0x00000002
#define BIT2 0x00000004
#define BIT3 0x00000008
#define BIT4 0x00000010
#define BIT5 0x00000020
#define BIT6 0x00000040
#define BIT7 0x00000080
#define BIT8 0x00000100
#define BIT9 0x00000200
#define BIT10 0x00000400
#define BIT11 0x00000800
#define BIT12 0x00001000
#define BIT13 0x00002000
#define BIT14 0x00004000
#define BIT15 0x00008000
#define BIT16 0x00010000
#define BIT17 0x00020000
#define BIT18 0x00040000
#define BIT19 0x00080000
#define BIT20 0x00100000
#define BIT21 0x00200000
#define BIT22 0x00400000
#define BIT23 0x00800000
#define BIT24 0x01000000
#define BIT25 0x02000000
#define BIT26 0x04000000
#define BIT27 0x08000000
#define BIT28 0x10000000
#define BIT29 0x20000000
#define BIT30 0x40000000
#define BIT31 0x80000000
// Rx smooth factor
#define Rx_Smooth_Factor 20
/* 2007/06/04 MH Define sliding window for RSSI history. */
#define PHY_RSSI_SLID_WIN_MAX 100
#define PHY_Beacon_RSSI_SLID_WIN_MAX 10
#define IC_VersionCut_D 0x3
#define IC_VersionCut_E 0x4
#if 0 //we need to use RT_TRACE instead DMESG as RT_TRACE will clearly show debug level wb.
#define DMESG(x,a...) printk(KERN_INFO RTL819xE_MODULE_NAME ": " x "\n", ## a)
#else
#define DMESG(x,a...)
extern u32 rt_global_debug_component;
#define RT_TRACE(component, x, args...) \
do { if(rt_global_debug_component & component) \
printk(KERN_DEBUG RTL819xE_MODULE_NAME ":" x , \
##args);\
}while(0);
#define COMP_TRACE BIT0 // For function call tracing.
#define COMP_DBG BIT1 // Only for temporary debug message.
#define COMP_INIT BIT2 // during driver initialization / halt / reset.
#define COMP_RECV BIT3 // Reveive part data path.
#define COMP_SEND BIT4 // Send part path.
#define COMP_IO BIT5 // I/O Related. Added by Annie, 2006-03-02.
#define COMP_POWER BIT6 // 802.11 Power Save mode or System/Device Power state related.
#define COMP_EPROM BIT7 // 802.11 link related: join/start BSS, leave BSS.
#define COMP_SWBW BIT8 // For bandwidth switch.
#define COMP_SEC BIT9// For Security.
#define COMP_TURBO BIT10 // For Turbo Mode related. By Annie, 2005-10-21.
#define COMP_QOS BIT11 // For QoS.
#define COMP_RATE BIT12 // For Rate Adaptive mechanism, 2006.07.02, by rcnjko. #define COMP_EVENTS 0x00000080 // Event handling
#define COMP_RXDESC BIT13 // Show Rx desc information for SD3 debug. Added by Annie, 2006-07-15.
#define COMP_PHY BIT14
#define COMP_DIG BIT15 // For DIG, 2006.09.25, by rcnjko.
#define COMP_TXAGC BIT16 // For Tx power, 060928, by rcnjko.
#define COMP_HALDM BIT17 // For HW Dynamic Mechanism, 061010, by rcnjko.
#define COMP_POWER_TRACKING BIT18 //FOR 8190 TX POWER TRACKING
#define COMP_EVENTS BIT19 // Event handling
#define COMP_RF BIT20 // For RF.
/* 11n or 8190 specific code should be put below this line */
#define COMP_FIRMWARE BIT21 //for firmware downloading
#define COMP_HT BIT22 // For 802.11n HT related information. by Emily 2006-8-11
#define COMP_RESET BIT23
#define COMP_CMDPKT BIT24
#define COMP_SCAN BIT25
#define COMP_IPS BIT26
#define COMP_DOWN BIT27 // for rm driver module
#define COMP_INTR BIT28 // for interrupt
#define COMP_ERR BIT31 // for error out, always on
#endif
//
// Queue Select Value in TxDesc
//
#define QSLT_BK 0x1
#define QSLT_BE 0x0
#define QSLT_VI 0x4
#define QSLT_VO 0x6
#define QSLT_BEACON 0x10
#define QSLT_HIGH 0x11
#define QSLT_MGNT 0x12
#define QSLT_CMD 0x13
#define DESC90_RATE1M 0x00
#define DESC90_RATE2M 0x01
#define DESC90_RATE5_5M 0x02
#define DESC90_RATE11M 0x03
#define DESC90_RATE6M 0x04
#define DESC90_RATE9M 0x05
#define DESC90_RATE12M 0x06
#define DESC90_RATE18M 0x07
#define DESC90_RATE24M 0x08
#define DESC90_RATE36M 0x09
#define DESC90_RATE48M 0x0a
#define DESC90_RATE54M 0x0b
#define DESC90_RATEMCS0 0x00
#define DESC90_RATEMCS1 0x01
#define DESC90_RATEMCS2 0x02
#define DESC90_RATEMCS3 0x03
#define DESC90_RATEMCS4 0x04
#define DESC90_RATEMCS5 0x05
#define DESC90_RATEMCS6 0x06
#define DESC90_RATEMCS7 0x07
#define DESC90_RATEMCS8 0x08
#define DESC90_RATEMCS9 0x09
#define DESC90_RATEMCS10 0x0a
#define DESC90_RATEMCS11 0x0b
#define DESC90_RATEMCS12 0x0c
#define DESC90_RATEMCS13 0x0d
#define DESC90_RATEMCS14 0x0e
#define DESC90_RATEMCS15 0x0f
#define DESC90_RATEMCS32 0x20
#define RTL819X_DEFAULT_RF_TYPE RF_1T2R
#define EEPROM_Default_LegacyHTTxPowerDiff 0x4
#define IEEE80211_WATCH_DOG_TIME 2000
typedef u32 RT_RF_CHANGE_SOURCE;
#define RF_CHANGE_BY_SW BIT31
#define RF_CHANGE_BY_HW BIT30
#define RF_CHANGE_BY_PS BIT29
#define RF_CHANGE_BY_IPS BIT28
#define RF_CHANGE_BY_INIT 0 // Do not change the RFOff reason. Defined by Bruce, 2008-01-17.
// RF state.
typedef enum _RT_RF_POWER_STATE {
eRfOn,
eRfSleep,
eRfOff
} RT_RF_POWER_STATE;
typedef enum _RT_JOIN_ACTION {
RT_JOIN_INFRA = 1,
RT_JOIN_IBSS = 2,
RT_START_IBSS = 3,
RT_NO_ACTION = 4,
} RT_JOIN_ACTION;
typedef enum _IPS_CALLBACK_FUNCION {
IPS_CALLBACK_NONE = 0,
IPS_CALLBACK_MGNT_LINK_REQUEST = 1,
IPS_CALLBACK_JOIN_REQUEST = 2,
} IPS_CALLBACK_FUNCION;
typedef struct _RT_POWER_SAVE_CONTROL {
/* Inactive Power Save(IPS) : Disable RF when disconnected */
bool bInactivePs;
bool bIPSModeBackup;
bool bSwRfProcessing;
RT_RF_POWER_STATE eInactivePowerState;
struct work_struct InactivePsWorkItem;
struct timer_list InactivePsTimer;
/* Return point for join action */
IPS_CALLBACK_FUNCION ReturnPoint;
/* Recored Parameters for rescheduled JoinRequest */
bool bTmpBssDesc;
RT_JOIN_ACTION tmpJoinAction;
struct ieee80211_network tmpBssDesc;
/* Recored Parameters for rescheduled MgntLinkRequest */
bool bTmpScanOnly;
bool bTmpActiveScan;
bool bTmpFilterHiddenAP;
bool bTmpUpdateParms;
u8 tmpSsidBuf[33];
OCTET_STRING tmpSsid2Scan;
bool bTmpSsid2Scan;
u8 tmpNetworkType;
u8 tmpChannelNumber;
u16 tmpBcnPeriod;
u8 tmpDtimPeriod;
u16 tmpmCap;
OCTET_STRING tmpSuppRateSet;
u8 tmpSuppRateBuf[MAX_NUM_RATES];
bool bTmpSuppRate;
IbssParms tmpIbpm;
bool bTmpIbpm;
/*
* Leisure Power Save:
* Disable RF if connected but traffic is not busy
*/
bool bLeisurePs;
u32 PowerProfile;
u8 LpsIdleCount;
u32 CurPsLevel;
u32 RegRfPsLevel;
bool bFwCtrlLPS;
u8 FWCtrlPSMode;
bool LinkReqInIPSRFOffPgs;
bool BufConnectinfoBefore;
} RT_POWER_SAVE_CONTROL, *PRT_POWER_SAVE_CONTROL;
/* For rtl819x */
typedef struct _tx_desc_819x_pci {
//DWORD 0
u16 PktSize;
u8 Offset;
u8 Reserved1:3;
u8 CmdInit:1;
u8 LastSeg:1;
u8 FirstSeg:1;
u8 LINIP:1;
u8 OWN:1;
//DWORD 1
u8 TxFWInfoSize;
u8 RATid:3;
u8 DISFB:1;
u8 USERATE:1;
u8 MOREFRAG:1;
u8 NoEnc:1;
u8 PIFS:1;
u8 QueueSelect:5;
u8 NoACM:1;
u8 Resv:2;
u8 SecCAMID:5;
u8 SecDescAssign:1;
u8 SecType:2;
//DWORD 2
u16 TxBufferSize;
u8 PktId:7;
u8 Resv1:1;
u8 Reserved2;
//DWORD 3
u32 TxBuffAddr;
//DWORD 4
u32 NextDescAddress;
//DWORD 5,6,7
u32 Reserved5;
u32 Reserved6;
u32 Reserved7;
}tx_desc_819x_pci, *ptx_desc_819x_pci;
typedef struct _tx_desc_cmd_819x_pci {
//DWORD 0
u16 PktSize;
u8 Reserved1;
u8 CmdType:3;
u8 CmdInit:1;
u8 LastSeg:1;
u8 FirstSeg:1;
u8 LINIP:1;
u8 OWN:1;
//DOWRD 1
u16 ElementReport;
u16 Reserved2;
//DOWRD 2
u16 TxBufferSize;
u16 Reserved3;
//DWORD 3,4,5
u32 TxBufferAddr;
u32 NextDescAddress;
u32 Reserved4;
u32 Reserved5;
u32 Reserved6;
}tx_desc_cmd_819x_pci, *ptx_desc_cmd_819x_pci;
typedef struct _tx_fwinfo_819x_pci {
//DOWRD 0
u8 TxRate:7;
u8 CtsEnable:1;
u8 RtsRate:7;
u8 RtsEnable:1;
u8 TxHT:1;
u8 Short:1; //Short PLCP for CCK, or short GI for 11n MCS
u8 TxBandwidth:1; // This is used for HT MCS rate only.
u8 TxSubCarrier:2; // This is used for legacy OFDM rate only.
u8 STBC:2;
u8 AllowAggregation:1;
u8 RtsHT:1; //Interpre RtsRate field as high throughput data rate
u8 RtsShort:1; //Short PLCP for CCK, or short GI for 11n MCS
u8 RtsBandwidth:1; // This is used for HT MCS rate only.
u8 RtsSubcarrier:2; // This is used for legacy OFDM rate only.
u8 RtsSTBC:2;
u8 EnableCPUDur:1; //Enable firmware to recalculate and assign packet duration
//DWORD 1
u8 RxMF:2;
u8 RxAMD:3;
u8 Reserved1:3;
u8 Reserved2;
u8 Reserved3;
u8 Reserved4;
//u32 Reserved;
}tx_fwinfo_819x_pci, *ptx_fwinfo_819x_pci;
typedef struct _rx_desc_819x_pci{
//DOWRD 0
u16 Length:14;
u16 CRC32:1;
u16 ICV:1;
u8 RxDrvInfoSize;
u8 Shift:2;
u8 PHYStatus:1;
u8 SWDec:1;
u8 LastSeg:1;
u8 FirstSeg:1;
u8 EOR:1;
u8 OWN:1;
//DWORD 1
u32 Reserved2;
//DWORD 2
u32 Reserved3;
//DWORD 3
u32 BufferAddress;
}rx_desc_819x_pci, *prx_desc_819x_pci;
typedef struct _rx_fwinfo_819x_pci{
//DWORD 0
u16 Reserved1:12;
u16 PartAggr:1;
u16 FirstAGGR:1;
u16 Reserved2:2;
u8 RxRate:7;
u8 RxHT:1;
u8 BW:1;
u8 SPLCP:1;
u8 Reserved3:2;
u8 PAM:1;
u8 Mcast:1;
u8 Bcast:1;
u8 Reserved4:1;
//DWORD 1
u32 TSFL;
}rx_fwinfo_819x_pci, *prx_fwinfo_819x_pci;
#define MAX_DEV_ADDR_SIZE 8 /* support till 64 bit bus width OS */
#define MAX_FIRMWARE_INFORMATION_SIZE 32 /*2006/04/30 by Emily forRTL8190*/
#define MAX_802_11_HEADER_LENGTH (40 + MAX_FIRMWARE_INFORMATION_SIZE)
#define ENCRYPTION_MAX_OVERHEAD 128
#define MAX_FRAGMENT_COUNT 8
#define MAX_TRANSMIT_BUFFER_SIZE (1600+(MAX_802_11_HEADER_LENGTH+ENCRYPTION_MAX_OVERHEAD)*MAX_FRAGMENT_COUNT)
#define scrclng 4 // octets for crc32 (FCS, ICV)
/* 8190 Loopback Mode definition */
typedef enum _rtl819x_loopback{
RTL819X_NO_LOOPBACK = 0,
RTL819X_MAC_LOOPBACK = 1,
RTL819X_DMA_LOOPBACK = 2,
RTL819X_CCK_LOOPBACK = 3,
}rtl819x_loopback_e;
/* due to rtl8192 firmware */
typedef enum _desc_packet_type_e{
DESC_PACKET_TYPE_INIT = 0,
DESC_PACKET_TYPE_NORMAL = 1,
}desc_packet_type_e;
typedef enum _firmware_status{
FW_STATUS_0_INIT = 0,
FW_STATUS_1_MOVE_BOOT_CODE = 1,
FW_STATUS_2_MOVE_MAIN_CODE = 2,
FW_STATUS_3_TURNON_CPU = 3,
FW_STATUS_4_MOVE_DATA_CODE = 4,
FW_STATUS_5_READY = 5,
}firmware_status_e;
typedef struct _rt_firmware{
firmware_status_e firmware_status;
u16 cmdpacket_frag_thresold;
#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000 //64k
#define MAX_FW_INIT_STEP 3
u8 firmware_buf[MAX_FW_INIT_STEP][RTL8190_MAX_FIRMWARE_CODE_SIZE];
u16 firmware_buf_size[MAX_FW_INIT_STEP];
}rt_firmware, *prt_firmware;
#define MAX_RECEIVE_BUFFER_SIZE 9100 // Add this to 9100 bytes to receive A-MSDU from RT-AP
/* Firmware Queue Layout */
#define NUM_OF_FIRMWARE_QUEUE 10
#define NUM_OF_PAGES_IN_FW 0x100
#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x0aa
#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x007
#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x024
#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x007
#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0
#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x2
#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x10
#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0
#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x4
#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xd
#define APPLIED_RESERVED_QUEUE_IN_FW 0x80000000
#define RSVD_FW_QUEUE_PAGE_BK_SHIFT 0x00
#define RSVD_FW_QUEUE_PAGE_BE_SHIFT 0x08
#define RSVD_FW_QUEUE_PAGE_VI_SHIFT 0x10
#define RSVD_FW_QUEUE_PAGE_VO_SHIFT 0x18
#define RSVD_FW_QUEUE_PAGE_MGNT_SHIFT 0x10
#define RSVD_FW_QUEUE_PAGE_CMD_SHIFT 0x08
#define RSVD_FW_QUEUE_PAGE_BCN_SHIFT 0x00
#define RSVD_FW_QUEUE_PAGE_PUB_SHIFT 0x08
#define DCAM 0xAC // Debug CAM Interface
#define AESMSK_FC 0xB2 // AES Mask register for frame control (0xB2~0xB3). Added by Annie, 2006-03-06.
#define CAM_CONTENT_COUNT 8
#define CFG_VALID BIT15
#define EPROM_93c46 0
#define EPROM_93c56 1
#define DEFAULT_FRAG_THRESHOLD 2342U
#define MIN_FRAG_THRESHOLD 256U
#define DEFAULT_BEACONINTERVAL 0x64U
#define DEFAULT_RETRY_RTS 7
#define DEFAULT_RETRY_DATA 7
#define PHY_RSSI_SLID_WIN_MAX 100
typedef enum _WIRELESS_MODE {
WIRELESS_MODE_UNKNOWN = 0x00,
WIRELESS_MODE_A = 0x01,
WIRELESS_MODE_B = 0x02,
WIRELESS_MODE_G = 0x04,
WIRELESS_MODE_AUTO = 0x08,
WIRELESS_MODE_N_24G = 0x10,
WIRELESS_MODE_N_5G = 0x20
} WIRELESS_MODE;
#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30
typedef struct buffer
{
struct buffer *next;
u32 *buf;
dma_addr_t dma;
} buffer;
typedef struct _rt_9x_tx_rate_history {
u32 cck[4];
u32 ofdm[8];
// HT_MCS[0][]: BW=0 SG=0
// HT_MCS[1][]: BW=1 SG=0
// HT_MCS[2][]: BW=0 SG=1
// HT_MCS[3][]: BW=1 SG=1
u32 ht_mcs[4][16];
}rt_tx_rahis_t, *prt_tx_rahis_t;
typedef struct _RT_SMOOTH_DATA_4RF {
char elements[4][100];//array to store values
u32 index; //index to current array to store
u32 TotalNum; //num of valid elements
u32 TotalVal[4]; //sum of valid elements
}RT_SMOOTH_DATA_4RF, *PRT_SMOOTH_DATA_4RF;
typedef enum _tag_TxCmd_Config_Index{
TXCMD_TXRA_HISTORY_CTRL = 0xFF900000,
TXCMD_RESET_TX_PKT_BUFF = 0xFF900001,
TXCMD_RESET_RX_PKT_BUFF = 0xFF900002,
TXCMD_SET_TX_DURATION = 0xFF900003,
TXCMD_SET_RX_RSSI = 0xFF900004,
TXCMD_SET_TX_PWR_TRACKING = 0xFF900005,
TXCMD_XXXX_CTRL,
}DCMD_TXCMD_OP;
typedef struct Stats
{
unsigned long rxrdu;
unsigned long rxok;
unsigned long received_rate_histogram[4][32]; //0: Total, 1:OK, 2:CRC, 3:ICV
unsigned long rxoverflow;
unsigned long rxint;
unsigned long txoverflow;
unsigned long txbeokint;
unsigned long txbkokint;
unsigned long txviokint;
unsigned long txvookint;
unsigned long txbeaconokint;
unsigned long txbeaconerr;
unsigned long txmanageokint;
unsigned long txcmdpktokint;
unsigned long txfeedback;
unsigned long txfeedbackok;
unsigned long txoktotal;
unsigned long txbytesunicast;
unsigned long rxbytesunicast;
unsigned long slide_signal_strength[100];
unsigned long slide_evm[100];
unsigned long slide_rssi_total; // For recording sliding window's RSSI value
unsigned long slide_evm_total; // For recording sliding window's EVM value
long signal_strength; // Transformed, in dbm. Beautified signal strength for UI, not correct.
u8 rx_rssi_percentage[4];
u8 rx_evm_percentage[2];
u32 Slide_Beacon_pwdb[100];
u32 Slide_Beacon_Total;
RT_SMOOTH_DATA_4RF cck_adc_pwdb;
} Stats;
// Bandwidth Offset
#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0
#define HAL_PRIME_CHNL_OFFSET_LOWER 1
#define HAL_PRIME_CHNL_OFFSET_UPPER 2
typedef struct ChnlAccessSetting {
u16 SIFS_Timer;
u16 DIFS_Timer;
u16 SlotTimeTimer;
u16 EIFS_Timer;
u16 CWminIndex;
u16 CWmaxIndex;
}*PCHANNEL_ACCESS_SETTING,CHANNEL_ACCESS_SETTING;
typedef struct _BB_REGISTER_DEFINITION{
u32 rfintfs; // set software control: // 0x870~0x877[8 bytes]
u32 rfintfi; // readback data: // 0x8e0~0x8e7[8 bytes]
u32 rfintfo; // output data: // 0x860~0x86f [16 bytes]
u32 rfintfe; // output enable: // 0x860~0x86f [16 bytes]
u32 rf3wireOffset; // LSSI data: // 0x840~0x84f [16 bytes]
u32 rfLSSI_Select; // BB Band Select: // 0x878~0x87f [8 bytes]
u32 rfTxGainStage; // Tx gain stage: // 0x80c~0x80f [4 bytes]
u32 rfHSSIPara1; // wire parameter control1 : // 0x820~0x823,0x828~0x82b, 0x830~0x833, 0x838~0x83b [16 bytes]
u32 rfHSSIPara2; // wire parameter control2 : // 0x824~0x827,0x82c~0x82f, 0x834~0x837, 0x83c~0x83f [16 bytes]
u32 rfSwitchControl; //Tx Rx antenna control : // 0x858~0x85f [16 bytes]
u32 rfAGCControl1; //AGC parameter control1 : // 0xc50~0xc53,0xc58~0xc5b, 0xc60~0xc63, 0xc68~0xc6b [16 bytes]
u32 rfAGCControl2; //AGC parameter control2 : // 0xc54~0xc57,0xc5c~0xc5f, 0xc64~0xc67, 0xc6c~0xc6f [16 bytes]
u32 rfRxIQImbalance; //OFDM Rx IQ imbalance matrix : // 0xc14~0xc17,0xc1c~0xc1f, 0xc24~0xc27, 0xc2c~0xc2f [16 bytes]
u32 rfRxAFE; //Rx IQ DC ofset and Rx digital filter, Rx DC notch filter : // 0xc10~0xc13,0xc18~0xc1b, 0xc20~0xc23, 0xc28~0xc2b [16 bytes]
u32 rfTxIQImbalance; //OFDM Tx IQ imbalance matrix // 0xc80~0xc83,0xc88~0xc8b, 0xc90~0xc93, 0xc98~0xc9b [16 bytes]
u32 rfTxAFE; //Tx IQ DC Offset and Tx DFIR type // 0xc84~0xc87,0xc8c~0xc8f, 0xc94~0xc97, 0xc9c~0xc9f [16 bytes]
u32 rfLSSIReadBack; //LSSI RF readback data // 0x8a0~0x8af [16 bytes]
}BB_REGISTER_DEFINITION_T, *PBB_REGISTER_DEFINITION_T;
typedef struct _rate_adaptive
{
u8 rate_adaptive_disabled;
u8 ratr_state;
u16 reserve;
u32 high_rssi_thresh_for_ra;
u32 high2low_rssi_thresh_for_ra;
u8 low2high_rssi_thresh_for_ra40M;
u32 low_rssi_thresh_for_ra40M;
u8 low2high_rssi_thresh_for_ra20M;
u32 low_rssi_thresh_for_ra20M;
u32 upper_rssi_threshold_ratr;
u32 middle_rssi_threshold_ratr;
u32 low_rssi_threshold_ratr;
u32 low_rssi_threshold_ratr_40M;
u32 low_rssi_threshold_ratr_20M;
u8 ping_rssi_enable; //cosa add for test
u32 ping_rssi_ratr; //cosa add for test
u32 ping_rssi_thresh_for_ra;//cosa add for test
u32 last_ratr;
} rate_adaptive, *prate_adaptive;
#define TxBBGainTableLength 37
#define CCKTxBBGainTableLength 23
typedef struct _txbbgain_struct
{
long txbb_iq_amplifygain;
u32 txbbgain_value;
} txbbgain_struct, *ptxbbgain_struct;
typedef struct _ccktxbbgain_struct
{
//The Value is from a22 to a29 one Byte one time is much Safer
u8 ccktxbb_valuearray[8];
} ccktxbbgain_struct,*pccktxbbgain_struct;
typedef struct _init_gain
{
u8 xaagccore1;
u8 xbagccore1;
u8 xcagccore1;
u8 xdagccore1;
u8 cca;
} init_gain, *pinit_gain;
/* 2007/11/02 MH Define RF mode temporarily for test. */
typedef enum tag_Rf_Operatetion_State
{
RF_STEP_INIT = 0,
RF_STEP_NORMAL,
RF_STEP_MAX
}RF_STEP_E;
typedef enum _RT_STATUS{
RT_STATUS_SUCCESS,
RT_STATUS_FAILURE,
RT_STATUS_PENDING,
RT_STATUS_RESOURCE
}RT_STATUS,*PRT_STATUS;
typedef enum _RT_CUSTOMER_ID
{
RT_CID_DEFAULT = 0,
RT_CID_8187_ALPHA0 = 1,
RT_CID_8187_SERCOMM_PS = 2,
RT_CID_8187_HW_LED = 3,
RT_CID_8187_NETGEAR = 4,
RT_CID_WHQL = 5,
RT_CID_819x_CAMEO = 6,
RT_CID_819x_RUNTOP = 7,
RT_CID_819x_Senao = 8,
RT_CID_TOSHIBA = 9, // Merge by Jacken, 2008/01/31.
RT_CID_819x_Netcore = 10,
RT_CID_Nettronix = 11,
RT_CID_DLINK = 12,
RT_CID_PRONET = 13,
RT_CID_COREGA = 14,
}RT_CUSTOMER_ID, *PRT_CUSTOMER_ID;
/* LED customization. */
typedef enum _LED_STRATEGY_8190{
SW_LED_MODE0, // SW control 1 LED via GPIO0. It is default option.
SW_LED_MODE1, // SW control for PCI Express
SW_LED_MODE2, // SW control for Cameo.
SW_LED_MODE3, // SW contorl for RunTop.
SW_LED_MODE4, // SW control for Netcore
SW_LED_MODE5, //added by vivi, for led new mode, DLINK
SW_LED_MODE6, //added by vivi, for led new mode, PRONET
HW_LED, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes)
}LED_STRATEGY_8190, *PLED_STRATEGY_8190;
#define CHANNEL_PLAN_LEN 10
#define sCrcLng 4
typedef struct _TX_FWINFO_STRUCUTRE{
//DOWRD 0
u8 TxRate:7;
u8 CtsEnable:1;
u8 RtsRate:7;
u8 RtsEnable:1;
u8 TxHT:1;
u8 Short:1;
u8 TxBandwidth:1;
u8 TxSubCarrier:2;
u8 STBC:2;
u8 AllowAggregation:1;
u8 RtsHT:1;
u8 RtsShort:1;
u8 RtsBandwidth:1;
u8 RtsSubcarrier:2;
u8 RtsSTBC:2;
u8 EnableCPUDur:1;
//DWORD 1
u32 RxMF:2;
u32 RxAMD:3;
u32 Reserved1:3;
u32 TxAGCOffset:4;
u32 TxAGCSign:1;
u32 Tx_INFO_RSVD:6;
u32 PacketID:13;
}TX_FWINFO_T;
typedef struct _TX_FWINFO_8190PCI{
//DOWRD 0
u8 TxRate:7;
u8 CtsEnable:1;
u8 RtsRate:7;
u8 RtsEnable:1;
u8 TxHT:1;
u8 Short:1; //Short PLCP for CCK, or short GI for 11n MCS
u8 TxBandwidth:1; // This is used for HT MCS rate only.
u8 TxSubCarrier:2; // This is used for legacy OFDM rate only.
u8 STBC:2;
u8 AllowAggregation:1;
u8 RtsHT:1; //Interpre RtsRate field as high throughput data rate
u8 RtsShort:1; //Short PLCP for CCK, or short GI for 11n MCS
u8 RtsBandwidth:1; // This is used for HT MCS rate only.
u8 RtsSubcarrier:2; // This is used for legacy OFDM rate only.
u8 RtsSTBC:2;
u8 EnableCPUDur:1; //Enable firmware to recalculate and assign packet duration
//DWORD 1
u32 RxMF:2;
u32 RxAMD:3;
u32 TxPerPktInfoFeedback:1; // 1: indicate that the transimission info of this packet should be gathered by Firmware and retured by Rx Cmd.
u32 Reserved1:2;
u32 TxAGCOffset:4; // Only 90 support
u32 TxAGCSign:1; // Only 90 support
u32 RAW_TXD:1; // MAC will send data in txpktbuffer without any processing,such as CRC check
u32 Retry_Limit:4; // CCX Support relative retry limit FW page only support 4 bits now.
u32 Reserved2:1;
u32 PacketID:13;
// DW 2
}TX_FWINFO_8190PCI, *PTX_FWINFO_8190PCI;
typedef struct _phy_ofdm_rx_status_report_819xpci
{
u8 trsw_gain_X[4];
u8 pwdb_all;
u8 cfosho_X[4];
u8 cfotail_X[4];
u8 rxevm_X[2];
u8 rxsnr_X[4];
u8 pdsnr_X[2];
u8 csi_current_X[2];
u8 csi_target_X[2];
u8 sigevm;
u8 max_ex_pwr;
u8 sgi_en;
u8 rxsc_sgien_exflg;
}phy_sts_ofdm_819xpci_t;
typedef struct _phy_cck_rx_status_report_819xpci
{
/* For CCK rate descriptor. This is a unsigned 8:1 variable. LSB bit presend
0.5. And MSB 7 bts presend a signed value. Range from -64~+63.5. */
u8 adc_pwdb_X[4];
u8 sq_rpt;
u8 cck_agc_rpt;
}phy_sts_cck_819xpci_t;
typedef struct _phy_ofdm_rx_status_rxsc_sgien_exintfflag{
u8 reserved:4;
u8 rxsc:2;
u8 sgi_en:1;
u8 ex_intf_flag:1;
}phy_ofdm_rx_status_rxsc_sgien_exintfflag;
typedef enum _RT_OP_MODE{
RT_OP_MODE_AP,
RT_OP_MODE_INFRASTRUCTURE,
RT_OP_MODE_IBSS,
RT_OP_MODE_NO_LINK,
}RT_OP_MODE, *PRT_OP_MODE;
/* 2007/11/02 MH Define RF mode temporarily for test. */
typedef enum tag_Rf_OpType
{
RF_OP_By_SW_3wire = 0,
RF_OP_By_FW,
RF_OP_MAX
}RF_OpType_E;
typedef enum _RESET_TYPE {
RESET_TYPE_NORESET = 0x00,
RESET_TYPE_NORMAL = 0x01,
RESET_TYPE_SILENT = 0x02
} RESET_TYPE;
typedef struct _tx_ring{
u32 * desc;
u8 nStuckCount;
struct _tx_ring * next;
}__attribute__ ((packed)) tx_ring, * ptx_ring;
struct rtl8192_tx_ring {
tx_desc_819x_pci *desc;
dma_addr_t dma;
unsigned int idx;
unsigned int entries;
struct sk_buff_head queue;
};
#define NIC_SEND_HANG_THRESHOLD_NORMAL 4
#define NIC_SEND_HANG_THRESHOLD_POWERSAVE 8
#define MAX_TX_QUEUE 9 // BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON.
#define MAX_RX_COUNT 64
#define MAX_TX_QUEUE_COUNT 9
typedef struct r8192_priv
{
struct pci_dev *pdev;
u8 *mem_start;
/* maintain info from eeprom */
short epromtype;
u16 eeprom_vid;
u16 eeprom_did;
u8 eeprom_CustomerID;
u16 eeprom_ChannelPlan;
RT_CUSTOMER_ID CustomerID;
u8 IC_Cut;
int irq;
struct ieee80211_device *ieee80211;
#ifdef ENABLE_LPS
bool ps_force;
bool force_lps;
bool bdisable_nic;
#endif
bool being_init_adapter;
u8 Rf_Mode;
u8 card_8192_version; /* if TCR reports card V B/C this discriminates */
spinlock_t irq_th_lock;
spinlock_t rf_ps_lock;
struct mutex mutex;
short chan;
short sens;
/* RX stuff */
rx_desc_819x_pci *rx_ring;
dma_addr_t rx_ring_dma;
unsigned int rx_idx;
struct sk_buff *rx_buf[MAX_RX_COUNT];
int rxringcount;
u16 rxbuffersize;
/* TX stuff */
struct rtl8192_tx_ring tx_ring[MAX_TX_QUEUE_COUNT];
int txringcount;
struct tasklet_struct irq_rx_tasklet;
struct tasklet_struct irq_tx_tasklet;
struct tasklet_struct irq_prepare_beacon_tasklet;
short up;
short crcmon; //if 1 allow bad crc frame reception in monitor mode
struct semaphore wx_sem;
struct semaphore rf_sem; //used to lock rf write operation added by wb, modified by david
u8 rf_type; /* 0 means 1T2R, 1 means 2T4R */
short (*rf_set_sens)(struct net_device *dev, short sens);
u8 (*rf_set_chan)(struct ieee80211_device *ieee80211, u8 ch);
short promisc;
/* stats */
struct Stats stats;
struct iw_statistics wstats;
struct proc_dir_entry *dir_dev;
struct ieee80211_rx_stats previous_stats;
/* RX stuff */
struct sk_buff_head skb_queue;
struct work_struct qos_activate;
//2 Tx Related variables
u16 ShortRetryLimit;
u16 LongRetryLimit;
u32 LastRxDescTSFHigh;
u32 LastRxDescTSFLow;
//2 Rx Related variables
u32 ReceiveConfig;
u8 retry_data;
u8 retry_rts;
struct work_struct reset_wq;
u8 rx_chk_cnt;
//for rtl819xPci
// Data Rate Config. Added by Annie, 2006-04-13.
u16 basic_rate;
u8 short_preamble;
u8 slot_time;
u16 SifsTime;
/* WirelessMode*/
u8 RegWirelessMode;
/*Firmware*/
prt_firmware pFirmware;
rtl819x_loopback_e LoopbackMode;
bool AutoloadFailFlag;
u16 EEPROMAntPwDiff; // Antenna gain offset from B/C/D to A
u8 EEPROMThermalMeter;
u8 EEPROMCrystalCap;
u8 EEPROMTxPowerLevelCCK[14];// CCK channel 1~14
// The following definition is for eeprom 93c56
u8 EEPROMRfACCKChnl1TxPwLevel[3]; //RF-A CCK Tx Power Level at channel 7
u8 EEPROMRfAOfdmChnlTxPwLevel[3];//RF-A CCK Tx Power Level at [0],[1],[2] = channel 1,7,13
u8 EEPROMRfCCCKChnl1TxPwLevel[3]; //RF-C CCK Tx Power Level at channel 7
u8 EEPROMRfCOfdmChnlTxPwLevel[3];//RF-C CCK Tx Power Level at [0],[1],[2] = channel 1,7,13
u8 EEPROMTxPowerLevelOFDM24G[14]; // OFDM 2.4G channel 1~14
u8 EEPROMLegacyHTTxPowerDiff; // Legacy to HT rate power diff
bool bTXPowerDataReadFromEEPORM;
/*channel plan*/
u16 RegChannelPlan; // Channel Plan specifed by user, 15: following setting of EEPROM, 0-14: default channel plan index specified by user.
u16 ChannelPlan;
/*PS related*/
// Rf off action for power save
u8 bHwRfOffAction; //0:No action, 1:By GPIO, 2:By Disable
/*PHY related*/
BB_REGISTER_DEFINITION_T PHYRegDef[4]; //Radio A/B/C/D
// Read/write are allow for following hardware information variables
u32 MCSTxPowerLevelOriginalOffset[6];
u32 CCKTxPowerLevelOriginalOffset;
u8 TxPowerLevelCCK[14]; // CCK channel 1~14
u8 TxPowerLevelCCK_A[14]; // RF-A, CCK channel 1~14
u8 TxPowerLevelCCK_C[14];
u8 TxPowerLevelOFDM24G[14]; // OFDM 2.4G channel 1~14
u8 TxPowerLevelOFDM5G[14]; // OFDM 5G
u8 TxPowerLevelOFDM24G_A[14]; // RF-A, OFDM 2.4G channel 1~14
u8 TxPowerLevelOFDM24G_C[14]; // RF-C, OFDM 2.4G channel 1~14
u8 LegacyHTTxPowerDiff; // Legacy to HT rate power diff
u8 AntennaTxPwDiff[3]; // Antenna gain offset, index 0 for B, 1 for C, and 2 for D
u8 CrystalCap; // CrystalCap.
u8 ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1
//05/27/2008 cck power enlarge
u8 CckPwEnl;
u16 TSSI_13dBm;
u32 Pwr_Track;
u8 CCKPresentAttentuation_20Mdefault;
u8 CCKPresentAttentuation_40Mdefault;
char CCKPresentAttentuation_difference;
char CCKPresentAttentuation;
// Use to calculate PWBD.
RT_RF_POWER_STATE eRFPowerState;
RT_RF_CHANGE_SOURCE RfOffReason;
RT_POWER_SAVE_CONTROL PowerSaveControl;
u8 bCckHighPower;
long undecorated_smoothed_pwdb;
long undecorated_smoothed_cck_adc_pwdb[4];
//for set channel
u8 SwChnlInProgress;
u8 SwChnlStage;
u8 SwChnlStep;
u8 SetBWModeInProgress;
HT_CHANNEL_WIDTH CurrentChannelBW;
// 8190 40MHz mode
//
u8 nCur40MhzPrimeSC; // Control channel sub-carrier
// Joseph test for shorten RF configuration time.
// We save RF reg0 in this variable to reduce RF reading.
//
u32 RfReg0Value[4];
u8 NumTotalRFPath;
bool brfpath_rxenable[4];
//+by amy 080507
struct timer_list watch_dog_timer;
u8 watchdog_last_time;
u8 watchdog_check_reset_cnt;
//+by amy 080515 for dynamic mechenism
//Add by amy Tx Power Control for Near/Far Range 2008/05/15
bool bDynamicTxHighPower; // Tx high power state
bool bDynamicTxLowPower; // Tx low power state
bool bLastDTPFlag_High;
bool bLastDTPFlag_Low;
/* OFDM RSSI. For high power or not */
u8 phy_check_reg824;
u32 phy_reg824_bit9;
//Add by amy for Rate Adaptive
rate_adaptive rate_adaptive;
//Add by amy for TX power tracking
//2008/05/15 Mars OPEN/CLOSE TX POWER TRACKING
const txbbgain_struct * txbbgain_table;
u8 txpower_count;//For 6 sec do tracking again
bool btxpower_trackingInit;
u8 OFDM_index;
u8 CCK_index;
u8 Record_CCK_20Mindex;
u8 Record_CCK_40Mindex;
//2007/09/10 Mars Add CCK TX Power Tracking
const ccktxbbgain_struct *cck_txbbgain_table;
const ccktxbbgain_struct *cck_txbbgain_ch14_table;
u8 rfa_txpowertrackingindex;
u8 rfa_txpowertrackingindex_real;
u8 rfa_txpowertracking_default;
u8 rfc_txpowertrackingindex;
u8 rfc_txpowertrackingindex_real;
u8 rfc_txpowertracking_default;
bool btxpower_tracking;
bool bcck_in_ch14;
//For Backup Initial Gain
init_gain initgain_backup;
u8 DefaultInitialGain[4];
// For EDCA Turbo mode, Added by amy 080515.
bool bis_any_nonbepkts;
bool bcurrent_turbo_EDCA;
bool bis_cur_rdlstate;
struct timer_list fsync_timer;
u32 rate_record;
u32 rateCountDiffRecord;
u32 ContiuneDiffCount;
bool bswitch_fsync;
u8 framesync;
u32 framesyncC34;
u8 framesyncMonitor;
//by amy for gpio
bool bHwRadioOff;
//by amy for ps
RT_OP_MODE OpMode;
//by amy for reset_count
u32 reset_count;
//by amy for silent reset
RESET_TYPE ResetProgress;
bool bForcedSilentReset;
bool bDisableNormalResetCheck;
u16 TxCounter;
u16 RxCounter;
int IrpPendingCount;
bool bResetInProgress;
bool force_reset;
u8 InitialGainOperateType;
//define work item by amy 080526
struct delayed_work update_beacon_wq;
struct delayed_work watch_dog_wq;
struct delayed_work txpower_tracking_wq;
struct delayed_work rfpath_check_wq;
struct delayed_work gpio_change_rf_wq;
struct delayed_work initialgain_operate_wq;
struct workqueue_struct *priv_wq;
}r8192_priv;
bool init_firmware(struct r8192_priv *priv);
u32 read_cam(struct r8192_priv *priv, u8 addr);
void write_cam(struct r8192_priv *priv, u8 addr, u32 data);
u8 read_nic_byte(struct r8192_priv *priv, int x);
u32 read_nic_dword(struct r8192_priv *priv, int x);
u16 read_nic_word(struct r8192_priv *priv, int x) ;
void write_nic_byte(struct r8192_priv *priv, int x,u8 y);
void write_nic_word(struct r8192_priv *priv, int x,u16 y);
void write_nic_dword(struct r8192_priv *priv, int x,u32 y);
int rtl8192_down(struct net_device *dev);
int rtl8192_up(struct net_device *dev);
void rtl8192_commit(struct r8192_priv *priv);
void write_phy(struct net_device *dev, u8 adr, u8 data);
void CamResetAllEntry(struct r8192_priv *priv);
void EnableHWSecurityConfig8192(struct r8192_priv *priv);
void setKey(struct r8192_priv *priv, u8 EntryNo, u8 KeyIndex, u16 KeyType,
const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent);
void firmware_init_param(struct r8192_priv *priv);
RT_STATUS cmpk_message_handle_tx(struct r8192_priv *priv, u8 *codevirtualaddress, u32 packettype, u32 buffer_len);
#ifdef ENABLE_IPS
void IPSEnter(struct r8192_priv *priv);
void IPSLeave(struct r8192_priv *priv);
void IPSLeave_wq(struct work_struct *work);
void ieee80211_ips_leave_wq(struct ieee80211_device *ieee80211);
void ieee80211_ips_leave(struct ieee80211_device *ieee80211);
#endif
#ifdef ENABLE_LPS
void LeisurePSEnter(struct ieee80211_device *ieee80211);
void LeisurePSLeave(struct ieee80211_device *ieee80211);
#endif
bool NicIFEnableNIC(struct r8192_priv *priv);
bool NicIFDisableNIC(struct r8192_priv *priv);
void PHY_SetRtl8192eRfOff(struct r8192_priv *priv);
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
/*++
Copyright-c Realtek Semiconductor Corp. All rights reserved.
Module Name:
r8192U_dm.c
Abstract:
HW dynamic mechanism.
Major Change History:
When Who What
---------- --------------- -------------------------------
2008-05-14 amy create version 0 porting from windows code.
--*/
#include "r8192E.h"
#include "r8192E_dm.h"
#include "r8192E_hw.h"
#include "r819xE_phy.h"
#include "r819xE_phyreg.h"
#include "r8190_rtl8256.h"
#define DRV_NAME "rtl819xE"
//
// Indicate different AP vendor for IOT issue.
//
static const u32 edca_setting_DL[HT_IOT_PEER_MAX] =
{ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5e4322, 0x5e4322};
static const u32 edca_setting_UL[HT_IOT_PEER_MAX] =
{ 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5e4322, 0x5e4322, 0x5e4322};
#define RTK_UL_EDCA 0xa44f
#define RTK_DL_EDCA 0x5e4322
dig_t dm_digtable;
// For Dynamic Rx Path Selection by Signal Strength
DRxPathSel DM_RxPathSelTable;
void dm_gpio_change_rf_callback(struct work_struct *work);
// DM --> Rate Adaptive
static void dm_check_rate_adaptive(struct r8192_priv *priv);
// DM --> Bandwidth switch
static void dm_init_bandwidth_autoswitch(struct r8192_priv *priv);
static void dm_bandwidth_autoswitch(struct r8192_priv *priv);
// DM --> TX power control
static void dm_check_txpower_tracking(struct r8192_priv *priv);
// DM --> Dynamic Init Gain by RSSI
static void dm_dig_init(struct r8192_priv *priv);
static void dm_ctrl_initgain_byrssi(struct r8192_priv *priv);
static void dm_ctrl_initgain_byrssi_highpwr(struct r8192_priv *priv);
static void dm_ctrl_initgain_byrssi_by_driverrssi(struct r8192_priv *priv);
static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(struct r8192_priv *priv);
static void dm_initial_gain(struct r8192_priv *priv);
static void dm_pd_th(struct r8192_priv *priv);
static void dm_cs_ratio(struct r8192_priv *priv);
static void dm_init_ctstoself(struct r8192_priv *priv);
// DM --> EDCA turboe mode control
static void dm_check_edca_turbo(struct r8192_priv *priv);
static void dm_init_edca_turbo(struct r8192_priv *priv);
// DM --> HW RF control
static void dm_check_rfctrl_gpio(struct r8192_priv *priv);
// DM --> Check current RX RF path state
static void dm_check_rx_path_selection(struct r8192_priv *priv);
static void dm_init_rxpath_selection(struct r8192_priv *priv);
static void dm_rxpath_sel_byrssi(struct r8192_priv *priv);
// DM --> Fsync for broadcom ap
static void dm_init_fsync(struct r8192_priv *priv);
static void dm_deInit_fsync(struct r8192_priv *priv);
static void dm_check_txrateandretrycount(struct r8192_priv *priv);
static void dm_check_fsync(struct r8192_priv *priv);
/*---------------------Define of Tx Power Control For Near/Far Range --------*/ //Add by Jacken 2008/02/18
static void dm_init_dynamic_txpower(struct r8192_priv *priv);
static void dm_dynamic_txpower(struct r8192_priv *priv);
// DM --> For rate adaptive and DIG, we must send RSSI to firmware
static void dm_send_rssi_tofw(struct r8192_priv *priv);
static void dm_ctstoself(struct r8192_priv *priv);
static void dm_fsync_timer_callback(unsigned long data);
/*
* Prepare SW resource for HW dynamic mechanism.
* This function is only invoked at driver intialization once.
*/
void init_hal_dm(struct r8192_priv *priv)
{
// Undecorated Smoothed Signal Strength, it can utilized to dynamic mechanism.
priv->undecorated_smoothed_pwdb = -1;
//Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code.
dm_init_dynamic_txpower(priv);
init_rate_adaptive(priv);
//dm_initialize_txpower_tracking(dev);
dm_dig_init(priv);
dm_init_edca_turbo(priv);
dm_init_bandwidth_autoswitch(priv);
dm_init_fsync(priv);
dm_init_rxpath_selection(priv);
dm_init_ctstoself(priv);
INIT_DELAYED_WORK(&priv->gpio_change_rf_wq, dm_gpio_change_rf_callback);
}
void deinit_hal_dm(struct r8192_priv *priv)
{
dm_deInit_fsync(priv);
}
void hal_dm_watchdog(struct r8192_priv *priv)
{
/*Add by amy 2008/05/15 ,porting from windows code.*/
dm_check_rate_adaptive(priv);
dm_dynamic_txpower(priv);
dm_check_txrateandretrycount(priv);
dm_check_txpower_tracking(priv);
dm_ctrl_initgain_byrssi(priv);
dm_check_edca_turbo(priv);
dm_bandwidth_autoswitch(priv);
dm_check_rfctrl_gpio(priv);
dm_check_rx_path_selection(priv);
dm_check_fsync(priv);
// Add by amy 2008-05-15 porting from windows code.
dm_send_rssi_tofw(priv);
dm_ctstoself(priv);
}
/*
* Decide Rate Adaptive Set according to distance (signal strength)
* 01/11/2008 MHC Modify input arguments and RATR table level.
* 01/16/2008 MHC RF_Type is assigned in ReadAdapterInfo(). We must call
* the function after making sure RF_Type.
*/
void init_rate_adaptive(struct r8192_priv *priv)
{
prate_adaptive pra = &priv->rate_adaptive;
pra->ratr_state = DM_RATR_STA_MAX;
pra->high2low_rssi_thresh_for_ra = RateAdaptiveTH_High;
pra->low2high_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M+5;
pra->low2high_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M+5;
pra->high_rssi_thresh_for_ra = RateAdaptiveTH_High+5;
pra->low_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M;
pra->low_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M;
if(priv->CustomerID == RT_CID_819x_Netcore)
pra->ping_rssi_enable = 1;
else
pra->ping_rssi_enable = 0;
pra->ping_rssi_thresh_for_ra = 15;
if (priv->rf_type == RF_2T4R)
{
// 07/10/08 MH Modify for RA smooth scheme.
/* 2008/01/11 MH Modify 2T RATR table for different RSSI. 080515 porting by amy from windows code.*/
pra->upper_rssi_threshold_ratr = 0x8f0f0000;
pra->middle_rssi_threshold_ratr = 0x8f0ff000;
pra->low_rssi_threshold_ratr = 0x8f0ff001;
pra->low_rssi_threshold_ratr_40M = 0x8f0ff005;
pra->low_rssi_threshold_ratr_20M = 0x8f0ff001;
pra->ping_rssi_ratr = 0x0000000d;//cosa add for test
}
else if (priv->rf_type == RF_1T2R)
{
pra->upper_rssi_threshold_ratr = 0x000f0000;
pra->middle_rssi_threshold_ratr = 0x000ff000;
pra->low_rssi_threshold_ratr = 0x000ff001;
pra->low_rssi_threshold_ratr_40M = 0x000ff005;
pra->low_rssi_threshold_ratr_20M = 0x000ff001;
pra->ping_rssi_ratr = 0x0000000d;//cosa add for test
}
}
static void dm_check_rate_adaptive(struct r8192_priv *priv)
{
PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo;
prate_adaptive pra = (prate_adaptive)&priv->rate_adaptive;
u32 currentRATR, targetRATR = 0;
u32 LowRSSIThreshForRA = 0, HighRSSIThreshForRA = 0;
bool bshort_gi_enabled = false;
static u8 ping_rssi_state=0;
if(!priv->up)
{
RT_TRACE(COMP_RATE, "<---- dm_check_rate_adaptive(): driver is going to unload\n");
return;
}
if(pra->rate_adaptive_disabled)//this variable is set by ioctl.
return;
// TODO: Only 11n mode is implemented currently,
if( !(priv->ieee80211->mode == WIRELESS_MODE_N_24G ||
priv->ieee80211->mode == WIRELESS_MODE_N_5G))
return;
if( priv->ieee80211->state == IEEE80211_LINKED )
{
// RT_TRACE(COMP_RATE, "dm_CheckRateAdaptive(): \t");
//
// Check whether Short GI is enabled
//
bshort_gi_enabled = (pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI40MHz) ||
(!pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI20MHz);
pra->upper_rssi_threshold_ratr =
(pra->upper_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
pra->middle_rssi_threshold_ratr =
(pra->middle_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
{
pra->low_rssi_threshold_ratr =
(pra->low_rssi_threshold_ratr_40M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
}
else
{
pra->low_rssi_threshold_ratr =
(pra->low_rssi_threshold_ratr_20M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
}
//cosa add for test
pra->ping_rssi_ratr =
(pra->ping_rssi_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
/* 2007/10/08 MH We support RA smooth scheme now. When it is the first
time to link with AP. We will not change upper/lower threshold. If
STA stay in high or low level, we must change two different threshold
to prevent jumping frequently. */
if (pra->ratr_state == DM_RATR_STA_HIGH)
{
HighRSSIThreshForRA = pra->high2low_rssi_thresh_for_ra;
LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)?
(pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M);
}
else if (pra->ratr_state == DM_RATR_STA_LOW)
{
HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra;
LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)?
(pra->low2high_rssi_thresh_for_ra40M):(pra->low2high_rssi_thresh_for_ra20M);
}
else
{
HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra;
LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)?
(pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M);
}
if(priv->undecorated_smoothed_pwdb >= (long)HighRSSIThreshForRA)
{
pra->ratr_state = DM_RATR_STA_HIGH;
targetRATR = pra->upper_rssi_threshold_ratr;
}else if(priv->undecorated_smoothed_pwdb >= (long)LowRSSIThreshForRA)
{
pra->ratr_state = DM_RATR_STA_MIDDLE;
targetRATR = pra->middle_rssi_threshold_ratr;
}else
{
pra->ratr_state = DM_RATR_STA_LOW;
targetRATR = pra->low_rssi_threshold_ratr;
}
//cosa add for test
if(pra->ping_rssi_enable)
{
//pHalData->UndecoratedSmoothedPWDB = 19;
if(priv->undecorated_smoothed_pwdb < (long)(pra->ping_rssi_thresh_for_ra+5))
{
if( (priv->undecorated_smoothed_pwdb < (long)pra->ping_rssi_thresh_for_ra) ||
ping_rssi_state )
{
pra->ratr_state = DM_RATR_STA_LOW;
targetRATR = pra->ping_rssi_ratr;
ping_rssi_state = 1;
}
}
else
{
ping_rssi_state = 0;
}
}
// For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7.
if(priv->ieee80211->GetHalfNmodeSupportByAPsHandler(priv->ieee80211))
targetRATR &= 0xf00fffff;
//
// Check whether updating of RATR0 is required
//
currentRATR = read_nic_dword(priv, RATR0);
if( targetRATR != currentRATR )
{
u32 ratr_value;
ratr_value = targetRATR;
RT_TRACE(COMP_RATE,"currentRATR = %x, targetRATR = %x\n", currentRATR, targetRATR);
if(priv->rf_type == RF_1T2R)
{
ratr_value &= ~(RATE_ALL_OFDM_2SS);
}
write_nic_dword(priv, RATR0, ratr_value);
write_nic_byte(priv, UFWP, 1);
pra->last_ratr = targetRATR;
}
}
else
{
pra->ratr_state = DM_RATR_STA_MAX;
}
}
static void dm_init_bandwidth_autoswitch(struct r8192_priv *priv)
{
priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz = BW_AUTO_SWITCH_LOW_HIGH;
priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz = BW_AUTO_SWITCH_HIGH_LOW;
priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false;
priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable = false;
}
static void dm_bandwidth_autoswitch(struct r8192_priv *priv)
{
if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 ||!priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable){
return;
}else{
if(priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz == false){//If send packets in 40 Mhz in 20/40
if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz)
priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = true;
}else{//in force send packets in 20 Mhz in 20/40
if(priv->undecorated_smoothed_pwdb >= priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz)
priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false;
}
}
}
//OFDM default at 0db, index=6.
static const u32 OFDMSwingTable[OFDM_Table_Length] = {
0x7f8001fe, // 0, +6db
0x71c001c7, // 1, +5db
0x65400195, // 2, +4db
0x5a400169, // 3, +3db
0x50800142, // 4, +2db
0x47c0011f, // 5, +1db
0x40000100, // 6, +0db ===> default, upper for higher temperature, lower for low temperature
0x390000e4, // 7, -1db
0x32c000cb, // 8, -2db
0x2d4000b5, // 9, -3db
0x288000a2, // 10, -4db
0x24000090, // 11, -5db
0x20000080, // 12, -6db
0x1c800072, // 13, -7db
0x19800066, // 14, -8db
0x26c0005b, // 15, -9db
0x24400051, // 16, -10db
0x12000048, // 17, -11db
0x10000040 // 18, -12db
};
static const u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = {
{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, // 0, +0db ===> CCK40M default
{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 1, -1db
{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 2, -2db
{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, // 3, -3db
{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, // 4, -4db
{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, // 5, -5db
{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, // 6, -6db ===> CCK20M default
{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, // 7, -7db
{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, // 8, -8db
{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, // 9, -9db
{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 10, -10db
{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} // 11, -11db
};
static const u8 CCKSwingTable_Ch14[CCK_Table_length][8] = {
{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, // 0, +0db ===> CCK40M default
{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 1, -1db
{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 2, -2db
{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, // 3, -3db
{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, // 4, -4db
{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, // 5, -5db
{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 6, -6db ===> CCK20M default
{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, // 7, -7db
{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 8, -8db
{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 9, -9db
{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 10, -10db
{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00} // 11, -11db
};
#define Pw_Track_Flag 0x11d
#define Tssi_Mea_Value 0x13c
#define Tssi_Report_Value1 0x134
#define Tssi_Report_Value2 0x13e
#define FW_Busy_Flag 0x13f
static void dm_TXPowerTrackingCallback_TSSI(struct r8192_priv *priv)
{
bool bHighpowerstate, viviflag = FALSE;
DCMD_TXCMD_T tx_cmd;
u8 powerlevelOFDM24G;
int i =0, j = 0, k = 0;
u8 RF_Type, tmp_report[5]={0, 0, 0, 0, 0};
u32 Value;
u8 Pwr_Flag;
u16 Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver=0;
// bool rtStatus = true;
u32 delta=0;
RT_TRACE(COMP_POWER_TRACKING,"%s()\n",__FUNCTION__);
// write_nic_byte(priv, 0x1ba, 0);
write_nic_byte(priv, Pw_Track_Flag, 0);
write_nic_byte(priv, FW_Busy_Flag, 0);
priv->ieee80211->bdynamic_txpower_enable = false;
bHighpowerstate = priv->bDynamicTxHighPower;
powerlevelOFDM24G = (u8)(priv->Pwr_Track>>24);
RF_Type = priv->rf_type;
Value = (RF_Type<<8) | powerlevelOFDM24G;
RT_TRACE(COMP_POWER_TRACKING, "powerlevelOFDM24G = %x\n", powerlevelOFDM24G);
for(j = 0; j<=30; j++)
{ //fill tx_cmd
tx_cmd.Op = TXCMD_SET_TX_PWR_TRACKING;
tx_cmd.Length = 4;
tx_cmd.Value = Value;
cmpk_message_handle_tx(priv, (u8*)&tx_cmd, DESC_PACKET_TYPE_INIT, sizeof(DCMD_TXCMD_T));
mdelay(1);
for(i = 0;i <= 30; i++)
{
Pwr_Flag = read_nic_byte(priv, Pw_Track_Flag);
if (Pwr_Flag == 0)
{
mdelay(1);
continue;
}
Avg_TSSI_Meas = read_nic_word(priv, Tssi_Mea_Value);
if(Avg_TSSI_Meas == 0)
{
write_nic_byte(priv, Pw_Track_Flag, 0);
write_nic_byte(priv, FW_Busy_Flag, 0);
return;
}
for(k = 0;k < 5; k++)
{
if(k !=4)
tmp_report[k] = read_nic_byte(priv, Tssi_Report_Value1+k);
else
tmp_report[k] = read_nic_byte(priv, Tssi_Report_Value2);
RT_TRACE(COMP_POWER_TRACKING, "TSSI_report_value = %d\n", tmp_report[k]);
}
//check if the report value is right
for(k = 0;k < 5; k++)
{
if(tmp_report[k] <= 20)
{
viviflag =TRUE;
break;
}
}
if(viviflag ==TRUE)
{
write_nic_byte(priv, Pw_Track_Flag, 0);
viviflag = FALSE;
RT_TRACE(COMP_POWER_TRACKING, "we filted this data\n");
for(k = 0;k < 5; k++)
tmp_report[k] = 0;
break;
}
for(k = 0;k < 5; k++)
{
Avg_TSSI_Meas_from_driver += tmp_report[k];
}
Avg_TSSI_Meas_from_driver = Avg_TSSI_Meas_from_driver*100/5;
RT_TRACE(COMP_POWER_TRACKING, "Avg_TSSI_Meas_from_driver = %d\n", Avg_TSSI_Meas_from_driver);
TSSI_13dBm = priv->TSSI_13dBm;
RT_TRACE(COMP_POWER_TRACKING, "TSSI_13dBm = %d\n", TSSI_13dBm);
//if(abs(Avg_TSSI_Meas_from_driver - TSSI_13dBm) <= E_FOR_TX_POWER_TRACK)
// For MacOS-compatible
if(Avg_TSSI_Meas_from_driver > TSSI_13dBm)
delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm;
else
delta = TSSI_13dBm - Avg_TSSI_Meas_from_driver;
if(delta <= E_FOR_TX_POWER_TRACK)
{
priv->ieee80211->bdynamic_txpower_enable = TRUE;
write_nic_byte(priv, Pw_Track_Flag, 0);
write_nic_byte(priv, FW_Busy_Flag, 0);
RT_TRACE(COMP_POWER_TRACKING, "tx power track is done\n");
RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation_difference = %d\n", priv->CCKPresentAttentuation_difference);
RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation = %d\n", priv->CCKPresentAttentuation);
return;
}
else
{
if(Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK)
{
if (RF_Type == RF_2T4R)
{
if((priv->rfa_txpowertrackingindex > 0) &&(priv->rfc_txpowertrackingindex > 0))
{
priv->rfa_txpowertrackingindex--;
if(priv->rfa_txpowertrackingindex_real > 4)
{
priv->rfa_txpowertrackingindex_real--;
rtl8192_setBBreg(priv, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value);
}
priv->rfc_txpowertrackingindex--;
if(priv->rfc_txpowertrackingindex_real > 4)
{
priv->rfc_txpowertrackingindex_real--;
rtl8192_setBBreg(priv, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value);
}
}
else
{
rtl8192_setBBreg(priv, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[4].txbbgain_value);
rtl8192_setBBreg(priv, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[4].txbbgain_value);
}
}
else
{
if(priv->rfc_txpowertrackingindex > 0)
{
priv->rfc_txpowertrackingindex--;
if(priv->rfc_txpowertrackingindex_real > 4)
{
priv->rfc_txpowertrackingindex_real--;
rtl8192_setBBreg(priv, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value);
}
}
else
rtl8192_setBBreg(priv, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[4].txbbgain_value);
}
}
else
{
if (RF_Type == RF_2T4R)
{
if((priv->rfa_txpowertrackingindex < TxBBGainTableLength - 1) &&(priv->rfc_txpowertrackingindex < TxBBGainTableLength - 1))
{
priv->rfa_txpowertrackingindex++;
priv->rfa_txpowertrackingindex_real++;
rtl8192_setBBreg(priv, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value);
priv->rfc_txpowertrackingindex++;
priv->rfc_txpowertrackingindex_real++;
rtl8192_setBBreg(priv, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value);
}
else
{
rtl8192_setBBreg(priv, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[TxBBGainTableLength - 1].txbbgain_value);
rtl8192_setBBreg(priv, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[TxBBGainTableLength - 1].txbbgain_value);
}
}
else
{
if(priv->rfc_txpowertrackingindex < (TxBBGainTableLength - 1))
{
priv->rfc_txpowertrackingindex++;
priv->rfc_txpowertrackingindex_real++;
rtl8192_setBBreg(priv, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex_real].txbbgain_value);
}
else
rtl8192_setBBreg(priv, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[TxBBGainTableLength - 1].txbbgain_value);
}
}
if (RF_Type == RF_2T4R)
priv->CCKPresentAttentuation_difference
= priv->rfa_txpowertrackingindex - priv->rfa_txpowertracking_default;
else
priv->CCKPresentAttentuation_difference
= priv->rfc_txpowertrackingindex - priv->rfc_txpowertracking_default;
if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
priv->CCKPresentAttentuation
= priv->CCKPresentAttentuation_20Mdefault + priv->CCKPresentAttentuation_difference;
else
priv->CCKPresentAttentuation
= priv->CCKPresentAttentuation_40Mdefault + priv->CCKPresentAttentuation_difference;
if(priv->CCKPresentAttentuation > (CCKTxBBGainTableLength-1))
priv->CCKPresentAttentuation = CCKTxBBGainTableLength-1;
if(priv->CCKPresentAttentuation < 0)
priv->CCKPresentAttentuation = 0;
if(1)
{
if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14)
{
priv->bcck_in_ch14 = TRUE;
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
}
else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14)
{
priv->bcck_in_ch14 = FALSE;
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
}
else
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
}
RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation_difference = %d\n", priv->CCKPresentAttentuation_difference);
RT_TRACE(COMP_POWER_TRACKING, "priv->CCKPresentAttentuation = %d\n", priv->CCKPresentAttentuation);
if (priv->CCKPresentAttentuation_difference <= -12||priv->CCKPresentAttentuation_difference >= 24)
{
priv->ieee80211->bdynamic_txpower_enable = TRUE;
write_nic_byte(priv, Pw_Track_Flag, 0);
write_nic_byte(priv, FW_Busy_Flag, 0);
RT_TRACE(COMP_POWER_TRACKING, "tx power track--->limited\n");
return;
}
}
write_nic_byte(priv, Pw_Track_Flag, 0);
Avg_TSSI_Meas_from_driver = 0;
for(k = 0;k < 5; k++)
tmp_report[k] = 0;
break;
}
write_nic_byte(priv, FW_Busy_Flag, 0);
}
priv->ieee80211->bdynamic_txpower_enable = TRUE;
write_nic_byte(priv, Pw_Track_Flag, 0);
}
static void dm_TXPowerTrackingCallback_ThermalMeter(struct r8192_priv *priv)
{
#define ThermalMeterVal 9
u32 tmpRegA, TempCCk;
u8 tmpOFDMindex, tmpCCKindex, tmpCCK20Mindex, tmpCCK40Mindex, tmpval;
int i =0, CCKSwingNeedUpdate=0;
if(!priv->btxpower_trackingInit)
{
//Query OFDM default setting
tmpRegA = rtl8192_QueryBBReg(priv, rOFDM0_XATxIQImbalance, bMaskDWord);
for(i=0; i<OFDM_Table_Length; i++) //find the index
{
if(tmpRegA == OFDMSwingTable[i])
{
priv->OFDM_index= (u8)i;
RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, OFDM_index=0x%x\n",
rOFDM0_XATxIQImbalance, tmpRegA, priv->OFDM_index);
}
}
//Query CCK default setting From 0xa22
TempCCk = rtl8192_QueryBBReg(priv, rCCK0_TxFilter1, bMaskByte2);
for(i=0 ; i<CCK_Table_length ; i++)
{
if(TempCCk == (u32)CCKSwingTable_Ch1_Ch13[i][0])
{
priv->CCK_index =(u8) i;
RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, CCK_index=0x%x\n",
rCCK0_TxFilter1, TempCCk, priv->CCK_index);
break;
}
}
priv->btxpower_trackingInit = TRUE;
//pHalData->TXPowercount = 0;
return;
}
// read and filter out unreasonable value
tmpRegA = rtl8192_phy_QueryRFReg(priv, RF90_PATH_A, 0x12, 0x078); // 0x12: RF Reg[10:7]
RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d\n", tmpRegA);
if(tmpRegA < 3 || tmpRegA > 13)
return;
if(tmpRegA >= 12) // if over 12, TP will be bad when high temperature
tmpRegA = 12;
RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d\n", tmpRegA);
priv->ThermalMeter[0] = ThermalMeterVal; //We use fixed value by Bryant's suggestion
priv->ThermalMeter[1] = ThermalMeterVal; //We use fixed value by Bryant's suggestion
//Get current RF-A temperature index
if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temperature
{
tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0]-(u8)tmpRegA);
tmpCCK40Mindex = tmpCCK20Mindex - 6;
if(tmpOFDMindex >= OFDM_Table_Length)
tmpOFDMindex = OFDM_Table_Length-1;
if(tmpCCK20Mindex >= CCK_Table_length)
tmpCCK20Mindex = CCK_Table_length-1;
if(tmpCCK40Mindex >= CCK_Table_length)
tmpCCK40Mindex = CCK_Table_length-1;
}
else
{
tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]);
if(tmpval >= 6) // higher temperature
tmpOFDMindex = tmpCCK20Mindex = 0; // max to +6dB
else
tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval;
tmpCCK40Mindex = 0;
}
if(priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) //40M
tmpCCKindex = tmpCCK40Mindex;
else
tmpCCKindex = tmpCCK20Mindex;
//record for bandwidth swith
priv->Record_CCK_20Mindex = tmpCCK20Mindex;
priv->Record_CCK_40Mindex = tmpCCK40Mindex;
RT_TRACE(COMP_POWER_TRACKING, "Record_CCK_20Mindex / Record_CCK_40Mindex = %d / %d.\n",
priv->Record_CCK_20Mindex, priv->Record_CCK_40Mindex);
if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14)
{
priv->bcck_in_ch14 = TRUE;
CCKSwingNeedUpdate = 1;
}
else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14)
{
priv->bcck_in_ch14 = FALSE;
CCKSwingNeedUpdate = 1;
}
if(priv->CCK_index != tmpCCKindex)
{
priv->CCK_index = tmpCCKindex;
CCKSwingNeedUpdate = 1;
}
if(CCKSwingNeedUpdate)
{
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
}
if(priv->OFDM_index != tmpOFDMindex)
{
priv->OFDM_index = tmpOFDMindex;
rtl8192_setBBreg(priv, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable[priv->OFDM_index]);
RT_TRACE(COMP_POWER_TRACKING, "Update OFDMSwing[%d] = 0x%x\n",
priv->OFDM_index, OFDMSwingTable[priv->OFDM_index]);
}
priv->txpower_count = 0;
}
void dm_txpower_trackingcallback(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work,struct delayed_work,work);
struct r8192_priv *priv = container_of(dwork,struct r8192_priv,txpower_tracking_wq);
if(priv->IC_Cut >= IC_VersionCut_D)
dm_TXPowerTrackingCallback_TSSI(priv);
else
dm_TXPowerTrackingCallback_ThermalMeter(priv);
}
static const txbbgain_struct rtl8192_txbbgain_table[] = {
{ 12, 0x7f8001fe },
{ 11, 0x788001e2 },
{ 10, 0x71c001c7 },
{ 9, 0x6b8001ae },
{ 8, 0x65400195 },
{ 7, 0x5fc0017f },
{ 6, 0x5a400169 },
{ 5, 0x55400155 },
{ 4, 0x50800142 },
{ 3, 0x4c000130 },
{ 2, 0x47c0011f },
{ 1, 0x43c0010f },
{ 0, 0x40000100 },
{ -1, 0x3c8000f2 },
{ -2, 0x390000e4 },
{ -3, 0x35c000d7 },
{ -4, 0x32c000cb },
{ -5, 0x300000c0 },
{ -6, 0x2d4000b5 },
{ -7, 0x2ac000ab },
{ -8, 0x288000a2 },
{ -9, 0x26000098 },
{ -10, 0x24000090 },
{ -11, 0x22000088 },
{ -12, 0x20000080 },
{ -13, 0x1a00006c },
{ -14, 0x1c800072 },
{ -15, 0x18000060 },
{ -16, 0x19800066 },
{ -17, 0x15800056 },
{ -18, 0x26c0005b },
{ -19, 0x14400051 },
{ -20, 0x24400051 },
{ -21, 0x1300004c },
{ -22, 0x12000048 },
{ -23, 0x11000044 },
{ -24, 0x10000040 },
};
/*
* ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
* This Table is for CH1~CH13
*/
static const ccktxbbgain_struct rtl8192_cck_txbbgain_table[] = {
{{ 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 }},
{{ 0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04 }},
{{ 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03 }},
{{ 0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03 }},
{{ 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 }},
{{ 0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03 }},
{{ 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 }},
{{ 0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03 }},
{{ 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02 }},
{{ 0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02 }},
{{ 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02 }},
{{ 0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02 }},
{{ 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02 }},
{{ 0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02 }},
{{ 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02 }},
{{ 0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02 }},
{{ 0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01 }},
{{ 0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02 }},
{{ 0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01 }},
{{ 0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01 }},
{{ 0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01 }},
{{ 0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01 }},
{{ 0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01 }},
};
/*
* ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
* This Table is for CH14
*/
static const ccktxbbgain_struct rtl8192_cck_txbbgain_ch14_table[] = {
{{ 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x2d, 0x2d, 0x27, 0x17, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x28, 0x28, 0x22, 0x14, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00 }},
{{ 0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00 }},
};
static void dm_InitializeTXPowerTracking_TSSI(struct r8192_priv *priv)
{
priv->txbbgain_table = rtl8192_txbbgain_table;
priv->cck_txbbgain_table = rtl8192_cck_txbbgain_table;
priv->cck_txbbgain_ch14_table = rtl8192_cck_txbbgain_ch14_table;
priv->btxpower_tracking = TRUE;
priv->txpower_count = 0;
priv->btxpower_trackingInit = FALSE;
}
static void dm_InitializeTXPowerTracking_ThermalMeter(struct r8192_priv *priv)
{
// Tx Power tracking by Theremal Meter require Firmware R/W 3-wire. This mechanism
// can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
// 3-wire by driver cause RF goes into wrong state.
if(priv->ieee80211->FwRWRF)
priv->btxpower_tracking = TRUE;
else
priv->btxpower_tracking = FALSE;
priv->txpower_count = 0;
priv->btxpower_trackingInit = FALSE;
}
void dm_initialize_txpower_tracking(struct r8192_priv *priv)
{
if(priv->IC_Cut >= IC_VersionCut_D)
dm_InitializeTXPowerTracking_TSSI(priv);
else
dm_InitializeTXPowerTracking_ThermalMeter(priv);
}
static void dm_CheckTXPowerTracking_TSSI(struct r8192_priv *priv)
{
static u32 tx_power_track_counter = 0;
RT_TRACE(COMP_POWER_TRACKING,"%s()\n",__FUNCTION__);
if(read_nic_byte(priv, 0x11e) ==1)
return;
if(!priv->btxpower_tracking)
return;
tx_power_track_counter++;
if (tx_power_track_counter > 90) {
queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0);
tx_power_track_counter =0;
}
}
static void dm_CheckTXPowerTracking_ThermalMeter(struct r8192_priv *priv)
{
static u8 TM_Trigger=0;
if(!priv->btxpower_tracking)
return;
else
{
if(priv->txpower_count <= 2)
{
priv->txpower_count++;
return;
}
}
if(!TM_Trigger)
{
//Attention!! You have to wirte all 12bits data to RF, or it may cause RF to crash
//actually write reg0x02 bit1=0, then bit1=1.
rtl8192_phy_SetRFReg(priv, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
rtl8192_phy_SetRFReg(priv, RF90_PATH_A, 0x02, bMask12Bits, 0x4f);
rtl8192_phy_SetRFReg(priv, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
rtl8192_phy_SetRFReg(priv, RF90_PATH_A, 0x02, bMask12Bits, 0x4f);
TM_Trigger = 1;
return;
}
else {
queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0);
TM_Trigger = 0;
}
}
static void dm_check_txpower_tracking(struct r8192_priv *priv)
{
if(priv->IC_Cut >= IC_VersionCut_D)
dm_CheckTXPowerTracking_TSSI(priv);
else
dm_CheckTXPowerTracking_ThermalMeter(priv);
}
static void dm_CCKTxPowerAdjust_TSSI(struct r8192_priv *priv, bool bInCH14)
{
u32 TempVal;
//Write 0xa22 0xa23
TempVal = 0;
if(!bInCH14){
//Write 0xa22 0xa23
TempVal = (u32)(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[0] +
(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[1]<<8)) ;
rtl8192_setBBreg(priv, rCCK0_TxFilter1, bMaskHWord, TempVal);
//Write 0xa24 ~ 0xa27
TempVal = 0;
TempVal = (u32)(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[2] +
(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[3]<<8) +
(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[4]<<16 )+
(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[5]<<24));
rtl8192_setBBreg(priv, rCCK0_TxFilter2, bMaskDWord, TempVal);
//Write 0xa28 0xa29
TempVal = 0;
TempVal = (u32)(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[6] +
(priv->cck_txbbgain_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[7]<<8)) ;
rtl8192_setBBreg(priv, rCCK0_DebugPort, bMaskLWord, TempVal);
}
else
{
TempVal = (u32)(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[0] +
(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[1]<<8)) ;
rtl8192_setBBreg(priv, rCCK0_TxFilter1, bMaskHWord, TempVal);
//Write 0xa24 ~ 0xa27
TempVal = 0;
TempVal = (u32)(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[2] +
(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[3]<<8) +
(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[4]<<16 )+
(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[5]<<24));
rtl8192_setBBreg(priv, rCCK0_TxFilter2, bMaskDWord, TempVal);
//Write 0xa28 0xa29
TempVal = 0;
TempVal = (u32)(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[6] +
(priv->cck_txbbgain_ch14_table[(u8)(priv->CCKPresentAttentuation)].ccktxbb_valuearray[7]<<8)) ;
rtl8192_setBBreg(priv, rCCK0_DebugPort, bMaskLWord, TempVal);
}
}
static void dm_CCKTxPowerAdjust_ThermalMeter(struct r8192_priv *priv,
bool bInCH14)
{
u32 TempVal;
TempVal = 0;
if(!bInCH14)
{
//Write 0xa22 0xa23
TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][0] +
(CCKSwingTable_Ch1_Ch13[priv->CCK_index][1]<<8) ;
rtl8192_setBBreg(priv, rCCK0_TxFilter1, bMaskHWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n",
rCCK0_TxFilter1, TempVal);
//Write 0xa24 ~ 0xa27
TempVal = 0;
TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][2] +
(CCKSwingTable_Ch1_Ch13[priv->CCK_index][3]<<8) +
(CCKSwingTable_Ch1_Ch13[priv->CCK_index][4]<<16 )+
(CCKSwingTable_Ch1_Ch13[priv->CCK_index][5]<<24);
rtl8192_setBBreg(priv, rCCK0_TxFilter2, bMaskDWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n",
rCCK0_TxFilter2, TempVal);
//Write 0xa28 0xa29
TempVal = 0;
TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][6] +
(CCKSwingTable_Ch1_Ch13[priv->CCK_index][7]<<8) ;
rtl8192_setBBreg(priv, rCCK0_DebugPort, bMaskLWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n",
rCCK0_DebugPort, TempVal);
}
else
{
// priv->CCKTxPowerAdjustCntNotCh14++; //cosa add for debug.
//Write 0xa22 0xa23
TempVal = CCKSwingTable_Ch14[priv->CCK_index][0] +
(CCKSwingTable_Ch14[priv->CCK_index][1]<<8) ;
rtl8192_setBBreg(priv, rCCK0_TxFilter1, bMaskHWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n",
rCCK0_TxFilter1, TempVal);
//Write 0xa24 ~ 0xa27
TempVal = 0;
TempVal = CCKSwingTable_Ch14[priv->CCK_index][2] +
(CCKSwingTable_Ch14[priv->CCK_index][3]<<8) +
(CCKSwingTable_Ch14[priv->CCK_index][4]<<16 )+
(CCKSwingTable_Ch14[priv->CCK_index][5]<<24);
rtl8192_setBBreg(priv, rCCK0_TxFilter2, bMaskDWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n",
rCCK0_TxFilter2, TempVal);
//Write 0xa28 0xa29
TempVal = 0;
TempVal = CCKSwingTable_Ch14[priv->CCK_index][6] +
(CCKSwingTable_Ch14[priv->CCK_index][7]<<8) ;
rtl8192_setBBreg(priv, rCCK0_DebugPort, bMaskLWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING,"CCK chnl 14, reg 0x%x = 0x%x\n",
rCCK0_DebugPort, TempVal);
}
}
void dm_cck_txpower_adjust(struct r8192_priv *priv, bool binch14)
{
if(priv->IC_Cut >= IC_VersionCut_D)
dm_CCKTxPowerAdjust_TSSI(priv, binch14);
else
dm_CCKTxPowerAdjust_ThermalMeter(priv, binch14);
}
/* Set DIG scheme init value. */
static void dm_dig_init(struct r8192_priv *priv)
{
/* 2007/10/05 MH Disable DIG scheme now. Not tested. */
dm_digtable.dig_enable_flag = true;
dm_digtable.dig_algorithm = DIG_ALGO_BY_RSSI;
dm_digtable.dbg_mode = DM_DBG_OFF; //off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig
dm_digtable.dig_algorithm_switch = 0;
/* 2007/10/04 MH Define init gain threshold. */
dm_digtable.dig_state = DM_STA_DIG_MAX;
dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX;
dm_digtable.initialgain_lowerbound_state = false;
dm_digtable.rssi_low_thresh = DM_DIG_THRESH_LOW;
dm_digtable.rssi_high_thresh = DM_DIG_THRESH_HIGH;
dm_digtable.rssi_high_power_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW;
dm_digtable.rssi_high_power_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH;
dm_digtable.rssi_val = 50; //for new dig debug rssi value
dm_digtable.backoff_val = DM_DIG_BACKOFF;
dm_digtable.rx_gain_range_max = DM_DIG_MAX;
if(priv->CustomerID == RT_CID_819x_Netcore)
dm_digtable.rx_gain_range_min = DM_DIG_MIN_Netcore;
else
dm_digtable.rx_gain_range_min = DM_DIG_MIN;
}
/*
* Driver must monitor RSSI and notify firmware to change initial
* gain according to different threshold. BB team provide the
* suggested solution.
*/
static void dm_ctrl_initgain_byrssi(struct r8192_priv *priv)
{
if (dm_digtable.dig_enable_flag == false)
return;
if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM)
dm_ctrl_initgain_byrssi_by_fwfalse_alarm(priv);
else if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
dm_ctrl_initgain_byrssi_by_driverrssi(priv);
}
static void dm_ctrl_initgain_byrssi_by_driverrssi(struct r8192_priv *priv)
{
u8 i;
static u8 fw_dig=0;
if (dm_digtable.dig_enable_flag == false)
return;
if(dm_digtable.dig_algorithm_switch) // if swithed algorithm, we have to disable FW Dig.
fw_dig = 0;
if(fw_dig <= 3) // execute several times to make sure the FW Dig is disabled
{// FW DIG Off
for(i=0; i<3; i++)
rtl8192_setBBreg(priv, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite.
fw_dig++;
dm_digtable.dig_state = DM_STA_DIG_OFF; //fw dig off.
}
if(priv->ieee80211->state == IEEE80211_LINKED)
dm_digtable.cur_connect_state = DIG_CONNECT;
else
dm_digtable.cur_connect_state = DIG_DISCONNECT;
if(dm_digtable.dbg_mode == DM_DBG_OFF)
dm_digtable.rssi_val = priv->undecorated_smoothed_pwdb;
dm_initial_gain(priv);
dm_pd_th(priv);
dm_cs_ratio(priv);
if(dm_digtable.dig_algorithm_switch)
dm_digtable.dig_algorithm_switch = 0;
dm_digtable.pre_connect_state = dm_digtable.cur_connect_state;
}
static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(struct r8192_priv *priv)
{
static u32 reset_cnt = 0;
u8 i;
if (dm_digtable.dig_enable_flag == false)
return;
if(dm_digtable.dig_algorithm_switch)
{
dm_digtable.dig_state = DM_STA_DIG_MAX;
// Fw DIG On.
for(i=0; i<3; i++)
rtl8192_setBBreg(priv, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite.
dm_digtable.dig_algorithm_switch = 0;
}
if (priv->ieee80211->state != IEEE80211_LINKED)
return;
// For smooth, we can not change DIG state.
if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_low_thresh) &&
(priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_thresh))
{
return;
}
/* 1. When RSSI decrease, We have to judge if it is smaller than a threshold
and then execute below step. */
if ((priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh))
{
/* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters
will be reset to init value. We must prevent the condition. */
if (dm_digtable.dig_state == DM_STA_DIG_OFF &&
(priv->reset_count == reset_cnt))
{
return;
}
else
{
reset_cnt = priv->reset_count;
}
// If DIG is off, DIG high power state must reset.
dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX;
dm_digtable.dig_state = DM_STA_DIG_OFF;
// 1.1 DIG Off.
rtl8192_setBBreg(priv, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite.
// 1.2 Set initial gain.
write_nic_byte(priv, rOFDM0_XAAGCCore1, 0x17);
write_nic_byte(priv, rOFDM0_XBAGCCore1, 0x17);
write_nic_byte(priv, rOFDM0_XCAGCCore1, 0x17);
write_nic_byte(priv, rOFDM0_XDAGCCore1, 0x17);
// 1.3 Lower PD_TH for OFDM.
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
{
/* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
// 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
write_nic_byte(priv, (rOFDM0_XATxAFE+3), 0x00);
}
else
write_nic_byte(priv, rOFDM0_RxDetector1, 0x42);
// 1.4 Lower CS ratio for CCK.
write_nic_byte(priv, 0xa0a, 0x08);
// 1.5 Higher EDCCA.
//PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x325);
return;
}
/* 2. When RSSI increase, We have to judge if it is larger than a threshold
and then execute below step. */
if ((priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) )
{
u8 reset_flag = 0;
if (dm_digtable.dig_state == DM_STA_DIG_ON &&
(priv->reset_count == reset_cnt))
{
dm_ctrl_initgain_byrssi_highpwr(priv);
return;
}
else
{
if (priv->reset_count != reset_cnt)
reset_flag = 1;
reset_cnt = priv->reset_count;
}
dm_digtable.dig_state = DM_STA_DIG_ON;
// 2.1 Set initial gain.
// 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment.
if (reset_flag == 1)
{
write_nic_byte(priv, rOFDM0_XAAGCCore1, 0x2c);
write_nic_byte(priv, rOFDM0_XBAGCCore1, 0x2c);
write_nic_byte(priv, rOFDM0_XCAGCCore1, 0x2c);
write_nic_byte(priv, rOFDM0_XDAGCCore1, 0x2c);
}
else
{
write_nic_byte(priv, rOFDM0_XAAGCCore1, 0x20);
write_nic_byte(priv, rOFDM0_XBAGCCore1, 0x20);
write_nic_byte(priv, rOFDM0_XCAGCCore1, 0x20);
write_nic_byte(priv, rOFDM0_XDAGCCore1, 0x20);
}
// 2.2 Higher PD_TH for OFDM.
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
{
/* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
// 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
write_nic_byte(priv, (rOFDM0_XATxAFE+3), 0x20);
}
else
write_nic_byte(priv, rOFDM0_RxDetector1, 0x44);
// 2.3 Higher CS ratio for CCK.
write_nic_byte(priv, 0xa0a, 0xcd);
// 2.4 Lower EDCCA.
/* 2008/01/11 MH 90/92 series are the same. */
//PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346);
// 2.5 DIG On.
rtl8192_setBBreg(priv, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite.
}
dm_ctrl_initgain_byrssi_highpwr(priv);
}
static void dm_ctrl_initgain_byrssi_highpwr(struct r8192_priv *priv)
{
static u32 reset_cnt_highpwr = 0;
// For smooth, we can not change high power DIG state in the range.
if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_high_power_lowthresh) &&
(priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_highthresh))
{
return;
}
/* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
it is larger than a threshold and then execute below step. */
// 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh)
{
if (dm_digtable.dig_highpwr_state == DM_STA_DIG_ON &&
(priv->reset_count == reset_cnt_highpwr))
return;
else
dm_digtable.dig_highpwr_state = DM_STA_DIG_ON;
// 3.1 Higher PD_TH for OFDM for high power state.
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
{
write_nic_byte(priv, (rOFDM0_XATxAFE+3), 0x10);
}
else
write_nic_byte(priv, rOFDM0_RxDetector1, 0x43);
}
else
{
if (dm_digtable.dig_highpwr_state == DM_STA_DIG_OFF&&
(priv->reset_count == reset_cnt_highpwr))
return;
else
dm_digtable.dig_highpwr_state = DM_STA_DIG_OFF;
if (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_lowthresh &&
priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh)
{
// 3.2 Recover PD_TH for OFDM for normal power region.
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
{
write_nic_byte(priv, (rOFDM0_XATxAFE+3), 0x20);
}
else
write_nic_byte(priv, rOFDM0_RxDetector1, 0x44);
}
}
reset_cnt_highpwr = priv->reset_count;
}
static void dm_initial_gain(struct r8192_priv *priv)
{
u8 initial_gain=0;
static u8 initialized=0, force_write=0;
static u32 reset_cnt=0;
if(dm_digtable.dig_algorithm_switch)
{
initialized = 0;
reset_cnt = 0;
}
if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state)
{
if(dm_digtable.cur_connect_state == DIG_CONNECT)
{
if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) > dm_digtable.rx_gain_range_max)
dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_max;
else if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min)
dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_min;
else
dm_digtable.cur_ig_value = dm_digtable.rssi_val+10-dm_digtable.backoff_val;
}
else //current state is disconnected
{
if(dm_digtable.cur_ig_value == 0)
dm_digtable.cur_ig_value = priv->DefaultInitialGain[0];
else
dm_digtable.cur_ig_value = dm_digtable.pre_ig_value;
}
}
else // disconnected -> connected or connected -> disconnected
{
dm_digtable.cur_ig_value = priv->DefaultInitialGain[0];
dm_digtable.pre_ig_value = 0;
}
// if silent reset happened, we should rewrite the values back
if(priv->reset_count != reset_cnt)
{
force_write = 1;
reset_cnt = priv->reset_count;
}
if(dm_digtable.pre_ig_value != read_nic_byte(priv, rOFDM0_XAAGCCore1))
force_write = 1;
{
if((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value)
|| !initialized || force_write)
{
initial_gain = (u8)dm_digtable.cur_ig_value;
// Set initial gain.
write_nic_byte(priv, rOFDM0_XAAGCCore1, initial_gain);
write_nic_byte(priv, rOFDM0_XBAGCCore1, initial_gain);
write_nic_byte(priv, rOFDM0_XCAGCCore1, initial_gain);
write_nic_byte(priv, rOFDM0_XDAGCCore1, initial_gain);
dm_digtable.pre_ig_value = dm_digtable.cur_ig_value;
initialized = 1;
force_write = 0;
}
}
}
static void dm_pd_th(struct r8192_priv *priv)
{
static u8 initialized=0, force_write=0;
static u32 reset_cnt = 0;
if(dm_digtable.dig_algorithm_switch)
{
initialized = 0;
reset_cnt = 0;
}
if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state)
{
if(dm_digtable.cur_connect_state == DIG_CONNECT)
{
if (dm_digtable.rssi_val >= dm_digtable.rssi_high_power_highthresh)
dm_digtable.curpd_thstate = DIG_PD_AT_HIGH_POWER;
else if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh))
dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) &&
(dm_digtable.rssi_val < dm_digtable.rssi_high_power_lowthresh))
dm_digtable.curpd_thstate = DIG_PD_AT_NORMAL_POWER;
else
dm_digtable.curpd_thstate = dm_digtable.prepd_thstate;
}
else
{
dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
}
}
else // disconnected -> connected or connected -> disconnected
{
dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
}
// if silent reset happened, we should rewrite the values back
if(priv->reset_count != reset_cnt)
{
force_write = 1;
reset_cnt = priv->reset_count;
}
{
if((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) ||
(initialized<=3) || force_write)
{
if(dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER)
{
// Lower PD_TH for OFDM.
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
{
/* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
// 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
write_nic_byte(priv, (rOFDM0_XATxAFE+3), 0x00);
}
else
write_nic_byte(priv, rOFDM0_RxDetector1, 0x42);
}
else if(dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER)
{
// Higher PD_TH for OFDM.
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
{
/* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
// 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
write_nic_byte(priv, (rOFDM0_XATxAFE+3), 0x20);
}
else
write_nic_byte(priv, rOFDM0_RxDetector1, 0x44);
}
else if(dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER)
{
// Higher PD_TH for OFDM for high power state.
if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
{
write_nic_byte(priv, (rOFDM0_XATxAFE+3), 0x10);
}
else
write_nic_byte(priv, rOFDM0_RxDetector1, 0x43);
}
dm_digtable.prepd_thstate = dm_digtable.curpd_thstate;
if(initialized <= 3)
initialized++;
force_write = 0;
}
}
}
static void dm_cs_ratio(struct r8192_priv *priv)
{
static u8 initialized=0,force_write=0;
static u32 reset_cnt = 0;
if(dm_digtable.dig_algorithm_switch)
{
initialized = 0;
reset_cnt = 0;
}
if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state)
{
if(dm_digtable.cur_connect_state == DIG_CONNECT)
{
if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh))
dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) )
dm_digtable.curcs_ratio_state = DIG_CS_RATIO_HIGHER;
else
dm_digtable.curcs_ratio_state = dm_digtable.precs_ratio_state;
}
else
{
dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
}
}
else // disconnected -> connected or connected -> disconnected
{
dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
}
// if silent reset happened, we should rewrite the values back
if(priv->reset_count != reset_cnt)
{
force_write = 1;
reset_cnt = priv->reset_count;
}
if((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) ||
!initialized || force_write)
{
if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER)
{
// Lower CS ratio for CCK.
write_nic_byte(priv, 0xa0a, 0x08);
}
else if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER)
{
// Higher CS ratio for CCK.
write_nic_byte(priv, 0xa0a, 0xcd);
}
dm_digtable.precs_ratio_state = dm_digtable.curcs_ratio_state;
initialized = 1;
force_write = 0;
}
}
void dm_init_edca_turbo(struct r8192_priv *priv)
{
priv->bcurrent_turbo_EDCA = false;
priv->ieee80211->bis_any_nonbepkts = false;
priv->bis_cur_rdlstate = false;
}
static void dm_check_edca_turbo(struct r8192_priv *priv)
{
PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo;
//PSTA_QOS pStaQos = pMgntInfo->pStaQos;
// Keep past Tx/Rx packet count for RT-to-RT EDCA turbo.
static unsigned long lastTxOkCnt = 0;
static unsigned long lastRxOkCnt = 0;
unsigned long curTxOkCnt = 0;
unsigned long curRxOkCnt = 0;
//
// Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
// should follow the settings from QAP. By Bruce, 2007-12-07.
//
if(priv->ieee80211->state != IEEE80211_LINKED)
goto dm_CheckEdcaTurbo_EXIT;
// We do not turn on EDCA turbo mode for some AP that has IOT issue
if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO)
goto dm_CheckEdcaTurbo_EXIT;
// Check the status for current condition.
if(!priv->ieee80211->bis_any_nonbepkts)
{
curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt;
// For RT-AP, we needs to turn it on when Rx>Tx
if(curRxOkCnt > 4*curTxOkCnt)
{
if(!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
{
write_nic_dword(priv, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]);
priv->bis_cur_rdlstate = true;
}
}
else
{
if(priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
{
write_nic_dword(priv, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]);
priv->bis_cur_rdlstate = false;
}
}
priv->bcurrent_turbo_EDCA = true;
}
else
{
//
// Turn Off EDCA turbo here.
// Restore original EDCA according to the declaration of AP.
//
if(priv->bcurrent_turbo_EDCA)
{
{
u8 u1bAIFS;
u32 u4bAcParam;
struct ieee80211_qos_parameters *qos_parameters = &priv->ieee80211->current_network.qos_data.parameters;
u8 mode = priv->ieee80211->mode;
// For Each time updating EDCA parameter, reset EDCA turbo mode status.
dm_init_edca_turbo(priv);
u1bAIFS = qos_parameters->aifs[0] * ((mode&(IEEE_G|IEEE_N_24G)) ?9:20) + aSifsTime;
u4bAcParam = ((((u32)(qos_parameters->tx_op_limit[0]))<< AC_PARAM_TXOP_LIMIT_OFFSET)|
(((u32)(qos_parameters->cw_max[0]))<< AC_PARAM_ECW_MAX_OFFSET)|
(((u32)(qos_parameters->cw_min[0]))<< AC_PARAM_ECW_MIN_OFFSET)|
((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET));
printk("===>u4bAcParam:%x, ", u4bAcParam);
//write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam);
write_nic_dword(priv, EDCAPARA_BE, u4bAcParam);
// Check ACM bit.
// If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13.
{
// TODO: Modified this part and try to set acm control in only 1 IO processing!!
PACI_AIFSN pAciAifsn = (PACI_AIFSN)&(qos_parameters->aifs[0]);
u8 AcmCtrl = read_nic_byte(priv, AcmHwCtrl );
if( pAciAifsn->f.ACM )
{ // ACM bit is 1.
AcmCtrl |= AcmHw_BeqEn;
}
else
{ // ACM bit is 0.
AcmCtrl &= (~AcmHw_BeqEn);
}
RT_TRACE( COMP_QOS,"SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl ) ;
write_nic_byte(priv, AcmHwCtrl, AcmCtrl );
}
}
priv->bcurrent_turbo_EDCA = false;
}
}
dm_CheckEdcaTurbo_EXIT:
// Set variables for next time.
priv->ieee80211->bis_any_nonbepkts = false;
lastTxOkCnt = priv->stats.txbytesunicast;
lastRxOkCnt = priv->stats.rxbytesunicast;
}
static void dm_init_ctstoself(struct r8192_priv *priv)
{
priv->ieee80211->bCTSToSelfEnable = TRUE;
priv->ieee80211->CTSToSelfTH = CTSToSelfTHVal;
}
static void dm_ctstoself(struct r8192_priv *priv)
{
PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo;
static unsigned long lastTxOkCnt = 0;
static unsigned long lastRxOkCnt = 0;
unsigned long curTxOkCnt = 0;
unsigned long curRxOkCnt = 0;
if(priv->ieee80211->bCTSToSelfEnable != TRUE)
{
pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF;
return;
}
/*
1. Uplink
2. Linksys350/Linksys300N
3. <50 disable, >55 enable
*/
if(pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM)
{
curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt;
if(curRxOkCnt > 4*curTxOkCnt) //downlink, disable CTS to self
{
pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF;
}
else //uplink
{
pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF;
}
lastTxOkCnt = priv->stats.txbytesunicast;
lastRxOkCnt = priv->stats.rxbytesunicast;
}
}
/* Copy 8187B template for 9xseries */
static void dm_check_rfctrl_gpio(struct r8192_priv *priv)
{
// Walk around for DTM test, we will not enable HW - radio on/off because r/w
// page 1 register before Lextra bus is enabled cause system fails when resuming
// from S4. 20080218, Emily
// Stop to execute workitem to prevent S3/S4 bug.
queue_delayed_work(priv->priv_wq,&priv->gpio_change_rf_wq,0);
}
/* PCI will not support workitem call back HW radio on-off control. */
void dm_gpio_change_rf_callback(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work,struct delayed_work,work);
struct r8192_priv *priv = container_of(dwork,struct r8192_priv,gpio_change_rf_wq);
u8 tmp1byte;
RT_RF_POWER_STATE eRfPowerStateToSet;
bool bActuallySet = false;
if (!priv->up) {
RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF),"dm_gpio_change_rf_callback(): Callback function breaks out!!\n");
} else {
// 0x108 GPIO input register is read only
//set 0x108 B1= 1: RF-ON; 0: RF-OFF.
tmp1byte = read_nic_byte(priv, GPI);
eRfPowerStateToSet = (tmp1byte&BIT1) ? eRfOn : eRfOff;
if (priv->bHwRadioOff && (eRfPowerStateToSet == eRfOn)) {
RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio ON\n");
priv->bHwRadioOff = false;
bActuallySet = true;
} else if ((!priv->bHwRadioOff) && (eRfPowerStateToSet == eRfOff)) {
RT_TRACE(COMP_RF, "gpiochangeRF - HW Radio OFF\n");
priv->bHwRadioOff = true;
bActuallySet = true;
}
if (bActuallySet) {
priv->bHwRfOffAction = 1;
MgntActSet_RF_State(priv, eRfPowerStateToSet, RF_CHANGE_BY_HW);
//DrvIFIndicateCurrentPhyStatus(pAdapter);
} else {
msleep(2000);
}
}
}
/* Check if Current RF RX path is enabled */
void dm_rf_pathcheck_workitemcallback(struct work_struct *work)
{
struct delayed_work *dwork = container_of(work,struct delayed_work,work);
struct r8192_priv *priv = container_of(dwork,struct r8192_priv,rfpath_check_wq);
u8 rfpath = 0, i;
/* 2008/01/30 MH After discussing with SD3 Jerry, 0xc04/0xd04 register will
always be the same. We only read 0xc04 now. */
rfpath = read_nic_byte(priv, 0xc04);
// Check Bit 0-3, it means if RF A-D is enabled.
for (i = 0; i < RF90_PATH_MAX; i++)
{
if (rfpath & (0x01<<i))
priv->brfpath_rxenable[i] = 1;
else
priv->brfpath_rxenable[i] = 0;
}
if(!DM_RxPathSelTable.Enable)
return;
dm_rxpath_sel_byrssi(priv);
}
static void dm_init_rxpath_selection(struct r8192_priv *priv)
{
u8 i;
DM_RxPathSelTable.Enable = 1; //default enabled
DM_RxPathSelTable.SS_TH_low = RxPathSelection_SS_TH_low;
DM_RxPathSelTable.diff_TH = RxPathSelection_diff_TH;
if(priv->CustomerID == RT_CID_819x_Netcore)
DM_RxPathSelTable.cck_method = CCK_Rx_Version_2;
else
DM_RxPathSelTable.cck_method = CCK_Rx_Version_1;
DM_RxPathSelTable.DbgMode = DM_DBG_OFF;
DM_RxPathSelTable.disabledRF = 0;
for(i=0; i<4; i++)
{
DM_RxPathSelTable.rf_rssi[i] = 50;
DM_RxPathSelTable.cck_pwdb_sta[i] = -64;
DM_RxPathSelTable.rf_enable_rssi_th[i] = 100;
}
}
static void dm_rxpath_sel_byrssi(struct r8192_priv *priv)
{
u8 i, max_rssi_index=0, min_rssi_index=0, sec_rssi_index=0, rf_num=0;
u8 tmp_max_rssi=0, tmp_min_rssi=0, tmp_sec_rssi=0;
u8 cck_default_Rx=0x2; //RF-C
u8 cck_optional_Rx=0x3;//RF-D
long tmp_cck_max_pwdb=0, tmp_cck_min_pwdb=0, tmp_cck_sec_pwdb=0;
u8 cck_rx_ver2_max_index=0, cck_rx_ver2_min_index=0, cck_rx_ver2_sec_index=0;
u8 cur_rf_rssi;
long cur_cck_pwdb;
static u8 disabled_rf_cnt=0, cck_Rx_Path_initialized=0;
u8 update_cck_rx_path;
if(priv->rf_type != RF_2T4R)
return;
if(!cck_Rx_Path_initialized)
{
DM_RxPathSelTable.cck_Rx_path = (read_nic_byte(priv, 0xa07)&0xf);
cck_Rx_Path_initialized = 1;
}
DM_RxPathSelTable.disabledRF = 0xf;
DM_RxPathSelTable.disabledRF &=~ (read_nic_byte(priv, 0xc04));
if(priv->ieee80211->mode == WIRELESS_MODE_B)
{
DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; //pure B mode, fixed cck version2
}
//decide max/sec/min rssi index
for (i=0; i<RF90_PATH_MAX; i++)
{
if(!DM_RxPathSelTable.DbgMode)
DM_RxPathSelTable.rf_rssi[i] = priv->stats.rx_rssi_percentage[i];
if(priv->brfpath_rxenable[i])
{
rf_num++;
cur_rf_rssi = DM_RxPathSelTable.rf_rssi[i];
if(rf_num == 1) // find first enabled rf path and the rssi values
{ //initialize, set all rssi index to the same one
max_rssi_index = min_rssi_index = sec_rssi_index = i;
tmp_max_rssi = tmp_min_rssi = tmp_sec_rssi = cur_rf_rssi;
}
else if(rf_num == 2)
{ // we pick up the max index first, and let sec and min to be the same one
if(cur_rf_rssi >= tmp_max_rssi)
{
tmp_max_rssi = cur_rf_rssi;
max_rssi_index = i;
}
else
{
tmp_sec_rssi = tmp_min_rssi = cur_rf_rssi;
sec_rssi_index = min_rssi_index = i;
}
}
else
{
if(cur_rf_rssi > tmp_max_rssi)
{
tmp_sec_rssi = tmp_max_rssi;
sec_rssi_index = max_rssi_index;
tmp_max_rssi = cur_rf_rssi;
max_rssi_index = i;
}
else if(cur_rf_rssi == tmp_max_rssi)
{ // let sec and min point to the different index
tmp_sec_rssi = cur_rf_rssi;
sec_rssi_index = i;
}
else if((cur_rf_rssi < tmp_max_rssi) &&(cur_rf_rssi > tmp_sec_rssi))
{
tmp_sec_rssi = cur_rf_rssi;
sec_rssi_index = i;
}
else if(cur_rf_rssi == tmp_sec_rssi)
{
if(tmp_sec_rssi == tmp_min_rssi)
{ // let sec and min point to the different index
tmp_sec_rssi = cur_rf_rssi;
sec_rssi_index = i;
}
else
{
// This case we don't need to set any index
}
}
else if((cur_rf_rssi < tmp_sec_rssi) && (cur_rf_rssi > tmp_min_rssi))
{
// This case we don't need to set any index
}
else if(cur_rf_rssi == tmp_min_rssi)
{
if(tmp_sec_rssi == tmp_min_rssi)
{ // let sec and min point to the different index
tmp_min_rssi = cur_rf_rssi;
min_rssi_index = i;
}
else
{
// This case we don't need to set any index
}
}
else if(cur_rf_rssi < tmp_min_rssi)
{
tmp_min_rssi = cur_rf_rssi;
min_rssi_index = i;
}
}
}
}
rf_num = 0;
// decide max/sec/min cck pwdb index
if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2)
{
for (i=0; i<RF90_PATH_MAX; i++)
{
if(priv->brfpath_rxenable[i])
{
rf_num++;
cur_cck_pwdb = DM_RxPathSelTable.cck_pwdb_sta[i];
if(rf_num == 1) // find first enabled rf path and the rssi values
{ //initialize, set all rssi index to the same one
cck_rx_ver2_max_index = cck_rx_ver2_min_index = cck_rx_ver2_sec_index = i;
tmp_cck_max_pwdb = tmp_cck_min_pwdb = tmp_cck_sec_pwdb = cur_cck_pwdb;
}
else if(rf_num == 2)
{ // we pick up the max index first, and let sec and min to be the same one
if(cur_cck_pwdb >= tmp_cck_max_pwdb)
{
tmp_cck_max_pwdb = cur_cck_pwdb;
cck_rx_ver2_max_index = i;
}
else
{
tmp_cck_sec_pwdb = tmp_cck_min_pwdb = cur_cck_pwdb;
cck_rx_ver2_sec_index = cck_rx_ver2_min_index = i;
}
}
else
{
if(cur_cck_pwdb > tmp_cck_max_pwdb)
{
tmp_cck_sec_pwdb = tmp_cck_max_pwdb;
cck_rx_ver2_sec_index = cck_rx_ver2_max_index;
tmp_cck_max_pwdb = cur_cck_pwdb;
cck_rx_ver2_max_index = i;
}
else if(cur_cck_pwdb == tmp_cck_max_pwdb)
{ // let sec and min point to the different index
tmp_cck_sec_pwdb = cur_cck_pwdb;
cck_rx_ver2_sec_index = i;
}
else if((cur_cck_pwdb < tmp_cck_max_pwdb) &&(cur_cck_pwdb > tmp_cck_sec_pwdb))
{
tmp_cck_sec_pwdb = cur_cck_pwdb;
cck_rx_ver2_sec_index = i;
}
else if(cur_cck_pwdb == tmp_cck_sec_pwdb)
{
if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb)
{ // let sec and min point to the different index
tmp_cck_sec_pwdb = cur_cck_pwdb;
cck_rx_ver2_sec_index = i;
}
else
{
// This case we don't need to set any index
}
}
else if((cur_cck_pwdb < tmp_cck_sec_pwdb) && (cur_cck_pwdb > tmp_cck_min_pwdb))
{
// This case we don't need to set any index
}
else if(cur_cck_pwdb == tmp_cck_min_pwdb)
{
if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb)
{ // let sec and min point to the different index
tmp_cck_min_pwdb = cur_cck_pwdb;
cck_rx_ver2_min_index = i;
}
else
{
// This case we don't need to set any index
}
}
else if(cur_cck_pwdb < tmp_cck_min_pwdb)
{
tmp_cck_min_pwdb = cur_cck_pwdb;
cck_rx_ver2_min_index = i;
}
}
}
}
}
// Set CCK Rx path
// reg0xA07[3:2]=cck default rx path, reg0xa07[1:0]=cck optional rx path.
update_cck_rx_path = 0;
if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2)
{
cck_default_Rx = cck_rx_ver2_max_index;
cck_optional_Rx = cck_rx_ver2_sec_index;
if(tmp_cck_max_pwdb != -64)
update_cck_rx_path = 1;
}
if(tmp_min_rssi < DM_RxPathSelTable.SS_TH_low && disabled_rf_cnt < 2)
{
if((tmp_max_rssi - tmp_min_rssi) >= DM_RxPathSelTable.diff_TH)
{
//record the enabled rssi threshold
DM_RxPathSelTable.rf_enable_rssi_th[min_rssi_index] = tmp_max_rssi+5;
//disable the BB Rx path, OFDM
rtl8192_setBBreg(priv, rOFDM0_TRxPathEnable, 0x1<<min_rssi_index, 0x0); // 0xc04[3:0]
rtl8192_setBBreg(priv, rOFDM1_TRxPathEnable, 0x1<<min_rssi_index, 0x0); // 0xd04[3:0]
disabled_rf_cnt++;
}
if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_1)
{
cck_default_Rx = max_rssi_index;
cck_optional_Rx = sec_rssi_index;
if(tmp_max_rssi)
update_cck_rx_path = 1;
}
}
if(update_cck_rx_path)
{
DM_RxPathSelTable.cck_Rx_path = (cck_default_Rx<<2)|(cck_optional_Rx);
rtl8192_setBBreg(priv, rCCK0_AFESetting, 0x0f000000, DM_RxPathSelTable.cck_Rx_path);
}
if(DM_RxPathSelTable.disabledRF)
{
for(i=0; i<4; i++)
{
if((DM_RxPathSelTable.disabledRF>>i) & 0x1) //disabled rf
{
if(tmp_max_rssi >= DM_RxPathSelTable.rf_enable_rssi_th[i])
{
//enable the BB Rx path
rtl8192_setBBreg(priv, rOFDM0_TRxPathEnable, 0x1<<i, 0x1); // 0xc04[3:0]
rtl8192_setBBreg(priv, rOFDM1_TRxPathEnable, 0x1<<i, 0x1); // 0xd04[3:0]
DM_RxPathSelTable.rf_enable_rssi_th[i] = 100;
disabled_rf_cnt--;
}
}
}
}
}
/*
* Call a workitem to check current RXRF path and Rx Path selection by RSSI.
*/
static void dm_check_rx_path_selection(struct r8192_priv *priv)
{
queue_delayed_work(priv->priv_wq,&priv->rfpath_check_wq,0);
}
static void dm_init_fsync(struct r8192_priv *priv)
{
priv->ieee80211->fsync_time_interval = 500;
priv->ieee80211->fsync_rate_bitmap = 0x0f000800;
priv->ieee80211->fsync_rssi_threshold = 30;
priv->ieee80211->bfsync_enable = false;
priv->ieee80211->fsync_multiple_timeinterval = 3;
priv->ieee80211->fsync_firstdiff_ratethreshold= 100;
priv->ieee80211->fsync_seconddiff_ratethreshold= 200;
priv->ieee80211->fsync_state = Default_Fsync;
priv->framesyncMonitor = 1; // current default 0xc38 monitor on
init_timer(&priv->fsync_timer);
priv->fsync_timer.data = (unsigned long)priv;
priv->fsync_timer.function = dm_fsync_timer_callback;
}
static void dm_deInit_fsync(struct r8192_priv *priv)
{
del_timer_sync(&priv->fsync_timer);
}
static void dm_fsync_timer_callback(unsigned long data)
{
struct r8192_priv *priv = (struct r8192_priv *)data;
u32 rate_index, rate_count = 0, rate_count_diff=0;
bool bSwitchFromCountDiff = false;
bool bDoubleTimeInterval = false;
if( priv->ieee80211->state == IEEE80211_LINKED &&
priv->ieee80211->bfsync_enable &&
(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC))
{
// Count rate 54, MCS [7], [12, 13, 14, 15]
u32 rate_bitmap;
for(rate_index = 0; rate_index <= 27; rate_index++)
{
rate_bitmap = 1 << rate_index;
if(priv->ieee80211->fsync_rate_bitmap & rate_bitmap)
rate_count+= priv->stats.received_rate_histogram[1][rate_index];
}
if(rate_count < priv->rate_record)
rate_count_diff = 0xffffffff - rate_count + priv->rate_record;
else
rate_count_diff = rate_count - priv->rate_record;
if(rate_count_diff < priv->rateCountDiffRecord)
{
u32 DiffNum = priv->rateCountDiffRecord - rate_count_diff;
// Contiune count
if(DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold)
priv->ContiuneDiffCount++;
else
priv->ContiuneDiffCount = 0;
// Contiune count over
if(priv->ContiuneDiffCount >=2)
{
bSwitchFromCountDiff = true;
priv->ContiuneDiffCount = 0;
}
}
else
{
// Stop contiune count
priv->ContiuneDiffCount = 0;
}
//If Count diff <= FsyncRateCountThreshold
if(rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold)
{
bSwitchFromCountDiff = true;
priv->ContiuneDiffCount = 0;
}
priv->rate_record = rate_count;
priv->rateCountDiffRecord = rate_count_diff;
RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync);
// if we never receive those mcs rate and rssi > 30 % then switch fsyn
if(priv->undecorated_smoothed_pwdb > priv->ieee80211->fsync_rssi_threshold && bSwitchFromCountDiff)
{
bDoubleTimeInterval = true;
priv->bswitch_fsync = !priv->bswitch_fsync;
if(priv->bswitch_fsync)
{
write_nic_byte(priv,0xC36, 0x1c);
write_nic_byte(priv, 0xC3e, 0x90);
}
else
{
write_nic_byte(priv, 0xC36, 0x5c);
write_nic_byte(priv, 0xC3e, 0x96);
}
}
else if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->fsync_rssi_threshold)
{
if(priv->bswitch_fsync)
{
priv->bswitch_fsync = false;
write_nic_byte(priv, 0xC36, 0x5c);
write_nic_byte(priv, 0xC3e, 0x96);
}
}
if(bDoubleTimeInterval){
if(timer_pending(&priv->fsync_timer))
del_timer_sync(&priv->fsync_timer);
priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval*priv->ieee80211->fsync_multiple_timeinterval);
add_timer(&priv->fsync_timer);
}
else{
if(timer_pending(&priv->fsync_timer))
del_timer_sync(&priv->fsync_timer);
priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval);
add_timer(&priv->fsync_timer);
}
}
else
{
// Let Register return to default value;
if(priv->bswitch_fsync)
{
priv->bswitch_fsync = false;
write_nic_byte(priv, 0xC36, 0x5c);
write_nic_byte(priv, 0xC3e, 0x96);
}
priv->ContiuneDiffCount = 0;
write_nic_dword(priv, rOFDM0_RxDetector2, 0x465c52cd);
}
RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount);
RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync);
}
static void dm_StartHWFsync(struct r8192_priv *priv)
{
RT_TRACE(COMP_HALDM, "%s\n", __FUNCTION__);
write_nic_dword(priv, rOFDM0_RxDetector2, 0x465c12cf);
write_nic_byte(priv, 0xc3b, 0x41);
}
static void dm_EndSWFsync(struct r8192_priv *priv)
{
RT_TRACE(COMP_HALDM, "%s\n", __FUNCTION__);
del_timer_sync(&(priv->fsync_timer));
// Let Register return to default value;
if(priv->bswitch_fsync)
{
priv->bswitch_fsync = false;
write_nic_byte(priv, 0xC36, 0x40);
write_nic_byte(priv, 0xC3e, 0x96);
}
priv->ContiuneDiffCount = 0;
write_nic_dword(priv, rOFDM0_RxDetector2, 0x465c52cd);
}
static void dm_StartSWFsync(struct r8192_priv *priv)
{
u32 rateIndex;
u32 rateBitmap;
RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__);
// Initial rate record to zero, start to record.
priv->rate_record = 0;
// Initial contiune diff count to zero, start to record.
priv->ContiuneDiffCount = 0;
priv->rateCountDiffRecord = 0;
priv->bswitch_fsync = false;
if(priv->ieee80211->mode == WIRELESS_MODE_N_24G)
{
priv->ieee80211->fsync_firstdiff_ratethreshold= 600;
priv->ieee80211->fsync_seconddiff_ratethreshold = 0xffff;
}
else
{
priv->ieee80211->fsync_firstdiff_ratethreshold= 200;
priv->ieee80211->fsync_seconddiff_ratethreshold = 200;
}
for(rateIndex = 0; rateIndex <= 27; rateIndex++)
{
rateBitmap = 1 << rateIndex;
if(priv->ieee80211->fsync_rate_bitmap & rateBitmap)
priv->rate_record += priv->stats.received_rate_histogram[1][rateIndex];
}
if(timer_pending(&priv->fsync_timer))
del_timer_sync(&priv->fsync_timer);
priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval);
add_timer(&priv->fsync_timer);
write_nic_dword(priv, rOFDM0_RxDetector2, 0x465c12cd);
}
static void dm_EndHWFsync(struct r8192_priv *priv)
{
RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__);
write_nic_dword(priv, rOFDM0_RxDetector2, 0x465c52cd);
write_nic_byte(priv, 0xc3b, 0x49);
}
static void dm_check_fsync(struct r8192_priv *priv)
{
#define RegC38_Default 0
#define RegC38_NonFsync_Other_AP 1
#define RegC38_Fsync_AP_BCM 2
//u32 framesyncC34;
static u8 reg_c38_State=RegC38_Default;
static u32 reset_cnt=0;
RT_TRACE(COMP_HALDM, "RSSI %d TimeInterval %d MultipleTimeInterval %d\n", priv->ieee80211->fsync_rssi_threshold, priv->ieee80211->fsync_time_interval, priv->ieee80211->fsync_multiple_timeinterval);
RT_TRACE(COMP_HALDM, "RateBitmap 0x%x FirstDiffRateThreshold %d SecondDiffRateThreshold %d\n", priv->ieee80211->fsync_rate_bitmap, priv->ieee80211->fsync_firstdiff_ratethreshold, priv->ieee80211->fsync_seconddiff_ratethreshold);
if( priv->ieee80211->state == IEEE80211_LINKED &&
(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC))
{
if(priv->ieee80211->bfsync_enable == 0)
{
switch(priv->ieee80211->fsync_state)
{
case Default_Fsync:
dm_StartHWFsync(priv);
priv->ieee80211->fsync_state = HW_Fsync;
break;
case SW_Fsync:
dm_EndSWFsync(priv);
dm_StartHWFsync(priv);
priv->ieee80211->fsync_state = HW_Fsync;
break;
case HW_Fsync:
default:
break;
}
}
else
{
switch(priv->ieee80211->fsync_state)
{
case Default_Fsync:
dm_StartSWFsync(priv);
priv->ieee80211->fsync_state = SW_Fsync;
break;
case HW_Fsync:
dm_EndHWFsync(priv);
dm_StartSWFsync(priv);
priv->ieee80211->fsync_state = SW_Fsync;
break;
case SW_Fsync:
default:
break;
}
}
if(priv->framesyncMonitor)
{
if(reg_c38_State != RegC38_Fsync_AP_BCM)
{ //For broadcom AP we write different default value
write_nic_byte(priv, rOFDM0_RxDetector3, 0x95);
reg_c38_State = RegC38_Fsync_AP_BCM;
}
}
}
else
{
switch(priv->ieee80211->fsync_state)
{
case HW_Fsync:
dm_EndHWFsync(priv);
priv->ieee80211->fsync_state = Default_Fsync;
break;
case SW_Fsync:
dm_EndSWFsync(priv);
priv->ieee80211->fsync_state = Default_Fsync;
break;
case Default_Fsync:
default:
break;
}
if(priv->framesyncMonitor)
{
if(priv->ieee80211->state == IEEE80211_LINKED)
{
if(priv->undecorated_smoothed_pwdb <= RegC38_TH)
{
if(reg_c38_State != RegC38_NonFsync_Other_AP)
{
write_nic_byte(priv, rOFDM0_RxDetector3, 0x90);
reg_c38_State = RegC38_NonFsync_Other_AP;
}
}
else if(priv->undecorated_smoothed_pwdb >= (RegC38_TH+5))
{
if(reg_c38_State)
{
write_nic_byte(priv, rOFDM0_RxDetector3, priv->framesync);
reg_c38_State = RegC38_Default;
}
}
}
else
{
if(reg_c38_State)
{
write_nic_byte(priv, rOFDM0_RxDetector3, priv->framesync);
reg_c38_State = RegC38_Default;
}
}
}
}
if(priv->framesyncMonitor)
{
if(priv->reset_count != reset_cnt)
{ //After silent reset, the reg_c38_State will be returned to default value
write_nic_byte(priv, rOFDM0_RxDetector3, priv->framesync);
reg_c38_State = RegC38_Default;
reset_cnt = priv->reset_count;
}
}
else
{
if(reg_c38_State)
{
write_nic_byte(priv, rOFDM0_RxDetector3, priv->framesync);
reg_c38_State = RegC38_Default;
}
}
}
/*
* Detect Signal strength to control TX Registry
* Tx Power Control For Near/Far Range
*/
static void dm_init_dynamic_txpower(struct r8192_priv *priv)
{
//Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code.
priv->ieee80211->bdynamic_txpower_enable = true; //Default to enable Tx Power Control
priv->bLastDTPFlag_High = false;
priv->bLastDTPFlag_Low = false;
priv->bDynamicTxHighPower = false;
priv->bDynamicTxLowPower = false;
}
static void dm_dynamic_txpower(struct r8192_priv *priv)
{
unsigned int txhipower_threshhold=0;
unsigned int txlowpower_threshold=0;
if(priv->ieee80211->bdynamic_txpower_enable != true)
{
priv->bDynamicTxHighPower = false;
priv->bDynamicTxLowPower = false;
return;
}
if((priv->ieee80211->current_network.atheros_cap_exist ) && (priv->ieee80211->mode == IEEE_G)){
txhipower_threshhold = TX_POWER_ATHEROAP_THRESH_HIGH;
txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW;
}
else
{
txhipower_threshhold = TX_POWER_NEAR_FIELD_THRESH_HIGH;
txlowpower_threshold = TX_POWER_NEAR_FIELD_THRESH_LOW;
}
RT_TRACE(COMP_TXAGC, "priv->undecorated_smoothed_pwdb = %ld\n" , priv->undecorated_smoothed_pwdb);
if(priv->ieee80211->state == IEEE80211_LINKED)
{
if(priv->undecorated_smoothed_pwdb >= txhipower_threshhold)
{
priv->bDynamicTxHighPower = true;
priv->bDynamicTxLowPower = false;
}
else
{
// high power state check
if(priv->undecorated_smoothed_pwdb < txlowpower_threshold && priv->bDynamicTxHighPower == true)
{
priv->bDynamicTxHighPower = false;
}
// low power state check
if(priv->undecorated_smoothed_pwdb < 35)
{
priv->bDynamicTxLowPower = true;
}
else if(priv->undecorated_smoothed_pwdb >= 40)
{
priv->bDynamicTxLowPower = false;
}
}
}
else
{
//pHalData->bTXPowerCtrlforNearFarRange = !pHalData->bTXPowerCtrlforNearFarRange;
priv->bDynamicTxHighPower = false;
priv->bDynamicTxLowPower = false;
}
if( (priv->bDynamicTxHighPower != priv->bLastDTPFlag_High ) ||
(priv->bDynamicTxLowPower != priv->bLastDTPFlag_Low ) )
{
RT_TRACE(COMP_TXAGC, "SetTxPowerLevel8190() channel = %d\n", priv->ieee80211->current_network.channel);
rtl8192_phy_setTxPower(priv, priv->ieee80211->current_network.channel);
}
priv->bLastDTPFlag_High = priv->bDynamicTxHighPower;
priv->bLastDTPFlag_Low = priv->bDynamicTxLowPower;
}
//added by vivi, for read tx rate and retrycount
static void dm_check_txrateandretrycount(struct r8192_priv *priv)
{
struct ieee80211_device* ieee = priv->ieee80211;
//for initial tx rate
ieee->softmac_stats.last_packet_rate = read_nic_byte(priv ,Initial_Tx_Rate_Reg);
//for tx tx retry count
ieee->softmac_stats.txretrycount = read_nic_dword(priv, Tx_Retry_Count_Reg);
}
static void dm_send_rssi_tofw(struct r8192_priv *priv)
{
// If we test chariot, we should stop the TX command ?
// Because 92E will always silent reset when we send tx command. We use register
// 0x1e0(byte) to botify driver.
write_nic_byte(priv, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb);
return;
}
/*****************************************************************************
* Copyright(c) 2007, RealTEK Technology Inc. All Right Reserved.
*
* Module: Hal819xUsbDM.h (RTL8192 Header H File)
*
*
* Note: For dynamic control definition constant structure.
*
*
* Export:
*
* Abbrev:
*
* History:
* Data Who Remark
* 10/04/2007 MHC Create initial version.
*
*****************************************************************************/
#ifndef __R8192UDM_H__
#define __R8192UDM_H__
#define OFDM_Table_Length 19
#define CCK_Table_length 12
#define DM_DIG_THRESH_HIGH 40
#define DM_DIG_THRESH_LOW 35
#define DM_DIG_HIGH_PWR_THRESH_HIGH 75
#define DM_DIG_HIGH_PWR_THRESH_LOW 70
#define BW_AUTO_SWITCH_HIGH_LOW 25
#define BW_AUTO_SWITCH_LOW_HIGH 30
#define DM_check_fsync_time_interval 500
#define DM_DIG_BACKOFF 12
#define DM_DIG_MAX 0x36
#define DM_DIG_MIN 0x1c
#define DM_DIG_MIN_Netcore 0x12
#define RxPathSelection_SS_TH_low 30
#define RxPathSelection_diff_TH 18
#define RateAdaptiveTH_High 50
#define RateAdaptiveTH_Low_20M 30
#define RateAdaptiveTH_Low_40M 10
#define VeryLowRSSI 15
#define CTSToSelfTHVal 35
//defined by vivi, for tx power track
#define E_FOR_TX_POWER_TRACK 300
//Dynamic Tx Power Control Threshold
#define TX_POWER_NEAR_FIELD_THRESH_HIGH 68
#define TX_POWER_NEAR_FIELD_THRESH_LOW 62
//added by amy for atheros AP
#define TX_POWER_ATHEROAP_THRESH_HIGH 78
#define TX_POWER_ATHEROAP_THRESH_LOW 72
//defined by vivi, for showing on UI. Newer firmware has changed to 0x1e0
#define Current_Tx_Rate_Reg 0x1e0//0x1b8
#define Initial_Tx_Rate_Reg 0x1e1 //0x1b9
#define Tx_Retry_Count_Reg 0x1ac
#define RegC38_TH 20
/* 2007/10/04 MH Define upper and lower threshold of DIG enable or disable. */
typedef struct _dynamic_initial_gain_threshold_
{
u8 dig_enable_flag;
u8 dig_algorithm;
u8 dbg_mode;
u8 dig_algorithm_switch;
long rssi_low_thresh;
long rssi_high_thresh;
long rssi_high_power_lowthresh;
long rssi_high_power_highthresh;
u8 dig_state;
u8 dig_highpwr_state;
u8 cur_connect_state;
u8 pre_connect_state;
u8 curpd_thstate;
u8 prepd_thstate;
u8 curcs_ratio_state;
u8 precs_ratio_state;
u32 pre_ig_value;
u32 cur_ig_value;
u8 backoff_val;
u8 rx_gain_range_max;
u8 rx_gain_range_min;
bool initialgain_lowerbound_state;
long rssi_val;
}dig_t;
typedef enum tag_dynamic_init_gain_state_definition
{
DM_STA_DIG_OFF = 0,
DM_STA_DIG_ON,
DM_STA_DIG_MAX
}dm_dig_sta_e;
/* 2007/10/08 MH Define RATR state. */
typedef enum tag_dynamic_ratr_state_definition
{
DM_RATR_STA_HIGH = 0,
DM_RATR_STA_MIDDLE = 1,
DM_RATR_STA_LOW = 2,
DM_RATR_STA_MAX
}dm_ratr_sta_e;
/* 2007/10/11 MH Define DIG operation type. */
typedef enum tag_dynamic_init_gain_operation_type_definition
{
DIG_TYPE_THRESH_HIGH = 0,
DIG_TYPE_THRESH_LOW = 1,
DIG_TYPE_THRESH_HIGHPWR_HIGH = 2,
DIG_TYPE_THRESH_HIGHPWR_LOW = 3,
DIG_TYPE_DBG_MODE = 4,
DIG_TYPE_RSSI = 5,
DIG_TYPE_ALGORITHM = 6,
DIG_TYPE_BACKOFF = 7,
DIG_TYPE_PWDB_FACTOR = 8,
DIG_TYPE_RX_GAIN_MIN = 9,
DIG_TYPE_RX_GAIN_MAX = 10,
DIG_TYPE_ENABLE = 20,
DIG_TYPE_DISABLE = 30,
DIG_OP_TYPE_MAX
}dm_dig_op_e;
typedef enum tag_dig_algorithm_definition
{
DIG_ALGO_BY_FALSE_ALARM = 0,
DIG_ALGO_BY_RSSI = 1,
DIG_ALGO_MAX
}dm_dig_alg_e;
typedef enum tag_dig_dbgmode_definition
{
DIG_DBG_OFF = 0,
DIG_DBG_ON = 1,
DIG_DBG_MAX
}dm_dig_dbg_e;
typedef enum tag_dig_connect_definition
{
DIG_DISCONNECT = 0,
DIG_CONNECT = 1,
DIG_CONNECT_MAX
}dm_dig_connect_e;
typedef enum tag_dig_packetdetection_threshold_definition
{
DIG_PD_AT_LOW_POWER = 0,
DIG_PD_AT_NORMAL_POWER = 1,
DIG_PD_AT_HIGH_POWER = 2,
DIG_PD_MAX
}dm_dig_pd_th_e;
typedef enum tag_dig_cck_cs_ratio_state_definition
{
DIG_CS_RATIO_LOWER = 0,
DIG_CS_RATIO_HIGHER = 1,
DIG_CS_MAX
}dm_dig_cs_ratio_e;
typedef struct _Dynamic_Rx_Path_Selection_
{
u8 Enable;
u8 DbgMode;
u8 cck_method;
u8 cck_Rx_path;
u8 SS_TH_low;
u8 diff_TH;
u8 disabledRF;
u8 reserved;
u8 rf_rssi[4];
u8 rf_enable_rssi_th[4];
long cck_pwdb_sta[4];
}DRxPathSel;
typedef enum tag_CCK_Rx_Path_Method_Definition
{
CCK_Rx_Version_1 = 0,
CCK_Rx_Version_2= 1,
CCK_Rx_Version_MAX
}DM_CCK_Rx_Path_Method;
typedef enum tag_DM_DbgMode_Definition
{
DM_DBG_OFF = 0,
DM_DBG_ON = 1,
DM_DBG_MAX
}DM_DBG_E;
typedef struct tag_Tx_Config_Cmd_Format
{
u32 Op; /* Command packet type. */
u32 Length; /* Command packet length. */
u32 Value;
}DCMD_TXCMD_T, *PDCMD_TXCMD_T;
extern dig_t dm_digtable;
extern DRxPathSel DM_RxPathSelTable;
void init_hal_dm(struct r8192_priv *priv);
void deinit_hal_dm(struct r8192_priv *priv);
void hal_dm_watchdog(struct r8192_priv *priv);
void init_rate_adaptive(struct r8192_priv *priv);
void dm_txpower_trackingcallback(struct work_struct *work);
void dm_rf_pathcheck_workitemcallback(struct work_struct *work);
void dm_initialize_txpower_tracking(struct r8192_priv *priv);
void dm_cck_txpower_adjust(struct r8192_priv *priv, bool binch14);
#endif /*__R8192UDM_H__ */
/*
This file contains wireless extension handlers.
This is part of rtl8180 OpenSource driver.
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part
of the official realtek driver.
Parts of this driver are based on the rtl8180 driver skeleton
from Patric Schenke & Andres Salomon.
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
We want to tanks the Authors of those projects and the Ndiswrapper
project Authors.
*/
#include <linux/string.h>
#include "r8192E.h"
#include "r8192E_hw.h"
#include "r8192E_wx.h"
#ifdef ENABLE_DOT11D
#include "ieee80211/dot11d.h"
#endif
#define RATE_COUNT 12
static const u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000,
6000000,9000000,12000000,18000000,24000000,36000000,48000000,54000000};
#ifndef ENETDOWN
#define ENETDOWN 1
#endif
static int r8192_wx_get_freq(struct net_device *dev,
struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
struct r8192_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_freq(priv->ieee80211,a,wrqu,b);
}
static int r8192_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
struct r8192_priv *priv=ieee80211_priv(dev);
return ieee80211_wx_get_mode(priv->ieee80211,a,wrqu,b);
}
static int r8192_wx_get_rate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_rate(priv->ieee80211,info,wrqu,extra);
}
static int r8192_wx_set_rate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
ret = ieee80211_wx_set_rate(priv->ieee80211,info,wrqu,extra);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_set_rts(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
ret = ieee80211_wx_set_rts(priv->ieee80211,info,wrqu,extra);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_get_rts(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_rts(priv->ieee80211,info,wrqu,extra);
}
static int r8192_wx_set_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
ret = ieee80211_wx_set_power(priv->ieee80211,info,wrqu,extra);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_get_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_power(priv->ieee80211,info,wrqu,extra);
}
static int r8192_wx_set_rawtx(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
int ret;
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_force_reset(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
down(&priv->wx_sem);
printk("%s(): force reset ! extra is %d\n",__FUNCTION__, *extra);
priv->force_reset = *extra;
up(&priv->wx_sem);
return 0;
}
static int r8192_wx_set_crcmon(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
int *parms = (int *)extra;
int enable = (parms[0] > 0);
short prev = priv->crcmon;
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
if(enable)
priv->crcmon=1;
else
priv->crcmon=0;
DMESG("bad CRC in monitor mode are %s",
priv->crcmon ? "accepted" : "rejected");
if(prev != priv->crcmon && priv->up){
//rtl8180_down(dev);
//rtl8180_up(dev);
}
up(&priv->wx_sem);
return 0;
}
static int r8192_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
struct r8192_priv *priv = ieee80211_priv(dev);
RT_RF_POWER_STATE rtState;
int ret;
if (priv->bHwRadioOff)
return 0;
rtState = priv->eRFPowerState;
down(&priv->wx_sem);
#ifdef ENABLE_IPS
if(wrqu->mode == IW_MODE_ADHOC){
if (priv->PowerSaveControl.bInactivePs) {
if(rtState == eRfOff){
if(priv->RfOffReason > RF_CHANGE_BY_IPS)
{
RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",__FUNCTION__);
up(&priv->wx_sem);
return -1;
}
else{
RT_TRACE(COMP_ERR, "%s(): IPSLeave\n",__FUNCTION__);
down(&priv->ieee80211->ips_sem);
IPSLeave(priv);
up(&priv->ieee80211->ips_sem);
}
}
}
}
#endif
ret = ieee80211_wx_set_mode(priv->ieee80211,a,wrqu,b);
//rtl8187_set_rxconf(dev);
up(&priv->wx_sem);
return ret;
}
struct iw_range_with_scan_capa
{
/* Informative stuff (to choose between different interface) */
__u32 throughput; /* To give an idea... */
/* In theory this value should be the maximum benchmarked
* TCP/IP throughput, because with most of these devices the
* bit rate is meaningless (overhead an co) to estimate how
* fast the connection will go and pick the fastest one.
* I suggest people to play with Netperf or any benchmark...
*/
/* NWID (or domain id) */
__u32 min_nwid; /* Minimal NWID we are able to set */
__u32 max_nwid; /* Maximal NWID we are able to set */
/* Old Frequency (backward compat - moved lower ) */
__u16 old_num_channels;
__u8 old_num_frequency;
/* Scan capabilities */
__u8 scan_capa;
};
static int rtl8180_wx_get_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct iw_range *range = (struct iw_range *)extra;
struct iw_range_with_scan_capa* tmp = (struct iw_range_with_scan_capa*)range;
struct r8192_priv *priv = ieee80211_priv(dev);
u16 val;
int i;
wrqu->data.length = sizeof(*range);
memset(range, 0, sizeof(*range));
/* Let's try to keep this struct in the same order as in
* linux/include/wireless.h
*/
/* TODO: See what values we can set, and remove the ones we can't
* set, or fill them with some default data.
*/
/* ~5 Mb/s real (802.11b) */
range->throughput = 130 * 1000 * 1000;
// TODO: Not used in 802.11b?
// range->min_nwid; /* Minimal NWID we are able to set */
// TODO: Not used in 802.11b?
// range->max_nwid; /* Maximal NWID we are able to set */
/* Old Frequency (backward compat - moved lower ) */
// range->old_num_channels;
// range->old_num_frequency;
// range->old_freq[6]; /* Filler to keep "version" at the same offset */
range->max_qual.qual = 100;
/* TODO: Find real max RSSI and stick here */
range->max_qual.level = 0;
range->max_qual.noise = -98;
range->max_qual.updated = 7; /* Updated all three */
range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
/* TODO: Find real 'good' to 'bad' threshold value for RSSI */
range->avg_qual.level = 20 + -98;
range->avg_qual.noise = 0;
range->avg_qual.updated = 7; /* Updated all three */
range->num_bitrates = RATE_COUNT;
for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
range->bitrate[i] = rtl8180_rates[i];
}
range->min_frag = MIN_FRAG_THRESHOLD;
range->max_frag = MAX_FRAG_THRESHOLD;
range->min_pmp=0;
range->max_pmp = 5000000;
range->min_pmt = 0;
range->max_pmt = 65535*1000;
range->pmp_flags = IW_POWER_PERIOD;
range->pmt_flags = IW_POWER_TIMEOUT;
range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 18;
// range->retry_capa; /* What retry options are supported */
// range->retry_flags; /* How to decode max/min retry limit */
// range->r_time_flags; /* How to decode max/min retry life */
// range->min_retry; /* Minimal number of retries */
// range->max_retry; /* Maximal number of retries */
// range->min_r_time; /* Minimal retry lifetime */
// range->max_r_time; /* Maximal retry lifetime */
for (i = 0, val = 0; i < 14; i++) {
// Include only legal frequencies for some countries
#ifdef ENABLE_DOT11D
if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) {
#else
if ((priv->ieee80211->channel_map)[i+1]) {
#endif
range->freq[val].i = i + 1;
range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000;
range->freq[val].e = 1;
val++;
} else {
// FIXME: do we need to set anything for channels
// we don't use ?
}
if (val == IW_MAX_FREQUENCIES)
break;
}
range->num_frequency = val;
range->num_channels = val;
range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2|
IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP;
tmp->scan_capa = 0x01;
return 0;
}
static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
struct r8192_priv *priv = ieee80211_priv(dev);
struct ieee80211_device* ieee = priv->ieee80211;
RT_RF_POWER_STATE rtState;
int ret;
if (priv->bHwRadioOff)
return 0;
rtState = priv->eRFPowerState;
if(!priv->up) return -ENETDOWN;
if (priv->ieee80211->LinkDetectInfo.bBusyTraffic == true)
return -EAGAIN;
if (wrqu->data.flags & IW_SCAN_THIS_ESSID)
{
struct iw_scan_req* req = (struct iw_scan_req*)b;
if (req->essid_len)
{
//printk("==**&*&*&**===>scan set ssid:%s\n", req->essid);
ieee->current_network.ssid_len = req->essid_len;
memcpy(ieee->current_network.ssid, req->essid, req->essid_len);
//printk("=====>network ssid:%s\n", ieee->current_network.ssid);
}
}
down(&priv->wx_sem);
#ifdef ENABLE_IPS
priv->ieee80211->actscanning = true;
if(priv->ieee80211->state != IEEE80211_LINKED){
if (priv->PowerSaveControl.bInactivePs) {
if(rtState == eRfOff){
if(priv->RfOffReason > RF_CHANGE_BY_IPS)
{
RT_TRACE(COMP_ERR, "%s(): RF is OFF.\n",__FUNCTION__);
up(&priv->wx_sem);
return -1;
}
else{
//RT_TRACE(COMP_PS, "%s(): IPSLeave\n",__FUNCTION__);
down(&priv->ieee80211->ips_sem);
IPSLeave(priv);
up(&priv->ieee80211->ips_sem);
}
}
}
priv->ieee80211->scanning = 0;
ieee80211_softmac_scan_syncro(priv->ieee80211);
ret = 0;
}
else
#else
if(priv->ieee80211->state != IEEE80211_LINKED){
priv->ieee80211->scanning = 0;
ieee80211_softmac_scan_syncro(priv->ieee80211);
ret = 0;
}
else
#endif
ret = ieee80211_wx_set_scan(priv->ieee80211,a,wrqu,b);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->bHwRadioOff)
return 0;
if(!priv->up) return -ENETDOWN;
down(&priv->wx_sem);
ret = ieee80211_wx_get_scan(priv->ieee80211,a,wrqu,b);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_set_essid(struct net_device *dev,
struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
struct r8192_priv *priv = ieee80211_priv(dev);
RT_RF_POWER_STATE rtState;
int ret;
if (priv->bHwRadioOff)
return 0;
rtState = priv->eRFPowerState;
down(&priv->wx_sem);
#ifdef ENABLE_IPS
down(&priv->ieee80211->ips_sem);
IPSLeave(priv);
up(&priv->ieee80211->ips_sem);
#endif
ret = ieee80211_wx_set_essid(priv->ieee80211,a,wrqu,b);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_get_essid(struct net_device *dev,
struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
down(&priv->wx_sem);
ret = ieee80211_wx_get_essid(priv->ieee80211, a, wrqu, b);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_set_freq(struct net_device *dev, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
{
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_get_name(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_name(priv->ieee80211, info, wrqu, extra);
}
static int r8192_wx_set_frag(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->bHwRadioOff)
return 0;
if (wrqu->frag.disabled)
priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD;
else {
if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
wrqu->frag.value > MAX_FRAG_THRESHOLD)
return -EINVAL;
priv->ieee80211->fts = wrqu->frag.value & ~0x1;
}
return 0;
}
static int r8192_wx_get_frag(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
wrqu->frag.value = priv->ieee80211->fts;
wrqu->frag.fixed = 0; /* no auto select */
wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD);
return 0;
}
static int r8192_wx_set_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *awrq,
char *extra)
{
int ret;
struct r8192_priv *priv = ieee80211_priv(dev);
// struct sockaddr *temp = (struct sockaddr *)awrq;
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
#ifdef ENABLE_IPS
down(&priv->ieee80211->ips_sem);
IPSLeave(priv);
up(&priv->ieee80211->ips_sem);
#endif
ret = ieee80211_wx_set_wap(priv->ieee80211,info,awrq,extra);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_get_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_wap(priv->ieee80211,info,wrqu,extra);
}
static int r8192_wx_get_enc(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *key)
{
struct r8192_priv *priv = ieee80211_priv(dev);
return ieee80211_wx_get_encode(priv->ieee80211, info, wrqu, key);
}
static int r8192_wx_set_enc(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *key)
{
struct r8192_priv *priv = ieee80211_priv(dev);
int ret;
struct ieee80211_device *ieee = priv->ieee80211;
//u32 TargetContent;
u32 hwkey[4]={0,0,0,0};
u8 mask=0xff;
u32 key_idx=0;
u8 zero_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} };
int i;
if (priv->bHwRadioOff)
return 0;
if(!priv->up) return -ENETDOWN;
priv->ieee80211->wx_set_enc = 1;
#ifdef ENABLE_IPS
down(&priv->ieee80211->ips_sem);
IPSLeave(priv);
up(&priv->ieee80211->ips_sem);
#endif
down(&priv->wx_sem);
RT_TRACE(COMP_SEC, "Setting SW wep key\n");
ret = ieee80211_wx_set_encode(priv->ieee80211,info,wrqu,key);
up(&priv->wx_sem);
//sometimes, the length is zero while we do not type key value
if(wrqu->encoding.length!=0){
for(i=0 ; i<4 ; i++){
hwkey[i] |= key[4*i+0]&mask;
if(i==1&&(4*i+1)==wrqu->encoding.length) mask=0x00;
if(i==3&&(4*i+1)==wrqu->encoding.length) mask=0x00;
hwkey[i] |= (key[4*i+1]&mask)<<8;
hwkey[i] |= (key[4*i+2]&mask)<<16;
hwkey[i] |= (key[4*i+3]&mask)<<24;
}
#define CONF_WEP40 0x4
#define CONF_WEP104 0x14
switch(wrqu->encoding.flags & IW_ENCODE_INDEX){
case 0: key_idx = ieee->tx_keyidx; break;
case 1: key_idx = 0; break;
case 2: key_idx = 1; break;
case 3: key_idx = 2; break;
case 4: key_idx = 3; break;
default: break;
}
//printk("-------====>length:%d, key_idx:%d, flag:%x\n", wrqu->encoding.length, key_idx, wrqu->encoding.flags);
if(wrqu->encoding.length==0x5){
ieee->pairwise_key_type = KEY_TYPE_WEP40;
EnableHWSecurityConfig8192(priv);
setKey(priv, key_idx, key_idx, KEY_TYPE_WEP40,
zero_addr[key_idx], 0, hwkey);
}
else if(wrqu->encoding.length==0xd){
ieee->pairwise_key_type = KEY_TYPE_WEP104;
EnableHWSecurityConfig8192(priv);
setKey(priv, key_idx, key_idx, KEY_TYPE_WEP104,
zero_addr[key_idx], 0, hwkey);
}
else printk("wrong type in WEP, not WEP40 and WEP104\n");
}
priv->ieee80211->wx_set_enc = 0;
return ret;
}
static int r8192_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa, union
iwreq_data *wrqu, char *p){
struct r8192_priv *priv = ieee80211_priv(dev);
int *parms=(int*)p;
int mode=parms[0];
priv->ieee80211->active_scan = mode;
return 1;
}
static int r8192_wx_set_retry(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
int err = 0;
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
if (wrqu->retry.flags & IW_RETRY_LIFETIME ||
wrqu->retry.disabled){
err = -EINVAL;
goto exit;
}
if (!(wrqu->retry.flags & IW_RETRY_LIMIT)){
err = -EINVAL;
goto exit;
}
if(wrqu->retry.value > R8180_MAX_RETRY){
err= -EINVAL;
goto exit;
}
if (wrqu->retry.flags & IW_RETRY_MAX) {
priv->retry_rts = wrqu->retry.value;
DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value);
}else {
priv->retry_data = wrqu->retry.value;
DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value);
}
/* FIXME !
* We might try to write directly the TX config register
* or to restart just the (R)TX process.
* I'm unsure if whole reset is really needed
*/
rtl8192_commit(priv);
/*
if(priv->up){
rtl8180_rtx_disable(dev);
rtl8180_rx_enable(dev);
rtl8180_tx_enable(dev);
}
*/
exit:
up(&priv->wx_sem);
return err;
}
static int r8192_wx_get_retry(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
wrqu->retry.disabled = 0; /* can't be disabled */
if ((wrqu->retry.flags & IW_RETRY_TYPE) ==
IW_RETRY_LIFETIME)
return -EINVAL;
if (wrqu->retry.flags & IW_RETRY_MAX) {
wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX;
wrqu->retry.value = priv->retry_rts;
} else {
wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MIN;
wrqu->retry.value = priv->retry_data;
}
//DMESG("returning %d",wrqu->retry.value);
return 0;
}
static int r8192_wx_get_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
if(priv->rf_set_sens == NULL)
return -1; /* we have not this support for this radio */
wrqu->sens.value = priv->sens;
return 0;
}
static int r8192_wx_set_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
short err = 0;
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
//DMESG("attempt to set sensivity to %ddb",wrqu->sens.value);
if(priv->rf_set_sens == NULL) {
err= -1; /* we have not this support for this radio */
goto exit;
}
if(priv->rf_set_sens(dev, wrqu->sens.value) == 0)
priv->sens = wrqu->sens.value;
else
err= -EINVAL;
exit:
up(&priv->wx_sem);
return err;
}
static int r8192_wx_set_enc_ext(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret=0;
struct r8192_priv *priv = ieee80211_priv(dev);
struct ieee80211_device* ieee = priv->ieee80211;
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
priv->ieee80211->wx_set_enc = 1;
#ifdef ENABLE_IPS
down(&priv->ieee80211->ips_sem);
IPSLeave(priv);
up(&priv->ieee80211->ips_sem);
#endif
ret = ieee80211_wx_set_encode_ext(ieee, info, wrqu, extra);
{
u8 broadcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
u8 zero[6] = {0};
u32 key[4] = {0};
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
struct iw_point *encoding = &wrqu->encoding;
u8 idx = 0, alg = 0, group = 0;
if ((encoding->flags & IW_ENCODE_DISABLED) ||
ext->alg == IW_ENCODE_ALG_NONE) //none is not allowed to use hwsec WB 2008.07.01
{
ieee->pairwise_key_type = ieee->group_key_type = KEY_TYPE_NA;
CamResetAllEntry(priv);
goto end_hw_sec;
}
alg = (ext->alg == IW_ENCODE_ALG_CCMP)?KEY_TYPE_CCMP:ext->alg; // as IW_ENCODE_ALG_CCMP is defined to be 3 and KEY_TYPE_CCMP is defined to 4;
idx = encoding->flags & IW_ENCODE_INDEX;
if (idx)
idx --;
group = ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY;
if ((!group) || (IW_MODE_ADHOC == ieee->iw_mode) || (alg == KEY_TYPE_WEP40))
{
if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40) )
alg = KEY_TYPE_WEP104;
ieee->pairwise_key_type = alg;
EnableHWSecurityConfig8192(priv);
}
memcpy((u8*)key, ext->key, 16); //we only get 16 bytes key.why? WB 2008.7.1
if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode !=2) )
{
if (ext->key_len == 13)
ieee->pairwise_key_type = alg = KEY_TYPE_WEP104;
setKey(priv, idx, idx, alg, zero, 0, key);
}
else if (group)
{
ieee->group_key_type = alg;
setKey(priv, idx, idx, alg, broadcast_addr, 0, key);
}
else //pairwise key
{
if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && ieee->pHTInfo->bCurrentHTSupport){
write_nic_byte(priv, 0x173, 1); //fix aes bug
}
setKey(priv, 4, idx, alg,
(u8*)ieee->ap_mac_addr, 0, key);
}
}
end_hw_sec:
priv->ieee80211->wx_set_enc = 0;
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_set_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
{
int ret=0;
//printk("====>%s()\n", __FUNCTION__);
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
ret = ieee80211_wx_set_auth(priv->ieee80211, info, &(data->param), extra);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
//printk("====>%s()\n", __FUNCTION__);
int ret=0;
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra);
up(&priv->wx_sem);
return ret;
}
static int r8192_wx_set_gen_ie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *data, char *extra)
{
//printk("====>%s(), len:%d\n", __FUNCTION__, data->length);
int ret=0;
struct r8192_priv *priv = ieee80211_priv(dev);
if (priv->bHwRadioOff)
return 0;
down(&priv->wx_sem);
ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->data.length);
up(&priv->wx_sem);
//printk("<======%s(), ret:%d\n", __FUNCTION__, ret);
return ret;
}
static int dummy(struct net_device *dev, struct iw_request_info *a,
union iwreq_data *wrqu,char *b)
{
return -1;
}
// check ac/dc status with the help of user space application */
static int r8192_wx_adapter_power_status(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct r8192_priv *priv = ieee80211_priv(dev);
#ifdef ENABLE_LPS
PRT_POWER_SAVE_CONTROL pPSC = &priv->PowerSaveControl;
struct ieee80211_device* ieee = priv->ieee80211;
#endif
down(&priv->wx_sem);
#ifdef ENABLE_LPS
RT_TRACE(COMP_POWER, "%s(): %s\n",__FUNCTION__, (*extra == 6)?"DC power":"AC power");
// ieee->ps shall not be set under DC mode, otherwise it conflict
// with Leisure power save mode setting.
//
if(*extra || priv->force_lps) {
priv->ps_force = false;
pPSC->bLeisurePs = true;
} else {
//LZM for PS-Poll AID issue. 090429
if(priv->ieee80211->state == IEEE80211_LINKED)
LeisurePSLeave(priv->ieee80211);
priv->ps_force = true;
pPSC->bLeisurePs = false;
ieee->ps = *extra;
}
#endif
up(&priv->wx_sem);
return 0;
}
static iw_handler r8192_wx_handlers[] =
{
NULL, /* SIOCSIWCOMMIT */
r8192_wx_get_name, /* SIOCGIWNAME */
dummy, /* SIOCSIWNWID */
dummy, /* SIOCGIWNWID */
r8192_wx_set_freq, /* SIOCSIWFREQ */
r8192_wx_get_freq, /* SIOCGIWFREQ */
r8192_wx_set_mode, /* SIOCSIWMODE */
r8192_wx_get_mode, /* SIOCGIWMODE */
r8192_wx_set_sens, /* SIOCSIWSENS */
r8192_wx_get_sens, /* SIOCGIWSENS */
NULL, /* SIOCSIWRANGE */
rtl8180_wx_get_range, /* SIOCGIWRANGE */
NULL, /* SIOCSIWPRIV */
NULL, /* SIOCGIWPRIV */
NULL, /* SIOCSIWSTATS */
NULL, /* SIOCGIWSTATS */
dummy, /* SIOCSIWSPY */
dummy, /* SIOCGIWSPY */
NULL, /* SIOCGIWTHRSPY */
NULL, /* SIOCWIWTHRSPY */
r8192_wx_set_wap, /* SIOCSIWAP */
r8192_wx_get_wap, /* SIOCGIWAP */
r8192_wx_set_mlme, /* MLME-- */
dummy, /* SIOCGIWAPLIST -- depricated */
r8192_wx_set_scan, /* SIOCSIWSCAN */
r8192_wx_get_scan, /* SIOCGIWSCAN */
r8192_wx_set_essid, /* SIOCSIWESSID */
r8192_wx_get_essid, /* SIOCGIWESSID */
dummy, /* SIOCSIWNICKN */
dummy, /* SIOCGIWNICKN */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
r8192_wx_set_rate, /* SIOCSIWRATE */
r8192_wx_get_rate, /* SIOCGIWRATE */
r8192_wx_set_rts, /* SIOCSIWRTS */
r8192_wx_get_rts, /* SIOCGIWRTS */
r8192_wx_set_frag, /* SIOCSIWFRAG */
r8192_wx_get_frag, /* SIOCGIWFRAG */
dummy, /* SIOCSIWTXPOW */
dummy, /* SIOCGIWTXPOW */
r8192_wx_set_retry, /* SIOCSIWRETRY */
r8192_wx_get_retry, /* SIOCGIWRETRY */
r8192_wx_set_enc, /* SIOCSIWENCODE */
r8192_wx_get_enc, /* SIOCGIWENCODE */
r8192_wx_set_power, /* SIOCSIWPOWER */
r8192_wx_get_power, /* SIOCGIWPOWER */
NULL, /*---hole---*/
NULL, /*---hole---*/
r8192_wx_set_gen_ie,//NULL, /* SIOCSIWGENIE */
NULL, /* SIOCSIWGENIE */
r8192_wx_set_auth,//NULL, /* SIOCSIWAUTH */
NULL,//r8192_wx_get_auth,//NULL, /* SIOCSIWAUTH */
r8192_wx_set_enc_ext, /* SIOCSIWENCODEEXT */
NULL,//r8192_wx_get_enc_ext,//NULL, /* SIOCSIWENCODEEXT */
NULL, /* SIOCSIWPMKSA */
NULL, /*---hole---*/
};
static const struct iw_priv_args r8192_private_args[] = {
{
SIOCIWFIRSTPRIV + 0x0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc"
},
{
SIOCIWFIRSTPRIV + 0x1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan"
},
{
SIOCIWFIRSTPRIV + 0x2,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx"
}
,
{
SIOCIWFIRSTPRIV + 0x3,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset"
}
,
{
SIOCIWFIRSTPRIV + 0x4,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE,
"set_power"
}
};
static iw_handler r8192_private_handler[] = {
r8192_wx_set_crcmon, /*SIOCIWSECONDPRIV*/
r8192_wx_set_scan_type,
r8192_wx_set_rawtx,
r8192_wx_force_reset,
r8192_wx_adapter_power_status,
};
static struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
struct ieee80211_device* ieee = priv->ieee80211;
struct iw_statistics* wstats = &priv->wstats;
int tmp_level = 0;
int tmp_qual = 0;
int tmp_noise = 0;
if(ieee->state < IEEE80211_LINKED)
{
wstats->qual.qual = 0;
wstats->qual.level = 0;
wstats->qual.noise = 0;
wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
return wstats;
}
tmp_level = (&ieee->current_network)->stats.rssi;
tmp_qual = (&ieee->current_network)->stats.signal;
tmp_noise = (&ieee->current_network)->stats.noise;
//printk("level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise);
wstats->qual.level = tmp_level;
wstats->qual.qual = tmp_qual;
wstats->qual.noise = tmp_noise;
wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
return wstats;
}
struct iw_handler_def r8192_wx_handlers_def={
.standard = r8192_wx_handlers,
.num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler),
.private = r8192_private_handler,
.num_private = sizeof(r8192_private_handler) / sizeof(iw_handler),
.num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args),
.get_wireless_stats = r8192_get_wireless_stats,
.private_args = (struct iw_priv_args *)r8192_private_args,
};
/*
This is part of rtl8180 OpenSource driver - v 0.3
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
Released under the terms of GPL (General Public Licence)
Parts of this driver are based on the GPL part of the official realtek driver
Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
*/
/* this file (will) contains wireless extension handlers*/
#ifndef R8180_WX_H
#define R8180_WX_H
extern struct iw_handler_def r8192_wx_handlers_def;
#endif
/*
Power management interface routines.
Written by Mariusz Matuszek.
This code is currently just a placeholder for later work and
does not do anything useful.
This is part of rtl8180 OpenSource driver.
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
Released under the terms of GPL (General Public Licence)
*/
#include "r8192E.h"
#include "r8192E_hw.h"
#include "r8192_pm.h"
#include "r8190_rtl8256.h"
int rtl8192E_save_state (struct pci_dev *dev, pm_message_t state)
{
printk(KERN_NOTICE "r8192E save state call (state %u).\n", state.event);
return -EAGAIN;
}
int rtl8192E_suspend (struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct r8192_priv *priv = ieee80211_priv(dev);
u32 ulRegRead;
RT_TRACE(COMP_POWER, "============> r8192E suspend call.\n");
if (!netif_running(dev))
goto out_pci_suspend;
if (dev->netdev_ops->ndo_stop)
dev->netdev_ops->ndo_stop(dev);
// Call MgntActSet_RF_State instead to prevent RF config race condition.
if(!priv->ieee80211->bSupportRemoteWakeUp) {
MgntActSet_RF_State(priv, eRfOff, RF_CHANGE_BY_INIT);
// 2006.11.30. System reset bit
ulRegRead = read_nic_dword(priv, CPU_GEN);
ulRegRead|=CPU_GEN_SYSTEM_RESET;
write_nic_dword(priv, CPU_GEN, ulRegRead);
} else {
//2008.06.03 for WOL
write_nic_dword(priv, WFCRC0, 0xffffffff);
write_nic_dword(priv, WFCRC1, 0xffffffff);
write_nic_dword(priv, WFCRC2, 0xffffffff);
//Write PMR register
write_nic_byte(priv, PMR, 0x5);
//Disable tx, enanble rx
write_nic_byte(priv, MacBlkCtrl, 0xa);
}
out_pci_suspend:
RT_TRACE(COMP_POWER, "r8192E support WOL call??????????????????????\n");
if(priv->ieee80211->bSupportRemoteWakeUp) {
RT_TRACE(COMP_POWER, "r8192E support WOL call!!!!!!!!!!!!!!!!!!.\n");
}
netif_device_detach(dev);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_enable_wake(pdev, pci_choose_state(pdev,state),
priv->ieee80211->bSupportRemoteWakeUp?1:0);
pci_set_power_state(pdev,pci_choose_state(pdev,state));
return 0;
}
int rtl8192E_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
int err;
u32 val;
RT_TRACE(COMP_POWER, "================>r8192E resume call.\n");
pci_set_power_state(pdev, PCI_D0);
err = pci_enable_device(pdev);
if(err) {
printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
dev->name);
return err;
}
pci_restore_state(pdev);
/*
* Suspend/Resume resets the PCI configuration space, so we have to
* re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
* from interfering with C3 CPU state. pci_restore_state won't help
* here since it only restores the first 64 bytes pci config header.
*/
pci_read_config_dword(pdev, 0x40, &val);
if ((val & 0x0000ff00) != 0) {
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
}
pci_enable_wake(pdev, PCI_D0, 0);
if(!netif_running(dev))
goto out;
netif_device_attach(dev);
if (dev->netdev_ops->ndo_open)
dev->netdev_ops->ndo_open(dev);
out:
RT_TRACE(COMP_POWER, "<================r8192E resume call.\n");
return 0;
}
int rtl8192E_enable_wake (struct pci_dev *dev, pm_message_t state, int enable)
{
printk(KERN_NOTICE "r8192E enable wake call (state %u, enable %d).\n",
state.event, enable);
return -EAGAIN;
}
/*
Power management interface routines.
Written by Mariusz Matuszek.
This code is currently just a placeholder for later work and
does not do anything useful.
This is part of rtl8180 OpenSource driver.
Copyright (C) Andrea Merello 2004 <andreamrl@tiscali.it>
Released under the terms of GPL (General Public Licence)
*/
#ifndef R8192E_PM_H
#define R8192E_PM_H
#include <linux/types.h>
#include <linux/pci.h>
int rtl8192E_save_state (struct pci_dev *dev, pm_message_t state);
int rtl8192E_suspend (struct pci_dev *dev, pm_message_t state);
int rtl8192E_resume (struct pci_dev *dev);
int rtl8192E_enable_wake (struct pci_dev *dev, pm_message_t state, int enable);
#endif //R8192E_PM_H
/******************************************************************************
(c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
Module: r819xusb_cmdpkt.c (RTL8190 TX/RX command packet handler Source C File)
Note: The module is responsible for handling TX and RX command packet.
1. TX : Send set and query configuration command packet.
2. RX : Receive tx feedback, beacon state, query configuration
command packet.
Function:
Export:
Abbrev:
History:
Data Who Remark
05/06/2008 amy Create initial version porting from windows driver.
******************************************************************************/
#include "r8192E.h"
#include "r8192E_hw.h"
#include "r819xE_cmdpkt.h"
/*
* Driver internal module can call the API to send message to
* firmware side. For example, you can send a debug command packet.
* Or you can send a request for FW to modify RLX4181 LBUS HW bank.
* Otherwise, you can change MAC/PHT/RF register by firmware at
* run time. We do not support message more than one segment now.
*/
RT_STATUS cmpk_message_handle_tx(
struct r8192_priv *priv,
u8* code_virtual_address,
u32 packettype,
u32 buffer_len)
{
RT_STATUS rt_status = RT_STATUS_SUCCESS;
u16 frag_threshold;
u16 frag_length = 0, frag_offset = 0;
rt_firmware *pfirmware = priv->pFirmware;
struct sk_buff *skb;
unsigned char *seg_ptr;
cb_desc *tcb_desc;
u8 bLastIniPkt;
PTX_FWINFO_8190PCI pTxFwInfo = NULL;
int i;
RT_TRACE(COMP_CMDPKT,"%s(),buffer_len is %d\n",__FUNCTION__,buffer_len);
firmware_init_param(priv);
//Fragmentation might be required
frag_threshold = pfirmware->cmdpacket_frag_thresold;
do {
if((buffer_len - frag_offset) > frag_threshold) {
frag_length = frag_threshold ;
bLastIniPkt = 0;
} else {
frag_length =(u16)(buffer_len - frag_offset);
bLastIniPkt = 1;
}
/* Allocate skb buffer to contain firmware info and tx descriptor info
* add 4 to avoid packet appending overflow.
* */
skb = dev_alloc_skb(frag_length + priv->ieee80211->tx_headroom + 4);
if(skb == NULL) {
rt_status = RT_STATUS_FAILURE;
goto Failed;
}
tcb_desc = (cb_desc*)(skb->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->queue_index = TXCMD_QUEUE;
tcb_desc->bCmdOrInit = packettype;
tcb_desc->bLastIniPkt = bLastIniPkt;
tcb_desc->pkt_size = frag_length;
//seg_ptr = skb_put(skb, frag_length + priv->ieee80211->tx_headroom);
seg_ptr = skb_put(skb, priv->ieee80211->tx_headroom);
pTxFwInfo = (PTX_FWINFO_8190PCI)seg_ptr;
memset(pTxFwInfo,0,sizeof(TX_FWINFO_8190PCI));
memset(pTxFwInfo,0x12,8);
seg_ptr +=sizeof(TX_FWINFO_8190PCI);
/*
* Transform from little endian to big endian
* and pending zero
*/
seg_ptr = skb_tail_pointer(skb);
for(i=0 ; i < frag_length; i+=4) {
*seg_ptr++ = ((i+0)<frag_length)?code_virtual_address[i+3]:0;
*seg_ptr++ = ((i+1)<frag_length)?code_virtual_address[i+2]:0;
*seg_ptr++ = ((i+2)<frag_length)?code_virtual_address[i+1]:0;
*seg_ptr++ = ((i+3)<frag_length)?code_virtual_address[i+0]:0;
}
skb_put(skb, i);
priv->ieee80211->softmac_hard_start_xmit(skb, priv->ieee80211);
code_virtual_address += frag_length;
frag_offset += frag_length;
}while(frag_offset < buffer_len);
Failed:
return rt_status;
}
static void cmpk_count_txstatistic(struct r8192_priv *priv, cmpk_txfb_t *pstx_fb)
{
#ifdef ENABLE_PS
RT_RF_POWER_STATE rtState;
pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
// When RF is off, we should not count the packet for hw/sw synchronize
// reason, ie. there may be a duration while sw switch is changed and hw
// switch is being changed. 2006.12.04, by shien chang.
if (rtState == eRfOff)
{
return;
}
#endif
#ifdef TODO
if(pAdapter->bInHctTest)
return;
#endif
/* We can not know the packet length and transmit type: broadcast or uni
or multicast. So the relative statistics must be collected in tx
feedback info. */
if (pstx_fb->tok)
{
priv->stats.txoktotal++;
/* We can not make sure broadcast/multicast or unicast mode. */
if (pstx_fb->pkt_type != PACKET_MULTICAST &&
pstx_fb->pkt_type != PACKET_BROADCAST) {
priv->stats.txbytesunicast += pstx_fb->pkt_length;
}
}
}
/*
* The function is responsible for extract the message inside TX
* feedbck message from firmware. It will contain dedicated info in
* ws-06-0063-rtl8190-command-packet-specification. Please
* refer to chapter "TX Feedback Element". We have to read 20 bytes
* in the command packet.
*/
static void cmpk_handle_tx_feedback(struct r8192_priv *priv, u8 *pmsg)
{
cmpk_txfb_t rx_tx_fb; /* */
priv->stats.txfeedback++;
memcpy((u8*)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
/* Use tx feedback info to count TX statistics. */
cmpk_count_txstatistic(priv, &rx_tx_fb);
}
/*
* The function is responsible for extract the message from
* firmware. It will contain dedicated info in
* ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
* Please refer to chapter "Interrupt Status Element".
*/
static void cmpk_handle_interrupt_status(struct r8192_priv *priv, u8 *pmsg)
{
cmpk_intr_sta_t rx_intr_status; /* */
DMESG("---> cmpk_Handle_Interrupt_Status()\n");
/* 1. Extract TX feedback info from RFD to temp structure buffer. */
/* It seems that FW use big endian(MIPS) and DRV use little endian in
windows OS. So we have to read the content byte by byte or transfer
endian type before copy the message copy. */
//rx_bcn_state.Element_ID = pMsg[0];
//rx_bcn_state.Length = pMsg[1];
rx_intr_status.length = pmsg[1];
if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
{
DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
return;
}
// Statistics of beacon for ad-hoc mode.
if( priv->ieee80211->iw_mode == IW_MODE_ADHOC)
{
//2 maybe need endian transform?
rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
//rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
{
priv->ieee80211->bibsscoordinator = true;
priv->stats.txbeaconokint++;
}
else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
{
priv->ieee80211->bibsscoordinator = false;
priv->stats.txbeaconerr++;
}
}
// Other informations in interrupt status we need?
DMESG("<---- cmpk_handle_interrupt_status()\n");
}
/*
* The function is responsible for extract the message from
* firmware. It will contain dedicated info in
* ws-06-0063-rtl8190-command-packet-specification. Please
* refer to chapter "Beacon State Element".
*/
static void cmpk_handle_query_config_rx(struct r8192_priv *priv, u8 *pmsg)
{
cmpk_query_cfg_t rx_query_cfg; /* */
/* 0. Display received message. */
//cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
/* 1. Extract TX feedback info from RFD to temp structure buffer. */
/* It seems that FW use big endian(MIPS) and DRV use little endian in
windows OS. So we have to read the content byte by byte or transfer
endian type before copy the message copy. */
//rx_query_cfg.Element_ID = pMsg[0];
//rx_query_cfg.Length = pMsg[1];
rx_query_cfg.cfg_action = (pmsg[4] & 0x80000000)>>31;
rx_query_cfg.cfg_type = (pmsg[4] & 0x60) >> 5;
rx_query_cfg.cfg_size = (pmsg[4] & 0x18) >> 3;
rx_query_cfg.cfg_page = (pmsg[6] & 0x0F) >> 0;
rx_query_cfg.cfg_offset = pmsg[7];
rx_query_cfg.value = (pmsg[8] << 24) | (pmsg[9] << 16) |
(pmsg[10] << 8) | (pmsg[11] << 0);
rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
(pmsg[14] << 8) | (pmsg[15] << 0);
}
/*
* Count aggregated tx status from firmwar of one type rx command
* packet element id = RX_TX_STATUS.
*/
static void cmpk_count_tx_status(struct r8192_priv *priv, cmpk_tx_status_t *pstx_status)
{
#ifdef ENABLE_PS
RT_RF_POWER_STATE rtstate;
pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
// When RF is off, we should not count the packet for hw/sw synchronize
// reason, ie. there may be a duration while sw switch is changed and hw
// switch is being changed. 2006.12.04, by shien chang.
if (rtState == eRfOff)
{
return;
}
#endif
priv->stats.txfeedbackok += pstx_status->txok;
priv->stats.txoktotal += pstx_status->txok;
priv->stats.txbytesunicast += pstx_status->txuclength;
}
/*
* Firmware add a new tx feedback status to reduce rx command
* packet buffer operation load.
*/
static void cmpk_handle_tx_status(struct r8192_priv *priv, u8 *pmsg)
{
cmpk_tx_status_t rx_tx_sts; /* */
memcpy((void*)&rx_tx_sts, (void*)pmsg, sizeof(cmpk_tx_status_t));
/* 2. Use tx feedback info to count TX statistics. */
cmpk_count_tx_status(priv, &rx_tx_sts);
}
/* Firmware add a new tx rate history */
static void cmpk_handle_tx_rate_history(struct r8192_priv *priv, u8 *pmsg)
{
u8 i;
u16 length = sizeof(cmpk_tx_rahis_t);
u32 *ptemp;
#ifdef ENABLE_PS
pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
// When RF is off, we should not count the packet for hw/sw synchronize
// reason, ie. there may be a duration while sw switch is changed and hw
// switch is being changed. 2006.12.04, by shien chang.
if (rtState == eRfOff)
{
return;
}
#endif
ptemp = (u32 *)pmsg;
//
// Do endian transfer to word alignment(16 bits) for windows system.
// You must do different endian transfer for linux and MAC OS
//
for (i = 0; i < (length/4); i++)
{
u16 temp1, temp2;
temp1 = ptemp[i]&0x0000FFFF;
temp2 = ptemp[i]>>16;
ptemp[i] = (temp1<<16)|temp2;
}
}
/*
* In the function, we will capture different RX command packet
* info. Every RX command packet element has different message
* length and meaning in content. We only support three type of RX
* command packet now. Please refer to document
* ws-06-0063-rtl8190-command-packet-specification.
*/
u32 cmpk_message_handle_rx(struct r8192_priv *priv, struct ieee80211_rx_stats *pstats)
{
// u32 debug_level = DBG_LOUD;
int total_length;
u8 cmd_length, exe_cnt = 0;
u8 element_id;
u8 *pcmd_buff;
RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx()\n");
/* 0. Check inpt arguments. If is is a command queue message or pointer is
null. */
if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
{
/* Print error message. */
/*RT_TRACE(COMP_SEND, DebugLevel,
("\n\r[CMPK]-->Err queue id or pointer"));*/
return 0; /* This is not a command packet. */
}
/* 1. Read received command packet message length from RFD. */
total_length = pstats->Length;
/* 2. Read virtual address from RFD. */
pcmd_buff = pstats->virtual_address;
/* 3. Read command pakcet element id and length. */
element_id = pcmd_buff[0];
/*RT_TRACE(COMP_SEND, DebugLevel,
("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
/* 4. Check every received command packet conent according to different
element type. Because FW may aggregate RX command packet to minimize
transmit time between DRV and FW.*/
// Add a counter to prevent to locked in the loop too long
while (total_length > 0 || exe_cnt++ >100)
{
/* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
element_id = pcmd_buff[0];
switch(element_id)
{
case RX_TX_FEEDBACK:
RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_FEEDBACK\n");
cmpk_handle_tx_feedback(priv, pcmd_buff);
cmd_length = CMPK_RX_TX_FB_SIZE;
break;
case RX_INTERRUPT_STATUS:
RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_INTERRUPT_STATUS\n");
cmpk_handle_interrupt_status(priv, pcmd_buff);
cmd_length = sizeof(cmpk_intr_sta_t);
break;
case BOTH_QUERY_CONFIG:
RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():BOTH_QUERY_CONFIG\n");
cmpk_handle_query_config_rx(priv, pcmd_buff);
cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
break;
case RX_TX_STATUS:
RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_STATUS\n");
cmpk_handle_tx_status(priv, pcmd_buff);
cmd_length = CMPK_RX_TX_STS_SIZE;
break;
case RX_TX_PER_PKT_FEEDBACK:
// You must at lease add a switch case element here,
// Otherwise, we will jump to default case.
//DbgPrint("CCX Test\r\n");
RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_PER_PKT_FEEDBACK\n");
cmd_length = CMPK_RX_TX_FB_SIZE;
break;
case RX_TX_RATE_HISTORY:
//DbgPrint(" rx tx rate history\r\n");
RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():RX_TX_HISTORY\n");
cmpk_handle_tx_rate_history(priv, pcmd_buff);
cmd_length = CMPK_TX_RAHIS_SIZE;
break;
default:
RT_TRACE(COMP_EVENTS, "---->cmpk_message_handle_rx():unknown CMD Element\n");
return 1; /* This is a command packet. */
}
total_length -= cmd_length;
pcmd_buff += cmd_length;
} /* while (total_length > 0) */
return 1; /* This is a command packet. */
RT_TRACE(COMP_EVENTS, "<----cmpk_message_handle_rx()\n");
}
#ifndef R819XUSB_CMDPKT_H
#define R819XUSB_CMDPKT_H
/* Different command packet have dedicated message length and definition. */
#define CMPK_RX_TX_FB_SIZE sizeof(cmpk_txfb_t) //20
#define CMPK_TX_SET_CONFIG_SIZE sizeof(cmpk_set_cfg_t) //16
#define CMPK_BOTH_QUERY_CONFIG_SIZE sizeof(cmpk_set_cfg_t) //16
#define CMPK_RX_TX_STS_SIZE sizeof(cmpk_tx_status_t)//
#define CMPK_RX_DBG_MSG_SIZE sizeof(cmpk_rx_dbginfo_t)//
#define CMPK_TX_RAHIS_SIZE sizeof(cmpk_tx_rahis_t)
/* 2008/05/08 amy For USB constant. */
#define ISR_TxBcnOk BIT27 // Transmit Beacon OK
#define ISR_TxBcnErr BIT26 // Transmit Beacon Error
#define ISR_BcnTimerIntr BIT13 // Beacon Timer Interrupt
#if 0
/* Define packet type. */
typedef enum tag_packet_type
{
PACKET_BROADCAST,
PACKET_MULTICAST,
PACKET_UNICAST,
PACKET_TYPE_MAX
}cmpk_pkt_type_e;
#endif
/* Define element ID of command packet. */
/*------------------------------Define structure----------------------------*/
/* Define different command packet structure. */
/* 1. RX side: TX feedback packet. */
typedef struct tag_cmd_pkt_tx_feedback
{
// DWORD 0
u8 element_id; /* Command packet type. */
u8 length; /* Command packet length. */
/* 2007/07/05 MH Change tx feedback info field. */
/*------TX Feedback Info Field */
u8 TID:4; /* */
u8 fail_reason:3; /* */
u8 tok:1; /* Transmit ok. */
u8 reserve1:4; /* */
u8 pkt_type:2; /* */
u8 bandwidth:1; /* */
u8 qos_pkt:1; /* */
// DWORD 1
u8 reserve2; /* */
/*------TX Feedback Info Field */
u8 retry_cnt; /* */
u16 pkt_id; /* */
// DWORD 3
u16 seq_num; /* */
u8 s_rate; /* Start rate. */
u8 f_rate; /* Final rate. */
// DWORD 4
u8 s_rts_rate; /* */
u8 f_rts_rate; /* */
u16 pkt_length; /* */
// DWORD 5
u16 reserve3; /* */
u16 duration; /* */
}cmpk_txfb_t;
/* 2. RX side: Interrupt status packet. It includes Beacon State,
Beacon Timer Interrupt and other useful informations in MAC ISR Reg. */
typedef struct tag_cmd_pkt_interrupt_status
{
u8 element_id; /* Command packet type. */
u8 length; /* Command packet length. */
u16 reserve;
u32 interrupt_status; /* Interrupt Status. */
}cmpk_intr_sta_t;
/* 3. TX side: Set configuration packet. */
typedef struct tag_cmd_pkt_set_configuration
{
u8 element_id; /* Command packet type. */
u8 length; /* Command packet length. */
u16 reserve1; /* */
u8 cfg_reserve1:3;
u8 cfg_size:2; /* Configuration info. */
u8 cfg_type:2; /* Configuration info. */
u8 cfg_action:1; /* Configuration info. */
u8 cfg_reserve2; /* Configuration info. */
u8 cfg_page:4; /* Configuration info. */
u8 cfg_reserve3:4; /* Configuration info. */
u8 cfg_offset; /* Configuration info. */
u32 value; /* */
u32 mask; /* */
}cmpk_set_cfg_t;
/* 4. Both side : TX/RX query configuraton packet. The query structure is the
same as set configuration. */
#define cmpk_query_cfg_t cmpk_set_cfg_t
/* 5. Multi packet feedback status. */
typedef struct tag_tx_stats_feedback // PJ quick rxcmd 09042007
{
// For endian transfer --> Driver will not the same as firmware structure.
// DW 0
u16 reserve1;
u8 length; // Command packet length
u8 element_id; // Command packet type
// DW 1
u16 txfail; // Tx Fail count
u16 txok; // Tx ok count
// DW 2
u16 txmcok; // tx multicast
u16 txretry; // Tx Retry count
// DW 3
u16 txucok; // tx unicast
u16 txbcok; // tx broadcast
// DW 4
u16 txbcfail; //
u16 txmcfail; //
// DW 5
u16 reserve2; //
u16 txucfail; //
// DW 6-8
u32 txmclength;
u32 txbclength;
u32 txuclength;
// DW 9
u16 reserve3_23;
u8 reserve3_1;
u8 rate;
}__attribute__((packed)) cmpk_tx_status_t;
/* 6. Debug feedback message. */
/* 2007/10/23 MH Define RX debug message */
typedef struct tag_rx_debug_message_feedback
{
// For endian transfer --> for driver
// DW 0
u16 reserve1;
u8 length; // Command packet length
u8 element_id; // Command packet type
// DW 1-??
// Variable debug message.
}cmpk_rx_dbginfo_t;
/* 2008/03/20 MH Define transmit rate history. For big endian format. */
typedef struct tag_tx_rate_history
{
// For endian transfer --> for driver
// DW 0
u8 element_id; // Command packet type
u8 length; // Command packet length
u16 reserved1;
// DW 1-2 CCK rate counter
u16 cck[4];
// DW 3-6
u16 ofdm[8];
// DW 7-14
//UINT16 MCS_BW0_SG0[16];
// DW 15-22
//UINT16 MCS_BW1_SG0[16];
// DW 23-30
//UINT16 MCS_BW0_SG1[16];
// DW 31-38
//UINT16 MCS_BW1_SG1[16];
// DW 7-14 BW=0 SG=0
// DW 15-22 BW=1 SG=0
// DW 23-30 BW=0 SG=1
// DW 31-38 BW=1 SG=1
u16 ht_mcs[4][16];
}__attribute__((packed)) cmpk_tx_rahis_t;
typedef enum tag_command_packet_directories
{
RX_TX_FEEDBACK = 0,
RX_INTERRUPT_STATUS = 1,
TX_SET_CONFIG = 2,
BOTH_QUERY_CONFIG = 3,
RX_TX_STATUS = 4,
RX_DBGINFO_FEEDBACK = 5,
RX_TX_PER_PKT_FEEDBACK = 6,
RX_TX_RATE_HISTORY = 7,
RX_CMD_ELE_MAX
}cmpk_element_e;
u32 cmpk_message_handle_rx(struct r8192_priv *priv, struct ieee80211_rx_stats *pstats);
#endif
/*
* Procedure: Init boot code/firmware code/data session
*
* Description: This routine will initialize firmware. If any error occurs
* during the initialization process, the routine shall terminate
* immediately and return fail.
*/
#include "r8192E.h"
#include "r8192E_hw.h"
#include <linux/firmware.h>
/* It should be double word alignment */
#define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4 * (v / 4) - 8)
enum firmware_init_step {
FW_INIT_STEP0_BOOT = 0,
FW_INIT_STEP1_MAIN = 1,
FW_INIT_STEP2_DATA = 2,
};
enum opt_rst_type {
OPT_SYSTEM_RESET = 0,
OPT_FIRMWARE_RESET = 1,
};
void firmware_init_param(struct r8192_priv *priv)
{
rt_firmware *pfirmware = priv->pFirmware;
pfirmware->cmdpacket_frag_thresold =
GET_COMMAND_PACKET_FRAG_THRESHOLD(MAX_TRANSMIT_BUFFER_SIZE);
}
/*
* segment the img and use the ptr and length to remember info on each segment
*/
static bool fw_download_code(struct r8192_priv *priv, u8 *code_virtual_address,
u32 buffer_len)
{
bool rt_status = true;
u16 frag_threshold;
u16 frag_length, frag_offset = 0;
int i;
rt_firmware *pfirmware = priv->pFirmware;
struct sk_buff *skb;
unsigned char *seg_ptr;
cb_desc *tcb_desc;
u8 bLastIniPkt;
firmware_init_param(priv);
/* Fragmentation might be required */
frag_threshold = pfirmware->cmdpacket_frag_thresold;
do {
if ((buffer_len - frag_offset) > frag_threshold) {
frag_length = frag_threshold ;
bLastIniPkt = 0;
} else {
frag_length = buffer_len - frag_offset;
bLastIniPkt = 1;
}
/*
* Allocate skb buffer to contain firmware info and tx
* descriptor info add 4 to avoid packet appending overflow.
*/
skb = dev_alloc_skb(frag_length + 4);
tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
tcb_desc->queue_index = TXCMD_QUEUE;
tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT;
tcb_desc->bLastIniPkt = bLastIniPkt;
seg_ptr = skb->data;
/*
* Transform from little endian to big endian and pending zero
*/
for (i = 0; i < frag_length; i += 4) {
*seg_ptr++ = ((i+0) < frag_length) ?
code_virtual_address[i+3] : 0;
*seg_ptr++ = ((i+1) < frag_length) ?
code_virtual_address[i+2] : 0;
*seg_ptr++ = ((i+2) < frag_length) ?
code_virtual_address[i+1] : 0;
*seg_ptr++ = ((i+3) < frag_length) ?
code_virtual_address[i+0] : 0;
}
tcb_desc->txbuf_size = (u16)i;
skb_put(skb, i);
priv->ieee80211->softmac_hard_start_xmit(skb, priv->ieee80211);
code_virtual_address += frag_length;
frag_offset += frag_length;
} while (frag_offset < buffer_len);
return rt_status;
}
/*
* Check whether main code is download OK. If OK, turn on CPU
*
* CPU register locates in different page against general
* register. Switch to CPU register in the begin and switch
* back before return
*/
static bool CPUcheck_maincodeok_turnonCPU(struct r8192_priv *priv)
{
unsigned long timeout;
bool rt_status = true;
u32 CPU_status = 0;
/* Check whether put code OK */
timeout = jiffies + msecs_to_jiffies(20);
while (time_before(jiffies, timeout)) {
CPU_status = read_nic_dword(priv, CPU_GEN);
if (CPU_status & CPU_GEN_PUT_CODE_OK)
break;
msleep(2);
}
if (!(CPU_status & CPU_GEN_PUT_CODE_OK)) {
RT_TRACE(COMP_ERR, "Download Firmware: Put code fail!\n");
goto CPUCheckMainCodeOKAndTurnOnCPU_Fail;
} else {
RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n");
}
/* Turn On CPU */
CPU_status = read_nic_dword(priv, CPU_GEN);
write_nic_byte(priv, CPU_GEN,
(u8)((CPU_status | CPU_GEN_PWR_STB_CPU) & 0xff));
mdelay(1);
/* Check whether CPU boot OK */
timeout = jiffies + msecs_to_jiffies(20);
while (time_before(jiffies, timeout)) {
CPU_status = read_nic_dword(priv, CPU_GEN);
if (CPU_status & CPU_GEN_BOOT_RDY)
break;
msleep(2);
}
if (!(CPU_status & CPU_GEN_BOOT_RDY))
goto CPUCheckMainCodeOKAndTurnOnCPU_Fail;
else
RT_TRACE(COMP_FIRMWARE, "Download Firmware: Boot ready!\n");
return rt_status;
CPUCheckMainCodeOKAndTurnOnCPU_Fail:
RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__);
rt_status = FALSE;
return rt_status;
}
static bool CPUcheck_firmware_ready(struct r8192_priv *priv)
{
unsigned long timeout;
bool rt_status = true;
u32 CPU_status = 0;
/* Check Firmware Ready */
timeout = jiffies + msecs_to_jiffies(20);
while (time_before(jiffies, timeout)) {
CPU_status = read_nic_dword(priv, CPU_GEN);
if (CPU_status & CPU_GEN_FIRM_RDY)
break;
msleep(2);
}
if (!(CPU_status & CPU_GEN_FIRM_RDY))
goto CPUCheckFirmwareReady_Fail;
else
RT_TRACE(COMP_FIRMWARE, "Download Firmware: Firmware ready!\n");
return rt_status;
CPUCheckFirmwareReady_Fail:
RT_TRACE(COMP_ERR, "ERR in %s()\n", __func__);
rt_status = false;
return rt_status;
}
bool init_firmware(struct r8192_priv *priv)
{
bool rt_status = true;
u32 file_length = 0;
u8 *mapped_file = NULL;
u32 init_step = 0;
enum opt_rst_type rst_opt = OPT_SYSTEM_RESET;
enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT;
rt_firmware *pfirmware = priv->pFirmware;
const struct firmware *fw_entry;
const char *fw_name[3] = { "RTL8192E/boot.img",
"RTL8192E/main.img",
"RTL8192E/data.img"};
int rc;
RT_TRACE(COMP_FIRMWARE, " PlatformInitFirmware()==>\n");
if (pfirmware->firmware_status == FW_STATUS_0_INIT) {
/* it is called by reset */
rst_opt = OPT_SYSTEM_RESET;
starting_state = FW_INIT_STEP0_BOOT;
/* TODO: system reset */
} else if (pfirmware->firmware_status == FW_STATUS_5_READY) {
/* it is called by Initialize */
rst_opt = OPT_FIRMWARE_RESET;
starting_state = FW_INIT_STEP2_DATA;
} else {
RT_TRACE(COMP_FIRMWARE,
"PlatformInitFirmware: undefined firmware state\n");
}
/*
* Download boot, main, and data image for System reset.
* Download data image for firmware reseta
*/
for (init_step = starting_state; init_step <= FW_INIT_STEP2_DATA;
init_step++) {
/*
* Open Image file, and map file to contineous memory if open file success.
* or read image file from array. Default load from IMG file
*/
if (rst_opt == OPT_SYSTEM_RESET) {
if (pfirmware->firmware_buf_size[init_step] == 0) {
rc = request_firmware(&fw_entry,
fw_name[init_step], &priv->pdev->dev);
if (rc < 0) {
RT_TRACE(COMP_FIRMWARE, "request firmware fail!\n");
goto download_firmware_fail;
}
if (fw_entry->size > sizeof(pfirmware->firmware_buf[init_step])) {
RT_TRACE(COMP_FIRMWARE,
"img file size exceed the container buffer fail!\n");
goto download_firmware_fail;
}
if (init_step != FW_INIT_STEP1_MAIN) {
memcpy(pfirmware->firmware_buf[init_step],
fw_entry->data, fw_entry->size);
pfirmware->firmware_buf_size[init_step] = fw_entry->size;
} else {
memset(pfirmware->firmware_buf[init_step], 0, 128);
memcpy(&pfirmware->firmware_buf[init_step][128], fw_entry->data,
fw_entry->size);
pfirmware->firmware_buf_size[init_step] = fw_entry->size+128;
}
if (rst_opt == OPT_SYSTEM_RESET)
release_firmware(fw_entry);
}
mapped_file = pfirmware->firmware_buf[init_step];
file_length = pfirmware->firmware_buf_size[init_step];
} else if (rst_opt == OPT_FIRMWARE_RESET) {
/* we only need to download data.img here */
mapped_file = pfirmware->firmware_buf[init_step];
file_length = pfirmware->firmware_buf_size[init_step];
}
/* Download image file */
/* The firmware download process is just as following,
* 1. that is each packet will be segmented and inserted to the
* wait queue.
* 2. each packet segment will be put in the skb_buff packet.
* 3. each skb_buff packet data content will already include
* the firmware info and Tx descriptor info
*/
rt_status = fw_download_code(priv, mapped_file, file_length);
if (rt_status != TRUE)
goto download_firmware_fail;
switch (init_step) {
case FW_INIT_STEP0_BOOT:
/* Download boot
* initialize command descriptor.
* will set polling bit when firmware code is also
* configured
*/
pfirmware->firmware_status = FW_STATUS_1_MOVE_BOOT_CODE;
/* mdelay(1000); */
/*
* To initialize IMEM, CPU move code from 0x80000080,
* hence, we send 0x80 byte packet
*/
break;
case FW_INIT_STEP1_MAIN:
/* Download firmware code.
* Wait until Boot Ready and Turn on CPU */
pfirmware->firmware_status = FW_STATUS_2_MOVE_MAIN_CODE;
/* Check Put Code OK and Turn On CPU */
rt_status = CPUcheck_maincodeok_turnonCPU(priv);
if (rt_status != TRUE) {
RT_TRACE(COMP_FIRMWARE,
"CPUcheck_maincodeok_turnonCPU fail!\n");
goto download_firmware_fail;
}
pfirmware->firmware_status = FW_STATUS_3_TURNON_CPU;
break;
case FW_INIT_STEP2_DATA:
/* download initial data code */
pfirmware->firmware_status = FW_STATUS_4_MOVE_DATA_CODE;
mdelay(1);
rt_status = CPUcheck_firmware_ready(priv);
if (rt_status != TRUE) {
RT_TRACE(COMP_FIRMWARE,
"CPUcheck_firmware_ready fail(%d)!\n",
rt_status);
goto download_firmware_fail;
}
/* wait until data code is initialized ready.*/
pfirmware->firmware_status = FW_STATUS_5_READY;
break;
}
}
RT_TRACE(COMP_FIRMWARE, "Firmware Download Success\n");
return rt_status;
download_firmware_fail:
RT_TRACE(COMP_ERR, "ERR in %s() step %d\n", __func__, init_step);
rt_status = false;
return rt_status;
}
MODULE_FIRMWARE("RTL8192E/boot.img");
MODULE_FIRMWARE("RTL8192E/main.img");
MODULE_FIRMWARE("RTL8192E/data.img");
#include "r8192E.h"
#include "r8192E_hw.h"
#include "r819xE_phyreg.h"
#include "r8190_rtl8256.h"
#include "r819xE_phy.h"
#include "r8192E_dm.h"
#ifdef ENABLE_DOT11D
#include "ieee80211/dot11d.h"
#endif
static const u32 RF_CHANNEL_TABLE_ZEBRA[] = {
0,
0x085c, //2412 1
0x08dc, //2417 2
0x095c, //2422 3
0x09dc, //2427 4
0x0a5c, //2432 5
0x0adc, //2437 6
0x0b5c, //2442 7
0x0bdc, //2447 8
0x0c5c, //2452 9
0x0cdc, //2457 10
0x0d5c, //2462 11
0x0ddc, //2467 12
0x0e5c, //2472 13
0x0f72, //2484
};
static u32 Rtl8192PciEMACPHY_Array[] = {
0x03c,0xffff0000,0x00000f0f,
0x340,0xffffffff,0x161a1a1a,
0x344,0xffffffff,0x12121416,
0x348,0x0000ffff,0x00001818,
0x12c,0xffffffff,0x04000802,
0x318,0x00000fff,0x00000100,
};
static u32 Rtl8192PciEMACPHY_Array_PG[] = {
0x03c,0xffff0000,0x00000f0f,
0xe00,0xffffffff,0x06090909,
0xe04,0xffffffff,0x00030306,
0xe08,0x0000ff00,0x00000000,
0xe10,0xffffffff,0x0a0c0d0f,
0xe14,0xffffffff,0x06070809,
0xe18,0xffffffff,0x0a0c0d0f,
0xe1c,0xffffffff,0x06070809,
0x12c,0xffffffff,0x04000802,
0x318,0x00000fff,0x00000800,
};
static u32 Rtl8192PciEAGCTAB_Array[AGCTAB_ArrayLength] = {
0xc78,0x7d000001,
0xc78,0x7d010001,
0xc78,0x7d020001,
0xc78,0x7d030001,
0xc78,0x7d040001,
0xc78,0x7d050001,
0xc78,0x7c060001,
0xc78,0x7b070001,
0xc78,0x7a080001,
0xc78,0x79090001,
0xc78,0x780a0001,
0xc78,0x770b0001,
0xc78,0x760c0001,
0xc78,0x750d0001,
0xc78,0x740e0001,
0xc78,0x730f0001,
0xc78,0x72100001,
0xc78,0x71110001,
0xc78,0x70120001,
0xc78,0x6f130001,
0xc78,0x6e140001,
0xc78,0x6d150001,
0xc78,0x6c160001,
0xc78,0x6b170001,
0xc78,0x6a180001,
0xc78,0x69190001,
0xc78,0x681a0001,
0xc78,0x671b0001,
0xc78,0x661c0001,
0xc78,0x651d0001,
0xc78,0x641e0001,
0xc78,0x491f0001,
0xc78,0x48200001,
0xc78,0x47210001,
0xc78,0x46220001,
0xc78,0x45230001,
0xc78,0x44240001,
0xc78,0x43250001,
0xc78,0x28260001,
0xc78,0x27270001,
0xc78,0x26280001,
0xc78,0x25290001,
0xc78,0x242a0001,
0xc78,0x232b0001,
0xc78,0x222c0001,
0xc78,0x212d0001,
0xc78,0x202e0001,
0xc78,0x0a2f0001,
0xc78,0x08300001,
0xc78,0x06310001,
0xc78,0x05320001,
0xc78,0x04330001,
0xc78,0x03340001,
0xc78,0x02350001,
0xc78,0x01360001,
0xc78,0x00370001,
0xc78,0x00380001,
0xc78,0x00390001,
0xc78,0x003a0001,
0xc78,0x003b0001,
0xc78,0x003c0001,
0xc78,0x003d0001,
0xc78,0x003e0001,
0xc78,0x003f0001,
0xc78,0x7d400001,
0xc78,0x7d410001,
0xc78,0x7d420001,
0xc78,0x7d430001,
0xc78,0x7d440001,
0xc78,0x7d450001,
0xc78,0x7c460001,
0xc78,0x7b470001,
0xc78,0x7a480001,
0xc78,0x79490001,
0xc78,0x784a0001,
0xc78,0x774b0001,
0xc78,0x764c0001,
0xc78,0x754d0001,
0xc78,0x744e0001,
0xc78,0x734f0001,
0xc78,0x72500001,
0xc78,0x71510001,
0xc78,0x70520001,
0xc78,0x6f530001,
0xc78,0x6e540001,
0xc78,0x6d550001,
0xc78,0x6c560001,
0xc78,0x6b570001,
0xc78,0x6a580001,
0xc78,0x69590001,
0xc78,0x685a0001,
0xc78,0x675b0001,
0xc78,0x665c0001,
0xc78,0x655d0001,
0xc78,0x645e0001,
0xc78,0x495f0001,
0xc78,0x48600001,
0xc78,0x47610001,
0xc78,0x46620001,
0xc78,0x45630001,
0xc78,0x44640001,
0xc78,0x43650001,
0xc78,0x28660001,
0xc78,0x27670001,
0xc78,0x26680001,
0xc78,0x25690001,
0xc78,0x246a0001,
0xc78,0x236b0001,
0xc78,0x226c0001,
0xc78,0x216d0001,
0xc78,0x206e0001,
0xc78,0x0a6f0001,
0xc78,0x08700001,
0xc78,0x06710001,
0xc78,0x05720001,
0xc78,0x04730001,
0xc78,0x03740001,
0xc78,0x02750001,
0xc78,0x01760001,
0xc78,0x00770001,
0xc78,0x00780001,
0xc78,0x00790001,
0xc78,0x007a0001,
0xc78,0x007b0001,
0xc78,0x007c0001,
0xc78,0x007d0001,
0xc78,0x007e0001,
0xc78,0x007f0001,
0xc78,0x2e00001e,
0xc78,0x2e01001e,
0xc78,0x2e02001e,
0xc78,0x2e03001e,
0xc78,0x2e04001e,
0xc78,0x2e05001e,
0xc78,0x3006001e,
0xc78,0x3407001e,
0xc78,0x3908001e,
0xc78,0x3c09001e,
0xc78,0x3f0a001e,
0xc78,0x420b001e,
0xc78,0x440c001e,
0xc78,0x450d001e,
0xc78,0x460e001e,
0xc78,0x460f001e,
0xc78,0x4710001e,
0xc78,0x4811001e,
0xc78,0x4912001e,
0xc78,0x4a13001e,
0xc78,0x4b14001e,
0xc78,0x4b15001e,
0xc78,0x4c16001e,
0xc78,0x4d17001e,
0xc78,0x4e18001e,
0xc78,0x4f19001e,
0xc78,0x4f1a001e,
0xc78,0x501b001e,
0xc78,0x511c001e,
0xc78,0x521d001e,
0xc78,0x521e001e,
0xc78,0x531f001e,
0xc78,0x5320001e,
0xc78,0x5421001e,
0xc78,0x5522001e,
0xc78,0x5523001e,
0xc78,0x5624001e,
0xc78,0x5725001e,
0xc78,0x5726001e,
0xc78,0x5827001e,
0xc78,0x5828001e,
0xc78,0x5929001e,
0xc78,0x592a001e,
0xc78,0x5a2b001e,
0xc78,0x5b2c001e,
0xc78,0x5c2d001e,
0xc78,0x5c2e001e,
0xc78,0x5d2f001e,
0xc78,0x5e30001e,
0xc78,0x5f31001e,
0xc78,0x6032001e,
0xc78,0x6033001e,
0xc78,0x6134001e,
0xc78,0x6235001e,
0xc78,0x6336001e,
0xc78,0x6437001e,
0xc78,0x6438001e,
0xc78,0x6539001e,
0xc78,0x663a001e,
0xc78,0x673b001e,
0xc78,0x673c001e,
0xc78,0x683d001e,
0xc78,0x693e001e,
0xc78,0x6a3f001e,
};
static u32 Rtl8192PciEPHY_REGArray[PHY_REGArrayLength] = {
0x0, };
static u32 Rtl8192PciEPHY_REG_1T2RArray[PHY_REG_1T2RArrayLength] = {
0x800,0x00000000,
0x804,0x00000001,
0x808,0x0000fc00,
0x80c,0x0000001c,
0x810,0x801010aa,
0x814,0x008514d0,
0x818,0x00000040,
0x81c,0x00000000,
0x820,0x00000004,
0x824,0x00690000,
0x828,0x00000004,
0x82c,0x00e90000,
0x830,0x00000004,
0x834,0x00690000,
0x838,0x00000004,
0x83c,0x00e90000,
0x840,0x00000000,
0x844,0x00000000,
0x848,0x00000000,
0x84c,0x00000000,
0x850,0x00000000,
0x854,0x00000000,
0x858,0x65a965a9,
0x85c,0x65a965a9,
0x860,0x001f0010,
0x864,0x007f0010,
0x868,0x001f0010,
0x86c,0x007f0010,
0x870,0x0f100f70,
0x874,0x0f100f70,
0x878,0x00000000,
0x87c,0x00000000,
0x880,0x6870e36c,
0x884,0xe3573600,
0x888,0x4260c340,
0x88c,0x0000ff00,
0x890,0x00000000,
0x894,0xfffffffe,
0x898,0x4c42382f,
0x89c,0x00656056,
0x8b0,0x00000000,
0x8e0,0x00000000,
0x8e4,0x00000000,
0x900,0x00000000,
0x904,0x00000023,
0x908,0x00000000,
0x90c,0x31121311,
0xa00,0x00d0c7d8,
0xa04,0x811f0008,
0xa08,0x80cd8300,
0xa0c,0x2e62740f,
0xa10,0x95009b78,
0xa14,0x11145008,
0xa18,0x00881117,
0xa1c,0x89140fa0,
0xa20,0x1a1b0000,
0xa24,0x090e1317,
0xa28,0x00000204,
0xa2c,0x00000000,
0xc00,0x00000040,
0xc04,0x00005433,
0xc08,0x000000e4,
0xc0c,0x6c6c6c6c,
0xc10,0x08800000,
0xc14,0x40000100,
0xc18,0x08000000,
0xc1c,0x40000100,
0xc20,0x08000000,
0xc24,0x40000100,
0xc28,0x08000000,
0xc2c,0x40000100,
0xc30,0x6de9ac44,
0xc34,0x465c52cd,
0xc38,0x497f5994,
0xc3c,0x0a969764,
0xc40,0x1f7c403f,
0xc44,0x000100b7,
0xc48,0xec020000,
0xc4c,0x00000300,
0xc50,0x69543420,
0xc54,0x433c0094,
0xc58,0x69543420,
0xc5c,0x433c0094,
0xc60,0x69543420,
0xc64,0x433c0094,
0xc68,0x69543420,
0xc6c,0x433c0094,
0xc70,0x2c7f000d,
0xc74,0x0186175b,
0xc78,0x0000001f,
0xc7c,0x00b91612,
0xc80,0x40000100,
0xc84,0x20000000,
0xc88,0x40000100,
0xc8c,0x20200000,
0xc90,0x40000100,
0xc94,0x00000000,
0xc98,0x40000100,
0xc9c,0x00000000,
0xca0,0x00492492,
0xca4,0x00000000,
0xca8,0x00000000,
0xcac,0x00000000,
0xcb0,0x00000000,
0xcb4,0x00000000,
0xcb8,0x00000000,
0xcbc,0x00492492,
0xcc0,0x00000000,
0xcc4,0x00000000,
0xcc8,0x00000000,
0xccc,0x00000000,
0xcd0,0x00000000,
0xcd4,0x00000000,
0xcd8,0x64b22427,
0xcdc,0x00766932,
0xce0,0x00222222,
0xd00,0x00000750,
0xd04,0x00000403,
0xd08,0x0000907f,
0xd0c,0x00000001,
0xd10,0xa0633333,
0xd14,0x33333c63,
0xd18,0x6a8f5b6b,
0xd1c,0x00000000,
0xd20,0x00000000,
0xd24,0x00000000,
0xd28,0x00000000,
0xd2c,0xcc979975,
0xd30,0x00000000,
0xd34,0x00000000,
0xd38,0x00000000,
0xd3c,0x00027293,
0xd40,0x00000000,
0xd44,0x00000000,
0xd48,0x00000000,
0xd4c,0x00000000,
0xd50,0x6437140a,
0xd54,0x024dbd02,
0xd58,0x00000000,
0xd5c,0x04032064,
0xe00,0x161a1a1a,
0xe04,0x12121416,
0xe08,0x00001800,
0xe0c,0x00000000,
0xe10,0x161a1a1a,
0xe14,0x12121416,
0xe18,0x161a1a1a,
0xe1c,0x12121416,
};
static u32 Rtl8192PciERadioA_Array[RadioA_ArrayLength] = {
0x019,0x00000003,
0x000,0x000000bf,
0x001,0x00000ee0,
0x002,0x0000004c,
0x003,0x000007f1,
0x004,0x00000975,
0x005,0x00000c58,
0x006,0x00000ae6,
0x007,0x000000ca,
0x008,0x00000e1c,
0x009,0x000007f0,
0x00a,0x000009d0,
0x00b,0x000001ba,
0x00c,0x00000240,
0x00e,0x00000020,
0x00f,0x00000990,
0x012,0x00000806,
0x014,0x000005ab,
0x015,0x00000f80,
0x016,0x00000020,
0x017,0x00000597,
0x018,0x0000050a,
0x01a,0x00000f80,
0x01b,0x00000f5e,
0x01c,0x00000008,
0x01d,0x00000607,
0x01e,0x000006cc,
0x01f,0x00000000,
0x020,0x000001a5,
0x01f,0x00000001,
0x020,0x00000165,
0x01f,0x00000002,
0x020,0x000000c6,
0x01f,0x00000003,
0x020,0x00000086,
0x01f,0x00000004,
0x020,0x00000046,
0x01f,0x00000005,
0x020,0x000001e6,
0x01f,0x00000006,
0x020,0x000001a6,
0x01f,0x00000007,
0x020,0x00000166,
0x01f,0x00000008,
0x020,0x000000c7,
0x01f,0x00000009,
0x020,0x00000087,
0x01f,0x0000000a,
0x020,0x000000f7,
0x01f,0x0000000b,
0x020,0x000000d7,
0x01f,0x0000000c,
0x020,0x000000b7,
0x01f,0x0000000d,
0x020,0x00000097,
0x01f,0x0000000e,
0x020,0x00000077,
0x01f,0x0000000f,
0x020,0x00000057,
0x01f,0x00000010,
0x020,0x00000037,
0x01f,0x00000011,
0x020,0x000000fb,
0x01f,0x00000012,
0x020,0x000000db,
0x01f,0x00000013,
0x020,0x000000bb,
0x01f,0x00000014,
0x020,0x000000ff,
0x01f,0x00000015,
0x020,0x000000e3,
0x01f,0x00000016,
0x020,0x000000c3,
0x01f,0x00000017,
0x020,0x000000a3,
0x01f,0x00000018,
0x020,0x00000083,
0x01f,0x00000019,
0x020,0x00000063,
0x01f,0x0000001a,
0x020,0x00000043,
0x01f,0x0000001b,
0x020,0x00000023,
0x01f,0x0000001c,
0x020,0x00000003,
0x01f,0x0000001d,
0x020,0x000001e3,
0x01f,0x0000001e,
0x020,0x000001c3,
0x01f,0x0000001f,
0x020,0x000001a3,
0x01f,0x00000020,
0x020,0x00000183,
0x01f,0x00000021,
0x020,0x00000163,
0x01f,0x00000022,
0x020,0x00000143,
0x01f,0x00000023,
0x020,0x00000123,
0x01f,0x00000024,
0x020,0x00000103,
0x023,0x00000203,
0x024,0x00000100,
0x00b,0x000001ba,
0x02c,0x000003d7,
0x02d,0x00000ff0,
0x000,0x00000037,
0x004,0x00000160,
0x007,0x00000080,
0x002,0x0000088d,
0x0fe,0x00000000,
0x0fe,0x00000000,
0x016,0x00000200,
0x016,0x00000380,
0x016,0x00000020,
0x016,0x000001a0,
0x000,0x000000bf,
0x00d,0x0000001f,
0x00d,0x00000c9f,
0x002,0x0000004d,
0x000,0x00000cbf,
0x004,0x00000975,
0x007,0x00000700,
};
static u32 Rtl8192PciERadioB_Array[RadioB_ArrayLength] = {
0x019,0x00000003,
0x000,0x000000bf,
0x001,0x000006e0,
0x002,0x0000004c,
0x003,0x000007f1,
0x004,0x00000975,
0x005,0x00000c58,
0x006,0x00000ae6,
0x007,0x000000ca,
0x008,0x00000e1c,
0x000,0x000000b7,
0x00a,0x00000850,
0x000,0x000000bf,
0x00b,0x000001ba,
0x00c,0x00000240,
0x00e,0x00000020,
0x015,0x00000f80,
0x016,0x00000020,
0x017,0x00000597,
0x018,0x0000050a,
0x01a,0x00000e00,
0x01b,0x00000f5e,
0x01d,0x00000607,
0x01e,0x000006cc,
0x00b,0x000001ba,
0x023,0x00000203,
0x024,0x00000100,
0x000,0x00000037,
0x004,0x00000160,
0x016,0x00000200,
0x016,0x00000380,
0x016,0x00000020,
0x016,0x000001a0,
0x00d,0x00000ccc,
0x000,0x000000bf,
0x002,0x0000004d,
0x000,0x00000cbf,
0x004,0x00000975,
0x007,0x00000700,
};
static u32 Rtl8192PciERadioC_Array[RadioC_ArrayLength] = {
0x0, };
static u32 Rtl8192PciERadioD_Array[RadioD_ArrayLength] = {
0x0, };
/*************************Define local function prototype**********************/
static u32 phy_FwRFSerialRead(struct r8192_priv *priv, RF90_RADIO_PATH_E eRFPath, u32 Offset);
static void phy_FwRFSerialWrite(struct r8192_priv *priv, RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data);
/*************************Define local function prototype**********************/
/******************************************************************************
*function: This function read BB parameters from Header file we gen,
* and do register read/write
* input: u32 dwBitMask //taget bit pos in the addr to be modified
* output: none
* return: u32 return the shift bit bit position of the mask
* ****************************************************************************/
static u32 rtl8192_CalculateBitShift(u32 dwBitMask)
{
u32 i;
for (i=0; i<=31; i++)
{
if (((dwBitMask>>i)&0x1) == 1)
break;
}
return i;
}
/******************************************************************************
*function: This function check different RF type to execute legal judgement. If RF Path is illegal, we will return false.
* input: none
* output: none
* return: 0(illegal, false), 1(legal,true)
* ***************************************************************************/
u8 rtl8192_phy_CheckIsLegalRFPath(struct r8192_priv *priv, u32 eRFPath)
{
u8 ret = 1;
if (priv->rf_type == RF_2T4R)
ret = 0;
else if (priv->rf_type == RF_1T2R)
{
if (eRFPath == RF90_PATH_A || eRFPath == RF90_PATH_B)
ret = 1;
else if (eRFPath == RF90_PATH_C || eRFPath == RF90_PATH_D)
ret = 0;
}
return ret;
}
/******************************************************************************
*function: This function set specific bits to BB register
* input: net_device dev
* u32 dwRegAddr //target addr to be modified
* u32 dwBitMask //taget bit pos in the addr to be modified
* u32 dwData //value to be write
* output: none
* return: none
* notice:
* ****************************************************************************/
void rtl8192_setBBreg(struct r8192_priv *priv, u32 dwRegAddr, u32 dwBitMask, u32 dwData)
{
u32 OriginalValue, BitShift, NewValue;
if(dwBitMask!= bMaskDWord)
{//if not "double word" write
OriginalValue = read_nic_dword(priv, dwRegAddr);
BitShift = rtl8192_CalculateBitShift(dwBitMask);
NewValue = (((OriginalValue) & (~dwBitMask)) | (dwData << BitShift));
write_nic_dword(priv, dwRegAddr, NewValue);
}else
write_nic_dword(priv, dwRegAddr, dwData);
}
/******************************************************************************
*function: This function reads specific bits from BB register
* input: net_device dev
* u32 dwRegAddr //target addr to be readback
* u32 dwBitMask //taget bit pos in the addr to be readback
* output: none
* return: u32 Data //the readback register value
* notice:
* ****************************************************************************/
u32 rtl8192_QueryBBReg(struct r8192_priv *priv, u32 dwRegAddr, u32 dwBitMask)
{
u32 OriginalValue, BitShift;
OriginalValue = read_nic_dword(priv, dwRegAddr);
BitShift = rtl8192_CalculateBitShift(dwBitMask);
return (OriginalValue & dwBitMask) >> BitShift;
}
/******************************************************************************
*function: This function read register from RF chip
* input: net_device dev
* RF90_RADIO_PATH_E eRFPath //radio path of A/B/C/D
* u32 Offset //target address to be read
* output: none
* return: u32 readback value
* notice: There are three types of serial operations:(1) Software serial write.(2)Hardware LSSI-Low Speed Serial Interface.(3)Hardware HSSI-High speed serial write. Driver here need to implement (1) and (2)---need more spec for this information.
* ****************************************************************************/
static u32 rtl8192_phy_RFSerialRead(struct r8192_priv *priv,
RF90_RADIO_PATH_E eRFPath, u32 Offset)
{
u32 ret = 0;
u32 NewOffset = 0;
BB_REGISTER_DEFINITION_T* pPhyReg = &priv->PHYRegDef[eRFPath];
//rtl8192_setBBreg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData, 0);
//make sure RF register offset is correct
Offset &= 0x3f;
//switch page for 8256 RF IC
//analog to digital off, for protection
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8]
if (Offset >= 31)
{
priv->RfReg0Value[eRFPath] |= 0x140;
//Switch to Reg_Mode2 for Reg 31-45
rtl8192_setBBreg(priv, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath]<<16) );
//modify offset
NewOffset = Offset -30;
}
else if (Offset >= 16)
{
priv->RfReg0Value[eRFPath] |= 0x100;
priv->RfReg0Value[eRFPath] &= (~0x40);
//Switch to Reg_Mode 1 for Reg16-30
rtl8192_setBBreg(priv, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath]<<16) );
NewOffset = Offset - 15;
}
else
NewOffset = Offset;
//put desired read addr to LSSI control Register
rtl8192_setBBreg(priv, pPhyReg->rfHSSIPara2, bLSSIReadAddress, NewOffset);
//Issue a posedge trigger
//
rtl8192_setBBreg(priv, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x0);
rtl8192_setBBreg(priv, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1);
// TODO: we should not delay such a long time. Ask help from SD3
msleep(1);
ret = rtl8192_QueryBBReg(priv, pPhyReg->rfLSSIReadBack, bLSSIReadBackData);
// Switch back to Reg_Mode0;
priv->RfReg0Value[eRFPath] &= 0xebf;
rtl8192_setBBreg(
priv,
pPhyReg->rf3wireOffset,
bMaskDWord,
(priv->RfReg0Value[eRFPath] << 16));
//analog to digital on
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter4, 0x300, 0x3);// 0x88c[9:8]
return ret;
}
/******************************************************************************
*function: This function write data to RF register
* input: net_device dev
* RF90_RADIO_PATH_E eRFPath //radio path of A/B/C/D
* u32 Offset //target address to be written
* u32 Data //The new register data to be written
* output: none
* return: none
* notice: For RF8256 only.
===========================================================
*Reg Mode RegCTL[1] RegCTL[0] Note
* (Reg00[12]) (Reg00[10])
*===========================================================
*Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf)
*------------------------------------------------------------------
*Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf)
*------------------------------------------------------------------
* Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf)
*------------------------------------------------------------------
* ****************************************************************************/
static void rtl8192_phy_RFSerialWrite(struct r8192_priv *priv,
RF90_RADIO_PATH_E eRFPath, u32 Offset,
u32 Data)
{
u32 DataAndAddr = 0, NewOffset = 0;
BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath];
Offset &= 0x3f;
//analog to digital off, for protection
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter4, 0xf00, 0x0);// 0x88c[11:8]
if (Offset >= 31)
{
priv->RfReg0Value[eRFPath] |= 0x140;
rtl8192_setBBreg(priv, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath] << 16));
NewOffset = Offset - 30;
}
else if (Offset >= 16)
{
priv->RfReg0Value[eRFPath] |= 0x100;
priv->RfReg0Value[eRFPath] &= (~0x40);
rtl8192_setBBreg(priv, pPhyReg->rf3wireOffset, bMaskDWord, (priv->RfReg0Value[eRFPath]<<16));
NewOffset = Offset - 15;
}
else
NewOffset = Offset;
// Put write addr in [5:0] and write data in [31:16]
DataAndAddr = (Data<<16) | (NewOffset&0x3f);
// Write Operation
rtl8192_setBBreg(priv, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr);
if(Offset==0x0)
priv->RfReg0Value[eRFPath] = Data;
// Switch back to Reg_Mode0;
if(Offset != 0)
{
priv->RfReg0Value[eRFPath] &= 0xebf;
rtl8192_setBBreg(
priv,
pPhyReg->rf3wireOffset,
bMaskDWord,
(priv->RfReg0Value[eRFPath] << 16));
}
//analog to digital on
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter4, 0x300, 0x3);// 0x88c[9:8]
}
/******************************************************************************
*function: This function set specific bits to RF register
* input: RF90_RADIO_PATH_E eRFPath //radio path of A/B/C/D
* u32 RegAddr //target addr to be modified
* u32 BitMask //taget bit pos in the addr to be modified
* u32 Data //value to be write
* output: none
* return: none
* notice:
* ****************************************************************************/
void rtl8192_phy_SetRFReg(struct r8192_priv *priv, RF90_RADIO_PATH_E eRFPath,
u32 RegAddr, u32 BitMask, u32 Data)
{
u32 Original_Value, BitShift, New_Value;
// u8 time = 0;
if (!rtl8192_phy_CheckIsLegalRFPath(priv, eRFPath))
return;
if (priv->eRFPowerState != eRfOn && !priv->being_init_adapter)
return;
//down(&priv->rf_sem);
RT_TRACE(COMP_PHY, "FW RF CTRL is not ready now\n");
if (priv->Rf_Mode == RF_OP_By_FW)
{
if (BitMask != bMask12Bits) // RF data is 12 bits only
{
Original_Value = phy_FwRFSerialRead(priv, eRFPath, RegAddr);
BitShift = rtl8192_CalculateBitShift(BitMask);
New_Value = (((Original_Value) & (~BitMask)) | (Data<< BitShift));
phy_FwRFSerialWrite(priv, eRFPath, RegAddr, New_Value);
}else
phy_FwRFSerialWrite(priv, eRFPath, RegAddr, Data);
udelay(200);
}
else
{
if (BitMask != bMask12Bits) // RF data is 12 bits only
{
Original_Value = rtl8192_phy_RFSerialRead(priv, eRFPath, RegAddr);
BitShift = rtl8192_CalculateBitShift(BitMask);
New_Value = (((Original_Value) & (~BitMask)) | (Data<< BitShift));
rtl8192_phy_RFSerialWrite(priv, eRFPath, RegAddr, New_Value);
}else
rtl8192_phy_RFSerialWrite(priv, eRFPath, RegAddr, Data);
}
//up(&priv->rf_sem);
}
/******************************************************************************
*function: This function reads specific bits from RF register
* input: net_device dev
* u32 RegAddr //target addr to be readback
* u32 BitMask //taget bit pos in the addr to be readback
* output: none
* return: u32 Data //the readback register value
* notice:
* ****************************************************************************/
u32 rtl8192_phy_QueryRFReg(struct r8192_priv *priv, RF90_RADIO_PATH_E eRFPath,
u32 RegAddr, u32 BitMask)
{
u32 Original_Value, Readback_Value, BitShift;
if (!rtl8192_phy_CheckIsLegalRFPath(priv, eRFPath))
return 0;
if (priv->eRFPowerState != eRfOn && !priv->being_init_adapter)
return 0;
down(&priv->rf_sem);
if (priv->Rf_Mode == RF_OP_By_FW)
{
Original_Value = phy_FwRFSerialRead(priv, eRFPath, RegAddr);
udelay(200);
}
else
{
Original_Value = rtl8192_phy_RFSerialRead(priv, eRFPath, RegAddr);
}
BitShift = rtl8192_CalculateBitShift(BitMask);
Readback_Value = (Original_Value & BitMask) >> BitShift;
up(&priv->rf_sem);
// udelay(200);
return Readback_Value;
}
/******************************************************************************
*function: We support firmware to execute RF-R/W.
* input: dev
* output: none
* return: none
* notice:
* ***************************************************************************/
static u32 phy_FwRFSerialRead(struct r8192_priv *priv,
RF90_RADIO_PATH_E eRFPath, u32 Offset)
{
u32 Data = 0;
u8 time = 0;
//DbgPrint("FW RF CTRL\n\r");
/* 2007/11/02 MH Firmware RF Write control. By Francis' suggestion, we can
not execute the scheme in the initial step. Otherwise, RF-R/W will waste
much time. This is only for site survey. */
// 1. Read operation need not insert data. bit 0-11
//Data &= bMask12Bits;
// 2. Write RF register address. Bit 12-19
Data |= ((Offset&0xFF)<<12);
// 3. Write RF path. bit 20-21
Data |= ((eRFPath&0x3)<<20);
// 4. Set RF read indicator. bit 22=0
//Data |= 0x00000;
// 5. Trigger Fw to operate the command. bit 31
Data |= 0x80000000;
// 6. We can not execute read operation if bit 31 is 1.
while (read_nic_dword(priv, QPNR)&0x80000000)
{
// If FW can not finish RF-R/W for more than ?? times. We must reset FW.
if (time++ < 100)
{
//DbgPrint("FW not finish RF-R Time=%d\n\r", time);
udelay(10);
}
else
break;
}
// 7. Execute read operation.
write_nic_dword(priv, QPNR, Data);
// 8. Check if firmawre send back RF content.
while (read_nic_dword(priv, QPNR)&0x80000000)
{
// If FW can not finish RF-R/W for more than ?? times. We must reset FW.
if (time++ < 100)
{
//DbgPrint("FW not finish RF-W Time=%d\n\r", time);
udelay(10);
}
else
return 0;
}
return read_nic_dword(priv, RF_DATA);
}
/******************************************************************************
*function: We support firmware to execute RF-R/W.
* input: dev
* output: none
* return: none
* notice:
* ***************************************************************************/
static void phy_FwRFSerialWrite(struct r8192_priv *priv,
RF90_RADIO_PATH_E eRFPath, u32 Offset, u32 Data)
{
u8 time = 0;
//DbgPrint("N FW RF CTRL RF-%d OF%02x DATA=%03x\n\r", eRFPath, Offset, Data);
/* 2007/11/02 MH Firmware RF Write control. By Francis' suggestion, we can
not execute the scheme in the initial step. Otherwise, RF-R/W will waste
much time. This is only for site survey. */
// 1. Set driver write bit and 12 bit data. bit 0-11
//Data &= bMask12Bits; // Done by uper layer.
// 2. Write RF register address. bit 12-19
Data |= ((Offset&0xFF)<<12);
// 3. Write RF path. bit 20-21
Data |= ((eRFPath&0x3)<<20);
// 4. Set RF write indicator. bit 22=1
Data |= 0x400000;
// 5. Trigger Fw to operate the command. bit 31=1
Data |= 0x80000000;
// 6. Write operation. We can not write if bit 31 is 1.
while (read_nic_dword(priv, QPNR)&0x80000000)
{
// If FW can not finish RF-R/W for more than ?? times. We must reset FW.
if (time++ < 100)
{
//DbgPrint("FW not finish RF-W Time=%d\n\r", time);
udelay(10);
}
else
break;
}
// 7. No matter check bit. We always force the write. Because FW will
// not accept the command.
write_nic_dword(priv, QPNR, Data);
/* 2007/11/02 MH Acoording to test, we must delay 20us to wait firmware
to finish RF write operation. */
/* 2008/01/17 MH We support delay in firmware side now. */
//delay_us(20);
}
/******************************************************************************
*function: This function read BB parameters from Header file we gen,
* and do register read/write
* input: dev
* output: none
* return: none
* notice: BB parameters may change all the time, so please make
* sure it has been synced with the newest.
* ***************************************************************************/
void rtl8192_phy_configmac(struct r8192_priv *priv)
{
u32 dwArrayLen = 0, i = 0;
u32* pdwArray = NULL;
#ifdef TO_DO_LIST
if(Adapter->bInHctTest)
{
RT_TRACE(COMP_PHY, "Rtl819XMACPHY_ArrayDTM\n");
dwArrayLen = MACPHY_ArrayLengthDTM;
pdwArray = Rtl819XMACPHY_ArrayDTM;
}
else if(priv->bTXPowerDataReadFromEEPORM)
#endif
if(priv->bTXPowerDataReadFromEEPORM)
{
RT_TRACE(COMP_PHY, "Rtl819XMACPHY_Array_PG\n");
dwArrayLen = MACPHY_Array_PGLength;
pdwArray = Rtl819XMACPHY_Array_PG;
}
else
{
RT_TRACE(COMP_PHY,"Read rtl819XMACPHY_Array\n");
dwArrayLen = MACPHY_ArrayLength;
pdwArray = Rtl819XMACPHY_Array;
}
for(i = 0; i<dwArrayLen; i=i+3){
RT_TRACE(COMP_DBG, "The Rtl8190MACPHY_Array[0] is %x Rtl8190MACPHY_Array[1] is %x Rtl8190MACPHY_Array[2] is %x\n",
pdwArray[i], pdwArray[i+1], pdwArray[i+2]);
if(pdwArray[i] == 0x318)
{
pdwArray[i+2] = 0x00000800;
//DbgPrint("ptrArray[i], ptrArray[i+1], ptrArray[i+2] = %x, %x, %x\n",
// ptrArray[i], ptrArray[i+1], ptrArray[i+2]);
}
rtl8192_setBBreg(priv, pdwArray[i], pdwArray[i+1], pdwArray[i+2]);
}
}
/******************************************************************************
*function: This function do dirty work
* input: dev
* output: none
* return: none
* notice: BB parameters may change all the time, so please make
* sure it has been synced with the newest.
* ***************************************************************************/
void rtl8192_phyConfigBB(struct r8192_priv *priv, u8 ConfigType)
{
int i;
//u8 ArrayLength;
u32* Rtl819XPHY_REGArray_Table = NULL;
u32* Rtl819XAGCTAB_Array_Table = NULL;
u16 AGCTAB_ArrayLen, PHY_REGArrayLen = 0;
#ifdef TO_DO_LIST
u32 *rtl8192PhyRegArrayTable = NULL, *rtl8192AgcTabArrayTable = NULL;
if(Adapter->bInHctTest)
{
AGCTAB_ArrayLen = AGCTAB_ArrayLengthDTM;
Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_ArrayDTM;
if(priv->RF_Type == RF_2T4R)
{
PHY_REGArrayLen = PHY_REGArrayLengthDTM;
Rtl819XPHY_REGArray_Table = Rtl819XPHY_REGArrayDTM;
}
else if (priv->RF_Type == RF_1T2R)
{
PHY_REGArrayLen = PHY_REG_1T2RArrayLengthDTM;
Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_1T2RArrayDTM;
}
}
else
#endif
{
AGCTAB_ArrayLen = AGCTAB_ArrayLength;
Rtl819XAGCTAB_Array_Table = Rtl819XAGCTAB_Array;
if(priv->rf_type == RF_2T4R)
{
PHY_REGArrayLen = PHY_REGArrayLength;
Rtl819XPHY_REGArray_Table = Rtl819XPHY_REGArray;
}
else if (priv->rf_type == RF_1T2R)
{
PHY_REGArrayLen = PHY_REG_1T2RArrayLength;
Rtl819XPHY_REGArray_Table = Rtl819XPHY_REG_1T2RArray;
}
}
if (ConfigType == BaseBand_Config_PHY_REG)
{
for (i=0; i<PHY_REGArrayLen; i+=2)
{
rtl8192_setBBreg(priv, Rtl819XPHY_REGArray_Table[i], bMaskDWord, Rtl819XPHY_REGArray_Table[i+1]);
RT_TRACE(COMP_DBG, "i: %x, The Rtl819xUsbPHY_REGArray[0] is %x Rtl819xUsbPHY_REGArray[1] is %x\n",i, Rtl819XPHY_REGArray_Table[i], Rtl819XPHY_REGArray_Table[i+1]);
}
}
else if (ConfigType == BaseBand_Config_AGC_TAB)
{
for (i=0; i<AGCTAB_ArrayLen; i+=2)
{
rtl8192_setBBreg(priv, Rtl819XAGCTAB_Array_Table[i], bMaskDWord, Rtl819XAGCTAB_Array_Table[i+1]);
RT_TRACE(COMP_DBG, "i:%x, The rtl819XAGCTAB_Array[0] is %x rtl819XAGCTAB_Array[1] is %x\n",i, Rtl819XAGCTAB_Array_Table[i], Rtl819XAGCTAB_Array_Table[i+1]);
}
}
}
/******************************************************************************
*function: This function initialize Register definition offset for Radio Path
* A/B/C/D
* input: net_device dev
* output: none
* return: none
* notice: Initialization value here is constant and it should never be changed
* ***************************************************************************/
static void rtl8192_InitBBRFRegDef(struct r8192_priv *priv)
{
// RF Interface Sowrtware Control
priv->PHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870
priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872)
priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 LSBs if read 32-bit from 0x874
priv->PHYRegDef[RF90_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876)
// RF Interface Readback Value
priv->PHYRegDef[RF90_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; // 16 LSBs if read 32-bit from 0x8E0
priv->PHYRegDef[RF90_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2)
priv->PHYRegDef[RF90_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 LSBs if read 32-bit from 0x8E4
priv->PHYRegDef[RF90_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;// 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6)
// RF Interface Output (and Enable)
priv->PHYRegDef[RF90_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x860
priv->PHYRegDef[RF90_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; // 16 LSBs if read 32-bit from 0x864
priv->PHYRegDef[RF90_PATH_C].rfintfo = rFPGA0_XC_RFInterfaceOE;// 16 LSBs if read 32-bit from 0x868
priv->PHYRegDef[RF90_PATH_D].rfintfo = rFPGA0_XD_RFInterfaceOE;// 16 LSBs if read 32-bit from 0x86C
// RF Interface (Output and) Enable
priv->PHYRegDef[RF90_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862)
priv->PHYRegDef[RF90_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; // 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866)
priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86A (16-bit for 0x86A)
priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86C (16-bit for 0x86E)
//Addr of LSSI. Wirte RF register by driver
priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter
priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter;
priv->PHYRegDef[RF90_PATH_D].rf3wireOffset = rFPGA0_XD_LSSIParameter;
// RF parameter
priv->PHYRegDef[RF90_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; //BB Band Select
priv->PHYRegDef[RF90_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter;
priv->PHYRegDef[RF90_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter;
priv->PHYRegDef[RF90_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter;
// Tx AGC Gain Stage (same for all path. Should we remove this?)
priv->PHYRegDef[RF90_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage
priv->PHYRegDef[RF90_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage
priv->PHYRegDef[RF90_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage
priv->PHYRegDef[RF90_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; //Tx gain stage
// Tranceiver A~D HSSI Parameter-1
priv->PHYRegDef[RF90_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; //wire control parameter1
priv->PHYRegDef[RF90_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; //wire control parameter1
priv->PHYRegDef[RF90_PATH_C].rfHSSIPara1 = rFPGA0_XC_HSSIParameter1; //wire control parameter1
priv->PHYRegDef[RF90_PATH_D].rfHSSIPara1 = rFPGA0_XD_HSSIParameter1; //wire control parameter1
// Tranceiver A~D HSSI Parameter-2
priv->PHYRegDef[RF90_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; //wire control parameter2
priv->PHYRegDef[RF90_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; //wire control parameter2
priv->PHYRegDef[RF90_PATH_C].rfHSSIPara2 = rFPGA0_XC_HSSIParameter2; //wire control parameter2
priv->PHYRegDef[RF90_PATH_D].rfHSSIPara2 = rFPGA0_XD_HSSIParameter2; //wire control parameter1
// RF switch Control
priv->PHYRegDef[RF90_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; //TR/Ant switch control
priv->PHYRegDef[RF90_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl;
priv->PHYRegDef[RF90_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl;
priv->PHYRegDef[RF90_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl;
// AGC control 1
priv->PHYRegDef[RF90_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1;
priv->PHYRegDef[RF90_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1;
priv->PHYRegDef[RF90_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1;
priv->PHYRegDef[RF90_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1;
// AGC control 2
priv->PHYRegDef[RF90_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2;
priv->PHYRegDef[RF90_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2;
priv->PHYRegDef[RF90_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2;
priv->PHYRegDef[RF90_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2;
// RX AFE control 1
priv->PHYRegDef[RF90_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance;
priv->PHYRegDef[RF90_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance;
priv->PHYRegDef[RF90_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance;
priv->PHYRegDef[RF90_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance;
// RX AFE control 1
priv->PHYRegDef[RF90_PATH_A].rfRxAFE = rOFDM0_XARxAFE;
priv->PHYRegDef[RF90_PATH_B].rfRxAFE = rOFDM0_XBRxAFE;
priv->PHYRegDef[RF90_PATH_C].rfRxAFE = rOFDM0_XCRxAFE;
priv->PHYRegDef[RF90_PATH_D].rfRxAFE = rOFDM0_XDRxAFE;
// Tx AFE control 1
priv->PHYRegDef[RF90_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance;
priv->PHYRegDef[RF90_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance;
priv->PHYRegDef[RF90_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance;
priv->PHYRegDef[RF90_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance;
// Tx AFE control 2
priv->PHYRegDef[RF90_PATH_A].rfTxAFE = rOFDM0_XATxAFE;
priv->PHYRegDef[RF90_PATH_B].rfTxAFE = rOFDM0_XBTxAFE;
priv->PHYRegDef[RF90_PATH_C].rfTxAFE = rOFDM0_XCTxAFE;
priv->PHYRegDef[RF90_PATH_D].rfTxAFE = rOFDM0_XDTxAFE;
// Tranceiver LSSI Readback
priv->PHYRegDef[RF90_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack;
priv->PHYRegDef[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack;
priv->PHYRegDef[RF90_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack;
priv->PHYRegDef[RF90_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack;
}
/******************************************************************************
*function: This function is to write register and then readback to make sure whether BB and RF is OK
* input: net_device dev
* HW90_BLOCK_E CheckBlock
* RF90_RADIO_PATH_E eRFPath //only used when checkblock is HW90_BLOCK_RF
* output: none
* return: return whether BB and RF is ok(0:OK; 1:Fail)
* notice: This function may be removed in the ASIC
* ***************************************************************************/
RT_STATUS rtl8192_phy_checkBBAndRF(struct r8192_priv *priv,
HW90_BLOCK_E CheckBlock,
RF90_RADIO_PATH_E eRFPath)
{
// BB_REGISTER_DEFINITION_T *pPhyReg = &priv->PHYRegDef[eRFPath];
RT_STATUS ret = RT_STATUS_SUCCESS;
u32 i, CheckTimes = 4, dwRegRead = 0;
u32 WriteAddr[4];
u32 WriteData[] = {0xfffff027, 0xaa55a02f, 0x00000027, 0x55aa502f};
// Initialize register address offset to be checked
WriteAddr[HW90_BLOCK_MAC] = 0x100;
WriteAddr[HW90_BLOCK_PHY0] = 0x900;
WriteAddr[HW90_BLOCK_PHY1] = 0x800;
WriteAddr[HW90_BLOCK_RF] = 0x3;
RT_TRACE(COMP_PHY, "=======>%s(), CheckBlock:%d\n", __FUNCTION__, CheckBlock);
for(i=0 ; i < CheckTimes ; i++)
{
//
// Write Data to register and readback
//
switch(CheckBlock)
{
case HW90_BLOCK_MAC:
RT_TRACE(COMP_ERR, "PHY_CheckBBRFOK(): Never Write 0x100 here!\n");
break;
case HW90_BLOCK_PHY0:
case HW90_BLOCK_PHY1:
write_nic_dword(priv, WriteAddr[CheckBlock], WriteData[i]);
dwRegRead = read_nic_dword(priv, WriteAddr[CheckBlock]);
break;
case HW90_BLOCK_RF:
WriteData[i] &= 0xfff;
rtl8192_phy_SetRFReg(priv, eRFPath, WriteAddr[HW90_BLOCK_RF], bMask12Bits, WriteData[i]);
// TODO: we should not delay for such a long time. Ask SD3
mdelay(10);
dwRegRead = rtl8192_phy_QueryRFReg(priv, eRFPath, WriteAddr[HW90_BLOCK_RF], bMaskDWord);
mdelay(10);
break;
default:
ret = RT_STATUS_FAILURE;
break;
}
//
// Check whether readback data is correct
//
if(dwRegRead != WriteData[i])
{
RT_TRACE(COMP_ERR, "====>error=====dwRegRead: %x, WriteData: %x\n", dwRegRead, WriteData[i]);
ret = RT_STATUS_FAILURE;
break;
}
}
return ret;
}
/******************************************************************************
*function: This function initialize BB&RF
* input: net_device dev
* output: none
* return: none
* notice: Initialization value may change all the time, so please make
* sure it has been synced with the newest.
* ***************************************************************************/
static RT_STATUS rtl8192_BB_Config_ParaFile(struct r8192_priv *priv)
{
RT_STATUS rtStatus = RT_STATUS_SUCCESS;
u8 bRegValue = 0, eCheckItem = 0;
u32 dwRegValue = 0;
/**************************************
//<1>Initialize BaseBand
**************************************/
/*--set BB Global Reset--*/
bRegValue = read_nic_byte(priv, BB_GLOBAL_RESET);
write_nic_byte(priv, BB_GLOBAL_RESET,(bRegValue|BB_GLOBAL_RESET_BIT));
/*---set BB reset Active---*/
dwRegValue = read_nic_dword(priv, CPU_GEN);
write_nic_dword(priv, CPU_GEN, (dwRegValue&(~CPU_GEN_BB_RST)));
/*----Ckeck FPGAPHY0 and PHY1 board is OK----*/
// TODO: this function should be removed on ASIC , Emily 2007.2.2
for(eCheckItem=(HW90_BLOCK_E)HW90_BLOCK_PHY0; eCheckItem<=HW90_BLOCK_PHY1; eCheckItem++)
{
rtStatus = rtl8192_phy_checkBBAndRF(priv, (HW90_BLOCK_E)eCheckItem, (RF90_RADIO_PATH_E)0); //don't care RF path
if(rtStatus != RT_STATUS_SUCCESS)
{
RT_TRACE((COMP_ERR | COMP_PHY), "PHY_RF8256_Config():Check PHY%d Fail!!\n", eCheckItem-1);
return rtStatus;
}
}
/*---- Set CCK and OFDM Block "OFF"----*/
rtl8192_setBBreg(priv, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x0);
/*----BB Register Initilazation----*/
//==m==>Set PHY REG From Header<==m==
rtl8192_phyConfigBB(priv, BaseBand_Config_PHY_REG);
/*----Set BB reset de-Active----*/
dwRegValue = read_nic_dword(priv, CPU_GEN);
write_nic_dword(priv, CPU_GEN, (dwRegValue|CPU_GEN_BB_RST));
/*----BB AGC table Initialization----*/
//==m==>Set PHY REG From Header<==m==
rtl8192_phyConfigBB(priv, BaseBand_Config_AGC_TAB);
if (priv->card_8192_version > VERSION_8190_BD)
{
if(priv->rf_type == RF_2T4R)
{
// Antenna gain offset from B/C/D to A
dwRegValue = ( priv->AntennaTxPwDiff[2]<<8 |
priv->AntennaTxPwDiff[1]<<4 |
priv->AntennaTxPwDiff[0]);
}
else
dwRegValue = 0x0; //Antenna gain offset doesn't make sense in RF 1T2R.
rtl8192_setBBreg(priv, rFPGA0_TxGainStage,
(bXBTxAGC|bXCTxAGC|bXDTxAGC), dwRegValue);
//XSTALLCap
dwRegValue = priv->CrystalCap;
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter1, bXtalCap92x, dwRegValue);
}
// Check if the CCK HighPower is turned ON.
// This is used to calculate PWDB.
// priv->bCckHighPower = (u8)(rtl8192_QueryBBReg(dev, rFPGA0_XA_HSSIParameter2, 0x200));
return rtStatus;
}
/******************************************************************************
*function: This function initialize BB&RF
* input: net_device dev
* output: none
* return: none
* notice: Initialization value may change all the time, so please make
* sure it has been synced with the newest.
* ***************************************************************************/
RT_STATUS rtl8192_BBConfig(struct r8192_priv *priv)
{
rtl8192_InitBBRFRegDef(priv);
//config BB&RF. As hardCode based initialization has not been well
//implemented, so use file first.FIXME:should implement it for hardcode?
return rtl8192_BB_Config_ParaFile(priv);
}
/******************************************************************************
*function: This function obtains the initialization value of Tx power Level offset
* input: net_device dev
* output: none
* return: none
* ***************************************************************************/
void rtl8192_phy_getTxPower(struct r8192_priv *priv)
{
priv->MCSTxPowerLevelOriginalOffset[0] =
read_nic_dword(priv, rTxAGC_Rate18_06);
priv->MCSTxPowerLevelOriginalOffset[1] =
read_nic_dword(priv, rTxAGC_Rate54_24);
priv->MCSTxPowerLevelOriginalOffset[2] =
read_nic_dword(priv, rTxAGC_Mcs03_Mcs00);
priv->MCSTxPowerLevelOriginalOffset[3] =
read_nic_dword(priv, rTxAGC_Mcs07_Mcs04);
priv->MCSTxPowerLevelOriginalOffset[4] =
read_nic_dword(priv, rTxAGC_Mcs11_Mcs08);
priv->MCSTxPowerLevelOriginalOffset[5] =
read_nic_dword(priv, rTxAGC_Mcs15_Mcs12);
// read rx initial gain
priv->DefaultInitialGain[0] = read_nic_byte(priv, rOFDM0_XAAGCCore1);
priv->DefaultInitialGain[1] = read_nic_byte(priv, rOFDM0_XBAGCCore1);
priv->DefaultInitialGain[2] = read_nic_byte(priv, rOFDM0_XCAGCCore1);
priv->DefaultInitialGain[3] = read_nic_byte(priv, rOFDM0_XDAGCCore1);
RT_TRACE(COMP_INIT, "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x)\n",
priv->DefaultInitialGain[0], priv->DefaultInitialGain[1],
priv->DefaultInitialGain[2], priv->DefaultInitialGain[3]);
// read framesync
priv->framesync = read_nic_byte(priv, rOFDM0_RxDetector3);
priv->framesyncC34 = read_nic_dword(priv, rOFDM0_RxDetector2);
RT_TRACE(COMP_INIT, "Default framesync (0x%x) = 0x%x\n",
rOFDM0_RxDetector3, priv->framesync);
// read SIFS (save the value read fome MACPHY_REG.txt)
priv->SifsTime = read_nic_word(priv, SIFS);
}
/******************************************************************************
*function: This function obtains the initialization value of Tx power Level offset
* input: net_device dev
* output: none
* return: none
* ***************************************************************************/
void rtl8192_phy_setTxPower(struct r8192_priv *priv, u8 channel)
{
u8 powerlevel = 0,powerlevelOFDM24G = 0;
char ant_pwr_diff;
u32 u4RegValue;
if(priv->epromtype == EPROM_93c46)
{
powerlevel = priv->TxPowerLevelCCK[channel-1];
powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1];
}
else if(priv->epromtype == EPROM_93c56)
{
if(priv->rf_type == RF_1T2R)
{
powerlevel = priv->TxPowerLevelCCK_C[channel-1];
powerlevelOFDM24G = priv->TxPowerLevelOFDM24G_C[channel-1];
}
else if(priv->rf_type == RF_2T4R)
{
// Mainly we use RF-A Tx Power to write the Tx Power registers, but the RF-C Tx
// Power must be calculated by the antenna diff.
// So we have to rewrite Antenna gain offset register here.
powerlevel = priv->TxPowerLevelCCK_A[channel-1];
powerlevelOFDM24G = priv->TxPowerLevelOFDM24G_A[channel-1];
ant_pwr_diff = priv->TxPowerLevelOFDM24G_C[channel-1]
-priv->TxPowerLevelOFDM24G_A[channel-1];
ant_pwr_diff &= 0xf;
priv->AntennaTxPwDiff[2] = 0;// RF-D, don't care
priv->AntennaTxPwDiff[1] = (u8)(ant_pwr_diff);// RF-C
priv->AntennaTxPwDiff[0] = 0;// RF-B, don't care
// Antenna gain offset from B/C/D to A
u4RegValue = ( priv->AntennaTxPwDiff[2]<<8 |
priv->AntennaTxPwDiff[1]<<4 |
priv->AntennaTxPwDiff[0]);
rtl8192_setBBreg(priv, rFPGA0_TxGainStage,
(bXBTxAGC|bXCTxAGC|bXDTxAGC), u4RegValue);
}
}
#ifdef TODO
//
// CCX 2 S31, AP control of client transmit power:
// 1. We shall not exceed Cell Power Limit as possible as we can.
// 2. Tolerance is +/- 5dB.
// 3. 802.11h Power Contraint takes higher precedence over CCX Cell Power Limit.
//
// TODO:
// 1. 802.11h power contraint
//
// 071011, by rcnjko.
//
if( pMgntInfo->OpMode == RT_OP_MODE_INFRASTRUCTURE &&
pMgntInfo->bWithCcxCellPwr &&
channel == pMgntInfo->dot11CurrentChannelNumber)
{
u8 CckCellPwrIdx = DbmToTxPwrIdx(Adapter, WIRELESS_MODE_B, pMgntInfo->CcxCellPwr);
u8 LegacyOfdmCellPwrIdx = DbmToTxPwrIdx(Adapter, WIRELESS_MODE_G, pMgntInfo->CcxCellPwr);
u8 OfdmCellPwrIdx = DbmToTxPwrIdx(Adapter, WIRELESS_MODE_N_24G, pMgntInfo->CcxCellPwr);
RT_TRACE(COMP_TXAGC, DBG_LOUD,
("CCX Cell Limit: %d dbm => CCK Tx power index : %d, Legacy OFDM Tx power index : %d, OFDM Tx power index: %d\n",
pMgntInfo->CcxCellPwr, CckCellPwrIdx, LegacyOfdmCellPwrIdx, OfdmCellPwrIdx));
RT_TRACE(COMP_TXAGC, DBG_LOUD,
("EEPROM channel(%d) => CCK Tx power index: %d, Legacy OFDM Tx power index : %d, OFDM Tx power index: %d\n",
channel, powerlevel, powerlevelOFDM24G + pHalData->LegacyHTTxPowerDiff, powerlevelOFDM24G));
// CCK
if(powerlevel > CckCellPwrIdx)
powerlevel = CckCellPwrIdx;
// Legacy OFDM, HT OFDM
if(powerlevelOFDM24G + pHalData->LegacyHTTxPowerDiff > OfdmCellPwrIdx)
{
if((OfdmCellPwrIdx - pHalData->LegacyHTTxPowerDiff) > 0)
{
powerlevelOFDM24G = OfdmCellPwrIdx - pHalData->LegacyHTTxPowerDiff;
}
else
{
LegacyOfdmCellPwrIdx = 0;
}
}
RT_TRACE(COMP_TXAGC, DBG_LOUD,
("Altered CCK Tx power index : %d, Legacy OFDM Tx power index: %d, OFDM Tx power index: %d\n",
powerlevel, powerlevelOFDM24G + pHalData->LegacyHTTxPowerDiff, powerlevelOFDM24G));
}
pHalData->CurrentCckTxPwrIdx = powerlevel;
pHalData->CurrentOfdm24GTxPwrIdx = powerlevelOFDM24G;
#endif
PHY_SetRF8256CCKTxPower(priv, powerlevel); //need further implement
PHY_SetRF8256OFDMTxPower(priv, powerlevelOFDM24G);
}
/******************************************************************************
*function: This function check Rf chip to do RF config
* input: net_device dev
* output: none
* return: only 8256 is supported
* ***************************************************************************/
RT_STATUS rtl8192_phy_RFConfig(struct r8192_priv *priv)
{
return PHY_RF8256_Config(priv);
}
/******************************************************************************
*function: This function update Initial gain
* input: net_device dev
* output: none
* return: As Windows has not implemented this, wait for complement
* ***************************************************************************/
void rtl8192_phy_updateInitGain(struct r8192_priv *priv)
{
}
/******************************************************************************
*function: This function read RF parameters from general head file, and do RF 3-wire
* input: net_device dev
* output: none
* return: return code show if RF configuration is successful(0:pass, 1:fail)
* Note: Delay may be required for RF configuration
* ***************************************************************************/
u8 rtl8192_phy_ConfigRFWithHeaderFile(struct r8192_priv *priv,
RF90_RADIO_PATH_E eRFPath)
{
int i;
//u32* pRFArray;
u8 ret = 0;
switch(eRFPath){
case RF90_PATH_A:
for(i = 0;i<RadioA_ArrayLength; i=i+2){
if(Rtl819XRadioA_Array[i] == 0xfe){
msleep(100);
continue;
}
rtl8192_phy_SetRFReg(priv, eRFPath, Rtl819XRadioA_Array[i], bMask12Bits, Rtl819XRadioA_Array[i+1]);
//msleep(1);
}
break;
case RF90_PATH_B:
for(i = 0;i<RadioB_ArrayLength; i=i+2){
if(Rtl819XRadioB_Array[i] == 0xfe){
msleep(100);
continue;
}
rtl8192_phy_SetRFReg(priv, eRFPath, Rtl819XRadioB_Array[i], bMask12Bits, Rtl819XRadioB_Array[i+1]);
//msleep(1);
}
break;
case RF90_PATH_C:
for(i = 0;i<RadioC_ArrayLength; i=i+2){
if(Rtl819XRadioC_Array[i] == 0xfe){
msleep(100);
continue;
}
rtl8192_phy_SetRFReg(priv, eRFPath, Rtl819XRadioC_Array[i], bMask12Bits, Rtl819XRadioC_Array[i+1]);
//msleep(1);
}
break;
case RF90_PATH_D:
for(i = 0;i<RadioD_ArrayLength; i=i+2){
if(Rtl819XRadioD_Array[i] == 0xfe){
msleep(100);
continue;
}
rtl8192_phy_SetRFReg(priv, eRFPath, Rtl819XRadioD_Array[i], bMask12Bits, Rtl819XRadioD_Array[i+1]);
//msleep(1);
}
break;
default:
break;
}
return ret;
}
/******************************************************************************
*function: This function set Tx Power of the channel
* input: struct net_device *dev
* u8 channel
* output: none
* return: none
* Note:
* ***************************************************************************/
static void rtl8192_SetTxPowerLevel(struct r8192_priv *priv, u8 channel)
{
u8 powerlevel = priv->TxPowerLevelCCK[channel-1];
u8 powerlevelOFDM24G = priv->TxPowerLevelOFDM24G[channel-1];
PHY_SetRF8256CCKTxPower(priv, powerlevel);
PHY_SetRF8256OFDMTxPower(priv, powerlevelOFDM24G);
}
/****************************************************************************************
*function: This function set command table variable(struct SwChnlCmd).
* input: SwChnlCmd* CmdTable //table to be set.
* u32 CmdTableIdx //variable index in table to be set
* u32 CmdTableSz //table size.
* SwChnlCmdID CmdID //command ID to set.
* u32 Para1
* u32 Para2
* u32 msDelay
* output:
* return: true if finished, false otherwise
* Note:
* ************************************************************************************/
static u8 rtl8192_phy_SetSwChnlCmdArray(
SwChnlCmd* CmdTable,
u32 CmdTableIdx,
u32 CmdTableSz,
SwChnlCmdID CmdID,
u32 Para1,
u32 Para2,
u32 msDelay
)
{
SwChnlCmd* pCmd;
if(CmdTable == NULL)
{
RT_TRACE(COMP_ERR, "phy_SetSwChnlCmdArray(): CmdTable cannot be NULL.\n");
return false;
}
if(CmdTableIdx >= CmdTableSz)
{
RT_TRACE(COMP_ERR, "phy_SetSwChnlCmdArray(): Access invalid index, please check size of the table, CmdTableIdx:%d, CmdTableSz:%d\n",
CmdTableIdx, CmdTableSz);
return false;
}
pCmd = CmdTable + CmdTableIdx;
pCmd->CmdID = CmdID;
pCmd->Para1 = Para1;
pCmd->Para2 = Para2;
pCmd->msDelay = msDelay;
return true;
}
/******************************************************************************
*function: This function set channel step by step
* input: struct net_device *dev
* u8 channel
* u8* stage //3 stages
* u8* step //
* u32* delay //whether need to delay
* output: store new stage, step and delay for next step(combine with function above)
* return: true if finished, false otherwise
* Note: Wait for simpler function to replace it //wb
* ***************************************************************************/
static u8 rtl8192_phy_SwChnlStepByStep(struct r8192_priv *priv, u8 channel,
u8* stage, u8* step, u32* delay)
{
// PCHANNEL_ACCESS_SETTING pChnlAccessSetting;
SwChnlCmd PreCommonCmd[MAX_PRECMD_CNT];
u32 PreCommonCmdCnt;
SwChnlCmd PostCommonCmd[MAX_POSTCMD_CNT];
u32 PostCommonCmdCnt;
SwChnlCmd RfDependCmd[MAX_RFDEPENDCMD_CNT];
u32 RfDependCmdCnt;
SwChnlCmd *CurrentCmd = NULL;
//RF90_RADIO_PATH_E eRFPath;
u8 eRFPath;
// u32 RfRetVal;
// u8 RetryCnt;
RT_TRACE(COMP_TRACE, "====>%s()====stage:%d, step:%d, channel:%d\n", __FUNCTION__, *stage, *step, channel);
// RT_ASSERT(IsLegalChannel(Adapter, channel), ("illegal channel: %d\n", channel));
#ifdef ENABLE_DOT11D
if (!IsLegalChannel(priv->ieee80211, channel))
{
RT_TRACE(COMP_ERR, "=============>set to illegal channel:%d\n", channel);
return true; //return true to tell upper caller function this channel setting is finished! Or it will in while loop.
}
#endif
//for(eRFPath = RF90_PATH_A; eRFPath <pHalData->NumTotalRFPath; eRFPath++)
//for(eRFPath = 0; eRFPath <RF90_PATH_MAX; eRFPath++)
{
//if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath))
// return false;
// <1> Fill up pre common command.
PreCommonCmdCnt = 0;
rtl8192_phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT,
CmdID_SetTxPowerLevel, 0, 0, 0);
rtl8192_phy_SetSwChnlCmdArray(PreCommonCmd, PreCommonCmdCnt++, MAX_PRECMD_CNT,
CmdID_End, 0, 0, 0);
// <2> Fill up post common command.
PostCommonCmdCnt = 0;
rtl8192_phy_SetSwChnlCmdArray(PostCommonCmd, PostCommonCmdCnt++, MAX_POSTCMD_CNT,
CmdID_End, 0, 0, 0);
// <3> Fill up RF dependent command.
RfDependCmdCnt = 0;
// TEST!! This is not the table for 8256!!
if (!(channel >= 1 && channel <= 14))
{
RT_TRACE(COMP_ERR, "illegal channel for Zebra 8256: %d\n", channel);
return false;
}
rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT,
CmdID_RF_WriteReg, rZebra1_Channel, channel, 10);
rtl8192_phy_SetSwChnlCmdArray(RfDependCmd, RfDependCmdCnt++, MAX_RFDEPENDCMD_CNT,
CmdID_End, 0, 0, 0);
do{
switch(*stage)
{
case 0:
CurrentCmd=&PreCommonCmd[*step];
break;
case 1:
CurrentCmd=&RfDependCmd[*step];
break;
case 2:
CurrentCmd=&PostCommonCmd[*step];
break;
}
if(CurrentCmd->CmdID==CmdID_End)
{
if((*stage)==2)
{
return true;
}
else
{
(*stage)++;
(*step)=0;
continue;
}
}
switch(CurrentCmd->CmdID)
{
case CmdID_SetTxPowerLevel:
if(priv->card_8192_version > (u8)VERSION_8190_BD) //xiong: consider it later!
rtl8192_SetTxPowerLevel(priv, channel);
break;
case CmdID_WritePortUlong:
write_nic_dword(priv, CurrentCmd->Para1, CurrentCmd->Para2);
break;
case CmdID_WritePortUshort:
write_nic_word(priv, CurrentCmd->Para1, (u16)CurrentCmd->Para2);
break;
case CmdID_WritePortUchar:
write_nic_byte(priv, CurrentCmd->Para1, (u8)CurrentCmd->Para2);
break;
case CmdID_RF_WriteReg:
for(eRFPath = 0; eRFPath <priv->NumTotalRFPath; eRFPath++)
rtl8192_phy_SetRFReg(priv, (RF90_RADIO_PATH_E)eRFPath, CurrentCmd->Para1, bMask12Bits, CurrentCmd->Para2<<7);
break;
default:
break;
}
break;
}while(true);
}/*for(Number of RF paths)*/
(*delay)=CurrentCmd->msDelay;
(*step)++;
return false;
}
/******************************************************************************
*function: This function does acturally set channel work
* input: struct net_device *dev
* u8 channel
* output: none
* return: noin
* Note: We should not call this function directly
* ***************************************************************************/
static void rtl8192_phy_FinishSwChnlNow(struct r8192_priv *priv, u8 channel)
{
u32 delay = 0;
while (!rtl8192_phy_SwChnlStepByStep(priv, channel, &priv->SwChnlStage, &priv->SwChnlStep, &delay))
{
if(delay>0)
msleep(delay);//or mdelay? need further consideration
if(!priv->up)
break;
}
}
/******************************************************************************
*function: Callback routine of the work item for switch channel.
* input:
*
* output: none
* return: noin
* ***************************************************************************/
void rtl8192_SwChnl_WorkItem(struct r8192_priv *priv)
{
RT_TRACE(COMP_TRACE, "==> SwChnlCallback819xUsbWorkItem()\n");
RT_TRACE(COMP_TRACE, "=====>--%s(), set chan:%d, priv:%p\n", __FUNCTION__, priv->chan, priv);
rtl8192_phy_FinishSwChnlNow(priv, priv->chan);
RT_TRACE(COMP_TRACE, "<== SwChnlCallback819xUsbWorkItem()\n");
}
/******************************************************************************
*function: This function scheduled actural workitem to set channel
* input: net_device dev
* u8 channel //channel to set
* output: none
* return: return code show if workitem is scheduled(1:pass, 0:fail)
* Note: Delay may be required for RF configuration
* ***************************************************************************/
u8 rtl8192_phy_SwChnl(struct ieee80211_device *ieee80211, u8 channel)
{
struct r8192_priv *priv = ieee80211_priv(ieee80211->dev);
RT_TRACE(COMP_PHY, "=====>%s()\n", __FUNCTION__);
if(!priv->up)
return false;
if(priv->SwChnlInProgress)
return false;
// if(pHalData->SetBWModeInProgress)
// return;
//--------------------------------------------
switch(priv->ieee80211->mode)
{
case WIRELESS_MODE_A:
case WIRELESS_MODE_N_5G:
if (channel<=14){
RT_TRACE(COMP_ERR, "WIRELESS_MODE_A but channel<=14\n");
return false;
}
break;
case WIRELESS_MODE_B:
if (channel>14){
RT_TRACE(COMP_ERR, "WIRELESS_MODE_B but channel>14\n");
return false;
}
break;
case WIRELESS_MODE_G:
case WIRELESS_MODE_N_24G:
if (channel>14){
RT_TRACE(COMP_ERR, "WIRELESS_MODE_G but channel>14\n");
return false;
}
break;
}
//--------------------------------------------
priv->SwChnlInProgress = true;
if(channel == 0)
channel = 1;
priv->chan=channel;
priv->SwChnlStage=0;
priv->SwChnlStep=0;
if (priv->up)
rtl8192_SwChnl_WorkItem(priv);
priv->SwChnlInProgress = false;
return true;
}
static void CCK_Tx_Power_Track_BW_Switch_TSSI(struct r8192_priv *priv)
{
switch(priv->CurrentChannelBW)
{
/* 20 MHz channel*/
case HT_CHANNEL_WIDTH_20:
//added by vivi, cck,tx power track, 20080703
priv->CCKPresentAttentuation =
priv->CCKPresentAttentuation_20Mdefault + priv->CCKPresentAttentuation_difference;
if(priv->CCKPresentAttentuation > (CCKTxBBGainTableLength-1))
priv->CCKPresentAttentuation = CCKTxBBGainTableLength-1;
if(priv->CCKPresentAttentuation < 0)
priv->CCKPresentAttentuation = 0;
RT_TRACE(COMP_POWER_TRACKING, "20M, priv->CCKPresentAttentuation = %d\n", priv->CCKPresentAttentuation);
if(priv->ieee80211->current_network.channel== 14 && !priv->bcck_in_ch14)
{
priv->bcck_in_ch14 = TRUE;
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
}
else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14)
{
priv->bcck_in_ch14 = FALSE;
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
}
else
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
break;
/* 40 MHz channel*/
case HT_CHANNEL_WIDTH_20_40:
//added by vivi, cck,tx power track, 20080703
priv->CCKPresentAttentuation =
priv->CCKPresentAttentuation_40Mdefault + priv->CCKPresentAttentuation_difference;
RT_TRACE(COMP_POWER_TRACKING, "40M, priv->CCKPresentAttentuation = %d\n", priv->CCKPresentAttentuation);
if(priv->CCKPresentAttentuation > (CCKTxBBGainTableLength-1))
priv->CCKPresentAttentuation = CCKTxBBGainTableLength-1;
if(priv->CCKPresentAttentuation < 0)
priv->CCKPresentAttentuation = 0;
if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14)
{
priv->bcck_in_ch14 = TRUE;
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
}
else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14)
{
priv->bcck_in_ch14 = FALSE;
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
}
else
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
break;
}
}
static void CCK_Tx_Power_Track_BW_Switch_ThermalMeter(struct r8192_priv *priv)
{
if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14)
priv->bcck_in_ch14 = TRUE;
else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14)
priv->bcck_in_ch14 = FALSE;
//write to default index and tx power track will be done in dm.
switch(priv->CurrentChannelBW)
{
/* 20 MHz channel*/
case HT_CHANNEL_WIDTH_20:
if(priv->Record_CCK_20Mindex == 0)
priv->Record_CCK_20Mindex = 6; //set default value.
priv->CCK_index = priv->Record_CCK_20Mindex;//6;
RT_TRACE(COMP_POWER_TRACKING, "20MHz, CCK_Tx_Power_Track_BW_Switch_ThermalMeter(),CCK_index = %d\n", priv->CCK_index);
break;
/* 40 MHz channel*/
case HT_CHANNEL_WIDTH_20_40:
priv->CCK_index = priv->Record_CCK_40Mindex;//0;
RT_TRACE(COMP_POWER_TRACKING, "40MHz, CCK_Tx_Power_Track_BW_Switch_ThermalMeter(), CCK_index = %d\n", priv->CCK_index);
break;
}
dm_cck_txpower_adjust(priv, priv->bcck_in_ch14);
}
static void CCK_Tx_Power_Track_BW_Switch(struct r8192_priv *priv)
{
//if(pHalData->bDcut == TRUE)
if(priv->IC_Cut >= IC_VersionCut_D)
CCK_Tx_Power_Track_BW_Switch_TSSI(priv);
else
CCK_Tx_Power_Track_BW_Switch_ThermalMeter(priv);
}
//
/******************************************************************************
*function: Callback routine of the work item for set bandwidth mode.
* input: struct net_device *dev
* HT_CHANNEL_WIDTH Bandwidth //20M or 40M
* HT_EXTCHNL_OFFSET Offset //Upper, Lower, or Don't care
* output: none
* return: none
* Note: I doubt whether SetBWModeInProgress flag is necessary as we can
* test whether current work in the queue or not.//do I?
* ***************************************************************************/
void rtl8192_SetBWModeWorkItem(struct r8192_priv *priv)
{
u8 regBwOpMode;
RT_TRACE(COMP_SWBW, "==>rtl8192_SetBWModeWorkItem() Switch to %s bandwidth\n",
priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20?"20MHz":"40MHz")
if(!priv->up)
{
priv->SetBWModeInProgress= false;
return;
}
//<1>Set MAC register
regBwOpMode = read_nic_byte(priv, BW_OPMODE);
switch(priv->CurrentChannelBW)
{
case HT_CHANNEL_WIDTH_20:
regBwOpMode |= BW_OPMODE_20MHZ;
// 2007/02/07 Mark by Emily because we have not verify whether this register works
write_nic_byte(priv, BW_OPMODE, regBwOpMode);
break;
case HT_CHANNEL_WIDTH_20_40:
regBwOpMode &= ~BW_OPMODE_20MHZ;
// 2007/02/07 Mark by Emily because we have not verify whether this register works
write_nic_byte(priv, BW_OPMODE, regBwOpMode);
break;
default:
RT_TRACE(COMP_ERR, "SetChannelBandwidth819xUsb(): unknown Bandwidth: %#X\n",priv->CurrentChannelBW);
break;
}
//<2>Set PHY related register
switch(priv->CurrentChannelBW)
{
case HT_CHANNEL_WIDTH_20:
// Add by Vivi 20071119
rtl8192_setBBreg(priv, rFPGA0_RFMOD, bRFMOD, 0x0);
rtl8192_setBBreg(priv, rFPGA1_RFMOD, bRFMOD, 0x0);
// rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1);
// Correct the tx power for CCK rate in 20M. Suggest by YN, 20071207
// write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000);
// write_nic_dword(dev, rCCK0_TxFilter2, 0x090e1317);
// write_nic_dword(dev, rCCK0_DebugPort, 0x00000204);
if(!priv->btxpower_tracking)
{
write_nic_dword(priv, rCCK0_TxFilter1, 0x1a1b0000);
write_nic_dword(priv, rCCK0_TxFilter2, 0x090e1317);
write_nic_dword(priv, rCCK0_DebugPort, 0x00000204);
}
else
CCK_Tx_Power_Track_BW_Switch(priv);
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter1, 0x00100000, 1);
break;
case HT_CHANNEL_WIDTH_20_40:
// Add by Vivi 20071119
rtl8192_setBBreg(priv, rFPGA0_RFMOD, bRFMOD, 0x1);
rtl8192_setBBreg(priv, rFPGA1_RFMOD, bRFMOD, 0x1);
//rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1));
//rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0);
//rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC);
// Correct the tx power for CCK rate in 40M. Suggest by YN, 20071207
//write_nic_dword(dev, rCCK0_TxFilter1, 0x35360000);
//write_nic_dword(dev, rCCK0_TxFilter2, 0x121c252e);
//write_nic_dword(dev, rCCK0_DebugPort, 0x00000409);
if(!priv->btxpower_tracking)
{
write_nic_dword(priv, rCCK0_TxFilter1, 0x35360000);
write_nic_dword(priv, rCCK0_TxFilter2, 0x121c252e);
write_nic_dword(priv, rCCK0_DebugPort, 0x00000409);
}
else
CCK_Tx_Power_Track_BW_Switch(priv);
// Set Control channel to upper or lower. These settings are required only for 40MHz
rtl8192_setBBreg(priv, rCCK0_System, bCCKSideBand, (priv->nCur40MhzPrimeSC>>1));
rtl8192_setBBreg(priv, rOFDM1_LSTF, 0xC00, priv->nCur40MhzPrimeSC);
rtl8192_setBBreg(priv, rFPGA0_AnalogParameter1, 0x00100000, 0);
break;
default:
RT_TRACE(COMP_ERR, "SetChannelBandwidth819xUsb(): unknown Bandwidth: %#X\n" ,priv->CurrentChannelBW);
break;
}
//Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315
//<3>Set RF related register
PHY_SetRF8256Bandwidth(priv, priv->CurrentChannelBW);
atomic_dec(&(priv->ieee80211->atm_swbw));
priv->SetBWModeInProgress= false;
RT_TRACE(COMP_SWBW, "<==SetBWMode819xUsb()\n");
}
/******************************************************************************
*function: This function schedules bandwidth switch work.
* input: struct net_device *dev
* HT_CHANNEL_WIDTH Bandwidth //20M or 40M
* HT_EXTCHNL_OFFSET Offset //Upper, Lower, or Don't care
* output: none
* return: none
* Note: I doubt whether SetBWModeInProgress flag is necessary as we can
* test whether current work in the queue or not.//do I?
* ***************************************************************************/
void rtl8192_SetBWMode(struct ieee80211_device *ieee, HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset)
{
struct r8192_priv *priv = ieee80211_priv(ieee->dev);
if(priv->SetBWModeInProgress)
return;
atomic_inc(&(priv->ieee80211->atm_swbw));
priv->SetBWModeInProgress= true;
priv->CurrentChannelBW = Bandwidth;
if(Offset==HT_EXTCHNL_OFFSET_LOWER)
priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_UPPER;
else if(Offset==HT_EXTCHNL_OFFSET_UPPER)
priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_LOWER;
else
priv->nCur40MhzPrimeSC = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
//queue_work(priv->priv_wq, &(priv->SetBWModeWorkItem));
// schedule_work(&(priv->SetBWModeWorkItem));
rtl8192_SetBWModeWorkItem(priv);
}
void InitialGain819xPci(struct ieee80211_device *ieee, u8 Operation)
{
#define SCAN_RX_INITIAL_GAIN 0x17
#define POWER_DETECTION_TH 0x08
struct r8192_priv *priv = ieee80211_priv(ieee->dev);
u32 BitMask;
u8 initial_gain;
if(priv->up)
{
switch(Operation)
{
case IG_Backup:
RT_TRACE(COMP_SCAN, "IG_Backup, backup the initial gain.\n");
initial_gain = SCAN_RX_INITIAL_GAIN;//pHalData->DefaultInitialGain[0];//
BitMask = bMaskByte0;
if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM)
rtl8192_setBBreg(priv, UFWP, bMaskByte1, 0x8); // FW DIG OFF
priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(priv, rOFDM0_XAAGCCore1, BitMask);
priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(priv, rOFDM0_XBAGCCore1, BitMask);
priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(priv, rOFDM0_XCAGCCore1, BitMask);
priv->initgain_backup.xdagccore1 = (u8)rtl8192_QueryBBReg(priv, rOFDM0_XDAGCCore1, BitMask);
BitMask = bMaskByte2;
priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(priv, rCCK0_CCA, BitMask);
RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc50 is %x\n",priv->initgain_backup.xaagccore1);
RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc58 is %x\n",priv->initgain_backup.xbagccore1);
RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc60 is %x\n",priv->initgain_backup.xcagccore1);
RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xc68 is %x\n",priv->initgain_backup.xdagccore1);
RT_TRACE(COMP_SCAN, "Scan InitialGainBackup 0xa0a is %x\n",priv->initgain_backup.cca);
RT_TRACE(COMP_SCAN, "Write scan initial gain = 0x%x \n", initial_gain);
write_nic_byte(priv, rOFDM0_XAAGCCore1, initial_gain);
write_nic_byte(priv, rOFDM0_XBAGCCore1, initial_gain);
write_nic_byte(priv, rOFDM0_XCAGCCore1, initial_gain);
write_nic_byte(priv, rOFDM0_XDAGCCore1, initial_gain);
RT_TRACE(COMP_SCAN, "Write scan 0xa0a = 0x%x \n", POWER_DETECTION_TH);
write_nic_byte(priv, 0xa0a, POWER_DETECTION_TH);
break;
case IG_Restore:
RT_TRACE(COMP_SCAN, "IG_Restore, restore the initial gain.\n");
BitMask = 0x7f; //Bit0~ Bit6
if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM)
rtl8192_setBBreg(priv, UFWP, bMaskByte1, 0x8); // FW DIG OFF
rtl8192_setBBreg(priv, rOFDM0_XAAGCCore1, BitMask, (u32)priv->initgain_backup.xaagccore1);
rtl8192_setBBreg(priv, rOFDM0_XBAGCCore1, BitMask, (u32)priv->initgain_backup.xbagccore1);
rtl8192_setBBreg(priv, rOFDM0_XCAGCCore1, BitMask, (u32)priv->initgain_backup.xcagccore1);
rtl8192_setBBreg(priv, rOFDM0_XDAGCCore1, BitMask, (u32)priv->initgain_backup.xdagccore1);
BitMask = bMaskByte2;
rtl8192_setBBreg(priv, rCCK0_CCA, BitMask, (u32)priv->initgain_backup.cca);
RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc50 is %x\n",priv->initgain_backup.xaagccore1);
RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc58 is %x\n",priv->initgain_backup.xbagccore1);
RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc60 is %x\n",priv->initgain_backup.xcagccore1);
RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xc68 is %x\n",priv->initgain_backup.xdagccore1);
RT_TRACE(COMP_SCAN, "Scan BBInitialGainRestore 0xa0a is %x\n",priv->initgain_backup.cca);
rtl8192_phy_setTxPower(priv, priv->ieee80211->current_network.channel);
if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM)
rtl8192_setBBreg(priv, UFWP, bMaskByte1, 0x1); // FW DIG ON
break;
default:
RT_TRACE(COMP_SCAN, "Unknown IG Operation.\n");
break;
}
}
}
#ifndef _R819XU_PHY_H
#define _R819XU_PHY_H
/* Channel switch: the size of command tables for switch channel */
#define MAX_PRECMD_CNT 16
#define MAX_RFDEPENDCMD_CNT 16
#define MAX_POSTCMD_CNT 16
#define MACPHY_Array_PGLength 30
#define Rtl819XMACPHY_Array_PG Rtl8192PciEMACPHY_Array_PG
#define Rtl819XMACPHY_Array Rtl8192PciEMACPHY_Array
#define RadioC_ArrayLength 1
#define RadioD_ArrayLength 1
#define Rtl819XRadioA_Array Rtl8192PciERadioA_Array
#define Rtl819XRadioB_Array Rtl8192PciERadioB_Array
#define Rtl819XRadioC_Array Rtl8192PciERadioC_Array
#define Rtl819XRadioD_Array Rtl8192PciERadioD_Array
#define Rtl819XAGCTAB_Array Rtl8192PciEAGCTAB_Array
#define PHY_REGArrayLength 1
#define Rtl819XPHY_REGArray Rtl8192PciEPHY_REGArray
#define PHY_REG_1T2RArrayLength 296
#define Rtl819XPHY_REG_1T2RArray Rtl8192PciEPHY_REG_1T2RArray
#define AGCTAB_ArrayLength 384
#define MACPHY_ArrayLength 18
#define RadioA_ArrayLength 246
#define RadioB_ArrayLength 78
typedef enum _SwChnlCmdID {
CmdID_End,
CmdID_SetTxPowerLevel,
CmdID_BBRegWrite10,
CmdID_WritePortUlong,
CmdID_WritePortUshort,
CmdID_WritePortUchar,
CmdID_RF_WriteReg,
} SwChnlCmdID;
/* switch channel data structure */
typedef struct _SwChnlCmd {
SwChnlCmdID CmdID;
u32 Para1;
u32 Para2;
u32 msDelay;
} __attribute__ ((packed)) SwChnlCmd;
extern u32 rtl819XMACPHY_Array_PG[];
extern u32 rtl819XPHY_REG_1T2RArray[];
extern u32 rtl819XAGCTAB_Array[];
extern u32 rtl819XRadioA_Array[];
extern u32 rtl819XRadioB_Array[];
extern u32 rtl819XRadioC_Array[];
extern u32 rtl819XRadioD_Array[];
typedef enum _HW90_BLOCK {
HW90_BLOCK_MAC = 0,
HW90_BLOCK_PHY0 = 1,
HW90_BLOCK_PHY1 = 2,
HW90_BLOCK_RF = 3,
/* Don't ever use this. */
HW90_BLOCK_MAXIMUM = 4,
} HW90_BLOCK_E, *PHW90_BLOCK_E;
typedef enum _RF90_RADIO_PATH {
/* Radio paths */
RF90_PATH_A = 0,
RF90_PATH_B = 1,
RF90_PATH_C = 2,
RF90_PATH_D = 3,
/* Max RF number 92 support */
RF90_PATH_MAX
} RF90_RADIO_PATH_E, *PRF90_RADIO_PATH_E;
#define bMaskByte0 0xff
#define bMaskByte1 0xff00
#define bMaskByte2 0xff0000
#define bMaskByte3 0xff000000
#define bMaskHWord 0xffff0000
#define bMaskLWord 0x0000ffff
#define bMaskDWord 0xffffffff
u8 rtl8192_phy_CheckIsLegalRFPath(struct r8192_priv *priv, u32 eRFPath);
void rtl8192_setBBreg(struct r8192_priv *priv, u32 dwRegAddr,
u32 dwBitMask, u32 dwData);
u32 rtl8192_QueryBBReg(struct r8192_priv *priv, u32 dwRegAddr,
u32 dwBitMask);
void rtl8192_phy_SetRFReg(struct r8192_priv *priv,
RF90_RADIO_PATH_E eRFPath, u32 RegAddr,
u32 BitMask, u32 Data);
u32 rtl8192_phy_QueryRFReg(struct r8192_priv *priv,
RF90_RADIO_PATH_E eRFPath, u32 RegAddr, u32 BitMask);
void rtl8192_phy_configmac(struct r8192_priv *priv);
void rtl8192_phyConfigBB(struct r8192_priv *priv, u8 ConfigType);
RT_STATUS rtl8192_phy_checkBBAndRF(struct r8192_priv *priv,
HW90_BLOCK_E CheckBlock, RF90_RADIO_PATH_E eRFPath);
RT_STATUS rtl8192_BBConfig(struct r8192_priv *priv);
void rtl8192_phy_getTxPower(struct r8192_priv *priv);
void rtl8192_phy_setTxPower(struct r8192_priv *priv, u8 channel);
RT_STATUS rtl8192_phy_RFConfig(struct r8192_priv *priv);
void rtl8192_phy_updateInitGain(struct r8192_priv *priv);
u8 rtl8192_phy_ConfigRFWithHeaderFile(struct r8192_priv *priv,
RF90_RADIO_PATH_E eRFPath);
u8 rtl8192_phy_SwChnl(struct ieee80211_device *ieee80211, u8 channel);
void rtl8192_SetBWMode(struct ieee80211_device *ieee80211,
HT_CHANNEL_WIDTH Bandwidth, HT_EXTCHNL_OFFSET Offset);
void rtl8192_SwChnl_WorkItem(struct r8192_priv *priv);
void rtl8192_SetBWModeWorkItem(struct r8192_priv *priv);
void InitialGain819xPci(struct ieee80211_device *ieee, u8 Operation);
#endif /* _R819XU_PHY_H */
What this layer should do
- It mantain the old mechanism as alternative, so the
ipw2100 driver works with really few changes.
- Encapsulate / Decapsulate rtllib packet
- Handle fragmentation
- Optionally provide an alterantive mechanism for netif queue stop/wake,
so that the rtllib layer will pass one fragment per time instead of
one txb struct per time. so the driver can stop the queue in the middle
of a packet.
- Provide two different TX interfaces for cards that can handle management
frames on one HW queue, and data on another, and for cards that have only
one HW queue (the latter untested and very, very rough).
- Optionally provide the logic for handling IBSS/MASTER/MONITOR/BSS modes
and for the channel, essid and wap get/set wireless extension requests.
so that the driver has only to change channel when the ieee stack tell it.
- Optionally provide a scanning mechanism so that the driver has not to
worry about this, just implement the set channel calback and pass
frames to the upper layer
- Optionally provide the bss client protocol handshaking (just with open
authentication)
- Optionally provide the probe request send mechanism
- Optionally provide the bss master mode logic to handle association
protocol (only open authentication) and probe responses.
- SW wep encryption (with open authentication)
- It collects some stats
- It provides beacons to the card when it ask for them
What this layer doesn't do (yet)
- Perform shared authentication
- Have full support for master mode (the AP should loop back in the air
frames from an associated client to another. This could be done easily
with few lines of code, and it is done in my previous version of the
stach, but a table of association must be keept and a disassociation
policy must be decided and implemented.
- Handle cleanly the full ieee 802.11 protocol. In AP mode it never
disassociate clients, and it is really prone to always allow access.
In bss client mode it is a bit rough with AP deauth and disassoc requests.
- It has not any entry point to view the collected stats.
- Altought it takes care of the card supported rates in the management frame
it sends, support for rate changing on TXed packet is not complete.
- Give up once associated in bss client mode (it never detect a
signal loss condition to disassociate and restart scanning)
- Provide a mechanism for enabling the TX in monitor mode, so
userspace programs can TX raw packets.
- Provide a mechanism for cards that need that the SW take care of beacon
TX completely, in sense that the SW has to enqueue by itself beacons
to the card so it TX them (if any...)
APIs
Callback functions in the original stack has been mantained.
following has been added (from rtllib.h)
/* Softmac-generated frames (mamagement) are TXed via this
* callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
* not set. As some cards may have different HW queues that
* one might want to use for data and management frames
* the option to have two callbacks might be useful.
* This fucntion can't sleep.
*/
int (*softmac_hard_start_xmit)(struct sk_buff *skb,
struct net_device *dev);
/* used instead of hard_start_xmit (not softmac_hard_start_xmit)
* if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
* frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
* then also management frames are sent via this callback.
* This function can't sleep.
*/
void (*softmac_data_hard_start_xmit)(struct sk_buff *skb,
struct net_device *dev);
/* stops the HW queue for DATA frames. Useful to avoid
* waste time to TX data frame when we are reassociating
* This function can sleep.
*/
void (*data_hard_stop)(struct net_device *dev);
/* OK this is complementar to data_poll_hard_stop */
void (*data_hard_resume)(struct net_device *dev);
/* ask to the driver to retune the radio .
* This function can sleep. the driver should ensure
* the radio has been swithced before return.
*/
void (*set_chan)(struct net_device *dev,short ch);
/* These are not used if the ieee stack takes care of
* scanning (IEEE_SOFTMAC_SCAN feature set).
* In this case only the set_chan is used.
*
* The syncro version is similar to the start_scan but
* does not return until all channels has been scanned.
* this is called in user context and should sleep,
* it is called in a work_queue when swithcing to ad-hoc mode
* or in behalf of iwlist scan when the card is associated
* and root user ask for a scan.
* the fucntion stop_scan should stop both the syncro and
* background scanning and can sleep.
* The fucntion start_scan should initiate the background
* scanning and can't sleep.
*/
void (*scan_syncro)(struct net_device *dev);
void (*start_scan)(struct net_device *dev);
void (*stop_scan)(struct net_device *dev);
/* indicate the driver that the link state is changed
* for example it may indicate the card is associated now.
* Driver might be interested in this to apply RX filter
* rules or simply light the LINK led
*/
void (*link_change)(struct net_device *dev);
Functions hard_data_[resume/stop] are optional and should not be used
if the driver decides to uses data+management frames enqueue in a
single HQ queue (thus using just the softmac_hard_data_start_xmit
callback).
Function that the driver can use are:
rtllib_get_beacon - this is called by the driver when
the HW needs a beacon.
rtllib_softmac_start_protocol - this should normally be called in the
driver open function
rtllib_softmac_stop_protocol - the opposite of the above
rtllib_wake_queue - this is similar to netif_wake_queue
rtllib_reset_queue - this throw away fragments pending(if any)
rtllib_stop_queue - this is similar to netif_stop_queue
known BUGS:
- When performing syncro scan (possiblily when swithcing to ad-hoc mode
and when running iwlist scan when associated) there is still an odd
behaviour.. I have not looked in this more accurately (yet).
locking:
locking is done by means of three structures.
1- ieee->lock (by means of spin_[un]lock_irq[save/restore]
2- ieee->wx_sem
3- ieee->scan_sem
the lock 1 is what protect most of the critical sections in the ieee stack.
the lock 2 is used to avoid that more than one of the SET wireless extension
handlers (as well as start/stop protocol function) are running at the same time.
the lock 1 is used when we need to modify or read the shared data in the wx handlers.
In other words the lock 2 will prevent one SET action will run across another SET
action (by make sleep the 2nd one) but allow GET actions, while the lock 1
make atomic those little shared data access in both GET and SET operation.
So get operation will be never be delayed really: they will never sleep..
Furthermore in the top of some SET operations a flag is set before acquiring
the lock. This is an help to make the previous running SET operation to
finish faster if needed (just in case the second one will totally undo the
first, so there is not need to complete the 1st really.. ).
The background scanning mechaninsm is protected by the lock 1 except for the
workqueue. this wq is here just to let the set_chan callback sleep (I thinked it
might be appreciated by USB network card driver developer). In this case the lock 3
take its turn.
Thus the stop function needs both the locks.
Funny in the syncro scan the lock 2 play its role (as both the syncro_scan
function and the stop scan function are called with this semaphore held).
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment