mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2024-11-15 11:35:35 +00:00
13b6fdb0b4
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>
1358 lines
38 KiB
C
1358 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, ®, &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
|