immortalwrt/package/jsda/rtl8192du/hal/rtl8192d_cmd.c
2019-07-02 18:06:49 +08:00

1159 lines
32 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
*
* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
*
******************************************************************************/
#define _RTL8192D_CMD_C_
#include <drv_conf.h>
#include <osdep_service.h>
#include <drv_types.h>
#include <recv_osdep.h>
#include <cmd_osdep.h>
#include <mlme_osdep.h>
#include <rtw_byteorder.h>
#include <circ_buf.h>
#include <rtw_ioctl_set.h>
#include <rtl8192d_hal.h>
static BOOLEAN
CheckWriteH2C(
PADAPTER Adapter,
u8 BoxNum
)
{
u8 valHMETFR;
BOOLEAN Result = _FALSE;
valHMETFR = rtw_read8(Adapter, REG_HMETFR);
//DbgPrint("CheckWriteH2C(): Reg[0x%2x] = %x\n",REG_HMETFR, valHMETFR);
if(((valHMETFR>>BoxNum)&BIT0) == 1)
Result = _TRUE;
return Result;
}
static BOOLEAN
CheckFwReadLastH2C(
PADAPTER Adapter,
u8 BoxNum
)
{
u8 valHMETFR;
BOOLEAN Result = _FALSE;
valHMETFR = rtw_read8(Adapter, REG_HMETFR);
//RT_TRACE(COMP_INIT,DBG_LOUD,("REG[%x] = %x\n", REG_HMETFR, valHMETFR));
// Do not seperate to 91C and 88C, we use the same setting. Suggested by SD4 Filen. 2009.12.03.
if(((valHMETFR>>BoxNum)&BIT0) == 0)
Result = _TRUE;
return Result;
}
//
// Description:
// Fill H2C command
// BOX_0-4 Format:
// bit [31-8] | 7 | [6-0]
// RSVD | CMD_EXT | CMD_ID
//
// BOX Extension 0-4 format:
// bit 15-0: RSVD
//
/*****************************************
* H2C Msg format :
*| 31 - 8 |7 | 6 - 0 |
*| h2c_msg |Ext_bit |CMD_ID |
*
******************************************/
static void _FillH2CCmd92D(_adapter* padapter, u8 ElementID, u32 CmdLen, u8* pCmdBuffer)
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
u8 BoxNum;
u16 BOXReg=0, BOXExtReg=0;
u8 BoxContent[4], BoxExtContent[2];
u8 BufIndex=0;
u8 U1btmp; //Read 0x1bf
u8 bWriteSucess = _FALSE;
u8 IsFwRead = _FALSE;
u8 WaitH2cLimmit = 100;
u8 WaitWriteH2cLimmit = 100;
u8 idx=0;
_func_enter_;
padapter = GET_PRIMARY_ADAPTER(padapter);
pHalData = GET_HAL_DATA(padapter);
_enter_critical_mutex(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex), NULL);
//DBG_8192C("FillH2CCmd : ElementID=%d \n",ElementID);
while(!bWriteSucess)
{
WaitWriteH2cLimmit--;
if(WaitWriteH2cLimmit == 0)
{
DBG_8192C("FillH2CCmd92D():Write H2C fail because no trigger for FW INT!!!!!!!!\n");
break;
}
// 2. Find the last BOX number which has been writen.
BoxNum = pHalData->LastHMEBoxNum;
switch(BoxNum)
{
case 0:
BOXReg = REG_HMEBOX_0;
BOXExtReg = REG_HMEBOX_EXT_0;
break;
case 1:
BOXReg = REG_HMEBOX_1;
BOXExtReg = REG_HMEBOX_EXT_1;
break;
case 2:
BOXReg = REG_HMEBOX_2;
BOXExtReg = REG_HMEBOX_EXT_2;
break;
case 3:
BOXReg = REG_HMEBOX_3;
BOXExtReg = REG_HMEBOX_EXT_3;
break;
default:
break;
}
// 3. Check if the box content is empty.
IsFwRead = CheckFwReadLastH2C(padapter, BoxNum);
while(!IsFwRead)
{
//wait until Fw read
WaitH2cLimmit--;
if(WaitH2cLimmit == 0)
{
DBG_8192C("FillH2CCmd92D(): Wating too long for FW read clear HMEBox(%d)!!!\n", BoxNum);
break;
}
rtw_udelay_os(10); //us
IsFwRead = CheckFwReadLastH2C(padapter, BoxNum);
U1btmp = rtw_read8(padapter, 0x1BF);
//DBG_8192C("FillH2CCmd92D(): Wating for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n", BoxNum, U1btmp);
}
// If Fw has not read the last H2C cmd, break and give up this H2C.
if(!IsFwRead)
{
DBG_8192C("FillH2CCmd92D(): Write H2C register BOX[%d] fail!!!!! Fw do not read. \n", BoxNum);
break;
}
// 4. Fill the H2C cmd into box
_rtw_memset(BoxContent, 0, sizeof(BoxContent));
_rtw_memset(BoxExtContent, 0, sizeof(BoxExtContent));
BoxContent[0] = ElementID; // Fill element ID
//DBG_8192C("FillH2CCmd92D():Write ElementID BOXReg(%4x) = %2x \n", BOXReg, ElementID);
switch(CmdLen)
{
case 1:
{
BoxContent[0] &= ~(BIT7);
_rtw_memcpy((u8 *)(BoxContent)+1, pCmdBuffer+BufIndex, 1);
//PlatformEFIOWrite4Byte(Adapter, BOXReg, *((pu4Byte)BoxContent));
//For Endian Free.
for(idx= 0; idx < 4; idx++)
{
rtw_write8(padapter, BOXReg+idx, BoxContent[idx]);
}
break;
}
case 2:
{
BoxContent[0] &= ~(BIT7);
_rtw_memcpy((u8 *)(BoxContent)+1, pCmdBuffer+BufIndex, 2);
//PlatformEFIOWrite4Byte(Adapter, BOXReg, *((pu4Byte)BoxContent));
for(idx=0; idx < 4; idx++)
{
rtw_write8(padapter, BOXReg+idx, BoxContent[idx]);
}
break;
}
case 3:
{
BoxContent[0] &= ~(BIT7);
_rtw_memcpy((u8 *)(BoxContent)+1, pCmdBuffer+BufIndex, 3);
//PlatformEFIOWrite4Byte(Adapter, BOXReg, *((pu4Byte)BoxContent));
for(idx = 0; idx < 4 ; idx++)
{
rtw_write8(padapter, BOXReg+idx, BoxContent[idx]);
}
break;
}
case 4:
{
BoxContent[0] |= (BIT7);
_rtw_memcpy((u8 *)(BoxExtContent), pCmdBuffer+BufIndex, 2);
_rtw_memcpy((u8 *)(BoxContent)+1, pCmdBuffer+BufIndex+2, 2);
//PlatformEFIOWrite2Byte(Adapter, BOXExtReg, *((pu2Byte)BoxExtContent));
//PlatformEFIOWrite4Byte(Adapter, BOXReg, *((pu4Byte)BoxContent));
for(idx = 0 ; idx < 2 ; idx ++)
{
rtw_write8(padapter, BOXExtReg+idx, BoxExtContent[idx]);
}
for(idx = 0 ; idx < 4 ; idx ++)
{
rtw_write8(padapter, BOXReg+idx, BoxContent[idx]);
}
break;
}
case 5:
{
BoxContent[0] |= (BIT7);
_rtw_memcpy((u8 *)(BoxExtContent), pCmdBuffer+BufIndex, 2);
_rtw_memcpy((u8 *)(BoxContent)+1, pCmdBuffer+BufIndex+2, 3);
//PlatformEFIOWrite2Byte(Adapter, BOXExtReg, *((pu2Byte)BoxExtContent));
//PlatformEFIOWrite4Byte(Adapter, BOXReg, *((pu4Byte)BoxContent));
for(idx = 0 ; idx < 2 ; idx ++)
{
rtw_write8(padapter, BOXExtReg+idx, BoxExtContent[idx]);
}
for(idx = 0 ; idx < 4 ; idx ++)
{
rtw_write8(padapter, BOXReg+idx, BoxContent[idx]);
}
break;
}
default:
break;
}
//DBG_8192C("FillH2CCmd(): BoxExtContent=0x%04x\n", *(u16*)BoxExtContent);
//DBG_8192C("FillH2CCmd(): BoxContent=0x%08x\n", *(u32*)BoxContent);
// 5. Normal chip does not need to check if the H2C cmd has be written successfully.
// 92D test chip does not need to check,
bWriteSucess = _TRUE;
// Record the next BoxNum
pHalData->LastHMEBoxNum = BoxNum+1;
if(pHalData->LastHMEBoxNum == 4) // loop to 0
pHalData->LastHMEBoxNum = 0;
//DBG_8192C("FillH2CCmd92D():pHalData->LastHMEBoxNum = %d\n", pHalData->LastHMEBoxNum);
}
_exit_critical_mutex(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex), NULL);
_func_exit_;
}
VOID
FillH2CCmd92D(
PADAPTER Adapter,
u8 ElementID,
u32 CmdLen,
u8* pCmdBuffer
)
{
u32 tmpCmdBuf[2];
//Adapter = ADJUST_TO_ADAPTIVE_ADAPTER(Adapter, TRUE);
if(Adapter->bFWReady == _FALSE)
{
DBG_8192C("FillH2CCmd92D(): return H2C cmd because of Fw download fail!!!\n");
return;
}
_rtw_memset(tmpCmdBuf, 0, 8);
_rtw_memcpy(tmpCmdBuf, pCmdBuffer, CmdLen);
_FillH2CCmd92D(Adapter, ElementID, CmdLen, (u8 *)&tmpCmdBuf);
return;
}
u8 rtl8192d_h2c_msg_hdl(_adapter *padapter, unsigned char *pbuf);
u8 rtl8192d_h2c_msg_hdl(_adapter *padapter, unsigned char *pbuf)
{
u8 ElementID, CmdLen;
u8 *pCmdBuffer;
struct cmd_msg_parm *pcmdmsg;
if(!pbuf)
return H2C_PARAMETERS_ERROR;
pcmdmsg = (struct cmd_msg_parm*)pbuf;
ElementID = pcmdmsg->eid;
CmdLen = pcmdmsg->sz;
pCmdBuffer = pcmdmsg->buf;
FillH2CCmd92D(padapter, ElementID, CmdLen, pCmdBuffer);
return H2C_SUCCESS;
}
u8 rtl8192d_set_raid_cmd(_adapter*padapter, u32 mask, u8 arg)
{
u8 buf[5];
u8 res=_SUCCESS;
_func_enter_;
_rtw_memset(buf, 0, 5);
mask = cpu_to_le32( mask );
_rtw_memcpy(buf, &mask, 4);
buf[4] = arg;
FillH2CCmd92D(padapter, H2C_RA_MASK, 5, buf);
_func_exit_;
return res;
}
//bitmap[0:27] = tx_rate_bitmap
//bitmap[28:31]= Rate Adaptive id
//arg[0:4] = macid
//arg[5] = Short GI
void rtl8192d_Add_RateATid(PADAPTER pAdapter, u32 bitmap, u8 arg)
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter);
if(pHalData->fw_ractrl == _TRUE)
{
rtl8192d_set_raid_cmd(pAdapter, bitmap, arg);
}
else
{
u8 macid, init_rate, shortGIrate=_FALSE;
init_rate = get_highest_rate_idx(bitmap&0x0fffffff)&0x3f;
macid = arg&0x1f;
shortGIrate = (arg&BIT(5)) ? _TRUE:_FALSE;
if (shortGIrate==_TRUE)
init_rate |= BIT(6);
rtw_write8(pAdapter, (REG_INIDATA_RATE_SEL+macid), (u8)init_rate);
}
}
void rtl8192d_set_FwPwrMode_cmd(_adapter*padapter, u8 Mode)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
u8 u1H2CSetPwrMode[3]={0};
u8 beacon_interval = 1;
_func_enter_;
DBG_871X("%s(): Mode = %d, SmartPS = %d\n", __FUNCTION__,Mode,pwrpriv->smart_ps);
SET_H2CCMD_PWRMODE_PARM_MODE(u1H2CSetPwrMode, Mode);
SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1H2CSetPwrMode, pwrpriv->smart_ps);
SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1H2CSetPwrMode, beacon_interval);
FillH2CCmd92D(padapter, H2C_SETPWRMODE, 3, u1H2CSetPwrMode);
_func_exit_;
}
void ConstructBeacon(_adapter *padapter, u8 *pframe, u32 *pLength);
void ConstructBeacon(_adapter *padapter, u8 *pframe, u32 *pLength)
{
struct rtw_ieee80211_hdr *pwlanhdr;
u16 *fctrl;
u32 rate_len, pktlen;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network);
u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
//DBG_871X("%s\n", __FUNCTION__);
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
_rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
SetFrameSubType(pframe, WIFI_BEACON);
pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
pktlen = sizeof (struct rtw_ieee80211_hdr_3addr);
//timestamp will be inserted by hardware
pframe += 8;
pktlen += 8;
// beacon interval: 2 bytes
_rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
pframe += 2;
pktlen += 2;
// capability info: 2 bytes
_rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
pframe += 2;
pktlen += 2;
if( (pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)
{
DBG_871X("ie len=%u\n", cur_network->IELength);
pktlen += cur_network->IELength - sizeof(NDIS_802_11_FIXED_IEs);
_rtw_memcpy(pframe, cur_network->IEs+sizeof(NDIS_802_11_FIXED_IEs), pktlen);
goto _ConstructBeacon;
}
//below for ad-hoc mode
// SSID
pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen);
// supported rates...
rate_len = rtw_get_rateset_len(cur_network->SupportedRates);
pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8)? 8: rate_len), cur_network->SupportedRates, &pktlen);
// DS parameter set
pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen);
if( (pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)
{
u32 ATIMWindow;
// IBSS Parameter Set...
//ATIMWindow = cur->Configuration.ATIMWindow;
ATIMWindow = 0;
pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen);
}
//todo: ERP IE
// EXTERNDED SUPPORTED RATE
if (rate_len > 8)
{
pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen);
}
//todo:HT for adhoc
_ConstructBeacon:
if ((pktlen + TXDESC_SIZE) > 512)
{
DBG_871X("beacon frame too large\n");
return;
}
*pLength = pktlen;
//DBG_871X("%s bcn_sz=%u\n", __FUNCTION__, pktlen);
}
void ConstructPSPoll(_adapter *padapter, u8 *pframe, u32 *pLength);
void ConstructPSPoll(_adapter *padapter, u8 *pframe, u32 *pLength)
{
struct rtw_ieee80211_hdr *pwlanhdr;
u16 *fctrl;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
//DBG_871X("%s\n", __FUNCTION__);
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
// Frame control.
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
SetPwrMgt(fctrl);
SetFrameSubType(pframe, WIFI_PSPOLL);
// AID.
SetDuration(pframe, (pmlmeinfo->aid| 0xc000));
// BSSID.
_rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
// TA.
_rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
*pLength = 16;
}
void ConstructNullFunctionData(_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, BOOLEAN bForcePowerSave);
void ConstructNullFunctionData(_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, BOOLEAN bForcePowerSave)
{
struct rtw_ieee80211_hdr *pwlanhdr;
u16 *fctrl;
u32 pktlen;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_network *cur_network = &pmlmepriv->cur_network;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
//DBG_871X("%s:%d\n", __FUNCTION__, bForcePowerSave);
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
if (bForcePowerSave)
{
SetPwrMgt(fctrl);
}
switch(cur_network->network.InfrastructureMode)
{
case Ndis802_11Infrastructure:
SetToDs(fctrl);
_rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
break;
case Ndis802_11APMode:
SetFrDs(fctrl);
_rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
break;
case Ndis802_11IBSS:
default:
_rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
break;
}
SetSeqNum(pwlanhdr, 0);
SetFrameSubType(pframe, WIFI_DATA_NULL);
pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
*pLength = pktlen;
}
void ConstructProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, BOOLEAN bHideSSID);
void ConstructProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, BOOLEAN bHideSSID)
{
struct rtw_ieee80211_hdr *pwlanhdr;
u16 *fctrl;
u8 *mac, *bssid;
u32 pktlen;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network);
//DBG_871X("%s\n", __FUNCTION__);
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
mac = myid(&(padapter->eeprompriv));
bssid = cur_network->MacAddress;
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
_rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
_rtw_memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
SetSeqNum(pwlanhdr, 0);
SetFrameSubType(fctrl, WIFI_PROBERSP);
pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
pframe += pktlen;
if(cur_network->IELength>MAX_IE_SZ)
return;
_rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength);
pframe += cur_network->IELength;
pktlen += cur_network->IELength;
*pLength = pktlen;
}
//
// Description: In normal chip, we should send some packet to Hw which will be used by Fw
// in FW LPS mode. The function is to fill the Tx descriptor of this packets, then
// Fw can tell Hw to send these packet derectly.
// Added by tynli. 2009.10.15.
//
static VOID
FillFakeTxDescriptor92D(
PADAPTER Adapter,
u8* pDesc,
u32 BufferLen,
BOOLEAN IsPsPoll
)
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
struct tx_desc *ptxdesc = (struct tx_desc *)pDesc;
// Clear all status
_rtw_memset(pDesc, 0, 32);
//offset 0
ptxdesc->txdw0 |= cpu_to_le32( OWN | FSG | LSG); //own, bFirstSeg, bLastSeg;
ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); //32 bytes for TX Desc
ptxdesc->txdw0 |= cpu_to_le32(BufferLen&0x0000ffff); // Buffer size + command header
//offset 4
ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT<<QSEL_SHT)&0x00001f00); // Fixed queue of Mgnt queue
//Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error vlaue by Hw.
if(IsPsPoll)
{
ptxdesc->txdw1 |= cpu_to_le32(NAVUSEHDR);
}
else
{
ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); // Hw set sequence number
ptxdesc->txdw3 |= cpu_to_le32((8 <<28)); //set bit3 to 1. Suugested by TimChen. 2009.12.29.
}
//offset 16
ptxdesc->txdw4 |= cpu_to_le32(BIT(8));//driver uses rate
if(pHalData->CurrentBandType92D == BAND_ON_5G)
ptxdesc->txdw5 |= cpu_to_le32(BIT(2));// use OFDM 6Mbps
// USB interface drop packet if the checksum of descriptor isn't correct.
// Using this checksum can let hardware recovery from packet bulk out error (e.g. Cancel URC, Bulk out error.).
rtl8192du_cal_txdesc_chksum(ptxdesc);
RT_PRINT_DATA(_module_rtl8712_cmd_c_, _drv_info_, "FillFakeTxDescriptor92D(): H2C Tx Desc Content ----->\n", pDesc, TXDESC_SIZE);
}
//
// Description: Fill the reserved packets that FW will use to RSVD page.
// Now we just send 4 types packet to rsvd page.
// (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp.
// Input:
// bDLFinished - FALSE: At the first time we will send all the packets as a large packet to Hw,
// so we need to set the packet length to total lengh.
// TRUE: At the second time, we should send the first packet (default:beacon)
// to Hw again and set the lengh in descriptor to the real beacon lengh.
// 2009.10.15 by tynli.
void SetFwRsvdPagePkt(PADAPTER Adapter, BOOLEAN bDLFinished);
void SetFwRsvdPagePkt(PADAPTER Adapter, BOOLEAN bDLFinished)
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
struct xmit_frame *pmgntframe;
struct pkt_attrib *pattrib;
struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
u32 BeaconLength, ProbeRspLength, PSPollLength, NullFunctionDataLength;
u8 *ReservedPagePacket;
u8 PageNum=0, U1bTmp, TxDescLen=0, TxDescOffset=0;
u16 BufIndex=0;
u32 TotalPacketLen;
u8 u1RsvdPageLoc[3]={0};
BOOLEAN bDLOK = _FALSE;
DBG_871X("%s\n", __FUNCTION__);
ReservedPagePacket = (u8*)rtw_malloc(1000);
if(ReservedPagePacket == NULL){
DBG_871X("%s(): alloc ReservedPagePacket fail !!!\n", __FUNCTION__);
return;
}
_rtw_memset(ReservedPagePacket, 0, 1000);
TxDescLen = 32;//TX_DESC_SIZE;
BufIndex = TXDESC_OFFSET;
TxDescOffset = TxDescLen + PACKET_OFFSET_SZ;;
//(1) beacon
ConstructBeacon(Adapter,&ReservedPagePacket[BufIndex],&BeaconLength);
RT_PRINT_DATA(_module_rtl8712_cmd_c_, _drv_info_,
"SetFwRsvdPagePkt(): HW_VAR_SET_TX_CMD: BCN\n",
&ReservedPagePacket[BufIndex], (BeaconLength+BufIndex));
//--------------------------------------------------------------------
// When we count the first page size, we need to reserve description size for the RSVD
// packet, it will be filled in front of the packet in TXPKTBUF.
U1bTmp = (u8)PageNum_128(BeaconLength+TxDescLen);
PageNum += U1bTmp;
// To reserved 2 pages for beacon buffer. 2010.06.24.
if(PageNum == 1)
PageNum+=1;
pHalData->FwRsvdPageStartOffset = PageNum;
BufIndex = (PageNum*128) + TxDescOffset;
//(2) ps-poll
ConstructPSPoll(Adapter, &ReservedPagePacket[BufIndex],&PSPollLength);
FillFakeTxDescriptor92D(Adapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, _TRUE);
RT_PRINT_DATA(_module_rtl8712_cmd_c_, _drv_info_,
"SetFwRsvdPagePkt(): HW_VAR_SET_TX_CMD: PS-POLL\n",
&ReservedPagePacket[BufIndex-TxDescLen], (PSPollLength+TxDescLen));
SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PageNum );
//------------------------------------------------------------------
U1bTmp = (u8)PageNum_128(PSPollLength+TxDescLen);
PageNum += U1bTmp;
BufIndex = (PageNum*128) + TxDescOffset;
//(3) null data
ConstructNullFunctionData(
Adapter,
&ReservedPagePacket[BufIndex],
&NullFunctionDataLength,
get_my_bssid(&(pmlmeinfo->network)),
_FALSE);
FillFakeTxDescriptor92D(Adapter, &ReservedPagePacket[BufIndex-TxDescLen], NullFunctionDataLength, _FALSE);
SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, PageNum);
RT_PRINT_DATA(_module_rtl8712_cmd_c_, _drv_info_,
"SetFwRsvdPagePkt(): HW_VAR_SET_TX_CMD: NULL DATA \n",
&ReservedPagePacket[BufIndex-TxDescLen], (NullFunctionDataLength+TxDescLen));
//------------------------------------------------------------------
U1bTmp = (u8)PageNum_128(NullFunctionDataLength+TxDescLen);
PageNum += U1bTmp;
BufIndex = (PageNum*128) + TxDescOffset;
//(4) probe response
ConstructProbeRsp(
Adapter,
&ReservedPagePacket[BufIndex],
&ProbeRspLength,
get_my_bssid(&(pmlmeinfo->network)),
_FALSE);
FillFakeTxDescriptor92D(Adapter, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, _FALSE);
SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PageNum);
RT_PRINT_DATA(_module_rtl8712_cmd_c_, _drv_info_,
"SetFwRsvdPagePkt(): HW_VAR_SET_TX_CMD: PROBE RSP \n",
&ReservedPagePacket[BufIndex-TxDescLen], (ProbeRspLength-TxDescLen));
//------------------------------------------------------------------
U1bTmp = (u8)PageNum_128(ProbeRspLength+TxDescLen);
PageNum += U1bTmp;
TotalPacketLen = (PageNum*128);
if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL)
{
return;
}
//update attribute
pattrib = &pmgntframe->attrib;
update_mgntframe_attrib(Adapter, pattrib);
pattrib->qsel = 0x10;
pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TxDescLen;
_rtw_memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
rtw_hal_mgnt_xmit(Adapter, pmgntframe);
bDLOK = _TRUE;
if(bDLOK)
{
DBG_871X("Set RSVD page location to Fw.\n");
FillH2CCmd92D(Adapter, H2C_RSVDPAGE, sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
//FillH2CCmd92D(Adapter, H2C_RSVDPAGE, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
}
rtw_mfree(ReservedPagePacket,1000);
}
void rtl8192d_set_FwJoinBssReport_cmd(_adapter* padapter, u8 mstatus)
{
u8 u1JoinBssRptParm[1]={0};
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
BOOLEAN bRecover = _FALSE;
_func_enter_;
DBG_871X("%s\n", __FUNCTION__);
if(mstatus == 1)
{
// We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C.
// Suggested by filen. Added by tynli.
rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
// Do not set TSF again here or vWiFi beacon DMA INT will not work.
//rtw_hal_set_hwreg(Adapter, HW_VAR_CORRECT_TSF, (pu1Byte)(&bTypeIbss));
// Hw sequende enable by dedault. 2010.06.23. by tynli.
//set REG_CR bit 8
pHalData->RegCR_1 |= BIT0;
rtw_write8(padapter, REG_CR+1, pHalData->RegCR_1);
// Disable Hw protection for a time which revserd for Hw sending beacon.
// Fix download reserved page packet fail that access collision with the protection time.
// 2010.05.11. Added by tynli.
//SetBcnCtrlReg(Adapter, 0, BIT3);
//SetBcnCtrlReg(Adapter, BIT4, 0);
rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL)&(~BIT(3)));
rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL)|BIT(4));
// Set FWHW_TXQ_CTRL 0x422[6]=0 to tell Hw the packet is not a real beacon frame.
if(pHalData->RegFwHwTxQCtrl&BIT6)
bRecover = _TRUE;
rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, (pHalData->RegFwHwTxQCtrl&(~BIT6)));
pHalData->RegFwHwTxQCtrl &= (~BIT6);
SetFwRsvdPagePkt(padapter, 0);
// 2010.05.11. Added by tynli.
//SetBcnCtrlReg(Adapter, BIT3, 0);
//SetBcnCtrlReg(Adapter, 0, BIT4);
rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL)|BIT(3));
rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL)&(~BIT(4)));
// To make sure that if there exists an adapter which would like to send beacon.
// If exists, the origianl value of 0x422[6] will be 1, we should check this to
// prevent from setting 0x422[6] to 0 after download reserved page, or it will cause
// the beacon cannot be sent by HW.
// 2010.06.23. Added by tynli.
if(bRecover)
{
rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, (pHalData->RegFwHwTxQCtrl|BIT6));
pHalData->RegFwHwTxQCtrl |= BIT6;
}
// Clear CR[8] or beacon packet will not be send to TxBuf anymore.
pHalData->RegCR_1 &= (~BIT0);
rtw_write8(padapter, REG_CR+1, pHalData->RegCR_1);
}
SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1JoinBssRptParm, mstatus);
FillH2CCmd92D(padapter, H2C_JOINBSSRPT, 1, u1JoinBssRptParm);
_func_exit_;
}
#ifdef CONFIG_P2P_PS
void rtl8192d_set_p2p_ctw_period_cmd(_adapter* padapter, u8 ctwindow)
{
u8 CTWPeriod = ctwindow;
FillH2CCmd92D(padapter, H2C_P2P_PS_CTW_CMD, 1, (u8 *)(&CTWPeriod));
}
void rtl8192d_set_p2p_ps_offload_cmd(_adapter* padapter, u8 p2p_ps_state)
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct wifidirect_info *pwdinfo = &( padapter->wdinfo );
struct P2P_PS_Offload_t *p2p_ps_offload = &pHalData->p2p_ps_offload;
u8 i;
u16 ctwindow;
u32 start_time, tsf_low;
_func_enter_;
switch(p2p_ps_state)
{
case P2P_PS_DISABLE:
DBG_8192C("P2P_PS_DISABLE \n");
_rtw_memset(p2p_ps_offload, 0 ,1);
break;
case P2P_PS_ENABLE:
DBG_8192C("P2P_PS_ENABLE \n");
// update CTWindow value.
if( pwdinfo->ctwindow > 0 )
{
p2p_ps_offload->CTWindow_En = 1;
ctwindow = pwdinfo->ctwindow;
rtl8192d_set_p2p_ctw_period_cmd(padapter, ctwindow);
//rtw_write16(padapter, REG_ATIMWND, ctwindow);
}
// hw only support 2 set of NoA
for( i=0 ; i<pwdinfo->noa_num ; i++)
{
// To control the register setting for which NOA
rtw_write8(padapter, 0x5CF, (i << 4));
if(i == 0)
p2p_ps_offload->NoA0_En = 1;
else
p2p_ps_offload->NoA1_En = 1;
// config P2P NoA Descriptor Register
rtw_write32(padapter, 0x5E0, pwdinfo->noa_duration[i]);
rtw_write32(padapter, 0x5E4, pwdinfo->noa_interval[i]);
//Get Current TSF value
tsf_low = rtw_read32(padapter, REG_TSFTR);
start_time = pwdinfo->noa_start_time[i];
if(pwdinfo->noa_count[i] != 1)
{
while( start_time <= (tsf_low+(50*1024) ) )
{
start_time += pwdinfo->noa_interval[i];
if(pwdinfo->noa_count[i] != 255)
pwdinfo->noa_count[i]--;
}
}
//DBG_8192C("%s(): start_time = %x\n",__FUNCTION__,start_time);
rtw_write32(padapter, 0x5E8, start_time);
rtw_write8(padapter, 0x5EC, pwdinfo->noa_count[i]);
}
if( (pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0) )
{
// rst p2p circuit
rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(4));
p2p_ps_offload->Offload_En = 1;
if(rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
{
p2p_ps_offload->role= 1;
p2p_ps_offload->AllStaSleep = 0;
}
else
{
p2p_ps_offload->role= 0;
}
p2p_ps_offload->discovery = 0;
}
break;
case P2P_PS_SCAN:
DBG_8192C("P2P_PS_SCAN \n");
p2p_ps_offload->discovery = 1;
break;
case P2P_PS_SCAN_DONE:
DBG_8192C("P2P_PS_SCAN_DONE \n");
p2p_ps_offload->discovery = 0;
pwdinfo->p2p_ps_state = P2P_PS_ENABLE;
break;
default:
break;
}
FillH2CCmd92D(padapter, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
_func_exit_;
}
#endif // CONFIG_P2P_PS
#ifdef CONFIG_TSF_RESET_OFFLOAD
/*
ask FW to Reset sync register at Beacon early interrupt
*/
u8 rtl8192d_reset_tsf(_adapter *padapter, u8 reset_port )
{
u8 buf[2];
u8 res=_SUCCESS;
_func_enter_;
if (IFACE_PORT0==reset_port) {
buf[0] = 0x1; buf[1] = 0;
} else{
buf[0] = 0x0; buf[1] = 0x1;
}
FillH2CCmd92D(padapter, H2C_92D_RESET_TSF, 2, buf);
_func_exit_;
return res;
}
int reset_tsf(PADAPTER Adapter, u8 reset_port )
{
u8 reset_cnt_before = 0, reset_cnt_after = 0, loop_cnt = 0;
u32 reg_reset_tsf_cnt = (IFACE_PORT0==reset_port) ?
REG_FW_RESET_TSF_CNT_0:REG_FW_RESET_TSF_CNT_1;
rtw_scan_abort(Adapter->pbuddy_adapter); /* site survey will cause reset_tsf fail */
reset_cnt_after = reset_cnt_before = rtw_read8(Adapter,reg_reset_tsf_cnt);
rtl8192d_reset_tsf(Adapter, reset_port);
while ((reset_cnt_after == reset_cnt_before ) && (loop_cnt < 10)) {
rtw_msleep_os(100);
loop_cnt++;
reset_cnt_after = rtw_read8(Adapter, reg_reset_tsf_cnt);
}
return(loop_cnt >= 10) ? _FAIL : _TRUE;
}
#endif // CONFIG_TSF_RESET_OFFLOAD
#ifdef CONFIG_WOWLAN
void rtl8192d_set_wowlan_cmd(_adapter* padapter)
{
u8 res=_SUCCESS;
u32 test=0;
struct recv_priv *precvpriv = &padapter->recvpriv;
SETWOWLAN_PARM pwowlan_parm;
struct pwrctrl_priv *pwrpriv=&padapter->pwrctrlpriv;
_func_enter_;
pwowlan_parm.mode =0;
pwowlan_parm.gpio_index=0;
pwowlan_parm.gpio_duration=0;
pwowlan_parm.second_mode =0;
pwowlan_parm.reserve=0;
//pause RX DMA
test = rtw_read8(padapter, REG_RXPKT_NUM+2);
test |= BIT(2);
rtw_write8(padapter, REG_RXPKT_NUM+2, test);
//286 BIT(1) , not 1(means idle) do rx urb
test = rtw_read8(padapter, REG_RXPKT_NUM+2) & BIT(1);
//printk("line(%d) 0x286=%d\n", __LINE__, rtw_read8(padapter, REG_RXPKT_NUM+2));
//check DMA idle?
while(test != BIT(1))
{
tasklet_schedule(&precvpriv->recv_tasklet);
test = rtw_read8(padapter, REG_RXPKT_NUM+2) & BIT(1);
rtw_msleep_os(10);
//printk("line(%d) 0x286=%d\n", __LINE__, test);
}
//mask usb se0 reset by Alex and DD
test = rtw_read8(padapter, 0xf8);
test &= ~(BIT(3)|BIT(4));
rtw_write8(padapter, 0xf8, test);
pwowlan_parm.mode |=FW_WOWLAN_FUN_EN;
//printk("\n %s 1.pwowlan_parm.mode=0x%x \n",__FUNCTION__,pwowlan_parm.mode );
if(pwrpriv->wowlan_pattern ==_TRUE){
pwowlan_parm.mode |= FW_WOWLAN_PATTERN_MATCH;
//printk("\n %s 2.pwowlan_parm.mode=0x%x \n",__FUNCTION__,pwowlan_parm.mode );
}
//if(pwrpriv->wowlan_magic ==_TRUE){
//pwowlan_parm.mode |=FW_WOWLAN_MAGIC_PKT;
//printk("\n %s 3.pwowlan_parm.mode=0x%x \n",__FUNCTION__,pwowlan_parm.mode );
//}
if(pwrpriv->wowlan_unicast ==_TRUE){
pwowlan_parm.mode |=FW_WOWLAN_UNICAST;
//printk("\n %s 4.pwowlan_parm.mode=0x%x \n",__FUNCTION__,pwowlan_parm.mode );
}
rtl8192d_set_FwJoinBssReport_cmd(padapter, 1);
//WOWLAN_GPIO_ACTIVE means GPIO high active
//pwowlan_parm.mode |=FW_WOWLAN_GPIO_ACTIVE;
pwowlan_parm.mode |=FW_WOWLAN_REKEY_WAKEUP;
pwowlan_parm.mode |=FW_WOWLAN_DEAUTH_WAKEUP;
//GPIO 0
pwowlan_parm.gpio_index=0;
//duration unit is 64us
pwowlan_parm.gpio_duration=0xff;
pwowlan_parm.second_mode|=FW_WOWLAN_GPIO_WAKEUP_EN;
pwowlan_parm.second_mode|=FW_FW_PARSE_MAGIC_PKT;
//printk("\n %s 5.pwowlan_parm.mode=0x%x \n",__FUNCTION__,pwowlan_parm.mode );
{ u8 *ptr=(u8 *)&pwowlan_parm;
printk("\n %s H2C_WO_WLAN=%x %02x:%02x:%02x:%02x:%02x \n",__FUNCTION__,H2C_WO_WLAN_CMD,ptr[0],ptr[1],ptr[2],ptr[3],ptr[4] );
}
FillH2CCmd92D(padapter, H2C_WO_WLAN_CMD, 4, (u8 *)&pwowlan_parm);
//keep alive period = 3 * 10 BCN interval
pwowlan_parm.mode =3;
pwowlan_parm.gpio_index=3;
FillH2CCmd92D(padapter, KEEP_ALIVE_CONTROL_CMD, 2, (u8 *)&pwowlan_parm);
printk("%s after KEEP_ALIVE_CONTROL_CMD register 0x81=%x \n",__FUNCTION__,rtw_read8(padapter, 0x85));
pwowlan_parm.mode =1;
pwowlan_parm.gpio_index=0;
pwowlan_parm.gpio_duration=0;
FillH2CCmd92D(padapter, DISCONNECT_DECISION_CTRL_CMD, 3, (u8 *)&pwowlan_parm);
printk("%s after DISCONNECT_DECISION_CTRL_CMD register 0x81=%x \n",__FUNCTION__,rtw_read8(padapter, 0x85));
//enable GPIO wakeup
pwowlan_parm.mode =1;
pwowlan_parm.gpio_index=0;
pwowlan_parm.gpio_duration=0;
FillH2CCmd92D(padapter, REMOTE_WAKE_CTRL_CMD, 1, (u8 *)&pwowlan_parm);
printk("%s after DISCONNECT_DECISION_CTRL_CMD register \n",__FUNCTION__);
_func_exit_;
return ;
}
#endif //CONFIG_WOWLAN