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