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 /*
2 
3  Broadcom B43 wireless driver
4 
5  debugfs driver debugging code
6 
7  Copyright (c) 2005-2007 Michael Buesch <[email protected]>
8 
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; see the file COPYING. If not, write to
21  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
22  Boston, MA 02110-1301, USA.
23 
24 */
25 
26 #include <linux/fs.h>
27 #include <linux/debugfs.h>
28 #include <linux/slab.h>
29 #include <linux/netdevice.h>
30 #include <linux/pci.h>
31 #include <linux/mutex.h>
32 
33 #include "b43.h"
34 #include "main.h"
35 #include "debugfs.h"
36 #include "dma.h"
37 #include "xmit.h"
38 
39 
40 /* The root directory. */
41 static struct dentry *rootdir;
42 
44  ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
45  int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
47  /* Offset of struct b43_dfs_file in struct b43_dfsentry */
49 };
50 
51 static inline
52 struct b43_dfs_file *fops_to_dfs_file(struct b43_wldev *dev,
53  const struct b43_debugfs_fops *dfops)
54 {
55  void *p;
56 
57  p = dev->dfsentry;
58  p += dfops->file_struct_offset;
59 
60  return p;
61 }
62 
63 
64 #define fappend(fmt, x...) \
65  do { \
66  if (bufsize - count) \
67  count += snprintf(buf + count, \
68  bufsize - count, \
69  fmt , ##x); \
70  else \
71  printk(KERN_ERR "b43: fappend overflow\n"); \
72  } while (0)
73 
74 
75 /* The biggest address values for SHM access from the debugfs files. */
76 #define B43_MAX_SHM_ROUTING 4
77 #define B43_MAX_SHM_ADDR 0xFFFF
78 
79 static ssize_t shm16read__read_file(struct b43_wldev *dev,
80  char *buf, size_t bufsize)
81 {
82  ssize_t count = 0;
83  unsigned int routing, addr;
84  u16 val;
85 
86  routing = dev->dfsentry->shm16read_routing_next;
87  addr = dev->dfsentry->shm16read_addr_next;
88  if ((routing > B43_MAX_SHM_ROUTING) ||
89  (addr > B43_MAX_SHM_ADDR))
90  return -EDESTADDRREQ;
91 
92  val = b43_shm_read16(dev, routing, addr);
93  fappend("0x%04X\n", val);
94 
95  return count;
96 }
97 
98 static int shm16read__write_file(struct b43_wldev *dev,
99  const char *buf, size_t count)
100 {
101  unsigned int routing, addr;
102  int res;
103 
104  res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
105  if (res != 2)
106  return -EINVAL;
107  if (routing > B43_MAX_SHM_ROUTING)
108  return -EADDRNOTAVAIL;
109  if (addr > B43_MAX_SHM_ADDR)
110  return -EADDRNOTAVAIL;
111  if (routing == B43_SHM_SHARED) {
112  if ((addr % 2) != 0)
113  return -EADDRNOTAVAIL;
114  }
115 
116  dev->dfsentry->shm16read_routing_next = routing;
117  dev->dfsentry->shm16read_addr_next = addr;
118 
119  return 0;
120 }
121 
122 static int shm16write__write_file(struct b43_wldev *dev,
123  const char *buf, size_t count)
124 {
125  unsigned int routing, addr, mask, set;
126  u16 val;
127  int res;
128 
129  res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
130  &routing, &addr, &mask, &set);
131  if (res != 4)
132  return -EINVAL;
133  if (routing > B43_MAX_SHM_ROUTING)
134  return -EADDRNOTAVAIL;
135  if (addr > B43_MAX_SHM_ADDR)
136  return -EADDRNOTAVAIL;
137  if (routing == B43_SHM_SHARED) {
138  if ((addr % 2) != 0)
139  return -EADDRNOTAVAIL;
140  }
141  if ((mask > 0xFFFF) || (set > 0xFFFF))
142  return -E2BIG;
143 
144  if (mask == 0)
145  val = 0;
146  else
147  val = b43_shm_read16(dev, routing, addr);
148  val &= mask;
149  val |= set;
150  b43_shm_write16(dev, routing, addr, val);
151 
152  return 0;
153 }
154 
155 static ssize_t shm32read__read_file(struct b43_wldev *dev,
156  char *buf, size_t bufsize)
157 {
158  ssize_t count = 0;
159  unsigned int routing, addr;
160  u32 val;
161 
162  routing = dev->dfsentry->shm32read_routing_next;
163  addr = dev->dfsentry->shm32read_addr_next;
164  if ((routing > B43_MAX_SHM_ROUTING) ||
165  (addr > B43_MAX_SHM_ADDR))
166  return -EDESTADDRREQ;
167 
168  val = b43_shm_read32(dev, routing, addr);
169  fappend("0x%08X\n", val);
170 
171  return count;
172 }
173 
174 static int shm32read__write_file(struct b43_wldev *dev,
175  const char *buf, size_t count)
176 {
177  unsigned int routing, addr;
178  int res;
179 
180  res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
181  if (res != 2)
182  return -EINVAL;
183  if (routing > B43_MAX_SHM_ROUTING)
184  return -EADDRNOTAVAIL;
185  if (addr > B43_MAX_SHM_ADDR)
186  return -EADDRNOTAVAIL;
187  if (routing == B43_SHM_SHARED) {
188  if ((addr % 2) != 0)
189  return -EADDRNOTAVAIL;
190  }
191 
192  dev->dfsentry->shm32read_routing_next = routing;
193  dev->dfsentry->shm32read_addr_next = addr;
194 
195  return 0;
196 }
197 
198 static int shm32write__write_file(struct b43_wldev *dev,
199  const char *buf, size_t count)
200 {
201  unsigned int routing, addr, mask, set;
202  u32 val;
203  int res;
204 
205  res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
206  &routing, &addr, &mask, &set);
207  if (res != 4)
208  return -EINVAL;
209  if (routing > B43_MAX_SHM_ROUTING)
210  return -EADDRNOTAVAIL;
211  if (addr > B43_MAX_SHM_ADDR)
212  return -EADDRNOTAVAIL;
213  if (routing == B43_SHM_SHARED) {
214  if ((addr % 2) != 0)
215  return -EADDRNOTAVAIL;
216  }
217  if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
218  return -E2BIG;
219 
220  if (mask == 0)
221  val = 0;
222  else
223  val = b43_shm_read32(dev, routing, addr);
224  val &= mask;
225  val |= set;
226  b43_shm_write32(dev, routing, addr, val);
227 
228  return 0;
229 }
230 
231 /* The biggest MMIO address that we allow access to from the debugfs files. */
232 #define B43_MAX_MMIO_ACCESS (0xF00 - 1)
233 
234 static ssize_t mmio16read__read_file(struct b43_wldev *dev,
235  char *buf, size_t bufsize)
236 {
237  ssize_t count = 0;
238  unsigned int addr;
239  u16 val;
240 
241  addr = dev->dfsentry->mmio16read_next;
242  if (addr > B43_MAX_MMIO_ACCESS)
243  return -EDESTADDRREQ;
244 
245  val = b43_read16(dev, addr);
246  fappend("0x%04X\n", val);
247 
248  return count;
249 }
250 
251 static int mmio16read__write_file(struct b43_wldev *dev,
252  const char *buf, size_t count)
253 {
254  unsigned int addr;
255  int res;
256 
257  res = sscanf(buf, "0x%X", &addr);
258  if (res != 1)
259  return -EINVAL;
260  if (addr > B43_MAX_MMIO_ACCESS)
261  return -EADDRNOTAVAIL;
262  if ((addr % 2) != 0)
263  return -EINVAL;
264 
265  dev->dfsentry->mmio16read_next = addr;
266 
267  return 0;
268 }
269 
270 static int mmio16write__write_file(struct b43_wldev *dev,
271  const char *buf, size_t count)
272 {
273  unsigned int addr, mask, set;
274  int res;
275  u16 val;
276 
277  res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
278  if (res != 3)
279  return -EINVAL;
280  if (addr > B43_MAX_MMIO_ACCESS)
281  return -EADDRNOTAVAIL;
282  if ((mask > 0xFFFF) || (set > 0xFFFF))
283  return -E2BIG;
284  if ((addr % 2) != 0)
285  return -EINVAL;
286 
287  if (mask == 0)
288  val = 0;
289  else
290  val = b43_read16(dev, addr);
291  val &= mask;
292  val |= set;
293  b43_write16(dev, addr, val);
294 
295  return 0;
296 }
297 
298 static ssize_t mmio32read__read_file(struct b43_wldev *dev,
299  char *buf, size_t bufsize)
300 {
301  ssize_t count = 0;
302  unsigned int addr;
303  u32 val;
304 
305  addr = dev->dfsentry->mmio32read_next;
306  if (addr > B43_MAX_MMIO_ACCESS)
307  return -EDESTADDRREQ;
308 
309  val = b43_read32(dev, addr);
310  fappend("0x%08X\n", val);
311 
312  return count;
313 }
314 
315 static int mmio32read__write_file(struct b43_wldev *dev,
316  const char *buf, size_t count)
317 {
318  unsigned int addr;
319  int res;
320 
321  res = sscanf(buf, "0x%X", &addr);
322  if (res != 1)
323  return -EINVAL;
324  if (addr > B43_MAX_MMIO_ACCESS)
325  return -EADDRNOTAVAIL;
326  if ((addr % 4) != 0)
327  return -EINVAL;
328 
329  dev->dfsentry->mmio32read_next = addr;
330 
331  return 0;
332 }
333 
334 static int mmio32write__write_file(struct b43_wldev *dev,
335  const char *buf, size_t count)
336 {
337  unsigned int addr, mask, set;
338  int res;
339  u32 val;
340 
341  res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
342  if (res != 3)
343  return -EINVAL;
344  if (addr > B43_MAX_MMIO_ACCESS)
345  return -EADDRNOTAVAIL;
346  if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
347  return -E2BIG;
348  if ((addr % 4) != 0)
349  return -EINVAL;
350 
351  if (mask == 0)
352  val = 0;
353  else
354  val = b43_read32(dev, addr);
355  val &= mask;
356  val |= set;
357  b43_write32(dev, addr, val);
358 
359  return 0;
360 }
361 
362 static ssize_t txstat_read_file(struct b43_wldev *dev,
363  char *buf, size_t bufsize)
364 {
365  struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
366  ssize_t count = 0;
367  int i, idx;
368  struct b43_txstatus *stat;
369 
370  if (log->end < 0) {
371  fappend("Nothing transmitted, yet\n");
372  goto out;
373  }
374  fappend("b43 TX status reports:\n\n"
375  "index | cookie | seq | phy_stat | frame_count | "
376  "rts_count | supp_reason | pm_indicated | "
377  "intermediate | for_ampdu | acked\n" "---\n");
378  i = log->end + 1;
379  idx = 0;
380  while (1) {
381  if (i == B43_NR_LOGGED_TXSTATUS)
382  i = 0;
383  stat = &(log->log[i]);
384  if (stat->cookie) {
385  fappend("%03d | "
386  "0x%04X | 0x%04X | 0x%02X | "
387  "0x%X | 0x%X | "
388  "%u | %u | "
389  "%u | %u | %u\n",
390  idx,
391  stat->cookie, stat->seq, stat->phy_stat,
392  stat->frame_count, stat->rts_count,
393  stat->supp_reason, stat->pm_indicated,
394  stat->intermediate, stat->for_ampdu,
395  stat->acked);
396  idx++;
397  }
398  if (i == log->end)
399  break;
400  i++;
401  }
402 out:
403 
404  return count;
405 }
406 
407 static int restart_write_file(struct b43_wldev *dev,
408  const char *buf, size_t count)
409 {
410  int err = 0;
411 
412  if (count > 0 && buf[0] == '1') {
413  b43_controller_restart(dev, "manually restarted");
414  } else
415  err = -EINVAL;
416 
417  return err;
418 }
419 
420 static unsigned long calc_expire_secs(unsigned long now,
421  unsigned long time,
422  unsigned long expire)
423 {
424  expire = time + expire;
425 
426  if (time_after(now, expire))
427  return 0; /* expired */
428  if (expire < now) {
429  /* jiffies wrapped */
430  expire -= MAX_JIFFY_OFFSET;
431  now -= MAX_JIFFY_OFFSET;
432  }
433  B43_WARN_ON(expire < now);
434 
435  return (expire - now) / HZ;
436 }
437 
438 static ssize_t loctls_read_file(struct b43_wldev *dev,
439  char *buf, size_t bufsize)
440 {
441  ssize_t count = 0;
442  struct b43_txpower_lo_control *lo;
443  int i, err = 0;
444  struct b43_lo_calib *cal;
445  unsigned long now = jiffies;
446  struct b43_phy *phy = &dev->phy;
447 
448  if (phy->type != B43_PHYTYPE_G) {
449  fappend("Device is not a G-PHY\n");
450  err = -ENODEV;
451  goto out;
452  }
453  lo = phy->g->lo_control;
454  fappend("-- Local Oscillator calibration data --\n\n");
455  fappend("HW-power-control enabled: %d\n",
456  dev->phy.hardware_power_control);
457  fappend("TX Bias: 0x%02X, TX Magn: 0x%02X (expire in %lu sec)\n",
458  lo->tx_bias, lo->tx_magn,
459  calc_expire_secs(now, lo->txctl_measured_time,
461  fappend("Power Vector: 0x%08X%08X (expires in %lu sec)\n",
462  (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32),
463  (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL),
464  calc_expire_secs(now, lo->pwr_vec_read_time,
466 
467  fappend("\nCalibrated settings:\n");
468  list_for_each_entry(cal, &lo->calib_list, list) {
469  bool active;
470 
471  active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) &&
472  b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt));
473  fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d "
474  "(expires in %lu sec)%s\n",
475  cal->bbatt.att,
476  cal->rfatt.att, cal->rfatt.with_padmix,
477  cal->ctl.i, cal->ctl.q,
478  calc_expire_secs(now, cal->calib_time,
480  active ? " ACTIVE" : "");
481  }
482 
483  fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n");
484  for (i = 0; i < lo->rfatt_list.len; i++) {
485  fappend("%u(%d), ",
486  lo->rfatt_list.list[i].att,
487  lo->rfatt_list.list[i].with_padmix);
488  }
489  fappend("\n");
490  fappend("\nUsed Baseband attenuation values:\n");
491  for (i = 0; i < lo->bbatt_list.len; i++) {
492  fappend("%u, ",
493  lo->bbatt_list.list[i].att);
494  }
495  fappend("\n");
496 
497 out:
498  return err ? err : count;
499 }
500 
501 #undef fappend
502 
503 static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
504  size_t count, loff_t *ppos)
505 {
506  struct b43_wldev *dev;
507  struct b43_debugfs_fops *dfops;
508  struct b43_dfs_file *dfile;
510  char *buf;
511  const size_t bufsize = 1024 * 16; /* 16 kiB buffer */
512  const size_t buforder = get_order(bufsize);
513  int err = 0;
514 
515  if (!count)
516  return 0;
517  dev = file->private_data;
518  if (!dev)
519  return -ENODEV;
520 
521  mutex_lock(&dev->wl->mutex);
522  if (b43_status(dev) < B43_STAT_INITIALIZED) {
523  err = -ENODEV;
524  goto out_unlock;
525  }
526 
527  dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
528  if (!dfops->read) {
529  err = -ENOSYS;
530  goto out_unlock;
531  }
532  dfile = fops_to_dfs_file(dev, dfops);
533 
534  if (!dfile->buffer) {
535  buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
536  if (!buf) {
537  err = -ENOMEM;
538  goto out_unlock;
539  }
540  memset(buf, 0, bufsize);
541  ret = dfops->read(dev, buf, bufsize);
542  if (ret <= 0) {
543  free_pages((unsigned long)buf, buforder);
544  err = ret;
545  goto out_unlock;
546  }
547  dfile->data_len = ret;
548  dfile->buffer = buf;
549  }
550 
551  ret = simple_read_from_buffer(userbuf, count, ppos,
552  dfile->buffer,
553  dfile->data_len);
554  if (*ppos >= dfile->data_len) {
555  free_pages((unsigned long)dfile->buffer, buforder);
556  dfile->buffer = NULL;
557  dfile->data_len = 0;
558  }
559 out_unlock:
560  mutex_unlock(&dev->wl->mutex);
561 
562  return err ? err : ret;
563 }
564 
565 static ssize_t b43_debugfs_write(struct file *file,
566  const char __user *userbuf,
567  size_t count, loff_t *ppos)
568 {
569  struct b43_wldev *dev;
570  struct b43_debugfs_fops *dfops;
571  char *buf;
572  int err = 0;
573 
574  if (!count)
575  return 0;
576  if (count > PAGE_SIZE)
577  return -E2BIG;
578  dev = file->private_data;
579  if (!dev)
580  return -ENODEV;
581 
582  mutex_lock(&dev->wl->mutex);
583  if (b43_status(dev) < B43_STAT_INITIALIZED) {
584  err = -ENODEV;
585  goto out_unlock;
586  }
587 
588  dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
589  if (!dfops->write) {
590  err = -ENOSYS;
591  goto out_unlock;
592  }
593 
594  buf = (char *)get_zeroed_page(GFP_KERNEL);
595  if (!buf) {
596  err = -ENOMEM;
597  goto out_unlock;
598  }
599  if (copy_from_user(buf, userbuf, count)) {
600  err = -EFAULT;
601  goto out_freepage;
602  }
603  err = dfops->write(dev, buf, count);
604  if (err)
605  goto out_freepage;
606 
607 out_freepage:
608  free_page((unsigned long)buf);
609 out_unlock:
610  mutex_unlock(&dev->wl->mutex);
611 
612  return err ? err : count;
613 }
614 
615 
616 #define B43_DEBUGFS_FOPS(name, _read, _write) \
617  static struct b43_debugfs_fops fops_##name = { \
618  .read = _read, \
619  .write = _write, \
620  .fops = { \
621  .open = simple_open, \
622  .read = b43_debugfs_read, \
623  .write = b43_debugfs_write, \
624  .llseek = generic_file_llseek, \
625  }, \
626  .file_struct_offset = offsetof(struct b43_dfsentry, \
627  file_##name), \
628  }
629 
630 B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file);
631 B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file);
632 B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file);
633 B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file);
634 B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file);
635 B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file);
636 B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file);
637 B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file);
638 B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL);
639 B43_DEBUGFS_FOPS(restart, NULL, restart_write_file);
640 B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL);
641 
642 
643 bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
644 {
645  bool enabled;
646 
647  enabled = (dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
648  if (unlikely(enabled)) {
649  /* Force full debugging messages, if the user enabled
650  * some dynamic debugging feature. */
652  }
653 
654  return enabled;
655 }
656 
657 static void b43_remove_dynamic_debug(struct b43_wldev *dev)
658 {
659  struct b43_dfsentry *e = dev->dfsentry;
660  int i;
661 
662  for (i = 0; i < __B43_NR_DYNDBG; i++)
663  debugfs_remove(e->dyn_debug_dentries[i]);
664 }
665 
666 static void b43_add_dynamic_debug(struct b43_wldev *dev)
667 {
668  struct b43_dfsentry *e = dev->dfsentry;
669  struct dentry *d;
670 
671 #define add_dyn_dbg(name, id, initstate) do { \
672  e->dyn_debug[id] = (initstate); \
673  d = debugfs_create_bool(name, 0600, e->subdir, \
674  &(e->dyn_debug[id])); \
675  if (!IS_ERR(d)) \
676  e->dyn_debug_dentries[id] = d; \
677  } while (0)
678 
679  add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0);
680  add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0);
681  add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);
682  add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
683  add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
684  add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
685  add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0);
686  add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0);
687  add_dyn_dbg("debug_verbose_stats", B43_DBG_VERBOSESTATS, 0);
688 
689 #undef add_dyn_dbg
690 }
691 
693 {
694  struct b43_dfsentry *e;
695  struct b43_txstatus_log *log;
696  char devdir[16];
697 
698  B43_WARN_ON(!dev);
699  e = kzalloc(sizeof(*e), GFP_KERNEL);
700  if (!e) {
701  b43err(dev->wl, "debugfs: add device OOM\n");
702  return;
703  }
704  e->dev = dev;
705  log = &e->txstatlog;
706  log->log = kcalloc(B43_NR_LOGGED_TXSTATUS,
707  sizeof(struct b43_txstatus), GFP_KERNEL);
708  if (!log->log) {
709  b43err(dev->wl, "debugfs: add device txstatus OOM\n");
710  kfree(e);
711  return;
712  }
713  log->end = -1;
714 
715  dev->dfsentry = e;
716 
717  snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
718  e->subdir = debugfs_create_dir(devdir, rootdir);
719  if (!e->subdir || IS_ERR(e->subdir)) {
720  if (e->subdir == ERR_PTR(-ENODEV)) {
721  b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
722  "enabled in kernel config\n");
723  } else {
724  b43err(dev->wl, "debugfs: cannot create %s directory\n",
725  devdir);
726  }
727  dev->dfsentry = NULL;
728  kfree(log->log);
729  kfree(e);
730  return;
731  }
732 
733  e->mmio16read_next = 0xFFFF; /* invalid address */
734  e->mmio32read_next = 0xFFFF; /* invalid address */
735  e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */
736  e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */
737  e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */
738  e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */
739 
740 #define ADD_FILE(name, mode) \
741  do { \
742  struct dentry *d; \
743  d = debugfs_create_file(__stringify(name), \
744  mode, e->subdir, dev, \
745  &fops_##name.fops); \
746  e->file_##name.dentry = NULL; \
747  if (!IS_ERR(d)) \
748  e->file_##name.dentry = d; \
749  } while (0)
750 
751 
752  ADD_FILE(shm16read, 0600);
753  ADD_FILE(shm16write, 0200);
754  ADD_FILE(shm32read, 0600);
755  ADD_FILE(shm32write, 0200);
756  ADD_FILE(mmio16read, 0600);
757  ADD_FILE(mmio16write, 0200);
758  ADD_FILE(mmio32read, 0600);
759  ADD_FILE(mmio32write, 0200);
760  ADD_FILE(txstat, 0400);
761  ADD_FILE(restart, 0200);
762  ADD_FILE(loctls, 0400);
763 
764 #undef ADD_FILE
765 
766  b43_add_dynamic_debug(dev);
767 }
768 
770 {
771  struct b43_dfsentry *e;
772 
773  if (!dev)
774  return;
775  e = dev->dfsentry;
776  if (!e)
777  return;
778  b43_remove_dynamic_debug(dev);
779 
780  debugfs_remove(e->file_shm16read.dentry);
781  debugfs_remove(e->file_shm16write.dentry);
782  debugfs_remove(e->file_shm32read.dentry);
783  debugfs_remove(e->file_shm32write.dentry);
784  debugfs_remove(e->file_mmio16read.dentry);
785  debugfs_remove(e->file_mmio16write.dentry);
786  debugfs_remove(e->file_mmio32read.dentry);
787  debugfs_remove(e->file_mmio32write.dentry);
788  debugfs_remove(e->file_txstat.dentry);
789  debugfs_remove(e->file_restart.dentry);
790  debugfs_remove(e->file_loctls.dentry);
791 
792  debugfs_remove(e->subdir);
793  kfree(e->txstatlog.log);
794  kfree(e);
795 }
796 
798  const struct b43_txstatus *status)
799 {
800  struct b43_dfsentry *e = dev->dfsentry;
801  struct b43_txstatus_log *log;
802  struct b43_txstatus *cur;
803  int i;
804 
805  if (!e)
806  return;
807  log = &e->txstatlog;
808  i = log->end + 1;
809  if (i == B43_NR_LOGGED_TXSTATUS)
810  i = 0;
811  log->end = i;
812  cur = &(log->log[i]);
813  memcpy(cur, status, sizeof(*cur));
814 }
815 
817 {
818  rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
819  if (IS_ERR(rootdir))
820  rootdir = NULL;
821 }
822 
824 {
825  debugfs_remove(rootdir);
826 }