[ALSA] PCM - clean up snd_pcm_lib_read/write
Introduce a common helper function for snd_pcm_lib_read and snd_pcm_lib_write for cleaning up the code. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Родитель
d948035a92
Коммит
130755108b
|
@ -1591,6 +1591,71 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
|
|||
|
||||
EXPORT_SYMBOL(snd_pcm_period_elapsed);
|
||||
|
||||
/*
|
||||
* Wait until avail_min data becomes available
|
||||
* Returns a negative error code if any error occurs during operation.
|
||||
* The available space is stored on availp. When err = 0 and avail = 0
|
||||
* on the capture stream, it indicates the stream is in DRAINING state.
|
||||
*/
|
||||
static int wait_for_avail_min(struct snd_pcm_substream *substream,
|
||||
snd_pcm_uframes_t *availp)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
wait_queue_t wait;
|
||||
int err = 0;
|
||||
snd_pcm_uframes_t avail = 0;
|
||||
long tout;
|
||||
|
||||
init_waitqueue_entry(&wait, current);
|
||||
add_wait_queue(&runtime->sleep, &wait);
|
||||
for (;;) {
|
||||
if (signal_pending(current)) {
|
||||
err = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
tout = schedule_timeout(msecs_to_jiffies(10000));
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
switch (runtime->status->state) {
|
||||
case SNDRV_PCM_STATE_SUSPENDED:
|
||||
err = -ESTRPIPE;
|
||||
goto _endloop;
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
err = -EPIPE;
|
||||
goto _endloop;
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
if (is_playback)
|
||||
err = -EPIPE;
|
||||
else
|
||||
avail = 0; /* indicate draining */
|
||||
goto _endloop;
|
||||
case SNDRV_PCM_STATE_OPEN:
|
||||
case SNDRV_PCM_STATE_SETUP:
|
||||
case SNDRV_PCM_STATE_DISCONNECTED:
|
||||
err = -EBADFD;
|
||||
goto _endloop;
|
||||
}
|
||||
if (!tout) {
|
||||
snd_printd("%s write error (DMA or IRQ trouble?)\n",
|
||||
is_playback ? "playback" : "capture");
|
||||
err = -EIO;
|
||||
break;
|
||||
}
|
||||
if (is_playback)
|
||||
avail = snd_pcm_playback_avail(runtime);
|
||||
else
|
||||
avail = snd_pcm_capture_avail(runtime);
|
||||
if (avail >= runtime->control->avail_min)
|
||||
break;
|
||||
}
|
||||
_endloop:
|
||||
remove_wait_queue(&runtime->sleep, &wait);
|
||||
*availp = avail;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
|
||||
unsigned int hwoff,
|
||||
unsigned long data, unsigned int off,
|
||||
|
@ -1653,79 +1718,14 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
|
|||
if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
|
||||
snd_pcm_update_hw_ptr(substream);
|
||||
avail = snd_pcm_playback_avail(runtime);
|
||||
if (!avail ||
|
||||
(snd_pcm_running(substream) &&
|
||||
(avail < runtime->control->avail_min && size > avail))) {
|
||||
wait_queue_t wait;
|
||||
enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
|
||||
long tout;
|
||||
|
||||
if (!avail) {
|
||||
if (nonblock) {
|
||||
err = -EAGAIN;
|
||||
goto _end_unlock;
|
||||
}
|
||||
|
||||
init_waitqueue_entry(&wait, current);
|
||||
add_wait_queue(&runtime->sleep, &wait);
|
||||
while (1) {
|
||||
if (signal_pending(current)) {
|
||||
state = SIGNALED;
|
||||
break;
|
||||
}
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
tout = schedule_timeout(10 * HZ);
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
if (tout == 0) {
|
||||
if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
|
||||
runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
|
||||
state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (runtime->status->state) {
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
state = ERROR;
|
||||
goto _end_loop;
|
||||
case SNDRV_PCM_STATE_SUSPENDED:
|
||||
state = SUSPENDED;
|
||||
goto _end_loop;
|
||||
case SNDRV_PCM_STATE_SETUP:
|
||||
state = DROPPED;
|
||||
goto _end_loop;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
avail = snd_pcm_playback_avail(runtime);
|
||||
if (avail >= runtime->control->avail_min) {
|
||||
state = READY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_end_loop:
|
||||
remove_wait_queue(&runtime->sleep, &wait);
|
||||
|
||||
switch (state) {
|
||||
case ERROR:
|
||||
err = -EPIPE;
|
||||
err = wait_for_avail_min(substream, &avail);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
case SUSPENDED:
|
||||
err = -ESTRPIPE;
|
||||
goto _end_unlock;
|
||||
case SIGNALED:
|
||||
err = -ERESTARTSYS;
|
||||
goto _end_unlock;
|
||||
case EXPIRED:
|
||||
snd_printd("playback write error (DMA or IRQ trouble?)\n");
|
||||
err = -EIO;
|
||||
goto _end_unlock;
|
||||
case DROPPED:
|
||||
err = -EBADFD;
|
||||
goto _end_unlock;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
frames = size > avail ? avail : size;
|
||||
cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
|
||||
|
@ -1925,86 +1925,22 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
|
|||
snd_pcm_uframes_t cont;
|
||||
if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
|
||||
snd_pcm_update_hw_ptr(substream);
|
||||
__draining:
|
||||
avail = snd_pcm_capture_avail(runtime);
|
||||
if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
|
||||
if (!avail) {
|
||||
err = -EPIPE;
|
||||
if (!avail) {
|
||||
if (runtime->status->state ==
|
||||
SNDRV_PCM_STATE_DRAINING) {
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
|
||||
goto _end_unlock;
|
||||
}
|
||||
} else if (avail < runtime->control->avail_min &&
|
||||
size > avail) {
|
||||
wait_queue_t wait;
|
||||
enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
|
||||
long tout;
|
||||
|
||||
if (nonblock) {
|
||||
err = -EAGAIN;
|
||||
goto _end_unlock;
|
||||
}
|
||||
|
||||
init_waitqueue_entry(&wait, current);
|
||||
add_wait_queue(&runtime->sleep, &wait);
|
||||
while (1) {
|
||||
if (signal_pending(current)) {
|
||||
state = SIGNALED;
|
||||
break;
|
||||
}
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
tout = schedule_timeout(10 * HZ);
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
if (tout == 0) {
|
||||
if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
|
||||
runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
|
||||
state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (runtime->status->state) {
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
state = ERROR;
|
||||
goto _end_loop;
|
||||
case SNDRV_PCM_STATE_SUSPENDED:
|
||||
state = SUSPENDED;
|
||||
goto _end_loop;
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
goto __draining;
|
||||
case SNDRV_PCM_STATE_SETUP:
|
||||
state = DROPPED;
|
||||
goto _end_loop;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
avail = snd_pcm_capture_avail(runtime);
|
||||
if (avail >= runtime->control->avail_min) {
|
||||
state = READY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_end_loop:
|
||||
remove_wait_queue(&runtime->sleep, &wait);
|
||||
|
||||
switch (state) {
|
||||
case ERROR:
|
||||
err = -EPIPE;
|
||||
err = wait_for_avail_min(substream, &avail);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
case SUSPENDED:
|
||||
err = -ESTRPIPE;
|
||||
goto _end_unlock;
|
||||
case SIGNALED:
|
||||
err = -ERESTARTSYS;
|
||||
goto _end_unlock;
|
||||
case EXPIRED:
|
||||
snd_printd("capture read error (DMA or IRQ trouble?)\n");
|
||||
err = -EIO;
|
||||
goto _end_unlock;
|
||||
case DROPPED:
|
||||
err = -EBADFD;
|
||||
goto _end_unlock;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!avail)
|
||||
continue; /* draining */
|
||||
}
|
||||
frames = size > avail ? avail : size;
|
||||
cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
|
||||
|
|
Загрузка…
Ссылка в новой задаче