From 52a3082fea41ffe77003be76ac1496d60bb7908e Mon Sep 17 00:00:00 2001
From: Pawel Osciak
Date: Thu, 29 Jul 2010 14:56:47 -0300
Subject: [PATCH] [media] v4l: Add compat functions for the multi-planar API
Add multi-planar ioctl handling to the 32bit compatibility layer.
[mchehab@redhat.com: Merged with a fixup patch from Pawel]
Signed-off-by: Pawel Osciak
Signed-off-by: Kyungmin Park
Signed-off-by: Marek Szyprowski
Reviewed-by: Hans Verkuil
Signed-off-by: Mauro Carvalho Chehab
---
drivers/media/video/v4l2-compat-ioctl32.c | 231 ++++++++++++++++++----
1 file changed, 196 insertions(+), 35 deletions(-)
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index dc82eb83c1d4..c19208a07b48 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -97,6 +97,14 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi
return 0;
}
+static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+ struct v4l2_pix_format_mplane __user *up)
+{
+ if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+ return -EFAULT;
+ return 0;
+}
+
static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
{
if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
@@ -104,6 +112,14 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi
return 0;
}
+static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+ struct v4l2_pix_format_mplane __user *up)
+{
+ if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+ return -EFAULT;
+ return 0;
+}
+
static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
{
if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
@@ -136,6 +152,7 @@ struct v4l2_format32 {
enum v4l2_buf_type type;
union {
struct v4l2_pix_format pix;
+ struct v4l2_pix_format_mplane pix_mp;
struct v4l2_window32 win;
struct v4l2_vbi_format vbi;
struct v4l2_sliced_vbi_format sliced;
@@ -152,6 +169,10 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+ &up->fmt.pix_mp);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
@@ -181,6 +202,10 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
+ &up->fmt.pix_mp);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
@@ -232,6 +257,17 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32
return 0;
}
+struct v4l2_plane32 {
+ __u32 bytesused;
+ __u32 length;
+ union {
+ __u32 mem_offset;
+ compat_long_t userptr;
+ } m;
+ __u32 data_offset;
+ __u32 reserved[11];
+};
+
struct v4l2_buffer32 {
__u32 index;
enum v4l2_buf_type type;
@@ -247,14 +283,64 @@ struct v4l2_buffer32 {
union {
__u32 offset;
compat_long_t userptr;
+ compat_caddr_t planes;
} m;
__u32 length;
__u32 input;
__u32 reserved;
};
+static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+ enum v4l2_memory memory)
+{
+ void __user *up_pln;
+ compat_long_t p;
+
+ if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
+ copy_in_user(&up->data_offset, &up32->data_offset,
+ sizeof(__u32)))
+ return -EFAULT;
+
+ if (memory == V4L2_MEMORY_USERPTR) {
+ if (get_user(p, &up32->m.userptr))
+ return -EFAULT;
+ up_pln = compat_ptr(p);
+ if (put_user((unsigned long)up_pln, &up->m.userptr))
+ return -EFAULT;
+ } else {
+ if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
+ sizeof(__u32)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
+ enum v4l2_memory memory)
+{
+ if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
+ copy_in_user(&up32->data_offset, &up->data_offset,
+ sizeof(__u32)))
+ return -EFAULT;
+
+ /* For MMAP, driver might've set up the offset, so copy it back.
+ * USERPTR stays the same (was userspace-provided), so no copying. */
+ if (memory == V4L2_MEMORY_MMAP)
+ if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
+ sizeof(__u32)))
+ return -EFAULT;
+
+ return 0;
+}
+
static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
{
+ struct v4l2_plane32 __user *uplane32;
+ struct v4l2_plane __user *uplane;
+ compat_caddr_t p;
+ int num_planes;
+ int ret;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
get_user(kp->index, &up->index) ||
@@ -263,33 +349,84 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
get_user(kp->memory, &up->memory) ||
get_user(kp->input, &up->input))
return -EFAULT;
- switch (kp->memory) {
- case V4L2_MEMORY_MMAP:
- if (get_user(kp->length, &up->length) ||
- get_user(kp->m.offset, &up->m.offset))
- return -EFAULT;
- break;
- case V4L2_MEMORY_USERPTR:
- {
- compat_long_t tmp;
- if (get_user(kp->length, &up->length) ||
- get_user(tmp, &up->m.userptr))
+ if (V4L2_TYPE_IS_OUTPUT(kp->type))
+ if (get_user(kp->bytesused, &up->bytesused) ||
+ get_user(kp->field, &up->field) ||
+ get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
+ get_user(kp->timestamp.tv_usec,
+ &up->timestamp.tv_usec))
return -EFAULT;
- kp->m.userptr = (unsigned long)compat_ptr(tmp);
+ if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+ if (get_user(kp->length, &up->length))
+ return -EFAULT;
+
+ num_planes = kp->length;
+ if (num_planes == 0) {
+ kp->m.planes = NULL;
+ /* num_planes == 0 is legal, e.g. when userspace doesn't
+ * need planes array on DQBUF*/
+ return 0;
}
- break;
- case V4L2_MEMORY_OVERLAY:
- if (get_user(kp->m.offset, &up->m.offset))
+
+ if (get_user(p, &up->m.planes))
return -EFAULT;
- break;
+
+ uplane32 = compat_ptr(p);
+ if (!access_ok(VERIFY_READ, uplane32,
+ num_planes * sizeof(struct v4l2_plane32)))
+ return -EFAULT;
+
+ /* We don't really care if userspace decides to kill itself
+ * by passing a very big num_planes value */
+ uplane = compat_alloc_user_space(num_planes *
+ sizeof(struct v4l2_plane));
+ kp->m.planes = uplane;
+
+ while (--num_planes >= 0) {
+ ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
+ if (ret)
+ return ret;
+ ++uplane;
+ ++uplane32;
+ }
+ } else {
+ switch (kp->memory) {
+ case V4L2_MEMORY_MMAP:
+ if (get_user(kp->length, &up->length) ||
+ get_user(kp->m.offset, &up->m.offset))
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_USERPTR:
+ {
+ compat_long_t tmp;
+
+ if (get_user(kp->length, &up->length) ||
+ get_user(tmp, &up->m.userptr))
+ return -EFAULT;
+
+ kp->m.userptr = (unsigned long)compat_ptr(tmp);
+ }
+ break;
+ case V4L2_MEMORY_OVERLAY:
+ if (get_user(kp->m.offset, &up->m.offset))
+ return -EFAULT;
+ break;
+ }
}
+
return 0;
}
static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
{
+ struct v4l2_plane32 __user *uplane32;
+ struct v4l2_plane __user *uplane;
+ compat_caddr_t p;
+ int num_planes;
+ int ret;
+
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
put_user(kp->index, &up->index) ||
put_user(kp->type, &up->type) ||
@@ -297,22 +434,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
put_user(kp->memory, &up->memory) ||
put_user(kp->input, &up->input))
return -EFAULT;
- switch (kp->memory) {
- case V4L2_MEMORY_MMAP:
- if (put_user(kp->length, &up->length) ||
- put_user(kp->m.offset, &up->m.offset))
- return -EFAULT;
- break;
- case V4L2_MEMORY_USERPTR:
- if (put_user(kp->length, &up->length) ||
- put_user(kp->m.userptr, &up->m.userptr))
- return -EFAULT;
- break;
- case V4L2_MEMORY_OVERLAY:
- if (put_user(kp->m.offset, &up->m.offset))
- return -EFAULT;
- break;
- }
+
if (put_user(kp->bytesused, &up->bytesused) ||
put_user(kp->field, &up->field) ||
put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
@@ -321,6 +443,43 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
put_user(kp->sequence, &up->sequence) ||
put_user(kp->reserved, &up->reserved))
return -EFAULT;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
+ num_planes = kp->length;
+ if (num_planes == 0)
+ return 0;
+
+ uplane = kp->m.planes;
+ if (get_user(p, &up->m.planes))
+ return -EFAULT;
+ uplane32 = compat_ptr(p);
+
+ while (--num_planes >= 0) {
+ ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
+ if (ret)
+ return ret;
+ ++uplane;
+ ++uplane32;
+ }
+ } else {
+ switch (kp->memory) {
+ case V4L2_MEMORY_MMAP:
+ if (put_user(kp->length, &up->length) ||
+ put_user(kp->m.offset, &up->m.offset))
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_USERPTR:
+ if (put_user(kp->length, &up->length) ||
+ put_user(kp->m.userptr, &up->m.userptr))
+ return -EFAULT;
+ break;
+ case V4L2_MEMORY_OVERLAY:
+ if (put_user(kp->m.offset, &up->m.offset))
+ return -EFAULT;
+ break;
+ }
+ }
+
return 0;
}
@@ -442,12 +601,13 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
if (get_user(p, &up->controls))
return -EFAULT;
ucontrols = compat_ptr(p);
- if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
+ if (!access_ok(VERIFY_READ, ucontrols,
+ n * sizeof(struct v4l2_ext_control32)))
return -EFAULT;
kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
kp->controls = kcontrols;
while (--n >= 0) {
- if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
+ if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
return -EFAULT;
if (ctrl_is_pointer(kcontrols->id)) {
void __user *s;
@@ -483,7 +643,8 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
if (get_user(p, &up->controls))
return -EFAULT;
ucontrols = compat_ptr(p);
- if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
+ if (!access_ok(VERIFY_WRITE, ucontrols,
+ n * sizeof(struct v4l2_ext_control32)))
return -EFAULT;
while (--n >= 0) {