brintos

brintos / linux-shallow public Read only

0
0
Text · 25.7 KiB · 9deaf59 Raw
1007 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * NXP Wireless LAN device driver: debugfs4 *5 * Copyright 2011-2020 NXP6 */7 8#include <linux/debugfs.h>9 10#include "main.h"11#include "11n.h"12 13 14static struct dentry *mwifiex_dfs_dir;15 16static char *bss_modes[] = {17	"UNSPECIFIED",18	"ADHOC",19	"STATION",20	"AP",21	"AP_VLAN",22	"WDS",23	"MONITOR",24	"MESH_POINT",25	"P2P_CLIENT",26	"P2P_GO",27	"P2P_DEVICE",28};29 30/*31 * Proc info file read handler.32 *33 * This function is called when the 'info' file is opened for reading.34 * It prints the following driver related information -35 *      - Driver name36 *      - Driver version37 *      - Driver extended version38 *      - Interface name39 *      - BSS mode40 *      - Media state (connected or disconnected)41 *      - MAC address42 *      - Total number of Tx bytes43 *      - Total number of Rx bytes44 *      - Total number of Tx packets45 *      - Total number of Rx packets46 *      - Total number of dropped Tx packets47 *      - Total number of dropped Rx packets48 *      - Total number of corrupted Tx packets49 *      - Total number of corrupted Rx packets50 *      - Carrier status (on or off)51 *      - Tx queue status (started or stopped)52 *53 * For STA mode drivers, it also prints the following extra -54 *      - ESSID55 *      - BSSID56 *      - Channel57 *      - Region code58 *      - Multicast count59 *      - Multicast addresses60 */61static ssize_t62mwifiex_info_read(struct file *file, char __user *ubuf,63		  size_t count, loff_t *ppos)64{65	struct mwifiex_private *priv =66		(struct mwifiex_private *) file->private_data;67	struct net_device *netdev = priv->netdev;68	struct netdev_hw_addr *ha;69	struct netdev_queue *txq;70	unsigned long page = get_zeroed_page(GFP_KERNEL);71	char *p = (char *) page, fmt[64];72	struct mwifiex_bss_info info;73	ssize_t ret;74	int i = 0;75 76	if (!p)77		return -ENOMEM;78 79	memset(&info, 0, sizeof(info));80	ret = mwifiex_get_bss_info(priv, &info);81	if (ret)82		goto free_and_exit;83 84	mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);85 86	mwifiex_get_ver_ext(priv, 0);87 88	p += sprintf(p, "driver_name = " "\"mwifiex\"\n");89	p += sprintf(p, "driver_version = %s", fmt);90	p += sprintf(p, "\nverext = %s", priv->version_str);91	p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);92 93	if (info.bss_mode >= ARRAY_SIZE(bss_modes))94		p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);95	else96		p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);97 98	p += sprintf(p, "media_state=\"%s\"\n",99		     (!priv->media_connected ? "Disconnected" : "Connected"));100	p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);101 102	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {103		p += sprintf(p, "multicast_count=\"%d\"\n",104			     netdev_mc_count(netdev));105		p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len,106			     info.ssid.ssid);107		p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);108		p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);109		p += sprintf(p, "country_code = \"%s\"\n", info.country_code);110		p += sprintf(p, "region_code=\"0x%x\"\n",111			     priv->adapter->region_code);112 113		netdev_for_each_mc_addr(ha, netdev)114			p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",115					i++, ha->addr);116	}117 118	p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);119	p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);120	p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);121	p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);122	p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);123	p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);124	p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);125	p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);126	p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))127					 ? "on" : "off"));128	p += sprintf(p, "tx queue");129	for (i = 0; i < netdev->num_tx_queues; i++) {130		txq = netdev_get_tx_queue(netdev, i);131		p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ?132			     "stopped" : "started");133	}134	p += sprintf(p, "\n");135 136	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,137				      (unsigned long) p - page);138 139free_and_exit:140	free_page(page);141	return ret;142}143 144/*145 * Proc getlog file read handler.146 *147 * This function is called when the 'getlog' file is opened for reading148 * It prints the following log information -149 *      - Number of multicast Tx frames150 *      - Number of failed packets151 *      - Number of Tx retries152 *      - Number of multicast Tx retries153 *      - Number of duplicate frames154 *      - Number of RTS successes155 *      - Number of RTS failures156 *      - Number of ACK failures157 *      - Number of fragmented Rx frames158 *      - Number of multicast Rx frames159 *      - Number of FCS errors160 *      - Number of Tx frames161 *      - WEP ICV error counts162 *      - Number of received beacons163 *      - Number of missed beacons164 */165static ssize_t166mwifiex_getlog_read(struct file *file, char __user *ubuf,167		    size_t count, loff_t *ppos)168{169	struct mwifiex_private *priv =170		(struct mwifiex_private *) file->private_data;171	unsigned long page = get_zeroed_page(GFP_KERNEL);172	char *p = (char *) page;173	ssize_t ret;174	struct mwifiex_ds_get_stats stats;175 176	if (!p)177		return -ENOMEM;178 179	memset(&stats, 0, sizeof(stats));180	ret = mwifiex_get_stats_info(priv, &stats);181	if (ret)182		goto free_and_exit;183 184	p += sprintf(p, "\n"185		     "mcasttxframe     %u\n"186		     "failed           %u\n"187		     "retry            %u\n"188		     "multiretry       %u\n"189		     "framedup         %u\n"190		     "rtssuccess       %u\n"191		     "rtsfailure       %u\n"192		     "ackfailure       %u\n"193		     "rxfrag           %u\n"194		     "mcastrxframe     %u\n"195		     "fcserror         %u\n"196		     "txframe          %u\n"197		     "wepicverrcnt-1   %u\n"198		     "wepicverrcnt-2   %u\n"199		     "wepicverrcnt-3   %u\n"200		     "wepicverrcnt-4   %u\n"201		     "bcn_rcv_cnt   %u\n"202		     "bcn_miss_cnt   %u\n",203		     stats.mcast_tx_frame,204		     stats.failed,205		     stats.retry,206		     stats.multi_retry,207		     stats.frame_dup,208		     stats.rts_success,209		     stats.rts_failure,210		     stats.ack_failure,211		     stats.rx_frag,212		     stats.mcast_rx_frame,213		     stats.fcs_error,214		     stats.tx_frame,215		     stats.wep_icv_error[0],216		     stats.wep_icv_error[1],217		     stats.wep_icv_error[2],218		     stats.wep_icv_error[3],219		     stats.bcn_rcv_cnt,220		     stats.bcn_miss_cnt);221 222 223	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,224				      (unsigned long) p - page);225 226free_and_exit:227	free_page(page);228	return ret;229}230 231/* Sysfs histogram file read handler.232 *233 * This function is called when the 'histogram' file is opened for reading234 * It prints the following histogram information -235 *      - Number of histogram samples236 *      - Receive packet number of each rx_rate237 *      - Receive packet number of each snr238 *      - Receive packet number of each nosie_flr239 *      - Receive packet number of each signal streath240 */241static ssize_t242mwifiex_histogram_read(struct file *file, char __user *ubuf,243		       size_t count, loff_t *ppos)244{245	struct mwifiex_private *priv =246		(struct mwifiex_private *)file->private_data;247	ssize_t ret;248	struct mwifiex_histogram_data *phist_data;249	int i, value;250	unsigned long page = get_zeroed_page(GFP_KERNEL);251	char *p = (char *)page;252 253	if (!p)254		return -ENOMEM;255 256	if (!priv || !priv->hist_data) {257		ret = -EFAULT;258		goto free_and_exit;259	}260 261	phist_data = priv->hist_data;262 263	p += sprintf(p, "\n"264		     "total samples = %d\n",265		     atomic_read(&phist_data->num_samples));266 267	p += sprintf(p,268		     "rx rates (in Mbps): 0=1M   1=2M 2=5.5M  3=11M   4=6M   5=9M  6=12M\n"269		     "7=18M  8=24M  9=36M  10=48M  11=54M 12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n");270 271	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {272		p += sprintf(p,273			     "44-53=MCS0-9(VHT:BW20) 54-63=MCS0-9(VHT:BW40) 64-73=MCS0-9(VHT:BW80)\n\n");274	} else {275		p += sprintf(p, "\n");276	}277 278	for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) {279		value = atomic_read(&phist_data->rx_rate[i]);280		if (value)281			p += sprintf(p, "rx_rate[%02d] = %d\n", i, value);282	}283 284	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {285		for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES;286		     i++) {287			value = atomic_read(&phist_data->rx_rate[i]);288			if (value)289				p += sprintf(p, "rx_rate[%02d] = %d\n",290					   i, value);291		}292	}293 294	for (i = 0; i < MWIFIEX_MAX_SNR; i++) {295		value =  atomic_read(&phist_data->snr[i]);296		if (value)297			p += sprintf(p, "snr[%02ddB] = %d\n", i, value);298	}299	for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) {300		value = atomic_read(&phist_data->noise_flr[i]);301		if (value)302			p += sprintf(p, "noise_flr[%02ddBm] = %d\n",303				(int)(i-128), value);304	}305	for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) {306		value = atomic_read(&phist_data->sig_str[i]);307		if (value)308			p += sprintf(p, "sig_strength[-%02ddBm] = %d\n",309				i, value);310	}311 312	ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,313				      (unsigned long)p - page);314 315free_and_exit:316	free_page(page);317	return ret;318}319 320static ssize_t321mwifiex_histogram_write(struct file *file, const char __user *ubuf,322			size_t count, loff_t *ppos)323{324	struct mwifiex_private *priv = (void *)file->private_data;325 326	if (priv && priv->hist_data)327		mwifiex_hist_data_reset(priv);328	return 0;329}330 331static struct mwifiex_debug_info info;332 333/*334 * Proc debug file read handler.335 *336 * This function is called when the 'debug' file is opened for reading337 * It prints the following log information -338 *      - Interrupt count339 *      - WMM AC VO packets count340 *      - WMM AC VI packets count341 *      - WMM AC BE packets count342 *      - WMM AC BK packets count343 *      - Maximum Tx buffer size344 *      - Tx buffer size345 *      - Current Tx buffer size346 *      - Power Save mode347 *      - Power Save state348 *      - Deep Sleep status349 *      - Device wakeup required status350 *      - Number of wakeup tries351 *      - Host Sleep configured status352 *      - Host Sleep activated status353 *      - Number of Tx timeouts354 *      - Number of command timeouts355 *      - Last timed out command ID356 *      - Last timed out command action357 *      - Last command ID358 *      - Last command action359 *      - Last command index360 *      - Last command response ID361 *      - Last command response index362 *      - Last event363 *      - Last event index364 *      - Number of host to card command failures365 *      - Number of sleep confirm command failures366 *      - Number of host to card data failure367 *      - Number of deauthentication events368 *      - Number of disassociation events369 *      - Number of link lost events370 *      - Number of deauthentication commands371 *      - Number of association success commands372 *      - Number of association failure commands373 *      - Number of commands sent374 *      - Number of data packets sent375 *      - Number of command responses received376 *      - Number of events received377 *      - Tx BA stream table (TID, RA)378 *      - Rx reorder table (TID, TA, Start window, Window size, Buffer)379 */380static ssize_t381mwifiex_debug_read(struct file *file, char __user *ubuf,382		   size_t count, loff_t *ppos)383{384	struct mwifiex_private *priv =385		(struct mwifiex_private *) file->private_data;386	unsigned long page = get_zeroed_page(GFP_KERNEL);387	char *p = (char *) page;388	ssize_t ret;389 390	if (!p)391		return -ENOMEM;392 393	ret = mwifiex_get_debug_info(priv, &info);394	if (ret)395		goto free_and_exit;396 397	p += mwifiex_debug_info_to_buffer(priv, p, &info);398 399	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,400				      (unsigned long) p - page);401 402free_and_exit:403	free_page(page);404	return ret;405}406 407static u32 saved_reg_type, saved_reg_offset, saved_reg_value;408 409/*410 * Proc regrdwr file write handler.411 *412 * This function is called when the 'regrdwr' file is opened for writing413 *414 * This function can be used to write to a register.415 */416static ssize_t417mwifiex_regrdwr_write(struct file *file,418		      const char __user *ubuf, size_t count, loff_t *ppos)419{420	char *buf;421	int ret;422	u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;423 424	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));425	if (IS_ERR(buf))426		return PTR_ERR(buf);427 428	if (sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value) != 3) {429		ret = -EINVAL;430		goto done;431	}432 433	if (reg_type == 0 || reg_offset == 0) {434		ret = -EINVAL;435		goto done;436	} else {437		saved_reg_type = reg_type;438		saved_reg_offset = reg_offset;439		saved_reg_value = reg_value;440		ret = count;441	}442done:443	kfree(buf);444	return ret;445}446 447/*448 * Proc regrdwr file read handler.449 *450 * This function is called when the 'regrdwr' file is opened for reading451 *452 * This function can be used to read from a register.453 */454static ssize_t455mwifiex_regrdwr_read(struct file *file, char __user *ubuf,456		     size_t count, loff_t *ppos)457{458	struct mwifiex_private *priv =459		(struct mwifiex_private *) file->private_data;460	unsigned long addr = get_zeroed_page(GFP_KERNEL);461	char *buf = (char *) addr;462	int pos = 0, ret = 0;463	u32 reg_value;464 465	if (!buf)466		return -ENOMEM;467 468	if (!saved_reg_type) {469		/* No command has been given */470		pos += snprintf(buf, PAGE_SIZE, "0");471		goto done;472	}473	/* Set command has been given */474	if (saved_reg_value != UINT_MAX) {475		ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,476					saved_reg_value);477 478		pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",479				saved_reg_type, saved_reg_offset,480				saved_reg_value);481 482		ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);483 484		goto done;485	}486	/* Get command has been given */487	ret = mwifiex_reg_read(priv, saved_reg_type,488			       saved_reg_offset, &reg_value);489	if (ret) {490		ret = -EINVAL;491		goto done;492	}493 494	pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,495			saved_reg_offset, reg_value);496 497	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);498 499done:500	free_page(addr);501	return ret;502}503 504/* Proc debug_mask file read handler.505 * This function is called when the 'debug_mask' file is opened for reading506 * This function can be used read driver debugging mask value.507 */508static ssize_t509mwifiex_debug_mask_read(struct file *file, char __user *ubuf,510			size_t count, loff_t *ppos)511{512	struct mwifiex_private *priv =513		(struct mwifiex_private *)file->private_data;514	unsigned long page = get_zeroed_page(GFP_KERNEL);515	char *buf = (char *)page;516	size_t ret = 0;517	int pos = 0;518 519	if (!buf)520		return -ENOMEM;521 522	pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n",523			priv->adapter->debug_mask);524	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);525 526	free_page(page);527	return ret;528}529 530/* Proc debug_mask file read handler.531 * This function is called when the 'debug_mask' file is opened for reading532 * This function can be used read driver debugging mask value.533 */534static ssize_t535mwifiex_debug_mask_write(struct file *file, const char __user *ubuf,536			 size_t count, loff_t *ppos)537{538	int ret;539	unsigned long debug_mask;540	struct mwifiex_private *priv = (void *)file->private_data;541	char *buf;542 543	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));544	if (IS_ERR(buf))545		return PTR_ERR(buf);546 547	if (kstrtoul(buf, 0, &debug_mask)) {548		ret = -EINVAL;549		goto done;550	}551 552	priv->adapter->debug_mask = debug_mask;553	ret = count;554done:555	kfree(buf);556	return ret;557}558 559/* debugfs verext file write handler.560 * This function is called when the 'verext' file is opened for write561 */562static ssize_t563mwifiex_verext_write(struct file *file, const char __user *ubuf,564		     size_t count, loff_t *ppos)565{566	int ret;567	u32 versionstrsel;568	struct mwifiex_private *priv = (void *)file->private_data;569 570	ret = kstrtou32_from_user(ubuf, count, 10, &versionstrsel);571	if (ret)572		return ret;573 574	priv->versionstrsel = versionstrsel;575 576	return count;577}578 579/* Proc verext file read handler.580 * This function is called when the 'verext' file is opened for reading581 * This function can be used read driver exteneed verion string.582 */583static ssize_t584mwifiex_verext_read(struct file *file, char __user *ubuf,585		    size_t count, loff_t *ppos)586{587	struct mwifiex_private *priv =588		(struct mwifiex_private *)file->private_data;589	char buf[256];590	int ret;591 592	mwifiex_get_ver_ext(priv, priv->versionstrsel);593	ret = snprintf(buf, sizeof(buf), "version string: %s\n",594		       priv->version_str);595 596	return simple_read_from_buffer(ubuf, count, ppos, buf, ret);597}598 599/* Proc memrw file write handler.600 * This function is called when the 'memrw' file is opened for writing601 * This function can be used to write to a memory location.602 */603static ssize_t604mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,605		    loff_t *ppos)606{607	int ret;608	char cmd;609	struct mwifiex_ds_mem_rw mem_rw;610	u16 cmd_action;611	struct mwifiex_private *priv = (void *)file->private_data;612	char *buf;613 614	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));615	if (IS_ERR(buf))616		return PTR_ERR(buf);617 618	ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);619	if (ret != 3) {620		ret = -EINVAL;621		goto done;622	}623 624	if ((cmd == 'r') || (cmd == 'R')) {625		cmd_action = HostCmd_ACT_GEN_GET;626		mem_rw.value = 0;627	} else if ((cmd == 'w') || (cmd == 'W')) {628		cmd_action = HostCmd_ACT_GEN_SET;629	} else {630		ret = -EINVAL;631		goto done;632	}633 634	memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw));635	if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,636			     &mem_rw, true))637		ret = -1;638	else639		ret = count;640 641done:642	kfree(buf);643	return ret;644}645 646/* Proc memrw file read handler.647 * This function is called when the 'memrw' file is opened for reading648 * This function can be used to read from a memory location.649 */650static ssize_t651mwifiex_memrw_read(struct file *file, char __user *ubuf,652		   size_t count, loff_t *ppos)653{654	struct mwifiex_private *priv = (void *)file->private_data;655	unsigned long addr = get_zeroed_page(GFP_KERNEL);656	char *buf = (char *)addr;657	int ret, pos = 0;658 659	if (!buf)660		return -ENOMEM;661 662	pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr,663			priv->mem_rw.value);664	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);665 666	free_page(addr);667	return ret;668}669 670static u32 saved_offset = -1, saved_bytes = -1;671 672/*673 * Proc rdeeprom file write handler.674 *675 * This function is called when the 'rdeeprom' file is opened for writing676 *677 * This function can be used to write to a RDEEPROM location.678 */679static ssize_t680mwifiex_rdeeprom_write(struct file *file,681		       const char __user *ubuf, size_t count, loff_t *ppos)682{683	char *buf;684	int ret = 0;685	int offset = -1, bytes = -1;686 687	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));688	if (IS_ERR(buf))689		return PTR_ERR(buf);690 691	if (sscanf(buf, "%d %d", &offset, &bytes) != 2) {692		ret = -EINVAL;693		goto done;694	}695 696	if (offset == -1 || bytes == -1) {697		ret = -EINVAL;698		goto done;699	} else {700		saved_offset = offset;701		saved_bytes = bytes;702		ret = count;703	}704done:705	kfree(buf);706	return ret;707}708 709/*710 * Proc rdeeprom read write handler.711 *712 * This function is called when the 'rdeeprom' file is opened for reading713 *714 * This function can be used to read from a RDEEPROM location.715 */716static ssize_t717mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,718		      size_t count, loff_t *ppos)719{720	struct mwifiex_private *priv =721		(struct mwifiex_private *) file->private_data;722	unsigned long addr = get_zeroed_page(GFP_KERNEL);723	char *buf = (char *) addr;724	int pos, ret, i;725	u8 value[MAX_EEPROM_DATA];726 727	if (!buf)728		return -ENOMEM;729 730	if (saved_offset == -1) {731		/* No command has been given */732		pos = snprintf(buf, PAGE_SIZE, "0");733		goto done;734	}735 736	/* Get command has been given */737	ret = mwifiex_eeprom_read(priv, (u16) saved_offset,738				  (u16) saved_bytes, value);739	if (ret) {740		ret = -EINVAL;741		goto out_free;742	}743 744	pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);745 746	for (i = 0; i < saved_bytes; i++)747		pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]);748 749done:750	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);751out_free:752	free_page(addr);753	return ret;754}755 756/* Proc hscfg file write handler757 * This function can be used to configure the host sleep parameters.758 */759static ssize_t760mwifiex_hscfg_write(struct file *file, const char __user *ubuf,761		    size_t count, loff_t *ppos)762{763	struct mwifiex_private *priv = (void *)file->private_data;764	char *buf;765	int ret, arg_num;766	struct mwifiex_ds_hs_cfg hscfg;767	int conditions = HS_CFG_COND_DEF;768	u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF;769 770	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));771	if (IS_ERR(buf))772		return PTR_ERR(buf);773 774	arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap);775 776	memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));777 778	if (arg_num > 3) {779		mwifiex_dbg(priv->adapter, ERROR,780			    "Too many arguments\n");781		ret = -EINVAL;782		goto done;783	}784 785	if (arg_num >= 1 && arg_num < 3)786		mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,787				      MWIFIEX_SYNC_CMD, &hscfg);788 789	if (arg_num) {790		if (conditions == HS_CFG_CANCEL) {791			mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD);792			ret = count;793			goto done;794		}795		hscfg.conditions = conditions;796	}797	if (arg_num >= 2)798		hscfg.gpio = gpio;799	if (arg_num == 3)800		hscfg.gap = gap;801 802	hscfg.is_invoke_hostcmd = false;803	mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,804			      MWIFIEX_SYNC_CMD, &hscfg);805 806	mwifiex_enable_hs(priv->adapter);807	clear_bit(MWIFIEX_IS_HS_ENABLING, &priv->adapter->work_flags);808	ret = count;809done:810	kfree(buf);811	return ret;812}813 814/* Proc hscfg file read handler815 * This function can be used to read host sleep configuration816 * parameters from driver.817 */818static ssize_t819mwifiex_hscfg_read(struct file *file, char __user *ubuf,820		   size_t count, loff_t *ppos)821{822	struct mwifiex_private *priv = (void *)file->private_data;823	unsigned long addr = get_zeroed_page(GFP_KERNEL);824	char *buf = (char *)addr;825	int pos, ret;826	struct mwifiex_ds_hs_cfg hscfg;827 828	if (!buf)829		return -ENOMEM;830 831	mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,832			      MWIFIEX_SYNC_CMD, &hscfg);833 834	pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions,835		       hscfg.gpio, hscfg.gap);836 837	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);838 839	free_page(addr);840	return ret;841}842 843static ssize_t844mwifiex_timeshare_coex_read(struct file *file, char __user *ubuf,845			    size_t count, loff_t *ppos)846{847	struct mwifiex_private *priv = file->private_data;848	char buf[3];849	bool timeshare_coex;850	int ret;851	unsigned int len;852 853	if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)854		return -EOPNOTSUPP;855 856	ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,857			       HostCmd_ACT_GEN_GET, 0, &timeshare_coex, true);858	if (ret)859		return ret;860 861	len = sprintf(buf, "%d\n", timeshare_coex);862	return simple_read_from_buffer(ubuf, count, ppos, buf, len);863}864 865static ssize_t866mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf,867			     size_t count, loff_t *ppos)868{869	bool timeshare_coex;870	struct mwifiex_private *priv = file->private_data;871	int ret;872 873	if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)874		return -EOPNOTSUPP;875 876	ret = kstrtobool_from_user(ubuf, count, &timeshare_coex);877	if (ret)878		return ret;879 880	ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,881			       HostCmd_ACT_GEN_SET, 0, &timeshare_coex, true);882	if (ret)883		return ret;884	else885		return count;886}887 888static ssize_t889mwifiex_reset_write(struct file *file,890		    const char __user *ubuf, size_t count, loff_t *ppos)891{892	struct mwifiex_private *priv = file->private_data;893	struct mwifiex_adapter *adapter = priv->adapter;894	bool result;895	int rc;896 897	rc = kstrtobool_from_user(ubuf, count, &result);898	if (rc)899		return rc;900 901	if (!result)902		return -EINVAL;903 904	if (adapter->if_ops.card_reset) {905		dev_info(adapter->dev, "Resetting per request\n");906		adapter->if_ops.card_reset(adapter);907	}908 909	return count;910}911 912#define MWIFIEX_DFS_ADD_FILE(name) do {                                 \913	debugfs_create_file(#name, 0644, priv->dfs_dev_dir, priv,       \914			    &mwifiex_dfs_##name##_fops);                \915} while (0);916 917#define MWIFIEX_DFS_FILE_OPS(name)                                      \918static const struct file_operations mwifiex_dfs_##name##_fops = {       \919	.read = mwifiex_##name##_read,                                  \920	.write = mwifiex_##name##_write,                                \921	.open = simple_open,                                            \922};923 924#define MWIFIEX_DFS_FILE_READ_OPS(name)                                 \925static const struct file_operations mwifiex_dfs_##name##_fops = {       \926	.read = mwifiex_##name##_read,                                  \927	.open = simple_open,                                            \928};929 930#define MWIFIEX_DFS_FILE_WRITE_OPS(name)                                \931static const struct file_operations mwifiex_dfs_##name##_fops = {       \932	.write = mwifiex_##name##_write,                                \933	.open = simple_open,                                            \934};935 936 937MWIFIEX_DFS_FILE_READ_OPS(info);938MWIFIEX_DFS_FILE_READ_OPS(debug);939MWIFIEX_DFS_FILE_READ_OPS(getlog);940MWIFIEX_DFS_FILE_OPS(regrdwr);941MWIFIEX_DFS_FILE_OPS(rdeeprom);942MWIFIEX_DFS_FILE_OPS(memrw);943MWIFIEX_DFS_FILE_OPS(hscfg);944MWIFIEX_DFS_FILE_OPS(histogram);945MWIFIEX_DFS_FILE_OPS(debug_mask);946MWIFIEX_DFS_FILE_OPS(timeshare_coex);947MWIFIEX_DFS_FILE_WRITE_OPS(reset);948MWIFIEX_DFS_FILE_OPS(verext);949 950/*951 * This function creates the debug FS directory structure and the files.952 */953void954mwifiex_dev_debugfs_init(struct mwifiex_private *priv)955{956	if (!mwifiex_dfs_dir || !priv)957		return;958 959	priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,960					       mwifiex_dfs_dir);961 962	MWIFIEX_DFS_ADD_FILE(info);963	MWIFIEX_DFS_ADD_FILE(debug);964	MWIFIEX_DFS_ADD_FILE(getlog);965	MWIFIEX_DFS_ADD_FILE(regrdwr);966	MWIFIEX_DFS_ADD_FILE(rdeeprom);967 968	MWIFIEX_DFS_ADD_FILE(memrw);969	MWIFIEX_DFS_ADD_FILE(hscfg);970	MWIFIEX_DFS_ADD_FILE(histogram);971	MWIFIEX_DFS_ADD_FILE(debug_mask);972	MWIFIEX_DFS_ADD_FILE(timeshare_coex);973	MWIFIEX_DFS_ADD_FILE(reset);974	MWIFIEX_DFS_ADD_FILE(verext);975}976 977/*978 * This function removes the debug FS directory structure and the files.979 */980void981mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)982{983	if (!priv)984		return;985 986	debugfs_remove_recursive(priv->dfs_dev_dir);987}988 989/*990 * This function creates the top level proc directory.991 */992void993mwifiex_debugfs_init(void)994{995	if (!mwifiex_dfs_dir)996		mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);997}998 999/*1000 * This function removes the top level proc directory.1001 */1002void1003mwifiex_debugfs_remove(void)1004{1005	debugfs_remove(mwifiex_dfs_dir);1006}1007