📄 debugfs.c
字号:
/* Broadcom B43 wireless driver debugfs driver debugging code Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.*/#include <linux/fs.h>#include <linux/debugfs.h>#include <linux/slab.h>#include <linux/netdevice.h>#include <linux/pci.h>#include <linux/mutex.h>#include "b43.h"#include "main.h"#include "debugfs.h"#include "dma.h"#include "pio.h"#include "xmit.h"/* The root directory. */static struct dentry *rootdir;struct b43_debugfs_fops { ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize); int (*write)(struct b43_wldev *dev, const char *buf, size_t count); struct file_operations fops; /* Offset of struct b43_dfs_file in struct b43_dfsentry */ size_t file_struct_offset; /* Take wl->irq_lock before calling read/write? */ bool take_irqlock;};static inlinestruct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev, const struct b43_debugfs_fops *dfops){ void *p; p = dev->dfsentry; p += dfops->file_struct_offset; return p;}#define fappend(fmt, x...) \ do { \ if (bufsize - count) \ count += snprintf(buf + count, \ bufsize - count, \ fmt , ##x); \ else \ printk(KERN_ERR "b43: fappend overflow\n"); \ } while (0)/* wl->irq_lock is locked */static ssize_t tsf_read_file(struct b43_wldev *dev, char *buf, size_t bufsize){ ssize_t count = 0; u64 tsf; b43_tsf_read(dev, &tsf); fappend("0x%08x%08x\n", (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), (unsigned int)(tsf & 0xFFFFFFFFULL)); return count;}/* wl->irq_lock is locked */static int tsf_write_file(struct b43_wldev *dev, const char *buf, size_t count){ u64 tsf; if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1) return -EINVAL; b43_tsf_write(dev, tsf); return 0;}/* wl->irq_lock is locked */static ssize_t ucode_regs_read_file(struct b43_wldev *dev, char *buf, size_t bufsize){ ssize_t count = 0; int i; for (i = 0; i < 64; i++) { fappend("r%d = 0x%04x\n", i, b43_shm_read16(dev, B43_SHM_SCRATCH, i)); } return count;}/* wl->irq_lock is locked */static ssize_t shm_read_file(struct b43_wldev *dev, char *buf, size_t bufsize){ ssize_t count = 0; int i; u16 tmp; __le16 *le16buf = (__le16 *)buf; for (i = 0; i < 0x1000; i++) { if (bufsize < sizeof(tmp)) break; tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i); le16buf[i] = cpu_to_le16(tmp); count += sizeof(tmp); bufsize -= sizeof(tmp); } return count;}static ssize_t txstat_read_file(struct b43_wldev *dev, char *buf, size_t bufsize){ struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; ssize_t count = 0; unsigned long flags; int i, idx; struct b43_txstatus *stat; spin_lock_irqsave(&log->lock, flags); if (log->end < 0) { fappend("Nothing transmitted, yet\n"); goto out_unlock; } fappend("b43 TX status reports:\n\n" "index | cookie | seq | phy_stat | frame_count | " "rts_count | supp_reason | pm_indicated | " "intermediate | for_ampdu | acked\n" "---\n"); i = log->end + 1; idx = 0; while (1) { if (i == B43_NR_LOGGED_TXSTATUS) i = 0; stat = &(log->log[i]); if (stat->cookie) { fappend("%03d | " "0x%04X | 0x%04X | 0x%02X | " "0x%X | 0x%X | " "%u | %u | " "%u | %u | %u\n", idx, stat->cookie, stat->seq, stat->phy_stat, stat->frame_count, stat->rts_count, stat->supp_reason, stat->pm_indicated, stat->intermediate, stat->for_ampdu, stat->acked); idx++; } if (i == log->end) break; i++; }out_unlock: spin_unlock_irqrestore(&log->lock, flags); return count;}static ssize_t txpower_g_read_file(struct b43_wldev *dev, char *buf, size_t bufsize){ ssize_t count = 0; if (dev->phy.type != B43_PHYTYPE_G) { fappend("Device is not a G-PHY\n"); goto out; } fappend("Control: %s\n", dev->phy.manual_txpower_control ? "MANUAL" : "AUTOMATIC"); fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att); fappend("Radio attenuation: %u\n", dev->phy.rfatt.att); fappend("TX Mixer Gain: %s\n", (dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF"); fappend("PA Gain 2dB: %s\n", (dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF"); fappend("PA Gain 3dB: %s\n", (dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF"); fappend("\n\n"); fappend("You can write to this file:\n"); fappend("Writing \"auto\" enables automatic txpower control.\n"); fappend ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" " "enables manual txpower control.\n"); fappend("Example: 5 4 0 0 1\n"); fappend("Enables manual control with Baseband attenuation 5, " "Radio attenuation 4, No TX Mixer Gain, " "No PA Gain 2dB, With PA Gain 3dB.\n");out: return count;}static int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count){ unsigned long phy_flags; if (dev->phy.type != B43_PHYTYPE_G) return -ENODEV; if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { /* Automatic control */ dev->phy.manual_txpower_control = 0; b43_phy_xmitpower(dev); } else { int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0; /* Manual control */ if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt, &txmix, &pa2db, &pa3db) != 5) return -EINVAL; b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); dev->phy.manual_txpower_control = 1; dev->phy.bbatt.att = bbatt; dev->phy.rfatt.att = rfatt; dev->phy.tx_control = 0; if (txmix) dev->phy.tx_control |= B43_TXCTL_TXMIX; if (pa2db) dev->phy.tx_control |= B43_TXCTL_PA2DB; if (pa3db) dev->phy.tx_control |= B43_TXCTL_PA3DB; b43_phy_lock(dev, phy_flags); b43_radio_lock(dev); b43_set_txpower_g(dev, &dev->phy.bbatt, &dev->phy.rfatt, dev->phy.tx_control); b43_radio_unlock(dev); b43_phy_unlock(dev, phy_flags); } return 0;}/* wl->irq_lock is locked */static int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count){ int err = 0; if (count > 0 && buf[0] == '1') { b43_controller_restart(dev, "manually restarted"); } else err = -EINVAL; return err;}static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize, struct b43_loctl table[B43_NR_BB][B43_NR_RF]){ unsigned int i, j; struct b43_loctl *ctl; for (i = 0; i < B43_NR_BB; i++) { for (j = 0; j < B43_NR_RF; j++) { ctl = &(table[i][j]); fappend("(bbatt %2u, rfatt %2u) -> " "(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n", i, j, ctl->i, ctl->q, ctl->used, b43_loctl_is_calibrated(ctl)); } } return count;}static ssize_t loctls_read_file(struct b43_wldev *dev, char *buf, size_t bufsize){ ssize_t count = 0; struct b43_txpower_lo_control *lo; int i, err = 0; if (dev->phy.type != B43_PHYTYPE_G) { fappend("Device is not a G-PHY\n"); err = -ENODEV; goto out; } lo = dev->phy.lo_control; fappend("-- Local Oscillator calibration data --\n\n"); fappend("Measured: %d, Rebuild: %d, HW-power-control: %d\n", lo->lo_measured, lo->rebuild, dev->phy.hardware_power_control); fappend("TX Bias: 0x%02X, TX Magn: 0x%02X\n", lo->tx_bias, lo->tx_magn); fappend("Power Vector: 0x%08X%08X\n", (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32), (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL)); fappend("\nControl table WITH PADMIX:\n"); count = append_lo_table(count, buf, bufsize, lo->with_padmix); fappend("\nControl table WITHOUT PADMIX:\n"); count = append_lo_table(count, buf, bufsize, lo->no_padmix); fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n"); for (i = 0; i < lo->rfatt_list.len; i++) { fappend("%u(%d), ", lo->rfatt_list.list[i].att, lo->rfatt_list.list[i].with_padmix); } fappend("\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -