PCM: snd_pcm_xxxx_drain() maybe blocked after suspend and resume

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>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Shengjiu Wang 2015-06-12 16:15:08 +08:00 committed by Takashi Iwai
parent 2fd098b587
commit 9ee6ec80b8
2 changed files with 28 additions and 0 deletions

View file

@ -617,6 +617,13 @@ static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
snd_pcm_uframes_t stop_threshold; snd_pcm_uframes_t stop_threshold;
int err; int err;
switch (snd_pcm_state(dmix->spcm)) {
case SND_PCM_STATE_SUSPENDED:
return -ESTRPIPE;
default:
break;
}
if (dmix->state == SND_PCM_STATE_OPEN) if (dmix->state == SND_PCM_STATE_OPEN)
return -EBADFD; return -EBADFD;
if (pcm->mode & SND_PCM_NONBLOCK) if (pcm->mode & SND_PCM_NONBLOCK)
@ -649,6 +656,13 @@ static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
snd_pcm_dmix_sync_area(pcm); snd_pcm_dmix_sync_area(pcm);
snd_pcm_wait_nocheck(pcm, -1); snd_pcm_wait_nocheck(pcm, -1);
snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */ 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); } while (dmix->state == SND_PCM_STATE_DRAINING);
pcm->stop_threshold = stop_threshold; pcm->stop_threshold = stop_threshold;

View file

@ -368,6 +368,13 @@ static int snd_pcm_dshare_drain(snd_pcm_t *pcm)
snd_pcm_uframes_t stop_threshold; snd_pcm_uframes_t stop_threshold;
int err; int err;
switch (snd_pcm_state(dshare->spcm)) {
case SND_PCM_STATE_SUSPENDED:
return -ESTRPIPE;
default:
break;
}
if (dshare->state == SND_PCM_STATE_OPEN) if (dshare->state == SND_PCM_STATE_OPEN)
return -EBADFD; return -EBADFD;
if (pcm->mode & SND_PCM_NONBLOCK) if (pcm->mode & SND_PCM_NONBLOCK)
@ -400,6 +407,13 @@ static int snd_pcm_dshare_drain(snd_pcm_t *pcm)
snd_pcm_dshare_sync_area(pcm); snd_pcm_dshare_sync_area(pcm);
snd_pcm_wait_nocheck(pcm, -1); snd_pcm_wait_nocheck(pcm, -1);
snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */ 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); } while (dshare->state == SND_PCM_STATE_DRAINING);
pcm->stop_threshold = stop_threshold; pcm->stop_threshold = stop_threshold;