diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/pcm_native.c | 73 |
1 files changed, 20 insertions, 53 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 59e5fbe6af51..561d6d95a2d3 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1387,11 +1387,6 @@ static struct action_ops snd_pcm_action_drain_init = { .post_action = snd_pcm_post_drain_init }; -struct drain_rec { - struct snd_pcm_substream *substream; - wait_queue_t wait; -}; - static int snd_pcm_drop(struct snd_pcm_substream *substream); /* @@ -1407,10 +1402,9 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, struct snd_card *card; struct snd_pcm_runtime *runtime; struct snd_pcm_substream *s; + wait_queue_t wait; int result = 0; - int i, num_drecs; int nonblock = 0; - struct drain_rec *drec, drec_tmp, *d; card = substream->pcm->card; runtime = substream->runtime; @@ -1433,38 +1427,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, } else if (substream->f_flags & O_NONBLOCK) nonblock = 1; - if (nonblock) - goto lock; /* no need to allocate waitqueues */ - - /* allocate temporary record for drain sync */ down_read(&snd_pcm_link_rwsem); - if (snd_pcm_stream_linked(substream)) { - drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL); - if (! drec) { - up_read(&snd_pcm_link_rwsem); - snd_power_unlock(card); - return -ENOMEM; - } - } else - drec = &drec_tmp; - - /* count only playback streams */ - num_drecs = 0; - snd_pcm_group_for_each_entry(s, substream) { - runtime = s->runtime; - if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { - d = &drec[num_drecs++]; - d->substream = s; - init_waitqueue_entry(&d->wait, current); - add_wait_queue(&runtime->sleep, &d->wait); - } - } - up_read(&snd_pcm_link_rwsem); - - lock: snd_pcm_stream_lock_irq(substream); /* resume pause */ - if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED) + if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) snd_pcm_pause(substream, 0); /* pre-start/stop - all running streams are changed to DRAINING state */ @@ -1479,25 +1445,35 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, for (;;) { long tout; + struct snd_pcm_runtime *to_check; if (signal_pending(current)) { result = -ERESTARTSYS; break; } - /* all finished? */ - for (i = 0; i < num_drecs; i++) { - runtime = drec[i].substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) + /* find a substream to drain */ + to_check = NULL; + snd_pcm_group_for_each_entry(s, substream) { + if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) + continue; + runtime = s->runtime; + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + to_check = runtime; break; + } } - if (i == num_drecs) - break; /* yes, all drained */ - + if (!to_check) + break; /* all drained */ + init_waitqueue_entry(&wait, current); + add_wait_queue(&to_check->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); + up_read(&snd_pcm_link_rwsem); snd_power_unlock(card); tout = schedule_timeout(10 * HZ); snd_power_lock(card); + down_read(&snd_pcm_link_rwsem); snd_pcm_stream_lock_irq(substream); + remove_wait_queue(&to_check->sleep, &wait); if (tout == 0) { if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) result = -ESTRPIPE; @@ -1512,16 +1488,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, unlock: snd_pcm_stream_unlock_irq(substream); - - if (!nonblock) { - for (i = 0; i < num_drecs; i++) { - d = &drec[i]; - runtime = d->substream->runtime; - remove_wait_queue(&runtime->sleep, &d->wait); - } - if (drec != &drec_tmp) - kfree(drec); - } + up_read(&snd_pcm_link_rwsem); snd_power_unlock(card); return result; |