aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-08-20 10:40:16 -0400
committerTakashi Iwai <tiwai@suse.de>2009-08-20 10:40:16 -0400
commit4cdc115fd38b54642e8536a5c2389483bcb9b2e9 (patch)
treee68cfe5e88d155d1a6820b563517dac27b8e6dd6 /sound
parent64f1607ffbbc772685733ea63e6f7f4183df1b16 (diff)
ALSA: pcm - Fix drain behavior in non-blocking mode
The current PCM core has the following problems regarding PCM draining in non-blocking mode: - the current f_flags isn't checked in snd_pcm_drain(), thus changing the mode dynamically via snd_pcm_nonblock() after open doesn't work. - calling drain in non-blocking mode just return -EAGAIN error, but doesn't provide any way to sync with draining. This patch fixes these issues. - check file->f_flags in snd_pcm_drain() properly - when O_NONBLOCK is set, PCM core sets the stream(s) to DRAIN state but quits ioctl immediately without waiting the whole drain; the caller can sync the drain manually via poll() Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/core/pcm_lib.c12
-rw-r--r--sound/core/pcm_native.c52
2 files changed, 37 insertions, 27 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 72cfd47af6b8..e3e78c7f2745 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -197,12 +197,16 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
197 avail = snd_pcm_capture_avail(runtime); 197 avail = snd_pcm_capture_avail(runtime);
198 if (avail > runtime->avail_max) 198 if (avail > runtime->avail_max)
199 runtime->avail_max = avail; 199 runtime->avail_max = avail;
200 if (avail >= runtime->stop_threshold) { 200 if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
201 if (substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING) 201 if (avail >= runtime->buffer_size) {
202 snd_pcm_drain_done(substream); 202 snd_pcm_drain_done(substream);
203 else 203 return -EPIPE;
204 }
205 } else {
206 if (avail >= runtime->stop_threshold) {
204 xrun(substream); 207 xrun(substream);
205 return -EPIPE; 208 return -EPIPE;
209 }
206 } 210 }
207 if (avail >= runtime->control->avail_min) 211 if (avail >= runtime->control->avail_min)
208 wake_up(&runtime->sleep); 212 wake_up(&runtime->sleep);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index ac2150e0670d..b08898cbfed3 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1343,8 +1343,6 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
1343 1343
1344static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) 1344static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)
1345{ 1345{
1346 if (substream->f_flags & O_NONBLOCK)
1347 return -EAGAIN;
1348 substream->runtime->trigger_master = substream; 1346 substream->runtime->trigger_master = substream;
1349 return 0; 1347 return 0;
1350} 1348}
@@ -1392,7 +1390,6 @@ static struct action_ops snd_pcm_action_drain_init = {
1392struct drain_rec { 1390struct drain_rec {
1393 struct snd_pcm_substream *substream; 1391 struct snd_pcm_substream *substream;
1394 wait_queue_t wait; 1392 wait_queue_t wait;
1395 snd_pcm_uframes_t stop_threshold;
1396}; 1393};
1397 1394
1398static int snd_pcm_drop(struct snd_pcm_substream *substream); 1395static int snd_pcm_drop(struct snd_pcm_substream *substream);
@@ -1404,13 +1401,15 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream);
1404 * After this call, all streams are supposed to be either SETUP or DRAINING 1401 * After this call, all streams are supposed to be either SETUP or DRAINING
1405 * (capture only) state. 1402 * (capture only) state.
1406 */ 1403 */
1407static int snd_pcm_drain(struct snd_pcm_substream *substream) 1404static int snd_pcm_drain(struct snd_pcm_substream *substream,
1405 struct file *file)
1408{ 1406{
1409 struct snd_card *card; 1407 struct snd_card *card;
1410 struct snd_pcm_runtime *runtime; 1408 struct snd_pcm_runtime *runtime;
1411 struct snd_pcm_substream *s; 1409 struct snd_pcm_substream *s;
1412 int result = 0; 1410 int result = 0;
1413 int i, num_drecs; 1411 int i, num_drecs;
1412 int nonblock = 0;
1414 struct drain_rec *drec, drec_tmp, *d; 1413 struct drain_rec *drec, drec_tmp, *d;
1415 1414
1416 card = substream->pcm->card; 1415 card = substream->pcm->card;
@@ -1428,6 +1427,15 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
1428 } 1427 }
1429 } 1428 }
1430 1429
1430 if (file) {
1431 if (file->f_flags & O_NONBLOCK)
1432 nonblock = 1;
1433 } else if (substream->f_flags & O_NONBLOCK)
1434 nonblock = 1;
1435
1436 if (nonblock)
1437 goto lock; /* no need to allocate waitqueues */
1438
1431 /* allocate temporary record for drain sync */ 1439 /* allocate temporary record for drain sync */
1432 down_read(&snd_pcm_link_rwsem); 1440 down_read(&snd_pcm_link_rwsem);
1433 if (snd_pcm_stream_linked(substream)) { 1441 if (snd_pcm_stream_linked(substream)) {
@@ -1449,16 +1457,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
1449 d->substream = s; 1457 d->substream = s;
1450 init_waitqueue_entry(&d->wait, current); 1458 init_waitqueue_entry(&d->wait, current);
1451 add_wait_queue(&runtime->sleep, &d->wait); 1459 add_wait_queue(&runtime->sleep, &d->wait);
1452 /* stop_threshold fixup to avoid endless loop when
1453 * stop_threshold > buffer_size
1454 */
1455 d->stop_threshold = runtime->stop_threshold;
1456 if (runtime->stop_threshold > runtime->buffer_size)
1457 runtime->stop_threshold = runtime->buffer_size;
1458 } 1460 }
1459 } 1461 }
1460 up_read(&snd_pcm_link_rwsem); 1462 up_read(&snd_pcm_link_rwsem);
1461 1463
1464 lock:
1462 snd_pcm_stream_lock_irq(substream); 1465 snd_pcm_stream_lock_irq(substream);
1463 /* resume pause */ 1466 /* resume pause */
1464 if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED) 1467 if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED)
@@ -1466,9 +1469,12 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
1466 1469
1467 /* pre-start/stop - all running streams are changed to DRAINING state */ 1470 /* pre-start/stop - all running streams are changed to DRAINING state */
1468 result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); 1471 result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0);
1469 if (result < 0) { 1472 if (result < 0)
1470 snd_pcm_stream_unlock_irq(substream); 1473 goto unlock;
1471 goto _error; 1474 /* in non-blocking, we don't wait in ioctl but let caller poll */
1475 if (nonblock) {
1476 result = -EAGAIN;
1477 goto unlock;
1472 } 1478 }
1473 1479
1474 for (;;) { 1480 for (;;) {
@@ -1504,18 +1510,18 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
1504 } 1510 }
1505 } 1511 }
1506 1512
1513 unlock:
1507 snd_pcm_stream_unlock_irq(substream); 1514 snd_pcm_stream_unlock_irq(substream);
1508 1515
1509 _error: 1516 if (!nonblock) {
1510 for (i = 0; i < num_drecs; i++) { 1517 for (i = 0; i < num_drecs; i++) {
1511 d = &drec[i]; 1518 d = &drec[i];
1512 runtime = d->substream->runtime; 1519 runtime = d->substream->runtime;
1513 remove_wait_queue(&runtime->sleep, &d->wait); 1520 remove_wait_queue(&runtime->sleep, &d->wait);
1514 runtime->stop_threshold = d->stop_threshold; 1521 }
1522 if (drec != &drec_tmp)
1523 kfree(drec);
1515 } 1524 }
1516
1517 if (drec != &drec_tmp)
1518 kfree(drec);
1519 snd_power_unlock(card); 1525 snd_power_unlock(card);
1520 1526
1521 return result; 1527 return result;
@@ -2544,7 +2550,7 @@ static int snd_pcm_common_ioctl1(struct file *file,
2544 return snd_pcm_hw_params_old_user(substream, arg); 2550 return snd_pcm_hw_params_old_user(substream, arg);
2545#endif 2551#endif
2546 case SNDRV_PCM_IOCTL_DRAIN: 2552 case SNDRV_PCM_IOCTL_DRAIN:
2547 return snd_pcm_drain(substream); 2553 return snd_pcm_drain(substream, file);
2548 case SNDRV_PCM_IOCTL_DROP: 2554 case SNDRV_PCM_IOCTL_DROP:
2549 return snd_pcm_drop(substream); 2555 return snd_pcm_drop(substream);
2550 case SNDRV_PCM_IOCTL_PAUSE: 2556 case SNDRV_PCM_IOCTL_PAUSE: