From patchwork Tue Mar 9 14:49:41 2010
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Pawel Osciak
X-Patchwork-Id: 84313
Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o29EnqUb007451
for ;
Tue, 9 Mar 2010 14:49:52 GMT
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1753992Ab0CIOtu (ORCPT
);
Tue, 9 Mar 2010 09:49:50 -0500
Received: from mailout1.w1.samsung.com ([210.118.77.11]:36913 "EHLO
mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
with ESMTP id S1753422Ab0CIOts (ORCPT
); Tue, 9 Mar 2010 09:49:48 -0500
Received: from eu_spt2 (mailout1.w1.samsung.com [210.118.77.11])
by mailout1.w1.samsung.com
(iPlanet Messaging Server 5.2 Patch 2 (built Jul 14 2004))
with ESMTP id <0KZ000C2DRUYVT@mailout1.w1.samsung.com> for
linux-media@vger.kernel.org; Tue, 09 Mar 2010 14:49:46 +0000 (GMT)
Received: from linux.samsung.com ([106.116.38.10])
by spt2.w1.samsung.com (iPlanet Messaging Server 5.2 Patch 2 (built
Jul 14
2004)) with ESMTPA id <0KZ000I0XRUXZE@spt2.w1.samsung.com> for
linux-media@vger.kernel.org; Tue, 09 Mar 2010 14:49:46 +0000 (GMT)
Received: from localhost.localdomain (unknown [106.116.37.23])
by linux.samsung.com (Postfix) with ESMTP id 9DA7B27004D; Tue,
09 Mar 2010 15:26:42 +0100 (CET)
Date: Tue, 09 Mar 2010 15:49:41 +0100
From: Pawel Osciak
Subject: [PATCH v2 1/3] v4l: Add support for multi-plane buffers to V4L2 API.
In-reply-to: <1268146183-2018-1-git-send-email-p.osciak@samsung.com>
To: linux-media@vger.kernel.org
Cc: p.osciak@samsung.com, m.szyprowski@samsung.com, kyungmin.park@samsung.com,
hverkuil@xs4all.nl
Message-id: <1268146183-2018-2-git-send-email-p.osciak@samsung.com>
MIME-version: 1.0
X-Mailer: git-send-email 1.7.0
Content-type: TEXT/PLAIN
Content-transfer-encoding: 7BIT
References: <1268146183-2018-1-git-send-email-p.osciak@samsung.com>
Sender: linux-media-owner@vger.kernel.org
Precedence: bulk
List-ID:
X-Mailing-List: linux-media@vger.kernel.org
X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by
milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]);
Tue, 09 Mar 2010 14:49:53 +0000 (UTC)
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 4b11257..b89b73f 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -172,6 +172,8 @@ static const char *v4l2_memory_names[] = {
[V4L2_MEMORY_MMAP] = "mmap",
[V4L2_MEMORY_USERPTR] = "userptr",
[V4L2_MEMORY_OVERLAY] = "overlay",
+ [V4L2_MEMORY_MULTI_USERPTR] = "multi-userptr",
+ [V4L2_MEMORY_MULTI_MMAP] = "multi-mmap",
};
#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \
@@ -1975,7 +1977,7 @@ static unsigned long cmd_input_size(unsigned int cmd)
switch (cmd) {
CMDINSIZE(ENUM_FMT, fmtdesc, type);
CMDINSIZE(G_FMT, format, type);
- CMDINSIZE(QUERYBUF, buffer, type);
+ CMDINSIZE(QUERYBUF, buffer, length);
CMDINSIZE(G_PARM, streamparm, type);
CMDINSIZE(ENUMSTD, standard, index);
CMDINSIZE(ENUMINPUT, input, index);
@@ -2000,6 +2002,46 @@ static unsigned long cmd_input_size(unsigned int cmd)
}
}
+static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
+ void * __user *user_ptr, void ***kernel_ptr)
+{
+ int ret = 0;
+
+ switch(cmd) {
+ case VIDIOC_QUERYBUF:
+ case VIDIOC_QBUF:
+ case VIDIOC_DQBUF: {
+ struct v4l2_buffer *buf = parg;
+
+ if ((buf->memory == V4L2_MEMORY_MULTI_USERPTR
+ || buf->memory == V4L2_MEMORY_MULTI_MMAP)) {
+ *user_ptr = (void __user *)buf->m.planes;
+ *kernel_ptr = (void **)&buf->m.planes;
+ *array_size = sizeof(struct v4l2_plane) * buf->length;
+ ret = 1;
+ }
+ break;
+ }
+
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS: {
+ struct v4l2_ext_controls *ctrls = parg;
+
+ if (ctrls->count != 0) {
+ *user_ptr = (void __user *)ctrls->controls;
+ *kernel_ptr = (void **)&ctrls->controls;
+ *array_size = sizeof(struct v4l2_ext_control)
+ * ctrls->count;
+ ret = 1;
+ }
+ break;
+ }
+ }
+
+ return ret;
+}
+
long video_ioctl2(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -2007,15 +2049,16 @@ long video_ioctl2(struct file *file,
void *mbuf = NULL;
void *parg = NULL;
long err = -EINVAL;
- int is_ext_ctrl;
- size_t ctrls_size = 0;
+ int has_array_args;
+ size_t array_size = 0;
void __user *user_ptr = NULL;
+ void **kernel_ptr = NULL;
#ifdef __OLD_VIDIOC_
cmd = video_fix_command(cmd);
#endif
- is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
- cmd == VIDIOC_TRY_EXT_CTRLS);
+ /*is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+ cmd == VIDIOC_TRY_EXT_CTRLS);*/
/* Copy arguments into temp kernel buffer */
if (_IOC_DIR(cmd) != _IOC_NONE) {
@@ -2045,43 +2088,39 @@ long video_ioctl2(struct file *file,
}
}
- if (is_ext_ctrl) {
- struct v4l2_ext_controls *p = parg;
+ has_array_args = check_array_args(cmd, parg, &array_size,
+ &user_ptr, &kernel_ptr);
- /* In case of an error, tell the caller that it wasn't
- a specific control that caused it. */
- p->error_idx = p->count;
- user_ptr = (void __user *)p->controls;
- if (p->count) {
- ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
- /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
- mbuf = kmalloc(ctrls_size, GFP_KERNEL);
- err = -ENOMEM;
- if (NULL == mbuf)
- goto out_ext_ctrl;
- err = -EFAULT;
- if (copy_from_user(mbuf, user_ptr, ctrls_size))
- goto out_ext_ctrl;
- p->controls = mbuf;
- }
+ if (has_array_args) {
+ /* When adding new types of array args, make sure that the
+ * parent argument to ioctl, which contains the array, fits into
+ * sbuf (so that mbuf will still remain unused up to here).
+ */
+ mbuf = kmalloc(array_size, GFP_KERNEL);
+ err = -ENOMEM;
+ if (NULL == mbuf)
+ goto out_array_args;
+ err = -EFAULT;
+ if (copy_from_user(mbuf, user_ptr, array_size))
+ goto out_array_args;
+ *kernel_ptr = mbuf;
}
/* Handles IOCTL */
err = __video_do_ioctl(file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
- if (is_ext_ctrl) {
- struct v4l2_ext_controls *p = parg;
- p->controls = (void *)user_ptr;
- if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+ if (has_array_args) {
+ *kernel_ptr = user_ptr;
+ if (copy_to_user(user_ptr, mbuf, array_size))
err = -EFAULT;
- goto out_ext_ctrl;
+ goto out_array_args;
}
if (err < 0)
goto out;
-out_ext_ctrl:
+out_array_args:
/* Copy results into user buffer */
switch (_IOC_DIR(cmd)) {
case _IOC_READ:
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index d4962a7..bf3f33d 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -70,6 +70,7 @@
* Moved from videodev.h
*/
#define VIDEO_MAX_FRAME 32
+#define VIDEO_MAX_PLANES 3
#ifndef __KERNEL__
@@ -180,6 +181,10 @@ enum v4l2_memory {
V4L2_MEMORY_MMAP = 1,
V4L2_MEMORY_USERPTR = 2,
V4L2_MEMORY_OVERLAY = 3,
+
+ /* Discontiguous buffer types */
+ V4L2_MEMORY_MULTI_USERPTR = 4,
+ V4L2_MEMORY_MULTI_MMAP = 5,
};
/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
@@ -519,6 +524,29 @@ struct v4l2_requestbuffers {
__u32 reserved[2];
};
+/* struct v4l2_plane - a multi-plane buffer plane.
+ *
+ * Multi-plane buffers consist of two or more planes, e.g. an YCbCr buffer
+ * with two planes has one plane for Y, and another for interleaved CbCr
+ * components. Each plane can reside in a separate memory buffer, or in
+ * a completely separate memory chip even (e.g. in embedded devices).
+ */
+struct v4l2_plane {
+ __u32 bytesused;
+
+ union {
+ __u32 offset;
+ unsigned long userptr;
+ } m;
+ __u32 length;
+ __u32 reserved[5];
+};
+
+/* struct v4l2_buffer - a video buffer (frame)
+ * @length: size of the buffer (not its payload) for single-plane buffers,
+ * number of planes (and number of elements in planes array)
+ * for multi-plane
+ */
struct v4l2_buffer {
__u32 index;
enum v4l2_buf_type type;
@@ -532,8 +560,9 @@ struct v4l2_buffer {
/* memory location */
enum v4l2_memory memory;
union {
- __u32 offset;
- unsigned long userptr;
+ __u32 offset;
+ unsigned long userptr;
+ struct v4l2_plane *planes;
} m;
__u32 length;
__u32 input;