]> err.no Git - linux-2.6/blob - drivers/net/wireless/libertas/debugfs.c
libertas: convert SLEEP_PARAMS to a direct command
[linux-2.6] / 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(u16 tlv_type, const u8 *tlv, u16 size)
351 {
352         __le16 le_type = cpu_to_le16(tlv_type);
353         ssize_t pos = 0;
354         struct mrvlietypesheader *tlv_h;
355         while (pos < size) {
356                 u16 length;
357                 tlv_h = (struct mrvlietypesheader *) tlv;
358                 if (tlv_h->type == le_type)
359                         return tlv_h;
360                 if (tlv_h->len == 0)
361                         return NULL;
362                 length = le16_to_cpu(tlv_h->len) +
363                         sizeof(struct mrvlietypesheader);
364                 pos += length;
365                 tlv += length;
366         }
367         return NULL;
368 }
369
370
371 /*
372  * This just gets the bitmap of currently subscribed events. Used when
373  * adding an additonal event subscription.
374  */
375 static u16 lbs_get_events_bitmap(struct lbs_private *priv)
376 {
377         ssize_t res;
378
379         struct cmd_ds_802_11_subscribe_event *events = kzalloc(
380                 sizeof(struct cmd_ds_802_11_subscribe_event),
381                 GFP_KERNEL);
382
383         res = lbs_prepare_and_send_command(priv,
384                         CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
385                         CMD_OPTION_WAITFORRSP, 0, events);
386
387         if (res) {
388                 kfree(events);
389                 return 0;
390         }
391         return le16_to_cpu(events->events);
392 }
393
394
395 static ssize_t lbs_threshold_read(
396         u16 tlv_type, u16 event_mask,
397         struct file *file, char __user *userbuf,
398         size_t count, loff_t *ppos)
399 {
400         struct lbs_private *priv = file->private_data;
401         ssize_t res = 0;
402         size_t pos = 0;
403         unsigned long addr = get_zeroed_page(GFP_KERNEL);
404         char *buf = (char *)addr;
405         u8 value;
406         u8 freq;
407         int events = 0;
408
409         struct cmd_ds_802_11_subscribe_event *subscribed = kzalloc(
410                 sizeof(struct cmd_ds_802_11_subscribe_event),
411                 GFP_KERNEL);
412         struct mrvlietypes_thresholds *got;
413
414         res = lbs_prepare_and_send_command(priv,
415                         CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_GET,
416                         CMD_OPTION_WAITFORRSP, 0, subscribed);
417         if (res) {
418                 kfree(subscribed);
419                 return res;
420         }
421
422         got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
423         if (got) {
424                 value = got->value;
425                 freq  = got->freq;
426                 events = le16_to_cpu(subscribed->events);
427         }
428         kfree(subscribed);
429
430         if (got)
431                 pos += snprintf(buf, len, "%d %d %d\n", value, freq,
432                         !!(events & event_mask));
433
434         res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
435
436         free_page(addr);
437         return res;
438 }
439
440
441 static ssize_t lbs_threshold_write(
442         u16 tlv_type, u16 event_mask,
443         struct file *file,
444         const char __user *userbuf,
445         size_t count, loff_t *ppos)
446 {
447         struct lbs_private *priv = file->private_data;
448         ssize_t res, buf_size;
449         int value, freq, curr_mask, new_mask;
450         unsigned long addr = get_zeroed_page(GFP_KERNEL);
451         char *buf = (char *)addr;
452         struct cmd_ds_802_11_subscribe_event *events;
453
454         buf_size = min(count, len - 1);
455         if (copy_from_user(buf, userbuf, buf_size)) {
456                 res = -EFAULT;
457                 goto out_unlock;
458         }
459         res = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
460         if (res != 3) {
461                 res = -EFAULT;
462                 goto out_unlock;
463         }
464         curr_mask = lbs_get_events_bitmap(priv);
465
466         if (new_mask)
467                 new_mask = curr_mask | event_mask;
468         else
469                 new_mask = curr_mask & ~event_mask;
470
471         /* Now everything is set and we can send stuff down to the firmware */
472         events = kzalloc(
473                 sizeof(struct cmd_ds_802_11_subscribe_event),
474                 GFP_KERNEL);
475         if (events) {
476                 struct mrvlietypes_thresholds *tlv =
477                         (struct mrvlietypes_thresholds *) events->tlv;
478                 events->action = cpu_to_le16(CMD_ACT_SET);
479                 events->events = cpu_to_le16(new_mask);
480                 tlv->header.type = cpu_to_le16(tlv_type);
481                 tlv->header.len = cpu_to_le16(
482                         sizeof(struct mrvlietypes_thresholds) -
483                         sizeof(struct mrvlietypesheader));
484                 tlv->value = value;
485                 if (tlv_type != TLV_TYPE_BCNMISS)
486                         tlv->freq = freq;
487                 lbs_prepare_and_send_command(priv,
488                         CMD_802_11_SUBSCRIBE_EVENT, CMD_ACT_SET,
489                         CMD_OPTION_WAITFORRSP, 0, events);
490                 kfree(events);
491         }
492
493         res = count;
494 out_unlock:
495         free_page(addr);
496         return res;
497 }
498
499
500 static ssize_t lbs_lowrssi_read(
501         struct file *file, char __user *userbuf,
502         size_t count, loff_t *ppos)
503 {
504         return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
505                 file, userbuf, count, ppos);
506 }
507
508
509 static ssize_t lbs_lowrssi_write(
510         struct file *file, const char __user *userbuf,
511         size_t count, loff_t *ppos)
512 {
513         return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
514                 file, userbuf, count, ppos);
515 }
516
517
518 static ssize_t lbs_lowsnr_read(
519         struct file *file, char __user *userbuf,
520         size_t count, loff_t *ppos)
521 {
522         return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
523                 file, userbuf, count, ppos);
524 }
525
526
527 static ssize_t lbs_lowsnr_write(
528         struct file *file, const char __user *userbuf,
529         size_t count, loff_t *ppos)
530 {
531         return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
532                 file, userbuf, count, ppos);
533 }
534
535
536 static ssize_t lbs_failcount_read(
537         struct file *file, char __user *userbuf,
538         size_t count, loff_t *ppos)
539 {
540         return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
541                 file, userbuf, count, ppos);
542 }
543
544
545 static ssize_t lbs_failcount_write(
546         struct file *file, const char __user *userbuf,
547         size_t count, loff_t *ppos)
548 {
549         return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
550                 file, userbuf, count, ppos);
551 }
552
553
554 static ssize_t lbs_highrssi_read(
555         struct file *file, char __user *userbuf,
556         size_t count, loff_t *ppos)
557 {
558         return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
559                 file, userbuf, count, ppos);
560 }
561
562
563 static ssize_t lbs_highrssi_write(
564         struct file *file, const char __user *userbuf,
565         size_t count, loff_t *ppos)
566 {
567         return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
568                 file, userbuf, count, ppos);
569 }
570
571
572 static ssize_t lbs_highsnr_read(
573         struct file *file, char __user *userbuf,
574         size_t count, loff_t *ppos)
575 {
576         return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
577                 file, userbuf, count, ppos);
578 }
579
580
581 static ssize_t lbs_highsnr_write(
582         struct file *file, const char __user *userbuf,
583         size_t count, loff_t *ppos)
584 {
585         return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
586                 file, userbuf, count, ppos);
587 }
588
589 static ssize_t lbs_bcnmiss_read(
590         struct file *file, char __user *userbuf,
591         size_t count, loff_t *ppos)
592 {
593         return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
594                 file, userbuf, count, ppos);
595 }
596
597
598 static ssize_t lbs_bcnmiss_write(
599         struct file *file, const char __user *userbuf,
600         size_t count, loff_t *ppos)
601 {
602         return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
603                 file, userbuf, count, ppos);
604 }
605
606
607
608
609
610
611
612
613 static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
614                                   size_t count, loff_t *ppos)
615 {
616         struct lbs_private *priv = file->private_data;
617         struct lbs_offset_value offval;
618         ssize_t pos = 0;
619         int ret;
620         unsigned long addr = get_zeroed_page(GFP_KERNEL);
621         char *buf = (char *)addr;
622
623         offval.offset = priv->mac_offset;
624         offval.value = 0;
625
626         ret = lbs_prepare_and_send_command(priv,
627                                 CMD_MAC_REG_ACCESS, 0,
628                                 CMD_OPTION_WAITFORRSP, 0, &offval);
629         mdelay(10);
630         pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
631                                 priv->mac_offset, priv->offsetvalue.value);
632
633         ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
634         free_page(addr);
635         return ret;
636 }
637
638 static ssize_t lbs_rdmac_write(struct file *file,
639                                     const char __user *userbuf,
640                                     size_t count, loff_t *ppos)
641 {
642         struct lbs_private *priv = file->private_data;
643         ssize_t res, buf_size;
644         unsigned long addr = get_zeroed_page(GFP_KERNEL);
645         char *buf = (char *)addr;
646
647         buf_size = min(count, len - 1);
648         if (copy_from_user(buf, userbuf, buf_size)) {
649                 res = -EFAULT;
650                 goto out_unlock;
651         }
652         priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
653         res = count;
654 out_unlock:
655         free_page(addr);
656         return res;
657 }
658
659 static ssize_t lbs_wrmac_write(struct file *file,
660                                     const char __user *userbuf,
661                                     size_t count, loff_t *ppos)
662 {
663
664         struct lbs_private *priv = file->private_data;
665         ssize_t res, buf_size;
666         u32 offset, value;
667         struct lbs_offset_value offval;
668         unsigned long addr = get_zeroed_page(GFP_KERNEL);
669         char *buf = (char *)addr;
670
671         buf_size = min(count, len - 1);
672         if (copy_from_user(buf, userbuf, buf_size)) {
673                 res = -EFAULT;
674                 goto out_unlock;
675         }
676         res = sscanf(buf, "%x %x", &offset, &value);
677         if (res != 2) {
678                 res = -EFAULT;
679                 goto out_unlock;
680         }
681
682         offval.offset = offset;
683         offval.value = value;
684         res = lbs_prepare_and_send_command(priv,
685                                 CMD_MAC_REG_ACCESS, 1,
686                                 CMD_OPTION_WAITFORRSP, 0, &offval);
687         mdelay(10);
688
689         res = count;
690 out_unlock:
691         free_page(addr);
692         return res;
693 }
694
695 static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
696                                   size_t count, loff_t *ppos)
697 {
698         struct lbs_private *priv = file->private_data;
699         struct lbs_offset_value offval;
700         ssize_t pos = 0;
701         int ret;
702         unsigned long addr = get_zeroed_page(GFP_KERNEL);
703         char *buf = (char *)addr;
704
705         offval.offset = priv->bbp_offset;
706         offval.value = 0;
707
708         ret = lbs_prepare_and_send_command(priv,
709                                 CMD_BBP_REG_ACCESS, 0,
710                                 CMD_OPTION_WAITFORRSP, 0, &offval);
711         mdelay(10);
712         pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
713                                 priv->bbp_offset, priv->offsetvalue.value);
714
715         ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
716         free_page(addr);
717
718         return ret;
719 }
720
721 static ssize_t lbs_rdbbp_write(struct file *file,
722                                     const char __user *userbuf,
723                                     size_t count, loff_t *ppos)
724 {
725         struct lbs_private *priv = file->private_data;
726         ssize_t res, buf_size;
727         unsigned long addr = get_zeroed_page(GFP_KERNEL);
728         char *buf = (char *)addr;
729
730         buf_size = min(count, len - 1);
731         if (copy_from_user(buf, userbuf, buf_size)) {
732                 res = -EFAULT;
733                 goto out_unlock;
734         }
735         priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
736         res = count;
737 out_unlock:
738         free_page(addr);
739         return res;
740 }
741
742 static ssize_t lbs_wrbbp_write(struct file *file,
743                                     const char __user *userbuf,
744                                     size_t count, loff_t *ppos)
745 {
746
747         struct lbs_private *priv = file->private_data;
748         ssize_t res, buf_size;
749         u32 offset, value;
750         struct lbs_offset_value offval;
751         unsigned long addr = get_zeroed_page(GFP_KERNEL);
752         char *buf = (char *)addr;
753
754         buf_size = min(count, len - 1);
755         if (copy_from_user(buf, userbuf, buf_size)) {
756                 res = -EFAULT;
757                 goto out_unlock;
758         }
759         res = sscanf(buf, "%x %x", &offset, &value);
760         if (res != 2) {
761                 res = -EFAULT;
762                 goto out_unlock;
763         }
764
765         offval.offset = offset;
766         offval.value = value;
767         res = lbs_prepare_and_send_command(priv,
768                                 CMD_BBP_REG_ACCESS, 1,
769                                 CMD_OPTION_WAITFORRSP, 0, &offval);
770         mdelay(10);
771
772         res = count;
773 out_unlock:
774         free_page(addr);
775         return res;
776 }
777
778 static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
779                                   size_t count, loff_t *ppos)
780 {
781         struct lbs_private *priv = file->private_data;
782         struct lbs_offset_value offval;
783         ssize_t pos = 0;
784         int ret;
785         unsigned long addr = get_zeroed_page(GFP_KERNEL);
786         char *buf = (char *)addr;
787
788         offval.offset = priv->rf_offset;
789         offval.value = 0;
790
791         ret = lbs_prepare_and_send_command(priv,
792                                 CMD_RF_REG_ACCESS, 0,
793                                 CMD_OPTION_WAITFORRSP, 0, &offval);
794         mdelay(10);
795         pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
796                                 priv->rf_offset, priv->offsetvalue.value);
797
798         ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
799         free_page(addr);
800
801         return ret;
802 }
803
804 static ssize_t lbs_rdrf_write(struct file *file,
805                                     const char __user *userbuf,
806                                     size_t count, loff_t *ppos)
807 {
808         struct lbs_private *priv = file->private_data;
809         ssize_t res, buf_size;
810         unsigned long addr = get_zeroed_page(GFP_KERNEL);
811         char *buf = (char *)addr;
812
813         buf_size = min(count, len - 1);
814         if (copy_from_user(buf, userbuf, buf_size)) {
815                 res = -EFAULT;
816                 goto out_unlock;
817         }
818         priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
819         res = count;
820 out_unlock:
821         free_page(addr);
822         return res;
823 }
824
825 static ssize_t lbs_wrrf_write(struct file *file,
826                                     const char __user *userbuf,
827                                     size_t count, loff_t *ppos)
828 {
829
830         struct lbs_private *priv = file->private_data;
831         ssize_t res, buf_size;
832         u32 offset, value;
833         struct lbs_offset_value offval;
834         unsigned long addr = get_zeroed_page(GFP_KERNEL);
835         char *buf = (char *)addr;
836
837         buf_size = min(count, len - 1);
838         if (copy_from_user(buf, userbuf, buf_size)) {
839                 res = -EFAULT;
840                 goto out_unlock;
841         }
842         res = sscanf(buf, "%x %x", &offset, &value);
843         if (res != 2) {
844                 res = -EFAULT;
845                 goto out_unlock;
846         }
847
848         offval.offset = offset;
849         offval.value = value;
850         res = lbs_prepare_and_send_command(priv,
851                                 CMD_RF_REG_ACCESS, 1,
852                                 CMD_OPTION_WAITFORRSP, 0, &offval);
853         mdelay(10);
854
855         res = count;
856 out_unlock:
857         free_page(addr);
858         return res;
859 }
860
861 #define FOPS(fread, fwrite) { \
862         .owner = THIS_MODULE, \
863         .open = open_file_generic, \
864         .read = (fread), \
865         .write = (fwrite), \
866 }
867
868 struct lbs_debugfs_files {
869         char *name;
870         int perm;
871         struct file_operations fops;
872 };
873
874 static struct lbs_debugfs_files debugfs_files[] = {
875         { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
876         { "getscantable", 0444, FOPS(lbs_getscantable,
877                                         write_file_dummy), },
878         { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
879                                 lbs_sleepparams_write), },
880         { "extscan", 0600, FOPS(NULL, lbs_extscan), },
881         { "setuserscan", 0600, FOPS(NULL, lbs_setuserscan), },
882 };
883
884 static struct lbs_debugfs_files debugfs_events_files[] = {
885         {"low_rssi", 0644, FOPS(lbs_lowrssi_read,
886                                 lbs_lowrssi_write), },
887         {"low_snr", 0644, FOPS(lbs_lowsnr_read,
888                                 lbs_lowsnr_write), },
889         {"failure_count", 0644, FOPS(lbs_failcount_read,
890                                 lbs_failcount_write), },
891         {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
892                                 lbs_bcnmiss_write), },
893         {"high_rssi", 0644, FOPS(lbs_highrssi_read,
894                                 lbs_highrssi_write), },
895         {"high_snr", 0644, FOPS(lbs_highsnr_read,
896                                 lbs_highsnr_write), },
897 };
898
899 static struct lbs_debugfs_files debugfs_regs_files[] = {
900         {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
901         {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
902         {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
903         {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
904         {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
905         {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
906 };
907
908 void lbs_debugfs_init(void)
909 {
910         if (!lbs_dir)
911                 lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
912
913         return;
914 }
915
916 void lbs_debugfs_remove(void)
917 {
918         if (lbs_dir)
919                  debugfs_remove(lbs_dir);
920         return;
921 }
922
923 void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
924 {
925         int i;
926         struct lbs_debugfs_files *files;
927         if (!lbs_dir)
928                 goto exit;
929
930         priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
931         if (!priv->debugfs_dir)
932                 goto exit;
933
934         for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
935                 files = &debugfs_files[i];
936                 priv->debugfs_files[i] = debugfs_create_file(files->name,
937                                                              files->perm,
938                                                              priv->debugfs_dir,
939                                                              priv,
940                                                              &files->fops);
941         }
942
943         priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
944         if (!priv->events_dir)
945                 goto exit;
946
947         for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
948                 files = &debugfs_events_files[i];
949                 priv->debugfs_events_files[i] = debugfs_create_file(files->name,
950                                                              files->perm,
951                                                              priv->events_dir,
952                                                              priv,
953                                                              &files->fops);
954         }
955
956         priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
957         if (!priv->regs_dir)
958                 goto exit;
959
960         for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
961                 files = &debugfs_regs_files[i];
962                 priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
963                                                              files->perm,
964                                                              priv->regs_dir,
965                                                              priv,
966                                                              &files->fops);
967         }
968
969 #ifdef PROC_DEBUG
970         lbs_debug_init(priv, dev);
971 #endif
972 exit:
973         return;
974 }
975
976 void lbs_debugfs_remove_one(struct lbs_private *priv)
977 {
978         int i;
979
980         for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
981                 debugfs_remove(priv->debugfs_regs_files[i]);
982
983         debugfs_remove(priv->regs_dir);
984
985         for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
986                 debugfs_remove(priv->debugfs_events_files[i]);
987
988         debugfs_remove(priv->events_dir);
989 #ifdef PROC_DEBUG
990         debugfs_remove(priv->debugfs_debug);
991 #endif
992         for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
993                 debugfs_remove(priv->debugfs_files[i]);
994         debugfs_remove(priv->debugfs_dir);
995 }
996
997
998
999 /* debug entry */
1000
1001 #ifdef PROC_DEBUG
1002
1003 #define item_size(n)    (FIELD_SIZEOF(struct lbs_private, n))
1004 #define item_addr(n)    (offsetof(struct lbs_private, n))
1005
1006
1007 struct debug_data {
1008         char name[32];
1009         u32 size;
1010         size_t addr;
1011 };
1012
1013 /* To debug any member of struct lbs_private, simply add one line here.
1014  */
1015 static struct debug_data items[] = {
1016         {"intcounter", item_size(intcounter), item_addr(intcounter)},
1017         {"psmode", item_size(psmode), item_addr(psmode)},
1018         {"psstate", item_size(psstate), item_addr(psstate)},
1019 };
1020
1021 static int num_of_items = ARRAY_SIZE(items);
1022
1023 /**
1024  *  @brief proc read function
1025  *
1026  *  @param page    pointer to buffer
1027  *  @param s       read data starting position
1028  *  @param off     offset
1029  *  @param cnt     counter
1030  *  @param eof     end of file flag
1031  *  @param data    data to output
1032  *  @return        number of output data
1033  */
1034 static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
1035                         size_t count, loff_t *ppos)
1036 {
1037         int val = 0;
1038         size_t pos = 0;
1039         ssize_t res;
1040         char *p;
1041         int i;
1042         struct debug_data *d;
1043         unsigned long addr = get_zeroed_page(GFP_KERNEL);
1044         char *buf = (char *)addr;
1045
1046         p = buf;
1047
1048         d = (struct debug_data *)file->private_data;
1049
1050         for (i = 0; i < num_of_items; i++) {
1051                 if (d[i].size == 1)
1052                         val = *((u8 *) d[i].addr);
1053                 else if (d[i].size == 2)
1054                         val = *((u16 *) d[i].addr);
1055                 else if (d[i].size == 4)
1056                         val = *((u32 *) d[i].addr);
1057                 else if (d[i].size == 8)
1058                         val = *((u64 *) d[i].addr);
1059
1060                 pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
1061         }
1062
1063         res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
1064
1065         free_page(addr);
1066         return res;
1067 }
1068
1069 /**
1070  *  @brief proc write function
1071  *
1072  *  @param f       file pointer
1073  *  @param buf     pointer to data buffer
1074  *  @param cnt     data number to write
1075  *  @param data    data to write
1076  *  @return        number of data
1077  */
1078 static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
1079                             size_t cnt, loff_t *ppos)
1080 {
1081         int r, i;
1082         char *pdata;
1083         char *p;
1084         char *p0;
1085         char *p1;
1086         char *p2;
1087         struct debug_data *d = (struct debug_data *)f->private_data;
1088
1089         pdata = kmalloc(cnt, GFP_KERNEL);
1090         if (pdata == NULL)
1091                 return 0;
1092
1093         if (copy_from_user(pdata, buf, cnt)) {
1094                 lbs_deb_debugfs("Copy from user failed\n");
1095                 kfree(pdata);
1096                 return 0;
1097         }
1098
1099         p0 = pdata;
1100         for (i = 0; i < num_of_items; i++) {
1101                 do {
1102                         p = strstr(p0, d[i].name);
1103                         if (p == NULL)
1104                                 break;
1105                         p1 = strchr(p, '\n');
1106                         if (p1 == NULL)
1107                                 break;
1108                         p0 = p1++;
1109                         p2 = strchr(p, '=');
1110                         if (!p2)
1111                                 break;
1112                         p2++;
1113                         r = simple_strtoul(p2, NULL, 0);
1114                         if (d[i].size == 1)
1115                                 *((u8 *) d[i].addr) = (u8) r;
1116                         else if (d[i].size == 2)
1117                                 *((u16 *) d[i].addr) = (u16) r;
1118                         else if (d[i].size == 4)
1119                                 *((u32 *) d[i].addr) = (u32) r;
1120                         else if (d[i].size == 8)
1121                                 *((u64 *) d[i].addr) = (u64) r;
1122                         break;
1123                 } while (1);
1124         }
1125         kfree(pdata);
1126
1127         return (ssize_t)cnt;
1128 }
1129
1130 static struct file_operations lbs_debug_fops = {
1131         .owner = THIS_MODULE,
1132         .open = open_file_generic,
1133         .write = lbs_debugfs_write,
1134         .read = lbs_debugfs_read,
1135 };
1136
1137 /**
1138  *  @brief create debug proc file
1139  *
1140  *  @param priv    pointer struct lbs_private
1141  *  @param dev     pointer net_device
1142  *  @return        N/A
1143  */
1144 static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev)
1145 {
1146         int i;
1147
1148         if (!priv->debugfs_dir)
1149                 return;
1150
1151         for (i = 0; i < num_of_items; i++)
1152                 items[i].addr += (size_t) priv;
1153
1154         priv->debugfs_debug = debugfs_create_file("debug", 0644,
1155                                                   priv->debugfs_dir, &items[0],
1156                                                   &lbs_debug_fops);
1157 }
1158 #endif