static ssize_t snd_compr_read(struct file *f, char __user *buf,
                size_t count, loff_t *offset)
 {
-       return -ENXIO;
+       struct snd_compr_file *data = f->private_data;
+       struct snd_compr_stream *stream;
+       size_t avail;
+       int retval;
+
+       if (snd_BUG_ON(!data))
+               return -EFAULT;
+
+       stream = &data->stream;
+       mutex_lock(&stream->device->lock);
+
+       /* read is allowed when stream is running */
+       if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
+               retval = -EBADFD;
+               goto out;
+       }
+
+       avail = snd_compr_get_avail(stream);
+       pr_debug("avail returned %ld\n", (unsigned long)avail);
+       /* calculate how much we can read from buffer */
+       if (avail > count)
+               avail = count;
+
+       if (stream->ops->copy) {
+               retval = stream->ops->copy(stream, buf, avail);
+       } else {
+               retval = -ENXIO;
+               goto out;
+       }
+       if (retval > 0)
+               stream->runtime->total_bytes_transferred += retval;
+
+out:
+       mutex_unlock(&stream->device->lock);
+       return retval;
 }
 
 static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
                retval = stream->ops->set_params(stream, params);
                if (retval)
                        goto out;
-               stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+
                stream->metadata_set = false;
                stream->next_track = false;
+
+               if (stream->direction == SND_COMPRESS_PLAYBACK)
+                       stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+               else
+                       stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
        } else {
                return -EPERM;
        }