Commit 9bffb1fb7c22c96d51d4ba06e2e023dd568a5872

Authored by Misael Lopez Cruz
Committed by Mark Brown
1 parent 29594404d7

ASoC: Prevent pop_wait overwrite

pop_wait is used to determine if a deferred playback close
needs to be cancelled when the a PCM is open or if after
the power-down delay expires it needs to run. pop_wait is
associated with the CODEC DAI, so the CODEC DAI must be
unique. This holds true for most CODECs, except for the
dummy CODEC and its DAI.

In DAI links with non-unique dummy CODECs (e.g. front-ends),
pop_wait can be overwritten by another DAI link using also a
dummy CODEC. Failure to cancel a deferred close can cause
mute due to the DAPM STOP event sent in the deferred work.

One scenario where pop_wait is overwritten and causing mute
is below (where hw:0,0 and hw:0,1 are two front-ends with
default pmdown_time = 5 secs):

aplay /dev/urandom -D hw:0,0 -c 2 -r 48000 -f S16_LE -d 1
sleep 1
aplay /dev/urandom -D hw:0,1 -c 2 -r 48000 -f S16_LE -d 3 &
aplay /dev/urandom -D hw:0,0 -c 2 -r 48000 -f S16_LE

Since CODECs may not be unique, pop_wait is moved to the PCM
runtime structure. Creating separate dummy CODECs for each
DAI link can also solve the problem, but at this point it's
only pop_wait variable in the CODEC DAI that has negative
effects by not being unique.

Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

Showing 4 changed files with 8 additions and 8 deletions Side-by-side Diff

include/sound/soc-dai.h
... ... @@ -242,7 +242,6 @@
242 242 unsigned int symmetric_rates:1;
243 243 struct snd_pcm_runtime *runtime;
244 244 unsigned int active;
245   - unsigned char pop_wait:1;
246 245 unsigned char probed:1;
247 246  
248 247 struct snd_soc_dapm_widget *playback_widget;
... ... @@ -1039,6 +1039,7 @@
1039 1039 struct snd_soc_dpcm_runtime dpcm[2];
1040 1040  
1041 1041 long pmdown_time;
  1042 + unsigned char pop_wait:1;
1042 1043  
1043 1044 /* runtime devices */
1044 1045 struct snd_pcm *pcm;
sound/soc/soc-compress.c
... ... @@ -113,7 +113,7 @@
113 113 SNDRV_PCM_STREAM_PLAYBACK,
114 114 SND_SOC_DAPM_STREAM_STOP);
115 115 } else
116   - codec_dai->pop_wait = 1;
  116 + rtd->pop_wait = 1;
117 117 schedule_delayed_work(&rtd->delayed_work,
118 118 msecs_to_jiffies(rtd->pmdown_time));
119 119 } else {
... ... @@ -333,11 +333,11 @@
333 333 pr_debug("pop wq checking: %s status: %s waiting: %s\n",
334 334 codec_dai->driver->playback.stream_name,
335 335 codec_dai->playback_active ? "active" : "inactive",
336   - codec_dai->pop_wait ? "yes" : "no");
  336 + rtd->pop_wait ? "yes" : "no");
337 337  
338 338 /* are we waiting on this codec DAI stream */
339   - if (codec_dai->pop_wait == 1) {
340   - codec_dai->pop_wait = 0;
  339 + if (rtd->pop_wait == 1) {
  340 + rtd->pop_wait = 0;
341 341 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
342 342 SND_SOC_DAPM_STREAM_STOP);
343 343 }
... ... @@ -407,7 +407,7 @@
407 407 SND_SOC_DAPM_STREAM_STOP);
408 408 } else {
409 409 /* start delayed pop wq here for playback streams */
410   - codec_dai->pop_wait = 1;
  410 + rtd->pop_wait = 1;
411 411 schedule_delayed_work(&rtd->delayed_work,
412 412 msecs_to_jiffies(rtd->pmdown_time));
413 413 }
... ... @@ -478,8 +478,8 @@
478 478  
479 479 /* cancel any delayed stream shutdown that is pending */
480 480 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
481   - codec_dai->pop_wait) {
482   - codec_dai->pop_wait = 0;
  481 + rtd->pop_wait) {
  482 + rtd->pop_wait = 0;
483 483 cancel_delayed_work(&rtd->delayed_work);
484 484 }
485 485