Commit 79fb9387 authored by Mark Brown's avatar Mark Brown

ASoC: Add DAPM widget power decision debugfs files

Currently when built with DEBUG DAPM will dump information about
the power state decisions it is taking for each widget to dmesg.
This isn't an ideal way of getting the information - it requires
a kernel build to turn it on and off and for large hub CODECs the
volume of information is so large as to be illegible. When the
output goes to the console it can also cause a noticable impact
on performance simply to print it out.

Improve the situation by adding a dapm directory to our debugfs
tree containing a file per widget with the same information in
it. This still requires a decision to build with debugfs support
but is easier to navigate and much less intrusive.

In addition to the previously displayed information active streams
are also shown in these files.
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
parent b8e583f6
...@@ -283,6 +283,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_device *socdev); ...@@ -283,6 +283,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
/* dapm sys fs - used by the core */ /* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev); int snd_soc_dapm_sys_add(struct device *dev);
void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec);
/* dapm audio pin control and status */ /* dapm audio pin control and status */
int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin); int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin);
......
...@@ -416,6 +416,7 @@ struct snd_soc_codec { ...@@ -416,6 +416,7 @@ struct snd_soc_codec {
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_reg; struct dentry *debugfs_reg;
struct dentry *debugfs_pop_time; struct dentry *debugfs_pop_time;
struct dentry *debugfs_dapm;
#endif #endif
}; };
......
...@@ -1267,10 +1267,18 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) ...@@ -1267,10 +1267,18 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
if (!codec->debugfs_pop_time) if (!codec->debugfs_pop_time)
printk(KERN_WARNING printk(KERN_WARNING
"Failed to create pop time debugfs file\n"); "Failed to create pop time debugfs file\n");
codec->debugfs_dapm = debugfs_create_dir("dapm", debugfs_root);
if (!codec->debugfs_dapm)
printk(KERN_WARNING
"Failed to create DAPM debugfs directory\n");
snd_soc_dapm_debugfs_init(codec);
} }
static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
{ {
debugfs_remove_recursive(codec->debugfs_dapm);
debugfs_remove(codec->debugfs_pop_time); debugfs_remove(codec->debugfs_pop_time);
debugfs_remove(codec->debugfs_reg); debugfs_remove(codec->debugfs_reg);
} }
......
...@@ -1081,6 +1081,92 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) ...@@ -1081,6 +1081,92 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
} }
#endif #endif
#ifdef CONFIG_DEBUG_FS
static int dapm_widget_power_open_file(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t dapm_widget_power_read_file(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct snd_soc_dapm_widget *w = file->private_data;
char *buf;
int in, out;
ssize_t ret;
struct snd_soc_dapm_path *p = NULL;
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
in = is_connected_input_ep(w);
dapm_clear_walk(w->codec);
out = is_connected_output_ep(w);
dapm_clear_walk(w->codec);
ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d\n",
w->name, w->power ? "On" : "Off", in, out);
if (w->active && w->sname)
ret += snprintf(buf, PAGE_SIZE - ret, " stream %s active\n",
w->sname);
list_for_each_entry(p, &w->sources, list_sink) {
if (p->connect)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
" in %s %s\n",
p->name ? p->name : "static",
p->source->name);
}
list_for_each_entry(p, &w->sinks, list_source) {
if (p->connect)
ret += snprintf(buf + ret, PAGE_SIZE - ret,
" out %s %s\n",
p->name ? p->name : "static",
p->sink->name);
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
return ret;
}
static const struct file_operations dapm_widget_power_fops = {
.open = dapm_widget_power_open_file,
.read = dapm_widget_power_read_file,
};
void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_widget *w;
struct dentry *d;
if (!codec->debugfs_dapm)
return;
list_for_each_entry(w, &codec->dapm_widgets, list) {
if (!w->name)
continue;
d = debugfs_create_file(w->name, 0444,
codec->debugfs_dapm, w,
&dapm_widget_power_fops);
if (!d)
printk(KERN_WARNING
"ASoC: Failed to create %s debugfs file\n",
w->name);
}
}
#else
void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec)
{
}
#endif
/* test and update the power status of a mux widget */ /* test and update the power status of a mux widget */
static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, int mask, struct snd_kcontrol *kcontrol, int mask,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment