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