diff options
Diffstat (limited to 'package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c')
-rw-r--r-- | package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c | 216 |
1 files changed, 198 insertions, 18 deletions
diff --git a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c index b24bf63c92..3ea9d08a27 100644 --- a/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c +++ b/package/bcm43xx-mac80211/src/bcm43xx/bcm43xx_debugfs.c @@ -254,6 +254,127 @@ out_unlock_bb: return res; } +static ssize_t txpower_g_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct bcm43xx_wldev *dev = file->private_data; + const size_t len = ARRAY_SIZE(big_buffer); + char *buf = big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + + mutex_lock(&big_buffer_mutex); + mutex_lock(&dev->wl->mutex); + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if ((bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) || + !dev->started) { + fappend("Not initialized\n"); + goto out; + } + if (dev->phy.type != BCM43xx_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 & BCM43xx_TXCTL_TXMIX) ? + "ON" : "OFF"); + fappend("PA Gain 2dB: %s\n", (dev->phy.tx_control & BCM43xx_TXCTL_PA2DB) ? + "ON" : "OFF"); + fappend("PA Gain 3dB: %s\n", (dev->phy.tx_control & BCM43xx_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: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + mutex_unlock(&dev->wl->mutex); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + mutex_unlock(&big_buffer_mutex); + + return res; +} + +static ssize_t txpower_g_write_file(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct bcm43xx_wldev *dev = file->private_data; + char *buf = big_buffer; + ssize_t buf_size; + ssize_t res; + unsigned long flags, phy_flags; + + mutex_lock(&big_buffer_mutex); + buf_size = min(count, ARRAY_SIZE(big_buffer) - 1); + if (copy_from_user(buf, user_buf, buf_size)) { + res = -EFAULT; + goto out_unlock_bb; + } + mutex_lock(&dev->wl->mutex); + spin_lock_irqsave(&dev->wl->irq_lock, flags); + if ((bcm43xx_status(dev) != BCM43xx_STAT_INITIALIZED) || + !dev->started) { + printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); + res = -ENODEV; + goto out_unlock; + } + if (dev->phy.type != BCM43xx_PHYTYPE_G) { + printk(KERN_ERR PFX "debugfs: Device is not a G-PHY\n"); + res = -ENODEV; + goto out_unlock; + } + if ((buf_size >= 4) && (memcmp(buf, "auto", 4) == 0)) { + /* Automatic control */ + dev->phy.manual_txpower_control = 0; + bcm43xx_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) { + printk(KERN_INFO PFX "debugfs: invalid value for \"tx_power_g\"\n"); + res = -EINVAL; + goto out_unlock; + } + bcm43xx_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 |= BCM43xx_TXCTL_TXMIX; + if (pa2db) + dev->phy.tx_control |= BCM43xx_TXCTL_PA2DB; + if (pa3db) + dev->phy.tx_control |= BCM43xx_TXCTL_PA3DB; + bcm43xx_phy_lock(dev, phy_flags); + bcm43xx_radio_lock(dev); + bcm43xx_set_txpower_g(dev, &dev->phy.bbatt, + &dev->phy.rfatt, dev->phy.tx_control); + bcm43xx_radio_unlock(dev); + bcm43xx_phy_unlock(dev, phy_flags); + } + res = buf_size; +out_unlock: + spin_unlock_irqrestore(&dev->wl->irq_lock, flags); + mutex_unlock(&dev->wl->mutex); +out_unlock_bb: + mutex_unlock(&big_buffer_mutex); + + return res; +} + + #undef fappend @@ -275,12 +396,53 @@ static struct file_operations txstat_fops = { .open = open_file_generic, }; +static struct file_operations txpower_g_fops = { + .read = txpower_g_read_file, + .write = txpower_g_write_file, + .open = open_file_generic, +}; + static struct file_operations restart_fops = { .write = restart_write_file, .open = open_file_generic, }; +int bcm43xx_debug(struct bcm43xx_wldev *dev, enum bcm43xx_dyndbg feature) +{ + return !!(dev->dfsentry->dyn_debug[feature]); +} + +static void bcm43xx_remove_dynamic_debug(struct bcm43xx_wldev *dev) +{ + struct bcm43xx_dfsentry *e = dev->dfsentry; + int i; + + for (i = 0; i < __BCM43xx_NR_DYNDBG; i++) + debugfs_remove(e->dyn_debug_dentries[i]); +} + +static void bcm43xx_add_dynamic_debug(struct bcm43xx_wldev *dev) +{ + struct bcm43xx_dfsentry *e = dev->dfsentry; + struct dentry *d; + +#define add_dyn_dbg(name, id, initstate) do { \ + e->dyn_debug[id] = (initstate); \ + d = debugfs_create_bool(name, 0600, e->subdir, \ + &(e->dyn_debug[id])); \ + if (!IS_ERR(d)) \ + e->dyn_debug_dentries[id] = d; \ + } while (0) + + add_dyn_dbg("debug_xmitpower", BCM43xx_DBG_XMITPOWER, 0); + add_dyn_dbg("debug_dmaoverflow", BCM43xx_DBG_DMAOVERFLOW, 0); + add_dyn_dbg("debug_pwork_fast", BCM43xx_DBG_PWORK_FAST, 0); + add_dyn_dbg("debug_pwork_stop", BCM43xx_DBG_PWORK_STOP, 0); + +#undef add_dyn_dbg +} + void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev) { struct bcm43xx_dfsentry *e; @@ -290,7 +452,7 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev) assert(dev); e = kzalloc(sizeof(*e), GFP_KERNEL); if (!e) { - printk(KERN_ERR PFX "out of memory\n"); + printk(KERN_ERR PFX "debugfs: add device OOM\n"); return; } e->dev = dev; @@ -299,7 +461,7 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev) sizeof(struct bcm43xx_txstatus), GFP_KERNEL); if (!log->log) { - printk(KERN_ERR PFX "debugfs txstatus log OOM\n"); + printk(KERN_ERR PFX "debugfs: add device txstatus OOM\n"); kfree(e); return; } @@ -310,18 +472,31 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_wldev *dev) snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy)); e->subdir = debugfs_create_dir(devdir, fs.root); - e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir, + if (!e->subdir || IS_ERR(e->subdir)) { + e->subdir = NULL; + kfree(log->log); + kfree(e); + return; + } + + e->dentry_tsf = debugfs_create_file("tsf", 0600, e->subdir, dev, &tsf_fops); - if (!e->dentry_tsf) - printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir); - e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir, + if (IS_ERR(e->dentry_tsf)) + e->dentry_tsf = NULL; + e->dentry_txstat = debugfs_create_file("tx_status", 0400, e->subdir, dev, &txstat_fops); - if (!e->dentry_txstat) - printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); - e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir, + if (IS_ERR(e->dentry_txstat)) + e->dentry_txstat = NULL; + e->dentry_txpower_g = debugfs_create_file("tx_power_g", 0600, e->subdir, + dev, &txpower_g_fops); + if (IS_ERR(e->dentry_txpower_g)) + e->dentry_txpower_g = NULL; + e->dentry_restart = debugfs_create_file("restart", 0200, e->subdir, dev, &restart_fops); - if (!e->dentry_restart) - printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir); + if (IS_ERR(e->dentry_restart)) + e->dentry_restart = NULL; + + bcm43xx_add_dynamic_debug(dev); } void bcm43xx_debugfs_remove_device(struct bcm43xx_wldev *dev) @@ -330,12 +505,14 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_wldev *dev) if (!dev) return; - e = dev->dfsentry; - assert(e); + if (!e) + return; + bcm43xx_remove_dynamic_debug(dev); debugfs_remove(e->dentry_tsf); debugfs_remove(e->dentry_txstat); debugfs_remove(e->dentry_restart); + debugfs_remove(e->dentry_txpower_g); debugfs_remove(e->subdir); kfree(e->txstatlog.log); kfree(e); @@ -365,11 +542,14 @@ void bcm43xx_debugfs_init(void) { memset(&fs, 0, sizeof(fs)); fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!fs.root) - printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n"); - fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops); - if (!fs.dentry_driverinfo) - printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n"); + if (!fs.root || IS_ERR(fs.root)) { + fs.root = NULL; + return; + } + fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, + NULL, &drvinfo_fops); + if (IS_ERR(fs.dentry_driverinfo)) + fs.dentry_driverinfo = NULL; } void bcm43xx_debugfs_exit(void) |