diff options
-rw-r--r-- | include/sound/soc-dapm.h | 1 | ||||
-rw-r--r-- | include/sound/soc.h | 1 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 1 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 61 |
4 files changed, 58 insertions, 6 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index bb5953219d0b..c080635b3c35 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -492,6 +492,7 @@ struct snd_soc_dapm_widget { /* used during DAPM updates */ struct list_head power_list; + struct list_head dirty; }; struct snd_soc_dapm_update { diff --git a/include/sound/soc.h b/include/sound/soc.h index 9d0524a3a7f8..8ab1cfed1067 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -826,6 +826,7 @@ struct snd_soc_card { struct list_head widgets; struct list_head paths; struct list_head dapm_list; + struct list_head dapm_dirty; /* Generic DAPM context for the card */ struct snd_soc_dapm_context dapm; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1ed8093b44e8..778c177b5bfb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2916,6 +2916,7 @@ int snd_soc_register_card(struct snd_soc_card *card) card->rtd[i].dai_link = &card->dai_link[i]; INIT_LIST_HEAD(&card->list); + INIT_LIST_HEAD(&card->dapm_dirty); card->instantiated = 0; mutex_init(&card->mutex); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index cb00918b08d6..9d6bb33e6094 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -119,6 +119,17 @@ static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...) kfree(buf); } +static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w) +{ + return !list_empty(&w->dirty); +} + +static void dapm_mark_dirty(struct snd_soc_dapm_widget *w) +{ + if (!dapm_dirty_widget(w)) + list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty); +} + /* create a new dapm widget */ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( const struct snd_soc_dapm_widget *_widget) @@ -1208,11 +1219,30 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, struct list_head *up_list, struct list_head *down_list) { + struct snd_soc_dapm_path *path; + if (w->power == power) return; trace_snd_soc_dapm_widget_power(w, power); + /* If we changed our power state perhaps our neigbours changed + * also. We're not yet smart enough to update relevant + * neighbours when we change the state of a widget, this acts + * as a proxy for that. It will notify more neighbours than + * is ideal. + */ + list_for_each_entry(path, &w->sources, list_sink) { + if (path->source) { + dapm_mark_dirty(path->source); + } + } + list_for_each_entry(path, &w->sinks, list_source) { + if (path->sink) { + dapm_mark_dirty(path->sink); + } + } + if (power) dapm_seq_insert(w, up_list, true); else @@ -1276,13 +1306,18 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); /* Check which widgets we need to power and store them in - * lists indicating if they should be powered up or down. + * lists indicating if they should be powered up or down. We + * only check widgets that have been flagged as dirty but note + * that new widgets may be added to the dirty list while we + * iterate. */ - list_for_each_entry(w, &card->widgets, list) { + list_for_each_entry(w, &card->dapm_dirty, dirty) { dapm_power_one_widget(w, &up_list, &down_list); } list_for_each_entry(w, &card->widgets, list) { + list_del_init(&w->dirty); + if (w->power) { d = w->dapm; @@ -1573,14 +1608,20 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, found = 1; /* we now need to match the string in the enum to the path */ - if (!(strcmp(path->name, e->texts[mux]))) + if (!(strcmp(path->name, e->texts[mux]))) { path->connect = 1; /* new connection */ - else + dapm_mark_dirty(path->source); + } else { + if (path->connect) + dapm_mark_dirty(path->source); path->connect = 0; /* old connection must be powered down */ + } } - if (found) + if (found) { + dapm_mark_dirty(widget); dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); + } return 0; } @@ -1605,10 +1646,13 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, /* found, now check type */ found = 1; path->connect = connect; + dapm_mark_dirty(path->source); } - if (found) + if (found) { + dapm_mark_dirty(widget); dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP); + } return 0; } @@ -1752,6 +1796,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, w->connected = status; if (status == 0) w->force = 0; + dapm_mark_dirty(w); return 0; } @@ -2107,6 +2152,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) w->new = 1; + list_add(&w->dirty, &(w->dapm->card->dapm_dirty)); dapm_debugfs_add_widget(w); } @@ -2588,6 +2634,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, INIT_LIST_HEAD(&w->sources); INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->list); + INIT_LIST_HEAD(&w->dirty); list_add(&w->list, &dapm->card->widgets); /* machine layer set ups unconnected pins and insertions */ @@ -2638,6 +2685,7 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", w->name, w->sname, stream, event); if (strstr(w->sname, stream)) { + dapm_mark_dirty(w); switch(event) { case SND_SOC_DAPM_STREAM_START: w->active = 1; @@ -2727,6 +2775,7 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin); w->connected = 1; w->force = 1; + dapm_mark_dirty(w); return 0; } |