Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * Marvell Wireless LAN device driver: debugfs
  3 *
  4 * Copyright (C) 2011, 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
 26static struct dentry *mwifiex_dfs_dir;
 27
 28static char *bss_modes[] = {
 29	"UNSPECIFIED",
 30	"ADHOC",
 31	"STATION",
 32	"AP",
 33	"AP_VLAN",
 34	"WDS",
 35	"MONITOR",
 36	"MESH_POINT",
 37	"P2P_CLIENT",
 38	"P2P_GO",
 39	"P2P_DEVICE",
 40};
 41
 42/* size/addr for mwifiex_debug_info */
 43#define item_size(n)		(FIELD_SIZEOF(struct mwifiex_debug_info, n))
 44#define item_addr(n)		(offsetof(struct mwifiex_debug_info, n))
 45
 46/* size/addr for struct mwifiex_adapter */
 47#define adapter_item_size(n)	(FIELD_SIZEOF(struct mwifiex_adapter, n))
 48#define adapter_item_addr(n)	(offsetof(struct mwifiex_adapter, n))
 49
 50struct mwifiex_debug_data {
 51	char name[32];		/* variable/array name */
 52	u32 size;		/* size of the variable/array */
 53	size_t addr;		/* address of the variable/array */
 54	int num;		/* number of variables in an array */
 55};
 56
 57static struct mwifiex_debug_data items[] = {
 58	{"int_counter", item_size(int_counter),
 59	 item_addr(int_counter), 1},
 60	{"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
 61	 item_addr(packets_out[WMM_AC_VO]), 1},
 62	{"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
 63	 item_addr(packets_out[WMM_AC_VI]), 1},
 64	{"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
 65	 item_addr(packets_out[WMM_AC_BE]), 1},
 66	{"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
 67	 item_addr(packets_out[WMM_AC_BK]), 1},
 68	{"tx_buf_size", item_size(tx_buf_size),
 69	 item_addr(tx_buf_size), 1},
 70	{"curr_tx_buf_size", item_size(curr_tx_buf_size),
 71	 item_addr(curr_tx_buf_size), 1},
 72	{"ps_mode", item_size(ps_mode),
 73	 item_addr(ps_mode), 1},
 74	{"ps_state", item_size(ps_state),
 75	 item_addr(ps_state), 1},
 76	{"is_deep_sleep", item_size(is_deep_sleep),
 77	 item_addr(is_deep_sleep), 1},
 78	{"wakeup_dev_req", item_size(pm_wakeup_card_req),
 79	 item_addr(pm_wakeup_card_req), 1},
 80	{"wakeup_tries", item_size(pm_wakeup_fw_try),
 81	 item_addr(pm_wakeup_fw_try), 1},
 82	{"hs_configured", item_size(is_hs_configured),
 83	 item_addr(is_hs_configured), 1},
 84	{"hs_activated", item_size(hs_activated),
 85	 item_addr(hs_activated), 1},
 86	{"num_tx_timeout", item_size(num_tx_timeout),
 87	 item_addr(num_tx_timeout), 1},
 88	{"is_cmd_timedout", item_size(is_cmd_timedout),
 89	 item_addr(is_cmd_timedout), 1},
 90	{"timeout_cmd_id", item_size(timeout_cmd_id),
 91	 item_addr(timeout_cmd_id), 1},
 92	{"timeout_cmd_act", item_size(timeout_cmd_act),
 93	 item_addr(timeout_cmd_act), 1},
 94	{"last_cmd_id", item_size(last_cmd_id),
 95	 item_addr(last_cmd_id), DBG_CMD_NUM},
 96	{"last_cmd_act", item_size(last_cmd_act),
 97	 item_addr(last_cmd_act), DBG_CMD_NUM},
 98	{"last_cmd_index", item_size(last_cmd_index),
 99	 item_addr(last_cmd_index), 1},
100	{"last_cmd_resp_id", item_size(last_cmd_resp_id),
101	 item_addr(last_cmd_resp_id), DBG_CMD_NUM},
102	{"last_cmd_resp_index", item_size(last_cmd_resp_index),
103	 item_addr(last_cmd_resp_index), 1},
104	{"last_event", item_size(last_event),
105	 item_addr(last_event), DBG_CMD_NUM},
106	{"last_event_index", item_size(last_event_index),
107	 item_addr(last_event_index), 1},
108	{"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
109	 item_addr(num_cmd_host_to_card_failure), 1},
110	{"num_cmd_sleep_cfm_fail",
111	 item_size(num_cmd_sleep_cfm_host_to_card_failure),
112	 item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
113	{"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
114	 item_addr(num_tx_host_to_card_failure), 1},
115	{"num_evt_deauth", item_size(num_event_deauth),
116	 item_addr(num_event_deauth), 1},
117	{"num_evt_disassoc", item_size(num_event_disassoc),
118	 item_addr(num_event_disassoc), 1},
119	{"num_evt_link_lost", item_size(num_event_link_lost),
120	 item_addr(num_event_link_lost), 1},
121	{"num_cmd_deauth", item_size(num_cmd_deauth),
122	 item_addr(num_cmd_deauth), 1},
123	{"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
124	 item_addr(num_cmd_assoc_success), 1},
125	{"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
126	 item_addr(num_cmd_assoc_failure), 1},
127	{"cmd_sent", item_size(cmd_sent),
128	 item_addr(cmd_sent), 1},
129	{"data_sent", item_size(data_sent),
130	 item_addr(data_sent), 1},
131	{"cmd_resp_received", item_size(cmd_resp_received),
132	 item_addr(cmd_resp_received), 1},
133	{"event_received", item_size(event_received),
134	 item_addr(event_received), 1},
135
136	/* variables defined in struct mwifiex_adapter */
137	{"cmd_pending", adapter_item_size(cmd_pending),
138	 adapter_item_addr(cmd_pending), 1},
139	{"tx_pending", adapter_item_size(tx_pending),
140	 adapter_item_addr(tx_pending), 1},
141	{"rx_pending", adapter_item_size(rx_pending),
142	 adapter_item_addr(rx_pending), 1},
143};
144
145static int num_of_items = ARRAY_SIZE(items);
146
147/*
148 * Proc info file read handler.
149 *
150 * This function is called when the 'info' file is opened for reading.
151 * It prints the following driver related information -
152 *      - Driver name
153 *      - Driver version
154 *      - Driver extended version
155 *      - Interface name
156 *      - BSS mode
157 *      - Media state (connected or disconnected)
158 *      - MAC address
159 *      - Total number of Tx bytes
160 *      - Total number of Rx bytes
161 *      - Total number of Tx packets
162 *      - Total number of Rx packets
163 *      - Total number of dropped Tx packets
164 *      - Total number of dropped Rx packets
165 *      - Total number of corrupted Tx packets
166 *      - Total number of corrupted Rx packets
167 *      - Carrier status (on or off)
168 *      - Tx queue status (started or stopped)
169 *
170 * For STA mode drivers, it also prints the following extra -
171 *      - ESSID
172 *      - BSSID
173 *      - Channel
174 *      - Region code
175 *      - Multicast count
176 *      - Multicast addresses
177 */
178static ssize_t
179mwifiex_info_read(struct file *file, char __user *ubuf,
180		  size_t count, loff_t *ppos)
181{
182	struct mwifiex_private *priv =
183		(struct mwifiex_private *) file->private_data;
184	struct net_device *netdev = priv->netdev;
185	struct netdev_hw_addr *ha;
186	struct netdev_queue *txq;
187	unsigned long page = get_zeroed_page(GFP_KERNEL);
188	char *p = (char *) page, fmt[64];
189	struct mwifiex_bss_info info;
190	ssize_t ret;
191	int i = 0;
192
193	if (!p)
194		return -ENOMEM;
195
196	memset(&info, 0, sizeof(info));
197	ret = mwifiex_get_bss_info(priv, &info);
198	if (ret)
199		goto free_and_exit;
200
201	mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
202
203	if (!priv->version_str[0])
204		mwifiex_get_ver_ext(priv);
205
206	p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
207	p += sprintf(p, "driver_version = %s", fmt);
208	p += sprintf(p, "\nverext = %s", priv->version_str);
209	p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
210
211	if (info.bss_mode >= ARRAY_SIZE(bss_modes))
212		p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
213	else
214		p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
215
216	p += sprintf(p, "media_state=\"%s\"\n",
217		     (!priv->media_connected ? "Disconnected" : "Connected"));
218	p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
219
220	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
221		p += sprintf(p, "multicast_count=\"%d\"\n",
222			     netdev_mc_count(netdev));
223		p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
224		p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
225		p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
226		p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
227
228		netdev_for_each_mc_addr(ha, netdev)
229			p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",
230					i++, ha->addr);
231	}
232
233	p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
234	p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
235	p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
236	p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
237	p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
238	p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
239	p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
240	p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
241	p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
242					 ? "on" : "off"));
243	p += sprintf(p, "tx queue");
244	for (i = 0; i < netdev->num_tx_queues; i++) {
245		txq = netdev_get_tx_queue(netdev, i);
246		p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ?
247			     "stopped" : "started");
248	}
249	p += sprintf(p, "\n");
250
251	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
252				      (unsigned long) p - page);
253
254free_and_exit:
255	free_page(page);
256	return ret;
257}
258
259/*
260 * Proc getlog file read handler.
261 *
262 * This function is called when the 'getlog' file is opened for reading
263 * It prints the following log information -
264 *      - Number of multicast Tx frames
265 *      - Number of failed packets
266 *      - Number of Tx retries
267 *      - Number of multicast Tx retries
268 *      - Number of duplicate frames
269 *      - Number of RTS successes
270 *      - Number of RTS failures
271 *      - Number of ACK failures
272 *      - Number of fragmented Rx frames
273 *      - Number of multicast Rx frames
274 *      - Number of FCS errors
275 *      - Number of Tx frames
276 *      - WEP ICV error counts
277 */
278static ssize_t
279mwifiex_getlog_read(struct file *file, char __user *ubuf,
280		    size_t count, loff_t *ppos)
281{
282	struct mwifiex_private *priv =
283		(struct mwifiex_private *) file->private_data;
284	unsigned long page = get_zeroed_page(GFP_KERNEL);
285	char *p = (char *) page;
286	ssize_t ret;
287	struct mwifiex_ds_get_stats stats;
288
289	if (!p)
290		return -ENOMEM;
291
292	memset(&stats, 0, sizeof(stats));
293	ret = mwifiex_get_stats_info(priv, &stats);
294	if (ret)
295		goto free_and_exit;
296
297	p += sprintf(p, "\n"
298		     "mcasttxframe     %u\n"
299		     "failed           %u\n"
300		     "retry            %u\n"
301		     "multiretry       %u\n"
302		     "framedup         %u\n"
303		     "rtssuccess       %u\n"
304		     "rtsfailure       %u\n"
305		     "ackfailure       %u\n"
306		     "rxfrag           %u\n"
307		     "mcastrxframe     %u\n"
308		     "fcserror         %u\n"
309		     "txframe          %u\n"
310		     "wepicverrcnt-1   %u\n"
311		     "wepicverrcnt-2   %u\n"
312		     "wepicverrcnt-3   %u\n"
313		     "wepicverrcnt-4   %u\n",
314		     stats.mcast_tx_frame,
315		     stats.failed,
316		     stats.retry,
317		     stats.multi_retry,
318		     stats.frame_dup,
319		     stats.rts_success,
320		     stats.rts_failure,
321		     stats.ack_failure,
322		     stats.rx_frag,
323		     stats.mcast_rx_frame,
324		     stats.fcs_error,
325		     stats.tx_frame,
326		     stats.wep_icv_error[0],
327		     stats.wep_icv_error[1],
328		     stats.wep_icv_error[2],
329		     stats.wep_icv_error[3]);
330
331
332	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
333				      (unsigned long) p - page);
334
335free_and_exit:
336	free_page(page);
337	return ret;
338}
339
340static struct mwifiex_debug_info info;
341
342/*
343 * Proc debug file read handler.
344 *
345 * This function is called when the 'debug' file is opened for reading
346 * It prints the following log information -
347 *      - Interrupt count
348 *      - WMM AC VO packets count
349 *      - WMM AC VI packets count
350 *      - WMM AC BE packets count
351 *      - WMM AC BK packets count
352 *      - Maximum Tx buffer size
353 *      - Tx buffer size
354 *      - Current Tx buffer size
355 *      - Power Save mode
356 *      - Power Save state
357 *      - Deep Sleep status
358 *      - Device wakeup required status
359 *      - Number of wakeup tries
360 *      - Host Sleep configured status
361 *      - Host Sleep activated status
362 *      - Number of Tx timeouts
363 *      - Number of command timeouts
364 *      - Last timed out command ID
365 *      - Last timed out command action
366 *      - Last command ID
367 *      - Last command action
368 *      - Last command index
369 *      - Last command response ID
370 *      - Last command response index
371 *      - Last event
372 *      - Last event index
373 *      - Number of host to card command failures
374 *      - Number of sleep confirm command failures
375 *      - Number of host to card data failure
376 *      - Number of deauthentication events
377 *      - Number of disassociation events
378 *      - Number of link lost events
379 *      - Number of deauthentication commands
380 *      - Number of association success commands
381 *      - Number of association failure commands
382 *      - Number of commands sent
383 *      - Number of data packets sent
384 *      - Number of command responses received
385 *      - Number of events received
386 *      - Tx BA stream table (TID, RA)
387 *      - Rx reorder table (TID, TA, Start window, Window size, Buffer)
388 */
389static ssize_t
390mwifiex_debug_read(struct file *file, char __user *ubuf,
391		   size_t count, loff_t *ppos)
392{
393	struct mwifiex_private *priv =
394		(struct mwifiex_private *) file->private_data;
395	struct mwifiex_debug_data *d = &items[0];
396	unsigned long page = get_zeroed_page(GFP_KERNEL);
397	char *p = (char *) page;
398	ssize_t ret;
399	size_t size, addr;
400	long val;
401	int i, j;
402
403	if (!p)
404		return -ENOMEM;
405
406	ret = mwifiex_get_debug_info(priv, &info);
407	if (ret)
408		goto free_and_exit;
409
410	for (i = 0; i < num_of_items; i++) {
411		p += sprintf(p, "%s=", d[i].name);
412
413		size = d[i].size / d[i].num;
414
415		if (i < (num_of_items - 3))
416			addr = d[i].addr + (size_t) &info;
417		else /* The last 3 items are struct mwifiex_adapter variables */
418			addr = d[i].addr + (size_t) priv->adapter;
419
420		for (j = 0; j < d[i].num; j++) {
421			switch (size) {
422			case 1:
423				val = *((u8 *) addr);
424				break;
425			case 2:
426				val = *((u16 *) addr);
427				break;
428			case 4:
429				val = *((u32 *) addr);
430				break;
431			case 8:
432				val = *((long long *) addr);
433				break;
434			default:
435				val = -1;
436				break;
437			}
438
439			p += sprintf(p, "%#lx ", val);
440			addr += size;
441		}
442
443		p += sprintf(p, "\n");
444	}
445
446	if (info.tx_tbl_num) {
447		p += sprintf(p, "Tx BA stream table:\n");
448		for (i = 0; i < info.tx_tbl_num; i++)
449			p += sprintf(p, "tid = %d, ra = %pM\n",
450				     info.tx_tbl[i].tid, info.tx_tbl[i].ra);
451	}
452
453	if (info.rx_tbl_num) {
454		p += sprintf(p, "Rx reorder table:\n");
455		for (i = 0; i < info.rx_tbl_num; i++) {
456			p += sprintf(p, "tid = %d, ta = %pM, "
457				     "start_win = %d, "
458				     "win_size = %d, buffer: ",
459				     info.rx_tbl[i].tid,
460				     info.rx_tbl[i].ta,
461				     info.rx_tbl[i].start_win,
462				     info.rx_tbl[i].win_size);
463
464			for (j = 0; j < info.rx_tbl[i].win_size; j++)
465				p += sprintf(p, "%c ",
466					     info.rx_tbl[i].buffer[j] ?
467					     '1' : '0');
468
469			p += sprintf(p, "\n");
470		}
471	}
472
473	ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
474				      (unsigned long) p - page);
475
476free_and_exit:
477	free_page(page);
478	return ret;
479}
480
481static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
482
483/*
484 * Proc regrdwr file write handler.
485 *
486 * This function is called when the 'regrdwr' file is opened for writing
487 *
488 * This function can be used to write to a register.
489 */
490static ssize_t
491mwifiex_regrdwr_write(struct file *file,
492		      const char __user *ubuf, size_t count, loff_t *ppos)
493{
494	unsigned long addr = get_zeroed_page(GFP_KERNEL);
495	char *buf = (char *) addr;
496	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
497	int ret;
498	u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
499
500	if (!buf)
501		return -ENOMEM;
502
503
504	if (copy_from_user(buf, ubuf, buf_size)) {
505		ret = -EFAULT;
506		goto done;
507	}
508
509	sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
510
511	if (reg_type == 0 || reg_offset == 0) {
512		ret = -EINVAL;
513		goto done;
514	} else {
515		saved_reg_type = reg_type;
516		saved_reg_offset = reg_offset;
517		saved_reg_value = reg_value;
518		ret = count;
519	}
520done:
521	free_page(addr);
522	return ret;
523}
524
525/*
526 * Proc regrdwr file read handler.
527 *
528 * This function is called when the 'regrdwr' file is opened for reading
529 *
530 * This function can be used to read from a register.
531 */
532static ssize_t
533mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
534		     size_t count, loff_t *ppos)
535{
536	struct mwifiex_private *priv =
537		(struct mwifiex_private *) file->private_data;
538	unsigned long addr = get_zeroed_page(GFP_KERNEL);
539	char *buf = (char *) addr;
540	int pos = 0, ret = 0;
541	u32 reg_value;
542
543	if (!buf)
544		return -ENOMEM;
545
546	if (!saved_reg_type) {
547		/* No command has been given */
548		pos += snprintf(buf, PAGE_SIZE, "0");
549		goto done;
550	}
551	/* Set command has been given */
552	if (saved_reg_value != UINT_MAX) {
553		ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
554					saved_reg_value);
555
556		pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
557				saved_reg_type, saved_reg_offset,
558				saved_reg_value);
559
560		ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
561
562		goto done;
563	}
564	/* Get command has been given */
565	ret = mwifiex_reg_read(priv, saved_reg_type,
566			       saved_reg_offset, &reg_value);
567	if (ret) {
568		ret = -EINVAL;
569		goto done;
570	}
571
572	pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
573			saved_reg_offset, reg_value);
574
575	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
576
577done:
578	free_page(addr);
579	return ret;
580}
581
582static u32 saved_offset = -1, saved_bytes = -1;
583
584/*
585 * Proc rdeeprom file write handler.
586 *
587 * This function is called when the 'rdeeprom' file is opened for writing
588 *
589 * This function can be used to write to a RDEEPROM location.
590 */
591static ssize_t
592mwifiex_rdeeprom_write(struct file *file,
593		       const char __user *ubuf, size_t count, loff_t *ppos)
594{
595	unsigned long addr = get_zeroed_page(GFP_KERNEL);
596	char *buf = (char *) addr;
597	size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
598	int ret = 0;
599	int offset = -1, bytes = -1;
600
601	if (!buf)
602		return -ENOMEM;
603
604
605	if (copy_from_user(buf, ubuf, buf_size)) {
606		ret = -EFAULT;
607		goto done;
608	}
609
610	sscanf(buf, "%d %d", &offset, &bytes);
611
612	if (offset == -1 || bytes == -1) {
613		ret = -EINVAL;
614		goto done;
615	} else {
616		saved_offset = offset;
617		saved_bytes = bytes;
618		ret = count;
619	}
620done:
621	free_page(addr);
622	return ret;
623}
624
625/*
626 * Proc rdeeprom read write handler.
627 *
628 * This function is called when the 'rdeeprom' file is opened for reading
629 *
630 * This function can be used to read from a RDEEPROM location.
631 */
632static ssize_t
633mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
634		      size_t count, loff_t *ppos)
635{
636	struct mwifiex_private *priv =
637		(struct mwifiex_private *) file->private_data;
638	unsigned long addr = get_zeroed_page(GFP_KERNEL);
639	char *buf = (char *) addr;
640	int pos = 0, ret = 0, i;
641	u8 value[MAX_EEPROM_DATA];
642
643	if (!buf)
644		return -ENOMEM;
645
646	if (saved_offset == -1) {
647		/* No command has been given */
648		pos += snprintf(buf, PAGE_SIZE, "0");
649		goto done;
650	}
651
652	/* Get command has been given */
653	ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
654				  (u16) saved_bytes, value);
655	if (ret) {
656		ret = -EINVAL;
657		goto done;
658	}
659
660	pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
661
662	for (i = 0; i < saved_bytes; i++)
663		pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]);
664
665	ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
666
667done:
668	free_page(addr);
669	return ret;
670}
671
672
673#define MWIFIEX_DFS_ADD_FILE(name) do {                                 \
674	if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir,        \
675			priv, &mwifiex_dfs_##name##_fops))              \
676		return;                                                 \
677} while (0);
678
679#define MWIFIEX_DFS_FILE_OPS(name)                                      \
680static const struct file_operations mwifiex_dfs_##name##_fops = {       \
681	.read = mwifiex_##name##_read,                                  \
682	.write = mwifiex_##name##_write,                                \
683	.open = simple_open,                                            \
684};
685
686#define MWIFIEX_DFS_FILE_READ_OPS(name)                                 \
687static const struct file_operations mwifiex_dfs_##name##_fops = {       \
688	.read = mwifiex_##name##_read,                                  \
689	.open = simple_open,                                            \
690};
691
692#define MWIFIEX_DFS_FILE_WRITE_OPS(name)                                \
693static const struct file_operations mwifiex_dfs_##name##_fops = {       \
694	.write = mwifiex_##name##_write,                                \
695	.open = simple_open,                                            \
696};
697
698
699MWIFIEX_DFS_FILE_READ_OPS(info);
700MWIFIEX_DFS_FILE_READ_OPS(debug);
701MWIFIEX_DFS_FILE_READ_OPS(getlog);
702MWIFIEX_DFS_FILE_OPS(regrdwr);
703MWIFIEX_DFS_FILE_OPS(rdeeprom);
704
705/*
706 * This function creates the debug FS directory structure and the files.
707 */
708void
709mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
710{
711	if (!mwifiex_dfs_dir || !priv)
712		return;
713
714	priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
715					       mwifiex_dfs_dir);
716
717	if (!priv->dfs_dev_dir)
718		return;
719
720	MWIFIEX_DFS_ADD_FILE(info);
721	MWIFIEX_DFS_ADD_FILE(debug);
722	MWIFIEX_DFS_ADD_FILE(getlog);
723	MWIFIEX_DFS_ADD_FILE(regrdwr);
724	MWIFIEX_DFS_ADD_FILE(rdeeprom);
725}
726
727/*
728 * This function removes the debug FS directory structure and the files.
729 */
730void
731mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
732{
733	if (!priv)
734		return;
735
736	debugfs_remove_recursive(priv->dfs_dev_dir);
737}
738
739/*
740 * This function creates the top level proc directory.
741 */
742void
743mwifiex_debugfs_init(void)
744{
745	if (!mwifiex_dfs_dir)
746		mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
747}
748
749/*
750 * This function removes the top level proc directory.
751 */
752void
753mwifiex_debugfs_remove(void)
754{
755	if (mwifiex_dfs_dir)
756		debugfs_remove(mwifiex_dfs_dir);
757}