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