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