diff options
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/compress_offload.c | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index bea523a5d852..3eb47d0006a7 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c | |||
@@ -123,6 +123,7 @@ static int snd_compr_open(struct inode *inode, struct file *f) | |||
123 | } | 123 | } |
124 | runtime->state = SNDRV_PCM_STATE_OPEN; | 124 | runtime->state = SNDRV_PCM_STATE_OPEN; |
125 | init_waitqueue_head(&runtime->sleep); | 125 | init_waitqueue_head(&runtime->sleep); |
126 | init_waitqueue_head(&runtime->wait); | ||
126 | data->stream.runtime = runtime; | 127 | data->stream.runtime = runtime; |
127 | f->private_data = (void *)data; | 128 | f->private_data = (void *)data; |
128 | mutex_lock(&compr->lock); | 129 | mutex_lock(&compr->lock); |
@@ -682,12 +683,34 @@ static int snd_compr_stop(struct snd_compr_stream *stream) | |||
682 | if (!retval) { | 683 | if (!retval) { |
683 | stream->runtime->state = SNDRV_PCM_STATE_SETUP; | 684 | stream->runtime->state = SNDRV_PCM_STATE_SETUP; |
684 | wake_up(&stream->runtime->sleep); | 685 | wake_up(&stream->runtime->sleep); |
686 | snd_compr_drain_notify(stream); | ||
685 | stream->runtime->total_bytes_available = 0; | 687 | stream->runtime->total_bytes_available = 0; |
686 | stream->runtime->total_bytes_transferred = 0; | 688 | stream->runtime->total_bytes_transferred = 0; |
687 | } | 689 | } |
688 | return retval; | 690 | return retval; |
689 | } | 691 | } |
690 | 692 | ||
693 | static int snd_compress_wait_for_drain(struct snd_compr_stream *stream) | ||
694 | { | ||
695 | /* | ||
696 | * We are called with lock held. So drop the lock while we wait for | ||
697 | * drain complete notfication from the driver | ||
698 | * | ||
699 | * It is expected that driver will notify the drain completion and then | ||
700 | * stream will be moved to SETUP state, even if draining resulted in an | ||
701 | * error. We can trigger next track after this. | ||
702 | */ | ||
703 | stream->runtime->state = SNDRV_PCM_STATE_DRAINING; | ||
704 | mutex_unlock(&stream->device->lock); | ||
705 | |||
706 | wait_event(stream->runtime->wait, stream->runtime->drain_wake); | ||
707 | |||
708 | wake_up(&stream->runtime->sleep); | ||
709 | mutex_lock(&stream->device->lock); | ||
710 | |||
711 | return 0; | ||
712 | } | ||
713 | |||
691 | static int snd_compr_drain(struct snd_compr_stream *stream) | 714 | static int snd_compr_drain(struct snd_compr_stream *stream) |
692 | { | 715 | { |
693 | int retval; | 716 | int retval; |
@@ -695,11 +718,17 @@ static int snd_compr_drain(struct snd_compr_stream *stream) | |||
695 | if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED || | 718 | if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED || |
696 | stream->runtime->state == SNDRV_PCM_STATE_SETUP) | 719 | stream->runtime->state == SNDRV_PCM_STATE_SETUP) |
697 | return -EPERM; | 720 | return -EPERM; |
721 | |||
722 | stream->runtime->drain_wake = 0; | ||
698 | retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN); | 723 | retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN); |
699 | if (!retval) { | 724 | if (retval) { |
700 | stream->runtime->state = SNDRV_PCM_STATE_DRAINING; | 725 | pr_err("SND_COMPR_TRIGGER_DRAIN failed %d\n", retval); |
701 | wake_up(&stream->runtime->sleep); | 726 | wake_up(&stream->runtime->sleep); |
727 | return retval; | ||
702 | } | 728 | } |
729 | |||
730 | retval = snd_compress_wait_for_drain(stream); | ||
731 | stream->runtime->state = SNDRV_PCM_STATE_SETUP; | ||
703 | return retval; | 732 | return retval; |
704 | } | 733 | } |
705 | 734 | ||
@@ -735,10 +764,16 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream) | |||
735 | if (stream->next_track == false) | 764 | if (stream->next_track == false) |
736 | return -EPERM; | 765 | return -EPERM; |
737 | 766 | ||
767 | stream->runtime->drain_wake = 0; | ||
738 | retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN); | 768 | retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN); |
769 | if (retval) { | ||
770 | pr_err("Partial drain returned failure\n"); | ||
771 | wake_up(&stream->runtime->sleep); | ||
772 | return retval; | ||
773 | } | ||
739 | 774 | ||
740 | stream->next_track = false; | 775 | stream->next_track = false; |
741 | return retval; | 776 | return snd_compress_wait_for_drain(stream); |
742 | } | 777 | } |
743 | 778 | ||
744 | static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | 779 | static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) |