[media] V4L: add two new ioctl()s for multi-size videobuffer management
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Wed, 28 Sep 2011 14:34:06 +0000 (11:34 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 3 Nov 2011 20:28:24 +0000 (18:28 -0200)
A possibility to preallocate and initialise buffers of different sizes
in V4L2 is required for an efficient implementation of a snapshot
mode. This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
VIDIOC_PREPARE_BUF and defines respective data structures.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-ioctl.c
include/linux/videodev2.h
include/media/v4l2-ioctl.h

index 61979b7..e77e0cf 100644 (file)
@@ -159,11 +159,16 @@ struct v4l2_format32 {
        } fmt;
 };
 
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+struct v4l2_create_buffers32 {
+       __u32                   index;          /* output: buffers index...index + count - 1 have been created */
+       __u32                   count;
+       enum v4l2_memory        memory;
+       struct v4l2_format32    format;         /* filled in by the user, plane sizes calculated by the driver */
+       __u32                   reserved[8];
+};
+
+static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
 {
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
-                       get_user(kp->type, &up->type))
-                       return -EFAULT;
        switch (kp->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
@@ -192,11 +197,24 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
        }
 }
 
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
+       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
+                       get_user(kp->type, &up->type))
+                       return -EFAULT;
+       return __get_v4l2_format32(kp, up);
+}
+
+static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+{
+       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
+           copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format.fmt)))
+                       return -EFAULT;
+       return __get_v4l2_format32(&kp->format, &up->format);
+}
+
+static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
 {
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
-               put_user(kp->type, &up->type))
-               return -EFAULT;
        switch (kp->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
@@ -225,6 +243,22 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
        }
 }
 
+static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+{
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
+               put_user(kp->type, &up->type))
+               return -EFAULT;
+       return __put_v4l2_format32(kp, up);
+}
+
+static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+{
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
+           copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt)))
+                       return -EFAULT;
+       return __put_v4l2_format32(&kp->format, &up->format);
+}
+
 struct v4l2_standard32 {
        __u32                index;
        __u32                id[2]; /* __u64 would get the alignment wrong */
@@ -702,6 +736,8 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u
 #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
 #define        VIDIOC_DQEVENT32        _IOR ('V', 89, struct v4l2_event32)
+#define VIDIOC_CREATE_BUFS32   _IOWR('V', 92, struct v4l2_create_buffers32)
+#define VIDIOC_PREPARE_BUF32   _IOWR('V', 93, struct v4l2_buffer32)
 
 #define VIDIOC_OVERLAY32       _IOW ('V', 14, s32)
 #define VIDIOC_STREAMON32      _IOW ('V', 18, s32)
@@ -721,6 +757,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                struct v4l2_standard v2s;
                struct v4l2_ext_controls v2ecs;
                struct v4l2_event v2ev;
+               struct v4l2_create_buffers v2crt;
                unsigned long vx;
                int vi;
        } karg;
@@ -751,6 +788,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
        case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
        case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
