• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/src/linux/linux-2.6/drivers/net/wireless/libertas/
1#include <linux/module.h>
2#include <linux/dcache.h>
3#include <linux/debugfs.h>
4#include <linux/delay.h>
5#include <linux/mm.h>
6#include <net/iw_handler.h>
7
8#include "dev.h"
9#include "decl.h"
10#include "host.h"
11#include "debugfs.h"
12
13static struct dentry *libertas_dir = NULL;
14static char *szStates[] = {
15	"Connected",
16	"Disconnected"
17};
18
19#ifdef PROC_DEBUG
20static void libertas_debug_init(wlan_private * priv, struct net_device *dev);
21#endif
22
23static int open_file_generic(struct inode *inode, struct file *file)
24{
25	file->private_data = inode->i_private;
26	return 0;
27}
28
29static ssize_t write_file_dummy(struct file *file, const char __user *buf,
30                                size_t count, loff_t *ppos)
31{
32        return -EINVAL;
33}
34
35static const size_t len = PAGE_SIZE;
36
37static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
38				  size_t count, loff_t *ppos)
39{
40	wlan_private *priv = file->private_data;
41	size_t pos = 0;
42	unsigned long addr = get_zeroed_page(GFP_KERNEL);
43	char *buf = (char *)addr;
44	ssize_t res;
45
46	pos += snprintf(buf+pos, len-pos, "state = %s\n",
47				szStates[priv->adapter->connect_status]);
48	pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
49				(u32) priv->adapter->regioncode);
50
51	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
52
53	free_page(addr);
54	return res;
55}
56
57
58static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
59				  size_t count, loff_t *ppos)
60{
61	wlan_private *priv = file->private_data;
62	size_t pos = 0;
63	int numscansdone = 0, res;
64	unsigned long addr = get_zeroed_page(GFP_KERNEL);
65	char *buf = (char *)addr;
66	struct bss_descriptor * iter_bss;
67
68	pos += snprintf(buf+pos, len-pos,
69		"# | ch  | ss  |       bssid       |   cap    |    TSF   | Qual | SSID \n");
70
71	mutex_lock(&priv->adapter->lock);
72	list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
73		u16 cap;
74
75		memcpy(&cap, &iter_bss->cap, sizeof(cap));
76		pos += snprintf(buf+pos, len-pos,
77			"%02u| %03d | %03ld | " MAC_FMT " |",
78			numscansdone, iter_bss->channel, iter_bss->rssi,
79			MAC_ARG(iter_bss->bssid));
80		pos += snprintf(buf+pos, len-pos, " %04x-", cap);
81		pos += snprintf(buf+pos, len-pos, "%c%c%c |",
82				iter_bss->cap.ibss ? 'A' : 'I',
83				iter_bss->cap.privacy ? 'P' : ' ',
84				iter_bss->cap.spectrummgmt ? 'S' : ' ');
85		pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf);
86		pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi));
87		pos += snprintf(buf+pos, len-pos, " %s\n",
88		                escape_essid(iter_bss->ssid, iter_bss->ssid_len));
89
90		numscansdone++;
91	}
92	mutex_unlock(&priv->adapter->lock);
93
94	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
95
96	free_page(addr);
97	return res;
98}
99
100static ssize_t libertas_sleepparams_write(struct file *file,
101				const char __user *user_buf, size_t count,
102				loff_t *ppos)
103{
104	wlan_private *priv = file->private_data;
105	ssize_t buf_size, res;
106	int p1, p2, p3, p4, p5, p6;
107	unsigned long addr = get_zeroed_page(GFP_KERNEL);
108	char *buf = (char *)addr;
109
110	buf_size = min(count, len - 1);
111	if (copy_from_user(buf, user_buf, buf_size)) {
112		res = -EFAULT;
113		goto out_unlock;
114	}
115	res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
116	if (res != 6) {
117		res = -EFAULT;
118		goto out_unlock;
119	}
120	priv->adapter->sp.sp_error = p1;
121	priv->adapter->sp.sp_offset = p2;
122	priv->adapter->sp.sp_stabletime = p3;
123	priv->adapter->sp.sp_calcontrol = p4;
124	priv->adapter->sp.sp_extsleepclk = p5;
125	priv->adapter->sp.sp_reserved = p6;
126
127        res = libertas_prepare_and_send_command(priv,
128				cmd_802_11_sleep_params,
129				cmd_act_set,
130				cmd_option_waitforrsp, 0, NULL);
131
132	if (!res)
133		res = count;
134	else
135		res = -EINVAL;
136
137out_unlock:
138	free_page(addr);
139	return res;
140}
141
142static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
143				  size_t count, loff_t *ppos)
144{
145	wlan_private *priv = file->private_data;
146	wlan_adapter *adapter = priv->adapter;
147	ssize_t res;
148	size_t pos = 0;
149	unsigned long addr = get_zeroed_page(GFP_KERNEL);
150	char *buf = (char *)addr;
151
152        res = libertas_prepare_and_send_command(priv,
153				cmd_802_11_sleep_params,
154				cmd_act_get,
155				cmd_option_waitforrsp, 0, NULL);
156	if (res) {
157		res = -EFAULT;
158		goto out_unlock;
159	}
160
161	pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
162			adapter->sp.sp_offset, adapter->sp.sp_stabletime,
163			adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
164			adapter->sp.sp_reserved);
165
166	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
167
168out_unlock:
169	free_page(addr);
170	return res;
171}
172
173static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
174				  size_t count, loff_t *ppos)
175{
176	wlan_private *priv = file->private_data;
177	ssize_t res, buf_size;
178	union iwreq_data wrqu;
179	unsigned long addr = get_zeroed_page(GFP_KERNEL);
180	char *buf = (char *)addr;
181
182	buf_size = min(count, len - 1);
183	if (copy_from_user(buf, userbuf, buf_size)) {
184		res = -EFAULT;
185		goto out_unlock;
186	}
187
188	libertas_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
189
190	memset(&wrqu, 0, sizeof(union iwreq_data));
191	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
192
193out_unlock:
194	free_page(addr);
195	return count;
196}
197
198static int libertas_parse_chan(char *buf, size_t count,
199			struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
200{
201	char *start, *end, *hold, *str;
202	int i = 0;
203
204	start = strstr(buf, "chan=");
205	if (!start)
206		return -EINVAL;
207	start += 5;
208	end = strstr(start, " ");
209	if (!end)
210		end = buf + count;
211	hold = kzalloc((end - start)+1, GFP_KERNEL);
212	if (!hold)
213		return -ENOMEM;
214	strncpy(hold, start, end - start);
215	hold[(end-start)+1] = '\0';
216	while(hold && (str = strsep(&hold, ","))) {
217		int chan;
218		char band, passive = 0;
219		sscanf(str, "%d%c%c", &chan, &band, &passive);
220		scan_cfg->chanlist[i].channumber = chan;
221		scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
222		if (band == 'b' || band == 'g')
223			scan_cfg->chanlist[i].radiotype = 0;
224		else if (band == 'a')
225			scan_cfg->chanlist[i].radiotype = 1;
226
227		scan_cfg->chanlist[i].scantime = dur;
228		i++;
229	}
230
231	kfree(hold);
232	return i;
233}
234
235static void libertas_parse_bssid(char *buf, size_t count,
236                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
237{
238	char *hold;
239	unsigned int mac[ETH_ALEN];
240
241	hold = strstr(buf, "bssid=");
242	if (!hold)
243		return;
244	hold += 6;
245	sscanf(hold, MAC_FMT, mac, mac+1, mac+2, mac+3, mac+4, mac+5);
246	memcpy(scan_cfg->bssid, mac, ETH_ALEN);
247}
248
249static void libertas_parse_ssid(char *buf, size_t count,
250                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
251{
252	char *hold, *end;
253	ssize_t size;
254
255	hold = strstr(buf, "ssid=");
256	if (!hold)
257		return;
258	hold += 5;
259	end = strstr(hold, " ");
260	if (!end)
261		end = buf + count - 1;
262
263	size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold));
264	strncpy(scan_cfg->ssid, hold, size);
265
266	return;
267}
268
269static int libertas_parse_clear(char *buf, size_t count, const char *tag)
270{
271	char *hold;
272	int val;
273
274	hold = strstr(buf, tag);
275	if (!hold)
276		return 0;
277	hold += strlen(tag);
278	sscanf(hold, "%d", &val);
279
280	if (val != 0)
281		val = 1;
282
283	return val;
284}
285
286static int libertas_parse_dur(char *buf, size_t count,
287                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
288{
289	char *hold;
290	int val;
291
292	hold = strstr(buf, "dur=");
293	if (!hold)
294		return 0;
295	hold += 4;
296	sscanf(hold, "%d", &val);
297
298	return val;
299}
300
301static void libertas_parse_probes(char *buf, size_t count,
302                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
303{
304	char *hold;
305	int val;
306
307	hold = strstr(buf, "probes=");
308	if (!hold)
309		return;
310	hold += 7;
311	sscanf(hold, "%d", &val);
312
313	scan_cfg->numprobes = val;
314
315	return;
316}
317
318static void libertas_parse_type(char *buf, size_t count,
319                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
320{
321	char *hold;
322	int val;
323
324	hold = strstr(buf, "type=");
325	if (!hold)
326		return;
327	hold += 5;
328	sscanf(hold, "%d", &val);
329
330	/* type=1,2 or 3 */
331	if (val < 1 || val > 3)
332		return;
333
334	scan_cfg->bsstype = val;
335
336	return;
337}
338
339static ssize_t libertas_setuserscan(struct file *file,
340				    const char __user *userbuf,
341				    size_t count, loff_t *ppos)
342{
343	wlan_private *priv = file->private_data;
344	ssize_t res, buf_size;
345	struct wlan_ioctl_user_scan_cfg *scan_cfg;
346	union iwreq_data wrqu;
347	int dur;
348	unsigned long addr = get_zeroed_page(GFP_KERNEL);
349	char *buf = (char *)addr;
350
351	scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
352	if (!scan_cfg)
353		return -ENOMEM;
354
355	buf_size = min(count, len - 1);
356	if (copy_from_user(buf, userbuf, buf_size)) {
357		res = -EFAULT;
358		goto out_unlock;
359	}
360
361	scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
362
363	dur = libertas_parse_dur(buf, count, scan_cfg);
364	libertas_parse_chan(buf, count, scan_cfg, dur);
365	libertas_parse_bssid(buf, count, scan_cfg);
366	scan_cfg->clear_bssid = libertas_parse_clear(buf, count, "clear_bssid=");
367	libertas_parse_ssid(buf, count, scan_cfg);
368	scan_cfg->clear_ssid = libertas_parse_clear(buf, count, "clear_ssid=");
369	libertas_parse_probes(buf, count, scan_cfg);
370	libertas_parse_type(buf, count, scan_cfg);
371
372	wlan_scan_networks(priv, scan_cfg, 1);
373	wait_event_interruptible(priv->adapter->cmd_pending,
374				 !priv->adapter->nr_cmd_pending);
375
376	memset(&wrqu, 0x00, sizeof(union iwreq_data));
377	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
378
379out_unlock:
380	free_page(addr);
381	kfree(scan_cfg);
382	return count;
383}
384
385static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
386			struct cmd_ctrl_node **cmdnode,
387			struct cmd_ds_command **cmd)
388{
389	u16 wait_option = cmd_option_waitforrsp;
390
391	if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
392		lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n");
393		return -ENOMEM;
394	}
395	if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
396		lbs_deb_debugfs("failed to allocate response buffer!\n");
397		return -ENOMEM;
398	}
399	libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
400	init_waitqueue_head(&(*cmdnode)->cmdwait_q);
401	(*cmdnode)->pdata_buf = *response_buf;
402	(*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
403	(*cmdnode)->cmdwaitqwoken = 0;
404	*cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
405	(*cmd)->command = cpu_to_le16(cmd_802_11_subscribe_event);
406	(*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum);
407	(*cmd)->result = 0;
408	return 0;
409}
410
411static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
412				  size_t count, loff_t *ppos)
413{
414	wlan_private *priv = file->private_data;
415	wlan_adapter *adapter = priv->adapter;
416	struct cmd_ctrl_node *pcmdnode;
417	struct cmd_ds_command *pcmdptr;
418	struct cmd_ds_802_11_subscribe_event *event;
419	void *response_buf;
420	int res, cmd_len;
421	ssize_t pos = 0;
422	unsigned long addr = get_zeroed_page(GFP_KERNEL);
423	char *buf = (char *)addr;
424
425	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
426	if (res < 0) {
427		free_page(addr);
428		return res;
429	}
430
431	event = &pcmdptr->params.subscribe_event;
432	event->action = cpu_to_le16(cmd_act_get);
433	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
434	libertas_queue_cmd(adapter, pcmdnode, 1);
435	wake_up_interruptible(&priv->mainthread.waitq);
436
437	/* Sleep until response is generated by FW */
438	wait_event_interruptible(pcmdnode->cmdwait_q,
439				 pcmdnode->cmdwaitqwoken);
440
441	pcmdptr = response_buf;
442	if (pcmdptr->result) {
443		lbs_pr_err("%s: fail, result=%d\n", __func__,
444			   le16_to_cpu(pcmdptr->result));
445		kfree(response_buf);
446		free_page(addr);
447		return 0;
448	}
449
450	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
451		lbs_pr_err("command response incorrect!\n");
452		kfree(response_buf);
453		free_page(addr);
454		return 0;
455	}
456
457	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
458	event = (void *)(response_buf + S_DS_GEN);
459	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
460		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
461		switch (header->type) {
462		struct mrvlietypes_rssithreshold  *Lowrssi;
463		case __constant_cpu_to_le16(TLV_TYPE_RSSI_LOW):
464			Lowrssi = (void *)(response_buf + cmd_len);
465			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
466					Lowrssi->rssivalue,
467					Lowrssi->rssifreq,
468					(event->events & cpu_to_le16(0x0001))?1:0);
469		default:
470			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
471			break;
472		}
473	}
474
475	kfree(response_buf);
476	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
477	free_page(addr);
478	return res;
479}
480
481static u16 libertas_get_events_bitmap(wlan_private *priv)
482{
483	wlan_adapter *adapter = priv->adapter;
484	struct cmd_ctrl_node *pcmdnode;
485	struct cmd_ds_command *pcmdptr;
486	struct cmd_ds_802_11_subscribe_event *event;
487	void *response_buf;
488	int res;
489	u16 event_bitmap;
490
491	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
492	if (res < 0)
493		return res;
494
495	event = &pcmdptr->params.subscribe_event;
496	event->action = cpu_to_le16(cmd_act_get);
497	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
498	libertas_queue_cmd(adapter, pcmdnode, 1);
499	wake_up_interruptible(&priv->mainthread.waitq);
500
501	/* Sleep until response is generated by FW */
502	wait_event_interruptible(pcmdnode->cmdwait_q,
503				 pcmdnode->cmdwaitqwoken);
504
505	pcmdptr = response_buf;
506
507	if (pcmdptr->result) {
508		lbs_pr_err("%s: fail, result=%d\n", __func__,
509			   le16_to_cpu(pcmdptr->result));
510		kfree(response_buf);
511		return 0;
512	}
513
514	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
515		lbs_pr_err("command response incorrect!\n");
516		kfree(response_buf);
517		return 0;
518	}
519
520	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
521	event_bitmap = le16_to_cpu(event->events);
522	kfree(response_buf);
523	return event_bitmap;
524}
525
526static ssize_t libertas_lowrssi_write(struct file *file,
527				    const char __user *userbuf,
528				    size_t count, loff_t *ppos)
529{
530	wlan_private *priv = file->private_data;
531	wlan_adapter *adapter = priv->adapter;
532	ssize_t res, buf_size;
533	int value, freq, subscribed, cmd_len;
534	struct cmd_ctrl_node *pcmdnode;
535	struct cmd_ds_command *pcmdptr;
536	struct cmd_ds_802_11_subscribe_event *event;
537	struct mrvlietypes_rssithreshold *rssi_threshold;
538	void *response_buf;
539	u16 event_bitmap;
540	u8 *ptr;
541	unsigned long addr = get_zeroed_page(GFP_KERNEL);
542	char *buf = (char *)addr;
543
544	buf_size = min(count, len - 1);
545	if (copy_from_user(buf, userbuf, buf_size)) {
546		res = -EFAULT;
547		goto out_unlock;
548	}
549	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
550	if (res != 3) {
551		res = -EFAULT;
552		goto out_unlock;
553	}
554
555	event_bitmap = libertas_get_events_bitmap(priv);
556
557	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
558	if (res < 0)
559		goto out_unlock;
560
561	event = &pcmdptr->params.subscribe_event;
562	event->action = cpu_to_le16(cmd_act_set);
563	pcmdptr->size = cpu_to_le16(S_DS_GEN +
564		sizeof(struct cmd_ds_802_11_subscribe_event) +
565		sizeof(struct mrvlietypes_rssithreshold));
566
567	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
568	ptr = (u8*) pcmdptr+cmd_len;
569	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
570	rssi_threshold->header.type = cpu_to_le16(0x0104);
571	rssi_threshold->header.len = cpu_to_le16(2);
572	rssi_threshold->rssivalue = value;
573	rssi_threshold->rssifreq = freq;
574	event_bitmap |= subscribed ? 0x0001 : 0x0;
575	event->events = cpu_to_le16(event_bitmap);
576
577	libertas_queue_cmd(adapter, pcmdnode, 1);
578	wake_up_interruptible(&priv->mainthread.waitq);
579
580	/* Sleep until response is generated by FW */
581	wait_event_interruptible(pcmdnode->cmdwait_q,
582				 pcmdnode->cmdwaitqwoken);
583
584	pcmdptr = response_buf;
585
586	if (pcmdptr->result) {
587		lbs_pr_err("%s: fail, result=%d\n", __func__,
588			   le16_to_cpu(pcmdptr->result));
589		kfree(response_buf);
590		free_page(addr);
591		return 0;
592	}
593
594	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
595		lbs_pr_err("command response incorrect!\n");
596		kfree(response_buf);
597		free_page(addr);
598		return 0;
599	}
600
601	res = count;
602out_unlock:
603	free_page(addr);
604	return res;
605}
606
607static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
608				  size_t count, loff_t *ppos)
609{
610	wlan_private *priv = file->private_data;
611	wlan_adapter *adapter = priv->adapter;
612	struct cmd_ctrl_node *pcmdnode;
613	struct cmd_ds_command *pcmdptr;
614	struct cmd_ds_802_11_subscribe_event *event;
615	void *response_buf;
616	int res, cmd_len;
617	ssize_t pos = 0;
618	unsigned long addr = get_zeroed_page(GFP_KERNEL);
619	char *buf = (char *)addr;
620
621	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
622	if (res < 0) {
623		free_page(addr);
624		return res;
625	}
626
627	event = &pcmdptr->params.subscribe_event;
628	event->action = cpu_to_le16(cmd_act_get);
629	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
630	libertas_queue_cmd(adapter, pcmdnode, 1);
631	wake_up_interruptible(&priv->mainthread.waitq);
632
633	/* Sleep until response is generated by FW */
634	wait_event_interruptible(pcmdnode->cmdwait_q,
635				 pcmdnode->cmdwaitqwoken);
636
637	pcmdptr = response_buf;
638
639	if (pcmdptr->result) {
640		lbs_pr_err("%s: fail, result=%d\n", __func__,
641			   le16_to_cpu(pcmdptr->result));
642		kfree(response_buf);
643		free_page(addr);
644		return 0;
645	}
646
647	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
648		lbs_pr_err("command response incorrect!\n");
649		kfree(response_buf);
650		free_page(addr);
651		return 0;
652	}
653
654	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
655	event = (void *)(response_buf + S_DS_GEN);
656	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
657		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
658		switch (header->type) {
659		struct mrvlietypes_snrthreshold *LowSnr;
660		case __constant_cpu_to_le16(TLV_TYPE_SNR_LOW):
661			LowSnr = (void *)(response_buf + cmd_len);
662			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
663					LowSnr->snrvalue,
664					LowSnr->snrfreq,
665					(event->events & cpu_to_le16(0x0002))?1:0);
666		default:
667			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
668			break;
669		}
670	}
671
672	kfree(response_buf);
673
674	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
675	free_page(addr);
676	return res;
677}
678
679static ssize_t libertas_lowsnr_write(struct file *file,
680				    const char __user *userbuf,
681				    size_t count, loff_t *ppos)
682{
683	wlan_private *priv = file->private_data;
684	wlan_adapter *adapter = priv->adapter;
685	ssize_t res, buf_size;
686	int value, freq, subscribed, cmd_len;
687	struct cmd_ctrl_node *pcmdnode;
688	struct cmd_ds_command *pcmdptr;
689	struct cmd_ds_802_11_subscribe_event *event;
690	struct mrvlietypes_snrthreshold *snr_threshold;
691	void *response_buf;
692	u16 event_bitmap;
693	u8 *ptr;
694	unsigned long addr = get_zeroed_page(GFP_KERNEL);
695	char *buf = (char *)addr;
696
697	buf_size = min(count, len - 1);
698	if (copy_from_user(buf, userbuf, buf_size)) {
699		res = -EFAULT;
700		goto out_unlock;
701	}
702	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
703	if (res != 3) {
704		res = -EFAULT;
705		goto out_unlock;
706	}
707
708	event_bitmap = libertas_get_events_bitmap(priv);
709
710	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
711	if (res < 0)
712		goto out_unlock;
713
714	event = &pcmdptr->params.subscribe_event;
715	event->action = cpu_to_le16(cmd_act_set);
716	pcmdptr->size = cpu_to_le16(S_DS_GEN +
717		sizeof(struct cmd_ds_802_11_subscribe_event) +
718		sizeof(struct mrvlietypes_snrthreshold));
719	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
720	ptr = (u8*) pcmdptr+cmd_len;
721	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
722	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
723	snr_threshold->header.len = cpu_to_le16(2);
724	snr_threshold->snrvalue = value;
725	snr_threshold->snrfreq = freq;
726	event_bitmap |= subscribed ? 0x0002 : 0x0;
727	event->events = cpu_to_le16(event_bitmap);
728
729	libertas_queue_cmd(adapter, pcmdnode, 1);
730	wake_up_interruptible(&priv->mainthread.waitq);
731
732	/* Sleep until response is generated by FW */
733	wait_event_interruptible(pcmdnode->cmdwait_q,
734				 pcmdnode->cmdwaitqwoken);
735
736	pcmdptr = response_buf;
737
738	if (pcmdptr->result) {
739		lbs_pr_err("%s: fail, result=%d\n", __func__,
740			   le16_to_cpu(pcmdptr->result));
741		kfree(response_buf);
742		free_page(addr);
743		return 0;
744	}
745
746	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
747		lbs_pr_err("command response incorrect!\n");
748		kfree(response_buf);
749		free_page(addr);
750		return 0;
751	}
752
753	res = count;
754
755out_unlock:
756	free_page(addr);
757	return res;
758}
759
760static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
761				  size_t count, loff_t *ppos)
762{
763	wlan_private *priv = file->private_data;
764	wlan_adapter *adapter = priv->adapter;
765	struct cmd_ctrl_node *pcmdnode;
766	struct cmd_ds_command *pcmdptr;
767	struct cmd_ds_802_11_subscribe_event *event;
768	void *response_buf;
769	int res, cmd_len;
770	ssize_t pos = 0;
771	unsigned long addr = get_zeroed_page(GFP_KERNEL);
772	char *buf = (char *)addr;
773
774	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
775	if (res < 0) {
776		free_page(addr);
777		return res;
778	}
779
780	event = &pcmdptr->params.subscribe_event;
781	event->action = cpu_to_le16(cmd_act_get);
782	pcmdptr->size =	cpu_to_le16(sizeof(*event) + S_DS_GEN);
783	libertas_queue_cmd(adapter, pcmdnode, 1);
784	wake_up_interruptible(&priv->mainthread.waitq);
785
786	/* Sleep until response is generated by FW */
787	wait_event_interruptible(pcmdnode->cmdwait_q,
788				 pcmdnode->cmdwaitqwoken);
789
790	pcmdptr = response_buf;
791
792	if (pcmdptr->result) {
793		lbs_pr_err("%s: fail, result=%d\n", __func__,
794			   le16_to_cpu(pcmdptr->result));
795		kfree(response_buf);
796		free_page(addr);
797		return 0;
798	}
799
800	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
801		lbs_pr_err("command response incorrect!\n");
802		kfree(response_buf);
803		free_page(addr);
804		return 0;
805	}
806
807	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
808	event = (void *)(response_buf + S_DS_GEN);
809	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
810		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
811		switch (header->type) {
812		struct mrvlietypes_failurecount *failcount;
813		case __constant_cpu_to_le16(TLV_TYPE_FAILCOUNT):
814			failcount = (void *)(response_buf + cmd_len);
815			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
816					failcount->failvalue,
817					failcount->Failfreq,
818					(event->events & cpu_to_le16(0x0004))?1:0);
819		default:
820			cmd_len += sizeof(struct mrvlietypes_failurecount);
821			break;
822		}
823	}
824
825	kfree(response_buf);
826	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
827	free_page(addr);
828	return res;
829}
830
831static ssize_t libertas_failcount_write(struct file *file,
832				    const char __user *userbuf,
833				    size_t count, loff_t *ppos)
834{
835	wlan_private *priv = file->private_data;
836	wlan_adapter *adapter = priv->adapter;
837	ssize_t res, buf_size;
838	int value, freq, subscribed, cmd_len;
839	struct cmd_ctrl_node *pcmdnode;
840	struct cmd_ds_command *pcmdptr;
841	struct cmd_ds_802_11_subscribe_event *event;
842	struct mrvlietypes_failurecount *failcount;
843	void *response_buf;
844	u16 event_bitmap;
845	u8 *ptr;
846	unsigned long addr = get_zeroed_page(GFP_KERNEL);
847	char *buf = (char *)addr;
848
849	buf_size = min(count, len - 1);
850	if (copy_from_user(buf, userbuf, buf_size)) {
851		res = -EFAULT;
852		goto out_unlock;
853	}
854	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
855	if (res != 3) {
856		res = -EFAULT;
857		goto out_unlock;
858	}
859
860	event_bitmap = libertas_get_events_bitmap(priv);
861
862	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
863	if (res < 0)
864		goto out_unlock;
865
866	event = &pcmdptr->params.subscribe_event;
867	event->action = cpu_to_le16(cmd_act_set);
868	pcmdptr->size = cpu_to_le16(S_DS_GEN +
869		sizeof(struct cmd_ds_802_11_subscribe_event) +
870		sizeof(struct mrvlietypes_failurecount));
871	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
872	ptr = (u8*) pcmdptr+cmd_len;
873	failcount = (struct mrvlietypes_failurecount *)(ptr);
874	failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
875	failcount->header.len = cpu_to_le16(2);
876	failcount->failvalue = value;
877	failcount->Failfreq = freq;
878	event_bitmap |= subscribed ? 0x0004 : 0x0;
879	event->events = cpu_to_le16(event_bitmap);
880
881	libertas_queue_cmd(adapter, pcmdnode, 1);
882	wake_up_interruptible(&priv->mainthread.waitq);
883
884	/* Sleep until response is generated by FW */
885	wait_event_interruptible(pcmdnode->cmdwait_q,
886				 pcmdnode->cmdwaitqwoken);
887
888	pcmdptr = (struct cmd_ds_command *)response_buf;
889
890	if (pcmdptr->result) {
891		lbs_pr_err("%s: fail, result=%d\n", __func__,
892			   le16_to_cpu(pcmdptr->result));
893		kfree(response_buf);
894		free_page(addr);
895		return 0;
896	}
897
898	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
899		lbs_pr_err("command response incorrect!\n");
900		kfree(response_buf);
901		free_page(addr);
902		return 0;
903	}
904
905	res = count;
906out_unlock:
907	free_page(addr);
908	return res;
909}
910
911static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
912				  size_t count, loff_t *ppos)
913{
914	wlan_private *priv = file->private_data;
915	wlan_adapter *adapter = priv->adapter;
916	struct cmd_ctrl_node *pcmdnode;
917	struct cmd_ds_command *pcmdptr;
918	struct cmd_ds_802_11_subscribe_event *event;
919	void *response_buf;
920	int res, cmd_len;
921	ssize_t pos = 0;
922	unsigned long addr = get_zeroed_page(GFP_KERNEL);
923	char *buf = (char *)addr;
924
925	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
926	if (res < 0) {
927		free_page(addr);
928		return res;
929	}
930
931	event = &pcmdptr->params.subscribe_event;
932	event->action = cpu_to_le16(cmd_act_get);
933	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
934	libertas_queue_cmd(adapter, pcmdnode, 1);
935	wake_up_interruptible(&priv->mainthread.waitq);
936
937	/* Sleep until response is generated by FW */
938	wait_event_interruptible(pcmdnode->cmdwait_q,
939				 pcmdnode->cmdwaitqwoken);
940
941	pcmdptr = response_buf;
942
943	if (pcmdptr->result) {
944		lbs_pr_err("%s: fail, result=%d\n", __func__,
945			   le16_to_cpu(pcmdptr->result));
946		free_page(addr);
947		kfree(response_buf);
948		return 0;
949	}
950
951	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
952		lbs_pr_err("command response incorrect!\n");
953		free_page(addr);
954		kfree(response_buf);
955		return 0;
956	}
957
958	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
959	event = (void *)(response_buf + S_DS_GEN);
960	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
961		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
962		switch (header->type) {
963		struct mrvlietypes_beaconsmissed *bcnmiss;
964		case __constant_cpu_to_le16(TLV_TYPE_BCNMISS):
965			bcnmiss = (void *)(response_buf + cmd_len);
966			pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
967					bcnmiss->beaconmissed,
968					(event->events & cpu_to_le16(0x0008))?1:0);
969		default:
970			cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
971			break;
972		}
973	}
974
975	kfree(response_buf);
976
977	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
978	free_page(addr);
979	return res;
980}
981
982static ssize_t libertas_bcnmiss_write(struct file *file,
983				    const char __user *userbuf,
984				    size_t count, loff_t *ppos)
985{
986	wlan_private *priv = file->private_data;
987	wlan_adapter *adapter = priv->adapter;
988	ssize_t res, buf_size;
989	int value, freq, subscribed, cmd_len;
990	struct cmd_ctrl_node *pcmdnode;
991	struct cmd_ds_command *pcmdptr;
992	struct cmd_ds_802_11_subscribe_event *event;
993	struct mrvlietypes_beaconsmissed *bcnmiss;
994	void *response_buf;
995	u16 event_bitmap;
996	u8 *ptr;
997	unsigned long addr = get_zeroed_page(GFP_KERNEL);
998	char *buf = (char *)addr;
999
1000	buf_size = min(count, len - 1);
1001	if (copy_from_user(buf, userbuf, buf_size)) {
1002		res = -EFAULT;
1003		goto out_unlock;
1004	}
1005	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1006	if (res != 3) {
1007		res = -EFAULT;
1008		goto out_unlock;
1009	}
1010
1011	event_bitmap = libertas_get_events_bitmap(priv);
1012
1013	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1014	if (res < 0)
1015		goto out_unlock;
1016
1017	event = &pcmdptr->params.subscribe_event;
1018	event->action = cpu_to_le16(cmd_act_set);
1019	pcmdptr->size = cpu_to_le16(S_DS_GEN +
1020		sizeof(struct cmd_ds_802_11_subscribe_event) +
1021		sizeof(struct mrvlietypes_beaconsmissed));
1022	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1023	ptr = (u8*) pcmdptr+cmd_len;
1024	bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
1025	bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
1026	bcnmiss->header.len = cpu_to_le16(2);
1027	bcnmiss->beaconmissed = value;
1028	event_bitmap |= subscribed ? 0x0008 : 0x0;
1029	event->events = cpu_to_le16(event_bitmap);
1030
1031	libertas_queue_cmd(adapter, pcmdnode, 1);
1032	wake_up_interruptible(&priv->mainthread.waitq);
1033
1034	/* Sleep until response is generated by FW */
1035	wait_event_interruptible(pcmdnode->cmdwait_q,
1036				 pcmdnode->cmdwaitqwoken);
1037
1038	pcmdptr = response_buf;
1039
1040	if (pcmdptr->result) {
1041		lbs_pr_err("%s: fail, result=%d\n", __func__,
1042			   le16_to_cpu(pcmdptr->result));
1043		kfree(response_buf);
1044		free_page(addr);
1045		return 0;
1046	}
1047
1048	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
1049		lbs_pr_err("command response incorrect!\n");
1050		free_page(addr);
1051		kfree(response_buf);
1052		return 0;
1053	}
1054
1055	res = count;
1056out_unlock:
1057	free_page(addr);
1058	return res;
1059}
1060
1061static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
1062				  size_t count, loff_t *ppos)
1063{
1064	wlan_private *priv = file->private_data;
1065	wlan_adapter *adapter = priv->adapter;
1066	struct cmd_ctrl_node *pcmdnode;
1067	struct cmd_ds_command *pcmdptr;
1068	struct cmd_ds_802_11_subscribe_event *event;
1069	void *response_buf;
1070	int res, cmd_len;
1071	ssize_t pos = 0;
1072	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1073	char *buf = (char *)addr;
1074
1075	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1076	if (res < 0) {
1077		free_page(addr);
1078		return res;
1079	}
1080
1081	event = &pcmdptr->params.subscribe_event;
1082	event->action = cpu_to_le16(cmd_act_get);
1083	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
1084	libertas_queue_cmd(adapter, pcmdnode, 1);
1085	wake_up_interruptible(&priv->mainthread.waitq);
1086
1087	/* Sleep until response is generated by FW */
1088	wait_event_interruptible(pcmdnode->cmdwait_q,
1089				 pcmdnode->cmdwaitqwoken);
1090
1091	pcmdptr = response_buf;
1092
1093	if (pcmdptr->result) {
1094		lbs_pr_err("%s: fail, result=%d\n", __func__,
1095			   le16_to_cpu(pcmdptr->result));
1096		kfree(response_buf);
1097		free_page(addr);
1098		return 0;
1099	}
1100
1101	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
1102		lbs_pr_err("command response incorrect!\n");
1103		kfree(response_buf);
1104		free_page(addr);
1105		return 0;
1106	}
1107
1108	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1109	event = (void *)(response_buf + S_DS_GEN);
1110	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
1111		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
1112		switch (header->type) {
1113		struct mrvlietypes_rssithreshold  *Highrssi;
1114		case __constant_cpu_to_le16(TLV_TYPE_RSSI_HIGH):
1115			Highrssi = (void *)(response_buf + cmd_len);
1116			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
1117					Highrssi->rssivalue,
1118					Highrssi->rssifreq,
1119					(event->events & cpu_to_le16(0x0010))?1:0);
1120		default:
1121			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
1122			break;
1123		}
1124	}
1125
1126	kfree(response_buf);
1127
1128	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1129	free_page(addr);
1130	return res;
1131}
1132
1133static ssize_t libertas_highrssi_write(struct file *file,
1134				    const char __user *userbuf,
1135				    size_t count, loff_t *ppos)
1136{
1137	wlan_private *priv = file->private_data;
1138	wlan_adapter *adapter = priv->adapter;
1139	ssize_t res, buf_size;
1140	int value, freq, subscribed, cmd_len;
1141	struct cmd_ctrl_node *pcmdnode;
1142	struct cmd_ds_command *pcmdptr;
1143	struct cmd_ds_802_11_subscribe_event *event;
1144	struct mrvlietypes_rssithreshold *rssi_threshold;
1145	void *response_buf;
1146	u16 event_bitmap;
1147	u8 *ptr;
1148	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1149	char *buf = (char *)addr;
1150
1151	buf_size = min(count, len - 1);
1152	if (copy_from_user(buf, userbuf, buf_size)) {
1153		res = -EFAULT;
1154		goto out_unlock;
1155	}
1156	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1157	if (res != 3) {
1158		res = -EFAULT;
1159		goto out_unlock;
1160	}
1161
1162	event_bitmap = libertas_get_events_bitmap(priv);
1163
1164	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1165	if (res < 0)
1166		goto out_unlock;
1167
1168	event = &pcmdptr->params.subscribe_event;
1169	event->action = cpu_to_le16(cmd_act_set);
1170	pcmdptr->size = cpu_to_le16(S_DS_GEN +
1171		sizeof(struct cmd_ds_802_11_subscribe_event) +
1172		sizeof(struct mrvlietypes_rssithreshold));
1173	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1174	ptr = (u8*) pcmdptr+cmd_len;
1175	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
1176	rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
1177	rssi_threshold->header.len = cpu_to_le16(2);
1178	rssi_threshold->rssivalue = value;
1179	rssi_threshold->rssifreq = freq;
1180	event_bitmap |= subscribed ? 0x0010 : 0x0;
1181	event->events = cpu_to_le16(event_bitmap);
1182
1183	libertas_queue_cmd(adapter, pcmdnode, 1);
1184	wake_up_interruptible(&priv->mainthread.waitq);
1185
1186	/* Sleep until response is generated by FW */
1187	wait_event_interruptible(pcmdnode->cmdwait_q,
1188				 pcmdnode->cmdwaitqwoken);
1189
1190	pcmdptr = response_buf;
1191
1192	if (pcmdptr->result) {
1193		lbs_pr_err("%s: fail, result=%d\n", __func__,
1194			   le16_to_cpu(pcmdptr->result));
1195		kfree(response_buf);
1196		return 0;
1197	}
1198
1199	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
1200		lbs_pr_err("command response incorrect!\n");
1201		kfree(response_buf);
1202		return 0;
1203	}
1204
1205	res = count;
1206out_unlock:
1207	free_page(addr);
1208	return res;
1209}
1210
1211static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
1212				  size_t count, loff_t *ppos)
1213{
1214	wlan_private *priv = file->private_data;
1215	wlan_adapter *adapter = priv->adapter;
1216	struct cmd_ctrl_node *pcmdnode;
1217	struct cmd_ds_command *pcmdptr;
1218	struct cmd_ds_802_11_subscribe_event *event;
1219	void *response_buf;
1220	int res, cmd_len;
1221	ssize_t pos = 0;
1222	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1223	char *buf = (char *)addr;
1224
1225	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1226	if (res < 0) {
1227		free_page(addr);
1228		return res;
1229	}
1230
1231	event = &pcmdptr->params.subscribe_event;
1232	event->action = cpu_to_le16(cmd_act_get);
1233	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
1234	libertas_queue_cmd(adapter, pcmdnode, 1);
1235	wake_up_interruptible(&priv->mainthread.waitq);
1236
1237	/* Sleep until response is generated by FW */
1238	wait_event_interruptible(pcmdnode->cmdwait_q,
1239				 pcmdnode->cmdwaitqwoken);
1240
1241	pcmdptr = response_buf;
1242
1243	if (pcmdptr->result) {
1244		lbs_pr_err("%s: fail, result=%d\n", __func__,
1245			   le16_to_cpu(pcmdptr->result));
1246		kfree(response_buf);
1247		free_page(addr);
1248		return 0;
1249	}
1250
1251	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
1252		lbs_pr_err("command response incorrect!\n");
1253		kfree(response_buf);
1254		free_page(addr);
1255		return 0;
1256	}
1257
1258	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1259	event = (void *)(response_buf + S_DS_GEN);
1260	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
1261		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
1262		switch (header->type) {
1263		struct mrvlietypes_snrthreshold *HighSnr;
1264		case __constant_cpu_to_le16(TLV_TYPE_SNR_HIGH):
1265			HighSnr = (void *)(response_buf + cmd_len);
1266			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
1267					HighSnr->snrvalue,
1268					HighSnr->snrfreq,
1269					(event->events & cpu_to_le16(0x0020))?1:0);
1270		default:
1271			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
1272			break;
1273		}
1274	}
1275
1276	kfree(response_buf);
1277
1278	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1279	free_page(addr);
1280	return res;
1281}
1282
1283static ssize_t libertas_highsnr_write(struct file *file,
1284				    const char __user *userbuf,
1285				    size_t count, loff_t *ppos)
1286{
1287	wlan_private *priv = file->private_data;
1288	wlan_adapter *adapter = priv->adapter;
1289	ssize_t res, buf_size;
1290	int value, freq, subscribed, cmd_len;
1291	struct cmd_ctrl_node *pcmdnode;
1292	struct cmd_ds_command *pcmdptr;
1293	struct cmd_ds_802_11_subscribe_event *event;
1294	struct mrvlietypes_snrthreshold *snr_threshold;
1295	void *response_buf;
1296	u16 event_bitmap;
1297	u8 *ptr;
1298	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1299	char *buf = (char *)addr;
1300
1301	buf_size = min(count, len - 1);
1302	if (copy_from_user(buf, userbuf, buf_size)) {
1303		res = -EFAULT;
1304		goto out_unlock;
1305	}
1306	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
1307	if (res != 3) {
1308		res = -EFAULT;
1309		goto out_unlock;
1310	}
1311
1312	event_bitmap = libertas_get_events_bitmap(priv);
1313
1314	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
1315	if (res < 0)
1316		goto out_unlock;
1317
1318	event = &pcmdptr->params.subscribe_event;
1319	event->action = cpu_to_le16(cmd_act_set);
1320	pcmdptr->size = cpu_to_le16(S_DS_GEN +
1321		sizeof(struct cmd_ds_802_11_subscribe_event) +
1322		sizeof(struct mrvlietypes_snrthreshold));
1323	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
1324	ptr = (u8*) pcmdptr+cmd_len;
1325	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
1326	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
1327	snr_threshold->header.len = cpu_to_le16(2);
1328	snr_threshold->snrvalue = value;
1329	snr_threshold->snrfreq = freq;
1330	event_bitmap |= subscribed ? 0x0020 : 0x0;
1331	event->events = cpu_to_le16(event_bitmap);
1332
1333	libertas_queue_cmd(adapter, pcmdnode, 1);
1334	wake_up_interruptible(&priv->mainthread.waitq);
1335
1336	/* Sleep until response is generated by FW */
1337	wait_event_interruptible(pcmdnode->cmdwait_q,
1338				 pcmdnode->cmdwaitqwoken);
1339
1340	pcmdptr = response_buf;
1341
1342	if (pcmdptr->result) {
1343		lbs_pr_err("%s: fail, result=%d\n", __func__,
1344			   le16_to_cpu(pcmdptr->result));
1345		kfree(response_buf);
1346		free_page(addr);
1347		return 0;
1348	}
1349
1350	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
1351		lbs_pr_err("command response incorrect!\n");
1352		kfree(response_buf);
1353		free_page(addr);
1354		return 0;
1355	}
1356
1357	res = count;
1358out_unlock:
1359	free_page(addr);
1360	return res;
1361}
1362
1363static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
1364				  size_t count, loff_t *ppos)
1365{
1366	wlan_private *priv = file->private_data;
1367	wlan_adapter *adapter = priv->adapter;
1368	struct wlan_offset_value offval;
1369	ssize_t pos = 0;
1370	int ret;
1371	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1372	char *buf = (char *)addr;
1373
1374	offval.offset = priv->mac_offset;
1375	offval.value = 0;
1376
1377	ret = libertas_prepare_and_send_command(priv,
1378				cmd_mac_reg_access, 0,
1379				cmd_option_waitforrsp, 0, &offval);
1380	mdelay(10);
1381	pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
1382				priv->mac_offset, adapter->offsetvalue.value);
1383
1384	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1385	free_page(addr);
1386	return ret;
1387}
1388
1389static ssize_t libertas_rdmac_write(struct file *file,
1390				    const char __user *userbuf,
1391				    size_t count, loff_t *ppos)
1392{
1393	wlan_private *priv = file->private_data;
1394	ssize_t res, buf_size;
1395	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1396	char *buf = (char *)addr;
1397
1398	buf_size = min(count, len - 1);
1399	if (copy_from_user(buf, userbuf, buf_size)) {
1400		res = -EFAULT;
1401		goto out_unlock;
1402	}
1403	priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
1404	res = count;
1405out_unlock:
1406	free_page(addr);
1407	return res;
1408}
1409
1410static ssize_t libertas_wrmac_write(struct file *file,
1411				    const char __user *userbuf,
1412				    size_t count, loff_t *ppos)
1413{
1414
1415	wlan_private *priv = file->private_data;
1416	ssize_t res, buf_size;
1417	u32 offset, value;
1418	struct wlan_offset_value offval;
1419	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1420	char *buf = (char *)addr;
1421
1422	buf_size = min(count, len - 1);
1423	if (copy_from_user(buf, userbuf, buf_size)) {
1424		res = -EFAULT;
1425		goto out_unlock;
1426	}
1427	res = sscanf(buf, "%x %x", &offset, &value);
1428	if (res != 2) {
1429		res = -EFAULT;
1430		goto out_unlock;
1431	}
1432
1433	offval.offset = offset;
1434	offval.value = value;
1435	res = libertas_prepare_and_send_command(priv,
1436				cmd_mac_reg_access, 1,
1437				cmd_option_waitforrsp, 0, &offval);
1438	mdelay(10);
1439
1440	res = count;
1441out_unlock:
1442	free_page(addr);
1443	return res;
1444}
1445
1446static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
1447				  size_t count, loff_t *ppos)
1448{
1449	wlan_private *priv = file->private_data;
1450	wlan_adapter *adapter = priv->adapter;
1451	struct wlan_offset_value offval;
1452	ssize_t pos = 0;
1453	int ret;
1454	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1455	char *buf = (char *)addr;
1456
1457	offval.offset = priv->bbp_offset;
1458	offval.value = 0;
1459
1460	ret = libertas_prepare_and_send_command(priv,
1461				cmd_bbp_reg_access, 0,
1462				cmd_option_waitforrsp, 0, &offval);
1463	mdelay(10);
1464	pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
1465				priv->bbp_offset, adapter->offsetvalue.value);
1466
1467	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1468	free_page(addr);
1469
1470	return ret;
1471}
1472
1473static ssize_t libertas_rdbbp_write(struct file *file,
1474				    const char __user *userbuf,
1475				    size_t count, loff_t *ppos)
1476{
1477	wlan_private *priv = file->private_data;
1478	ssize_t res, buf_size;
1479	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1480	char *buf = (char *)addr;
1481
1482	buf_size = min(count, len - 1);
1483	if (copy_from_user(buf, userbuf, buf_size)) {
1484		res = -EFAULT;
1485		goto out_unlock;
1486	}
1487	priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
1488	res = count;
1489out_unlock:
1490	free_page(addr);
1491	return res;
1492}
1493
1494static ssize_t libertas_wrbbp_write(struct file *file,
1495				    const char __user *userbuf,
1496				    size_t count, loff_t *ppos)
1497{
1498
1499	wlan_private *priv = file->private_data;
1500	ssize_t res, buf_size;
1501	u32 offset, value;
1502	struct wlan_offset_value offval;
1503	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1504	char *buf = (char *)addr;
1505
1506	buf_size = min(count, len - 1);
1507	if (copy_from_user(buf, userbuf, buf_size)) {
1508		res = -EFAULT;
1509		goto out_unlock;
1510	}
1511	res = sscanf(buf, "%x %x", &offset, &value);
1512	if (res != 2) {
1513		res = -EFAULT;
1514		goto out_unlock;
1515	}
1516
1517	offval.offset = offset;
1518	offval.value = value;
1519	res = libertas_prepare_and_send_command(priv,
1520				cmd_bbp_reg_access, 1,
1521				cmd_option_waitforrsp, 0, &offval);
1522	mdelay(10);
1523
1524	res = count;
1525out_unlock:
1526	free_page(addr);
1527	return res;
1528}
1529
1530static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
1531				  size_t count, loff_t *ppos)
1532{
1533	wlan_private *priv = file->private_data;
1534	wlan_adapter *adapter = priv->adapter;
1535	struct wlan_offset_value offval;
1536	ssize_t pos = 0;
1537	int ret;
1538	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1539	char *buf = (char *)addr;
1540
1541	offval.offset = priv->rf_offset;
1542	offval.value = 0;
1543
1544	ret = libertas_prepare_and_send_command(priv,
1545				cmd_rf_reg_access, 0,
1546				cmd_option_waitforrsp, 0, &offval);
1547	mdelay(10);
1548	pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
1549				priv->rf_offset, adapter->offsetvalue.value);
1550
1551	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1552	free_page(addr);
1553
1554	return ret;
1555}
1556
1557static ssize_t libertas_rdrf_write(struct file *file,
1558				    const char __user *userbuf,
1559				    size_t count, loff_t *ppos)
1560{
1561	wlan_private *priv = file->private_data;
1562	ssize_t res, buf_size;
1563	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1564	char *buf = (char *)addr;
1565
1566	buf_size = min(count, len - 1);
1567	if (copy_from_user(buf, userbuf, buf_size)) {
1568		res = -EFAULT;
1569		goto out_unlock;
1570	}
1571	priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
1572	res = count;
1573out_unlock:
1574	free_page(addr);
1575	return res;
1576}
1577
1578static ssize_t libertas_wrrf_write(struct file *file,
1579				    const char __user *userbuf,
1580				    size_t count, loff_t *ppos)
1581{
1582
1583	wlan_private *priv = file->private_data;
1584	ssize_t res, buf_size;
1585	u32 offset, value;
1586	struct wlan_offset_value offval;
1587	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1588	char *buf = (char *)addr;
1589
1590	buf_size = min(count, len - 1);
1591	if (copy_from_user(buf, userbuf, buf_size)) {
1592		res = -EFAULT;
1593		goto out_unlock;
1594	}
1595	res = sscanf(buf, "%x %x", &offset, &value);
1596	if (res != 2) {
1597		res = -EFAULT;
1598		goto out_unlock;
1599	}
1600
1601	offval.offset = offset;
1602	offval.value = value;
1603	res = libertas_prepare_and_send_command(priv,
1604				cmd_rf_reg_access, 1,
1605				cmd_option_waitforrsp, 0, &offval);
1606	mdelay(10);
1607
1608	res = count;
1609out_unlock:
1610	free_page(addr);
1611	return res;
1612}
1613
1614#define FOPS(fread, fwrite) { \
1615	.owner = THIS_MODULE, \
1616	.open = open_file_generic, \
1617	.read = (fread), \
1618	.write = (fwrite), \
1619}
1620
1621struct libertas_debugfs_files {
1622	char *name;
1623	int perm;
1624	struct file_operations fops;
1625};
1626
1627static struct libertas_debugfs_files debugfs_files[] = {
1628	{ "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
1629	{ "getscantable", 0444, FOPS(libertas_getscantable,
1630					write_file_dummy), },
1631	{ "sleepparams", 0644, FOPS(libertas_sleepparams_read,
1632				libertas_sleepparams_write), },
1633	{ "extscan", 0600, FOPS(NULL, libertas_extscan), },
1634	{ "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
1635};
1636
1637static struct libertas_debugfs_files debugfs_events_files[] = {
1638	{"low_rssi", 0644, FOPS(libertas_lowrssi_read,
1639				libertas_lowrssi_write), },
1640	{"low_snr", 0644, FOPS(libertas_lowsnr_read,
1641				libertas_lowsnr_write), },
1642	{"failure_count", 0644, FOPS(libertas_failcount_read,
1643				libertas_failcount_write), },
1644	{"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
1645				libertas_bcnmiss_write), },
1646	{"high_rssi", 0644, FOPS(libertas_highrssi_read,
1647				libertas_highrssi_write), },
1648	{"high_snr", 0644, FOPS(libertas_highsnr_read,
1649				libertas_highsnr_write), },
1650};
1651
1652static struct libertas_debugfs_files debugfs_regs_files[] = {
1653	{"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
1654	{"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
1655	{"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
1656	{"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
1657	{"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
1658	{"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
1659};
1660
1661void libertas_debugfs_init(void)
1662{
1663	if (!libertas_dir)
1664		libertas_dir = debugfs_create_dir("libertas_wireless", NULL);
1665
1666	return;
1667}
1668
1669void libertas_debugfs_remove(void)
1670{
1671	if (libertas_dir)
1672		 debugfs_remove(libertas_dir);
1673	return;
1674}
1675
1676void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
1677{
1678	int i;
1679	struct libertas_debugfs_files *files;
1680	if (!libertas_dir)
1681		goto exit;
1682
1683	priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
1684	if (!priv->debugfs_dir)
1685		goto exit;
1686
1687	for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
1688		files = &debugfs_files[i];
1689		priv->debugfs_files[i] = debugfs_create_file(files->name,
1690							     files->perm,
1691							     priv->debugfs_dir,
1692							     priv,
1693							     &files->fops);
1694	}
1695
1696	priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
1697	if (!priv->events_dir)
1698		goto exit;
1699
1700	for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
1701		files = &debugfs_events_files[i];
1702		priv->debugfs_events_files[i] = debugfs_create_file(files->name,
1703							     files->perm,
1704							     priv->events_dir,
1705							     priv,
1706							     &files->fops);
1707	}
1708
1709	priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
1710	if (!priv->regs_dir)
1711		goto exit;
1712
1713	for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
1714		files = &debugfs_regs_files[i];
1715		priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
1716							     files->perm,
1717							     priv->regs_dir,
1718							     priv,
1719							     &files->fops);
1720	}
1721
1722#ifdef PROC_DEBUG
1723	libertas_debug_init(priv, dev);
1724#endif
1725exit:
1726	return;
1727}
1728
1729void libertas_debugfs_remove_one(wlan_private *priv)
1730{
1731	int i;
1732
1733	for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
1734		debugfs_remove(priv->debugfs_regs_files[i]);
1735
1736	debugfs_remove(priv->regs_dir);
1737
1738	for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
1739		debugfs_remove(priv->debugfs_events_files[i]);
1740
1741	debugfs_remove(priv->events_dir);
1742#ifdef PROC_DEBUG
1743	debugfs_remove(priv->debugfs_debug);
1744#endif
1745	for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
1746		debugfs_remove(priv->debugfs_files[i]);
1747	debugfs_remove(priv->debugfs_dir);
1748}
1749
1750
1751
1752/* debug entry */
1753
1754#ifdef PROC_DEBUG
1755
1756#define item_size(n)	(FIELD_SIZEOF(wlan_adapter, n))
1757#define item_addr(n)	(offsetof(wlan_adapter, n))
1758
1759
1760struct debug_data {
1761	char name[32];
1762	u32 size;
1763	size_t addr;
1764};
1765
1766/* To debug any member of wlan_adapter, simply add one line here.
1767 */
1768static struct debug_data items[] = {
1769	{"intcounter", item_size(intcounter), item_addr(intcounter)},
1770	{"psmode", item_size(psmode), item_addr(psmode)},
1771	{"psstate", item_size(psstate), item_addr(psstate)},
1772};
1773
1774static int num_of_items = ARRAY_SIZE(items);
1775
1776/**
1777 *  @brief proc read function
1778 *
1779 *  @param page	   pointer to buffer
1780 *  @param s       read data starting position
1781 *  @param off     offset
1782 *  @param cnt     counter
1783 *  @param eof     end of file flag
1784 *  @param data    data to output
1785 *  @return 	   number of output data
1786 */
1787static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
1788			size_t count, loff_t *ppos)
1789{
1790	int val = 0;
1791	size_t pos = 0;
1792	ssize_t res;
1793	char *p;
1794	int i;
1795	struct debug_data *d;
1796	unsigned long addr = get_zeroed_page(GFP_KERNEL);
1797	char *buf = (char *)addr;
1798
1799	p = buf;
1800
1801	d = (struct debug_data *)file->private_data;
1802
1803	for (i = 0; i < num_of_items; i++) {
1804		if (d[i].size == 1)
1805			val = *((u8 *) d[i].addr);
1806		else if (d[i].size == 2)
1807			val = *((u16 *) d[i].addr);
1808		else if (d[i].size == 4)
1809			val = *((u32 *) d[i].addr);
1810		else if (d[i].size == 8)
1811			val = *((u64 *) d[i].addr);
1812
1813		pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
1814	}
1815
1816	res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
1817
1818	free_page(addr);
1819	return res;
1820}
1821
1822/**
1823 *  @brief proc write function
1824 *
1825 *  @param f	   file pointer
1826 *  @param buf     pointer to data buffer
1827 *  @param cnt     data number to write
1828 *  @param data    data to write
1829 *  @return 	   number of data
1830 */
1831static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf,
1832			    size_t cnt, loff_t *ppos)
1833{
1834	int r, i;
1835	char *pdata;
1836	char *p;
1837	char *p0;
1838	char *p1;
1839	char *p2;
1840	struct debug_data *d = (struct debug_data *)f->private_data;
1841
1842	pdata = (char *)kmalloc(cnt, GFP_KERNEL);
1843	if (pdata == NULL)
1844		return 0;
1845
1846	if (copy_from_user(pdata, buf, cnt)) {
1847		lbs_deb_debugfs("Copy from user failed\n");
1848		kfree(pdata);
1849		return 0;
1850	}
1851
1852	p0 = pdata;
1853	for (i = 0; i < num_of_items; i++) {
1854		do {
1855			p = strstr(p0, d[i].name);
1856			if (p == NULL)
1857				break;
1858			p1 = strchr(p, '\n');
1859			if (p1 == NULL)
1860				break;
1861			p0 = p1++;
1862			p2 = strchr(p, '=');
1863			if (!p2)
1864				break;
1865			p2++;
1866			r = simple_strtoul(p2, NULL, 0);
1867			if (d[i].size == 1)
1868				*((u8 *) d[i].addr) = (u8) r;
1869			else if (d[i].size == 2)
1870				*((u16 *) d[i].addr) = (u16) r;
1871			else if (d[i].size == 4)
1872				*((u32 *) d[i].addr) = (u32) r;
1873			else if (d[i].size == 8)
1874				*((u64 *) d[i].addr) = (u64) r;
1875			break;
1876		} while (1);
1877	}
1878	kfree(pdata);
1879
1880	return (ssize_t)cnt;
1881}
1882
1883static struct file_operations libertas_debug_fops = {
1884	.owner = THIS_MODULE,
1885	.open = open_file_generic,
1886	.write = wlan_debugfs_write,
1887	.read = wlan_debugfs_read,
1888};
1889
1890/**
1891 *  @brief create debug proc file
1892 *
1893 *  @param priv	   pointer wlan_private
1894 *  @param dev     pointer net_device
1895 *  @return 	   N/A
1896 */
1897static void libertas_debug_init(wlan_private * priv, struct net_device *dev)
1898{
1899	int i;
1900
1901	if (!priv->debugfs_dir)
1902		return;
1903
1904	for (i = 0; i < num_of_items; i++)
1905		items[i].addr += (size_t) priv->adapter;
1906
1907	priv->debugfs_debug = debugfs_create_file("debug", 0644,
1908						  priv->debugfs_dir, &items[0],
1909						  &libertas_debug_fops);
1910}
1911#endif
1912