Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52a3082f authored by Pawel Osciak's avatar Pawel Osciak Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarPawel Osciak <p.osciak@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent d14e6d76
Loading
Loading
Loading
Loading
+195 −34
Original line number Original line Diff line number Diff line
@@ -97,6 +97,14 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi
	return 0;
	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)
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)))
	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;
	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)
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)))
	if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
@@ -136,6 +152,7 @@ struct v4l2_format32 {
	enum v4l2_buf_type type;
	enum v4l2_buf_type type;
	union {
	union {
		struct v4l2_pix_format	pix;
		struct v4l2_pix_format	pix;
		struct v4l2_pix_format_mplane	pix_mp;
		struct v4l2_window32	win;
		struct v4l2_window32	win;
		struct v4l2_vbi_format	vbi;
		struct v4l2_vbi_format	vbi;
		struct v4l2_sliced_vbi_format	sliced;
		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_CAPTURE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
		return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
		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_OVERLAY:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
		return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
		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_CAPTURE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
		return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
		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_OVERLAY:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
		return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
		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;
	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 {
struct v4l2_buffer32 {
	__u32			index;
	__u32			index;
	enum v4l2_buf_type      type;
	enum v4l2_buf_type      type;
@@ -247,14 +283,64 @@ struct v4l2_buffer32 {
	union {
	union {
		__u32           offset;
		__u32           offset;
		compat_long_t   userptr;
		compat_long_t   userptr;
		compat_caddr_t  planes;
	} m;
	} m;
	__u32			length;
	__u32			length;
	__u32			input;
	__u32			input;
	__u32			reserved;
	__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)
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)) ||
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
		get_user(kp->index, &up->index) ||
		get_user(kp->index, &up->index) ||
@@ -263,6 +349,49 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
		get_user(kp->memory, &up->memory) ||
		get_user(kp->memory, &up->memory) ||
		get_user(kp->input, &up->input))
		get_user(kp->input, &up->input))
			return -EFAULT;
			return -EFAULT;

	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;

	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;
		}

		if (get_user(p, &up->m.planes))
			return -EFAULT;

		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) {
		switch (kp->memory) {
		case V4L2_MEMORY_MMAP:
		case V4L2_MEMORY_MMAP:
			if (get_user(kp->length, &up->length) ||
			if (get_user(kp->length, &up->length) ||
@@ -285,11 +414,19 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
				return -EFAULT;
				return -EFAULT;
			break;
			break;
		}
		}
	}

	return 0;
	return 0;
}
}


static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
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)) ||
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
		put_user(kp->index, &up->index) ||
		put_user(kp->index, &up->index) ||
		put_user(kp->type, &up->type) ||
		put_user(kp->type, &up->type) ||
@@ -297,6 +434,34 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
		put_user(kp->memory, &up->memory) ||
		put_user(kp->memory, &up->memory) ||
		put_user(kp->input, &up->input))
		put_user(kp->input, &up->input))
			return -EFAULT;
			return -EFAULT;

	if (put_user(kp->bytesused, &up->bytesused) ||
		put_user(kp->field, &up->field) ||
		put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
		put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
		copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
		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) {
		switch (kp->memory) {
		case V4L2_MEMORY_MMAP:
		case V4L2_MEMORY_MMAP:
			if (put_user(kp->length, &up->length) ||
			if (put_user(kp->length, &up->length) ||
@@ -313,14 +478,8 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
				return -EFAULT;
				return -EFAULT;
			break;
			break;
		}
		}
	if (put_user(kp->bytesused, &up->bytesused) ||
	}
		put_user(kp->field, &up->field) ||

		put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
		put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
		copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
		put_user(kp->sequence, &up->sequence) ||
		put_user(kp->reserved, &up->reserved))
			return -EFAULT;
	return 0;
	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))
	if (get_user(p, &up->controls))
		return -EFAULT;
		return -EFAULT;
	ucontrols = compat_ptr(p);
	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;
		return -EFAULT;
	kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
	kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
	kp->controls = kcontrols;
	kp->controls = kcontrols;
	while (--n >= 0) {
	while (--n >= 0) {
		if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
		if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
			return -EFAULT;
			return -EFAULT;
		if (ctrl_is_pointer(kcontrols->id)) {
		if (ctrl_is_pointer(kcontrols->id)) {
			void __user *s;
			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))
	if (get_user(p, &up->controls))
		return -EFAULT;
		return -EFAULT;
	ucontrols = compat_ptr(p);
	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;
		return -EFAULT;


	while (--n >= 0) {
	while (--n >= 0) {