staging: r8723au: Add source files for new driver - part 1

The Realtek USB device RTL8723AU is found in Lenovo Yoga 13 tablets.
A driver for it has been available in a GitHub repo for several months.
This commit contains the first part of the source files. The source
is arbitrarily split to avoid E-mail files that are too large.

Jes Sorensen at RedHat has made many improvements to the vendor code,
and he has been doing the testing. I do not have access to this device.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Jes Sorensen <Jes.Sorensen@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Larry Finger 2014-03-28 21:37:38 -05:00 committed by Greg Kroah-Hartman
parent 8e0c083234
commit 5e93f35209
17 changed files with 35551 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,718 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
#define _RTW_EFUSE_C_
#include <osdep_service.h>
#include <drv_types.h>
#include <rtw_efuse.h>
/*------------------------Define local variable------------------------------*/
/* */
#define REG_EFUSE_CTRL 0x0030
#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */
/* */
/*-----------------------------------------------------------------------------
* Function: Efuse_PowerSwitch23a
*
* Overview: When we want to enable write operation, we should change to
* pwr on state. When we stop write, we should switch to 500k mode
* and disable LDO 2.5V.
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 11/17/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
void
Efuse_PowerSwitch23a(
struct rtw_adapter * pAdapter,
u8 bWrite,
u8 PwrState)
{
pAdapter->HalFunc.EfusePowerSwitch(pAdapter, bWrite, PwrState);
}
/*-----------------------------------------------------------------------------
* Function: efuse_GetCurrentSize23a
*
* Overview: Get current efuse size!!!
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 11/16/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
u16
Efuse_GetCurrentSize23a(struct rtw_adapter *pAdapter, u8 efuseType)
{
u16 ret = 0;
ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType);
return ret;
}
/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */
u8
Efuse_CalculateWordCnts23a(u8 word_en)
{
u8 word_cnts = 0;
if (!(word_en & BIT(0))) word_cnts++; /* 0 : write enable */
if (!(word_en & BIT(1))) word_cnts++;
if (!(word_en & BIT(2))) word_cnts++;
if (!(word_en & BIT(3))) word_cnts++;
return word_cnts;
}
/* */
/* Description: */
/* Execute E-Fuse read byte operation. */
/* Refered from SD1 Richard. */
/* */
/* Assumption: */
/* 1. Boot from E-Fuse and successfully auto-load. */
/* 2. PASSIVE_LEVEL (USB interface) */
/* */
/* Created by Roger, 2008.10.21. */
/* */
void
ReadEFuseByte23a(struct rtw_adapter *Adapter, u16 _offset, u8 *pbuf)
{
u32 value32;
u8 readbyte;
u16 retry;
/* u32 start = rtw_get_current_time(); */
/* Write Address */
rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff));
readbyte = rtw_read8(Adapter, EFUSE_CTRL+2);
rtw_write8(Adapter, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc));
/* Write bit 32 0 */
readbyte = rtw_read8(Adapter, EFUSE_CTRL+3);
rtw_write8(Adapter, EFUSE_CTRL+3, (readbyte & 0x7f));
/* Check bit 32 read-ready */
retry = 0;
value32 = rtw_read32(Adapter, EFUSE_CTRL);
/* while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10)) */
while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10000))
{
value32 = rtw_read32(Adapter, EFUSE_CTRL);
retry++;
}
/* 20100205 Joseph: Add delay suggested by SD1 Victor. */
/* This fix the problem that Efuse read error in high temperature condition. */
/* Designer says that there shall be some delay after ready bit is set, or the */
/* result will always stay on last data we read. */
udelay(50);
value32 = rtw_read32(Adapter, EFUSE_CTRL);
*pbuf = (u8)(value32 & 0xff);
/* DBG_8723A("ReadEFuseByte23a _offset:%08u, in %d ms\n", _offset , rtw_get_passing_time_ms23a(start)); */
}
/* */
/* Description: */
/* 1. Execute E-Fuse read byte operation according as map offset and */
/* save to E-Fuse table. */
/* 2. Refered from SD1 Richard. */
/* */
/* Assumption: */
/* 1. Boot from E-Fuse and successfully auto-load. */
/* 2. PASSIVE_LEVEL (USB interface) */
/* */
/* Created by Roger, 2008.10.21. */
/* */
/* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */
/* 2. Add efuse utilization collect. */
/* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */
/* write addr must be after sec5. */
/* */
void
efuse_ReadEFuse(struct rtw_adapter *Adapter, u8 efuseType,
u16 _offset, u16 _size_byte, u8 *pbuf);
void
efuse_ReadEFuse(struct rtw_adapter *Adapter, u8 efuseType,
u16 _offset, u16 _size_byte, u8 *pbuf)
{
Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset,
_size_byte, pbuf);
}
void
EFUSE_GetEfuseDefinition23a(struct rtw_adapter *pAdapter, u8 efuseType,
u8 type, void *pOut)
{
pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType,
type, pOut);
}
/*-----------------------------------------------------------------------------
* Function: EFUSE_Read1Byte23a
*
* Overview: Copy from WMAC fot EFUSE read 1 byte.
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 09/23/2008 MHC Copy from WMAC.
*
*---------------------------------------------------------------------------*/
u8
EFUSE_Read1Byte23a(struct rtw_adapter *Adapter, u16 Address)
{
u8 data;
u8 Bytetemp = {0x00};
u8 temp = {0x00};
u32 k = 0;
u16 contentLen = 0;
EFUSE_GetEfuseDefinition23a(Adapter, EFUSE_WIFI,
TYPE_EFUSE_REAL_CONTENT_LEN,
(void *)&contentLen);
if (Address < contentLen) /* E-fuse 512Byte */
{
/* Write E-fuse Register address bit0~7 */
temp = Address & 0xFF;
rtw_write8(Adapter, EFUSE_CTRL+1, temp);
Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2);
/* Write E-fuse Register address bit8~9 */
temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);
rtw_write8(Adapter, EFUSE_CTRL+2, temp);
/* Write 0x30[31]= 0 */
Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
temp = Bytetemp & 0x7F;
rtw_write8(Adapter, EFUSE_CTRL+3, temp);
/* Wait Write-ready (0x30[31]= 1) */
Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
while(!(Bytetemp & 0x80))
{
Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
k++;
if (k == 1000)
{
k = 0;
break;
}
}
data = rtw_read8(Adapter, EFUSE_CTRL);
return data;
}
else
return 0xFF;
}/* EFUSE_Read1Byte23a */
/*-----------------------------------------------------------------------------
* Function: EFUSE_Write1Byte
*
* Overview: Copy from WMAC fot EFUSE write 1 byte.
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 09/23/2008 MHC Copy from WMAC.
*
*---------------------------------------------------------------------------*/
void
EFUSE_Write1Byte(
struct rtw_adapter * Adapter,
u16 Address,
u8 Value);
void
EFUSE_Write1Byte(
struct rtw_adapter * Adapter,
u16 Address,
u8 Value)
{
u8 Bytetemp = {0x00};
u8 temp = {0x00};
u32 k = 0;
u16 contentLen = 0;
/* RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr =%x Data =%x\n", Address, Value)); */
EFUSE_GetEfuseDefinition23a(Adapter, EFUSE_WIFI,
TYPE_EFUSE_REAL_CONTENT_LEN,
(void *)&contentLen);
if (Address < contentLen) /* E-fuse 512Byte */
{
rtw_write8(Adapter, EFUSE_CTRL, Value);
/* Write E-fuse Register address bit0~7 */
temp = Address & 0xFF;
rtw_write8(Adapter, EFUSE_CTRL+1, temp);
Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2);
/* Write E-fuse Register address bit8~9 */
temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);
rtw_write8(Adapter, EFUSE_CTRL+2, temp);
/* Write 0x30[31]= 1 */
Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
temp = Bytetemp | 0x80;
rtw_write8(Adapter, EFUSE_CTRL+3, temp);
/* Wait Write-ready (0x30[31]= 0) */
Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
while(Bytetemp & 0x80)
{
Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
k++;
if (k == 100)
{
k = 0;
break;
}
}
}
}/* EFUSE_Write1Byte */
/* 11/16/2008 MH Read one byte from real Efuse. */
u8
efuse_OneByteRead23a(struct rtw_adapter *pAdapter, u16 addr, u8 *data)
{
u8 tmpidx = 0;
u8 bResult;
/* -----------------e-fuse reg ctrl --------------------------------- */
/* address */
rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff));
rtw_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) &0x03)) |
(rtw_read8(pAdapter, EFUSE_CTRL+2)&0xFC));
rtw_write8(pAdapter, EFUSE_CTRL+3, 0x72);/* read cmd */
while(!(0x80 &rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx<100))
tmpidx++;
if (tmpidx < 100) {
*data = rtw_read8(pAdapter, EFUSE_CTRL);
bResult = true;
} else {
*data = 0xff;
bResult = false;
}
return bResult;
}
/* 11/16/2008 MH Write one byte to reald Efuse. */
u8
efuse_OneByteWrite23a(struct rtw_adapter *pAdapter, u16 addr, u8 data)
{
u8 tmpidx = 0;
u8 bResult;
/* RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr = %x Data =%x\n", addr, data)); */
/* return 0; */
/* -----------------e-fuse reg ctrl --------------------------------- */
/* address */
rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff));
rtw_write8(pAdapter, EFUSE_CTRL+2,
(rtw_read8(pAdapter, EFUSE_CTRL+2)&0xFC)|(u8)((addr>>8)&0x03));
rtw_write8(pAdapter, EFUSE_CTRL, data);/* data */
rtw_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */
while((0x80 & rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx<100)) {
tmpidx++;
}
if (tmpidx<100)
{
bResult = true;
}
else
{
bResult = false;
}
return bResult;
}
int
Efuse_PgPacketRead23a(struct rtw_adapter *pAdapter, u8 offset, u8 *data)
{
int ret = 0;
ret = pAdapter->HalFunc.Efuse_PgPacketRead23a(pAdapter, offset, data);
return ret;
}
int
Efuse_PgPacketWrite23a(struct rtw_adapter *pAdapter, u8 offset,
u8 word_en, u8 *data)
{
int ret;
ret = pAdapter->HalFunc.Efuse_PgPacketWrite23a(pAdapter, offset,
word_en, data);
return ret;
}
/*-----------------------------------------------------------------------------
* Function: efuse_WordEnableDataRead23a
*
* Overview: Read allowed word in current efuse section data.
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 11/16/2008 MHC Create Version 0.
* 11/21/2008 MHC Fix Write bug when we only enable late word.
*
*---------------------------------------------------------------------------*/
void
efuse_WordEnableDataRead23a(u8 word_en,
u8 *sourdata,
u8 *targetdata)
{
if (!(word_en&BIT(0)))
{
targetdata[0] = sourdata[0];
targetdata[1] = sourdata[1];
}
if (!(word_en&BIT(1)))
{
targetdata[2] = sourdata[2];
targetdata[3] = sourdata[3];
}
if (!(word_en&BIT(2)))
{
targetdata[4] = sourdata[4];
targetdata[5] = sourdata[5];
}
if (!(word_en&BIT(3)))
{
targetdata[6] = sourdata[6];
targetdata[7] = sourdata[7];
}
}
u8
Efuse_WordEnableDataWrite23a(struct rtw_adapter *pAdapter, u16 efuse_addr,
u8 word_en, u8 *data)
{
u8 ret = 0;
ret = pAdapter->HalFunc.Efuse_WordEnableDataWrite23a(pAdapter, efuse_addr,
word_en, data);
return ret;
}
static u8 efuse_read8(struct rtw_adapter *padapter, u16 address, u8 *value)
{
return efuse_OneByteRead23a(padapter, address, value);
}
static u8 efuse_write8(struct rtw_adapter *padapter, u16 address, u8 *value)
{
return efuse_OneByteWrite23a(padapter, address, *value);
}
/*
* read/wirte raw efuse data
*/
u8 rtw_efuse_access23a(struct rtw_adapter *padapter, u8 bWrite, u16 start_addr,
u16 cnts, u8 *data)
{
int i = 0;
u16 real_content_len = 0, max_available_size = 0;
u8 res = _FAIL ;
u8 (*rw8)(struct rtw_adapter *, u16, u8*);
EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI,
TYPE_EFUSE_REAL_CONTENT_LEN,
(void *)&real_content_len);
EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI,
TYPE_AVAILABLE_EFUSE_BYTES_TOTAL,
(void *)&max_available_size);
if (start_addr > real_content_len)
return _FAIL;
if (true == bWrite) {
if ((start_addr + cnts) > max_available_size)
return _FAIL;
rw8 = &efuse_write8;
} else
rw8 = &efuse_read8;
Efuse_PowerSwitch23a(padapter, bWrite, true);
/* e-fuse one byte read / write */
for (i = 0; i < cnts; i++) {
if (start_addr >= real_content_len) {
res = _FAIL;
break;
}
res = rw8(padapter, start_addr++, data++);
if (_FAIL == res) break;
}
Efuse_PowerSwitch23a(padapter, bWrite, false);
return res;
}
/* */
u16 efuse_GetMaxSize23a(struct rtw_adapter *padapter)
{
u16 max_size;
EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI,
TYPE_AVAILABLE_EFUSE_BYTES_TOTAL,
(void *)&max_size);
return max_size;
}
/* */
u8 efuse_GetCurrentSize23a(struct rtw_adapter *padapter, u16 *size)
{
Efuse_PowerSwitch23a(padapter, false, true);
*size = Efuse_GetCurrentSize23a(padapter, EFUSE_WIFI);
Efuse_PowerSwitch23a(padapter, false, false);
return _SUCCESS;
}
/* */
u8 rtw_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data)
{
u16 mapLen = 0;
EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI,
TYPE_EFUSE_MAP_LEN, (void *)&mapLen);
if ((addr + cnts) > mapLen)
return _FAIL;
Efuse_PowerSwitch23a(padapter, false, true);
efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data);
Efuse_PowerSwitch23a(padapter, false, false);
return _SUCCESS;
}
u8 rtw_BT_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data)
{
u16 mapLen = 0;
EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT,
TYPE_EFUSE_MAP_LEN, (void *)&mapLen);
if ((addr + cnts) > mapLen)
return _FAIL;
Efuse_PowerSwitch23a(padapter, false, true);
efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data);
Efuse_PowerSwitch23a(padapter, false, false);
return _SUCCESS;
}
/*-----------------------------------------------------------------------------
* Function: Efuse_ReadAllMap
*
* Overview: Read All Efuse content
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 11/11/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
void
Efuse_ReadAllMap(struct rtw_adapter *pAdapter, u8 efuseType, u8 *Efuse);
void
Efuse_ReadAllMap(struct rtw_adapter *pAdapter, u8 efuseType, u8 *Efuse)
{
u16 mapLen = 0;
Efuse_PowerSwitch23a(pAdapter, false, true);
EFUSE_GetEfuseDefinition23a(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN,
(void *)&mapLen);
efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse);
Efuse_PowerSwitch23a(pAdapter, false, false);
}
/*-----------------------------------------------------------------------------
* Function: efuse_ShadowRead1Byte
* efuse_ShadowRead2Byte
* efuse_ShadowRead4Byte
*
* Overview: Read from efuse init map by one/two/four bytes !!!!!
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 11/12/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
static void
efuse_ShadowRead1Byte(
struct rtw_adapter * pAdapter,
u16 Offset,
u8 *Value)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
*Value = pEEPROM->efuse_eeprom_data[Offset];
} /* EFUSE_ShadowRead23a1Byte */
/* Read Two Bytes */
static void
efuse_ShadowRead2Byte(
struct rtw_adapter * pAdapter,
u16 Offset,
u16 *Value)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
*Value = pEEPROM->efuse_eeprom_data[Offset];
*Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8;
} /* EFUSE_ShadowRead23a2Byte */
/* Read Four Bytes */
static void
efuse_ShadowRead4Byte(
struct rtw_adapter * pAdapter,
u16 Offset,
u32 *Value)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
*Value = pEEPROM->efuse_eeprom_data[Offset];
*Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8;
*Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16;
*Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24;
} /* efuse_ShadowRead4Byte */
/*-----------------------------------------------------------------------------
* Function: EFUSE_ShadowMapUpdate23a
*
* Overview: Transfer current EFUSE content to shadow init and modify map.
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 11/13/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
void EFUSE_ShadowMapUpdate23a(struct rtw_adapter *pAdapter, u8 efuseType)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
u16 mapLen = 0;
EFUSE_GetEfuseDefinition23a(pAdapter, efuseType,
TYPE_EFUSE_MAP_LEN, (void *)&mapLen);
if (pEEPROM->bautoload_fail_flag == true)
memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen);
else
Efuse_ReadAllMap(pAdapter, efuseType,
pEEPROM->efuse_eeprom_data);
}/* EFUSE_ShadowMapUpdate23a */
/*-----------------------------------------------------------------------------
* Function: EFUSE_ShadowRead23a
*
* Overview: Read from efuse init map !!!!!
*
* Input: NONE
*
* Output: NONE
*
* Return: NONE
*
* Revised History:
* When Who Remark
* 11/12/2008 MHC Create Version 0.
*
*---------------------------------------------------------------------------*/
void
EFUSE_ShadowRead23a(
struct rtw_adapter * pAdapter,
u8 Type,
u16 Offset,
u32 *Value )
{
if (Type == 1)
efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value);
else if (Type == 2)
efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value);
else if (Type == 4)
efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value);
} /* EFUSE_ShadowRead23a */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,266 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
/*
The purpose of rtw_io.c
a. provides the API
b. provides the protocol engine
c. provides the software interface between caller and the hardware interface
Compiler Flag Option:
1. For USB:
a. USE_ASYNC_IRP: Both sync/async operations are provided.
Only sync read/rtw_write_mem operations are provided.
jackson@realtek.com.tw
*/
#define _RTW_IO_C_
#include <osdep_service.h>
#include <drv_types.h>
#include <rtw_io.h>
#include <osdep_intf.h>
#include <usb_ops.h>
u8 _rtw_read823a(struct rtw_adapter *adapter, u32 addr)
{
u8 r_val;
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
r_val = pintfhdl->io_ops._read8(pintfhdl, addr);
return r_val;
}
u16 _rtw_read1623a(struct rtw_adapter *adapter, u32 addr)
{
u16 r_val;
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
r_val = pintfhdl->io_ops._read16(pintfhdl, addr);
return le16_to_cpu(r_val);
}
u32 _rtw_read3223a(struct rtw_adapter *adapter, u32 addr)
{
u32 r_val;
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
r_val = pintfhdl->io_ops._read32(pintfhdl, addr);
return le32_to_cpu(r_val);
}
int _rtw_write823a(struct rtw_adapter *adapter, u32 addr, u8 val)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
int ret;
ret = pintfhdl->io_ops._write8(pintfhdl, addr, val);
return RTW_STATUS_CODE23a(ret);
}
int _rtw_write1623a(struct rtw_adapter *adapter, u32 addr, u16 val)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
int ret;
val = cpu_to_le16(val);
ret = pintfhdl->io_ops._write16(pintfhdl, addr, val);
return RTW_STATUS_CODE23a(ret);
}
int _rtw_write3223a(struct rtw_adapter *adapter, u32 addr, u32 val)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
int ret;
val = cpu_to_le32(val);
ret = pintfhdl->io_ops._write32(pintfhdl, addr, val);
return RTW_STATUS_CODE23a(ret);
}
int _rtw_writeN23a(struct rtw_adapter *adapter, u32 addr , u32 length , u8 *pdata)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = (struct intf_hdl*)&pio_priv->intf;
int ret;
ret = pintfhdl->io_ops._writeN(pintfhdl, addr, length, pdata);
return RTW_STATUS_CODE23a(ret);
}
int _rtw_write823a_async23a(struct rtw_adapter *adapter, u32 addr, u8 val)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
int ret;
ret = pintfhdl->io_ops._write8_async(pintfhdl, addr, val);
return RTW_STATUS_CODE23a(ret);
}
int _rtw_write1623a_async(struct rtw_adapter *adapter, u32 addr, u16 val)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
int ret;
val = cpu_to_le16(val);
ret = pintfhdl->io_ops._write16_async(pintfhdl, addr, val);
return RTW_STATUS_CODE23a(ret);
}
int _rtw_write3223a_async23a(struct rtw_adapter *adapter, u32 addr, u32 val)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
int ret;
val = cpu_to_le32(val);
ret = pintfhdl->io_ops._write32_async(pintfhdl, addr, val);
return RTW_STATUS_CODE23a(ret);
}
void _rtw_read_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
if ((adapter->bDriverStopped == true) ||
(adapter->bSurpriseRemoved == true)) {
RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
("rtw_read_mem:bDriverStopped(%d) OR "
"bSurpriseRemoved(%d)", adapter->bDriverStopped,
adapter->bSurpriseRemoved));
return;
}
pintfhdl->io_ops._read_mem(pintfhdl, addr, cnt, pmem);
}
void _rtw_write_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
pintfhdl->io_ops._write_mem(pintfhdl, addr, cnt, pmem);
}
void _rtw_read_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt,
struct recv_buf *rbuf)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
if ((adapter->bDriverStopped == true) ||
(adapter->bSurpriseRemoved == true)) {
RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
("rtw_read_port:bDriverStopped(%d) OR "
"bSurpriseRemoved(%d)", adapter->bDriverStopped,
adapter->bSurpriseRemoved));
return;
}
pintfhdl->io_ops._read_port(pintfhdl, addr, cnt, rbuf);
}
void _rtw_read_port23a_cancel(struct rtw_adapter *adapter)
{
void (*_read_port_cancel)(struct intf_hdl *pintfhdl);
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
_read_port_cancel = pintfhdl->io_ops._read_port_cancel;
if (_read_port_cancel)
_read_port_cancel(pintfhdl);
}
u32 _rtw_write_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt,
struct xmit_buf *xbuf)
{
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
u32 ret = _SUCCESS;
ret = pintfhdl->io_ops._write_port(pintfhdl, addr, cnt, xbuf);
return ret;
}
u32 _rtw_write_port23a_and_wait23a(struct rtw_adapter *adapter, u32 addr, u32 cnt,
struct xmit_buf *pxmitbuf, int timeout_ms)
{
int ret = _SUCCESS;
struct submit_ctx sctx;
rtw_sctx_init23a(&sctx, timeout_ms);
pxmitbuf->sctx = &sctx;
ret = _rtw_write_port23a(adapter, addr, cnt, pxmitbuf);
if (ret == _SUCCESS)
ret = rtw_sctx_wait23a(&sctx);
return ret;
}
void _rtw_write_port23a_cancel(struct rtw_adapter *adapter)
{
void (*_write_port_cancel)(struct intf_hdl *pintfhdl);
struct io_priv *pio_priv = &adapter->iopriv;
struct intf_hdl *pintfhdl = &pio_priv->intf;
_write_port_cancel = pintfhdl->io_ops._write_port_cancel;
if (_write_port_cancel)
_write_port_cancel(pintfhdl);
}
int rtw_init_io_priv23a(struct rtw_adapter *padapter,
void (*set_intf_ops)(struct _io_ops *pops))
{
struct io_priv *piopriv = &padapter->iopriv;
struct intf_hdl *pintf = &piopriv->intf;
if (set_intf_ops == NULL)
return _FAIL;
piopriv->padapter = padapter;
pintf->padapter = padapter;
pintf->pintf_dev = adapter_to_dvobj(padapter);
set_intf_ops(&pintf->io_ops);
return _SUCCESS;
}

