summaryrefslogtreecommitdiff
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d515e7a78ea8..248d5f7d86f9 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2210,6 +2210,139 @@ static const struct file_operations dapm_bias_fops = {
.llseek = default_llseek,
};
+static ssize_t dapm_graph_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct snd_soc_card *card = file->private_data;
+ struct snd_soc_dapm_context *dapm;
+ struct snd_soc_dapm_path *p;
+ struct snd_soc_dapm_widget *w;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dapm_widget *wdone[16];
+ struct snd_soc_dai *dai;
+ int i, num_wdone = 0, cluster = 0;
+ char *buf;
+ ssize_t bufsize;
+ ssize_t ret = 0;
+
+ bufsize = 1024 * card->num_dapm_widgets;
+ buf = kmalloc(bufsize, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&card->dapm_mutex);
+
+#define bufprintf(...) \
+ ret += scnprintf(buf + ret, bufsize - ret, __VA_ARGS__)
+
+ bufprintf("digraph dapm {\n");
+
+ /*
+ * Print the user-visible devices of the card.
+ */
+ bufprintf("subgraph cluster_%d {\n", cluster++);
+ bufprintf("label=\"Devices\";style=filled;fillcolor=gray;\n");
+ for_each_card_rtds(card, rtd) {
+ if (rtd->dai_link->no_pcm)
+ continue;
+
+ bufprintf("w%pK [label=\"%d: %s\"];\n", rtd,
+ rtd->pcm->device, rtd->dai_link->name);
+ }
+ bufprintf("};\n");
+
+ /*
+ * Print the playback/capture widgets of DAIs just next to
+ * the user-visible devices. Keep the list of already printed
+ * widgets in 'wdone', so they will be skipped later.
+ */
+ for_each_card_rtds(card, rtd) {
+ for_each_rtd_cpu_dais(rtd, i, dai) {
+ if (dai->playback_widget) {
+ w = dai->playback_widget;
+ bufprintf("w%pK [label=\"%s\"];\n", w, w->name);
+ if (!rtd->dai_link->no_pcm)
+ bufprintf("w%pK -> w%pK;\n", rtd, w);
+ wdone[num_wdone] = w;
+ if (num_wdone < ARRAY_SIZE(wdone))
+ num_wdone++;
+ }
+
+ if (dai->capture_widget) {
+ w = dai->capture_widget;
+ bufprintf("w%pK [label=\"%s\"];\n", w, w->name);
+ if (!rtd->dai_link->no_pcm)
+ bufprintf("w%pK -> w%pK;\n", w, rtd);
+ wdone[num_wdone] = w;
+ if (num_wdone < ARRAY_SIZE(wdone))
+ num_wdone++;
+ }
+ }
+ }
+
+ for_each_card_dapms(card, dapm) {
+ const char *prefix = soc_dapm_prefix(dapm);
+
+ if (dapm != &card->dapm) {
+ bufprintf("subgraph cluster_%d {\n", cluster++);
+ if (prefix)
+ bufprintf("label=\"%s\";\n", prefix);
+ else if (dapm->component)
+ bufprintf("label=\"%s\";\n",
+ dapm->component->name);
+ }
+
+ for_each_card_widgets(dapm->card, w) {
+ const char *name = w->name;
+ bool skip = false;
+
+ if (w->dapm != dapm)
+ continue;
+
+ if (list_empty(&w->edges[0]) && list_empty(&w->edges[1]))
+ continue;
+
+ for (i = 0; i < num_wdone; i++)
+ if (wdone[i] == w)
+ skip = true;
+ if (skip)
+ continue;
+
+ if (prefix && strlen(name) > strlen(prefix) + 1)
+ name += strlen(prefix) + 1;
+
+ bufprintf("w%pK [label=\"%s\"];\n", w, name);
+ }
+
+ if (dapm != &card->dapm)
+ bufprintf("}\n");
+ }
+
+ list_for_each_entry(p, &card->paths, list) {
+ if (p->name)
+ bufprintf("w%pK -> w%pK [label=\"%s\"];\n",
+ p->source, p->sink, p->name);
+ else
+ bufprintf("w%pK -> w%pK;\n", p->source, p->sink);
+ }
+
+ bufprintf("}\n");
+#undef bufprintf
+
+ mutex_unlock(&card->dapm_mutex);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations dapm_graph_fops = {
+ .open = simple_open,
+ .read = dapm_graph_read_file,
+ .llseek = default_llseek,
+};
+
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
struct dentry *parent)
{
@@ -2220,6 +2353,10 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
debugfs_create_file("bias_level", 0444, dapm->debugfs_dapm, dapm,
&dapm_bias_fops);
+
+ if (dapm == &dapm->card->dapm)
+ debugfs_create_file("graph.dot", 0444, dapm->debugfs_dapm,
+ dapm->card, &dapm_graph_fops);
}
static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)