cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

debugfs.c (27161B)


      1/*
      2 * NXP Wireless LAN device driver: debugfs
      3 *
      4 * Copyright 2011-2020 NXP
      5 *
      6 * This software file (the "File") is distributed by NXP
      7 * under the terms of the GNU General Public License Version 2, June 1991
      8 * (the "License").  You may use, redistribute and/or modify this File in
      9 * accordance with the terms and conditions of the License, a copy of which
     10 * is available by writing to the Free Software Foundation, Inc.,
     11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
     12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
     13 *
     14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
     15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
     16 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
     17 * this warranty disclaimer.
     18 */
     19
     20#include <linux/debugfs.h>
     21
     22#include "main.h"
     23#include "11n.h"
     24
     25
     26static struct dentry *mwifiex_dfs_dir;
     27
     28static char *bss_modes[] = {
     29	"UNSPECIFIED",
     30	"ADHOC",
     31	"STATION",
     32	"AP",
     33	"AP_VLAN",
     34	"WDS",
     35	"MONITOR",
     36	"MESH_POINT",
     37	"P2P_CLIENT",
     38	"P2P_GO",
     39	"P2P_DEVICE",
     40};
     41
     42/*
     43 * Proc info file read handler.
     44 *
     45 * This function is called when the 'info' file is opened for reading.
     46 * It prints the following driver related information -
     47 *      - Driver name
     48 *      - Driver version
     49 *      - Driver extended version
     50 *      - Interface name
     51 *      - BSS mode
     52 *      - Media state (connected or disconnected)
     53 *      - MAC address
     54 *      - Total number of Tx bytes
     55 *      - Total number of Rx bytes
     56 *      - Total number of Tx packets
     57 *      - Total number of Rx packets
     58 *      - Total number of dropped Tx packets
     59 *      - Total number of dropped Rx packets
     60 *      - Total number of corrupted Tx packets
     61 *      - Total number of corrupted Rx packets
     62 *      - Carrier status (on or off)
     63 *      - Tx queue status (started or stopped)
     64 *
     65 * For STA mode drivers, it also prints the following extra -
     66 *      - ESSID
     67 *      - BSSID
     68 *      - Channel
     69 *      - Region code
     70 *      - Multicast count
     71 *      - Multicast addresses
     72 */
     73static ssize_t
     74mwifiex_info_read(struct file *file, char __user *ubuf,
     75		  size_t count, loff_t *ppos)
     76{
     77	struct mwifiex_private *priv =
     78		(struct mwifiex_private *) file->private_data;
     79	struct net_device *netdev = priv->netdev;
     80	struct netdev_hw_addr *ha;
     81	struct netdev_queue *txq;
     82	unsigned long page = get_zeroed_page(GFP_KERNEL);
     83	char *p = (char *) page, fmt[64];
     84	struct mwifiex_bss_info info;
     85	ssize_t ret;
     86	int i = 0;
     87
     88	if (!p)
     89		return -ENOMEM;
     90
     91	memset(&info, 0, sizeof(info));
     92	ret = mwifiex_get_bss_info(priv, &info);
     93	if (ret)
     94		goto free_and_exit;
     95
     96	mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
     97
     98	mwifiex_get_ver_ext(priv, 0);
     99
    100	p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
    101	p += sprintf(p, "driver_version = %s", fmt);
    102	p += sprintf(p, "\nverext = %s", priv->version_str);
    103	p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
    104
    105	if (info.bss_mode >= ARRAY_SIZE(bss_modes))
    106		p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
    107	else
    108		p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
    109
    110	p += sprintf(p, "media_state=\"%s\"\n",
    111		     (!priv->media_connected ? "Disconnected" : "Connected"));
    112	p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
    113
    114	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
    115		p += sprintf(p, "multicast_count=\"%d\"\n",
    116			     netdev_mc_count(netdev));
    117		p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len,
    118			     info.ssid.ssid);
    119		p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
    120		p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
    121		p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
    122		p += sprintf(p, "region_code=\"0x%x\"\n",
    123			     priv->adapter->region_code);
    124
    125		netdev_for_each_mc_addr(ha, netdev)
    126			p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",
    127					i++, ha->addr);
    128	}
    129
    130	p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
    131	p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
    132	p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
    133	p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
    134	p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
    135	p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
    136	p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
    137	p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
    138	p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
    139					 ? "on" : "off"));
    140	p += sprintf(p, "tx queue");
    141	for (i = 0; i < netdev->num_tx_queues; i++) {
    142		txq = netdev_get_tx_queue(netdev, i);
    143		p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ?
    144			     "stopped" : "started");
    145	}
    146	p += sprintf(p, "\n");
    147
    148	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
    149				      (unsigned long) p - page);
    150
    151free_and_exit:
    152	free_page(page);
    153	return ret;
    154}
    155
    156/*
    157 * Proc getlog file read handler.
    158 *
    159 * This function is called when the 'getlog' file is opened for reading
    160 * It prints the following log information -
    161 *      - Number of multicast Tx frames
    162 *      - Number of failed packets
    163 *      - Number of Tx retries
    164 *      - Number of multicast Tx retries
    165 *      - Number of duplicate frames
    166 *      - Number of RTS successes
    167 *      - Number of RTS failures
    168 *      - Number of ACK failures
    169 *      - Number of fragmented Rx frames
    170 *      - Number of multicast Rx frames
    171 *      - Number of FCS errors
    172 *      - Number of Tx frames
    173 *      - WEP ICV error counts
    174 *      - Number of received beacons
    175 *      - Number of missed beacons
    176 */
    177static ssize_t
    178mwifiex_getlog_read(struct file *file, char __user *ubuf,
    179		    size_t count, loff_t *ppos)
    180{
    181	struct mwifiex_private *priv =
    182		(struct mwifiex_private *) file->private_data;
    183	unsigned long page = get_zeroed_page(GFP_KERNEL);
    184	char *p = (char *) page;
    185	ssize_t ret;
    186	struct mwifiex_ds_get_stats stats;
    187
    188	if (!p)
    189		return -ENOMEM;
    190
    191	memset(&stats, 0, sizeof(stats));
    192	ret = mwifiex_get_stats_info(priv, &stats);
    193	if (ret)
    194		goto free_and_exit;
    195
    196	p += sprintf(p, "\n"
    197		     "mcasttxframe     %u\n"
    198		     "failed           %u\n"
    199		     "retry            %u\n"
    200		     "multiretry       %u\n"
    201		     "framedup         %u\n"
    202		     "rtssuccess       %u\n"
    203		     "rtsfailure       %u\n"
    204		     "ackfailure       %u\n"
    205		     "rxfrag           %u\n"
    206		     "mcastrxframe     %u\n"
    207		     "fcserror         %u\n"
    208		     "txframe          %u\n"
    209		     "wepicverrcnt-1   %u\n"
    210		     "wepicverrcnt-2   %u\n"
    211		     "wepicverrcnt-3   %u\n"
    212		     "wepicverrcnt-4   %u\n"
    213		     "bcn_rcv_cnt   %u\n"
    214		     "bcn_miss_cnt   %u\n",
    215		     stats.mcast_tx_frame,
    216		     stats.failed,
    217		     stats.retry,
    218		     stats.multi_retry,
    219		     stats.frame_dup,
    220		     stats.rts_success,
    221		     stats.rts_failure,
    222		     stats.ack_failure,
    223		     stats.rx_frag,
    224		     stats.mcast_rx_frame,
    225		     stats.fcs_error,
    226		     stats.tx_frame,
    227		     stats.wep_icv_error[0],
    228		     stats.wep_icv_error[1],
    229		     stats.wep_icv_error[2],
    230		     stats.wep_icv_error[3],
    231		     stats.bcn_rcv_cnt,
    232		     stats.bcn_miss_cnt);
    233
    234
    235	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
    236				      (unsigned long) p - page);
    237
    238free_and_exit:
    239	free_page(page);
    240	return ret;
    241}
    242
    243/* Sysfs histogram file read handler.
    244 *
    245 * This function is called when the 'histogram' file is opened for reading
    246 * It prints the following histogram information -
    247 *      - Number of histogram samples
    248 *      - Receive packet number of each rx_rate
    249 *      - Receive packet number of each snr
    250 *      - Receive packet number of each nosie_flr
    251 *      - Receive packet number of each signal streath
    252 */
    253static ssize_t
    254mwifiex_histogram_read(struct file *file, char __user *ubuf,
    255		       size_t count, loff_t *ppos)
    256{
    257	struct mwifiex_private *priv =
    258		(struct mwifiex_private *)file->private_data;
    259	ssize_t ret;
    260	struct mwifiex_histogram_data *phist_data;
    261	int i, value;
    262	unsigned long page = get_zeroed_page(GFP_KERNEL);
    263	char *p = (char *)page;
    264
    265	if (!p)
    266		return -ENOMEM;
    267
    268	if (!priv || !priv->hist_data)
    269		return -EFAULT;
    270	phist_data = priv->hist_data;
    271
    272	p += sprintf(p, "\n"
    273		     "total samples = %d\n",
    274		     atomic_read(&phist_data->num_samples));
    275
    276	p += sprintf(p,
    277		     "rx rates (in Mbps): 0=1M   1=2M 2=5.5M  3=11M   4=6M   5=9M  6=12M\n"
    278		     "7=18M  8=24M  9=36M  10=48M  11=54M 12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n");
    279
    280	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
    281		p += sprintf(p,
    282			     "44-53=MCS0-9(VHT:BW20) 54-63=MCS0-9(VHT:BW40) 64-73=MCS0-9(VHT:BW80)\n\n");
    283	} else {
    284		p += sprintf(p, "\n");
    285	}
    286
    287	for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) {
    288		value = atomic_read(&phist_data->rx_rate[i]);
    289		if (value)
    290			p += sprintf(p, "rx_rate[%02d] = %d\n", i, value);
    291	}
    292
    293	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
    294		for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES;
    295		     i++) {
    296			value = atomic_read(&phist_data->rx_rate[i]);
    297			if (value)
    298				p += sprintf(p, "rx_rate[%02d] = %d\n",
    299					   i, value);
    300		}
    301	}
    302
    303	for (i = 0; i < MWIFIEX_MAX_SNR; i++) {
    304		value =  atomic_read(&phist_data->snr[i]);
    305		if (value)
    306			p += sprintf(p, "snr[%02ddB] = %d\n", i, value);
    307	}
    308	for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) {
    309		value = atomic_read(&phist_data->noise_flr[i]);
    310		if (value)
    311			p += sprintf(p, "noise_flr[%02ddBm] = %d\n",
    312				(int)(i-128), value);
    313	}
    314	for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) {
    315		value = atomic_read(&phist_data->sig_str[i]);
    316		if (value)
    317			p += sprintf(p, "sig_strength[-%02ddBm] = %d\n",
    318				i, value);
    319	}
    320
    321	ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
    322				      (unsigned long)p - page);
    323
    324	return ret;
    325}
    326
    327static ssize_t
    328mwifiex_histogram_write(struct file *file, const char __user *ubuf,
    329			size_t count, loff_t *ppos)
    330{
    331	struct mwifiex_private *priv = (void *)file->private_data;
    332
    333	if (priv && priv->hist_data)
    334		mwifiex_hist_data_reset(priv);
    335	return 0;
    336}
    337
    338static struct mwifiex_debug_info info;
    339
    340/*
    341 * Proc debug file read handler.
    342 *
    343 * This function is called when the 'debug' file is opened for reading
    344 * It prints the following log information -
    345 *      - Interrupt count
    346 *      - WMM AC VO packets count
    347 *      - WMM AC VI packets count
    348 *      - WMM AC BE packets count
    349 *      - WMM AC BK packets count
    350 *      - Maximum Tx buffer size
    351 *      - Tx buffer size
    352 *      - Current Tx buffer size
    353 *      - Power Save mode
    354 *      - Power Save state
    355 *      - Deep Sleep status
    356 *      - Device wakeup required status
    357 *      - Number of wakeup tries
    358 *      - Host Sleep configured status
    359 *      - Host Sleep activated status
    360 *      - Number of Tx timeouts
    361 *      - Number of command timeouts
    362 *      - Last timed out command ID
    363 *      - Last timed out command action
    364 *      - Last command ID
    365 *      - Last command action
    366 *      - Last command index
    367 *      - Last command response ID
    368 *      - Last command response index
    369 *      - Last event
    370 *      - Last event index
    371 *      - Number of host to card command failures
    372 *      - Number of sleep confirm command failures
    373 *      - Number of host to card data failure
    374 *      - Number of deauthentication events
    375 *      - Number of disassociation events
    376 *      - Number of link lost events
    377 *      - Number of deauthentication commands
    378 *      - Number of association success commands
    379 *      - Number of association failure commands
    380 *      - Number of commands sent
    381 *      - Number of data packets sent
    382 *      - Number of command responses received
    383 *      - Number of events received
    384 *      - Tx BA stream table (TID, RA)
    385 *      - Rx reorder table (TID, TA, Start window, Window size, Buffer)
    386 */
    387static ssize_t
    388mwifiex_debug_read(struct file *file, char __user *ubuf,
    389		   size_t count, loff_t *ppos)
    390{
    391	struct mwifiex_private *priv =
    392		(struct mwifiex_private *) file->private_data;
    393	unsigned long page = get_zeroed_page(GFP_KERNEL);
    394	char *p = (char *) page;
    395	ssize_t ret;
    396
    397	if (!p)
    398		return -ENOMEM;
    399
    400	ret = mwifiex_get_debug_info(priv, &info);
    401	if (ret)
    402		goto free_and_exit;
    403
    404	p += mwifiex_debug_info_to_buffer(priv, p, &info);
    405
    406	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
    407				      (unsigned long) p - page);
    408
    409free_and_exit:
    410	free_page(page);
    411	return ret;
    412}
    413
    414static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
    415
    416/*
    417 * Proc regrdwr file write handler.
    418 *
    419 * This function is called when the 'regrdwr' file is opened for writing
    420 *
    421 * This function can be used to write to a register.
    422 */
    423static ssize_t
    424mwifiex_regrdwr_write(struct file *file,
    425		      const char __user *ubuf, size_t count, loff_t *ppos)
    426{
    427	char *buf;
    428	int ret;
    429	u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
    430
    431	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
    432	if (IS_ERR(buf))
    433		return PTR_ERR(buf);
    434
    435	sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
    436
    437	if (reg_type == 0 || reg_offset == 0) {
    438		ret = -EINVAL;
    439		goto done;
    440	} else {
    441		saved_reg_type = reg_type;
    442		saved_reg_offset = reg_offset;
    443		saved_reg_value = reg_value;
    444		ret = count;
    445	}
    446done:
    447	kfree(buf);
    448	return ret;
    449}
    450
    451/*
    452 * Proc regrdwr file read handler.
    453 *
    454 * This function is called when the 'regrdwr' file is opened for reading
    455 *
    456 * This function can be used to read from a register.
    457 */
    458static ssize_t
    459mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
    460		     size_t count, loff_t *ppos)
    461{
    462	struct mwifiex_private *priv =
    463		(struct mwifiex_private *) file->private_data;
    464	unsigned long addr = get_zeroed_page(GFP_KERNEL);
    465	char *buf = (char *) addr;
    466	int pos = 0, ret = 0;
    467	u32 reg_value;
    468
    469	if (!buf)
    470		return -ENOMEM;
    471
    472	if (!saved_reg_type) {
    473		/* No command has been given */
    474		pos += snprintf(buf, PAGE_SIZE, "0");
    475		goto done;
    476	}
    477	/* Set command has been given */
    478	if (saved_reg_value != UINT_MAX) {
    479		ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
    480					saved_reg_value);
    481
    482		pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
    483				saved_reg_type, saved_reg_offset,
    484				saved_reg_value);
    485
    486		ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
    487
    488		goto done;
    489	}
    490	/* Get command has been given */
    491	ret = mwifiex_reg_read(priv, saved_reg_type,
    492			       saved_reg_offset, &reg_value);
    493	if (ret) {
    494		ret = -EINVAL;
    495		goto done;
    496	}
    497
    498	pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
    499			saved_reg_offset, reg_value);
    500
    501	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
    502
    503done:
    504	free_page(addr);
    505	return ret;
    506}
    507
    508/* Proc debug_mask file read handler.
    509 * This function is called when the 'debug_mask' file is opened for reading
    510 * This function can be used read driver debugging mask value.
    511 */
    512static ssize_t
    513mwifiex_debug_mask_read(struct file *file, char __user *ubuf,
    514			size_t count, loff_t *ppos)
    515{
    516	struct mwifiex_private *priv =
    517		(struct mwifiex_private *)file->private_data;
    518	unsigned long page = get_zeroed_page(GFP_KERNEL);
    519	char *buf = (char *)page;
    520	size_t ret = 0;
    521	int pos = 0;
    522
    523	if (!buf)
    524		return -ENOMEM;
    525
    526	pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n",
    527			priv->adapter->debug_mask);
    528	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
    529
    530	free_page(page);
    531	return ret;
    532}
    533
    534/* Proc debug_mask file read handler.
    535 * This function is called when the 'debug_mask' file is opened for reading
    536 * This function can be used read driver debugging mask value.
    537 */
    538static ssize_t
    539mwifiex_debug_mask_write(struct file *file, const char __user *ubuf,
    540			 size_t count, loff_t *ppos)
    541{
    542	int ret;
    543	unsigned long debug_mask;
    544	struct mwifiex_private *priv = (void *)file->private_data;
    545	char *buf;
    546
    547	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
    548	if (IS_ERR(buf))
    549		return PTR_ERR(buf);
    550
    551	if (kstrtoul(buf, 0, &debug_mask)) {
    552		ret = -EINVAL;
    553		goto done;
    554	}
    555
    556	priv->adapter->debug_mask = debug_mask;
    557	ret = count;
    558done:
    559	kfree(buf);
    560	return ret;
    561}
    562
    563/* debugfs verext file write handler.
    564 * This function is called when the 'verext' file is opened for write
    565 */
    566static ssize_t
    567mwifiex_verext_write(struct file *file, const char __user *ubuf,
    568		     size_t count, loff_t *ppos)
    569{
    570	int ret;
    571	u32 versionstrsel;
    572	struct mwifiex_private *priv = (void *)file->private_data;
    573	char buf[16];
    574
    575	memset(buf, 0, sizeof(buf));
    576
    577	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
    578		return -EFAULT;
    579
    580	ret = kstrtou32(buf, 10, &versionstrsel);
    581	if (ret)
    582		return ret;
    583
    584	priv->versionstrsel = versionstrsel;
    585
    586	return count;
    587}
    588
    589/* Proc verext file read handler.
    590 * This function is called when the 'verext' file is opened for reading
    591 * This function can be used read driver exteneed verion string.
    592 */
    593static ssize_t
    594mwifiex_verext_read(struct file *file, char __user *ubuf,
    595		    size_t count, loff_t *ppos)
    596{
    597	struct mwifiex_private *priv =
    598		(struct mwifiex_private *)file->private_data;
    599	char buf[256];
    600	int ret;
    601
    602	mwifiex_get_ver_ext(priv, priv->versionstrsel);
    603	ret = snprintf(buf, sizeof(buf), "version string: %s\n",
    604		       priv->version_str);
    605
    606	return simple_read_from_buffer(ubuf, count, ppos, buf, ret);
    607}
    608
    609/* Proc memrw file write handler.
    610 * This function is called when the 'memrw' file is opened for writing
    611 * This function can be used to write to a memory location.
    612 */
    613static ssize_t
    614mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,
    615		    loff_t *ppos)
    616{
    617	int ret;
    618	char cmd;
    619	struct mwifiex_ds_mem_rw mem_rw;
    620	u16 cmd_action;
    621	struct mwifiex_private *priv = (void *)file->private_data;
    622	char *buf;
    623
    624	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
    625	if (IS_ERR(buf))
    626		return PTR_ERR(buf);
    627
    628	ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);
    629	if (ret != 3) {
    630		ret = -EINVAL;
    631		goto done;
    632	}
    633
    634	if ((cmd == 'r') || (cmd == 'R')) {
    635		cmd_action = HostCmd_ACT_GEN_GET;
    636		mem_rw.value = 0;
    637	} else if ((cmd == 'w') || (cmd == 'W')) {
    638		cmd_action = HostCmd_ACT_GEN_SET;
    639	} else {
    640		ret = -EINVAL;
    641		goto done;
    642	}
    643
    644	memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw));
    645	if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,
    646			     &mem_rw, true))
    647		ret = -1;
    648	else
    649		ret = count;
    650
    651done:
    652	kfree(buf);
    653	return ret;
    654}
    655
    656/* Proc memrw file read handler.
    657 * This function is called when the 'memrw' file is opened for reading
    658 * This function can be used to read from a memory location.
    659 */
    660static ssize_t
    661mwifiex_memrw_read(struct file *file, char __user *ubuf,
    662		   size_t count, loff_t *ppos)
    663{
    664	struct mwifiex_private *priv = (void *)file->private_data;
    665	unsigned long addr = get_zeroed_page(GFP_KERNEL);
    666	char *buf = (char *)addr;
    667	int ret, pos = 0;
    668
    669	if (!buf)
    670		return -ENOMEM;
    671
    672	pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr,
    673			priv->mem_rw.value);
    674	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
    675
    676	free_page(addr);
    677	return ret;
    678}
    679
    680static u32 saved_offset = -1, saved_bytes = -1;
    681
    682/*
    683 * Proc rdeeprom file write handler.
    684 *
    685 * This function is called when the 'rdeeprom' file is opened for writing
    686 *
    687 * This function can be used to write to a RDEEPROM location.
    688 */
    689static ssize_t
    690mwifiex_rdeeprom_write(struct file *file,
    691		       const char __user *ubuf, size_t count, loff_t *ppos)
    692{
    693	char *buf;
    694	int ret = 0;
    695	int offset = -1, bytes = -1;
    696
    697	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
    698	if (IS_ERR(buf))
    699		return PTR_ERR(buf);
    700
    701	sscanf(buf, "%d %d", &offset, &bytes);
    702
    703	if (offset == -1 || bytes == -1) {
    704		ret = -EINVAL;
    705		goto done;
    706	} else {
    707		saved_offset = offset;
    708		saved_bytes = bytes;
    709		ret = count;
    710	}
    711done:
    712	kfree(buf);
    713	return ret;
    714}
    715
    716/*
    717 * Proc rdeeprom read write handler.
    718 *
    719 * This function is called when the 'rdeeprom' file is opened for reading
    720 *
    721 * This function can be used to read from a RDEEPROM location.
    722 */
    723static ssize_t
    724mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
    725		      size_t count, loff_t *ppos)
    726{
    727	struct mwifiex_private *priv =
    728		(struct mwifiex_private *) file->private_data;
    729	unsigned long addr = get_zeroed_page(GFP_KERNEL);
    730	char *buf = (char *) addr;
    731	int pos, ret, i;
    732	u8 value[MAX_EEPROM_DATA];
    733
    734	if (!buf)
    735		return -ENOMEM;
    736
    737	if (saved_offset == -1) {
    738		/* No command has been given */
    739		pos = snprintf(buf, PAGE_SIZE, "0");
    740		goto done;
    741	}
    742
    743	/* Get command has been given */
    744	ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
    745				  (u16) saved_bytes, value);
    746	if (ret) {
    747		ret = -EINVAL;
    748		goto out_free;
    749	}
    750
    751	pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
    752
    753	for (i = 0; i < saved_bytes; i++)
    754		pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]);
    755
    756done:
    757	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
    758out_free:
    759	free_page(addr);
    760	return ret;
    761}
    762
    763/* Proc hscfg file write handler
    764 * This function can be used to configure the host sleep parameters.
    765 */
    766static ssize_t
    767mwifiex_hscfg_write(struct file *file, const char __user *ubuf,
    768		    size_t count, loff_t *ppos)
    769{
    770	struct mwifiex_private *priv = (void *)file->private_data;
    771	char *buf;
    772	int ret, arg_num;
    773	struct mwifiex_ds_hs_cfg hscfg;
    774	int conditions = HS_CFG_COND_DEF;
    775	u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF;
    776
    777	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
    778	if (IS_ERR(buf))
    779		return PTR_ERR(buf);
    780
    781	arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap);
    782
    783	memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));
    784
    785	if (arg_num > 3) {
    786		mwifiex_dbg(priv->adapter, ERROR,
    787			    "Too many arguments\n");
    788		ret = -EINVAL;
    789		goto done;
    790	}
    791
    792	if (arg_num >= 1 && arg_num < 3)
    793		mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
    794				      MWIFIEX_SYNC_CMD, &hscfg);
    795
    796	if (arg_num) {
    797		if (conditions == HS_CFG_CANCEL) {
    798			mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD);
    799			ret = count;
    800			goto done;
    801		}
    802		hscfg.conditions = conditions;
    803	}
    804	if (arg_num >= 2)
    805		hscfg.gpio = gpio;
    806	if (arg_num == 3)
    807		hscfg.gap = gap;
    808
    809	hscfg.is_invoke_hostcmd = false;
    810	mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
    811			      MWIFIEX_SYNC_CMD, &hscfg);
    812
    813	mwifiex_enable_hs(priv->adapter);
    814	clear_bit(MWIFIEX_IS_HS_ENABLING, &priv->adapter->work_flags);
    815	ret = count;
    816done:
    817	kfree(buf);
    818	return ret;
    819}
    820
    821/* Proc hscfg file read handler
    822 * This function can be used to read host sleep configuration
    823 * parameters from driver.
    824 */
    825static ssize_t
    826mwifiex_hscfg_read(struct file *file, char __user *ubuf,
    827		   size_t count, loff_t *ppos)
    828{
    829	struct mwifiex_private *priv = (void *)file->private_data;
    830	unsigned long addr = get_zeroed_page(GFP_KERNEL);
    831	char *buf = (char *)addr;
    832	int pos, ret;
    833	struct mwifiex_ds_hs_cfg hscfg;
    834
    835	if (!buf)
    836		return -ENOMEM;
    837
    838	mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
    839			      MWIFIEX_SYNC_CMD, &hscfg);
    840
    841	pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions,
    842		       hscfg.gpio, hscfg.gap);
    843
    844	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
    845
    846	free_page(addr);
    847	return ret;
    848}
    849
    850static ssize_t
    851mwifiex_timeshare_coex_read(struct file *file, char __user *ubuf,
    852			    size_t count, loff_t *ppos)
    853{
    854	struct mwifiex_private *priv = file->private_data;
    855	char buf[3];
    856	bool timeshare_coex;
    857	int ret;
    858	unsigned int len;
    859
    860	if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)
    861		return -EOPNOTSUPP;
    862
    863	ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,
    864			       HostCmd_ACT_GEN_GET, 0, &timeshare_coex, true);
    865	if (ret)
    866		return ret;
    867
    868	len = sprintf(buf, "%d\n", timeshare_coex);
    869	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
    870}
    871
    872static ssize_t
    873mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf,
    874			     size_t count, loff_t *ppos)
    875{
    876	bool timeshare_coex;
    877	struct mwifiex_private *priv = file->private_data;
    878	char kbuf[16];
    879	int ret;
    880
    881	if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)
    882		return -EOPNOTSUPP;
    883
    884	memset(kbuf, 0, sizeof(kbuf));
    885
    886	if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count)))
    887		return -EFAULT;
    888
    889	if (strtobool(kbuf, &timeshare_coex))
    890		return -EINVAL;
    891
    892	ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,
    893			       HostCmd_ACT_GEN_SET, 0, &timeshare_coex, true);
    894	if (ret)
    895		return ret;
    896	else
    897		return count;
    898}
    899
    900static ssize_t
    901mwifiex_reset_write(struct file *file,
    902		    const char __user *ubuf, size_t count, loff_t *ppos)
    903{
    904	struct mwifiex_private *priv = file->private_data;
    905	struct mwifiex_adapter *adapter = priv->adapter;
    906	bool result;
    907	int rc;
    908
    909	rc = kstrtobool_from_user(ubuf, count, &result);
    910	if (rc)
    911		return rc;
    912
    913	if (!result)
    914		return -EINVAL;
    915
    916	if (adapter->if_ops.card_reset) {
    917		dev_info(adapter->dev, "Resetting per request\n");
    918		adapter->if_ops.card_reset(adapter);
    919	}
    920
    921	return count;
    922}
    923
    924#define MWIFIEX_DFS_ADD_FILE(name) do {                                 \
    925	debugfs_create_file(#name, 0644, priv->dfs_dev_dir, priv,       \
    926			    &mwifiex_dfs_##name##_fops);                \
    927} while (0);
    928
    929#define MWIFIEX_DFS_FILE_OPS(name)                                      \
    930static const struct file_operations mwifiex_dfs_##name##_fops = {       \
    931	.read = mwifiex_##name##_read,                                  \
    932	.write = mwifiex_##name##_write,                                \
    933	.open = simple_open,                                            \
    934};
    935
    936#define MWIFIEX_DFS_FILE_READ_OPS(name)                                 \
    937static const struct file_operations mwifiex_dfs_##name##_fops = {       \
    938	.read = mwifiex_##name##_read,                                  \
    939	.open = simple_open,                                            \
    940};
    941
    942#define MWIFIEX_DFS_FILE_WRITE_OPS(name)                                \
    943static const struct file_operations mwifiex_dfs_##name##_fops = {       \
    944	.write = mwifiex_##name##_write,                                \
    945	.open = simple_open,                                            \
    946};
    947
    948
    949MWIFIEX_DFS_FILE_READ_OPS(info);
    950MWIFIEX_DFS_FILE_READ_OPS(debug);
    951MWIFIEX_DFS_FILE_READ_OPS(getlog);
    952MWIFIEX_DFS_FILE_OPS(regrdwr);
    953MWIFIEX_DFS_FILE_OPS(rdeeprom);
    954MWIFIEX_DFS_FILE_OPS(memrw);
    955MWIFIEX_DFS_FILE_OPS(hscfg);
    956MWIFIEX_DFS_FILE_OPS(histogram);
    957MWIFIEX_DFS_FILE_OPS(debug_mask);
    958MWIFIEX_DFS_FILE_OPS(timeshare_coex);
    959MWIFIEX_DFS_FILE_WRITE_OPS(reset);
    960MWIFIEX_DFS_FILE_OPS(verext);
    961
    962/*
    963 * This function creates the debug FS directory structure and the files.
    964 */
    965void
    966mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
    967{
    968	if (!mwifiex_dfs_dir || !priv)
    969		return;
    970
    971	priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
    972					       mwifiex_dfs_dir);
    973
    974	if (!priv->dfs_dev_dir)
    975		return;
    976
    977	MWIFIEX_DFS_ADD_FILE(info);
    978	MWIFIEX_DFS_ADD_FILE(debug);
    979	MWIFIEX_DFS_ADD_FILE(getlog);
    980	MWIFIEX_DFS_ADD_FILE(regrdwr);
    981	MWIFIEX_DFS_ADD_FILE(rdeeprom);
    982
    983	MWIFIEX_DFS_ADD_FILE(memrw);
    984	MWIFIEX_DFS_ADD_FILE(hscfg);
    985	MWIFIEX_DFS_ADD_FILE(histogram);
    986	MWIFIEX_DFS_ADD_FILE(debug_mask);
    987	MWIFIEX_DFS_ADD_FILE(timeshare_coex);
    988	MWIFIEX_DFS_ADD_FILE(reset);
    989	MWIFIEX_DFS_ADD_FILE(verext);
    990}
    991
    992/*
    993 * This function removes the debug FS directory structure and the files.
    994 */
    995void
    996mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
    997{
    998	if (!priv)
    999		return;
   1000
   1001	debugfs_remove_recursive(priv->dfs_dev_dir);
   1002}
   1003
   1004/*
   1005 * This function creates the top level proc directory.
   1006 */
   1007void
   1008mwifiex_debugfs_init(void)
   1009{
   1010	if (!mwifiex_dfs_dir)
   1011		mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
   1012}
   1013
   1014/*
   1015 * This function removes the top level proc directory.
   1016 */
   1017void
   1018mwifiex_debugfs_remove(void)
   1019{
   1020	debugfs_remove(mwifiex_dfs_dir);
   1021}