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