diff options
| -rw-r--r-- | include/sound/asound.h | 2 | ||||
| -rw-r--r-- | sound/core/pcm_lib.c | 12 | ||||
| -rw-r--r-- | sound/core/pcm_native.c | 52 |
3 files changed, 38 insertions, 28 deletions
diff --git a/include/sound/asound.h b/include/sound/asound.h index 82aed3f47534..1f57bb92eb5a 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h | |||
| @@ -138,7 +138,7 @@ struct snd_hwdep_dsp_image { | |||
| 138 | * * | 138 | * * |
| 139 | *****************************************************************************/ | 139 | *****************************************************************************/ |
| 140 | 140 | ||
| 141 | #define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9) | 141 | #define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10) |
| 142 | 142 | ||
| 143 | typedef unsigned long snd_pcm_uframes_t; | 143 | typedef unsigned long snd_pcm_uframes_t; |
| 144 | typedef signed long snd_pcm_sframes_t; | 144 | typedef signed long snd_pcm_sframes_t; |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 9db60d831bb2..30f410832a25 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 | ||
| 1344 | static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) | 1344 | static 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 = { | |||
| 1392 | struct drain_rec { | 1390 | struct 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 | ||
| 1398 | static int snd_pcm_drop(struct snd_pcm_substream *substream); | 1395 | static 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 | */ |
| 1407 | static int snd_pcm_drain(struct snd_pcm_substream *substream) | 1404 | static 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: |
