|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright (c) 2007 Bruno Randolf <bruno@thinktube.com>
|
|
|
+ * Copyright (c) 2007-2008 Bruno Randolf <bruno@thinktube.com>
|
|
|
*
|
|
|
* This file is free software: you may copy, redistribute and/or modify it
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
@@ -200,7 +200,7 @@ static ssize_t read_file_tsf(struct file *file, char __user *user_buf,
|
|
|
{
|
|
|
struct ath5k_softc *sc = file->private_data;
|
|
|
char buf[100];
|
|
|
- snprintf(buf, 100, "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
|
|
|
+ snprintf(buf, sizeof(buf), "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
|
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf, 19);
|
|
|
}
|
|
|
|
|
@@ -209,7 +209,12 @@ static ssize_t write_file_tsf(struct file *file,
|
|
|
size_t count, loff_t *ppos)
|
|
|
{
|
|
|
struct ath5k_softc *sc = file->private_data;
|
|
|
- if (strncmp(userbuf, "reset", 5) == 0) {
|
|
|
+ char buf[20];
|
|
|
+
|
|
|
+ if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ if (strncmp(buf, "reset", 5) == 0) {
|
|
|
ath5k_hw_reset_tsf(sc->ah);
|
|
|
printk(KERN_INFO "debugfs reset TSF\n");
|
|
|
}
|
|
@@ -231,8 +236,8 @@ static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
|
|
|
{
|
|
|
struct ath5k_softc *sc = file->private_data;
|
|
|
struct ath5k_hw *ah = sc->ah;
|
|
|
- char buf[1000];
|
|
|
- int len = 0;
|
|
|
+ char buf[500];
|
|
|
+ unsigned int len = 0;
|
|
|
unsigned int v;
|
|
|
u64 tsf;
|
|
|
|
|
@@ -277,11 +282,15 @@ static ssize_t write_file_beacon(struct file *file,
|
|
|
{
|
|
|
struct ath5k_softc *sc = file->private_data;
|
|
|
struct ath5k_hw *ah = sc->ah;
|
|
|
+ char buf[20];
|
|
|
+
|
|
|
+ if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
|
|
|
+ return -EFAULT;
|
|
|
|
|
|
- if (strncmp(userbuf, "disable", 7) == 0) {
|
|
|
+ if (strncmp(buf, "disable", 7) == 0) {
|
|
|
AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
|
|
|
printk(KERN_INFO "debugfs disable beacons\n");
|
|
|
- } else if (strncmp(userbuf, "enable", 6) == 0) {
|
|
|
+ } else if (strncmp(buf, "enable", 6) == 0) {
|
|
|
AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
|
|
|
printk(KERN_INFO "debugfs enable beacons\n");
|
|
|
}
|
|
@@ -314,6 +323,82 @@ static const struct file_operations fops_reset = {
|
|
|
};
|
|
|
|
|
|
|
|
|
+/* debugfs: debug level */
|
|
|
+
|
|
|
+static struct {
|
|
|
+ enum ath5k_debug_level level;
|
|
|
+ const char *name;
|
|
|
+ const char *desc;
|
|
|
+} dbg_info[] = {
|
|
|
+ { ATH5K_DEBUG_RESET, "reset", "reset and initialization" },
|
|
|
+ { ATH5K_DEBUG_INTR, "intr", "interrupt handling" },
|
|
|
+ { ATH5K_DEBUG_MODE, "mode", "mode init/setup" },
|
|
|
+ { ATH5K_DEBUG_XMIT, "xmit", "basic xmit operation" },
|
|
|
+ { ATH5K_DEBUG_BEACON, "beacon", "beacon handling" },
|
|
|
+ { ATH5K_DEBUG_CALIBRATE, "calib", "periodic calibration" },
|
|
|
+ { ATH5K_DEBUG_TXPOWER, "txpower", "transmit power setting" },
|
|
|
+ { ATH5K_DEBUG_LED, "led", "LED mamagement" },
|
|
|
+ { ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" },
|
|
|
+ { ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" },
|
|
|
+ { ATH5K_DEBUG_DUMPMODES, "dumpmodes", "dump modes" },
|
|
|
+ { ATH5K_DEBUG_TRACE, "trace", "trace function calls" },
|
|
|
+ { ATH5K_DEBUG_ANY, "all", "show all debug levels" },
|
|
|
+};
|
|
|
+
|
|
|
+static ssize_t read_file_debug(struct file *file, char __user *user_buf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ struct ath5k_softc *sc = file->private_data;
|
|
|
+ char buf[700];
|
|
|
+ unsigned int len = 0;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ len += snprintf(buf+len, sizeof(buf)-len,
|
|
|
+ "DEBUG LEVEL: 0x%08x\n\n", sc->debug.level);
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(dbg_info) - 1; i++) {
|
|
|
+ len += snprintf(buf+len, sizeof(buf)-len,
|
|
|
+ "%10s %c 0x%08x - %s\n", dbg_info[i].name,
|
|
|
+ sc->debug.level & dbg_info[i].level ? '+' : ' ',
|
|
|
+ dbg_info[i].level, dbg_info[i].desc);
|
|
|
+ }
|
|
|
+ len += snprintf(buf+len, sizeof(buf)-len,
|
|
|
+ "%10s %c 0x%08x - %s\n", dbg_info[i].name,
|
|
|
+ sc->debug.level == dbg_info[i].level ? '+' : ' ',
|
|
|
+ dbg_info[i].level, dbg_info[i].desc);
|
|
|
+
|
|
|
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t write_file_debug(struct file *file,
|
|
|
+ const char __user *userbuf,
|
|
|
+ size_t count, loff_t *ppos)
|
|
|
+{
|
|
|
+ struct ath5k_softc *sc = file->private_data;
|
|
|
+ unsigned int i;
|
|
|
+ char buf[20];
|
|
|
+
|
|
|
+ if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(dbg_info); i++) {
|
|
|
+ if (strncmp(buf, dbg_info[i].name,
|
|
|
+ strlen(dbg_info[i].name)) == 0) {
|
|
|
+ sc->debug.level ^= dbg_info[i].level; /* toggle bit */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return count;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct file_operations fops_debug = {
|
|
|
+ .read = read_file_debug,
|
|
|
+ .write = write_file_debug,
|
|
|
+ .open = ath5k_debugfs_open,
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
/* init */
|
|
|
|
|
|
void
|
|
@@ -326,26 +411,24 @@ void
|
|
|
ath5k_debug_init_device(struct ath5k_softc *sc)
|
|
|
{
|
|
|
sc->debug.level = ath5k_debug;
|
|
|
+
|
|
|
sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
|
|
|
- ath5k_global_debugfs);
|
|
|
- sc->debug.debugfs_debug = debugfs_create_u32("debug",
|
|
|
- 0666, sc->debug.debugfs_phydir, &sc->debug.level);
|
|
|
+ ath5k_global_debugfs);
|
|
|
+
|
|
|
+ sc->debug.debugfs_debug = debugfs_create_file("debug", 0666,
|
|
|
+ sc->debug.debugfs_phydir, sc, &fops_debug);
|
|
|
|
|
|
sc->debug.debugfs_registers = debugfs_create_file("registers", 0444,
|
|
|
- sc->debug.debugfs_phydir,
|
|
|
- sc, &fops_registers);
|
|
|
+ sc->debug.debugfs_phydir, sc, &fops_registers);
|
|
|
|
|
|
sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666,
|
|
|
- sc->debug.debugfs_phydir,
|
|
|
- sc, &fops_tsf);
|
|
|
+ sc->debug.debugfs_phydir, sc, &fops_tsf);
|
|
|
|
|
|
sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666,
|
|
|
- sc->debug.debugfs_phydir,
|
|
|
- sc, &fops_beacon);
|
|
|
+ sc->debug.debugfs_phydir, sc, &fops_beacon);
|
|
|
|
|
|
sc->debug.debugfs_reset = debugfs_create_file("reset", 0222,
|
|
|
- sc->debug.debugfs_phydir,
|
|
|
- sc, &fops_reset);
|
|
|
+ sc->debug.debugfs_phydir, sc, &fops_reset);
|
|
|
}
|
|
|
|
|
|
void
|
|
@@ -415,8 +498,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
|
|
|
struct ath5k_buf *bf;
|
|
|
int status;
|
|
|
|
|
|
- if (likely(!(sc->debug.level &
|
|
|
- (ATH5K_DEBUG_RESET | ATH5K_DEBUG_FATAL))))
|
|
|
+ if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
|
|
|
return;
|
|
|
|
|
|
printk(KERN_DEBUG "rx queue %x, link %p\n",
|
|
@@ -426,7 +508,7 @@ ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
|
|
|
list_for_each_entry(bf, &sc->rxbuf, list) {
|
|
|
ds = bf->desc;
|
|
|
status = ah->ah_proc_rx_desc(ah, ds);
|
|
|
- if (!status || (sc->debug.level & ATH5K_DEBUG_FATAL))
|
|
|
+ if (!status)
|
|
|
ath5k_debug_printrxbuf(bf, status == 0);
|
|
|
}
|
|
|
spin_unlock_bh(&sc->rxbuflock);
|