Merge remote-tracking branch 'lsk/v3.10/topic/aosp' into linux-linaro-lsk-android
[firefly-linux-kernel-4.4.55.git] / sound / core / compress_offload.c
index fe399f8c18f4812cf436aa2eecf6911e9a93b758..0d430adee88d6a142917fa77d720b962cd44f91b 100644 (file)
@@ -133,7 +133,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
                kfree(data);
        }
        snd_card_unref(compr->card);
-       return 0;
+       return ret;
 }
 
 static int snd_compr_free(struct inode *inode, struct file *f)
@@ -665,14 +665,48 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
                return -EPERM;
        retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
        if (!retval) {
-               stream->runtime->state = SNDRV_PCM_STATE_SETUP;
-               wake_up(&stream->runtime->sleep);
+               snd_compr_drain_notify(stream);
                stream->runtime->total_bytes_available = 0;
                stream->runtime->total_bytes_transferred = 0;
        }
        return retval;
 }
 
+static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)
+{
+       int ret;
+
+       /*
+        * We are called with lock held. So drop the lock while we wait for
+        * drain complete notfication from the driver
+        *
+        * It is expected that driver will notify the drain completion and then
+        * stream will be moved to SETUP state, even if draining resulted in an
+        * error. We can trigger next track after this.
+        */
+       stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
+       mutex_unlock(&stream->device->lock);
+
+       /* we wait for drain to complete here, drain can return when
+        * interruption occurred, wait returned error or success.
+        * For the first two cases we don't do anything different here and
+        * return after waking up
+        */
+
+       ret = wait_event_interruptible(stream->runtime->sleep,
+                       (stream->runtime->state != SNDRV_PCM_STATE_DRAINING));
+       if (ret == -ERESTARTSYS)
+               pr_debug("wait aborted by a signal");
+       else if (ret)
+               pr_debug("wait for drain failed with %d\n", ret);
+
+
+       wake_up(&stream->runtime->sleep);
+       mutex_lock(&stream->device->lock);
+
+       return ret;
+}
+
 static int snd_compr_drain(struct snd_compr_stream *stream)
 {
        int retval;
@@ -680,12 +714,15 @@ static int snd_compr_drain(struct snd_compr_stream *stream)
        if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
                        stream->runtime->state == SNDRV_PCM_STATE_SETUP)
                return -EPERM;
+
        retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
-       if (!retval) {
-               stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
+       if (retval) {
+               pr_debug("SND_COMPR_TRIGGER_DRAIN failed %d\n", retval);
                wake_up(&stream->runtime->sleep);
+               return retval;
        }
-       return retval;
+
+       return snd_compress_wait_for_drain(stream);
 }
 
 static int snd_compr_next_track(struct snd_compr_stream *stream)
@@ -721,9 +758,14 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream)
                return -EPERM;
 
        retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
+       if (retval) {
+               pr_debug("Partial drain returned failure\n");
+               wake_up(&stream->runtime->sleep);
+               return retval;
+       }
 
        stream->next_track = false;
-       return retval;
+       return snd_compress_wait_for_drain(stream);
 }
 
 static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
@@ -740,7 +782,7 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
        mutex_lock(&stream->device->lock);
        switch (_IOC_NR(cmd)) {
        case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
-               put_user(SNDRV_COMPRESS_VERSION,
+               retval = put_user(SNDRV_COMPRESS_VERSION,
                                (int __user *)arg) ? -EFAULT : 0;
                break;
        case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
@@ -834,7 +876,8 @@ static int snd_compress_dev_disconnect(struct snd_device *device)
        struct snd_compr *compr;
 
        compr = device->device_data;
-       snd_unregister_device(compr->direction, compr->card, compr->device);
+       snd_unregister_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
+               compr->device);
        return 0;
 }