aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMisael Lopez Cruz <misael.lopez@ti.com>2012-12-13 13:23:05 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-12-15 09:45:09 -0500
commit9bffb1fb7c22c96d51d4ba06e2e023dd568a5872 (patch)
tree88cc04ca2ff1f66f36561e559886fc8cbeeaca6e
parent29594404d7fe73cd80eaa4ee8c43dcc53970c60e (diff)
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>
-rw-r--r--include/sound/soc-dai.h1
-rw-r--r--include/sound/soc.h1
-rw-r--r--sound/soc/soc-compress.c2
-rw-r--r--sound/soc/soc-pcm.c12
4 files changed, 8 insertions, 8 deletions
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 628db7bca4fd..3953cea0ecfb 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -242,7 +242,6 @@ struct snd_soc_dai {
242 unsigned int symmetric_rates:1; 242 unsigned int symmetric_rates:1;
243 struct snd_pcm_runtime *runtime; 243 struct snd_pcm_runtime *runtime;
244 unsigned int active; 244 unsigned int active;
245 unsigned char pop_wait:1;
246 unsigned char probed:1; 245 unsigned char probed:1;
247 246
248 struct snd_soc_dapm_widget *playback_widget; 247 struct snd_soc_dapm_widget *playback_widget;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 91244a096c19..769e27c774a3 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1039,6 +1039,7 @@ struct snd_soc_pcm_runtime {
1039 struct snd_soc_dpcm_runtime dpcm[2]; 1039 struct snd_soc_dpcm_runtime dpcm[2];
1040 1040
1041 long pmdown_time; 1041 long pmdown_time;
1042 unsigned char pop_wait:1;
1042 1043
1043 /* runtime devices */ 1044 /* runtime devices */
1044 struct snd_pcm *pcm; 1045 struct snd_pcm *pcm;
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 967d0e173e1b..5fbfb06e8083 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -113,7 +113,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
113 SNDRV_PCM_STREAM_PLAYBACK, 113 SNDRV_PCM_STREAM_PLAYBACK,
114 SND_SOC_DAPM_STREAM_STOP); 114 SND_SOC_DAPM_STREAM_STOP);
115 } else 115 } else
116 codec_dai->pop_wait = 1; 116 rtd->pop_wait = 1;
117 schedule_delayed_work(&rtd->delayed_work, 117 schedule_delayed_work(&rtd->delayed_work,
118 msecs_to_jiffies(rtd->pmdown_time)); 118 msecs_to_jiffies(rtd->pmdown_time));
119 } else { 119 } else {
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index ef22d0bd9e9e..3a2423bd84b2 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -333,11 +333,11 @@ static void close_delayed_work(struct work_struct *work)
333 pr_debug("pop wq checking: %s status: %s waiting: %s\n", 333 pr_debug("pop wq checking: %s status: %s waiting: %s\n",
334 codec_dai->driver->playback.stream_name, 334 codec_dai->driver->playback.stream_name,
335 codec_dai->playback_active ? "active" : "inactive", 335 codec_dai->playback_active ? "active" : "inactive",
336 codec_dai->pop_wait ? "yes" : "no"); 336 rtd->pop_wait ? "yes" : "no");
337 337
338 /* are we waiting on this codec DAI stream */ 338 /* are we waiting on this codec DAI stream */
339 if (codec_dai->pop_wait == 1) { 339 if (rtd->pop_wait == 1) {
340 codec_dai->pop_wait = 0; 340 rtd->pop_wait = 0;
341 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, 341 snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
342 SND_SOC_DAPM_STREAM_STOP); 342 SND_SOC_DAPM_STREAM_STOP);
343 } 343 }
@@ -407,7 +407,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
407 SND_SOC_DAPM_STREAM_STOP); 407 SND_SOC_DAPM_STREAM_STOP);
408 } else { 408 } else {
409 /* start delayed pop wq here for playback streams */ 409 /* start delayed pop wq here for playback streams */
410 codec_dai->pop_wait = 1; 410 rtd->pop_wait = 1;
411 schedule_delayed_work(&rtd->delayed_work, 411 schedule_delayed_work(&rtd->delayed_work,
412 msecs_to_jiffies(rtd->pmdown_time)); 412 msecs_to_jiffies(rtd->pmdown_time));
413 } 413 }
@@ -478,8 +478,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
478 478
479 /* cancel any delayed stream shutdown that is pending */ 479 /* cancel any delayed stream shutdown that is pending */
480 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 480 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
481 codec_dai->pop_wait) { 481 rtd->pop_wait) {
482 codec_dai->pop_wait = 0; 482 rtd->pop_wait = 0;
483 cancel_delayed_work(&rtd->delayed_work); 483 cancel_delayed_work(&rtd->delayed_work);
484 } 484 }
485 485