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