+       case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
+       case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
        }
 
        switch (cmd) {
@@ -775,6 +814,12 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                compatible_arg = 0;
                break;
 
+       case VIDIOC_CREATE_BUFS:
+               err = get_v4l2_create32(&karg.v2crt, up);
+               compatible_arg = 0;
+               break;
+
+       case VIDIOC_PREPARE_BUF:
        case VIDIOC_QUERYBUF:
        case VIDIOC_QBUF:
        case VIDIOC_DQBUF:
@@ -860,6 +905,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                err = put_v4l2_format32(&karg.v2f, up);
                break;
 
+       case VIDIOC_CREATE_BUFS:
+               err = put_v4l2_create32(&karg.v2crt, up);
+               break;
+
        case VIDIOC_QUERYBUF:
        case VIDIOC_QBUF:
        case VIDIOC_DQBUF:
@@ -959,6 +1008,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
        case VIDIOC_DQEVENT32:
        case VIDIOC_SUBSCRIBE_EVENT:
        case VIDIOC_UNSUBSCRIBE_EVENT:
+       case VIDIOC_CREATE_BUFS32:
+       case VIDIOC_PREPARE_BUF32:
                ret = do_video_ioctl(file, cmd, arg);
                break;
 
index 24fd433..e1da8fc 100644 (file)
@@ -273,6 +273,8 @@ static const char *v4l2_ioctls[] = {
        [_IOC_NR(VIDIOC_DQEVENT)]          = "VIDIOC_DQEVENT",
        [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)]  = "VIDIOC_SUBSCRIBE_EVENT",
        [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT",
+       [_IOC_NR(VIDIOC_CREATE_BUFS)]      = "VIDIOC_CREATE_BUFS",
+       [_IOC_NR(VIDIOC_PREPARE_BUF)]      = "VIDIOC_PREPARE_BUF",
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
@@ -2104,6 +2106,40 @@ static long __video_do_ioctl(struct file *file,
                dbgarg(cmd, "type=0x%8.8x", sub->type);
                break;
        }
+       case VIDIOC_CREATE_BUFS:
+       {
+               struct v4l2_create_buffers *create = arg;
+
+               if (!ops->vidioc_create_bufs)
+                       break;
+               if (ret_prio) {
+                       ret = ret_prio;
+                       break;
+               }
+               ret = check_fmt(ops, create->format.type);
+               if (ret)
+                       break;
+
+               ret = ops->vidioc_create_bufs(file, fh, create);
+
+               dbgarg(cmd, "count=%d @ %d\n", create->count, create->index);
+               break;
+       }
+       case VIDIOC_PREPARE_BUF:
+       {
+               struct v4l2_buffer *b = arg;
+
+               if (!ops->vidioc_prepare_buf)
+                       break;
+               ret = check_fmt(ops, b->type);
+               if (ret)
+                       break;
+
+               ret = ops->vidioc_prepare_buf(file, fh, b);
+
+               dbgarg(cmd, "index=%d", b->index);
+               break;
+       }
        default:
                if (!ops->vidioc_default)
                        break;
index 225560c..cd512f0 100644 (file)
@@ -653,6 +653,10 @@ struct v4l2_buffer {
 #define V4L2_BUF_FLAG_ERROR    0x0040
 #define V4L2_BUF_FLAG_TIMECODE 0x0100  /* timecode field is valid */
 #define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
+#define V4L2_BUF_FLAG_PREPARED 0x0400  /* Buffer is prepared for queuing */
+/* Cache handling flags */
+#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE      0x0800
+#define V4L2_BUF_FLAG_NO_CACHE_CLEAN           0x1000
 
 /*
  *     O V E R L A Y   P R E V I E W
@@ -2138,6 +2142,15 @@ struct v4l2_dbg_chip_ident {
        __u32 revision;    /* chip revision, chip specific */
 } __attribute__ ((packed));
 
+/* VIDIOC_CREATE_BUFS */
+struct v4l2_create_buffers {
+       __u32                   index;          /* output: buffers index...index + count - 1 have been created */
+       __u32                   count;
+       enum v4l2_memory        memory;
+       struct v4l2_format      format;         /* "type" is used always, the rest if sizeimage == 0 */
+       __u32                   reserved[8];
+};
+
 /*
  *     I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
  *
@@ -2228,6 +2241,11 @@ struct v4l2_dbg_chip_ident {
 #define        VIDIOC_SUBSCRIBE_EVENT   _IOW('V', 90, struct v4l2_event_subscription)
 #define        VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription)
 
+/* Experimental, the below two ioctls may change over the next couple of kernel
+   versions */
+#define VIDIOC_CREATE_BUFS     _IOWR('V', 92, struct v4l2_create_buffers)
+#define VIDIOC_PREPARE_BUF     _IOWR('V', 93, struct v4l2_buffer)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
index dd9f1e7..4d1c74a 100644 (file)
@@ -122,6 +122,8 @@ struct v4l2_ioctl_ops {
        int (*vidioc_qbuf)    (struct file *file, void *fh, struct v4l2_buffer *b);
        int (*vidioc_dqbuf)   (struct file *file, void *fh, struct v4l2_buffer *b);
 
+       int (*vidioc_create_bufs)(struct file *file, void *fh, struct v4l2_create_buffers *b);
+       int (*vidioc_prepare_buf)(struct file *file, void *fh, struct v4l2_buffer *b);
 
        int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i);
        int (*vidioc_g_fbuf)   (struct file *file, void *fh,