• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/net/wireless/libertas/
1#include <linux/dcache.h>
2#include <linux/debugfs.h>
3#include <linux/delay.h>
4#include <linux/mm.h>
5#include <linux/string.h>
6#include <linux/slab.h>
7
8#include "decl.h"
9#include "cmd.h"
10#include "debugfs.h"
11
12static struct dentry *lbs_dir;
13static char *szStates[] = {
14	"Connected",
15	"Disconnected"
16};
17
18#ifdef PROC_DEBUG
19static void lbs_debug_init(struct lbs_private *priv);
20#endif
21
22static int open_file_generic(struct inode *inode, struct file *file)
23{
24	file->private_data = inode->i_private;
25	return 0;
26}
27
28static ssize_t write_file_dummy(struct file *file, const char __user *buf,
29                                size_t count, loff_t *ppos)
30{
31        return -EINVAL;
32}
33
34static const size_t len = PAGE_SIZE;
35
36static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
37				  size_t count, loff_t *ppos)
38{
39	struct lbs_private *priv = file->private_data;
40	size_t pos = 0;
41	unsigned long addr = get_zeroed_page(GFP_KERNEL);
42	char *buf = (char *)addr;
43	ssize_t res;
44	if (!buf)
45		return -ENOMEM;
46
47	pos += snprintf(buf+pos, len-pos, "state = %s\n",
48				szStates[priv->connect_status]);
49	pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
50				(u32) priv->regioncode);
51
52	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
53
54	free_page(addr);
55	return res;
56}
57
58static ssize_t lbs_sleepparams_write(struct file *file,
59				const char __user *user_buf, size_t count,
60				loff_t *ppos)
61{
62	struct lbs_private *priv = file->private_data;
63	ssize_t buf_size, ret;
64	struct sleep_params sp;
65	int p1, p2, p3, p4, p5, p6;
66	unsigned long addr = get_zeroed_page(GFP_KERNEL);
67	char *buf = (char *)addr;
68	if (!buf)
69		return -ENOMEM;
70
71	buf_size = min(count, len - 1);
72	if (copy_from_user(buf, user_buf, buf_size)) {
73		ret = -EFAULT;
74		goto out_unlock;
75	}
76	ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
77	if (ret != 6) {
78		ret = -EINVAL;
79		goto out_unlock;
80	}
81	sp.sp_error = p1;
82	sp.sp_offset = p2;
83	sp.sp_stabletime = p3;
84	sp.sp_calcontrol = p4;
85	sp.sp_extsleepclk = p5;
86	sp.sp_reserved = p6;
87
88	ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
89	if (!ret)
90		ret = count;
91	else if (ret > 0)
92		ret = -EINVAL;
93
94out_unlock:
95	free_page(addr);
96	return ret;
97}
98
99static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
100				  size_t count, loff_t *ppos)
101{
102	struct lbs_private *priv = file->private_data;
103	ssize_t ret;
104	size_t pos = 0;
105	struct sleep_params sp;
106	unsigned long addr = get_zeroed_page(GFP_KERNEL);
107	char *buf = (char *)addr;
108	if (!buf)
109		return -ENOMEM;
110
111	ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
112	if (ret)
113		goto out_unlock;
114
115	pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
116			sp.sp_offset, sp.sp_stabletime,
117			sp.sp_calcontrol, sp.sp_extsleepclk,
118			sp.sp_reserved);
119
120	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
121
122out_unlock:
123	free_page(addr);
124	return ret;
125}
126
127static ssize_t lbs_host_sleep_write(struct file *file,
128				const char __user *user_buf, size_t count,
129				loff_t *ppos)
130{
131	struct lbs_private *priv = file->private_data;
132	ssize_t buf_size, ret;
133	int host_sleep;
134	unsigned long addr = get_zeroed_page(GFP_KERNEL);
135	char *buf = (char *)addr;
136	if (!buf)
137		return -ENOMEM;
138
139	buf_size = min(count, len - 1);
140	if (copy_from_user(buf, user_buf, buf_size)) {
141		ret = -EFAULT;
142		goto out_unlock;
143	}
144	ret = sscanf(buf, "%d", &host_sleep);
145	if (ret != 1) {
146		ret = -EINVAL;
147		goto out_unlock;
148	}
149
150	if (host_sleep == 0)
151		ret = lbs_set_host_sleep(priv, 0);
152	else if (host_sleep == 1) {
153		if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
154			lbs_pr_info("wake parameters not configured");
155			ret = -EINVAL;
156			goto out_unlock;
157		}
158		ret = lbs_set_host_sleep(priv, 1);
159	} else {
160		lbs_pr_err("invalid option\n");
161		ret = -EINVAL;
162	}
163
164	if (!ret)
165		ret = count;
166
167out_unlock:
168	free_page(addr);
169	return ret;
170}
171
172static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
173				  size_t count, loff_t *ppos)
174{
175	struct lbs_private *priv = file->private_data;
176	ssize_t ret;
177	size_t pos = 0;
178	unsigned long addr = get_zeroed_page(GFP_KERNEL);
179	char *buf = (char *)addr;
180	if (!buf)
181		return -ENOMEM;
182
183	pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
184
185	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
186
187	free_page(addr);
188	return ret;
189}
190
191/*
192 * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
193 * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
194 * firmware. Here's an example:
195 *	04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
196 *	00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
197 *	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
198 *
199 * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
200 * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
201 * defined in mrvlietypes_thresholds
202 *
203 * This function searches in this TLV data chunk for a given TLV type
204 * and returns a pointer to the first data byte of the TLV, or to NULL
205 * if the TLV hasn't been found.
206 */
207static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
208{
209	struct mrvl_ie_header *tlv_h;
210	uint16_t length;
211	ssize_t pos = 0;
212
213	while (pos < size) {
214		tlv_h = (struct mrvl_ie_header *) tlv;
215		if (!tlv_h->len)
216			return NULL;
217		if (tlv_h->type == cpu_to_le16(tlv_type))
218			return tlv_h;
219		length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
220		pos += length;
221		tlv += length;
222	}
223	return NULL;
224}
225
226
227static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
228				  struct file *file, char __user *userbuf,
229				  size_t count, loff_t *ppos)
230{
231	struct cmd_ds_802_11_subscribe_event *subscribed;
232	struct mrvl_ie_thresholds *got;
233	struct lbs_private *priv = file->private_data;
234	ssize_t ret = 0;
235	size_t pos = 0;
236	char *buf;
237	u8 value;
238	u8 freq;
239	int events = 0;
240
241	buf = (char *)get_zeroed_page(GFP_KERNEL);
242	if (!buf)
243		return -ENOMEM;
244
245	subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
246	if (!subscribed) {
247		ret = -ENOMEM;
248		goto out_page;
249	}
250
251	subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
252	subscribed->action = cpu_to_le16(CMD_ACT_GET);
253
254	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
255	if (ret)
256		goto out_cmd;
257
258	got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
259	if (got) {
260		value = got->value;
261		freq  = got->freq;
262		events = le16_to_cpu(subscribed->events);
263
264		pos += snprintf(buf, len, "%d %d %d\n", value, freq,
265				!!(events & event_mask));
266	}
267
268	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
269
270 out_cmd:
271	kfree(subscribed);
272
273 out_page:
274	free_page((unsigned long)buf);
275	return ret;
276}
277
278
279static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
280				   struct file *file,
281				   const char __user *userbuf, size_t count,
282				   loff_t *ppos)
283{
284	struct cmd_ds_802_11_subscribe_event *events;
285	struct mrvl_ie_thresholds *tlv;
286	struct lbs_private *priv = file->private_data;
287	ssize_t buf_size;
288	int value, freq, new_mask;
289	uint16_t curr_mask;
290	char *buf;
291	int ret;
292
293	buf = (char *)get_zeroed_page(GFP_KERNEL);
294	if (!buf)
295		return -ENOMEM;
296
297	buf_size = min(count, len - 1);
298	if (copy_from_user(buf, userbuf, buf_size)) {
299		ret = -EFAULT;
300		goto out_page;
301	}
302	ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
303	if (ret != 3) {
304		ret = -EINVAL;
305		goto out_page;
306	}
307	events = kzalloc(sizeof(*events), GFP_KERNEL);
308	if (!events) {
309		ret = -ENOMEM;
310		goto out_page;
311	}
312
313	events->hdr.size = cpu_to_le16(sizeof(*events));
314	events->action = cpu_to_le16(CMD_ACT_GET);
315
316	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
317	if (ret)
318		goto out_events;
319
320	curr_mask = le16_to_cpu(events->events);
321
322	if (new_mask)
323		new_mask = curr_mask | event_mask;
324	else
325		new_mask = curr_mask & ~event_mask;
326
327	/* Now everything is set and we can send stuff down to the firmware */
328
329	tlv = (void *)events->tlv;
330
331	events->action = cpu_to_le16(CMD_ACT_SET);
332	events->events = cpu_to_le16(new_mask);
333	tlv->header.type = cpu_to_le16(tlv_type);
334	tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
335	tlv->value = value;
336	if (tlv_type != TLV_TYPE_BCNMISS)
337		tlv->freq = freq;
338
339	/* The command header, the action, the event mask, and one TLV */
340	events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
341
342	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
343
344	if (!ret)
345		ret = count;
346 out_events:
347	kfree(events);
348 out_page:
349	free_page((unsigned long)buf);
350	return ret;
351}
352
353
354static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
355				size_t count, loff_t *ppos)
356{
357	return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
358				  file, userbuf, count, ppos);
359}
360
361
362static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
363				 size_t count, loff_t *ppos)
364{
365	return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
366				   file, userbuf, count, ppos);
367}
368
369
370static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
371			       size_t count, loff_t *ppos)
372{
373	return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
374				  file, userbuf, count, ppos);
375}
376
377
378static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
379				size_t count, loff_t *ppos)
380{
381	return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
382				   file, userbuf, count, ppos);
383}
384
385
386static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
387				  size_t count, loff_t *ppos)
388{
389	return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
390				  file, userbuf, count, ppos);
391}
392
393
394static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
395				   size_t count, loff_t *ppos)
396{
397	return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
398				   file, userbuf, count, ppos);
399}
400
401
402static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
403				 size_t count, loff_t *ppos)
404{
405	return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
406				  file, userbuf, count, ppos);
407}
408
409
410static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
411				  size_t count, loff_t *ppos)
412{
413	return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
414				   file, userbuf, count, ppos);
415}
416
417
418static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
419				size_t count, loff_t *ppos)
420{
421	return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
422				  file, userbuf, count, ppos);
423}
424
425
426static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
427				 size_t count, loff_t *ppos)
428{
429	return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
430				   file, userbuf, count, ppos);
431}
432
433static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
434				size_t count, loff_t *ppos)
435{
436	return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
437				  file, userbuf, count, ppos);
438}
439
440
441static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
442				 size_t count, loff_t *ppos)
443{
444	return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
445				   file, userbuf, count, ppos);
446}
447
448
449static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
450				  size_t count, loff_t *ppos)
451{
452	struct lbs_private *priv = file->private_data;
453	ssize_t pos = 0;
454	int ret;
455	unsigned long addr = get_zeroed_page(GFP_KERNEL);
456	char *buf = (char *)addr;
457	u32 val = 0;
458
459	if (!buf)
460		return -ENOMEM;
461
462	ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val);
463	mdelay(10);
464	if (!ret) {
465		pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n",
466				priv->mac_offset, val);
467		ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
468	}
469	free_page(addr);
470	return ret;
471}
472
473static ssize_t lbs_rdmac_write(struct file *file,
474				    const char __user *userbuf,
475				    size_t count, loff_t *ppos)
476{
477	struct lbs_private *priv = file->private_data;
478	ssize_t res, buf_size;
479	unsigned long addr = get_zeroed_page(GFP_KERNEL);
480	char *buf = (char *)addr;
481	if (!buf)
482		return -ENOMEM;
483
484	buf_size = min(count, len - 1);
485	if (copy_from_user(buf, userbuf, buf_size)) {
486		res = -EFAULT;
487		goto out_unlock;
488	}
489	priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
490	res = count;
491out_unlock:
492	free_page(addr);
493	return res;
494}
495
496static ssize_t lbs_wrmac_write(struct file *file,
497				    const char __user *userbuf,
498				    size_t count, loff_t *ppos)
499{
500
501	struct lbs_private *priv = file->private_data;
502	ssize_t res, buf_size;
503	u32 offset, value;
504	unsigned long addr = get_zeroed_page(GFP_KERNEL);
505	char *buf = (char *)addr;
506	if (!buf)
507		return -ENOMEM;
508
509	buf_size = min(count, len - 1);
510	if (copy_from_user(buf, userbuf, buf_size)) {
511		res = -EFAULT;
512		goto out_unlock;
513	}
514	res = sscanf(buf, "%x %x", &offset, &value);
515	if (res != 2) {
516		res = -EFAULT;
517		goto out_unlock;
518	}
519
520	res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value);
521	mdelay(10);
522
523	if (!res)
524		res = count;
525out_unlock:
526	free_page(addr);
527	return res;
528}
529
530static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
531				  size_t count, loff_t *ppos)
532{
533	struct lbs_private *priv = file->private_data;
534	ssize_t pos = 0;
535	int ret;
536	unsigned long addr = get_zeroed_page(GFP_KERNEL);
537	char *buf = (char *)addr;
538	u32 val;
539
540	if (!buf)
541		return -ENOMEM;
542
543	ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val);
544	mdelay(10);
545	if (!ret) {
546		pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n",
547				priv->bbp_offset, val);
548		ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
549	}
550	free_page(addr);
551
552	return ret;
553}
554
555static ssize_t lbs_rdbbp_write(struct file *file,
556				    const char __user *userbuf,
557				    size_t count, loff_t *ppos)
558{
559	struct lbs_private *priv = file->private_data;
560	ssize_t res, buf_size;
561	unsigned long addr = get_zeroed_page(GFP_KERNEL);
562	char *buf = (char *)addr;
563	if (!buf)
564		return -ENOMEM;
565
566	buf_size = min(count, len - 1);
567	if (copy_from_user(buf, userbuf, buf_size)) {
568		res = -EFAULT;
569		goto out_unlock;
570	}
571	priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
572	res = count;
573out_unlock:
574	free_page(addr);
575	return res;
576}
577
578static ssize_t lbs_wrbbp_write(struct file *file,
579				    const char __user *userbuf,
580				    size_t count, loff_t *ppos)
581{
582
583	struct lbs_private *priv = file->private_data;
584	ssize_t res, buf_size;
585	u32 offset, value;
586	unsigned long addr = get_zeroed_page(GFP_KERNEL);
587	char *buf = (char *)addr;
588	if (!buf)
589		return -ENOMEM;
590
591	buf_size = min(count, len - 1);
592	if (copy_from_user(buf, userbuf, buf_size)) {
593		res = -EFAULT;
594		goto out_unlock;
595	}
596	res = sscanf(buf, "%x %x", &offset, &value);
597	if (res != 2) {
598		res = -EFAULT;
599		goto out_unlock;
600	}
601
602	res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value);
603	mdelay(10);
604
605	if (!res)
606		res = count;
607out_unlock:
608	free_page(addr);
609	return res;
610}
611
612static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
613				  size_t count, loff_t *ppos)
614{
615	struct lbs_private *priv = file->private_data;
616	ssize_t pos = 0;
617	int ret;
618	unsigned long addr = get_zeroed_page(GFP_KERNEL);
619	char *buf = (char *)addr;
620	u32 val;
621
622	if (!buf)
623		return -ENOMEM;
624
625	ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val);
626	mdelay(10);
627	if (!ret) {
628		pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n",
629				priv->rf_offset, val);
630		ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
631	}
632	free_page(addr);
633
634	return ret;
635}
636
637static ssize_t lbs_rdrf_write(struct file *file,
638				    const char __user *userbuf,
639				    size_t count, loff_t *ppos)
640{
641	struct lbs_private *priv = file->private_data;
642	ssize_t res, buf_size;
643	unsigned long addr = get_zeroed_page(GFP_KERNEL);
644	char *buf = (char *)addr;
645	if (!buf)
646		return -ENOMEM;
647
648	buf_size = min(count, len - 1);
649	if (copy_from_user(buf, userbuf, buf_size)) {
650		res = -EFAULT;
651		goto out_unlock;
652	}
653	priv->rf_offset = simple_strtoul(buf, NULL, 16);
654	res = count;
655out_unlock:
656	free_page(addr);
657	return res;
658}
659
660static ssize_t lbs_wrrf_write(struct file *file,
661				    const char __user *userbuf,
662				    size_t count, loff_t *ppos)
663{
664
665	struct lbs_private *priv = file->private_data;
666	ssize_t res, buf_size;
667	u32 offset, value;
668	unsigned long addr = get_zeroed_page(GFP_KERNEL);
669	char *buf = (char *)addr;
670	if (!buf)
671		return -ENOMEM;
672
673	buf_size = min(count, len - 1);
674	if (copy_from_user(buf, userbuf, buf_size)) {
675		res = -EFAULT;
676		goto out_unlock;
677	}
678	res = sscanf(buf, "%x %x", &offset, &value);
679	if (res != 2) {
680		res = -EFAULT;
681		goto out_unlock;
682	}
683
684	res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value);
685	mdelay(10);
686
687	if (!res)
688		res = count;
689out_unlock:
690	free_page(addr);
691	return res;
692}
693
694#define FOPS(fread, fwrite) { \
695	.owner = THIS_MODULE, \
696	.open = open_file_generic, \
697	.read = (fread), \
698	.write = (fwrite), \
699}
700
701struct lbs_debugfs_files {
702	const char *name;
703	int perm;
704	struct file_operations fops;
705};
706
707static const struct lbs_debugfs_files debugfs_files[] = {
708	{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
709	{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
710				lbs_sleepparams_write), },
711	{ "hostsleep", 0644, FOPS(lbs_host_sleep_read,
712				lbs_host_sleep_write), },
713};
714
715static const struct lbs_debugfs_files debugfs_events_files[] = {
716	{"low_rssi", 0644, FOPS(lbs_lowrssi_read,
717				lbs_lowrssi_write), },
718	{"low_snr", 0644, FOPS(lbs_lowsnr_read,
719				lbs_lowsnr_write), },
720	{"failure_count", 0644, FOPS(lbs_failcount_read,
721				lbs_failcount_write), },
722	{"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
723				lbs_bcnmiss_write), },
724	{"high_rssi", 0644, FOPS(lbs_highrssi_read,
725				lbs_highrssi_write), },
726	{"high_snr", 0644, FOPS(lbs_highsnr_read,
727				lbs_highsnr_write), },
728};
729
730static const struct lbs_debugfs_files debugfs_regs_files[] = {
731	{"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
732	{"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
733	{"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
734	{"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
735	{"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
736	{"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
737};
738
739void lbs_debugfs_init(void)
740{
741	if (!lbs_dir)
742		lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
743}
744
745void lbs_debugfs_remove(void)
746{
747	if (lbs_dir)
748		 debugfs_remove(lbs_dir);
749}
750
751void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
752{
753	int i;
754	const struct lbs_debugfs_files *files;
755	if (!lbs_dir)
756		goto exit;
757
758	priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
759	if (!priv->debugfs_dir)
760		goto exit;
761
762	for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
763		files = &debugfs_files[i];
764		priv->debugfs_files[i] = debugfs_create_file(files->name,
765							     files->perm,
766							     priv->debugfs_dir,
767							     priv,
768							     &files->fops);
769	}
770
771	priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
772	if (!priv->events_dir)
773		goto exit;
774
775	for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
776		files = &debugfs_events_files[i];
777		priv->debugfs_events_files[i] = debugfs_create_file(files->name,
778							     files->perm,
779							     priv->events_dir,
780							     priv,
781							     &files->fops);
782	}
783
784	priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
785	if (!priv->regs_dir)
786		goto exit;
787
788	for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
789		files = &debugfs_regs_files[i];
790		priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
791							     files->perm,
792							     priv->regs_dir,
793							     priv,
794							     &files->fops);
795	}
796
797#ifdef PROC_DEBUG
798	lbs_debug_init(priv);
799#endif
800exit:
801	return;
802}
803
804void lbs_debugfs_remove_one(struct lbs_private *priv)
805{
806	int i;
807
808	for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
809		debugfs_remove(priv->debugfs_regs_files[i]);
810
811	debugfs_remove(priv->regs_dir);
812
813	for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
814		debugfs_remove(priv->debugfs_events_files[i]);
815
816	debugfs_remove(priv->events_dir);
817#ifdef PROC_DEBUG
818	debugfs_remove(priv->debugfs_debug);
819#endif
820	for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
821		debugfs_remove(priv->debugfs_files[i]);
822	debugfs_remove(priv->debugfs_dir);
823}
824
825
826
827/* debug entry */
828
829#ifdef PROC_DEBUG
830
831#define item_size(n)	(FIELD_SIZEOF(struct lbs_private, n))
832#define item_addr(n)	(offsetof(struct lbs_private, n))
833
834
835struct debug_data {
836	char name[32];
837	u32 size;
838	size_t addr;
839};
840
841/* To debug any member of struct lbs_private, simply add one line here.
842 */
843static struct debug_data items[] = {
844	{"psmode", item_size(psmode), item_addr(psmode)},
845	{"psstate", item_size(psstate), item_addr(psstate)},
846};
847
848static int num_of_items = ARRAY_SIZE(items);
849
850/**
851 *  @brief proc read function
852 *
853 *  @param page	   pointer to buffer
854 *  @param s       read data starting position
855 *  @param off     offset
856 *  @param cnt     counter
857 *  @param eof     end of file flag
858 *  @param data    data to output
859 *  @return 	   number of output data
860 */
861static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
862			size_t count, loff_t *ppos)
863{
864	int val = 0;
865	size_t pos = 0;
866	ssize_t res;
867	char *p;
868	int i;
869	struct debug_data *d;
870	unsigned long addr = get_zeroed_page(GFP_KERNEL);
871	char *buf = (char *)addr;
872	if (!buf)
873		return -ENOMEM;
874
875	p = buf;
876
877	d = file->private_data;
878
879	for (i = 0; i < num_of_items; i++) {
880		if (d[i].size == 1)
881			val = *((u8 *) d[i].addr);
882		else if (d[i].size == 2)
883			val = *((u16 *) d[i].addr);
884		else if (d[i].size == 4)
885			val = *((u32 *) d[i].addr);
886		else if (d[i].size == 8)
887			val = *((u64 *) d[i].addr);
888
889		pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
890	}
891
892	res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
893
894	free_page(addr);
895	return res;
896}
897
898/**
899 *  @brief proc write function
900 *
901 *  @param f	   file pointer
902 *  @param buf     pointer to data buffer
903 *  @param cnt     data number to write
904 *  @param data    data to write
905 *  @return 	   number of data
906 */
907static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
908			    size_t cnt, loff_t *ppos)
909{
910	int r, i;
911	char *pdata;
912	char *p;
913	char *p0;
914	char *p1;
915	char *p2;
916	struct debug_data *d = f->private_data;
917
918	pdata = kmalloc(cnt, GFP_KERNEL);
919	if (pdata == NULL)
920		return 0;
921
922	if (copy_from_user(pdata, buf, cnt)) {
923		lbs_deb_debugfs("Copy from user failed\n");
924		kfree(pdata);
925		return 0;
926	}
927
928	p0 = pdata;
929	for (i = 0; i < num_of_items; i++) {
930		do {
931			p = strstr(p0, d[i].name);
932			if (p == NULL)
933				break;
934			p1 = strchr(p, '\n');
935			if (p1 == NULL)
936				break;
937			p0 = p1++;
938			p2 = strchr(p, '=');
939			if (!p2)
940				break;
941			p2++;
942			r = simple_strtoul(p2, NULL, 0);
943			if (d[i].size == 1)
944				*((u8 *) d[i].addr) = (u8) r;
945			else if (d[i].size == 2)
946				*((u16 *) d[i].addr) = (u16) r;
947			else if (d[i].size == 4)
948				*((u32 *) d[i].addr) = (u32) r;
949			else if (d[i].size == 8)
950				*((u64 *) d[i].addr) = (u64) r;
951			break;
952		} while (1);
953	}
954	kfree(pdata);
955
956	return (ssize_t)cnt;
957}
958
959static const struct file_operations lbs_debug_fops = {
960	.owner = THIS_MODULE,
961	.open = open_file_generic,
962	.write = lbs_debugfs_write,
963	.read = lbs_debugfs_read,
964};
965
966/**
967 *  @brief create debug proc file
968 *
969 *  @param priv	   pointer struct lbs_private
970 *  @param dev     pointer net_device
971 *  @return 	   N/A
972 */
973static void lbs_debug_init(struct lbs_private *priv)
974{
975	int i;
976
977	if (!priv->debugfs_dir)
978		return;
979
980	for (i = 0; i < num_of_items; i++)
981		items[i].addr += (size_t) priv;
982
983	priv->debugfs_debug = debugfs_create_file("debug", 0644,
984						  priv->debugfs_dir, &items[0],
985						  &lbs_debug_fops);
986}
987#endif
988