1 /*
2  * Marvell Wireless LAN device driver: debugfs
3  *
4  * Copyright (C) 2011-2014, Marvell International Ltd.
5  *
6  * This software file (the "File") is distributed by Marvell International
7  * Ltd. 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 
26 static struct dentry *mwifiex_dfs_dir;
27 
28 static 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  */
73 static ssize_t
74 mwifiex_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 
151 free_and_exit:
152 	free_page(page);
153 	return ret;
154 }
155 
156 /*
157  * Proc device dump read handler.
158  *
159  * This function is called when the 'device_dump' file is opened for
160  * reading.
161  * This function dumps driver information and firmware memory segments
162  * (ex. DTCM, ITCM, SQRAM etc.) for
163  * debugging.
164  */
165 static ssize_t
166 mwifiex_device_dump_read(struct file *file, char __user *ubuf,
167 			 size_t count, loff_t *ppos)
168 {
169 	struct mwifiex_private *priv = file->private_data;
170 
171 	if (!priv->adapter->if_ops.device_dump)
172 		return -EIO;
173 
174 	priv->adapter->if_ops.device_dump(priv->adapter);
175 
176 	return 0;
177 }
178 
179 /*
180  * Proc getlog file read handler.
181  *
182  * This function is called when the 'getlog' file is opened for reading
183  * It prints the following log information -
184  *      - Number of multicast Tx frames
185  *      - Number of failed packets
186  *      - Number of Tx retries
187  *      - Number of multicast Tx retries
188  *      - Number of duplicate frames
189  *      - Number of RTS successes
190  *      - Number of RTS failures
191  *      - Number of ACK failures
192  *      - Number of fragmented Rx frames
193  *      - Number of multicast Rx frames
194  *      - Number of FCS errors
195  *      - Number of Tx frames
196  *      - WEP ICV error counts
197  *      - Number of received beacons
198  *      - Number of missed beacons
199  */
200 static ssize_t
201 mwifiex_getlog_read(struct file *file, char __user *ubuf,
202 		    size_t count, loff_t *ppos)
203 {
204 	struct mwifiex_private *priv =
205 		(struct mwifiex_private *) file->private_data;
206 	unsigned long page = get_zeroed_page(GFP_KERNEL);
207 	char *p = (char *) page;
208 	ssize_t ret;
209 	struct mwifiex_ds_get_stats stats;
210 
211 	if (!p)
212 		return -ENOMEM;
213 
214 	memset(&stats, 0, sizeof(stats));
215 	ret = mwifiex_get_stats_info(priv, &stats);
216 	if (ret)
217 		goto free_and_exit;
218 
219 	p += sprintf(p, "\n"
220 		     "mcasttxframe     %u\n"
221 		     "failed           %u\n"
222 		     "retry            %u\n"
223 		     "multiretry       %u\n"
224 		     "framedup         %u\n"
225 		     "rtssuccess       %u\n"
226 		     "rtsfailure       %u\n"
227 		     "ackfailure       %u\n"
228 		     "rxfrag           %u\n"
229 		     "mcastrxframe     %u\n"
230 		     "fcserror         %u\n"
231 		     "txframe          %u\n"
232 		     "wepicverrcnt-1   %u\n"
233 		     "wepicverrcnt-2   %u\n"
234 		     "wepicverrcnt-3   %u\n"
235 		     "wepicverrcnt-4   %u\n"
236 		     "bcn_rcv_cnt   %u\n"
237 		     "bcn_miss_cnt   %u\n",
238 		     stats.mcast_tx_frame,
239 		     stats.failed,
240 		     stats.retry,
241 		     stats.multi_retry,
242 		     stats.frame_dup,
243 		     stats.rts_success,
244 		     stats.rts_failure,
245 		     stats.ack_failure,
246 		     stats.rx_frag,
247 		     stats.mcast_rx_frame,
248 		     stats.fcs_error,
249 		     stats.tx_frame,
250 		     stats.wep_icv_error[0],
251 		     stats.wep_icv_error[1],
252 		     stats.wep_icv_error[2],
253 		     stats.wep_icv_error[3],
254 		     stats.bcn_rcv_cnt,
255 		     stats.bcn_miss_cnt);
256 
257 
258 	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
259 				      (unsigned long) p - page);
260 
261 free_and_exit:
262 	free_page(page);
263 	return ret;
264 }
265 
266 /* Sysfs histogram file read handler.
267  *
268  * This function is called when the 'histogram' file is opened for reading
269  * It prints the following histogram information -
270  *      - Number of histogram samples
271  *      - Receive packet number of each rx_rate
272  *      - Receive packet number of each snr
273  *      - Receive packet number of each nosie_flr
274  *      - Receive packet number of each signal streath
275  */
276 static ssize_t
277 mwifiex_histogram_read(struct file *file, char __user *ubuf,
278 		       size_t count, loff_t *ppos)
279 {
280 	struct mwifiex_private *priv =
281 		(struct mwifiex_private *)file->private_data;
282 	ssize_t ret;
283 	struct mwifiex_histogram_data *phist_data;
284 	int i, value;
285 	unsigned long page = get_zeroed_page(GFP_KERNEL);
286 	char *p = (char *)page;
287 
288 	if (!p)
289 		return -ENOMEM;
290 
291 	if (!priv || !priv->hist_data)
292 		return -EFAULT;
293 	phist_data = priv->hist_data;
294 
295 	p += sprintf(p, "\n"
296 		     "total samples = %d\n",
297 		     atomic_read(&phist_data->num_samples));
298 
299 	p += sprintf(p, "rx rates (in Mbps): 0=1M   1=2M");
300 	p += sprintf(p, "2=5.5M  3=11M   4=6M   5=9M  6=12M\n");
301 	p += sprintf(p, "7=18M  8=24M  9=36M  10=48M  11=54M");
302 	p += sprintf(p, "12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n");
303 
304 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
305 		p += sprintf(p, "44-53=MCS0-9(VHT:BW20)");
306 		p += sprintf(p, "54-63=MCS0-9(VHT:BW40)");
307 		p += sprintf(p, "64-73=MCS0-9(VHT:BW80)\n\n");
308 	} else {
309 		p += sprintf(p, "\n");
310 	}
311 
312 	for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) {
313 		value = atomic_read(&phist_data->rx_rate[i]);
314 		if (value)
315 			p += sprintf(p, "rx_rate[%02d] = %d\n", i, value);
316 	}
317 
318 	if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
319 		for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES;
320 		     i++) {
321 			value = atomic_read(&phist_data->rx_rate[i]);
322 			if (value)
323 				p += sprintf(p, "rx_rate[%02d] = %d\n",
324 					   i, value);
325 		}
326 	}
327 
328 	for (i = 0; i < MWIFIEX_MAX_SNR; i++) {
329 		value =  atomic_read(&phist_data->snr[i]);
330 		if (value)
331 			p += sprintf(p, "snr[%02ddB] = %d\n", i, value);
332 	}
333 	for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) {
334 		value = atomic_read(&phist_data->noise_flr[i]);
335 		if (value)
336 			p += sprintf(p, "noise_flr[-%02ddBm] = %d\n",
337 				(int)(i-128), value);
338 	}
339 	for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) {
340 		value = atomic_read(&phist_data->sig_str[i]);
341 		if (value)
342 			p += sprintf(p, "sig_strength[-%02ddBm] = %d\n",
343 				i, value);
344 	}
345 
346 	ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
347 				      (unsigned long)p - page);
348 
349 	return ret;
350 }
351 
352 static ssize_t
353 mwifiex_histogram_write(struct file *file, const char __user *ubuf,
354 			size_t count, loff_t *ppos)
355 {
356 	struct mwifiex_private *priv = (void *)file->private_data;
357 
358 	if (priv && priv->hist_data)
359 		mwifiex_hist_data_reset(priv);
360 	return 0;
361 }
362 
363 static struct mwifiex_debug_info info;
364 
365 /*
366  * Proc debug file read handler.
367  *
368  * This function is called when the 'debug' file is opened for reading
369  * It prints the following log information -
370  *      - Interrupt count
371  *      - WMM AC VO packets count
372  *      - WMM AC VI packets count
373  *      - WMM AC BE packets count
374  *      - WMM AC BK packets count
375  *      - Maximum Tx buffer size
376  *      - Tx buffer size
377  *      - Current Tx buffer size
378  *      - Power Save mode
379  *      - Power Save state
380  *      - Deep Sleep status
381  *      - Device wakeup required status
382  *      - Number of wakeup tries
383  *      - Host Sleep configured status
384  *      - Host Sleep activated status
385  *      - Number of Tx timeouts
386  *      - Number of command timeouts
387  *      - Last timed out command ID
388  *      - Last timed out command action
389  *      - Last command ID
390  *      - Last command action
391  *      - Last command index
392  *      - Last command response ID
393  *      - Last command response index
394  *      - Last event
395  *      - Last event index
396  *      - Number of host to card command failures
397  *      - Number of sleep confirm command failures
398  *      - Number of host to card data failure
399  *      - Number of deauthentication events
400  *      - Number of disassociation events
401  *      - Number of link lost events
402  *      - Number of deauthentication commands
403  *      - Number of association success commands
404  *      - Number of association failure commands
405  *      - Number of commands sent
406  *      - Number of data packets sent
407  *      - Number of command responses received
408  *      - Number of events received
409  *      - Tx BA stream table (TID, RA)
410  *      - Rx reorder table (TID, TA, Start window, Window size, Buffer)
411  */
412 static ssize_t
413 mwifiex_debug_read(struct file *file, char __user *ubuf,
414 		   size_t count, loff_t *ppos)
415 {
416 	struct mwifiex_private *priv =
417 		(struct mwifiex_private *) file->private_data;
418 	unsigned long page = get_zeroed_page(GFP_KERNEL);
419 	char *p = (char *) page;
420 	ssize_t ret;
421 
422 	if (!p)
423 		return -ENOMEM;
424 
425 	ret = mwifiex_get_debug_info(priv, &info);
426 	if (ret)
427 		goto free_and_exit;
428 
429 	p += mwifiex_debug_info_to_buffer(priv, p, &info);
430 
431 	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
432 				      (unsigned long) p - page);
433 
434 free_and_exit:
435 	free_page(page);
436 	return ret;
437 }
438 
439 static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
440 
441 /*
442  * Proc regrdwr file write handler.
443  *
444  * This function is called when the 'regrdwr' file is opened for writing
445  *
446  * This function can be used to write to a register.
447  */
448 static ssize_t
449 mwifiex_regrdwr_write(struct file *file,
450 		      const char __user *ubuf, size_t count, loff_t *ppos)
451 {
452 	char *buf;
453 	int ret;
454 	u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
455 
456 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
457 	if (IS_ERR(buf))
458 		return PTR_ERR(buf);
459 
460 	sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
461 
462 	if (reg_type == 0 || reg_offset == 0) {
463 		ret = -EINVAL;
464 		goto done;
465 	} else {
466 		saved_reg_type = reg_type;
467 		saved_reg_offset = reg_offset;
468 		saved_reg_value = reg_value;
469 		ret = count;
470 	}
471 done:
472 	kfree(buf);
473 	return ret;
474 }
475 
476 /*
477  * Proc regrdwr file read handler.
478  *
479  * This function is called when the 'regrdwr' file is opened for reading
480  *
481  * This function can be used to read from a register.
482  */
483 static ssize_t
484 mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
485 		     size_t count, loff_t *ppos)
486 {
487 	struct mwifiex_private *priv =
488 		(struct mwifiex_private *) file->private_data;
489 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
490 	char *buf = (char *) addr;
491 	int pos = 0, ret = 0;
492 	u32 reg_value;
493 
494 	if (!buf)
495 		return -ENOMEM;
496 
497 	if (!saved_reg_type) {
498 		/* No command has been given */
499 		pos += snprintf(buf, PAGE_SIZE, "0");
500 		goto done;
501 	}
502 	/* Set command has been given */
503 	if (saved_reg_value != UINT_MAX) {
504 		ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
505 					saved_reg_value);
506 
507 		pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
508 				saved_reg_type, saved_reg_offset,
509 				saved_reg_value);
510 
511 		ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
512 
513 		goto done;
514 	}
515 	/* Get command has been given */
516 	ret = mwifiex_reg_read(priv, saved_reg_type,
517 			       saved_reg_offset, &reg_value);
518 	if (ret) {
519 		ret = -EINVAL;
520 		goto done;
521 	}
522 
523 	pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
524 			saved_reg_offset, reg_value);
525 
526 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
527 
528 done:
529 	free_page(addr);
530 	return ret;
531 }
532 
533 /* Proc debug_mask file read handler.
534  * This function is called when the 'debug_mask' file is opened for reading
535  * This function can be used read driver debugging mask value.
536  */
537 static ssize_t
538 mwifiex_debug_mask_read(struct file *file, char __user *ubuf,
539 			size_t count, loff_t *ppos)
540 {
541 	struct mwifiex_private *priv =
542 		(struct mwifiex_private *)file->private_data;
543 	unsigned long page = get_zeroed_page(GFP_KERNEL);
544 	char *buf = (char *)page;
545 	size_t ret = 0;
546 	int pos = 0;
547 
548 	if (!buf)
549 		return -ENOMEM;
550 
551 	pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n",
552 			priv->adapter->debug_mask);
553 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
554 
555 	free_page(page);
556 	return ret;
557 }
558 
559 /* Proc debug_mask file read handler.
560  * This function is called when the 'debug_mask' file is opened for reading
561  * This function can be used read driver debugging mask value.
562  */
563 static ssize_t
564 mwifiex_debug_mask_write(struct file *file, const char __user *ubuf,
565 			 size_t count, loff_t *ppos)
566 {
567 	int ret;
568 	unsigned long debug_mask;
569 	struct mwifiex_private *priv = (void *)file->private_data;
570 	char *buf;
571 
572 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
573 	if (IS_ERR(buf))
574 		return PTR_ERR(buf);
575 
576 	if (kstrtoul(buf, 0, &debug_mask)) {
577 		ret = -EINVAL;
578 		goto done;
579 	}
580 
581 	priv->adapter->debug_mask = debug_mask;
582 	ret = count;
583 done:
584 	kfree(buf);
585 	return ret;
586 }
587 
588 /* debugfs verext file write handler.
589  * This function is called when the 'verext' file is opened for write
590  */
591 static ssize_t
592 mwifiex_verext_write(struct file *file, const char __user *ubuf,
593 		     size_t count, loff_t *ppos)
594 {
595 	int ret;
596 	u32 versionstrsel;
597 	struct mwifiex_private *priv = (void *)file->private_data;
598 	char buf[16];
599 
600 	memset(buf, 0, sizeof(buf));
601 
602 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
603 		return -EFAULT;
604 
605 	ret = kstrtou32(buf, 10, &versionstrsel);
606 	if (ret)
607 		return ret;
608 
609 	priv->versionstrsel = versionstrsel;
610 
611 	return count;
612 }
613 
614 /* Proc verext file read handler.
615  * This function is called when the 'verext' file is opened for reading
616  * This function can be used read driver exteneed verion string.
617  */
618 static ssize_t
619 mwifiex_verext_read(struct file *file, char __user *ubuf,
620 		    size_t count, loff_t *ppos)
621 {
622 	struct mwifiex_private *priv =
623 		(struct mwifiex_private *)file->private_data;
624 	char buf[256];
625 	int ret;
626 
627 	mwifiex_get_ver_ext(priv, priv->versionstrsel);
628 	ret = snprintf(buf, sizeof(buf), "version string: %s\n",
629 		       priv->version_str);
630 
631 	return simple_read_from_buffer(ubuf, count, ppos, buf, ret);
632 }
633 
634 /* Proc memrw file write handler.
635  * This function is called when the 'memrw' file is opened for writing
636  * This function can be used to write to a memory location.
637  */
638 static ssize_t
639 mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,
640 		    loff_t *ppos)
641 {
642 	int ret;
643 	char cmd;
644 	struct mwifiex_ds_mem_rw mem_rw;
645 	u16 cmd_action;
646 	struct mwifiex_private *priv = (void *)file->private_data;
647 	char *buf;
648 
649 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
650 	if (IS_ERR(buf))
651 		return PTR_ERR(buf);
652 
653 	ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);
654 	if (ret != 3) {
655 		ret = -EINVAL;
656 		goto done;
657 	}
658 
659 	if ((cmd == 'r') || (cmd == 'R')) {
660 		cmd_action = HostCmd_ACT_GEN_GET;
661 		mem_rw.value = 0;
662 	} else if ((cmd == 'w') || (cmd == 'W')) {
663 		cmd_action = HostCmd_ACT_GEN_SET;
664 	} else {
665 		ret = -EINVAL;
666 		goto done;
667 	}
668 
669 	memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw));
670 	if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,
671 			     &mem_rw, true))
672 		ret = -1;
673 	else
674 		ret = count;
675 
676 done:
677 	kfree(buf);
678 	return ret;
679 }
680 
681 /* Proc memrw file read handler.
682  * This function is called when the 'memrw' file is opened for reading
683  * This function can be used to read from a memory location.
684  */
685 static ssize_t
686 mwifiex_memrw_read(struct file *file, char __user *ubuf,
687 		   size_t count, loff_t *ppos)
688 {
689 	struct mwifiex_private *priv = (void *)file->private_data;
690 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
691 	char *buf = (char *)addr;
692 	int ret, pos = 0;
693 
694 	if (!buf)
695 		return -ENOMEM;
696 
697 	pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr,
698 			priv->mem_rw.value);
699 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
700 
701 	free_page(addr);
702 	return ret;
703 }
704 
705 static u32 saved_offset = -1, saved_bytes = -1;
706 
707 /*
708  * Proc rdeeprom file write handler.
709  *
710  * This function is called when the 'rdeeprom' file is opened for writing
711  *
712  * This function can be used to write to a RDEEPROM location.
713  */
714 static ssize_t
715 mwifiex_rdeeprom_write(struct file *file,
716 		       const char __user *ubuf, size_t count, loff_t *ppos)
717 {
718 	char *buf;
719 	int ret = 0;
720 	int offset = -1, bytes = -1;
721 
722 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
723 	if (IS_ERR(buf))
724 		return PTR_ERR(buf);
725 
726 	sscanf(buf, "%d %d", &offset, &bytes);
727 
728 	if (offset == -1 || bytes == -1) {
729 		ret = -EINVAL;
730 		goto done;
731 	} else {
732 		saved_offset = offset;
733 		saved_bytes = bytes;
734 		ret = count;
735 	}
736 done:
737 	kfree(buf);
738 	return ret;
739 }
740 
741 /*
742  * Proc rdeeprom read write handler.
743  *
744  * This function is called when the 'rdeeprom' file is opened for reading
745  *
746  * This function can be used to read from a RDEEPROM location.
747  */
748 static ssize_t
749 mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
750 		      size_t count, loff_t *ppos)
751 {
752 	struct mwifiex_private *priv =
753 		(struct mwifiex_private *) file->private_data;
754 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
755 	char *buf = (char *) addr;
756 	int pos, ret, i;
757 	u8 value[MAX_EEPROM_DATA];
758 
759 	if (!buf)
760 		return -ENOMEM;
761 
762 	if (saved_offset == -1) {
763 		/* No command has been given */
764 		pos = snprintf(buf, PAGE_SIZE, "0");
765 		goto done;
766 	}
767 
768 	/* Get command has been given */
769 	ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
770 				  (u16) saved_bytes, value);
771 	if (ret) {
772 		ret = -EINVAL;
773 		goto out_free;
774 	}
775 
776 	pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
777 
778 	for (i = 0; i < saved_bytes; i++)
779 		pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]);
780 
781 done:
782 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
783 out_free:
784 	free_page(addr);
785 	return ret;
786 }
787 
788 /* Proc hscfg file write handler
789  * This function can be used to configure the host sleep parameters.
790  */
791 static ssize_t
792 mwifiex_hscfg_write(struct file *file, const char __user *ubuf,
793 		    size_t count, loff_t *ppos)
794 {
795 	struct mwifiex_private *priv = (void *)file->private_data;
796 	char *buf;
797 	int ret, arg_num;
798 	struct mwifiex_ds_hs_cfg hscfg;
799 	int conditions = HS_CFG_COND_DEF;
800 	u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF;
801 
802 	buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
803 	if (IS_ERR(buf))
804 		return PTR_ERR(buf);
805 
806 	arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap);
807 
808 	memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));
809 
810 	if (arg_num > 3) {
811 		mwifiex_dbg(priv->adapter, ERROR,
812 			    "Too many arguments\n");
813 		ret = -EINVAL;
814 		goto done;
815 	}
816 
817 	if (arg_num >= 1 && arg_num < 3)
818 		mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
819 				      MWIFIEX_SYNC_CMD, &hscfg);
820 
821 	if (arg_num) {
822 		if (conditions == HS_CFG_CANCEL) {
823 			mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD);
824 			ret = count;
825 			goto done;
826 		}
827 		hscfg.conditions = conditions;
828 	}
829 	if (arg_num >= 2)
830 		hscfg.gpio = gpio;
831 	if (arg_num == 3)
832 		hscfg.gap = gap;
833 
834 	hscfg.is_invoke_hostcmd = false;
835 	mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
836 			      MWIFIEX_SYNC_CMD, &hscfg);
837 
838 	mwifiex_enable_hs(priv->adapter);
839 	priv->adapter->hs_enabling = false;
840 	ret = count;
841 done:
842 	kfree(buf);
843 	return ret;
844 }
845 
846 /* Proc hscfg file read handler
847  * This function can be used to read host sleep configuration
848  * parameters from driver.
849  */
850 static ssize_t
851 mwifiex_hscfg_read(struct file *file, char __user *ubuf,
852 		   size_t count, loff_t *ppos)
853 {
854 	struct mwifiex_private *priv = (void *)file->private_data;
855 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
856 	char *buf = (char *)addr;
857 	int pos, ret;
858 	struct mwifiex_ds_hs_cfg hscfg;
859 
860 	if (!buf)
861 		return -ENOMEM;
862 
863 	mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
864 			      MWIFIEX_SYNC_CMD, &hscfg);
865 
866 	pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions,
867 		       hscfg.gpio, hscfg.gap);
868 
869 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
870 
871 	free_page(addr);
872 	return ret;
873 }
874 
875 static ssize_t
876 mwifiex_timeshare_coex_read(struct file *file, char __user *ubuf,
877 			    size_t count, loff_t *ppos)
878 {
879 	struct mwifiex_private *priv = file->private_data;
880 	char buf[3];
881 	bool timeshare_coex;
882 	int ret;
883 	unsigned int len;
884 
885 	if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)
886 		return -EOPNOTSUPP;
887 
888 	ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,
889 			       HostCmd_ACT_GEN_GET, 0, &timeshare_coex, true);
890 	if (ret)
891 		return ret;
892 
893 	len = sprintf(buf, "%d\n", timeshare_coex);
894 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
895 }
896 
897 static ssize_t
898 mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf,
899 			     size_t count, loff_t *ppos)
900 {
901 	bool timeshare_coex;
902 	struct mwifiex_private *priv = file->private_data;
903 	char kbuf[16];
904 	int ret;
905 
906 	if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)
907 		return -EOPNOTSUPP;
908 
909 	memset(kbuf, 0, sizeof(kbuf));
910 
911 	if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count)))
912 		return -EFAULT;
913 
914 	if (strtobool(kbuf, &timeshare_coex))
915 		return -EINVAL;
916 
917 	ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,
918 			       HostCmd_ACT_GEN_SET, 0, &timeshare_coex, true);
919 	if (ret)
920 		return ret;
921 	else
922 		return count;
923 }
924 
925 static ssize_t
926 mwifiex_reset_write(struct file *file,
927 		    const char __user *ubuf, size_t count, loff_t *ppos)
928 {
929 	struct mwifiex_private *priv = file->private_data;
930 	struct mwifiex_adapter *adapter = priv->adapter;
931 	bool result;
932 	int rc;
933 
934 	rc = kstrtobool_from_user(ubuf, count, &result);
935 	if (rc)
936 		return rc;
937 
938 	if (!result)
939 		return -EINVAL;
940 
941 	if (adapter->if_ops.card_reset) {
942 		dev_info(adapter->dev, "Resetting per request\n");
943 		adapter->if_ops.card_reset(adapter);
944 	}
945 
946 	return count;
947 }
948 
949 #define MWIFIEX_DFS_ADD_FILE(name) do {                                 \
950 	if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir,        \
951 			priv, &mwifiex_dfs_##name##_fops))              \
952 		return;                                                 \
953 } while (0);
954 
955 #define MWIFIEX_DFS_FILE_OPS(name)                                      \
956 static const struct file_operations mwifiex_dfs_##name##_fops = {       \
957 	.read = mwifiex_##name##_read,                                  \
958 	.write = mwifiex_##name##_write,                                \
959 	.open = simple_open,                                            \
960 };
961 
962 #define MWIFIEX_DFS_FILE_READ_OPS(name)                                 \
963 static const struct file_operations mwifiex_dfs_##name##_fops = {       \
964 	.read = mwifiex_##name##_read,                                  \
965 	.open = simple_open,                                            \
966 };
967 
968 #define MWIFIEX_DFS_FILE_WRITE_OPS(name)                                \
969 static const struct file_operations mwifiex_dfs_##name##_fops = {       \
970 	.write = mwifiex_##name##_write,                                \
971 	.open = simple_open,                                            \
972 };
973 
974 
975 MWIFIEX_DFS_FILE_READ_OPS(info);
976 MWIFIEX_DFS_FILE_READ_OPS(debug);
977 MWIFIEX_DFS_FILE_READ_OPS(getlog);
978 MWIFIEX_DFS_FILE_READ_OPS(device_dump);
979 MWIFIEX_DFS_FILE_OPS(regrdwr);
980 MWIFIEX_DFS_FILE_OPS(rdeeprom);
981 MWIFIEX_DFS_FILE_OPS(memrw);
982 MWIFIEX_DFS_FILE_OPS(hscfg);
983 MWIFIEX_DFS_FILE_OPS(histogram);
984 MWIFIEX_DFS_FILE_OPS(debug_mask);
985 MWIFIEX_DFS_FILE_OPS(timeshare_coex);
986 MWIFIEX_DFS_FILE_WRITE_OPS(reset);
987 MWIFIEX_DFS_FILE_OPS(verext);
988 
989 /*
990  * This function creates the debug FS directory structure and the files.
991  */
992 void
993 mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
994 {
995 	if (!mwifiex_dfs_dir || !priv)
996 		return;
997 
998 	priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
999 					       mwifiex_dfs_dir);
1000 
1001 	if (!priv->dfs_dev_dir)
1002 		return;
1003 
1004 	MWIFIEX_DFS_ADD_FILE(info);
1005 	MWIFIEX_DFS_ADD_FILE(debug);
1006 	MWIFIEX_DFS_ADD_FILE(getlog);
1007 	MWIFIEX_DFS_ADD_FILE(regrdwr);
1008 	MWIFIEX_DFS_ADD_FILE(rdeeprom);
1009 	MWIFIEX_DFS_ADD_FILE(device_dump);
1010 	MWIFIEX_DFS_ADD_FILE(memrw);
1011 	MWIFIEX_DFS_ADD_FILE(hscfg);
1012 	MWIFIEX_DFS_ADD_FILE(histogram);
1013 	MWIFIEX_DFS_ADD_FILE(debug_mask);
1014 	MWIFIEX_DFS_ADD_FILE(timeshare_coex);
1015 	MWIFIEX_DFS_ADD_FILE(reset);
1016 	MWIFIEX_DFS_ADD_FILE(verext);
1017 }
1018 
1019 /*
1020  * This function removes the debug FS directory structure and the files.
1021  */
1022 void
1023 mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
1024 {
1025 	if (!priv)
1026 		return;
1027 
1028 	debugfs_remove_recursive(priv->dfs_dev_dir);
1029 }
1030 
1031 /*
1032  * This function creates the top level proc directory.
1033  */
1034 void
1035 mwifiex_debugfs_init(void)
1036 {
1037 	if (!mwifiex_dfs_dir)
1038 		mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
1039 }
1040 
1041 /*
1042  * This function removes the top level proc directory.
1043  */
1044 void
1045 mwifiex_debugfs_remove(void)
1046 {
1047 	debugfs_remove(mwifiex_dfs_dir);
1048 }
1049