mirror of
https://github.com/torvalds/linux.git
synced 2024-11-08 13:11:45 +00:00
[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 <p.osciak@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
d14e6d76eb
commit
52a3082fea
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user