1 /* 2 3 Broadcom B43 wireless driver 4 5 debugfs driver debugging code 6 7 Copyright (c) 2005-2007 Michael Buesch <m@bues.ch> 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 43 struct b43_debugfs_fops { 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); 46 struct file_operations fops; 47 /* Offset of struct b43_dfs_file in struct b43_dfsentry */ 48 size_t file_struct_offset; 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, 460 B43_LO_TXCTL_EXPIRE)); 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, 465 B43_LO_PWRVEC_EXPIRE)); 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, 479 B43_LO_CALIB_EXPIRE), 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; 509 ssize_t uninitialized_var(ret); 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(debugfs_real_fops(file), 528 struct b43_debugfs_fops, fops); 529 if (!dfops->read) { 530 err = -ENOSYS; 531 goto out_unlock; 532 } 533 dfile = fops_to_dfs_file(dev, dfops); 534 535 if (!dfile->buffer) { 536 buf = (char *)__get_free_pages(GFP_KERNEL, buforder); 537 if (!buf) { 538 err = -ENOMEM; 539 goto out_unlock; 540 } 541 memset(buf, 0, bufsize); 542 ret = dfops->read(dev, buf, bufsize); 543 if (ret <= 0) { 544 free_pages((unsigned long)buf, buforder); 545 err = ret; 546 goto out_unlock; 547 } 548 dfile->data_len = ret; 549 dfile->buffer = buf; 550 } 551 552 ret = simple_read_from_buffer(userbuf, count, ppos, 553 dfile->buffer, 554 dfile->data_len); 555 if (*ppos >= dfile->data_len) { 556 free_pages((unsigned long)dfile->buffer, buforder); 557 dfile->buffer = NULL; 558 dfile->data_len = 0; 559 } 560 out_unlock: 561 mutex_unlock(&dev->wl->mutex); 562 563 return err ? err : ret; 564 } 565 566 static ssize_t b43_debugfs_write(struct file *file, 567 const char __user *userbuf, 568 size_t count, loff_t *ppos) 569 { 570 struct b43_wldev *dev; 571 struct b43_debugfs_fops *dfops; 572 char *buf; 573 int err = 0; 574 575 if (!count) 576 return 0; 577 if (count > PAGE_SIZE) 578 return -E2BIG; 579 dev = file->private_data; 580 if (!dev) 581 return -ENODEV; 582 583 mutex_lock(&dev->wl->mutex); 584 if (b43_status(dev) < B43_STAT_INITIALIZED) { 585 err = -ENODEV; 586 goto out_unlock; 587 } 588 589 dfops = container_of(debugfs_real_fops(file), 590 struct b43_debugfs_fops, fops); 591 if (!dfops->write) { 592 err = -ENOSYS; 593 goto out_unlock; 594 } 595 596 buf = (char *)get_zeroed_page(GFP_KERNEL); 597 if (!buf) { 598 err = -ENOMEM; 599 goto out_unlock; 600 } 601 if (copy_from_user(buf, userbuf, count)) { 602 err = -EFAULT; 603 goto out_freepage; 604 } 605 err = dfops->write(dev, buf, count); 606 if (err) 607 goto out_freepage; 608 609 out_freepage: 610 free_page((unsigned long)buf); 611 out_unlock: 612 mutex_unlock(&dev->wl->mutex); 613 614 return err ? err : count; 615 } 616 617 618 #define B43_DEBUGFS_FOPS(name, _read, _write) \ 619 static struct b43_debugfs_fops fops_##name = { \ 620 .read = _read, \ 621 .write = _write, \ 622 .fops = { \ 623 .open = simple_open, \ 624 .read = b43_debugfs_read, \ 625 .write = b43_debugfs_write, \ 626 .llseek = generic_file_llseek, \ 627 }, \ 628 .file_struct_offset = offsetof(struct b43_dfsentry, \ 629 file_##name), \ 630 } 631 632 B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file); 633 B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file); 634 B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file); 635 B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file); 636 B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file); 637 B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file); 638 B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file); 639 B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file); 640 B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL); 641 B43_DEBUGFS_FOPS(restart, NULL, restart_write_file); 642 B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL); 643 644 645 bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) 646 { 647 bool enabled; 648 649 enabled = (dev->dfsentry && dev->dfsentry->dyn_debug[feature]); 650 if (unlikely(enabled)) { 651 /* Force full debugging messages, if the user enabled 652 * some dynamic debugging feature. */ 653 b43_modparam_verbose = B43_VERBOSITY_MAX; 654 } 655 656 return enabled; 657 } 658 659 static void b43_remove_dynamic_debug(struct b43_wldev *dev) 660 { 661 struct b43_dfsentry *e = dev->dfsentry; 662 int i; 663 664 for (i = 0; i < __B43_NR_DYNDBG; i++) 665 debugfs_remove(e->dyn_debug_dentries[i]); 666 } 667 668 static void b43_add_dynamic_debug(struct b43_wldev *dev) 669 { 670 struct b43_dfsentry *e = dev->dfsentry; 671 struct dentry *d; 672 673 #define add_dyn_dbg(name, id, initstate) do { \ 674 e->dyn_debug[id] = (initstate); \ 675 d = debugfs_create_bool(name, 0600, e->subdir, \ 676 &(e->dyn_debug[id])); \ 677 if (!IS_ERR(d)) \ 678 e->dyn_debug_dentries[id] = d; \ 679 } while (0) 680 681 add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, false); 682 add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, false); 683 add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, false); 684 add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, false); 685 add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, false); 686 add_dyn_dbg("debug_lo", B43_DBG_LO, false); 687 add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, false); 688 add_dyn_dbg("debug_keys", B43_DBG_KEYS, false); 689 add_dyn_dbg("debug_verbose_stats", B43_DBG_VERBOSESTATS, false); 690 691 #undef add_dyn_dbg 692 } 693 694 void b43_debugfs_add_device(struct b43_wldev *dev) 695 { 696 struct b43_dfsentry *e; 697 struct b43_txstatus_log *log; 698 char devdir[16]; 699 700 B43_WARN_ON(!dev); 701 e = kzalloc(sizeof(*e), GFP_KERNEL); 702 if (!e) { 703 b43err(dev->wl, "debugfs: add device OOM\n"); 704 return; 705 } 706 e->dev = dev; 707 log = &e->txstatlog; 708 log->log = kcalloc(B43_NR_LOGGED_TXSTATUS, 709 sizeof(struct b43_txstatus), GFP_KERNEL); 710 if (!log->log) { 711 b43err(dev->wl, "debugfs: add device txstatus OOM\n"); 712 kfree(e); 713 return; 714 } 715 log->end = -1; 716 717 dev->dfsentry = e; 718 719 snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy)); 720 e->subdir = debugfs_create_dir(devdir, rootdir); 721 if (!e->subdir || IS_ERR(e->subdir)) { 722 if (e->subdir == ERR_PTR(-ENODEV)) { 723 b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not " 724 "enabled in kernel config\n"); 725 } else { 726 b43err(dev->wl, "debugfs: cannot create %s directory\n", 727 devdir); 728 } 729 dev->dfsentry = NULL; 730 kfree(log->log); 731 kfree(e); 732 return; 733 } 734 735 e->mmio16read_next = 0xFFFF; /* invalid address */ 736 e->mmio32read_next = 0xFFFF; /* invalid address */ 737 e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */ 738 e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */ 739 e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */ 740 e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */ 741 742 #define ADD_FILE(name, mode) \ 743 do { \ 744 struct dentry *d; \ 745 d = debugfs_create_file(__stringify(name), \ 746 mode, e->subdir, dev, \ 747 &fops_##name.fops); \ 748 e->file_##name.dentry = NULL; \ 749 if (!IS_ERR(d)) \ 750 e->file_##name.dentry = d; \ 751 } while (0) 752 753 754 ADD_FILE(shm16read, 0600); 755 ADD_FILE(shm16write, 0200); 756 ADD_FILE(shm32read, 0600); 757 ADD_FILE(shm32write, 0200); 758 ADD_FILE(mmio16read, 0600); 759 ADD_FILE(mmio16write, 0200); 760 ADD_FILE(mmio32read, 0600); 761 ADD_FILE(mmio32write, 0200); 762 ADD_FILE(txstat, 0400); 763 ADD_FILE(restart, 0200); 764 ADD_FILE(loctls, 0400); 765 766 #undef ADD_FILE 767 768 b43_add_dynamic_debug(dev); 769 } 770 771 void b43_debugfs_remove_device(struct b43_wldev *dev) 772 { 773 struct b43_dfsentry *e; 774 775 if (!dev) 776 return; 777 e = dev->dfsentry; 778 if (!e) 779 return; 780 b43_remove_dynamic_debug(dev); 781 782 debugfs_remove(e->file_shm16read.dentry); 783 debugfs_remove(e->file_shm16write.dentry); 784 debugfs_remove(e->file_shm32read.dentry); 785 debugfs_remove(e->file_shm32write.dentry); 786 debugfs_remove(e->file_mmio16read.dentry); 787 debugfs_remove(e->file_mmio16write.dentry); 788 debugfs_remove(e->file_mmio32read.dentry); 789 debugfs_remove(e->file_mmio32write.dentry); 790 debugfs_remove(e->file_txstat.dentry); 791 debugfs_remove(e->file_restart.dentry); 792 debugfs_remove(e->file_loctls.dentry); 793 794 debugfs_remove(e->subdir); 795 kfree(e->txstatlog.log); 796 kfree(e); 797 } 798 799 void b43_debugfs_log_txstat(struct b43_wldev *dev, 800 const struct b43_txstatus *status) 801 { 802 struct b43_dfsentry *e = dev->dfsentry; 803 struct b43_txstatus_log *log; 804 struct b43_txstatus *cur; 805 int i; 806 807 if (!e) 808 return; 809 log = &e->txstatlog; 810 i = log->end + 1; 811 if (i == B43_NR_LOGGED_TXSTATUS) 812 i = 0; 813 log->end = i; 814 cur = &(log->log[i]); 815 memcpy(cur, status, sizeof(*cur)); 816 } 817 818 void b43_debugfs_init(void) 819 { 820 rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); 821 if (IS_ERR(rootdir)) 822 rootdir = NULL; 823 } 824 825 void b43_debugfs_exit(void) 826 { 827 debugfs_remove(rootdir); 828 } 829