Re: [PATCH] media: uvcvideo: Read support
From: Hans Verkuil
Date: Mon Mar 04 2019 - 07:54:16 EST
On 3/4/19 1:35 PM, Hugues Fruchet wrote:
> Add support of read() call from userspace by implementing
> uvc_v4l2_read() with vb2_read() helper.
>
> Signed-off-by: Hugues Fruchet <hugues.fruchet@xxxxxx>
> ---
> drivers/media/usb/uvc/uvc_queue.c | 15 ++++++++++++++-
> drivers/media/usb/uvc/uvc_v4l2.c | 11 ++++++++---
> drivers/media/usb/uvc/uvcvideo.h | 2 ++
> 3 files changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
> index 682698e..0c8a0a8 100644
> --- a/drivers/media/usb/uvc/uvc_queue.c
> +++ b/drivers/media/usb/uvc/uvc_queue.c
> @@ -227,7 +227,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
> int ret;
>
> queue->queue.type = type;
> - queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
> + queue->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
> queue->queue.drv_priv = queue;
> queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
> queue->queue.mem_ops = &vb2_vmalloc_memops;
> @@ -361,6 +361,19 @@ int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type)
> return ret;
> }
>
> +ssize_t uvc_queue_read(struct uvc_video_queue *queue, struct file *file,
> + char __user *buf, size_t count, loff_t *ppos)
> +{
> + ssize_t ret;
> +
> + mutex_lock(&queue->mutex);
> + ret = vb2_read(&queue->queue, buf, count, ppos,
> + file->f_flags & O_NONBLOCK);
> + mutex_unlock(&queue->mutex);
> +
> + return ret;
> +}
> +
> int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
> {
> return vb2_mmap(&queue->queue, vma);
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 84be596..3866832 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -594,7 +594,8 @@ static int uvc_ioctl_querycap(struct file *file, void *fh,
> strscpy(cap->driver, "uvcvideo", sizeof(cap->driver));
> strscpy(cap->card, vdev->name, sizeof(cap->card));
> usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info));
> - cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
> + cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING |
> + V4L2_CAP_READWRITE
> | chain->caps;
device_caps for VIDEO_CAPTURE should also get V4L2_CAP_READWRITE. See uvc_register_video_device().
Regards,
Hans
>
> return 0;
> @@ -1434,8 +1435,12 @@ static long uvc_v4l2_compat_ioctl32(struct file *file,
> static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
> size_t count, loff_t *ppos)
> {
> - uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n");
> - return -EINVAL;
> + struct uvc_fh *handle = file->private_data;
> + struct uvc_streaming *stream = handle->stream;
> +
> + uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read\n");
> +
> + return uvc_queue_read(&stream->queue, file, data, count, ppos);
> }
>
> static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index c7c1baa..5d0515c 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -766,6 +766,8 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
> struct uvc_buffer *buf);
> struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue);
> void uvc_queue_buffer_release(struct uvc_buffer *buf);
> +ssize_t uvc_queue_read(struct uvc_video_queue *queue, struct file *file,
> + char __user *buf, size_t count, loff_t *ppos);
> int uvc_queue_mmap(struct uvc_video_queue *queue,
> struct vm_area_struct *vma);
> __poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
>