After suspend and resume, the alsa driver is stopped. But if alsa-lib run into snd_pcm_xxxx_drain(), it need to wait avail >= pcm->stop_threshold, otherwise, it will not exit the loop, so finally it is blocked at poll() of snd_pcm_wait_nocheck(pcm, -1). This patch is to add state check after snd_pcm_wait_nocheck(pcm, -1), if the state is SND_PCM_STATE_SUSPENDED, then return error.
Signed-off-by: Shengjiu Wang shengjiu.wang@freescale.com --- changes in v2: - Add state check in beginning of drain() - Add fix for pcm_dshare() - Mov the state check to the place that is after snd_pcm_direct_clear_timer_queue(dmix). That the suspend may happen just before calling snd_pcm_direct_clear_timer_queue(dmix), which will force the next poll to wait. So move state check to new place may safty.
src/pcm/pcm_dmix.c | 14 ++++++++++++++ src/pcm/pcm_dshare.c | 14 ++++++++++++++ 2 files changed, 28 insertions(+)
diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index babde6a..91148b9 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -616,6 +616,13 @@ static int snd_pcm_dmix_drain(snd_pcm_t *pcm) snd_pcm_uframes_t stop_threshold; int err;
+ switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + if (dmix->state == SND_PCM_STATE_OPEN) return -EBADFD; if (pcm->mode & SND_PCM_NONBLOCK) @@ -648,6 +655,13 @@ static int snd_pcm_dmix_drain(snd_pcm_t *pcm) snd_pcm_dmix_sync_area(pcm); snd_pcm_wait_nocheck(pcm, -1); snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */ + + switch (snd_pcm_state(dmix->spcm)) { + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } } } while (dmix->state == SND_PCM_STATE_DRAINING); pcm->stop_threshold = stop_threshold; diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index 020e6f7..24975d4 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -367,6 +367,13 @@ static int snd_pcm_dshare_drain(snd_pcm_t *pcm) snd_pcm_uframes_t stop_threshold; int err;
+ switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } + if (dshare->state == SND_PCM_STATE_OPEN) return -EBADFD; if (pcm->mode & SND_PCM_NONBLOCK) @@ -399,6 +406,13 @@ static int snd_pcm_dshare_drain(snd_pcm_t *pcm) snd_pcm_dshare_sync_area(pcm); snd_pcm_wait_nocheck(pcm, -1); snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */ + + switch (snd_pcm_state(dshare->spcm)) { + case SND_PCM_STATE_SUSPENDED: + return -ESTRPIPE; + default: + break; + } } } while (dshare->state == SND_PCM_STATE_DRAINING); pcm->stop_threshold = stop_threshold;