View File

@ -0,0 +1,601 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2012 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.
*
******************************************************************************/
#define _RTW_IOCTL_SET_C_
#include <osdep_service.h>
#include <drv_types.h>
#include <rtw_ioctl_set.h>
#include <hal_intf.h>
#include <usb_osintf.h>
#include <usb_ops.h>
#include <linux/ieee80211.h>
u8 rtw_do_join23a(struct rtw_adapter *padapter)
{
struct list_head *plist, *phead;
u8* pibss = NULL;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct rtw_queue *queue = &pmlmepriv->scanned_queue;
u8 ret = _SUCCESS;
spin_lock_bh(&pmlmepriv->scanned_queue.lock);
phead = get_list_head(queue);
plist = phead->next;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("\n rtw_do_join23a: phead = %p; plist = %p\n\n\n",
phead, plist));
pmlmepriv->cur_network.join_res = -2;
set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
pmlmepriv->to_join = true;
if (_rtw_queue_empty23a(queue) == true) {
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
/* when set_ssid/set_bssid for rtw_do_join23a(), but
scanning queue is empty */
/* we try to issue sitesurvey firstly */
if (pmlmepriv->LinkDetectInfo.bBusyTraffic == false ||
rtw_to_roaming(padapter) > 0) {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("rtw_do_join23a(): site survey if scanned_queue "
"is empty\n."));
/* submit site_survey23a_cmd */
ret = rtw_sitesurvey_cmd23a(padapter,
&pmlmepriv->assoc_ssid, 1,
NULL, 0);
if (ret != _SUCCESS) {
pmlmepriv->to_join = false;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("rtw_do_join23a(): site survey return "
"error\n."));
}
} else {
pmlmepriv->to_join = false;
ret = _FAIL;
}
goto exit;
} else {
int select_ret;
spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
select_ret = rtw_select_and_join_from_scanned_queue23a(pmlmepriv);
if (select_ret == _SUCCESS) {
pmlmepriv->to_join = false;
mod_timer(&pmlmepriv->assoc_timer,
jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT));
} else {
if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
struct wlan_bssid_ex *pdev_network;
/* submit createbss_cmd to change to a
ADHOC_MASTER */
/* pmlmepriv->lock has been acquired by
caller... */
pdev_network =
&padapter->registrypriv.dev_network;
pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
pibss = padapter->registrypriv.dev_network.MacAddress;
memcpy(&pdev_network->Ssid,
&pmlmepriv->assoc_ssid,
sizeof(struct cfg80211_ssid));
rtw_update_registrypriv_dev_network23a(padapter);
rtw_generate_random_ibss23a(pibss);
if (rtw_createbss_cmd23a(padapter) != _SUCCESS) {
RT_TRACE(_module_rtl871x_ioctl_set_c_,
_drv_err_,
("***Error =>do_goin: rtw_creat"
"ebss_cmd status FAIL***\n"));
ret = false;
goto exit;
}
pmlmepriv->to_join = false;
RT_TRACE(_module_rtl871x_ioctl_set_c_,
_drv_info_,
("***Error => rtw_select_and_join_from"
"_scanned_queue FAIL under STA_Mode"
"***\n "));
} else {
/* can't associate ; reset under-linking */
_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
/* when set_ssid/set_bssid for rtw_do_join23a(),
but there are no desired bss in scanning
queue */
/* we try to issue sitesurvey firstly */
if (pmlmepriv->LinkDetectInfo.bBusyTraffic ==
false || rtw_to_roaming(padapter) > 0) {
/* DBG_8723A("rtw_do_join23a() when no "
"desired bss in scanning queue\n");
*/
ret = rtw_sitesurvey_cmd23a(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
if (ret != _SUCCESS) {
pmlmepriv->to_join = false;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n."));
}
} else {
ret = _FAIL;
pmlmepriv->to_join = false;
}
}
}
}
exit:
return ret;
}
u8 rtw_set_802_11_ssid23a(struct rtw_adapter* padapter, struct cfg80211_ssid *ssid)
{
u8 status = _SUCCESS;
u32 cur_time = 0;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_network *pnetwork = &pmlmepriv->cur_network;
DBG_8723A_LEVEL(_drv_always_, "set ssid [%s] fw_state = 0x%08x\n",
ssid->ssid, get_fwstate(pmlmepriv));
if (padapter->hw_init_completed == false) {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("set_ssid: hw_init_completed == false =>exit!!!\n"));
status = _FAIL;
goto exit;
}
spin_lock_bh(&pmlmepriv->lock);
DBG_8723A("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
goto handle_tkip_countermeasure;
} else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) {
goto release_mlme_lock;
}
if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true)
{
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
if ((pmlmepriv->assoc_ssid.ssid_len == ssid->ssid_len) &&
!memcmp(&pmlmepriv->assoc_ssid.ssid, ssid->ssid,
ssid->ssid_len)) {
if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false))
{
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("Set SSID is the same ssid, fw_state = 0x%08x\n",
get_fwstate(pmlmepriv)));
if (rtw_is_same_ibss23a(padapter, pnetwork) == false)
{
/* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
rtw_disassoc_cmd23a(padapter, 0, true);
if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
rtw_indicate_disconnect23a(padapter);
rtw_free_assoc_resources23a(padapter, 1);
if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
}
} else {
goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
}
} else {
rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_JOINBSS, 1);
}
} else {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("Set SSID not the same ssid\n"));
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("set_ssid =[%s] len = 0x%x\n", ssid->ssid,
(unsigned int)ssid->ssid_len));
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("assoc_ssid =[%s] len = 0x%x\n",
pmlmepriv->assoc_ssid.ssid,
(unsigned int)pmlmepriv->assoc_ssid.ssid_len));
rtw_disassoc_cmd23a(padapter, 0, true);
if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
rtw_indicate_disconnect23a(padapter);
rtw_free_assoc_resources23a(padapter, 1);
if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
}
}
}
handle_tkip_countermeasure:
if (padapter->securitypriv.btkip_countermeasure == true) {
cur_time = jiffies;
if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ)
{
padapter->securitypriv.btkip_countermeasure = false;
padapter->securitypriv.btkip_countermeasure_time = 0;
}
else
{
status = _FAIL;
goto release_mlme_lock;
}
}
memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct cfg80211_ssid));
pmlmepriv->assoc_by_bssid = false;
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
pmlmepriv->to_join = true;
}
else {
status = rtw_do_join23a(padapter);
}
release_mlme_lock:
spin_unlock_bh(&pmlmepriv->lock);
exit:
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("-rtw_set_802_11_ssid23a: status =%d\n", status));
return status;
}
u8 rtw_set_802_11_infrastructure_mode23a(struct rtw_adapter* padapter,
enum ndis_802_11_net_infra networktype)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_network *cur_network = &pmlmepriv->cur_network;
enum ndis_802_11_net_infra* pold_state = &cur_network->network.InfrastructureMode;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_,
("+rtw_set_802_11_infrastructure_mode23a: old =%d new =%d fw_state = 0x%08x\n",
*pold_state, networktype, get_fwstate(pmlmepriv)));
if (*pold_state != networktype)
{
spin_lock_bh(&pmlmepriv->lock);
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!"));
/* DBG_8723A("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */
if (*pold_state == Ndis802_11APMode)
{
/* change to other mode from Ndis802_11APMode */
cur_network->join_res = -1;
#ifdef CONFIG_8723AU_AP_MODE
stop_ap_mode23a(padapter);
#endif
}
if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ||(*pold_state == Ndis802_11IBSS))
rtw_disassoc_cmd23a(padapter, 0, true);
if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true))
rtw_free_assoc_resources23a(padapter, 1);
if ((*pold_state == Ndis802_11Infrastructure) ||(*pold_state == Ndis802_11IBSS))
{
if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
{
rtw_indicate_disconnect23a(padapter); /* will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not */
}
}
*pold_state = networktype;
_clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE);
switch (networktype)
{
case Ndis802_11IBSS:
set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
break;
case Ndis802_11Infrastructure:
set_fwstate(pmlmepriv, WIFI_STATION_STATE);
break;
case Ndis802_11APMode:
set_fwstate(pmlmepriv, WIFI_AP_STATE);
#ifdef CONFIG_8723AU_AP_MODE
start_ap_mode23a(padapter);
/* rtw_indicate_connect23a(padapter); */
#endif
break;
case Ndis802_11AutoUnknown:
case Ndis802_11InfrastructureMax:
break;
}
/* SecClearAllKeys(adapter); */
/* RT_TRACE(COMP_OID_SET, DBG_LOUD, ("set_infrastructure: fw_state:%x after changing mode\n", */
/* get_fwstate(pmlmepriv))); */
spin_unlock_bh(&pmlmepriv->lock);
}
return true;
}
u8 rtw_set_802_11_bssid23a_list_scan(struct rtw_adapter *padapter,
struct cfg80211_ssid *pssid, int ssid_max_num)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
u8 res = true;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("+rtw_set_802_11_bssid23a_list_scan(), fw_state =%x\n",
get_fwstate(pmlmepriv)));
if (!padapter) {
res = false;
goto exit;
}
if (padapter->hw_init_completed == false) {
res = false;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("\n === rtw_set_802_11_bssid23a_list_scan:"
"hw_init_completed == false ===\n"));
goto exit;
}
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ||
(pmlmepriv->LinkDetectInfo.bBusyTraffic == true)) {
/* Scan or linking is in progress, do nothing. */
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("rtw_set_802_11_bssid23a_list_scan fail since fw_state "
"= %x\n", get_fwstate(pmlmepriv)));
res = true;
if (check_fwstate(pmlmepriv,
(_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n"));
} else {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("\n###pmlmepriv->sitesurveyctrl.traffic_"
"busy == true\n"));
}
} else {
if (rtw_is_scan_deny(padapter)) {
DBG_8723A(FUNC_ADPT_FMT": scan deny\n",
FUNC_ADPT_ARG(padapter));
return _SUCCESS;
}
spin_lock_bh(&pmlmepriv->lock);
res = rtw_sitesurvey_cmd23a(padapter, pssid, ssid_max_num,
NULL, 0);
spin_unlock_bh(&pmlmepriv->lock);
}
exit:
return res;
}
u8 rtw_set_802_11_authentication_mode23a(struct rtw_adapter* padapter,
enum ndis_802_11_auth_mode authmode)
{
struct security_priv *psecuritypriv = &padapter->securitypriv;
int res;
u8 ret;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("set_802_11_auth.mode(): mode =%x\n", authmode));
psecuritypriv->ndisauthtype = authmode;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("rtw_set_802_11_authentication_mode23a:"
"psecuritypriv->ndisauthtype =%d",
psecuritypriv->ndisauthtype));
if (psecuritypriv->ndisauthtype > 3)
psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
res = rtw_set_auth23a(padapter, psecuritypriv);
if (res == _SUCCESS)
ret = true;
else
ret = false;
return ret;
}
u8 rtw_set_802_11_add_wep23a(struct rtw_adapter* padapter,
struct ndis_802_11_wep *wep)
{
u8 bdefaultkey;
u8 btransmitkey;
int keyid, res;
struct security_priv *psecuritypriv = &padapter->securitypriv;
u8 ret = _SUCCESS;
bdefaultkey = (wep->KeyIndex & 0x40000000) > 0 ? false : true;
btransmitkey = (wep->KeyIndex & 0x80000000) > 0 ? true : false;
keyid = wep->KeyIndex & 0x3fffffff;
if (keyid >= 4) {
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
("MgntActrtw_set_802_11_add_wep23a:keyid>4 =>fail\n"));
ret = false;
goto exit;
}
switch (wep->KeyLength)
{
case 5:
psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("MgntActrtw_set_802_11_add_wep23a:wep->KeyLength = 5\n"));
break;
case 13:
psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("MgntActrtw_set_802_11_add_wep23a:wep->KeyLength = 13\n"));
break;
default:
psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("MgntActrtw_set_802_11_add_wep23a:wep->KeyLength!= 5 "
"or 13\n"));
break;
}
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("rtw_set_802_11_add_wep23a:befor memcpy, wep->KeyLength = 0x%x "
"wep->KeyIndex = 0x%x keyid =%x\n",
wep->KeyLength, wep->KeyIndex, keyid));
memcpy(&psecuritypriv->dot11DefKey[keyid].skey[0],
&wep->KeyMaterial, wep->KeyLength);
psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength;
psecuritypriv->dot11PrivacyKeyIndex = keyid;
RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
("rtw_set_802_11_add_wep23a:security key material : %x %x %x %x "
"%x %x %x %x %x %x %x %x %x\n",
psecuritypriv->dot11DefKey[keyid].skey[0],
psecuritypriv->dot11DefKey[keyid].skey[1],
psecuritypriv->dot11DefKey[keyid].skey[2],
psecuritypriv->dot11DefKey[keyid].skey[3],
psecuritypriv->dot11DefKey[keyid].skey[4],
psecuritypriv->dot11DefKey[keyid].skey[5],
psecuritypriv->dot11DefKey[keyid].skey[6],
psecuritypriv->dot11DefKey[keyid].skey[7],
psecuritypriv->dot11DefKey[keyid].skey[8],
psecuritypriv->dot11DefKey[keyid].skey[9],
psecuritypriv->dot11DefKey[keyid].skey[10],
psecuritypriv->dot11DefKey[keyid].skey[11],
psecuritypriv->dot11DefKey[keyid].skey[12]));
res = rtw_set_key23a(padapter, psecuritypriv, keyid, 1);
if (res == _FAIL)
ret = false;
exit:
return ret;
}
/*
* rtw_get_cur_max_rate23a -
* @adapter: pointer to _adapter structure
*
* Return 0 or 100Kbps
*/
u16 rtw_get_cur_max_rate23a(struct rtw_adapter *adapter)
{
int i = 0;
u8 *p;
u16 rate = 0, max_rate = 0;
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
struct registry_priv *pregistrypriv = &adapter->registrypriv;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
struct ieee80211_ht_cap *pht_capie;
u8 rf_type = 0;
u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
u16 mcs_rate = 0;
u32 ht_ielen = 0;
if (!check_fwstate(pmlmepriv, _FW_LINKED) &&
!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
return 0;
if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N|WIRELESS_11_5N)) {
p = rtw_get_ie23a(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_,
&ht_ielen, pcur_bss->IELength - 12);
if (p && ht_ielen > 0) {
pht_capie = (struct ieee80211_ht_cap *)(p + 2);
memcpy(&mcs_rate, &pht_capie->mcs, 2);
/* bw_40MHz = (pht_capie->cap_info&
IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1:0; */
/* cur_bwmod is updated by beacon, pmlmeinfo is
updated by association response */
bw_40MHz = (pmlmeext->cur_bwmode &&
(HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH &
pmlmeinfo->HT_info.infos[0])) ? 1:0;
/* short_GI = (pht_capie->cap_info & (IEEE80211_HT_CAP
_SGI_20|IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; */
short_GI_20 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_20) ? 1:0;
short_GI_40 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_40) ? 1:0;
rtw23a_hal_get_hwreg(adapter, HW_VAR_RF_TYPE,
(u8 *)(&rf_type));
max_rate = rtw_mcs_rate23a(rf_type, bw_40MHz &
pregistrypriv->cbw40_enable,
short_GI_20, short_GI_40,
pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate
);
}
} else {
while ((pcur_bss->SupportedRates[i] != 0) &&
(pcur_bss->SupportedRates[i] != 0xFF)) {
rate = pcur_bss->SupportedRates[i] & 0x7F;
if (rate>max_rate)
max_rate = rate;
i++;
}
max_rate = max_rate * 10 / 2;
}
return max_rate;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,686 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2012 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.
*
******************************************************************************/
#define _RTW_PWRCTRL_C_
#include <osdep_service.h>
#include <drv_types.h>
#include <osdep_intf.h>
#ifdef CONFIG_8723AU_BT_COEXIST
#include <rtl8723a_hal.h>
#endif
void ips_enter23a(struct rtw_adapter * padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
down(&pwrpriv->lock);
pwrpriv->bips_processing = true;
/* syn ips_mode with request */
pwrpriv->ips_mode = pwrpriv->ips_mode_req;
pwrpriv->ips_enter23a_cnts++;
DBG_8723A("==>ips_enter23a cnts:%d\n", pwrpriv->ips_enter23a_cnts);
#ifdef CONFIG_8723AU_BT_COEXIST
BTDM_TurnOffBtCoexistBeforeEnterIPS(padapter);
#endif
if (rf_off == pwrpriv->change_rfpwrstate)
{
pwrpriv->bpower_saving = true;
DBG_8723A_LEVEL(_drv_always_, "nolinked power save enter\n");
if (pwrpriv->ips_mode == IPS_LEVEL_2)
pwrpriv->bkeepfwalive = true;
rtw_ips_pwr_down23a(padapter);
pwrpriv->rf_pwrstate = rf_off;
}
pwrpriv->bips_processing = false;
up(&pwrpriv->lock);
}
int ips_leave23a(struct rtw_adapter * padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
int result = _SUCCESS;
int keyid;
down(&pwrpriv->lock);
if ((pwrpriv->rf_pwrstate == rf_off) &&!pwrpriv->bips_processing)
{
pwrpriv->bips_processing = true;
pwrpriv->change_rfpwrstate = rf_on;
pwrpriv->ips_leave23a_cnts++;
DBG_8723A("==>ips_leave23a cnts:%d\n", pwrpriv->ips_leave23a_cnts);
if ((result = rtw_ips_pwr_up23a(padapter)) == _SUCCESS) {
pwrpriv->rf_pwrstate = rf_on;
}
DBG_8723A_LEVEL(_drv_always_, "nolinked power save leave\n");
if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) ||(_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm))
{
DBG_8723A("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing);
set_channel_bwmode23a(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
for (keyid = 0;keyid<4;keyid++) {
if (pmlmepriv->key_mask & CHKBIT(keyid)) {
if (keyid == psecuritypriv->dot11PrivacyKeyIndex)
result = rtw_set_key23a(padapter, psecuritypriv, keyid, 1);
else
result = rtw_set_key23a(padapter, psecuritypriv, keyid, 0);
}
}
}
DBG_8723A("==> ips_leave23a.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c));
pwrpriv->bips_processing = false;
pwrpriv->bkeepfwalive = false;
pwrpriv->bpower_saving = false;
}
up(&pwrpriv->lock);
return result;
}
static bool rtw_pwr_unassociated_idle(struct rtw_adapter *adapter)
{
struct rtw_adapter *buddy = adapter->pbuddy_adapter;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
struct xmit_priv *pxmit_priv = &adapter->xmitpriv;
#ifdef CONFIG_8723AU_P2P
struct wifidirect_info *pwdinfo = &adapter->wdinfo;
#endif
bool ret = false;
if (adapter->pwrctrlpriv.ips_deny_time >= rtw_get_current_time())
goto exit;
if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)
|| check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS)
|| check_fwstate(pmlmepriv, WIFI_AP_STATE)
|| check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)
|| !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)
) {
goto exit;
}
/* consider buddy, if exist */
if (buddy) {
struct mlme_priv *b_pmlmepriv = &buddy->mlmepriv;
#ifdef CONFIG_8723AU_P2P
struct wifidirect_info *b_pwdinfo = &buddy->wdinfo;
#endif
if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)
|| check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS)
|| check_fwstate(b_pmlmepriv, WIFI_AP_STATE)
|| check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)
|| !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE)
) {
goto exit;
}
}
if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF ||
pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) {
DBG_8723A_LEVEL(_drv_always_, "There are some pkts to transmit\n");
DBG_8723A_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n",
pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt);
goto exit;
}
ret = true;
exit:
return ret;
}
void rtw_ps_processor23a(struct rtw_adapter*padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
enum rt_rf_power_state rfpwrstate;
pwrpriv->ps_processing = true;
if (pwrpriv->bips_processing == true)
goto exit;
if (padapter->pwrctrlpriv.bHWPwrPindetect) {
rfpwrstate = RfOnOffDetect23a(padapter);
DBG_8723A("@@@@- #2 %s ==> rfstate:%s\n", __func__, (rfpwrstate == rf_on)?"rf_on":"rf_off");
if (rfpwrstate!= pwrpriv->rf_pwrstate) {
if (rfpwrstate == rf_off) {
pwrpriv->change_rfpwrstate = rf_off;
pwrpriv->brfoffbyhw = true;
padapter->bCardDisableWOHSM = true;
rtw_hw_suspend23a(padapter);
} else {
pwrpriv->change_rfpwrstate = rf_on;
rtw_hw_resume23a(padapter);
}
DBG_8723A("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off)?"rf_off":"rf_on");
}
pwrpriv->pwr_state_check_cnts ++;
}
if (pwrpriv->ips_mode_req == IPS_NONE)
goto exit;
if (rtw_pwr_unassociated_idle(padapter) == false)
goto exit;
if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0))
{
DBG_8723A("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv));
pwrpriv->change_rfpwrstate = rf_off;
ips_enter23a(padapter);
}
exit:
rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
pwrpriv->ps_processing = false;
return;
}
static void pwr_state_check_handler(unsigned long data)
{
struct rtw_adapter *padapter = (struct rtw_adapter *)data;
rtw_ps_cmd23a(padapter);
}
/*
*
* Parameters
* padapter
* pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4
*
*/
void rtw_set_rpwm23a(struct rtw_adapter *padapter, u8 pslv)
{
u8 rpwm;
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
pslv = PS_STATE(pslv);
if (true == pwrpriv->btcoex_rfon)
{
if (pslv < PS_STATE_S4)
pslv = PS_STATE_S3;
}
if (pwrpriv->rpwm == pslv) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
("%s: Already set rpwm[0x%02X], new = 0x%02X!\n", __func__, pwrpriv->rpwm, pslv));
return;
}
if ((padapter->bSurpriseRemoved == true) ||
(padapter->hw_init_completed == false)) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n",
__func__, padapter->bSurpriseRemoved, padapter->hw_init_completed));
pwrpriv->cpwm = PS_STATE_S4;
return;
}
if (padapter->bDriverStopped == true) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv));
if (pslv < PS_STATE_S2) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv));
return;
}
}
rpwm = pslv | pwrpriv->tog;
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
("rtw_set_rpwm23a: rpwm = 0x%02x cpwm = 0x%02x\n", rpwm, pwrpriv->cpwm));
pwrpriv->rpwm = pslv;
rtw_hal_set_hwreg23a(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm));
pwrpriv->tog += 0x80;
pwrpriv->cpwm = pslv;
}
u8 PS_RDY_CHECK(struct rtw_adapter * padapter)
{
unsigned long delta_time;
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
delta_time = jiffies - pwrpriv->DelayLPSLastTimeStamp;
if (delta_time < LPS_DELAY_TIME)
{
return false;
}
if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) ||
(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) ||
(check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
return false;
if (true == pwrpriv->bInSuspend)
return false;
if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false))
{
DBG_8723A("Group handshake still in progress !!!\n");
return false;
}
if (!rtw_cfg80211_pwr_mgmt(padapter))
return false;
return true;
}
void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
#ifdef CONFIG_8723AU_P2P
struct wifidirect_info *pwdinfo = &padapter->wdinfo;
#endif /* CONFIG_8723AU_P2P */
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
("%s: PowerMode =%d Smart_PS =%d\n",
__func__, ps_mode, smart_ps));
if (ps_mode > PM_Card_Disable) {
RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode));
return;
}
if (pwrpriv->pwr_mode == ps_mode)
{
if (PS_MODE_ACTIVE == ps_mode) return;
if ((pwrpriv->smart_ps == smart_ps) &&
(pwrpriv->bcn_ant_mode == bcn_ant_mode))
{
return;
}
}
if (ps_mode == PS_MODE_ACTIVE) {
#ifdef CONFIG_8723AU_P2P
if (pwdinfo->opp_ps == 0)
#endif /* CONFIG_8723AU_P2P */
{
DBG_8723A("rtw_set_ps_mode23a: Leave 802.11 power save\n");
pwrpriv->pwr_mode = ps_mode;
rtw_set_rpwm23a(padapter, PS_STATE_S4);
rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
pwrpriv->bFwCurrentInPSMode = false;
}
}
else
{
if (PS_RDY_CHECK(padapter)
#ifdef CONFIG_8723AU_BT_COEXIST
|| (BT_1Ant(padapter) == true)
#endif
)
{
DBG_8723A("%s: Enter 802.11 power save\n", __func__);
pwrpriv->bFwCurrentInPSMode = true;
pwrpriv->pwr_mode = ps_mode;
pwrpriv->smart_ps = smart_ps;
pwrpriv->bcn_ant_mode = bcn_ant_mode;
rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
#ifdef CONFIG_8723AU_P2P
/* Set CTWindow after LPS */
if (pwdinfo->opp_ps == 1)
p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 0);
#endif /* CONFIG_8723AU_P2P */
rtw_set_rpwm23a(padapter, PS_STATE_S2);
}
}
}
/*
* Return:
* 0: Leave OK
* -1: Timeout
* -2: Other error
*/
s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms)
{
u32 start_time;
u8 bAwake = false;
s32 err = 0;
start_time = rtw_get_current_time();
while (1)
{
rtw23a_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake);
if (true == bAwake)
break;
if (true == padapter->bSurpriseRemoved)
{
err = -2;
DBG_8723A("%s: device surprise removed!!\n", __func__);
break;
}
if (rtw_get_passing_time_ms23a(start_time) > delay_ms)
{
err = -1;
DBG_8723A("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms);
break;
}
udelay(100);
}
return err;
}
/* Description: */
/* Enter the leisure power save mode. */
void LPS_Enter23a(struct rtw_adapter *padapter)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
if (!PS_RDY_CHECK(padapter))
return;
if (pwrpriv->bLeisurePs) {
/* Idle for a while if we connect to AP a while ago. */
if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */
if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) {
pwrpriv->bpower_saving = true;
DBG_8723A("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps);
/* For Tenda W311R IOT issue */
rtw_set_ps_mode23a(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0);
}
} else {
pwrpriv->LpsIdleCount++;
}
}
}
/* Description: */
/* Leave the leisure power save mode. */
void LPS_Leave23a(struct rtw_adapter *padapter)
{
#define LPS_LEAVE_TIMEOUT_MS 100
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
if (pwrpriv->bLeisurePs) {
if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) {
rtw_set_ps_mode23a(padapter, PS_MODE_ACTIVE, 0, 0);
if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
LPS_RF_ON_check23a(padapter, LPS_LEAVE_TIMEOUT_MS);
}
}
pwrpriv->bpower_saving = false;
}
/* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */
/* Move code to function by tynli. 2010.03.26. */
void LeaveAllPowerSaveMode23a(struct rtw_adapter *Adapter)
{
struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
u8 enqueue = 0;
/* DBG_8723A("%s.....\n", __func__); */
if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
{ /* connect */
#ifdef CONFIG_8723AU_P2P
p2p_ps_wk_cmd23a(Adapter, P2P_PS_DISABLE, enqueue);
#endif /* CONFIG_8723AU_P2P */
rtw_lps_ctrl_wk_cmd23a(Adapter, LPS_CTRL_LEAVE, enqueue);
}
}
void rtw_init_pwrctrl_priv23a(struct rtw_adapter *padapter)
{
struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
sema_init(&pwrctrlpriv->lock, 1);
pwrctrlpriv->rf_pwrstate = rf_on;
pwrctrlpriv->ips_enter23a_cnts = 0;
pwrctrlpriv->ips_leave23a_cnts = 0;
pwrctrlpriv->bips_processing = false;
pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode;
pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode;
pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL;
pwrctrlpriv->pwr_state_check_cnts = 0;
pwrctrlpriv->bInternalAutoSuspend = false;
pwrctrlpriv->bInSuspend = false;
pwrctrlpriv->bkeepfwalive = false;
pwrctrlpriv->LpsIdleCount = 0;
pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */
pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false;
pwrctrlpriv->bFwCurrentInPSMode = false;
pwrctrlpriv->rpwm = 0;
pwrctrlpriv->cpwm = PS_STATE_S4;
pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE;
pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps;
pwrctrlpriv->bcn_ant_mode = 0;
pwrctrlpriv->tog = 0x80;
pwrctrlpriv->btcoex_rfon = false;
setup_timer(&pwrctrlpriv->pwr_state_check_timer,
pwr_state_check_handler, (unsigned long)padapter);
}
void rtw_free_pwrctrl_priv(struct rtw_adapter *adapter)
{
}
u8 rtw_interface_ps_func23a(struct rtw_adapter *padapter, enum hal_intf_ps_func efunc_id, u8* val)
{
u8 bResult = true;
rtw_hal_intf_ps_func23a(padapter, efunc_id, val);
return bResult;
}
inline void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime23a(ms);
}
/*
* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend
* @adapter: pointer to _adapter structure
* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup
* Return _SUCCESS or _FAIL
*/
int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const char *caller)
{
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
int ret = _SUCCESS;
u32 start = rtw_get_current_time();
if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms))
pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms);
if (pwrpriv->ps_processing) {
DBG_8723A("%s wait ps_processing...\n", __func__);
while (pwrpriv->ps_processing && rtw_get_passing_time_ms23a(start) <= 3000)
msleep(10);
if (pwrpriv->ps_processing)
DBG_8723A("%s wait ps_processing timeout\n", __func__);
else
DBG_8723A("%s wait ps_processing done\n", __func__);
}
if (rtw_hal_sreset_inprogress(padapter)) {
DBG_8723A("%s wait sreset_inprogress...\n", __func__);
while (rtw_hal_sreset_inprogress(padapter) && rtw_get_passing_time_ms23a(start) <= 4000)
msleep(10);
if (rtw_hal_sreset_inprogress(padapter))
DBG_8723A("%s wait sreset_inprogress timeout\n", __func__);
else
DBG_8723A("%s wait sreset_inprogress done\n", __func__);
}
if (pwrpriv->bInternalAutoSuspend == false && pwrpriv->bInSuspend) {
DBG_8723A("%s wait bInSuspend...\n", __func__);
while (pwrpriv->bInSuspend &&
(rtw_get_passing_time_ms23a(start) <= 3000)) {
msleep(10);
}
if (pwrpriv->bInSuspend)
DBG_8723A("%s wait bInSuspend timeout\n", __func__);
else
DBG_8723A("%s wait bInSuspend done\n", __func__);
}
/* System suspend is not allowed to wakeup */
if ((pwrpriv->bInternalAutoSuspend == false) && (true == pwrpriv->bInSuspend)) {
ret = _FAIL;
goto exit;
}
/* block??? */
if ((pwrpriv->bInternalAutoSuspend == true) && (padapter->net_closed == true)) {
ret = _FAIL;
goto exit;
}
/* I think this should be check in IPS, LPS, autosuspend functions... */
if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
{
ret = _SUCCESS;
goto exit;
}
if (rf_off == pwrpriv->rf_pwrstate) {
DBG_8723A("%s call ips_leave23a....\n", __func__);
if (_FAIL == ips_leave23a(padapter)) {
DBG_8723A("======> ips_leave23a fail.............\n");
ret = _FAIL;
goto exit;
}
}
/* TODO: the following checking need to be merged... */
if (padapter->bDriverStopped || !padapter->bup ||
!padapter->hw_init_completed) {
DBG_8723A("%s: bDriverStopped =%d, bup =%d, hw_init_completed "
"=%u\n", caller, padapter->bDriverStopped,
padapter->bup, padapter->hw_init_completed);
ret = false;
goto exit;
}
exit:
if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms))
pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime23a(ips_deffer_ms);
return ret;
}
int rtw_pm_set_lps23a(struct rtw_adapter *padapter, u8 mode)
{
int ret = 0;
struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
if (mode < PS_MODE_NUM)
{
if (pwrctrlpriv->power_mgnt != mode)
{
if (PS_MODE_ACTIVE == mode)
{
LeaveAllPowerSaveMode23a(padapter);
}
else
{
pwrctrlpriv->LpsIdleCount = 2;
}
pwrctrlpriv->power_mgnt = mode;
pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false;
}
}
else
{
ret = -EINVAL;
}
return ret;
}
int rtw_pm_set_ips23a(struct rtw_adapter *padapter, u8 mode)
{
struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) {
rtw_ips_mode_req(pwrctrlpriv, mode);
DBG_8723A("%s %s\n", __func__, mode == IPS_NORMAL?"IPS_NORMAL":"IPS_LEVEL_2");
return 0;
}
else if (mode == IPS_NONE) {
rtw_ips_mode_req(pwrctrlpriv, mode);
DBG_8723A("%s %s\n", __func__, "IPS_NONE");
if ((padapter->bSurpriseRemoved == 0)&&_FAIL == rtw_pwr_wakeup(padapter))
return -EFAULT;
}
else {
return -EINVAL;
}
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,253 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2012 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.
*
******************************************************************************/
#include<rtw_sreset.h>
void sreset_init_value23a(struct rtw_adapter *padapter)
{
struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
struct sreset_priv *psrtpriv = &pHalData->srestpriv;
mutex_init(&psrtpriv->silentreset_mutex);
psrtpriv->silent_reset_inprogress = false;
psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
psrtpriv->last_tx_time = 0;
psrtpriv->last_tx_complete_time = 0;
}
void sreset_reset_value23a(struct rtw_adapter *padapter)
{
struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
struct sreset_priv *psrtpriv = &pHalData->srestpriv;
psrtpriv->silent_reset_inprogress = false;
psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
psrtpriv->last_tx_time = 0;
psrtpriv->last_tx_complete_time = 0;
}
u8 sreset_get_wifi_status23a(struct rtw_adapter *padapter)
{
struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
struct sreset_priv *psrtpriv = &pHalData->srestpriv;
u8 status = WIFI_STATUS_SUCCESS;
u32 val32 = 0;
if (psrtpriv->silent_reset_inprogress)
return status;
val32 = rtw_read32(padapter, REG_TXDMA_STATUS);
if (val32 == 0xeaeaeaea) {
psrtpriv->Wifi_Error_Status = WIFI_IF_NOT_EXIST;
} else if (val32 != 0) {
DBG_8723A("txdmastatu(%x)\n", val32);
psrtpriv->Wifi_Error_Status = WIFI_MAC_TXDMA_ERROR;
}
if (WIFI_STATUS_SUCCESS != psrtpriv->Wifi_Error_Status) {
DBG_8723A("==>%s error_status(0x%x)\n", __func__, psrtpriv->Wifi_Error_Status);
status = (psrtpriv->Wifi_Error_Status &~(USB_READ_PORT_FAIL|USB_WRITE_PORT_FAIL));
}
DBG_8723A("==> %s wifi_status(0x%x)\n", __func__, status);
/* status restore */
psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
return status;
}
void sreset_set_wifi_error_status23a(struct rtw_adapter *padapter, u32 status)
{
struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
pHalData->srestpriv.Wifi_Error_Status = status;
}
void sreset_set_trigger_point(struct rtw_adapter *padapter, s32 tgp)
{
struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
pHalData->srestpriv.dbg_trigger_point = tgp;
}
bool sreset_inprogress(struct rtw_adapter *padapter)
{
struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
return pHalData->srestpriv.silent_reset_inprogress;
}
static void sreset_restore_security_station(struct rtw_adapter *padapter)
{
struct mlme_priv *mlmepriv = &padapter->mlmepriv;
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info *psta;
struct mlme_ext_info *pmlmeinfo = &padapter->mlmeextpriv.mlmext_info;
u8 val8;
if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X)
val8 = 0xcc;
else
val8 = 0xcf;
rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
(padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
psta = rtw_get_stainfo23a(pstapriv, get_bssid(mlmepriv));
if (psta == NULL) {
/* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */
} else {
/* pairwise key */
rtw_setstakey_cmd23a(padapter, (unsigned char *)psta, true);
/* group key */
rtw_set_key23a(padapter,&padapter->securitypriv, padapter->securitypriv.dot118021XGrpKeyid, 0);
}
}
}
static void sreset_restore_network_station(struct rtw_adapter *padapter)
{
struct mlme_priv *mlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
u8 threshold;
rtw_setopmode_cmd23a(padapter, Ndis802_11Infrastructure);
/* TH = 1 => means that invalidate usb rx aggregation */
/* TH = 0 => means that validate usb rx aggregation, use init value. */
if (mlmepriv->htpriv.ht_option) {
if (padapter->registrypriv.wifi_spec == 1)
threshold = 1;
else
threshold = 0;
rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
} else {
threshold = 1;
rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
}
set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
/* disable dynamic functions, such as high power, DIG */
/* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); */
rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress);
{
u8 join_type = 0;
rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
}
Set_MSR23a(padapter, (pmlmeinfo->state & 0x3));
mlmeext_joinbss_event_callback23a(padapter, 1);
/* restore Sequence No. */
rtw_write8(padapter, 0x4dc, padapter->xmitpriv.nqos_ssn);
sreset_restore_security_station(padapter);
}
static void sreset_restore_network_status(struct rtw_adapter *padapter)
{
struct mlme_priv *mlmepriv = &padapter->mlmepriv;
if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) {
DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
sreset_restore_network_station(padapter);
} else if (check_fwstate(mlmepriv, WIFI_AP_STATE)) {
DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
rtw_ap_restore_network(padapter);
} else if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE)) {
DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
} else {
DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
}
}
static void sreset_stop_adapter(struct rtw_adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
if (padapter == NULL)
return;
DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
if (!rtw_netif_queue_stopped(padapter->pnetdev))
netif_tx_stop_all_queues(padapter->pnetdev);
rtw_cancel_all_timer23a(padapter);
/* TODO: OS and HCI independent */
tasklet_kill(&pxmitpriv->xmit_tasklet);
if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
rtw_scan_abort23a(padapter);
if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
rtw23a_join_to_handler((unsigned long)padapter);
}
static void sreset_start_adapter(struct rtw_adapter *padapter)
{
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
if (padapter == NULL)
return;
DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
if (check_fwstate(pmlmepriv, _FW_LINKED)) {
sreset_restore_network_status(padapter);
}
/* TODO: OS and HCI independent */
tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
mod_timer(&padapter->mlmepriv.dynamic_chk_timer,
jiffies + msecs_to_jiffies(2000));
if (rtw_netif_queue_stopped(padapter->pnetdev))
netif_tx_wake_all_queues(padapter->pnetdev);
}
void sreset_reset(struct rtw_adapter *padapter)
{
struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
struct sreset_priv *psrtpriv = &pHalData->srestpriv;
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
unsigned long start = jiffies;
DBG_8723A("%s\n", __func__);
psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
mutex_lock(&psrtpriv->silentreset_mutex);
psrtpriv->silent_reset_inprogress = true;
pwrpriv->change_rfpwrstate = rf_off;
sreset_stop_adapter(padapter);
ips_enter23a(padapter);
ips_leave23a(padapter);
sreset_start_adapter(padapter);
psrtpriv->silent_reset_inprogress = false;
mutex_unlock(&psrtpriv->silentreset_mutex);
DBG_8723A("%s done in %d ms\n", __func__,
jiffies_to_msecs(jiffies - start));
}

