blob: 31229d13baf0b92c7e06e06de6008c69f379254f [file] [log] [blame]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* 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 http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*
** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_proc.c#2
*/
/*! \file "gl_proc.c"
* \brief This file defines the interface which can interact with users in /proc fs.
*
* Detail description.
*/
/*******************************************************************************
* C O M P I L E R F L A G S
********************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
********************************************************************************
*/
#include "precomp.h"
#include "gl_os.h"
#include "gl_kal.h"
#include "debug.h"
#include "wlan_lib.h"
#include "debug.h"
#include "wlan_oid.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
#define PROC_MCR_ACCESS "mcr"
#if defined(_HIF_USB)
#define PROC_ROOT_NAME "wlan_usb"
#else
#define PROC_ROOT_NAME "wlan"
#endif
#if CFG_SUPPORT_DEBUG_FS
#define PROC_ROAM_PARAM "roam_param"
#define PROC_COUNTRY "country"
#endif
#define PROC_DRV_STATUS "status"
#define PROC_RX_STATISTICS "rx_statistics"
#define PROC_TX_STATISTICS "tx_statistics"
#define PROC_DBG_LEVEL_NAME "dbg_level"
#define PROC_DRIVER_CMD "driver"
#define PROC_CFG "cfg"
#define PROC_EFUSE_DUMP "efuse_dump"
#define PROC_CSI_DATA_NAME "csi_data"
#define PROC_GET_TXPWR_TBL "get_txpwr_tbl"
#define PROC_MCR_ACCESS_MAX_USER_INPUT_LEN 20
#define PROC_RX_STATISTICS_MAX_USER_INPUT_LEN 10
#define PROC_TX_STATISTICS_MAX_USER_INPUT_LEN 10
#define PROC_DBG_LEVEL_MAX_USER_INPUT_LEN 20
#define PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN 30
#define PROC_UID_SHELL 2000
#define PROC_GID_WIFI 1010
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
struct PROC_CSI_FORMAT_T {
UINT_8 ucMagicNum;
UINT_8 ucCsiType;
UINT_16 u2Length;
UINT_64 u8TimeStamp;
INT_8 cRssi;
UINT_8 ucSNR;
} __KAL_ATTRIB_PACKED__;
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
static P_GLUE_INFO_T g_prGlueInfo_proc;
static UINT_32 u4McrOffset;
static struct proc_dir_entry *gprProcRoot;
static UINT_8 aucDbModuleName[][PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN] = {
"INIT", "HAL", "INTR", "REQ", "TX", "RX", "RFTEST", "EMU", "SW1", "SW2",
"SW3", "SW4", "HEM", "AIS", "RLM", "MEM", "CNM", "RSN", "BSS", "SCN",
"SAA", "AAA", "P2P", "QM", "SEC", "BOW", "WAPI", "ROAMING", "TDLS", "PF",
"OID", "NIC"
};
/* This buffer could be overwrite by any proc commands */
static UINT_8 g_aucProcBuf[3000];
/* This u32 is only for DriverCmdRead/Write, should not be used by other function */
static UINT_32 g_u4NextDriverReadLen;
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
static int procCsiDataOpen(struct inode *n, struct file *f)
{
struct CSI_DATA_T *prCsiData = NULL;
if (g_prGlueInfo_proc && g_prGlueInfo_proc->prAdapter) {
prCsiData = &(g_prGlueInfo_proc->prAdapter->rCsiData);
prCsiData->bIncomplete = FALSE;
prCsiData->bIsOutputing = FALSE;
}
return 0;
}
static int procCsiDataRelease(struct inode *n, struct file *f)
{
struct CSI_DATA_T *prCsiData = NULL;
if (g_prGlueInfo_proc && g_prGlueInfo_proc->prAdapter) {
prCsiData = &(g_prGlueInfo_proc->prAdapter->rCsiData);
prCsiData->bIncomplete = FALSE;
prCsiData->bIsOutputing = FALSE;
}
return 0;
}
static ssize_t procCsiDataPrepare(UINT_8 *buf, struct CSI_DATA_T *prCsiData)
{
INT_32 i4Pos = 0;
enum ENUM_CSI_MODULATION_BW_TYPE_T eModulationType = CSI_TYPE_CCK_BW20;
struct PROC_CSI_FORMAT_T rProcCsiData;
if (prCsiData->ucBw == 0)
eModulationType = prCsiData->bIsCck ? CSI_TYPE_CCK_BW20 : CSI_TYPE_OFDM_BW20;
else if (prCsiData->ucBw == 1)
eModulationType = CSI_TYPE_OFDM_BW40;
else if (prCsiData->ucBw == 2)
eModulationType = CSI_TYPE_OFDM_BW80;
rProcCsiData.ucMagicNum = 0xAB; /* magic number */
rProcCsiData.ucCsiType = eModulationType;
rProcCsiData.u2Length = (UINT_16) (14 + prCsiData->u2DataCount * sizeof(INT_16) * 2);
kalMemCopy(&(rProcCsiData.u8TimeStamp), &(prCsiData->u8TimeStamp), sizeof(UINT_64));
rProcCsiData.cRssi = prCsiData->cRssi;
rProcCsiData.ucSNR = prCsiData->ucSNR;
i4Pos = sizeof(rProcCsiData);
kalMemCopy(buf, &rProcCsiData, i4Pos);
kalMemCopy(&buf[i4Pos], prCsiData->ac2IData, prCsiData->u2DataCount * sizeof(INT_16));
i4Pos += prCsiData->u2DataCount * sizeof(INT_16);
kalMemCopy(&buf[i4Pos], prCsiData->ac2QData, prCsiData->u2DataCount * sizeof(INT_16));
i4Pos += prCsiData->u2DataCount * sizeof(INT_16);
return i4Pos;
}
static ssize_t procCsiDataRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
UINT_8 *temp = &g_aucProcBuf[0];
UINT_32 u4CopySize = 0;
UINT_32 u4StartIdx = 0;
INT_32 i4Pos = 0;
struct CSI_DATA_T *prCsiData = NULL;
if (g_prGlueInfo_proc && g_prGlueInfo_proc->prAdapter)
prCsiData = &(g_prGlueInfo_proc->prAdapter->rCsiData);
else
return 0;
if (prCsiData->bIncomplete == FALSE) {
/*
* No older CSI data in buffer waiting for reading out, so prepare a new one
* for reading.
*/
wait_event_interruptible(prCsiData->waitq, prCsiData->u2DataCount != 0);
prCsiData->bIsOutputing = TRUE;
i4Pos = procCsiDataPrepare(temp, prCsiData);
}
if (prCsiData->bIncomplete == FALSE) {
/* The frist run of reading the CSI data */
u4StartIdx = 0;
if (i4Pos > count) {
u4CopySize = count;
prCsiData->u4RemainingDataSize = i4Pos - count;
prCsiData->u4CopiedDataSize = count;
prCsiData->bIncomplete = TRUE;
} else {
u4CopySize = i4Pos;
prCsiData->bIncomplete = FALSE;
}
} else {
/* Reading the remaining CSI data in the buffer */
u4StartIdx = prCsiData->u4CopiedDataSize;
if (prCsiData->u4RemainingDataSize > count) {
u4CopySize = count;
prCsiData->u4RemainingDataSize -= count;
prCsiData->u4CopiedDataSize += count;
} else {
u4CopySize = prCsiData->u4RemainingDataSize;
prCsiData->bIncomplete = FALSE;
}
}
if (copy_to_user(buf, &g_aucProcBuf[u4StartIdx], u4CopySize)) {
DBGLOG(INIT, ERROR, "copy to user failed\n");
return -EFAULT;
}
*f_pos += u4CopySize;
if (prCsiData->bIncomplete == FALSE) {
prCsiData->bIsOutputing = FALSE;
prCsiData->u2DataCount = 0;
}
return (ssize_t)u4CopySize;
}
static ssize_t procDbgLevelRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
UINT_8 *temp = &g_aucProcBuf[0];
UINT_32 u4CopySize = 0;
UINT_16 i;
UINT_16 u2ModuleNum = 0;
UINT_32 u4BufMax = sizeof(g_aucProcBuf);
INT_32 i4Pos = 0;
/* if *f_ops>0, we should return 0 to make cat command exit */
if (*f_pos > 0)
return 0;
i4Pos = scnprintf(temp, (sizeof(g_aucProcBuf) - i4Pos),
"\nERROR|WARN|STATE|EVENT|TRACE|INFO|LOUD|TEMP\n"
"bit0 |bit1|bit2 |bit3 |bit4 |bit5|bit6|bit7\n\n"
"Debug Module\tIndex\tLevel\tDebug Module\tIndex\tLevel\n\n");
u2ModuleNum = (sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & 0xfe;
for (i = 0; i < u2ModuleNum; i += 2)
i4Pos += scnprintf((temp + i4Pos), (u4BufMax - i4Pos),
"DBG_%s_IDX\t(0x%02x):\t0x%02x\tDBG_%s_IDX\t(0x%02x):\t0x%02x\n",
&aucDbModuleName[i][0], i, aucDebugModule[i],
&aucDbModuleName[i+1][0], i+1, aucDebugModule[i+1]);
if ((sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & 0x1)
i4Pos += scnprintf((temp + i4Pos), (u4BufMax - i4Pos),
"DBG_%s_IDX\t(0x%02x):\t0x%02x\n",
&aucDbModuleName[u2ModuleNum][0], u2ModuleNum, aucDebugModule[u2ModuleNum]);
u4CopySize = i4Pos;
if (u4CopySize > count)
u4CopySize = count;
if (copy_to_user(buf, g_aucProcBuf, u4CopySize)) {
DBGLOG(INIT, ERROR, "copy to user failed\n");
return -EFAULT;
}
*f_pos += u4CopySize;
return (ssize_t)u4CopySize;
}
#if WLAN_INCLUDE_PROC
#if CFG_SUPPORT_EASY_DEBUG
static void *procEfuseDump_start(struct seq_file *s, loff_t *pos)
{
static unsigned long counter;
if (*pos == 0)
counter = *pos; /* read file init */
if (counter >= EFUSE_ADDR_MAX)
return NULL;
return &counter;
}
static void *procEfuseDump_next(struct seq_file *s, void *v, loff_t *pos)
{
unsigned long *tmp_v = (unsigned long *)v;
(*tmp_v) += EFUSE_BLOCK_SIZE;
if (*tmp_v >= EFUSE_ADDR_MAX)
return NULL;
return tmp_v;
}
static void procEfuseDump_stop(struct seq_file *s, void *v)
{
/* nothing to do, we use a static value in start() */
}
static int procEfuseDump_show(struct seq_file *s, void *v)
{
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
UINT_32 u4BufLen = 0;
P_GLUE_INFO_T prGlueInfo;
UINT_32 idx_addr, idx_value;
PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfo = {};
prGlueInfo = g_prGlueInfo_proc;
#if (CFG_EEPROM_PAGE_ACCESS == 1)
idx_addr = *(loff_t *)v;
rAccessEfuseInfo.u4Address = (idx_addr / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE;
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryProcessAccessEfuseRead,
&rAccessEfuseInfo,
sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), TRUE, TRUE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
seq_printf(s, "efuse read fail (0x%03X)\n", rAccessEfuseInfo.u4Address);
return 0;
}
for (idx_value = 0; idx_value < EFUSE_BLOCK_SIZE; idx_value++)
seq_printf(s, "0x%03X=0x%02X\n"
, rAccessEfuseInfo.u4Address+idx_value
, prGlueInfo->prAdapter->aucEepromVaule[idx_value]);
return 0;
#else
seq_puts(s, "efuse ops is invalid\n");
return -EPERM; /* return negative value to stop read process */
#endif
}
static int procEfuseDumpOpen(struct inode *inode, struct file *file)
{
static const struct seq_operations procEfuseDump_ops = {
.start = procEfuseDump_start,
.next = procEfuseDump_next,
.stop = procEfuseDump_stop,
.show = procEfuseDump_show
};
return seq_open(file, &procEfuseDump_ops);
}
static ssize_t procCfgRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
UINT_8 *temp = &g_aucProcBuf[0];
UINT_32 u4CopySize = 0;
UINT_16 i;
INT_32 i4Pos = 0;
UINT_32 u4BufMax = sizeof(g_aucProcBuf);
#define BUFFER_RESERVE_BYTE 50
P_GLUE_INFO_T prGlueInfo;
P_WLAN_CFG_ENTRY_T prWlanCfgEntry;
P_ADAPTER_T prAdapter;
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(gPrDev));
if (!prGlueInfo) {
DBGLOG(INIT, ERROR, "procCfgRead prGlueInfo is NULL?\n");
return -EFAULT;
}
prAdapter = prGlueInfo->prAdapter;
/* if *f_ops>0, we should return 0 to make cat command exit */
if (*f_pos > 0)
return 0;
i4Pos = scnprintf(temp, (sizeof(g_aucProcBuf) - i4Pos), "\nDUMP CONFIGURATION :\n"
"<KEY|VALUE> OR <D:KEY|VALUE>\n"
"'D': driver part current setting\n"
"===================================\n");
for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) {
prWlanCfgEntry = wlanCfgGetEntryByIndex(prAdapter, i, 0);
if ((!prWlanCfgEntry) || (prWlanCfgEntry->aucKey[0] == '\0'))
break;
i4Pos += scnprintf((temp + i4Pos), (u4BufMax - i4Pos),
"%s|%s\n", prWlanCfgEntry->aucKey, prWlanCfgEntry->aucValue);
if (i4Pos > (sizeof(g_aucProcBuf)-BUFFER_RESERVE_BYTE))
break;
}
for (i = 0; i < WLAN_CFG_REC_ENTRY_NUM_MAX; i++) {
prWlanCfgEntry = wlanCfgGetEntryByIndex(prAdapter, i, 1);
if ((!prWlanCfgEntry) || (prWlanCfgEntry->aucKey[0] == '\0'))
break;
i4Pos += scnprintf((temp + i4Pos), (u4BufMax - i4Pos),
"D:%s|%s\n", prWlanCfgEntry->aucKey, prWlanCfgEntry->aucValue);
if (i4Pos > (sizeof(g_aucProcBuf)-BUFFER_RESERVE_BYTE))
break;
}
u4CopySize = i4Pos;
if (u4CopySize > count)
u4CopySize = count;
if (copy_to_user(buf, g_aucProcBuf, u4CopySize)) {
DBGLOG(INIT, ERROR, "copy to user failed\n");
return -EFAULT;
}
*f_pos += u4CopySize;
return (ssize_t)u4CopySize;
}
static ssize_t procCfgWrite(struct file *file, const char __user *buffer,
size_t count, loff_t *data)
{
/* UINT_32 u4DriverCmd, u4DriverValue;
*UINT_8 *temp = &g_aucProcBuf[0];
*/
UINT_32 u4CopySize = sizeof(g_aucProcBuf);
P_GLUE_INFO_T prGlueInfo;
PUINT_8 pucTmp;
INT_32 i4Pos = 0;
/* PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; */
kalMemSet(g_aucProcBuf, 0, u4CopySize);
if (u4CopySize >= (count+1))
u4CopySize = count;
else
u4CopySize -= 1;
pucTmp = g_aucProcBuf;
i4Pos = scnprintf(pucTmp, sizeof(g_aucProcBuf), "%s ", "set_cfg");
pucTmp += i4Pos;
u4CopySize -= i4Pos;
if (copy_from_user(pucTmp, buffer, u4CopySize)) {
DBGLOG(INIT, ERROR, "error of copy from user\n");
return -EFAULT;
}
g_aucProcBuf[u4CopySize] = '\0';
prGlueInfo = g_prGlueInfo_proc;
/* if g_u4NextDriverReadLen >0,
* the content for next DriverCmdRead will be in : g_aucProcBuf with length : g_u4NextDriverReadLen
*/
g_u4NextDriverReadLen = priv_driver_set_cfg(prGlueInfo->prDevHandler, g_aucProcBuf, sizeof(g_aucProcBuf));
return count;
}
static ssize_t procDriverCmdRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
/* DriverCmd read should only be executed right after a DriverCmd write
* because content buffer 'g_aucProcBuf' is a global buffer for all proc command,
* otherwise , the content could be overwrite by other proc command
*/
UINT_32 u4CopySize = 0;
/* if *f_ops>0, we should return 0 to make cat command exit */
if (*f_pos > 0)
return 0;
if (g_u4NextDriverReadLen > 0) /* Detect content to show */
u4CopySize = g_u4NextDriverReadLen;
if (copy_to_user(buf, g_aucProcBuf, u4CopySize)) {
DBGLOG(INIT, ERROR, "copy to user failed\n");
return -EFAULT;
}
g_u4NextDriverReadLen = 0;
*f_pos += u4CopySize;
return (ssize_t)u4CopySize;
}
static ssize_t procDriverCmdWrite(struct file *file, const char __user *buffer,
size_t count, loff_t *data)
{
/* UINT_32 u4DriverCmd, u4DriverValue;
* UINT_8 *temp = &g_aucProcBuf[0];
*/
UINT_32 u4CopySize = sizeof(g_aucProcBuf);
P_GLUE_INFO_T prGlueInfo;
/* PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; */
kalMemSet(g_aucProcBuf, 0, u4CopySize);
if (u4CopySize >= (count+1))
u4CopySize = count;
else
u4CopySize -= 1;
if (copy_from_user(g_aucProcBuf, buffer, u4CopySize)) {
DBGLOG(INIT, ERROR, "error of copy from user\n");
return -EFAULT;
}
g_aucProcBuf[u4CopySize] = '\0';
prGlueInfo = g_prGlueInfo_proc;
/* if g_u4NextDriverReadLen >0,
* the content for next DriverCmdRead will be in : g_aucProcBuf with length : g_u4NextDriverReadLen
*/
g_u4NextDriverReadLen = priv_driver_cmds(prGlueInfo->prDevHandler, g_aucProcBuf, sizeof(g_aucProcBuf));
return count;
}
#endif
#endif
static ssize_t procDbgLevelWrite(struct file *file, const char __user *buffer,
size_t count, loff_t *data)
{
UINT_32 u4NewDbgModule, u4NewDbgLevel;
UINT_8 *temp = &g_aucProcBuf[0];
UINT_32 u4CopySize = sizeof(g_aucProcBuf);
kalMemSet(g_aucProcBuf, 0, u4CopySize);
if (u4CopySize >= count+1)
u4CopySize = count;
else
u4CopySize -= 1;
if (copy_from_user(g_aucProcBuf, buffer, u4CopySize)) {
DBGLOG(INIT, ERROR, "error of copy from user\n");
return -EFAULT;
}
g_aucProcBuf[u4CopySize] = '\0';
while (temp) {
if (sscanf(temp, "0x%x:0x%x", &u4NewDbgModule, &u4NewDbgLevel) != 2) {
DBGLOG(INIT, ERROR, "debug module and debug level should be one byte in length\n");
break;
}
if (u4NewDbgModule == 0xFF) {
UINT_8 i = 0;
for (; i < DBG_MODULE_NUM; i++)
aucDebugModule[i] = u4NewDbgLevel & DBG_CLASS_MASK;
break;
}
if (u4NewDbgModule >= DBG_MODULE_NUM) {
DBGLOG(INIT, ERROR, "debug module index should less than %d\n", DBG_MODULE_NUM);
break;
}
aucDebugModule[u4NewDbgModule] = u4NewDbgLevel & DBG_CLASS_MASK;
temp = kalStrChr(temp, ',');
if (!temp)
break;
temp++; /* skip ',' */
}
return count;
}
#define TXPWR_TABLE_ENTRY(_siso_mcs, _cdd_mcs, _mimo_mcs, _idx) \
{ \
.mcs[STREAM_SISO] = _siso_mcs, \
.mcs[STREAM_CDD] = _cdd_mcs, \
.mcs[STREAM_MIMO] = _mimo_mcs, \
.idx = (_idx), \
}
static struct txpwr_table_entry dsss[] = {
TXPWR_TABLE_ENTRY("DSSS1", "", "", PWR_DSSS_CCK),
TXPWR_TABLE_ENTRY("DSSS2", "", "", PWR_DSSS_CCK),
TXPWR_TABLE_ENTRY("CCK5", "", "", PWR_DSSS_BPKS),
TXPWR_TABLE_ENTRY("CCK11", "", "", PWR_DSSS_BPKS),
};
static struct txpwr_table_entry ofdm[] = {
TXPWR_TABLE_ENTRY("OFDM6", "OFDM6", "", PWR_OFDM_BPSK),
TXPWR_TABLE_ENTRY("OFDM9", "OFDM9", "", PWR_OFDM_BPSK),
TXPWR_TABLE_ENTRY("OFDM12", "OFDM12", "", PWR_OFDM_QPSK),
TXPWR_TABLE_ENTRY("OFDM18", "OFDM18", "", PWR_OFDM_QPSK),
TXPWR_TABLE_ENTRY("OFDM24", "OFDM24", "", PWR_OFDM_16QAM),
TXPWR_TABLE_ENTRY("OFDM36", "OFDM36", "", PWR_OFDM_16QAM),
TXPWR_TABLE_ENTRY("OFDM48", "OFDM48", "", PWR_OFDM_48Mbps),
TXPWR_TABLE_ENTRY("OFDM54", "OFDM54", "", PWR_OFDM_54Mbps),
};
static struct txpwr_table_entry ht[] = {
TXPWR_TABLE_ENTRY("MCS0", "MCS0", "MCS8", PWR_HT_BPSK),
TXPWR_TABLE_ENTRY("MCS1", "MCS1", "MCS9", PWR_HT_QPSK),
TXPWR_TABLE_ENTRY("MCS2", "MCS2", "MCS10", PWR_HT_QPSK),
TXPWR_TABLE_ENTRY("MCS3", "MCS3", "MCS11", PWR_HT_16QAM),
TXPWR_TABLE_ENTRY("MCS4", "MCS4", "MCS12", PWR_HT_16QAM),
TXPWR_TABLE_ENTRY("MCS5", "MCS5", "MCS13", PWR_HT_MCS5),
TXPWR_TABLE_ENTRY("MCS6", "MCS6", "MCS14", PWR_HT_MCS6),
TXPWR_TABLE_ENTRY("MCS7", "MCS7", "MCS15", PWR_HT_MCS7),
};
static struct txpwr_table_entry vht[] = {
TXPWR_TABLE_ENTRY("MCS0", "MCS0", "MCS0", PWR_VHT20_BPSK),
TXPWR_TABLE_ENTRY("MCS1", "MCS1", "MCS1", PWR_VHT20_QPSK),
TXPWR_TABLE_ENTRY("MCS2", "MCS2", "MCS2", PWR_VHT20_QPSK),
TXPWR_TABLE_ENTRY("MCS3", "MCS3", "MCS3", PWR_VHT20_16QAM),
TXPWR_TABLE_ENTRY("MCS4", "MCS4", "MCS4", PWR_VHT20_16QAM),
TXPWR_TABLE_ENTRY("MCS5", "MCS5", "MCS5", PWR_VHT20_64QAM),
TXPWR_TABLE_ENTRY("MCS6", "MCS6", "MCS6", PWR_VHT20_64QAM),
TXPWR_TABLE_ENTRY("MCS7", "MCS7", "MCS7", PWR_VHT20_MCS7),
TXPWR_TABLE_ENTRY("MCS8", "MCS8", "MCS8", PWR_VHT20_MCS8),
TXPWR_TABLE_ENTRY("MCS9", "MCS9", "MCS9", PWR_VHT20_MCS9),
};
static struct txpwr_table txpwr_tables[] = {
{"Legacy", dsss, ARRAY_SIZE(dsss)},
{"11g", ofdm, ARRAY_SIZE(ofdm)},
{"11a", ofdm, ARRAY_SIZE(ofdm)},
{"HT20", ht, ARRAY_SIZE(ht)},
{"HT40", ht, ARRAY_SIZE(ht)},
{"VHT20", vht, ARRAY_SIZE(vht)},
{"VHT40", vht, ARRAY_SIZE(vht)},
{"VHT80", vht, ARRAY_SIZE(vht)},
};
#define TMP_SZ (448)
#define CDD_PWR_OFFSET (6)
void print_txpwr_tbl(struct txpwr_table *txpwr_tbl, unsigned char ch,
unsigned char *tx_pwr[], char pwr_offset[],
char *stream_buf[], unsigned int stream_pos[])
{
struct txpwr_table_entry *tmp_tbl = txpwr_tbl->tables;
unsigned int idx, pwr_idx, stream_idx;
char pwr[TXPWR_TBL_NUM] = {0}, tmp_pwr = 0;
char prefix[5], tmp[4];
char *buf = NULL;
unsigned int *pos = NULL;
int i;
for (i = 0; i < txpwr_tbl->n_tables; i++) {
idx = tmp_tbl[i].idx;
for (pwr_idx = 0; pwr_idx < TXPWR_TBL_NUM; pwr_idx++) {
if (!tx_pwr[pwr_idx]) {
DBGLOG(REQ, WARN,
"Power table[%d] is NULL\n", pwr_idx);
return;
}
pwr[pwr_idx] = tx_pwr[pwr_idx][idx] +
pwr_offset[pwr_idx];
pwr[pwr_idx] = (pwr[pwr_idx] > MAX_TX_POWER) ?
MAX_TX_POWER : pwr[pwr_idx];
}
for (stream_idx = 0; stream_idx < STREAM_NUM; stream_idx++) {
buf = stream_buf[stream_idx];
pos = &stream_pos[stream_idx];
if (tmp_tbl[i].mcs[stream_idx][0] == '\0')
continue;
switch (stream_idx) {
case STREAM_SISO:
kalStrnCpy(prefix, "siso", sizeof(prefix));
break;
case STREAM_CDD:
kalStrnCpy(prefix, "cdd", sizeof(prefix));
break;
case STREAM_MIMO:
kalStrnCpy(prefix, "mimo", sizeof(prefix));
break;
}
*pos += kalScnprintf(buf + *pos, TMP_SZ - *pos,
"%s, %d, %s, %s, ",
prefix, ch,
txpwr_tbl->phy_mode,
tmp_tbl[i].mcs[stream_idx]);
for (pwr_idx = 0; pwr_idx < TXPWR_TBL_NUM; pwr_idx++) {
/* The target power of cdd less
* 3dBm than siso
*/
tmp_pwr = (pwr_idx == MAC_TBL &&
stream_idx == STREAM_CDD) ?
pwr[pwr_idx] - CDD_PWR_OFFSET :
pwr[pwr_idx];
tmp_pwr = (tmp_pwr > 0) ? tmp_pwr : 0;
if (pwr_idx + 1 == TXPWR_TBL_NUM)
kalStrnCpy(tmp, "\n", sizeof(tmp));
else
kalStrnCpy(tmp, ", ", sizeof(tmp));
*pos += kalScnprintf(buf + *pos, TMP_SZ - *pos,
"%d.%d%s",
tmp_pwr / 2,
tmp_pwr % 2 * 5,
tmp);
}
}
}
}
static ssize_t procGetTxpwrTblRead(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
P_GLUE_INFO_T prGlueInfo = NULL;
P_ADAPTER_T prAdapter = NULL;
P_BSS_INFO_T prBssInfo = NULL;
unsigned char ucBssIndex;
P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = NULL;
WLAN_STATUS status;
struct PARAM_CMD_GET_TXPWR_TBL pwr_tbl;
struct POWER_LIMIT *tx_pwr_tbl = pwr_tbl.tx_pwr_tbl;
char *buffer;
unsigned int pos = 0, buf_len = count, oid_len;
unsigned char i, j;
char *stream_buf[STREAM_NUM] = {NULL};
unsigned int stream_pos[STREAM_NUM] = {0};
unsigned char *tx_pwr[TXPWR_TBL_NUM] = {NULL};
char pwr_offset[TXPWR_TBL_NUM] = {0};
unsigned char offset = 0;
int ret;
/* if *f_ops>0, we should return 0 to make cat command exit */
if (*f_pos > 0)
return 0;
prGlueInfo = g_prGlueInfo_proc;
if (!prGlueInfo)
return -EFAULT;
prAdapter = prGlueInfo->prAdapter;
prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) netdev_priv(gPrDev);
if (prNetDevPrivate->prGlueInfo != prGlueInfo)
return -EFAULT;
ucBssIndex = prNetDevPrivate->ucBssIdx;
prBssInfo = prAdapter->aprBssInfo[ucBssIndex];
if (!prBssInfo)
return -EFAULT;
kalMemZero(&pwr_tbl, sizeof(pwr_tbl));
if (prAdapter->rWifiVar.fgDbDcModeEn)
pwr_tbl.ucDbdcIdx = prBssInfo->eDBDCBand;
else
pwr_tbl.ucDbdcIdx = ENUM_BAND_0;
status = kalIoctl(prGlueInfo,
wlanoidGetTxPwrTbl,
&pwr_tbl,
sizeof(pwr_tbl), TRUE, FALSE, TRUE, &oid_len);
if (status != WLAN_STATUS_SUCCESS) {
DBGLOG(REQ, WARN, "Query Tx Power Table fail\n");
return -EINVAL;
}
buffer = (char *) kalMemAlloc(buf_len, VIR_MEM_TYPE);
if (!buffer)
return -ENOMEM;
for (i = 0; i < STREAM_NUM; i++) {
stream_buf[i] = (char *) kalMemAlloc(TMP_SZ, VIR_MEM_TYPE);
if (!stream_buf[i]) {
ret = -ENOMEM;
goto out;
}
}
pos = kalScnprintf(buffer, buf_len,
"\n%s",
"spatial stream, Channel, bw, modulation, ");
pos += kalScnprintf(buffer + pos, buf_len - pos,
"%s\n",
"regulatory limit, board limit, target power");
for (i = 0; i < ARRAY_SIZE(txpwr_tables); i++) {
for (j = 0; j < STREAM_NUM; j++) {
kalMemZero(stream_buf[j], TMP_SZ);
stream_pos[j] = 0;
}
for (j = 0; j < TXPWR_TBL_NUM; j++) {
tx_pwr[j] = NULL;
pwr_offset[j] = 0;
}
switch (i) {
case DSSS:
if (pwr_tbl.ucCenterCh > 14)
continue;
for (j = 0; j < TXPWR_TBL_NUM; j++)
tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_dsss;
break;
case OFDM_24G:
if (pwr_tbl.ucCenterCh > 14)
continue;
for (j = 0; j < TXPWR_TBL_NUM; j++)
tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_ofdm;
break;
case OFDM_5G:
if (pwr_tbl.ucCenterCh <= 14)
continue;
for (j = 0; j < TXPWR_TBL_NUM; j++)
tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_ofdm;
break;
case HT20:
for (j = 0; j < TXPWR_TBL_NUM; j++)
tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_ht20;
break;
case HT40:
for (j = 0; j < TXPWR_TBL_NUM; j++)
tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_ht40;
break;
case VHT20:
if (pwr_tbl.ucCenterCh <= 14)
continue;
for (j = 0; j < TXPWR_TBL_NUM; j++)
tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_vht20;
break;
case VHT40:
case VHT80:
if (pwr_tbl.ucCenterCh <= 14)
continue;
offset = (i == VHT40) ?
PWR_Vht40_OFFSET : PWR_Vht80_OFFSET;
for (j = 0; j < TXPWR_TBL_NUM; j++) {
tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_vht20;
pwr_offset[j] =
tx_pwr_tbl[j].tx_pwr_vht_OFST[offset];
/* Covert 7bit 2'complement value to 8bit */
pwr_offset[j] |= (pwr_offset[j] & BIT(6)) ?
BIT(7) : 0;
}
break;
default:
break;
}
print_txpwr_tbl(&txpwr_tables[i], pwr_tbl.ucCenterCh,
tx_pwr, pwr_offset,
stream_buf, stream_pos);
for (j = 0; j < STREAM_NUM; j++) {
pos += kalScnprintf(buffer + pos, buf_len - pos,
"%s",
stream_buf[j]);
}
}
if (copy_to_user(buf, buffer, pos)) {
DBGLOG(INIT, ERROR, "copy to user failed\n");
ret = -EFAULT;
goto out;
}
*f_pos += pos;
ret = pos;
out:
for (i = 0; i < STREAM_NUM; i++) {
if (stream_buf[i])
kalMemFree(stream_buf[i], VIR_MEM_TYPE, TMP_SZ);
}
kalMemFree(buffer, VIR_MEM_TYPE, buf_len);
return ret;
}
static const struct file_operations dbglevel_ops = {
.owner = THIS_MODULE,
.read = procDbgLevelRead,
.write = procDbgLevelWrite,
};
static const struct file_operations csidata_ops = {
.owner = THIS_MODULE,
.read = procCsiDataRead,
.open = procCsiDataOpen,
.release = procCsiDataRelease,
};
#if WLAN_INCLUDE_PROC
#if CFG_SUPPORT_EASY_DEBUG
static const struct file_operations efusedump_ops = {
.owner = THIS_MODULE,
.open = procEfuseDumpOpen,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static const struct file_operations drivercmd_ops = {
.owner = THIS_MODULE,
.read = procDriverCmdRead,
.write = procDriverCmdWrite,
};
static const struct file_operations cfg_ops = {
.owner = THIS_MODULE,
.read = procCfgRead,
.write = procCfgWrite,
};
#endif
#endif
static const struct file_operations get_txpwr_tbl_ops = {
.owner = THIS_MODULE,
.read = procGetTxpwrTblRead,
};
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
/*----------------------------------------------------------------------------*/
/*!
* \brief The PROC function for reading MCR register to User Space, the offset of
* the MCR is specified in u4McrOffset.
*
* \param[in] page Buffer provided by kernel.
* \param[in out] start Start Address to read(3 methods).
* \param[in] off Offset.
* \param[in] count Allowable number to read.
* \param[out] eof End of File indication.
* \param[in] data Pointer to the private data structure.
*
* \return number of characters print to the buffer from User Space.
*/
/*----------------------------------------------------------------------------*/
static ssize_t procMCRRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
P_GLUE_INFO_T prGlueInfo;
PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo;
UINT_32 u4BufLen;
UINT_8 *temp = &g_aucProcBuf[0];
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
INT_32 i4Count = 0;
/* Kevin: Apply PROC read method 1. */
if (*f_pos > 0)
return 0; /* To indicate end of file. */
prGlueInfo = g_prGlueInfo_proc;
rMcrInfo.u4McrOffset = u4McrOffset;
rStatus = kalIoctl(prGlueInfo,
wlanoidQueryMcrRead, (PVOID)&rMcrInfo, sizeof(rMcrInfo), TRUE, TRUE, TRUE, &u4BufLen);
kalMemZero(g_aucProcBuf, sizeof(g_aucProcBuf));
i4Count = scnprintf(temp, sizeof(g_aucProcBuf),
"MCR (0x%08xh): 0x%08x\n", rMcrInfo.u4McrOffset, rMcrInfo.u4McrData);
if (copy_to_user(buf, g_aucProcBuf, i4Count)) {
DBGLOG(INIT, ERROR, "copy to user failed\n");
return -EFAULT;
}
*f_pos += i4Count;
return i4Count;
} /* end of procMCRRead() */
/*----------------------------------------------------------------------------*/
/*!
* \brief The PROC function for writing MCR register to HW or update u4McrOffset
* for reading MCR later.
*
* \param[in] file pointer to file.
* \param[in] buffer Buffer from user space.
* \param[in] count Number of characters to write
* \param[in] data Pointer to the private data structure.
*
* \return number of characters write from User Space.
*/
/*----------------------------------------------------------------------------*/
static ssize_t procMCRWrite(struct file *file, const char __user *buffer,
size_t count, loff_t *data)
{
P_GLUE_INFO_T prGlueInfo;
char acBuf[PROC_MCR_ACCESS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */
int i4CopySize;
PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo;
UINT_32 u4BufLen;
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
int num = 0;
ASSERT(data);
i4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1);
if (copy_from_user(acBuf, buffer, i4CopySize))
return 0;
acBuf[i4CopySize] = '\0';
num = sscanf(acBuf, "0x%x 0x%x", &rMcrInfo.u4McrOffset, &rMcrInfo.u4McrData);
switch (num) {
case 2:
/* NOTE: Sometimes we want to test if bus will still be ok, after accessing
* the MCR which is not align to DW boundary.
*/
/* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */
{
prGlueInfo = (P_GLUE_INFO_T) netdev_priv((struct net_device *)data);
u4McrOffset = rMcrInfo.u4McrOffset;
/* printk("Write 0x%lx to MCR 0x%04lx\n", */
/* rMcrInfo.u4McrOffset, rMcrInfo.u4McrData); */
rStatus = kalIoctl(prGlueInfo,
wlanoidSetMcrWrite,
(PVOID)&rMcrInfo, sizeof(rMcrInfo), FALSE, FALSE, TRUE, &u4BufLen);
}
break;
case 1:
/* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */
{
u4McrOffset = rMcrInfo.u4McrOffset;
}
break;
default:
break;
}
return count;
} /* end of procMCRWrite() */
static const struct file_operations mcr_ops = {
.owner = THIS_MODULE,
.read = procMCRRead,
.write = procMCRWrite,
};
#if CFG_SUPPORT_DEBUG_FS
static ssize_t procRoamRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
UINT_32 u4CopySize;
WLAN_STATUS rStatus;
UINT_32 u4BufLen;
/* if *f_pos > 0, it means has read successed last time, don't try again */
if (*f_pos > 0)
return 0;
rStatus = kalIoctl(g_prGlueInfo_proc, wlanoidGetRoamParams, g_aucProcBuf, sizeof(g_aucProcBuf),
TRUE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "failed to read roam params\n");
return -EINVAL;
}
u4CopySize = kalStrLen(g_aucProcBuf);
if (copy_to_user(buf, g_aucProcBuf, u4CopySize)) {
DBGLOG(INIT, ERROR, "copy to user failed\n");
return -EFAULT;
}
*f_pos += u4CopySize;
return (INT_32)u4CopySize;
}
static ssize_t procRoamWrite(struct file *file, const char __user *buffer,
size_t count, loff_t *data)
{
WLAN_STATUS rStatus;
UINT_32 u4BufLen = 0;
UINT_32 u4CopySize = sizeof(g_aucProcBuf);
kalMemSet(g_aucProcBuf, 0, u4CopySize);
if (u4CopySize >= count+1)
u4CopySize = count;
else
u4CopySize -= 1;
if (copy_from_user(g_aucProcBuf, buffer, u4CopySize)) {
DBGLOG(INIT, ERROR, "error of copy from user\n");
return -EFAULT;
}
g_aucProcBuf[u4CopySize] = '\0';
if (kalStrnCmp(g_aucProcBuf, "force_roam", 10) == 0)
rStatus = kalIoctl(g_prGlueInfo_proc, wlanoidSetForceRoam, NULL, 0,
FALSE, FALSE, TRUE, &u4BufLen);
else
rStatus = kalIoctl(g_prGlueInfo_proc, wlanoidSetRoamParams, g_aucProcBuf,
kalStrLen(g_aucProcBuf), FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "failed to set roam params: %s\n", g_aucProcBuf);
return -EINVAL;
}
return count;
}
static const struct file_operations roam_ops = {
.owner = THIS_MODULE,
.read = procRoamRead,
.write = procRoamWrite,
};
static ssize_t procCountryRead(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
UINT_32 u4CopySize;
UINT_16 u2CountryCode = 0;
UINT_32 u4BufLen;
WLAN_STATUS rStatus;
/* if *f_pos > 0, it means has read successed last time, don't try again */
if (*f_pos > 0)
return 0;
rStatus = kalIoctl(g_prGlueInfo_proc, wlanoidGetCountryCode,
&u2CountryCode, 2, TRUE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "failed to get country code\n");
return -EINVAL;
}
if (u2CountryCode)
kalSprintf(g_aucProcBuf, "Current Country Code: %c%c\n",
(u2CountryCode>>8) & 0xff, u2CountryCode & 0xff);
else
kalStrCpy(g_aucProcBuf, "Current Country Code: NULL\n");
u4CopySize = kalStrLen(g_aucProcBuf);
if (copy_to_user(buf, g_aucProcBuf, u4CopySize)) {
DBGLOG(INIT, ERROR, "copy to user failed\n");
return -EFAULT;
}
*f_pos += u4CopySize;
return (INT_32)u4CopySize;
}
static ssize_t procCountryWrite(struct file *file, const char __user *buffer,
size_t count, loff_t *data)
{
UINT_32 u4BufLen = 0;
WLAN_STATUS rStatus;
UINT_32 u4CopySize = sizeof(g_aucProcBuf);
kalMemSet(g_aucProcBuf, 0, u4CopySize);
if (u4CopySize >= count+1)
u4CopySize = count;
else
u4CopySize -= 1;
if (copy_from_user(g_aucProcBuf, buffer, u4CopySize)) {
DBGLOG(INIT, ERROR, "error of copy from user\n");
return -EFAULT;
}
g_aucProcBuf[u4CopySize] = '\0';
rStatus = kalIoctl(g_prGlueInfo_proc, wlanoidSetCountryCode,
&g_aucProcBuf[0], 2, FALSE, FALSE, TRUE, &u4BufLen);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, INFO, "failed set country code: %s\n", g_aucProcBuf);
return -EINVAL;
}
return count;
}
static const struct file_operations country_ops = {
.owner = THIS_MODULE,
.read = procCountryRead,
.write = procCountryWrite,
};
#endif
INT_32 procInitFs(VOID)
{
g_u4NextDriverReadLen = 0;
if (init_net.proc_net == (struct proc_dir_entry *)NULL) {
DBGLOG(INIT, ERROR, "init proc fs fail: proc_net == NULL\n");
return -ENOENT;
}
/*
* Directory: Root (/proc/net/wlan0)
*/
gprProcRoot = proc_mkdir(PROC_ROOT_NAME, init_net.proc_net);
if (!gprProcRoot) {
DBGLOG(INIT, ERROR, "gprProcRoot == NULL\n");
return -ENOENT;
}
proc_set_user(gprProcRoot, KUIDT_INIT(PROC_UID_SHELL), KGIDT_INIT(PROC_GID_WIFI));
return 0;
} /* end of procInitProcfs() */
INT_32 procUninitProcFs(VOID)
{
#if KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE
remove_proc_subtree(PROC_ROOT_NAME, init_net.proc_net);
#else
remove_proc_entry(PROC_ROOT_NAME, init_net.proc_net);
#endif
return 0;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function clean up a PROC fs created by procInitProcfs().
*
* \param[in] prDev Pointer to the struct net_device.
* \param[in] pucDevName Pointer to the name of net_device.
*
* \return N/A
*/
/*----------------------------------------------------------------------------*/
INT_32 procRemoveProcfs(VOID)
{
remove_proc_entry(PROC_MCR_ACCESS, gprProcRoot);
remove_proc_entry(PROC_DRIVER_CMD, gprProcRoot);
remove_proc_entry(PROC_DBG_LEVEL_NAME, gprProcRoot);
remove_proc_entry(PROC_CFG, gprProcRoot);
remove_proc_entry(PROC_EFUSE_DUMP, gprProcRoot);
remove_proc_entry(PROC_CSI_DATA_NAME, gprProcRoot);
remove_proc_entry(PROC_GET_TXPWR_TBL, gprProcRoot);
#if CFG_SUPPORT_DEBUG_FS
remove_proc_entry(PROC_ROAM_PARAM, gprProcRoot);
remove_proc_entry(PROC_COUNTRY, gprProcRoot);
#endif
return 0;
} /* end of procRemoveProcfs() */
INT_32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo)
{
struct proc_dir_entry *prEntry;
DBGLOG(INIT, INFO, "[%s]\n", __func__);
g_prGlueInfo_proc = prGlueInfo;
prEntry = proc_create(PROC_MCR_ACCESS, 0664, gprProcRoot, &mcr_ops);
if (prEntry == NULL) {
DBGLOG(INIT, ERROR, "Unable to create /proc entry\n\r");
return -1;
}
#if CFG_SUPPORT_DEBUG_FS
prEntry = proc_create(PROC_ROAM_PARAM, 0664, gprProcRoot, &roam_ops);
if (prEntry == NULL) {
DBGLOG(INIT, ERROR, "Unable to create /proc entry\n\r");
return -1;
}
prEntry = proc_create(PROC_COUNTRY, 0664, gprProcRoot, &country_ops);
if (prEntry == NULL) {
DBGLOG(INIT, ERROR, "Unable to create /proc entry\n\r");
return -1;
}
#endif
#if CFG_SUPPORT_EASY_DEBUG
prEntry = proc_create(PROC_DRIVER_CMD, 0664, gprProcRoot, &drivercmd_ops);
if (prEntry == NULL) {
DBGLOG(INIT, ERROR, "Unable to create /proc entry for driver command\n\r");
return -1;
}
prEntry = proc_create(PROC_CFG, 0664, gprProcRoot, &cfg_ops);
if (prEntry == NULL) {
DBGLOG(INIT, ERROR, "Unable to create /proc entry for driver command\n\r");
return -1;
}
prEntry = proc_create(PROC_EFUSE_DUMP, 0664, gprProcRoot, &efusedump_ops);
if (prEntry == NULL) {
DBGLOG(INIT, ERROR, "Unable to create /proc entry efuse\n\r");
return -1;
}
#endif
prEntry = proc_create(PROC_GET_TXPWR_TBL, 0664, gprProcRoot,
&get_txpwr_tbl_ops);
if (prEntry == NULL) {
DBGLOG(INIT, ERROR, "Unable to create /proc entry efuse\n\r");
return -1;
}
prEntry = proc_create(PROC_DBG_LEVEL_NAME, 0664, gprProcRoot, &dbglevel_ops);
if (prEntry == NULL) {
DBGLOG(INIT, ERROR, "Unable to create /proc entry dbgLevel\n\r");
return -1;
}
prEntry = proc_create(PROC_CSI_DATA_NAME, 0664, gprProcRoot, &csidata_ops);
if (prEntry == NULL) {
DBGLOG(INIT, ERROR, "Unable to create /proc entry csidata\n\r");
return -1;
}
return 0;
}
#if 0
/*----------------------------------------------------------------------------*/
/*!
* \brief The PROC function for reading Driver Status to User Space.
*
* \param[in] page Buffer provided by kernel.
* \param[in out] start Start Address to read(3 methods).
* \param[in] off Offset.
* \param[in] count Allowable number to read.
* \param[out] eof End of File indication.
* \param[in] data Pointer to the private data structure.
*
* \return number of characters print to the buffer from User Space.
*/
/*----------------------------------------------------------------------------*/
static int procDrvStatusRead(char *page, char **start, off_t off, int count, int *eof, void *data)
{
P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv;
char *p = page;
UINT_32 u4Count;
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(data);
/* Kevin: Apply PROC read method 1. */
if (off != 0)
return 0; /* To indicate end of file. */
SPRINTF(p, ("GLUE LAYER STATUS:"));
SPRINTF(p, ("\n=================="));
SPRINTF(p, ("\n* Number of Pending Frames: %ld\n", prGlueInfo->u4TxPendingFrameNum));
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
wlanoidQueryDrvStatusForLinuxProc(prGlueInfo->prAdapter, p, &u4Count);
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
u4Count += (UINT_32) (p - page);
*eof = 1;
return (int)u4Count;
} /* end of procDrvStatusRead() */
/*----------------------------------------------------------------------------*/
/*!
* \brief The PROC function for reading Driver RX Statistic Counters to User Space.
*
* \param[in] page Buffer provided by kernel.
* \param[in out] start Start Address to read(3 methods).
* \param[in] off Offset.
* \param[in] count Allowable number to read.
* \param[out] eof End of File indication.
* \param[in] data Pointer to the private data structure.
*
* \return number of characters print to the buffer from User Space.
*/
/*----------------------------------------------------------------------------*/
static int procRxStatisticsRead(char *page, char **start, off_t off, int count, int *eof, void *data)
{
P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv;
char *p = page;
UINT_32 u4Count;
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(data);
/* Kevin: Apply PROC read method 1. */
if (off != 0)
return 0; /* To indicate end of file. */
SPRINTF(p, ("RX STATISTICS (Write 1 to clear):"));
SPRINTF(p, ("\n=================================\n"));
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
wlanoidQueryRxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count);
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
u4Count += (UINT_32) (p - page);
*eof = 1;
return (int)u4Count;
} /* end of procRxStatisticsRead() */
/*----------------------------------------------------------------------------*/
/*!
* \brief The PROC function for reset Driver RX Statistic Counters.
*
* \param[in] file pointer to file.
* \param[in] buffer Buffer from user space.
* \param[in] count Number of characters to write
* \param[in] data Pointer to the private data structure.
*
* \return number of characters write from User Space.
*/
/*----------------------------------------------------------------------------*/
static int procRxStatisticsWrite(struct file *file, const char *buffer, unsigned long count, void *data)
{
P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv;
char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */
UINT_32 u4CopySize;
UINT_32 u4ClearCounter;
INT_32 rv;
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(data);
u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1);
copy_from_user(acBuf, buffer, u4CopySize);
acBuf[u4CopySize] = '\0';
rv = kstrtoint(acBuf, 0, &u4ClearCounter);
if (rv == 1) {
if (u4ClearCounter == 1) {
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
wlanoidSetRxStatisticsForLinuxProc(prGlueInfo->prAdapter);
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
}
}
return count;
} /* end of procRxStatisticsWrite() */
/*----------------------------------------------------------------------------*/
/*!
* \brief The PROC function for reading Driver TX Statistic Counters to User Space.
*
* \param[in] page Buffer provided by kernel.
* \param[in out] start Start Address to read(3 methods).
* \param[in] off Offset.
* \param[in] count Allowable number to read.
* \param[out] eof End of File indication.
* \param[in] data Pointer to the private data structure.
*
* \return number of characters print to the buffer from User Space.
*/
/*----------------------------------------------------------------------------*/
static int procTxStatisticsRead(char *page, char **start, off_t off, int count, int *eof, void *data)
{
P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv;
char *p = page;
UINT_32 u4Count;
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(data);
/* Kevin: Apply PROC read method 1. */
if (off != 0)
return 0; /* To indicate end of file. */
SPRINTF(p, ("TX STATISTICS (Write 1 to clear):"));
SPRINTF(p, ("\n=================================\n"));
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
wlanoidQueryTxStatisticsForLinuxProc(prGlueInfo->prAdapter, p, &u4Count);
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
u4Count += (UINT_32) (p - page);
*eof = 1;
return (int)u4Count;
} /* end of procTxStatisticsRead() */
/*----------------------------------------------------------------------------*/
/*!
* \brief The PROC function for reset Driver TX Statistic Counters.
*
* \param[in] file pointer to file.
* \param[in] buffer Buffer from user space.
* \param[in] count Number of characters to write
* \param[in] data Pointer to the private data structure.
*
* \return number of characters write from User Space.
*/
/*----------------------------------------------------------------------------*/
static int procTxStatisticsWrite(struct file *file, const char *buffer, unsigned long count, void *data)
{
P_GLUE_INFO_T prGlueInfo = ((struct net_device *)data)->priv;
char acBuf[PROC_RX_STATISTICS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */
UINT_32 u4CopySize;
UINT_32 u4ClearCounter;
INT_32 rv;
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(data);
u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : (sizeof(acBuf) - 1);
copy_from_user(acBuf, buffer, u4CopySize);
acBuf[u4CopySize] = '\0';
rv = kstrtoint(acBuf, 0, &u4ClearCounter);
if (rv == 1) {
if (u4ClearCounter == 1) {
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
wlanoidSetTxStatisticsForLinuxProc(prGlueInfo->prAdapter);
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_FSM);
}
}
return count;
} /* end of procTxStatisticsWrite() */
#endif