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.c50
1 files changed, 37 insertions, 13 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d09bdca63c62..10819b3e0b98 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1129,6 +1129,34 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
}
/*
+ * Recursively reset the cached number of inputs or outputs for the specified
+ * widget and all widgets that can be reached via incoming or outcoming paths
+ * from the widget.
+ */
+static void invalidate_paths_ep(struct snd_soc_dapm_widget *widget,
+ enum snd_soc_dapm_direction dir)
+{
+ enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
+ struct snd_soc_dapm_path *path;
+
+ widget->endpoints[dir] = -1;
+
+ snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
+ if (path->weak || path->is_supply)
+ continue;
+
+ if (path->walking)
+ return;
+
+ if (path->connect) {
+ path->walking = 1;
+ invalidate_paths_ep(path->node[dir], dir);
+ path->walking = 0;
+ }
+ }
+}
+
+/*
* Common implementation for is_connected_output_ep() and
* is_connected_input_ep(). The function is inlined since the combined size of
* the two specialized functions is only marginally larger then the size of the
@@ -1257,21 +1285,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- /*
- * For is_connected_{output,input}_ep fully discover the graph we need
- * to reset the cached number of inputs and outputs.
- */
- list_for_each_entry(w, &card->widgets, list) {
- w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
- w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
- }
-
- if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- paths = is_connected_output_ep(dai->playback_widget, &widgets,
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ w = dai->playback_widget;
+ invalidate_paths_ep(w, SND_SOC_DAPM_DIR_OUT);
+ paths = is_connected_output_ep(w, &widgets,
custom_stop_condition);
- else
- paths = is_connected_input_ep(dai->capture_widget, &widgets,
+ } else {
+ w = dai->capture_widget;
+ invalidate_paths_ep(w, SND_SOC_DAPM_DIR_IN);
+ paths = is_connected_input_ep(w, &widgets,
custom_stop_condition);
+ }
/* Drop starting point */
list_del(widgets.next);