View File

@ -0,0 +1,509 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
#define _RTW_STA_MGT_C_
#include <osdep_service.h>
#include <drv_types.h>
#include <recv_osdep.h>
#include <xmit_osdep.h>
#include <mlme_osdep.h>
#include <sta_info.h>
void _rtw_init_stainfo(struct sta_info *psta)
{
memset((u8 *)psta, 0, sizeof (struct sta_info));
spin_lock_init(&psta->lock);
INIT_LIST_HEAD(&psta->list);
INIT_LIST_HEAD(&psta->hash_list);
_rtw_init_queue23a(&psta->sleep_q);
psta->sleepq_len = 0;
_rtw_init_sta_xmit_priv23a(&psta->sta_xmitpriv);
_rtw_init_sta_recv_priv23a(&psta->sta_recvpriv);
#ifdef CONFIG_8723AU_AP_MODE
INIT_LIST_HEAD(&psta->asoc_list);
INIT_LIST_HEAD(&psta->auth_list);
psta->expire_to = 0;
psta->flags = 0;
psta->capability = 0;
psta->bpairwise_key_installed = false;
psta->nonerp_set = 0;
psta->no_short_slot_time_set = 0;
psta->no_short_preamble_set = 0;
psta->no_ht_gf_set = 0;
psta->no_ht_set = 0;
psta->ht_20mhz_set = 0;
psta->keep_alive_trycnt = 0;
#endif /* CONFIG_8723AU_AP_MODE */
}
u32 _rtw_init_sta_priv23a(struct sta_priv *pstapriv)
{
struct sta_info *psta;
s32 i;
pstapriv->pallocated_stainfo_buf = rtw_zvmalloc(sizeof(struct sta_info) * NUM_STA+ 4);
if (!pstapriv->pallocated_stainfo_buf)
return _FAIL;
pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 -
((unsigned long)(pstapriv->pallocated_stainfo_buf) & 3);
_rtw_init_queue23a(&pstapriv->free_sta_queue);
spin_lock_init(&pstapriv->sta_hash_lock);
pstapriv->asoc_sta_count = 0;
_rtw_init_queue23a(&pstapriv->sleep_q);
_rtw_init_queue23a(&pstapriv->wakeup_q);
psta = (struct sta_info *)(pstapriv->pstainfo_buf);
for (i = 0; i < NUM_STA; i++) {
_rtw_init_stainfo(psta);
INIT_LIST_HEAD(&pstapriv->sta_hash[i]);
list_add_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue));
psta++;
}
#ifdef CONFIG_8723AU_AP_MODE
pstapriv->sta_dz_bitmap = 0;
pstapriv->tim_bitmap = 0;
INIT_LIST_HEAD(&pstapriv->asoc_list);
INIT_LIST_HEAD(&pstapriv->auth_list);
spin_lock_init(&pstapriv->asoc_list_lock);
spin_lock_init(&pstapriv->auth_list_lock);
pstapriv->asoc_list_cnt = 0;
pstapriv->auth_list_cnt = 0;
pstapriv->auth_to = 3; /* 3*2 = 6 sec */
pstapriv->assoc_to = 3;
/* pstapriv->expire_to = 900; 900*2 = 1800 sec = 30 min, expire after no any traffic. */
/* pstapriv->expire_to = 30; 30*2 = 60 sec = 1 min, expire after no any traffic. */
pstapriv->expire_to = 3; /* 3*2 = 6 sec */
pstapriv->max_num_sta = NUM_STA;
#endif
return _SUCCESS;
}
inline int rtw_stainfo_offset23a(struct sta_priv *stapriv, struct sta_info *sta)
{
int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info);
if (!stainfo_offset_valid(offset))
DBG_8723A("%s invalid offset(%d), out of range!!!", __func__, offset);
return offset;
}
inline struct sta_info *rtw_get_stainfo23a_by_offset23a(struct sta_priv *stapriv, int offset)
{
if (!stainfo_offset_valid(offset))
DBG_8723A("%s invalid offset(%d), out of range!!!", __func__, offset);
return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info));
}
/* this function is used to free the memory of lock || sema for all stainfos */
void rtw_mfree_all_stainfo(struct sta_priv *pstapriv)
{
struct list_head *plist, *phead;
struct sta_info *psta;
spin_lock_bh(&pstapriv->sta_hash_lock);
phead = get_list_head(&pstapriv->free_sta_queue);
/* we really achieve a lot in this loop .... */
list_for_each(plist, phead)
psta = container_of(plist, struct sta_info, list);
spin_unlock_bh(&pstapriv->sta_hash_lock);
}
void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv)
{
rtw_mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */
}
u32 _rtw_free_sta_priv23a(struct sta_priv *pstapriv)
{
struct list_head *phead, *plist, *ptmp;
struct sta_info *psta;
struct recv_reorder_ctrl *preorder_ctrl;
int index;
if (pstapriv) {
/* delete all reordering_ctrl_timer */
spin_lock_bh(&pstapriv->sta_hash_lock);
for (index = 0; index < NUM_STA; index++) {
phead = &pstapriv->sta_hash[index];
list_for_each_safe(plist, ptmp, phead) {
int i;
psta = container_of(plist, struct sta_info,
hash_list);
for (i = 0; i < 16 ; i++) {
preorder_ctrl = &psta->recvreorder_ctrl[i];
del_timer_sync(&preorder_ctrl->reordering_ctrl_timer);
}
}
}
spin_unlock_bh(&pstapriv->sta_hash_lock);
/*===============================*/
rtw_mfree_sta_priv_lock(pstapriv);
if (pstapriv->pallocated_stainfo_buf)
rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info)*NUM_STA+4);
}
return _SUCCESS;
}
struct sta_info *rtw_alloc_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr)
{
struct list_head *phash_list;
struct sta_info *psta;
struct rtw_queue *pfree_sta_queue;
struct recv_reorder_ctrl *preorder_ctrl;
uint tmp_aid;
s32 index;
int i = 0;
u16 wRxSeqInitialValue = 0xffff;
pfree_sta_queue = &pstapriv->free_sta_queue;
spin_lock_bh(&pstapriv->sta_hash_lock);
if (_rtw_queue_empty23a(pfree_sta_queue)) {
spin_unlock_bh(&pstapriv->sta_hash_lock);
return NULL;
}
psta = container_of((&pfree_sta_queue->queue)->next, struct sta_info, list);
list_del_init(&psta->list);
tmp_aid = psta->aid;
_rtw_init_stainfo(psta);
psta->padapter = pstapriv->padapter;
memcpy(psta->hwaddr, hwaddr, ETH_ALEN);
index = wifi_mac_hash(hwaddr);
RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_,
("rtw_alloc_stainfo23a: index = %x", index));
if (index >= NUM_STA) {
RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_,
("ERROR => rtw_alloc_stainfo23a: index >= NUM_STA"));
psta = NULL;
goto exit;
}
phash_list = &pstapriv->sta_hash[index];
list_add_tail(&psta->hash_list, phash_list);
pstapriv->asoc_sta_count ++ ;
/* For the SMC router, the sequence number of first packet of WPS handshake will be 0. */
/* In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */
/* So, we initialize the tid_rxseq variable as the 0xffff. */
for (i = 0; i < 16; i++)
memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2);
RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_,
("alloc number_%d stainfo with hwaddr = %pM\n",
pstapriv->asoc_sta_count, hwaddr));
init_addba_retry_timer23a(psta);
/* for A-MPDU Rx reordering buffer control */
for (i = 0; i < 16; i++) {
preorder_ctrl = &psta->recvreorder_ctrl[i];
preorder_ctrl->padapter = pstapriv->padapter;
preorder_ctrl->enable = false;
preorder_ctrl->indicate_seq = 0xffff;
preorder_ctrl->wend_b = 0xffff;
/* preorder_ctrl->wsize_b = (NR_RECVBUFF-2); */
preorder_ctrl->wsize_b = 64;/* 64; */
_rtw_init_queue23a(&preorder_ctrl->pending_recvframe_queue);
rtw_init_recv_timer23a(preorder_ctrl);
}
/* init for DM */
psta->rssi_stat.UndecoratedSmoothedPWDB = (-1);
psta->rssi_stat.UndecoratedSmoothedCCK = (-1);
/* init for the sequence number of received management frame */
psta->RxMgmtFrameSeqNum = 0xffff;
exit:
spin_unlock_bh(&pstapriv->sta_hash_lock);
return psta;
}
/* using pstapriv->sta_hash_lock to protect */
u32 rtw_free_stainfo23a(struct rtw_adapter *padapter, struct sta_info *psta)
{
struct rtw_queue *pfree_sta_queue;
struct recv_reorder_ctrl *preorder_ctrl;
struct sta_xmit_priv *pstaxmitpriv;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct sta_priv *pstapriv = &padapter->stapriv;
struct hw_xmit *phwxmit;
int i;
if (psta == NULL)
goto exit;
spin_lock_bh(&psta->lock);
psta->state &= ~_FW_LINKED;
spin_unlock_bh(&psta->lock);
pfree_sta_queue = &pstapriv->free_sta_queue;
pstaxmitpriv = &psta->sta_xmitpriv;
spin_lock_bh(&pxmitpriv->lock);
rtw_free_xmitframe_queue23a(pxmitpriv, &psta->sleep_q);
psta->sleepq_len = 0;
/* vo */
rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending);
list_del_init(&pstaxmitpriv->vo_q.tx_pending);
phwxmit = pxmitpriv->hwxmits;
phwxmit->accnt -= pstaxmitpriv->vo_q.qcnt;
pstaxmitpriv->vo_q.qcnt = 0;
/* vi */
rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending);
list_del_init(&pstaxmitpriv->vi_q.tx_pending);
phwxmit = pxmitpriv->hwxmits+1;
phwxmit->accnt -= pstaxmitpriv->vi_q.qcnt;
pstaxmitpriv->vi_q.qcnt = 0;
/* be */
rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->be_q.sta_pending);
list_del_init(&pstaxmitpriv->be_q.tx_pending);
phwxmit = pxmitpriv->hwxmits+2;
phwxmit->accnt -= pstaxmitpriv->be_q.qcnt;
pstaxmitpriv->be_q.qcnt = 0;
/* bk */
rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending);
list_del_init(&pstaxmitpriv->bk_q.tx_pending);
phwxmit = pxmitpriv->hwxmits+3;
phwxmit->accnt -= pstaxmitpriv->bk_q.qcnt;
pstaxmitpriv->bk_q.qcnt = 0;
spin_unlock_bh(&pxmitpriv->lock);
list_del_init(&psta->hash_list);
RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("\n free number_%d stainfo with hwaddr = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x \n", pstapriv->asoc_sta_count, psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5]));
pstapriv->asoc_sta_count --;
/* re-init sta_info; 20061114 will be init in alloc_stainfo */
/* _rtw_init_sta_xmit_priv23a(&psta->sta_xmitpriv); */
/* _rtw_init_sta_recv_priv23a(&psta->sta_recvpriv); */
del_timer_sync(&psta->addba_retry_timer);
/* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */
for (i = 0; i < 16; i++) {
struct list_head *phead, *plist;
struct recv_frame *prframe;
struct rtw_queue *ppending_recvframe_queue;
struct rtw_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
preorder_ctrl = &psta->recvreorder_ctrl[i];
del_timer_sync(&preorder_ctrl->reordering_ctrl_timer);
ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
spin_lock_bh(&ppending_recvframe_queue->lock);
phead = get_list_head(ppending_recvframe_queue);
plist = phead->next;
while (!list_empty(phead)) {
prframe = container_of(plist, struct recv_frame, list);
plist = plist->next;
list_del_init(&prframe->list);
rtw_free_recvframe23a(prframe, pfree_recv_queue);
}
spin_unlock_bh(&ppending_recvframe_queue->lock);
}
if (!(psta->state & WIFI_AP_STATE))
rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, false);
#ifdef CONFIG_8723AU_AP_MODE
spin_lock_bh(&pstapriv->auth_list_lock);
if (!list_empty(&psta->auth_list)) {
list_del_init(&psta->auth_list);
pstapriv->auth_list_cnt--;
}
spin_unlock_bh(&pstapriv->auth_list_lock);
psta->expire_to = 0;
psta->sleepq_ac_len = 0;
psta->qos_info = 0;
psta->max_sp_len = 0;
psta->uapsd_bk = 0;
psta->uapsd_be = 0;
psta->uapsd_vi = 0;
psta->uapsd_vo = 0;
psta->has_legacy_ac = 0;
pstapriv->sta_dz_bitmap &= ~CHKBIT(psta->aid);
pstapriv->tim_bitmap &= ~CHKBIT(psta->aid);
if ((psta->aid >0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) {
pstapriv->sta_aid[psta->aid - 1] = NULL;
psta->aid = 0;
}
#endif /* CONFIG_8723AU_AP_MODE */
list_add_tail(&psta->list, get_list_head(pfree_sta_queue));
exit:
return _SUCCESS;
}
/* free all stainfo which in sta_hash[all] */
void rtw_free_all_stainfo23a(struct rtw_adapter *padapter)
{
struct list_head *plist, *phead, *ptmp;
struct sta_info *psta;
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info* pbcmc_stainfo = rtw_get_bcmc_stainfo23a(padapter);
s32 index; if (pstapriv->asoc_sta_count == 1)
return;
spin_lock_bh(&pstapriv->sta_hash_lock);
for (index = 0; index < NUM_STA; index++) {
phead = &pstapriv->sta_hash[index];
list_for_each_safe(plist, ptmp, phead) {
psta = container_of(plist, struct sta_info, hash_list);
if (pbcmc_stainfo!= psta)
rtw_free_stainfo23a(padapter, psta);
}
}
spin_unlock_bh(&pstapriv->sta_hash_lock);
}
/* any station allocated can be searched by hash list */
struct sta_info *rtw_get_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr)
{
struct list_head *plist, *phead;
struct sta_info *psta = NULL;
u32 index;
u8 *addr;
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (hwaddr == NULL)
return NULL;
if (is_multicast_ether_addr(hwaddr))
addr = bc_addr;
else
addr = hwaddr;
index = wifi_mac_hash(addr);
spin_lock_bh(&pstapriv->sta_hash_lock);
phead = &pstapriv->sta_hash[index];
list_for_each(plist, phead) {
psta = container_of(plist, struct sta_info, hash_list);
if (!memcmp(psta->hwaddr, addr, ETH_ALEN)) {
/* if found the matched address */
break;
}
psta = NULL;
}
spin_unlock_bh(&pstapriv->sta_hash_lock);
return psta;
}
u32 rtw_init_bcmc_stainfo23a(struct rtw_adapter* padapter)
{
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info *psta;
struct tx_servq *ptxservq;
u32 res = _SUCCESS;
unsigned char bcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
psta = rtw_alloc_stainfo23a(pstapriv, bcast_addr);
if (psta == NULL) {
res = _FAIL;
RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_,
("rtw_alloc_stainfo23a fail"));
return res;
}
/* default broadcast & multicast use macid 1 */
psta->mac_id = 1;
ptxservq = &psta->sta_xmitpriv.be_q;
return _SUCCESS;
}
struct sta_info *rtw_get_bcmc_stainfo23a(struct rtw_adapter *padapter)
{
struct sta_info *psta;
struct sta_priv *pstapriv = &padapter->stapriv;
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
psta = rtw_get_stainfo23a(pstapriv, bc_addr);
return psta;
}
u8 rtw_access_ctrl23a(struct rtw_adapter *padapter, u8 *mac_addr)
{
u8 res = true;
#ifdef CONFIG_8723AU_AP_MODE
struct list_head *plist, *phead;
struct rtw_wlan_acl_node *paclnode;
u8 match = false;
struct sta_priv *pstapriv = &padapter->stapriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
struct rtw_queue *pacl_node_q = &pacl_list->acl_node_q;
spin_lock_bh(&pacl_node_q->lock);
phead = get_list_head(pacl_node_q);
list_for_each(plist, phead) {
paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
if (!memcmp(paclnode->addr, mac_addr, ETH_ALEN)) {
if (paclnode->valid) {
match = true;
break;
}
}
}
spin_unlock_bh(&pacl_node_q->lock);
if (pacl_list->mode == 1)/* accept unless in deny list */
res = (match) ? false : true;
else if (pacl_list->mode == 2)/* deny unless in accept list */
res = (match) ? true : false;
else
res = true;
#endif
return res;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff