diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 5d46aa2..fee8b94 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -605,27 +605,21 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
 
 	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 		if (ops->vidioc_g_fmt_vid_cap ||
 				ops->vidioc_g_fmt_vid_cap_mplane)
 			return 0;
 		break;
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-		if (ops->vidioc_g_fmt_vid_cap_mplane)
-			return 0;
-		break;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 		if (ops->vidioc_g_fmt_vid_overlay)
 			return 0;
 		break;
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 		if (ops->vidioc_g_fmt_vid_out ||
 				ops->vidioc_g_fmt_vid_out_mplane)
 			return 0;
 		break;
-	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-		if (ops->vidioc_g_fmt_vid_out_mplane)
-			return 0;
-		break;
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		if (ops->vidioc_g_fmt_vid_out_overlay)
 			return 0;
@@ -654,6 +648,64 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type)
 	return -EINVAL;
 }
 
+static enum v4l2_buf_type convert_type(const struct v4l2_ioctl_ops *ops,
+					enum v4l2_buf_type type)
+{
+	if (ops == NULL)
+		return type;
+
+	switch (type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (!ops->vidioc_g_fmt_vid_cap
+				&& ops->vidioc_g_fmt_vid_cap_mplane)
+			return V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		if (!ops->vidioc_g_fmt_vid_cap_mplane
+				&& ops->vidioc_g_fmt_vid_cap)
+			return V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+		if (!ops->vidioc_g_fmt_vid_out
+				&& ops->vidioc_g_fmt_vid_out_mplane)
+			return V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (!ops->vidioc_g_fmt_vid_out_mplane
+				&& ops->vidioc_g_fmt_vid_out)
+			return V4L2_BUF_TYPE_VIDEO_OUTPUT;
+		break;
+	default:
+		break;
+	}
+
+	return type;
+}
+
+static int type_sp_to_mp(enum v4l2_buf_type t_sp, enum v4l2_buf_type *t_mp)
+{
+	if (t_sp == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		*t_mp = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	else if (t_sp == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		*t_mp = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int type_mp_to_sp(enum v4l2_buf_type t_mp, enum v4l2_buf_type *t_sp)
+{
+	if (t_mp == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		*t_sp = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	else if (t_mp == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		*t_sp = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
  * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane
  * equivalent
@@ -663,13 +715,11 @@ static int fmt_sp_to_mp(const struct v4l2_format *f_sp,
 {
 	struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
 	const struct v4l2_pix_format *pix = &f_sp->fmt.pix;
+	int ret;
 
-	if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
-		f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-	else
-		return -EINVAL;
+	ret = type_sp_to_mp(f_sp->type, &f_mp->type);
+	if (ret)
+		return ret;
 
 	pix_mp->width = pix->width;
 	pix_mp->height = pix->height;
@@ -692,13 +742,11 @@ static int fmt_mp_to_sp(const struct v4l2_format *f_mp,
 {
 	const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp;
 	struct v4l2_pix_format *pix = &f_sp->fmt.pix;
+	int ret;
 
-	if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-		f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-		f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-	else
-		return -EINVAL;
+	ret = type_mp_to_sp(f_mp->type, &f_sp->type);
+	if (ret)
+		return ret;
 
 	pix->width = pix_mp->width;
 	pix->height = pix_mp->height;
@@ -711,6 +759,48 @@ static int fmt_mp_to_sp(const struct v4l2_format *f_mp,
 	return 0;
 }
 
+static int buf_sp_to_mp(const struct v4l2_buffer *b_sp,
+			struct v4l2_buffer *b_mp)
+{
+	int ret;
+
+	memcpy(b_mp, b_sp, sizeof *b_mp);
+	ret = type_sp_to_mp(b_sp->type, &b_mp->type);
+	if (ret)
+		return ret;
+	b_mp->m.planes[0].length = b_sp->length;
+	b_mp->m.planes[0].bytesused = b_mp->bytesused;
+	b_mp->length = 1;
+	memcpy(&b_mp->m.planes[0].m, &b_sp->m, sizeof(struct v4l2_plane));
+
+	return 0;
+}
+
+static int buf_mp_to_sp(const struct v4l2_buffer *b_mp,
+			struct v4l2_buffer *b_sp)
+{
+	int ret;
+
+	memcpy(b_sp, b_mp, sizeof *b_sp);
+	ret = type_mp_to_sp(b_mp->type, &b_sp->type);
+	if (ret)
+		return ret;
+	b_sp->length = b_mp->m.planes[0].length;
+	b_sp->bytesused = b_mp->m.planes[0].bytesused;
+	memcpy(&b_sp->m, &b_mp->m.planes[0].m, sizeof(struct v4l2_plane));
+
+	return 0;
+}
+
+static int convert_buffer(const struct v4l2_buffer *b_src,
+				struct v4l2_buffer *b_dst)
+{
+	if (V4L2_TYPE_IS_MULTIPLANAR(b_src->type))
+		return buf_mp_to_sp(b_src, b_dst);
+	else
+		return buf_sp_to_mp(b_src, b_dst);
+}
+
 static long __video_do_ioctl(struct file *file,
 		unsigned int cmd, void *arg)
 {
@@ -718,6 +808,9 @@ static long __video_do_ioctl(struct file *file,
 	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
 	void *fh = file->private_data;
 	struct v4l2_format f_copy;
+	enum v4l2_buf_type old_type;
+	struct v4l2_buffer buf_copy;
+	struct v4l2_plane buf_copy_planes[VIDEO_MAX_PLANES];
 	long ret = -EINVAL;
 
 	if (ops == NULL) {
@@ -726,6 +819,8 @@ static long __video_do_ioctl(struct file *file,
 		return -EINVAL;
 	}
 
+	buf_copy.m.planes = buf_copy_planes;
+
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	/********************************************************
 	 All other V4L1 calls are handled by v4l1_compat module.
@@ -1241,11 +1336,15 @@ static long __video_do_ioctl(struct file *file,
 		if (p->type < V4L2_BUF_TYPE_PRIVATE)
 			CLEAR_AFTER_FIELD(p, memory);
 
+		old_type = p->type;
+		p->type = convert_type(ops, p->type);
+
 		ret = ops->vidioc_reqbufs(file, fh, p);
 		dbgarg(cmd, "count=%d, type=%s, memory=%s\n",
 				p->count,
 				prt_names(p->type, v4l2_type_names),
 				prt_names(p->memory, v4l2_memory_names));
+		p->type = old_type;
 		break;
 	}
 	case VIDIOC_QUERYBUF:
@@ -1258,7 +1357,17 @@ static long __video_do_ioctl(struct file *file,
 		if (ret)
 			break;
 
-		ret = ops->vidioc_querybuf(file, fh, p);
+		buf_copy.type = convert_type(ops, p->type);
+		if (p->type != buf_copy.type) {
+			ret = convert_buffer(p, &buf_copy);
+			if (ret)
+				break;
+			ret = ops->vidioc_querybuf(file, fh, &buf_copy);
+			if (!ret)
+				ret = convert_buffer(&buf_copy, p);
+		} else {
+			ret = ops->vidioc_querybuf(file, fh, p);
+		}
 		if (!ret)
 			dbgbuf(cmd, vfd, p);
 		break;
@@ -1273,7 +1382,17 @@ static long __video_do_ioctl(struct file *file,
 		if (ret)
 			break;
 
-		ret = ops->vidioc_qbuf(file, fh, p);
+		buf_copy.type = convert_type(ops, p->type);
+		if (p->type != buf_copy.type) {
+			ret = convert_buffer(p, &buf_copy);
+			if (ret)
+				break;
+			ret = ops->vidioc_qbuf(file, fh, &buf_copy);
+			if (!ret)
+				ret = convert_buffer(&buf_copy, p);
+		} else {
+			ret = ops->vidioc_qbuf(file, fh, p);
+		}
 		if (!ret)
 			dbgbuf(cmd, vfd, p);
 		break;
@@ -1288,7 +1407,17 @@ static long __video_do_ioctl(struct file *file,
 		if (ret)
 			break;
 
-		ret = ops->vidioc_dqbuf(file, fh, p);
+		buf_copy.type = convert_type(ops, p->type);
+		if (p->type != buf_copy.type) {
+			ret = convert_buffer(p, &buf_copy);
+			if (ret)
+				break;
+			ret = ops->vidioc_dqbuf(file, fh, &buf_copy);
+			if (!ret)
+				ret = convert_buffer(&buf_copy, p);
+		} else {
+			ret = ops->vidioc_dqbuf(file, fh, p);
+		}
 		if (!ret)
 			dbgbuf(cmd, vfd, p);
 		break;
@@ -1337,6 +1466,9 @@ static long __video_do_ioctl(struct file *file,
 		if (!ops->vidioc_streamon)
 			break;
 		dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
+
+		i = convert_type(ops, i);
+
 		ret = ops->vidioc_streamon(file, fh, i);
 		break;
 	}
@@ -1347,6 +1479,9 @@ static long __video_do_ioctl(struct file *file,
 		if (!ops->vidioc_streamoff)
 			break;
 		dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
+
+		i = convert_type(ops, i);
+
 		ret = ops->vidioc_streamoff(file, fh, i);
 		break;
 	}
@@ -1811,9 +1946,14 @@ static long __video_do_ioctl(struct file *file,
 			break;
 
 		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+
+		old_type = p->type;
+		p->type = convert_type(ops, p->type);
+
 		ret = ops->vidioc_g_crop(file, fh, p);
 		if (!ret)
 			dbgrect(vfd, "", &p->c);
+		p->type = old_type;
 		break;
 	}
 	case VIDIOC_S_CROP:
@@ -1824,7 +1964,12 @@ static long __video_do_ioctl(struct file *file,
 			break;
 		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
 		dbgrect(vfd, "", &p->c);
+
+		old_type = p->type;
+		p->type = convert_type(ops, p->type);
+
 		ret = ops->vidioc_s_crop(file, fh, p);
+		p->type = old_type;
 		break;
 	}
 	case VIDIOC_CROPCAP:
@@ -1836,11 +1981,16 @@ static long __video_do_ioctl(struct file *file,
 			break;
 
 		dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
+
+		old_type = p->type;
+		p->type = convert_type(ops, p->type);
+
 		ret = ops->vidioc_cropcap(file, fh, p);
 		if (!ret) {
 			dbgrect(vfd, "bounds ", &p->bounds);
 			dbgrect(vfd, "defrect ", &p->defrect);
 		}
+		p->type = old_type;
 		break;
 	}
 	case VIDIOC_G_JPEGCOMP:
@@ -1914,7 +2064,12 @@ static long __video_do_ioctl(struct file *file,
 			ret = check_fmt(ops, p->type);
 			if (ret)
 				break;
+
+			old_type = p->type;
+			p->type = convert_type(ops, p->type);
+
 			ret = ops->vidioc_g_parm(file, fh, p);
+			p->type = old_type;
 		} else {
 			v4l2_std_id std = vfd->current_norm;
 
@@ -1945,7 +2100,12 @@ static long __video_do_ioctl(struct file *file,
 			break;
 
 		dbgarg(cmd, "type=%d\n", p->type);
+
+		old_type = p->type;
+		p->type = convert_type(ops, p->type);
+
 		ret = ops->vidioc_s_parm(file, fh, p);
+		p->type = old_type;
 		break;
 	}
 	case VIDIOC_G_TUNER:
