OSDN Git Service

ASoC: dapm: Invalidate only paths reachable for a given stream
authorSzymon Mielczarek <szymonx.mielczarek@linux.intel.com>
Fri, 9 Aug 2019 08:40:34 +0000 (10:40 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 12 Aug 2019 13:01:59 +0000 (14:01 +0100)
By resetting the cached number of endpoints for all card's widgets we may
overwrite previously cached values for other streams. The situation may
happen especially when running streams simultaneously.

Signed-off-by: Szymon Mielczarek <szymonx.mielczarek@linux.intel.com>
Link: https://lore.kernel.org/r/20190809084034.26220-1-szymonx.mielczarek@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/soc-dapm.c

index d09bdca..10819b3 100644 (file)
@@ -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);