aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h1
-rw-r--r--sound/soc/soc-dapm.c161
2 files changed, 154 insertions, 8 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 43ca1656dab4..89823cfe6f04 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -569,6 +569,7 @@ struct snd_soc_dapm_widget {
569 struct list_head sinks; 569 struct list_head sinks;
570 570
571 /* used during DAPM updates */ 571 /* used during DAPM updates */
572 struct list_head work_list;
572 struct list_head power_list; 573 struct list_head power_list;
573 struct list_head dirty; 574 struct list_head dirty;
574 int inputs; 575 int inputs;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 8e26c2bc7fdf..6bf2c9795df2 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -159,6 +159,116 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
159 } 159 }
160} 160}
161 161
162/*
163 * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input
164 * paths
165 * @w: The widget for which to invalidate the cached number of input paths
166 *
167 * The function resets the cached number of inputs for the specified widget and
168 * all widgets that can be reached via outgoing paths from the widget.
169 *
170 * This function must be called if the number of input paths for a widget might
171 * have changed. E.g. if the source state of a widget changes or a path is added
172 * or activated with the widget as the sink.
173 */
174static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
175{
176 struct snd_soc_dapm_widget *sink;
177 struct snd_soc_dapm_path *p;
178 LIST_HEAD(list);
179
180 dapm_assert_locked(w->dapm);
181
182 if (w->inputs == -1)
183 return;
184
185 w->inputs = -1;
186 list_add_tail(&w->work_list, &list);
187
188 list_for_each_entry(w, &list, work_list) {
189 list_for_each_entry(p, &w->sinks, list_source) {
190 if (p->is_supply || p->weak || !p->connect)
191 continue;
192 sink = p->sink;
193 if (sink->inputs != -1) {
194 sink->inputs = -1;
195 list_add_tail(&sink->work_list, &list);
196 }
197 }
198 }
199}
200
201/*
202 * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
203 * output paths
204 * @w: The widget for which to invalidate the cached number of output paths
205 *
206 * Resets the cached number of outputs for the specified widget and all widgets
207 * that can be reached via incoming paths from the widget.
208 *
209 * This function must be called if the number of output paths for a widget might
210 * have changed. E.g. if the sink state of a widget changes or a path is added
211 * or activated with the widget as the source.
212 */
213static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
214{
215 struct snd_soc_dapm_widget *source;
216 struct snd_soc_dapm_path *p;
217 LIST_HEAD(list);
218
219 dapm_assert_locked(w->dapm);
220
221 if (w->outputs == -1)
222 return;
223
224 w->outputs = -1;
225 list_add_tail(&w->work_list, &list);
226
227 list_for_each_entry(w, &list, work_list) {
228 list_for_each_entry(p, &w->sources, list_sink) {
229 if (p->is_supply || p->weak || !p->connect)
230 continue;
231 source = p->source;
232 if (source->outputs != -1) {
233 source->outputs = -1;
234 list_add_tail(&source->work_list, &list);
235 }
236 }
237 }
238}
239
240/*
241 * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
242 * for the widgets connected to a path
243 * @p: The path to invalidate
244 *
245 * Resets the cached number of inputs for the sink of the path and the cached
246 * number of outputs for the source of the path.
247 *
248 * This function must be called when a path is added, removed or the connected
249 * state changes.
250 */
251static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
252{
253 /*
254 * Weak paths or supply paths do not influence the number of input or
255 * output paths of their neighbors.
256 */
257 if (p->weak || p->is_supply)
258 return;
259
260 /*
261 * The number of connected endpoints is the sum of the number of
262 * connected endpoints of all neighbors. If a node with 0 connected
263 * endpoints is either connected or disconnected that sum won't change,
264 * so there is no need to re-check the path.
265 */
266 if (p->source->inputs != 0)
267 dapm_widget_invalidate_input_paths(p->sink);
268 if (p->sink->outputs != 0)
269 dapm_widget_invalidate_output_paths(p->source);
270}
271
162void dapm_mark_endpoints_dirty(struct snd_soc_card *card) 272void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
163{ 273{
164 struct snd_soc_dapm_widget *w; 274 struct snd_soc_dapm_widget *w;
@@ -166,8 +276,13 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
166 mutex_lock(&card->dapm_mutex); 276 mutex_lock(&card->dapm_mutex);
167 277
168 list_for_each_entry(w, &card->widgets, list) { 278 list_for_each_entry(w, &card->widgets, list) {
169 if (w->is_sink || w->is_source) 279 if (w->is_sink || w->is_source) {
170 dapm_mark_dirty(w, "Rechecking endpoints"); 280 dapm_mark_dirty(w, "Rechecking endpoints");
281 if (w->is_sink)
282 dapm_widget_invalidate_output_paths(w);
283 if (w->is_source)
284 dapm_widget_invalidate_input_paths(w);
285 }
171 } 286 }
172 287
173 mutex_unlock(&card->dapm_mutex); 288 mutex_unlock(&card->dapm_mutex);
@@ -379,8 +494,6 @@ static void dapm_reset(struct snd_soc_card *card)
379 list_for_each_entry(w, &card->widgets, list) { 494 list_for_each_entry(w, &card->widgets, list) {
380 w->new_power = w->power; 495 w->new_power = w->power;
381 w->power_checked = false; 496 w->power_checked = false;
382 w->inputs = -1;
383 w->outputs = -1;
384 } 497 }
385} 498}
386 499
@@ -931,10 +1044,19 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
931 struct snd_soc_dapm_widget_list **list) 1044 struct snd_soc_dapm_widget_list **list)
932{ 1045{
933 struct snd_soc_card *card = dai->card; 1046 struct snd_soc_card *card = dai->card;
1047 struct snd_soc_dapm_widget *w;
934 int paths; 1048 int paths;
935 1049
936 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); 1050 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
937 dapm_reset(card); 1051
1052 /*
1053 * For is_connected_{output,input}_ep fully discover the graph we need
1054 * to reset the cached number of inputs and outputs.
1055 */
1056 list_for_each_entry(w, &card->widgets, list) {
1057 w->inputs = -1;
1058 w->outputs = -1;
1059 }
938 1060
939 if (stream == SNDRV_PCM_STREAM_PLAYBACK) 1061 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
940 paths = is_connected_output_ep(dai->playback_widget, list); 1062 paths = is_connected_output_ep(dai->playback_widget, list);
@@ -1846,6 +1968,7 @@ static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
1846 path->connect = connect; 1968 path->connect = connect;
1847 dapm_mark_dirty(path->source, reason); 1969 dapm_mark_dirty(path->source, reason);
1848 dapm_mark_dirty(path->sink, reason); 1970 dapm_mark_dirty(path->sink, reason);
1971 dapm_path_invalidate(path);
1849} 1972}
1850 1973
1851/* test and update the power status of a mux widget */ 1974/* test and update the power status of a mux widget */
@@ -2084,8 +2207,11 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
2084 return -EINVAL; 2207 return -EINVAL;
2085 } 2208 }
2086 2209
2087 if (w->connected != status) 2210 if (w->connected != status) {
2088 dapm_mark_dirty(w, "pin configuration"); 2211 dapm_mark_dirty(w, "pin configuration");
2212 dapm_widget_invalidate_input_paths(w);
2213 dapm_widget_invalidate_output_paths(w);
2214 }
2089 2215
2090 w->connected = status; 2216 w->connected = status;
2091 if (status == 0) 2217 if (status == 0)
@@ -2267,6 +2393,9 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2267 dapm_mark_dirty(wsource, "Route added"); 2393 dapm_mark_dirty(wsource, "Route added");
2268 dapm_mark_dirty(wsink, "Route added"); 2394 dapm_mark_dirty(wsink, "Route added");
2269 2395
2396 if (dapm->card->instantiated && path->connect)
2397 dapm_path_invalidate(path);
2398
2270 return 0; 2399 return 0;
2271err: 2400err:
2272 kfree(path); 2401 kfree(path);
@@ -2390,6 +2519,8 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2390 2519
2391 dapm_mark_dirty(wsource, "Route removed"); 2520 dapm_mark_dirty(wsource, "Route removed");
2392 dapm_mark_dirty(wsink, "Route removed"); 2521 dapm_mark_dirty(wsink, "Route removed");
2522 if (path->connect)
2523 dapm_path_invalidate(path);
2393 2524
2394 dapm_free_path(path); 2525 dapm_free_path(path);
2395 2526
@@ -3007,6 +3138,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3007 INIT_LIST_HEAD(&w->dirty); 3138 INIT_LIST_HEAD(&w->dirty);
3008 list_add(&w->list, &dapm->card->widgets); 3139 list_add(&w->list, &dapm->card->widgets);
3009 3140
3141 w->inputs = -1;
3142 w->outputs = -1;
3143
3010 /* machine layer set ups unconnected pins and insertions */ 3144 /* machine layer set ups unconnected pins and insertions */
3011 w->connected = 1; 3145 w->connected = 1;
3012 return w; 3146 return w;
@@ -3355,10 +3489,13 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
3355 break; 3489 break;
3356 } 3490 }
3357 3491
3358 if (w->id == snd_soc_dapm_dai_in) 3492 if (w->id == snd_soc_dapm_dai_in) {
3359 w->is_source = w->active; 3493 w->is_source = w->active;
3360 else 3494 dapm_widget_invalidate_input_paths(w);
3495 } else {
3361 w->is_sink = w->active; 3496 w->is_sink = w->active;
3497 dapm_widget_invalidate_output_paths(w);
3498 }
3362 } 3499 }
3363} 3500}
3364 3501
@@ -3485,7 +3622,15 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3485 } 3622 }
3486 3623
3487 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin); 3624 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
3488 w->connected = 1; 3625 if (!w->connected) {
3626 /*
3627 * w->force does not affect the number of input or output paths,
3628 * so we only have to recheck if w->connected is changed
3629 */
3630 dapm_widget_invalidate_input_paths(w);
3631 dapm_widget_invalidate_output_paths(w);
3632 w->connected = 1;
3633 }
3489 w->force = 1; 3634 w->force = 1;
3490 dapm_mark_dirty(w, "force enable"); 3635 dapm_mark_dirty(w, "force enable");
3491 3636