mwifiex/mxm_wifiex/wlan_src/mlinux/moal_proc.c
Sherry Sun 8ffae47921 mxm_wifiex: update to mxm5x17283 release
changes:
1. WCSWREL-191: Fixed the error when loading module param from user config for SD8801
2. WCSWREL-186: Fixed the issue of mlanutl failing on kernel higher than L5.15
3. Fixed low throughput issue for WPA3 SAE
4. Added driver change for WLAN throughput improvement on 8997 SoC
5. Updated README to recommend not to use WEP/TKIP for all chipsets
6. WCSWREL-180: Fix P2P test fail on kernel higher than L5.12
7. WCSWREL-156: kernel_write/kernel_read not allowed by drivers for L5.10 kernel GKI buildou
8. Alternative for pm_qos_add_request/pm_qos_remove_request

Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
Approved-by: Tian Yang <yang.tian@nxp.com>
2021-10-12 12:16:50 +08:00

1359 lines
38 KiB
C

/** @file moal_proc.c
*
* @brief This file contains functions for proc file.
*
*
* Copyright 2008-2021 NXP
*
* This software file (the File) is distributed by NXP
* under the terms of the GNU General Public License Version 2, June 1991
* (the License). You may use, redistribute and/or modify the File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*
*/
/********************************************************
Change log:
10/21/2008: initial version
********************************************************/
#include "moal_main.h"
#ifdef UAP_SUPPORT
#include "moal_uap.h"
#endif
#ifdef SDIO
#include "moal_sdio.h"
#endif
/********************************************************
Local Variables
********************************************************/
#ifdef CONFIG_PROC_FS
#define STATUS_PROC "wifi_status"
#define MWLAN_PROC "mwlan"
#define WLAN_PROC "adapter%d"
/** Proc mwlan directory entry */
static struct proc_dir_entry *proc_mwlan;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
#define PROC_DIR NULL
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
#define PROC_DIR (&proc_root)
#else
#define PROC_DIR proc_net
#endif
#ifdef STA_SUPPORT
static char *szModes[] = {
"Unknown",
"Managed",
"Ad-hoc",
"Auto",
};
#endif
/********************************************************
Global Variables
********************************************************/
int wifi_status;
/********************************************************
Local Functions
********************************************************/
/**
* @brief Proc read function for info
*
* @param sfp pointer to seq_file structure
* @param data
*
* @return Number of output data
*/
static int woal_info_proc_read(struct seq_file *sfp, void *data)
{
struct net_device *netdev = (struct net_device *)sfp->private;
char fmt[MLAN_MAX_VER_STR_LEN];
moal_private *priv = (moal_private *)netdev_priv(netdev);
#ifdef STA_SUPPORT
int i = 0;
moal_handle *handle = NULL;
mlan_bss_info info;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
struct dev_mc_list *mcptr = netdev->mc_list;
int mc_count = netdev->mc_count;
#else
struct netdev_hw_addr *mcptr = NULL;
int mc_count = netdev_mc_count(netdev);
#endif /* < 2.6.35 */
#else
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
int i = 0;
#endif /* >= 2.6.29 */
#endif
#ifdef UAP_SUPPORT
mlan_ds_uap_stats ustats;
#endif
union {
t_u32 l;
t_u8 c[4];
} ver;
ENTER();
if (priv == NULL)
goto exit;
#ifdef STA_SUPPORT
handle = priv->phandle;
if (handle == NULL)
goto exit;
#endif
if (!MODULE_GET) {
LEAVE();
return 0;
}
memset(fmt, 0, sizeof(fmt));
#ifdef UAP_SUPPORT
memset(&ustats, 0, sizeof(ustats));
if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
seq_printf(sfp, "driver_name = "
"\"uap\"\n");
woal_uap_get_version(priv, fmt, sizeof(fmt) - 1);
if (MLAN_STATUS_SUCCESS !=
woal_uap_get_stats(priv, MOAL_IOCTL_WAIT, &ustats)) {
MODULE_PUT;
LEAVE();
return -EFAULT;
}
}
#endif /* UAP_SUPPORT*/
#ifdef STA_SUPPORT
memset(&info, 0, sizeof(info));
if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
woal_get_version(handle, fmt, sizeof(fmt) - 1);
if (MLAN_STATUS_SUCCESS !=
woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &info)) {
MODULE_PUT;
LEAVE();
return -EFAULT;
}
seq_printf(sfp, "driver_name = "
"\"wlan\"\n");
}
#endif
seq_printf(sfp, "driver_version = %s", fmt);
seq_printf(sfp, "\ninterface_name=\"%s\"\n", netdev->name);
ver.l = handle->fw_release_number;
seq_printf(sfp, "firmware_major_version=%u.%u.%u\n", ver.c[2], ver.c[1],
ver.c[0]);
#ifdef WIFI_DIRECT_SUPPORT
if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
seq_printf(sfp, "bss_mode = \"WIFIDIRECT-Client\"\n");
else
seq_printf(sfp, "bss_mode = \"WIFIDIRECT-GO\"\n");
}
#endif
#ifdef STA_SUPPORT
if (priv->bss_type == MLAN_BSS_TYPE_STA)
seq_printf(sfp, "bss_mode =\"%s\"\n", szModes[info.bss_mode]);
#endif
seq_printf(sfp, "media_state=\"%s\"\n",
((priv->media_connected == MFALSE) ? "Disconnected" :
"Connected"));
seq_printf(sfp, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
netdev->dev_addr[0], netdev->dev_addr[1],
netdev->dev_addr[2], netdev->dev_addr[3],
netdev->dev_addr[4], netdev->dev_addr[5]);
#ifdef STA_SUPPORT
if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
seq_printf(sfp, "multicast_count=\"%d\"\n", mc_count);
seq_printf(sfp, "essid=\"%s\"\n", info.ssid.ssid);
seq_printf(sfp, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
info.bssid[0], info.bssid[1], info.bssid[2],
info.bssid[3], info.bssid[4], info.bssid[5]);
seq_printf(sfp, "channel=\"%d\"\n", (int)info.bss_chan);
seq_printf(sfp, "region_code = \"%02x\"\n",
(t_u8)info.region_code);
/*
* Put out the multicast list
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
for (i = 0; i < netdev->mc_count; i++) {
seq_printf(
sfp,
"multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
i, mcptr->dmi_addr[0], mcptr->dmi_addr[1],
mcptr->dmi_addr[2], mcptr->dmi_addr[3],
mcptr->dmi_addr[4], mcptr->dmi_addr[5]);
mcptr = mcptr->next;
}
#else
netdev_for_each_mc_addr (mcptr, netdev)
seq_printf(
sfp,
"multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
i++, mcptr->addr[0], mcptr->addr[1],
mcptr->addr[2], mcptr->addr[3], mcptr->addr[4],
mcptr->addr[5]);
#endif /* < 2.6.35 */
}
#endif
seq_printf(sfp, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
seq_printf(sfp, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
seq_printf(sfp, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
seq_printf(sfp, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
seq_printf(sfp, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
seq_printf(sfp, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
seq_printf(sfp, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
seq_printf(sfp, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
seq_printf(sfp, "carrier %s\n",
((netif_carrier_ok(priv->netdev)) ? "on" : "off"));
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
for (i = 0; i < (int)netdev->num_tx_queues; i++) {
seq_printf(sfp, "tx queue %d: %s\n", i,
((netif_tx_queue_stopped(
netdev_get_tx_queue(netdev, 0))) ?
"stopped" :
"started"));
}
#else
seq_printf(sfp, "tx queue %s\n",
((netif_queue_stopped(priv->netdev)) ? "stopped" :
"started"));
#endif
#ifdef UAP_SUPPORT
if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
seq_printf(sfp, "tkip_mic_failures = %u\n",
ustats.tkip_mic_failures);
seq_printf(sfp, "ccmp_decrypt_errors = %u\n",
ustats.ccmp_decrypt_errors);
seq_printf(sfp, "wep_undecryptable_count = %u\n",
ustats.wep_undecryptable_count);
seq_printf(sfp, "wep_icv_error_count = %u\n",
ustats.wep_icv_error_count);
seq_printf(sfp, "decrypt_failure_count = %u\n",
ustats.decrypt_failure_count);
seq_printf(sfp, "mcast_tx_count = %u\n", ustats.mcast_tx_count);
seq_printf(sfp, "failed_count = %u\n", ustats.failed_count);
seq_printf(sfp, "retry_count = %u\n", ustats.retry_count);
seq_printf(sfp, "multiple_retry_count = %u\n",
ustats.multi_retry_count);
seq_printf(sfp, "frame_duplicate_count = %u\n",
ustats.frame_dup_count);
seq_printf(sfp, "rts_success_count = %u\n",
ustats.rts_success_count);
seq_printf(sfp, "rts_failure_count = %u\n",
ustats.rts_failure_count);
seq_printf(sfp, "ack_failure_count = %u\n",
ustats.ack_failure_count);
seq_printf(sfp, "rx_fragment_count = %u\n",
ustats.rx_fragment_count);
seq_printf(sfp, "mcast_rx_frame_count = %u\n",
ustats.mcast_rx_frame_count);
seq_printf(sfp, "fcs_error_count = %u\n",
ustats.fcs_error_count);
seq_printf(sfp, "tx_frame_count = %u\n", ustats.tx_frame_count);
seq_printf(sfp, "rsna_tkip_cm_invoked = %u\n",
ustats.rsna_tkip_cm_invoked);
seq_printf(sfp, "rsna_4way_hshk_failures = %u\n",
ustats.rsna_4way_hshk_failures);
}
#endif /* UAP_SUPPORT */
seq_printf(sfp, "=== tp_acnt.on:%d drop_point:%d ===\n",
handle->tp_acnt.on, handle->tp_acnt.drop_point);
seq_printf(sfp, "====Tx accounting====\n");
for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
seq_printf(sfp, "[%d] Tx packets : %lu\n", i,
handle->tp_acnt.tx_packets[i]);
seq_printf(sfp, "[%d] Tx packets last: %lu\n", i,
handle->tp_acnt.tx_packets_last[i]);
seq_printf(sfp, "[%d] Tx packets rate: %lu\n", i,
handle->tp_acnt.tx_packets_rate[i]);
seq_printf(sfp, "[%d] Tx bytes : %lu\n", i,
handle->tp_acnt.tx_bytes[i]);
seq_printf(sfp, "[%d] Tx bytes last : %lu\n", i,
handle->tp_acnt.tx_bytes_last[i]);
seq_printf(sfp, "[%d] Tx bytes rate : %luMbps\n", i,
handle->tp_acnt.tx_bytes_rate[i] * 8 / 1024 / 1024);
}
seq_printf(sfp, "Tx amsdu cnt : %lu\n",
handle->tp_acnt.tx_amsdu_cnt);
seq_printf(sfp, "Tx amsdu cnt last : %lu\n",
handle->tp_acnt.tx_amsdu_cnt_last);
seq_printf(sfp, "Tx amsdu cnt rate : %lu\n",
handle->tp_acnt.tx_amsdu_cnt_rate);
seq_printf(sfp, "Tx amsdu pkt cnt : %lu\n",
handle->tp_acnt.tx_amsdu_pkt_cnt);
seq_printf(sfp, "Tx amsdu pkt cnt last : %lu\n",
handle->tp_acnt.tx_amsdu_pkt_cnt_last);
seq_printf(sfp, "Tx amsdu pkt cnt rate : %lu\n",
handle->tp_acnt.tx_amsdu_pkt_cnt_rate);
seq_printf(sfp, "Tx intr cnt : %lu\n",
handle->tp_acnt.tx_intr_cnt);
seq_printf(sfp, "Tx intr last : %lu\n",
handle->tp_acnt.tx_intr_last);
seq_printf(sfp, "Tx intr rate : %lu\n",
handle->tp_acnt.tx_intr_rate);
seq_printf(sfp, "Tx pending : %lu\n",
handle->tp_acnt.tx_pending);
seq_printf(sfp, "Tx xmit skb realloc : %lu\n",
handle->tp_acnt.tx_xmit_skb_realloc_cnt);
seq_printf(sfp, "Tx stop queue cnt : %lu\n",
handle->tp_acnt.tx_stop_queue_cnt);
seq_printf(sfp, "====Rx accounting====\n");
for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) {
seq_printf(sfp, "[%d] Rx packets : %lu\n", i,
handle->tp_acnt.rx_packets[i]);
seq_printf(sfp, "[%d] Rx packets last: %lu\n", i,
handle->tp_acnt.rx_packets_last[i]);
seq_printf(sfp, "[%d] Rx packets rate: %lu\n", i,
handle->tp_acnt.rx_packets_rate[i]);
seq_printf(sfp, "[%d] Rx bytes : %lu\n", i,
handle->tp_acnt.rx_bytes[i]);
seq_printf(sfp, "[%d] Rx bytes last : %lu\n", i,
handle->tp_acnt.rx_bytes_last[i]);
seq_printf(sfp, "[%d] Rx bytes rate : %luMbps\n", i,
handle->tp_acnt.rx_bytes_rate[i] * 8 / 1024 / 1024);
}
seq_printf(sfp, "Rx amsdu cnt : %lu\n",
handle->tp_acnt.rx_amsdu_cnt);
seq_printf(sfp, "Rx amsdu cnt last : %lu\n",
handle->tp_acnt.rx_amsdu_cnt_last);
seq_printf(sfp, "Rx amsdu cnt rate : %lu\n",
handle->tp_acnt.rx_amsdu_cnt_rate);
seq_printf(sfp, "Rx amsdu pkt cnt : %lu\n",
handle->tp_acnt.rx_amsdu_pkt_cnt);
seq_printf(sfp, "Rx amsdu pkt cnt last : %lu\n",
handle->tp_acnt.rx_amsdu_pkt_cnt_last);
seq_printf(sfp, "Rx amsdu pkt cnt rate : %lu\n",
handle->tp_acnt.rx_amsdu_pkt_cnt_rate);
seq_printf(sfp, "Rx intr cnt : %lu\n",
handle->tp_acnt.rx_intr_cnt);
seq_printf(sfp, "Rx intr last : %lu\n",
handle->tp_acnt.rx_intr_last);
seq_printf(sfp, "Rx intr rate : %lu\n",
handle->tp_acnt.rx_intr_rate);
seq_printf(sfp, "Rx pending : %lu\n",
handle->tp_acnt.rx_pending);
seq_printf(sfp, "Rx pause : %lu\n",
handle->tp_acnt.rx_paused_cnt);
seq_printf(sfp, "Rx rdptr full cnt : %lu\n",
handle->tp_acnt.rx_rdptr_full_cnt);
exit:
LEAVE();
MODULE_PUT;
return 0;
}
static int woal_info_proc_open(struct inode *inode, struct file *file)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
return single_open(file, woal_info_proc_read, PDE_DATA(inode));
#else
return single_open(file, woal_info_proc_read, PDE(inode)->data);
#endif
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static const struct proc_ops info_proc_fops = {
.proc_open = woal_info_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
#else
static const struct file_operations info_proc_fops = {
.owner = THIS_MODULE,
.open = woal_info_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
#ifdef SDIO
#define CMD52_STR_LEN 50
/*
* @brief Parse cmd52 string
*
* @param buffer A pointer user buffer
* @param len Length user buffer
* @param func Parsed func number
* @param reg Parsed reg value
* @param val Parsed value to set
* @return BT_STATUS_SUCCESS
*/
static int parse_cmd52_string(const char *buffer, size_t len, int *func,
int *reg, int *val)
{
int ret = MLAN_STATUS_SUCCESS;
char *string = NULL;
char *pos = NULL;
gfp_t flag;
ENTER();
flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
string = kzalloc(CMD52_STR_LEN, flag);
if (string == NULL)
return -ENOMEM;
moal_memcpy_ext(NULL, string, buffer + strlen("sdcmd52rw="),
len - strlen("sdcmd52rw="), CMD52_STR_LEN - 1);
string = strstrip(string);
*func = -1;
*reg = -1;
*val = -1;
/* Get func */
pos = strsep(&string, " \t");
if (pos)
*func = woal_string_to_number(pos);
/* Get reg */
pos = strsep(&string, " \t");
if (pos)
*reg = woal_string_to_number(pos);
/* Get val (optional) */
pos = strsep(&string, " \t");
if (pos)
*val = woal_string_to_number(pos);
kfree(string);
LEAVE();
return ret;
}
#endif
/**
* @brief config proc write function
*
* @param f file pointer
* @param buf pointer to data buffer
* @param count data number to write
* @param off Offset
*
* @return number of data
*/
static ssize_t woal_config_write(struct file *f, const char __user *buf,
size_t count, loff_t *off)
{
char databuf[101];
char *line = NULL;
t_u32 config_data = 0;
struct seq_file *sfp = f->private_data;
moal_handle *handle = (moal_handle *)sfp->private;
#ifdef SDIO
int func = 0, reg = 0, val = 0;
#endif
moal_handle *ref_handle = NULL;
t_u32 cmd = 0;
int copy_len;
moal_private *priv = NULL;
ENTER();
if (!MODULE_GET) {
LEAVE();
return 0;
}
if (count >= sizeof(databuf)) {
MODULE_PUT;
LEAVE();
return (int)count;
}
memset(databuf, 0, sizeof(databuf));
copy_len = MIN((sizeof(databuf) - 1), count);
if (copy_from_user(databuf, buf, copy_len)) {
MODULE_PUT;
LEAVE();
return 0;
}
line = databuf;
if (!strncmp(databuf, "soft_reset", strlen("soft_reset"))) {
line += strlen("soft_reset") + 1;
config_data = (t_u32)woal_string_to_number(line);
PRINTM(MINFO, "soft_reset: %d\n", (int)config_data);
if (woal_request_soft_reset(handle) == MLAN_STATUS_SUCCESS)
handle->hardware_status = HardwareStatusReset;
else
PRINTM(MERROR, "Could not perform soft reset\n");
}
if (!strncmp(databuf, "drv_mode", strlen("drv_mode"))) {
line += strlen("drv_mode") + 1;
config_data = (t_u32)woal_string_to_number(line);
PRINTM(MINFO, "drv_mode: %d\n", (int)config_data);
if (config_data != (t_u32)handle->params.drv_mode)
if (woal_switch_drv_mode(handle, config_data) !=
MLAN_STATUS_SUCCESS) {
PRINTM(MERROR, "Could not switch drv mode\n");
}
}
#ifdef SDIO
if (IS_SD(handle->card_type)) {
if (!strncmp(databuf, "sdcmd52rw=", strlen("sdcmd52rw=")) &&
count > strlen("sdcmd52rw=")) {
parse_cmd52_string((const char *)databuf, (size_t)count,
&func, &reg, &val);
woal_sdio_read_write_cmd52(handle, func, reg, val);
}
}
#endif /* SD */
if (!strncmp(databuf, "debug_dump", strlen("debug_dump"))) {
PRINTM(MERROR, "Recevie debug_dump command\n");
#ifdef USB
if (!IS_USB(handle->card_type))
#endif
handle->driver_status = MTRUE;
ref_handle = (moal_handle *)handle->pref_mac;
if (ref_handle) {
priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY);
if (priv) {
#ifdef DEBUG_LEVEL1
drvdbg &= ~MFW_D;
#endif
woal_mlan_debug_info(priv);
woal_moal_debug_info(priv, NULL, MFALSE);
}
}
priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
if (priv) {
#ifdef DEBUG_LEVEL1
drvdbg &= ~MFW_D;
#endif
woal_mlan_debug_info(priv);
woal_moal_debug_info(priv, NULL, MFALSE);
handle->ops.dump_fw_info(handle);
}
}
if (!strncmp(databuf, "fwdump_file=", strlen("fwdump_file="))) {
int len = copy_len - strlen("fwdump_file=");
gfp_t flag;
if (len) {
kfree(handle->fwdump_fname);
flag = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC :
GFP_KERNEL;
handle->fwdump_fname = kzalloc(len, flag);
if (handle->fwdump_fname)
moal_memcpy_ext(handle, handle->fwdump_fname,
databuf +
strlen("fwdump_file="),
len - 1, len - 1);
}
}
if (!strncmp(databuf, "fw_reload", strlen("fw_reload"))) {
if (!strncmp(databuf, "fw_reload=", strlen("fw_reload="))) {
line += strlen("fw_reload") + 1;
config_data = (t_u32)woal_string_to_number(line);
}
#ifdef SDIO_MMC
else if (IS_SD(handle->card_type))
config_data = FW_RELOAD_SDIO_INBAND_RESET;
#endif
PRINTM(MMSG, "Request fw_reload=%d\n", config_data);
woal_request_fw_reload(handle, config_data);
}
if (!strncmp(databuf, "drop_point=", strlen("drop_point="))) {
line += strlen("drop_point") + 1;
config_data = (t_u32)woal_string_to_number(line);
if (config_data) {
handle->tp_acnt.on = 1;
handle->tp_acnt.drop_point = config_data;
if (handle->is_tp_acnt_timer_set == MFALSE) {
woal_initialize_timer(&handle->tp_acnt.timer,
woal_tp_acnt_timer_func,
handle);
handle->is_tp_acnt_timer_set = MTRUE;
woal_mod_timer(&handle->tp_acnt.timer, 1000);
}
} else {
if (handle->is_tp_acnt_timer_set) {
woal_cancel_timer(&handle->tp_acnt.timer);
handle->is_tp_acnt_timer_set = MFALSE;
}
memset((void *)&handle->tp_acnt, 0,
sizeof(moal_tp_acnt_t));
}
priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
if (priv)
woal_set_tp_state(priv);
PRINTM(MMSG, "on=%d drop_point=%d\n", handle->tp_acnt.on,
handle->tp_acnt.drop_point);
}
if (!strncmp(databuf, "rf_test_mode", strlen("rf_test_mode"))) {
line += strlen("rf_test_mode") + 1;
config_data = (t_u32)woal_string_to_number(line);
PRINTM(MINFO, "RF test mode: %d\n", (int)config_data);
if (config_data != (t_u32)handle->rf_test_mode)
if (woal_process_rf_test_mode(handle, config_data) !=
MLAN_STATUS_SUCCESS)
PRINTM(MERROR, "Could not set RF test mode\n");
}
if (!strncmp(databuf, "tx_antenna", strlen("tx_antenna"))) {
line += strlen("tx_antenna") + 1;
config_data = (t_u32)woal_string_to_number(line);
cmd = MFG_CMD_TX_ANT;
}
if (!strncmp(databuf, "rx_antenna", strlen("rx_antenna"))) {
line += strlen("rx_antenna") + 1;
config_data = (t_u32)woal_string_to_number(line);
cmd = MFG_CMD_RX_ANT;
}
if (!strncmp(databuf, "radio_mode", strlen("radio_mode"))) {
line += strlen("radio_mode") + 1;
config_data = (t_u32)woal_string_to_number(line);
cmd = MFG_CMD_RADIO_MODE_CFG;
}
if (!strncmp(databuf, "channel", strlen("channel"))) {
line += strlen("channel") + 1;
config_data = (t_u32)woal_string_to_number(line);
cmd = MFG_CMD_RF_CHAN;
}
if (!strncmp(databuf, "band", strlen("band"))) {
line += strlen("band") + 1;
config_data = (t_u32)woal_string_to_number(line);
cmd = MFG_CMD_RF_BAND_AG;
}
if (!strncmp(databuf, "bw", strlen("bw"))) {
line += strlen("bw") + 1;
config_data = (t_u32)woal_string_to_number(line);
cmd = MFG_CMD_RF_CHANNELBW;
}
if (!strncmp(databuf, "get_and_reset_per", strlen("get_and_reset_per")))
cmd = MFG_CMD_CLR_RX_ERR;
if (!strncmp(databuf, "tx_power=", strlen("tx_power=")) &&
count > strlen("tx_power="))
cmd = MFG_CMD_RFPWR;
if (!strncmp(databuf, "tx_frame=", strlen("tx_frame=")) &&
count > strlen("tx_frame="))
cmd = MFG_CMD_TX_FRAME;
if (!strncmp(databuf, "tx_continuous=", strlen("tx_continuous=")) &&
count > strlen("tx_continuous="))
cmd = MFG_CMD_TX_CONT;
if (!strncmp(databuf, "he_tb_tx=", strlen("he_tb_tx=")) &&
count > strlen("he_tb_tx="))
cmd = MFG_CMD_CONFIG_MAC_HE_TB_TX;
if (cmd && handle->rf_test_mode &&
(woal_process_rf_test_mode_cmd(
handle, cmd, (const char *)databuf, (size_t)count,
MLAN_ACT_SET, config_data) != MLAN_STATUS_SUCCESS)) {
PRINTM(MERROR, "RF test mode cmd error\n");
}
if (cmd && !handle->rf_test_mode)
PRINTM(MERROR, "RF test mode is disabled\n");
MODULE_PUT;
LEAVE();
return (int)count;
}
/**
* @brief config proc read function
*
* @param sfp pointer to seq_file structure
* @param data
*
* @return number of output data
*/
static int woal_config_read(struct seq_file *sfp, void *data)
{
moal_handle *handle = (moal_handle *)sfp->private;
int i;
ENTER();
if (!MODULE_GET) {
LEAVE();
return 0;
}
seq_printf(sfp, "hardware_status=%d\n", (int)handle->hardware_status);
seq_printf(sfp, "netlink_num=%d\n", (int)handle->netlink_num);
seq_printf(sfp, "drv_mode=%d\n", (int)handle->params.drv_mode);
#ifdef SDIO
if (IS_SD(handle->card_type)) {
seq_printf(sfp, "sdcmd52rw=%d 0x%0x 0x%02X\n",
handle->cmd52_func, handle->cmd52_reg,
handle->cmd52_val);
}
#endif /* SD */
seq_printf(sfp, "rf_test_mode=%u\n", handle->rf_test_mode);
if (handle->rf_test_mode && handle->rf_data) {
seq_printf(sfp, "tx_antenna=%u\n", handle->rf_data->tx_antenna);
seq_printf(sfp, "rx_antenna=%u\n", handle->rf_data->rx_antenna);
seq_printf(sfp, "band=%u\n", handle->rf_data->band);
seq_printf(sfp, "bw=%u\n", handle->rf_data->bandwidth);
if (handle->rf_data->channel)
seq_printf(sfp, "channel=%u\n",
handle->rf_data->channel);
else
seq_printf(sfp, "channel=\n");
if (handle->rf_data->radio_mode[0])
seq_printf(sfp, "radio_mode[0]=%u\n",
handle->rf_data->radio_mode[0]);
else
seq_printf(sfp, "radio_mode[0]=\n");
if (handle->rf_data->radio_mode[1])
seq_printf(sfp, "radio_mode[1]=%u\n",
handle->rf_data->radio_mode[1]);
else
seq_printf(sfp, "radio_mode[1]=\n");
seq_printf(sfp, "total rx pkt count=%u\n",
handle->rf_data->rx_tot_pkt_count);
seq_printf(sfp, "rx multicast/broadcast pkt count=%u\n",
handle->rf_data->rx_mcast_bcast_pkt_count);
seq_printf(sfp, "rx fcs error pkt count=%u\n",
handle->rf_data->rx_pkt_fcs_err_count);
if (handle->rf_data->tx_power_data[0]) {
seq_printf(sfp, "tx_power=%u",
handle->rf_data->tx_power_data[0]);
seq_printf(sfp, " %u",
handle->rf_data->tx_power_data[1]);
seq_printf(sfp, " %u\n",
handle->rf_data->tx_power_data[2]);
} else
seq_printf(sfp, "tx_power=\n");
seq_printf(sfp, "tx_continuous=%u",
handle->rf_data->tx_cont_data[0]);
if (handle->rf_data->tx_cont_data[0] == MTRUE) {
seq_printf(sfp, " %u",
handle->rf_data->tx_cont_data[1]);
seq_printf(sfp, " 0x%x",
handle->rf_data->tx_cont_data[2]);
for (i = 3; i < 6; i++)
seq_printf(sfp, " %u",
handle->rf_data->tx_cont_data[i]);
}
seq_printf(sfp, "\n");
seq_printf(sfp, "tx_frame=%u",
handle->rf_data->tx_frame_data[0]);
if (handle->rf_data->tx_frame_data[0] == MTRUE) {
seq_printf(sfp, " %u",
handle->rf_data->tx_frame_data[1]);
seq_printf(sfp, " 0x%x",
handle->rf_data->tx_frame_data[2]);
for (i = 3; i < 13; i++)
seq_printf(sfp, " %u",
handle->rf_data->tx_frame_data[i]);
for (i = 13; i < 20; i++)
seq_printf(sfp, " %u",
handle->rf_data->tx_frame_data[i]);
seq_printf(sfp, " %02x:%02x:%02x:%02x:%02x:%02x",
handle->rf_data->bssid[0],
handle->rf_data->bssid[1],
handle->rf_data->bssid[2],
handle->rf_data->bssid[3],
handle->rf_data->bssid[4],
handle->rf_data->bssid[5]);
}
seq_printf(sfp, "\n");
seq_printf(sfp, "he_tb_tx=%u", handle->rf_data->he_tb_tx[0]);
if (handle->rf_data->he_tb_tx[0] == MTRUE) {
seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[1]);
seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[2]);
seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[3]);
seq_printf(sfp, " %u", handle->rf_data->he_tb_tx[4]);
}
seq_printf(sfp, "\n");
}
MODULE_PUT;
LEAVE();
return 0;
}
static int woal_config_proc_open(struct inode *inode, struct file *file)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
return single_open(file, woal_config_read, PDE_DATA(inode));
#else
return single_open(file, woal_config_read, PDE(inode)->data);
#endif
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static const struct proc_ops config_proc_fops = {
.proc_open = woal_config_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
.proc_write = woal_config_write,
};
#else
static const struct file_operations config_proc_fops = {
.owner = THIS_MODULE,
.open = woal_config_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = woal_config_write,
};
#endif
static int woal_drv_dump_read(struct seq_file *sfp, void *data)
{
moal_handle *handle = (moal_handle *)sfp->private;
int ret = 0;
ENTER();
if (MODULE_GET == 0) {
LEAVE();
return 0;
}
if (!handle) {
PRINTM(MERROR, "handle is NULL!\n");
LEAVE();
return 0;
}
if (!handle->drv_dump_buf || !handle->drv_dump_len)
handle->drv_dump_buf =
woal_dump_drv_info(handle, &handle->drv_dump_len);
if (!handle->drv_dump_buf || !handle->drv_dump_len) {
PRINTM(MERROR,
"driver dump buffer is NULL or total length is zero\n");
goto done;
}
if (sfp->size < handle->drv_dump_len) {
PRINTM(MERROR,
"drv dump size too big, size=%d, drv_dump_len=%d\n",
(int)sfp->size, handle->drv_dump_len);
sfp->count = sfp->size;
ret = 0;
MODULE_PUT;
return ret;
}
memset(sfp->buf, 0x00, sfp->size);
sfp->count = handle->drv_dump_len;
moal_memcpy_ext(handle, sfp->buf, handle->drv_dump_buf,
handle->drv_dump_len, sfp->size);
done:
moal_vfree(handle, handle->drv_dump_buf);
handle->drv_dump_len = 0;
handle->drv_dump_buf = NULL;
MODULE_PUT;
LEAVE();
return 0;
}
static int woal_drv_dump_proc_open(struct inode *inode, struct file *file)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
return single_open(file, woal_drv_dump_read, PDE_DATA(inode));
#else
return single_open(file, woal_drv_dump_read, PDE(inode)->data);
#endif
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static const struct proc_ops drv_dump_fops = {
.proc_open = woal_drv_dump_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
#else
static const struct file_operations drv_dump_fops = {
.owner = THIS_MODULE,
.open = woal_drv_dump_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
static int woal_fw_dump_read(struct seq_file *sfp, void *data)
{
moal_handle *handle = (moal_handle *)sfp->private;
int ret = 0;
ENTER();
if (MODULE_GET == 0) {
LEAVE();
return 0;
}
if (!handle) {
PRINTM(MERROR, "handle is null!\n");
goto done;
}
if (handle->fw_dump == MTRUE) {
PRINTM(MERROR, "fw dump is in progress\n");
goto done;
}
if (!handle->fw_dump_buf || !handle->fw_dump_len) {
PRINTM(MERROR,
"fw dump buffer is NULL or total length is zero\n");
goto done;
}
if (sfp->size < handle->fw_dump_len) {
PRINTM(MERROR,
"fw dump size too big, size=%d, fw_dump_len=%ld\n",
(int)sfp->size, (long int)handle->fw_dump_len);
sfp->count = sfp->size;
ret = 0;
MODULE_PUT;
return ret;
}
sfp->count = handle->fw_dump_len;
moal_memcpy_ext(handle, sfp->buf, handle->fw_dump_buf,
handle->fw_dump_len, sfp->size);
moal_vfree(handle, handle->fw_dump_buf);
handle->fw_dump_buf = NULL;
handle->fw_dump_len = 0;
done:
MODULE_PUT;
LEAVE();
return 0;
}
static int woal_fw_dump_proc_open(struct inode *inode, struct file *file)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
return single_open(file, woal_fw_dump_read, PDE_DATA(inode));
#else
return single_open(file, woal_fw_dump_read, PDE(inode)->data);
#endif
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static const struct proc_ops fw_dump_fops = {
.proc_open = woal_fw_dump_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
#else
static const struct file_operations fw_dump_fops = {
.owner = THIS_MODULE,
.open = woal_fw_dump_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
/**
* @brief wifi status proc read function
*
* @param sfp pointer to seq_file structure
* @param data
*
* @return number of output data
*/
static int woal_wifi_status_read(struct seq_file *sfp, void *data)
{
ENTER();
if (!MODULE_GET) {
LEAVE();
return 0;
}
seq_printf(sfp, "%d\n", wifi_status);
MODULE_PUT;
LEAVE();
return 0;
}
static int woal_wifi_status_proc_open(struct inode *inode, struct file *file)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
return single_open(file, woal_wifi_status_read, PDE_DATA(inode));
#else
return single_open(file, woal_wifi_status_read, PDE(inode)->data);
#endif
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static const struct proc_ops wifi_status_proc_fops = {
.proc_open = woal_wifi_status_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
#else
static const struct file_operations wifi_status_proc_fops = {
.owner = THIS_MODULE,
.open = woal_wifi_status_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
/********************************************************
Global Functions
********************************************************/
/**
* @brief Convert string to number
*
* @param s Pointer to numbered string
*
* @return Converted number from string s
*/
int woal_string_to_number(char *s)
{
int r = 0;
int base = 0;
int pn = 1;
if (!strncmp(s, "-", 1)) {
pn = -1;
s++;
}
if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) {
base = 16;
s += 2;
} else
base = 10;
for (; *s; s++) {
if ((*s >= '0') && (*s <= '9'))
r = (r * base) + (*s - '0');
else if ((*s >= 'A') && (*s <= 'F'))
r = (r * base) + (*s - 'A' + 10);
else if ((*s >= 'a') && (*s <= 'f'))
r = (r * base) + (*s - 'a' + 10);
else
break;
}
return r * pn;
}
/**
* @brief This function creates proc mwlan directory
* directory structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status woal_root_proc_init(void)
{
ENTER();
PRINTM(MINFO, "Create /proc/mwlan directory\n");
proc_mwlan = proc_mkdir(MWLAN_PROC, PROC_DIR);
if (!proc_mwlan) {
PRINTM(MERROR,
"woal_root_proc_init: Cannot create /proc/mwlan\n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
/* create /proc/mwlan/wifi_status */
proc_create_data(STATUS_PROC, 0666, proc_mwlan, &wifi_status_proc_fops,
NULL);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief This function removes proc mwlan directory
* directory structure
*
* @return N/A
*/
void woal_root_proc_remove(void)
{
ENTER();
remove_proc_entry(STATUS_PROC, proc_mwlan);
remove_proc_entry(MWLAN_PROC, PROC_DIR);
proc_mwlan = NULL;
LEAVE();
}
/**
* @brief Create the top level proc directory
*
* @param handle Pointer to woal_handle
*
* @return N/A
*/
void woal_proc_init(moal_handle *handle)
{
struct proc_dir_entry *r;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
struct proc_dir_entry *pde = proc_mwlan;
#endif
char config_proc_dir[20];
char drv_dump_dir[20];
char fw_dump_dir[20];
ENTER();
if (handle->proc_wlan) {
PRINTM(MMSG, "woal_proc_init: proc_wlan is already exist %s\n",
handle->proc_wlan_name);
goto done;
}
snprintf(handle->proc_wlan_name, sizeof(handle->proc_wlan_name),
WLAN_PROC, handle->handle_idx);
PRINTM(MINFO, "Create Proc Interface %s\n", handle->proc_wlan_name);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
/* Check if directory already exists */
for (pde = pde->subdir; pde; pde = pde->next) {
if (pde->namelen &&
!strcmp(handle->proc_wlan_name, pde->name)) {
/* Directory exists */
PRINTM(MWARN, "proc interface already exists!\n");
handle->proc_wlan = pde;
break;
}
}
if (pde == NULL) {
handle->proc_wlan =
proc_mkdir(handle->proc_wlan_name, proc_mwlan);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
if (handle->proc_wlan)
atomic_set(&handle->proc_wlan->count, 1);
#endif
}
#else
handle->proc_wlan = proc_mkdir(handle->proc_wlan_name, proc_mwlan);
#endif
if (!handle->proc_wlan) {
PRINTM(MERROR, "Cannot create proc interface %s!\n",
handle->proc_wlan_name);
goto done;
}
strcpy(config_proc_dir, "config");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
r = proc_create_data(config_proc_dir, 0666, handle->proc_wlan,
&config_proc_fops, handle);
#else
r = create_proc_entry(config_proc_dir, 0644, handle->proc_wlan);
if (r) {
r->data = handle;
r->proc_fops = &config_proc_fops;
}
#endif
if (!r)
PRINTM(MERROR, "Fail to create proc config\n");
strcpy(drv_dump_dir, "drv_dump");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
r = proc_create_data(drv_dump_dir, 0644, handle->proc_wlan,
&drv_dump_fops, handle);
#else
r = create_proc_entry(drv_dump_dir, 0644, handle->proc_wlan);
if (r) {
r->data = handle;
r->proc_fops = &drv_dump_fops;
}
#endif
if (!r)
PRINTM(MERROR, "Failed to create proc drv dump\n");
strcpy(fw_dump_dir, "fw_dump");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
r = proc_create_data(fw_dump_dir, 0644, handle->proc_wlan,
&fw_dump_fops, handle);
#else
r = create_proc_entry(fw_dump_dir, 0644, handle->proc_wlan);
if (r) {
r->data = handle;
r->proc_fops = &fw_dump_fops;
}
#endif
if (!r)
PRINTM(MERROR, "Failed to create proc fw dump\n");
done:
LEAVE();
}
/**
* @brief Remove the top level proc directory
*
* @param handle pointer moal_handle
*
* @return N/A
*/
void woal_proc_exit(moal_handle *handle)
{
char config_proc_dir[20];
char drv_dump_dir[20];
char fw_dump_dir[20];
ENTER();
PRINTM(MINFO, "Remove Proc Interface %s\n", handle->proc_wlan_name);
if (handle->proc_wlan) {
strcpy(config_proc_dir, "config");
remove_proc_entry(config_proc_dir, handle->proc_wlan);
strcpy(drv_dump_dir, "drv_dump");
remove_proc_entry(drv_dump_dir, handle->proc_wlan);
strcpy(fw_dump_dir, "fw_dump");
remove_proc_entry(fw_dump_dir, handle->proc_wlan);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
/* Remove only if we are the only instance using this */
if (atomic_read(&(handle->proc_wlan->count)) > 1) {
PRINTM(MWARN, "More than one interface using proc!\n");
} else {
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
atomic_dec(&(handle->proc_wlan->count));
#endif
remove_proc_entry(handle->proc_wlan_name, proc_mwlan);
handle->proc_wlan = NULL;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
}
#endif
}
if (handle->fw_dump_buf) {
moal_vfree(handle, handle->fw_dump_buf);
handle->fw_dump_buf = NULL;
handle->fw_dump_len = 0;
}
if (handle->drv_dump_buf) {
moal_vfree(handle, handle->drv_dump_buf);
handle->drv_dump_len = 0;
handle->drv_dump_buf = NULL;
}
LEAVE();
}
/**
* @brief Create proc file for interface
*
* @param priv pointer moal_private
*
* @return N/A
*/
void woal_create_proc_entry(moal_private *priv)
{
struct proc_dir_entry *r;
struct net_device *dev = priv->netdev;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
char proc_dir_name[22];
#endif
ENTER();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
if (!priv->proc_entry) {
memset(proc_dir_name, 0, sizeof(proc_dir_name));
memcpy(proc_dir_name, priv->phandle->proc_wlan_name,
sizeof(proc_dir_name) - 2);
proc_dir_name[strlen(proc_dir_name)] = '/';
if (strlen(dev->name) >
((sizeof(proc_dir_name) - 1) - (strlen(proc_dir_name)))) {
PRINTM(MERROR,
"Failed to create proc entry, device name is too long\n");
LEAVE();
return;
}
strcat(proc_dir_name, dev->name);
/* Try to create adapterX/dev_name directory first under
* /proc/mwlan/ */
priv->proc_entry = proc_mkdir(proc_dir_name, proc_mwlan);
if (priv->proc_entry) {
/* Success. Continue normally */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
if (!priv->phandle->proc_wlan) {
priv->phandle->proc_wlan =
priv->proc_entry->parent;
}
atomic_inc(&(priv->phandle->proc_wlan->count));
#endif
} else {
/* Failure. adapterX/ may not exist. Try to create that
* first */
priv->phandle->proc_wlan = proc_mkdir(
priv->phandle->proc_wlan_name, proc_mwlan);
if (!priv->phandle->proc_wlan) {
/* Failure. Something broken */
LEAVE();
return;
} else {
/* Success. Now retry creating mlanX */
priv->proc_entry =
proc_mkdir(proc_dir_name, proc_mwlan);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
atomic_inc(&(priv->phandle->proc_wlan->count));
#endif
}
}
#else
if (priv->phandle->proc_wlan && !priv->proc_entry) {
priv->proc_entry =
proc_mkdir(dev->name, priv->phandle->proc_wlan);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
atomic_inc(&(priv->phandle->proc_wlan->count));
#endif /* < 3.10.0 */
#endif /* < 2.6.26 */
strcpy(priv->proc_entry_name, dev->name);
if (priv->proc_entry) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
r = proc_create_data("info", 0, priv->proc_entry,
&info_proc_fops, dev);
#else
r = create_proc_entry("info", 0, priv->proc_entry);
if (r) {
r->data = dev;
r->proc_fops = &info_proc_fops;
}
#endif
if (!r)
PRINTM(MMSG, "Fail to create proc info\n");
}
}
LEAVE();
}
/**
* @brief Remove proc file
*
* @param priv Pointer moal_private
*
* @return N/A
*/
void woal_proc_remove(moal_private *priv)
{
ENTER();
if (priv->phandle->proc_wlan && priv->proc_entry) {
remove_proc_entry("info", priv->proc_entry);
remove_proc_entry(priv->proc_entry_name,
priv->phandle->proc_wlan);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
atomic_dec(&(priv->phandle->proc_wlan->count));
#endif
priv->proc_entry = NULL;
}
LEAVE();
}
#endif