[RFC PATCH 1/2] v4l2: add extended streaming operations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Hans Verkuil <hans.verkuil@xxxxxxxxx>

For year 2038 and to simplify multiplanar formats.

Signed-off-by: Hans Verkuil <hans.verkuil@xxxxxxxxx>
---
 drivers/media/v4l2-core/v4l2-common.c    |  72 +++++++
 drivers/media/v4l2-core/v4l2-dev.c       |   4 +
 drivers/media/v4l2-core/v4l2-ioctl.c     | 146 +++++++++++++-
 drivers/media/v4l2-core/v4l2-mem2mem.c   |  97 +++++++++
 drivers/media/v4l2-core/videobuf2-v4l2.c | 332 +++++++++++++++----------------
 include/media/v4l2-common.h              |   5 +
 include/media/v4l2-ioctl.h               |  17 ++
 include/media/v4l2-mem2mem.h             |   8 +
 include/media/videobuf2-v4l2.h           |   9 +
 include/uapi/linux/videodev2.h           |  47 +++++
 10 files changed, 557 insertions(+), 180 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index a5ea1f517291..9faa77566a32 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -405,3 +405,75 @@ void v4l2_get_timestamp(struct timeval *tv)
 	tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
 }
 EXPORT_SYMBOL_GPL(v4l2_get_timestamp);
+
+void v4l2_ext_buffer_to_buffer(const struct v4l2_ext_buffer *e,
+			       struct v4l2_buffer *b)
+{
+	u64 nsecs;
+
+	b->index = e->index;
+	b->type = e->type;
+	b->flags = e->flags;
+	b->field = e->field;
+	b->sequence = e->sequence;
+	b->memory = e->memory;
+	b->timestamp.tv_sec = div64_u64_rem(e->timestamp, NSEC_PER_SEC, &nsecs);
+	b->timestamp.tv_usec = (u32)nsecs / NSEC_PER_USEC;
+	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
+		unsigned int i;
+
+		b->length = e->num_planes;
+		for (i = 0; i < e->num_planes; i++) {
+			b->m.planes[i].length = e->planes[i].length;
+			b->m.planes[i].bytesused = e->planes[i].bytesused;
+			b->m.planes[i].m.userptr = e->planes[i].m.userptr;
+			b->m.planes[i].data_offset = e->planes[i].data_offset;
+			memset(b->m.planes[i].reserved, 0,
+			       sizeof(b->m.planes[i].reserved));
+		}
+	} else {
+		b->bytesused = e->planes[0].bytesused;
+		b->length = e->planes[0].length;
+		b->m.userptr = e->planes[0].m.userptr;
+	}
+	b->reserved2 = b->reserved = 0;
+	memset(&b->timecode, 0, sizeof(b->timecode));
+}
+EXPORT_SYMBOL_GPL(v4l2_ext_buffer_to_buffer);
+
+int v4l2_buffer_to_ext_buffer(const struct v4l2_buffer *b,
+			      struct v4l2_ext_buffer *e)
+{
+	e->index = b->index;
+	e->type = b->type;
+	e->flags = b->flags;
+	e->field = b->field;
+	e->sequence = b->sequence;
+	e->memory = b->memory;
+	e->timestamp = b->timestamp.tv_sec * NSEC_PER_SEC +
+		b->timestamp.tv_usec * NSEC_PER_USEC;
+	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
+		unsigned int i;
+
+		if (b->m.planes == NULL)
+			return -EINVAL;
+		e->num_planes = b->length;
+		for (i = 0; i < e->num_planes; i++) {
+			e->planes[i].length = b->m.planes[i].length;
+			e->planes[i].bytesused = b->m.planes[i].bytesused;
+			e->planes[i].m.userptr = b->m.planes[i].m.userptr;
+			e->planes[i].data_offset = b->m.planes[i].data_offset;
+			memset(e->planes[i].reserved, 0,
+			       sizeof(e->planes[i].reserved));
+		}
+	} else {
+		e->num_planes = 1;
+		e->planes[0].bytesused = b->bytesused;
+		e->planes[0].length = b->length;
+		e->planes[0].m.userptr = b->m.userptr;
+		e->planes[0].data_offset = 0;
+	}
+	memset(&e->reserved, 0, sizeof(e->reserved));
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_buffer_to_ext_buffer);
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index c647ba648805..1ce80636453b 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -678,6 +678,10 @@ static void determine_valid_ioctls(struct video_device *vdev)
 		SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
 		SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
 		SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
+		SET_VALID_IOCTL(ops, VIDIOC_EXT_QUERYBUF, vidioc_ext_querybuf);
+		SET_VALID_IOCTL(ops, VIDIOC_EXT_QBUF, vidioc_ext_qbuf);
+		SET_VALID_IOCTL(ops, VIDIOC_EXT_DQBUF, vidioc_ext_dqbuf);
+		SET_VALID_IOCTL(ops, VIDIOC_EXT_PREPARE_BUF, vidioc_ext_prepare_buf);
 	}
 
 	if (is_vid || is_vbi || is_tch) {
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 79614992ee21..b014904ec3bc 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -466,6 +466,28 @@ static void v4l_print_buffer(const void *arg, bool write_only)
 			tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits);
 }
 
+static void v4l_print_ext_buffer(const void *arg, bool write_only)
+{
+	const struct v4l2_ext_buffer *p = arg;
+	const struct v4l2_ext_plane *plane;
+	int i;
+
+	pr_cont("%lld index=%d, type=%s, flags=0x%08x, field=%s, sequence=%d, memory=%s\n",
+			p->timestamp,
+			p->index,
+			prt_names(p->type, v4l2_type_names),
+			p->flags, prt_names(p->field, v4l2_field_names),
+			p->sequence, prt_names(p->memory, v4l2_memory_names));
+
+	for (i = 0; i < p->num_planes; ++i) {
+		plane = &p->planes[i];
+		printk(KERN_DEBUG
+			"plane %d: bytesused=%d, data_offset=0x%08x, offset/userptr=0x%llx, length=%d\n",
+			i, plane->bytesused, plane->data_offset,
+			plane->m.userptr, plane->length);
+	}
+}
+
 static void v4l_print_exportbuffer(const void *arg, bool write_only)
 {
 	const struct v4l2_exportbuffer *p = arg;
@@ -1897,27 +1919,51 @@ static int v4l_querybuf(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
 	struct v4l2_buffer *p = arg;
+	struct v4l2_ext_buffer e;
 	int ret = check_fmt(file, p->type);
 
-	return ret ? ret : ops->vidioc_querybuf(file, fh, p);
+	if (ret || ops->vidioc_querybuf)
+		return ret ? ret : ops->vidioc_querybuf(file, fh, p);
+
+	v4l2_buffer_to_ext_buffer(p, &e);
+	ret = ops->vidioc_ext_querybuf(file, fh, &e);
+	if (!ret)
+		v4l2_ext_buffer_to_buffer(&e, p);
+	return ret;
 }
 
 static int v4l_qbuf(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
 	struct v4l2_buffer *p = arg;
+	struct v4l2_ext_buffer e;
 	int ret = check_fmt(file, p->type);
 
-	return ret ? ret : ops->vidioc_qbuf(file, fh, p);
+	if (ret || ops->vidioc_qbuf)
+		return ret ? ret : ops->vidioc_qbuf(file, fh, p);
+
+	v4l2_buffer_to_ext_buffer(p, &e);
+	ret = ops->vidioc_ext_qbuf(file, fh, &e);
+	if (!ret)
+		v4l2_ext_buffer_to_buffer(&e, p);
+	return ret;
 }
 
 static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
 	struct v4l2_buffer *p = arg;
+	struct v4l2_ext_buffer e;
 	int ret = check_fmt(file, p->type);
 
-	return ret ? ret : ops->vidioc_dqbuf(file, fh, p);
+	if (ret || ops->vidioc_dqbuf)
+		return ret ? ret : ops->vidioc_dqbuf(file, fh, p);
+
+	v4l2_buffer_to_ext_buffer(p, &e);
+	ret = ops->vidioc_ext_dqbuf(file, fh, &e);
+	if (!ret)
+		v4l2_ext_buffer_to_buffer(&e, p);
+	return ret;
 }
 
 static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
@@ -1946,9 +1992,17 @@ static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
 	struct v4l2_buffer *b = arg;
+	struct v4l2_ext_buffer e;
 	int ret = check_fmt(file, b->type);
 
-	return ret ? ret : ops->vidioc_prepare_buf(file, fh, b);
+	if (ret || ops->vidioc_prepare_buf)
+		return ret ? ret : ops->vidioc_prepare_buf(file, fh, b);
+
+	v4l2_buffer_to_ext_buffer(b, &e);
+	ret = ops->vidioc_ext_prepare_buf(file, fh, &e);
+	if (!ret)
+		v4l2_ext_buffer_to_buffer(&e, b);
+	return ret;
 }
 
 static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
@@ -2511,6 +2565,86 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
 	return -ENOTTY;
 }
 
+static int v4l_ext_prepare_buf(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh, void *arg)
+{
+	struct v4l2_ext_buffer *e = arg;
+	struct v4l2_plane planes[VIDEO_MAX_PLANES];
+	struct v4l2_buffer b = {
+		.m.planes = planes,
+	};
+	int ret = check_fmt(file, e->type);
+
+	if (ret || ops->vidioc_ext_prepare_buf)
+		return ret ? ret : ops->vidioc_ext_prepare_buf(file, fh, e);
+
+	v4l2_ext_buffer_to_buffer(e, &b);
+	ret = ops->vidioc_prepare_buf(file, fh, &b);
+	if (!ret)
+		v4l2_buffer_to_ext_buffer(&b, e);
+	return ret;
+}
+
+static int v4l_ext_querybuf(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh, void *arg)
+{
+	struct v4l2_ext_buffer *e = arg;
+	struct v4l2_plane planes[VIDEO_MAX_PLANES];
+	struct v4l2_buffer b = {
+		.m.planes = planes,
+	};
+	int ret = check_fmt(file, e->type);
+
+	if (ret || ops->vidioc_ext_querybuf)
+		return ret ? ret : ops->vidioc_ext_querybuf(file, fh, e);
+
+	v4l2_ext_buffer_to_buffer(e, &b);
+	ret = ops->vidioc_querybuf(file, fh, &b);
+	if (!ret)
+		v4l2_buffer_to_ext_buffer(&b, e);
+	return ret;
+}
+
+static int v4l_ext_qbuf(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh, void *arg)
+{
+	struct v4l2_ext_buffer *e = arg;
+	struct v4l2_plane planes[VIDEO_MAX_PLANES];
+	struct v4l2_buffer b = {
+		.m.planes = planes,
+	};
+	int ret = check_fmt(file, e->type);
+
+	if (ret || ops->vidioc_ext_qbuf)
+		return ret ? ret : ops->vidioc_ext_qbuf(file, fh, e);
+
+	v4l2_ext_buffer_to_buffer(e, &b);
+	ret = ops->vidioc_qbuf(file, fh, &b);
+	if (!ret)
+		v4l2_buffer_to_ext_buffer(&b, e);
+	return ret;
+}
+
+static int v4l_ext_dqbuf(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh, void *arg)
+{
+	struct v4l2_ext_buffer *e = arg;
+	struct v4l2_plane planes[VIDEO_MAX_PLANES];
+	struct v4l2_buffer b = {
+		.m.planes = planes,
+	};
+	int ret = check_fmt(file, e->type);
+
+	if (ret || ops->vidioc_ext_dqbuf)
+		return ret ? ret : ops->vidioc_ext_dqbuf(file, fh, e);
+
+	v4l2_ext_buffer_to_buffer(e, &b);
+	ret = ops->vidioc_dqbuf(file, fh, &b);
+	if (!ret)
+		v4l2_buffer_to_ext_buffer(&b, e);
+	return ret;
+}
+
 struct v4l2_ioctl_info {
 	unsigned int ioctl;
 	u32 flags;
@@ -2642,6 +2776,10 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
 	IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
 	IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
 	IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
+	IOCTL_INFO_FNC(VIDIOC_EXT_QUERYBUF, v4l_ext_querybuf, v4l_print_ext_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_ext_buffer, num_planes)),
+	IOCTL_INFO_FNC(VIDIOC_EXT_QBUF, v4l_ext_qbuf, v4l_print_ext_buffer, INFO_FL_QUEUE),
+	IOCTL_INFO_FNC(VIDIOC_EXT_DQBUF, v4l_ext_dqbuf, v4l_print_ext_buffer, INFO_FL_QUEUE),
+	IOCTL_INFO_FNC(VIDIOC_EXT_PREPARE_BUF, v4l_ext_prepare_buf, v4l_print_ext_buffer, INFO_FL_QUEUE),
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index f62e68aa04c4..fe9a7f982085 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -423,6 +423,67 @@ int v4l2_m2m_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_prepare_buf);
 
+int v4l2_m2m_ext_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		      struct v4l2_ext_buffer *buf)
+{
+	struct vb2_queue *vq;
+	int ret = 0;
+	unsigned int i;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
+	ret = vb2_ext_querybuf(vq, buf);
+
+	/* Adjust MMAP memory offsets for the CAPTURE queue */
+	if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) {
+		for (i = 0; i < buf->num_planes; ++i)
+			buf->planes[i].m.mem_offset
+					+= DST_QUEUE_OFF_BASE;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ext_querybuf);
+
+int v4l2_m2m_ext_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		  struct v4l2_ext_buffer *buf)
+{
+	struct vb2_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
+	ret = vb2_ext_qbuf(vq, buf);
+	if (!ret)
+		v4l2_m2m_try_schedule(m2m_ctx);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ext_qbuf);
+
+int v4l2_m2m_ext_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+		   struct v4l2_ext_buffer *buf)
+{
+	struct vb2_queue *vq;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
+	return vb2_ext_dqbuf(vq, buf, file->f_flags & O_NONBLOCK);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ext_dqbuf);
+
+int v4l2_m2m_ext_prepare_buf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+			 struct v4l2_ext_buffer *buf)
+{
+	struct vb2_queue *vq;
+	int ret;
+
+	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
+	ret = vb2_ext_prepare_buf(vq, buf);
+	if (!ret)
+		v4l2_m2m_try_schedule(m2m_ctx);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ext_prepare_buf);
+
 int v4l2_m2m_create_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 			 struct v4l2_create_buffers *create)
 {
@@ -752,6 +813,42 @@ int v4l2_m2m_ioctl_prepare_buf(struct file *file, void *priv,
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_prepare_buf);
 
+int v4l2_m2m_ioctl_ext_querybuf(struct file *file, void *priv,
+				struct v4l2_ext_buffer *buf)
+{
+	struct v4l2_fh *fh = file->private_data;
+
+	return v4l2_m2m_ext_querybuf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_ext_querybuf);
+
+int v4l2_m2m_ioctl_ext_qbuf(struct file *file, void *priv,
+				struct v4l2_ext_buffer *buf)
+{
+	struct v4l2_fh *fh = file->private_data;
+
+	return v4l2_m2m_ext_qbuf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_ext_qbuf);
+
+int v4l2_m2m_ioctl_ext_dqbuf(struct file *file, void *priv,
+				struct v4l2_ext_buffer *buf)
+{
+	struct v4l2_fh *fh = file->private_data;
+
+	return v4l2_m2m_ext_dqbuf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_ext_dqbuf);
+
+int v4l2_m2m_ioctl_ext_prepare_buf(struct file *file, void *priv,
+			       struct v4l2_ext_buffer *buf)
+{
+	struct v4l2_fh *fh = file->private_data;
+
+	return v4l2_m2m_ext_prepare_buf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_ext_prepare_buf);
+
 int v4l2_m2m_ioctl_expbuf(struct file *file, void *priv,
 				struct v4l2_exportbuffer *eb)
 {
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 0c0669976bdc..34ff016d34ee 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -51,22 +51,16 @@ module_param(debug, int, 0644);
 
 /**
  * __verify_planes_array() - verify that the planes array passed in struct
- * v4l2_buffer from userspace can be safely used
+ * v4l2_ext_buffer from userspace can be safely used
  */
-static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_ext_buffer *b)
 {
 	if (!V4L2_TYPE_IS_MULTIPLANAR(b->type))
 		return 0;
 
-	/* Is memory for copying plane information present? */
-	if (b->m.planes == NULL) {
-		dprintk(1, "multi-planar buffer passed but planes array not provided\n");
-		return -EINVAL;
-	}
-
-	if (b->length < vb->num_planes || b->length > VB2_MAX_PLANES) {
+	if (b->num_planes < vb->num_planes || b->num_planes > VB2_MAX_PLANES) {
 		dprintk(1, "incorrect planes array length, expected %d, got %d\n",
-			vb->num_planes, b->length);
+			vb->num_planes, b->num_planes);
 		return -EINVAL;
 	}
 
@@ -82,7 +76,7 @@ static int __verify_planes_array_core(struct vb2_buffer *vb, const void *pb)
  * __verify_length() - Verify that the bytesused value for each plane fits in
  * the plane length and that the data offset doesn't exceed the bytesused value.
  */
-static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+static int __verify_length(struct vb2_buffer *vb, const struct v4l2_ext_buffer *b)
 {
 	unsigned int length;
 	unsigned int bytesused;
@@ -91,27 +85,19 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 	if (!V4L2_TYPE_IS_OUTPUT(b->type))
 		return 0;
 
-	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
-		for (plane = 0; plane < vb->num_planes; ++plane) {
-			length = (b->memory == VB2_MEMORY_USERPTR ||
-				  b->memory == VB2_MEMORY_DMABUF)
-			       ? b->m.planes[plane].length
-				: vb->planes[plane].length;
-			bytesused = b->m.planes[plane].bytesused
-				  ? b->m.planes[plane].bytesused : length;
-
-			if (b->m.planes[plane].bytesused > length)
-				return -EINVAL;
-
-			if (b->m.planes[plane].data_offset > 0 &&
-			    b->m.planes[plane].data_offset >= bytesused)
-				return -EINVAL;
-		}
-	} else {
-		length = (b->memory == VB2_MEMORY_USERPTR)
-			? b->length : vb->planes[0].length;
+	for (plane = 0; plane < vb->num_planes; ++plane) {
+		length = (b->memory == VB2_MEMORY_USERPTR ||
+			  b->memory == VB2_MEMORY_DMABUF)
+		       ? b->planes[plane].length
+			: vb->planes[plane].length;
+		bytesused = b->planes[plane].bytesused
+			  ? b->planes[plane].bytesused : length;
 
-		if (b->bytesused > length)
+		if (b->planes[plane].bytesused > length)
+			return -EINVAL;
+
+		if (b->planes[plane].data_offset > 0 &&
+		    b->planes[plane].data_offset >= bytesused)
 			return -EINVAL;
 	}
 
@@ -120,8 +106,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 
 static void __copy_timestamp(struct vb2_buffer *vb, const void *pb)
 {
-	const struct v4l2_buffer *b = pb;
-	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	const struct v4l2_ext_buffer *b = pb;
 	struct vb2_queue *q = vb->vb2_queue;
 
 	if (q->is_output) {
@@ -130,10 +115,7 @@ static void __copy_timestamp(struct vb2_buffer *vb, const void *pb)
 		 * and the timecode field and flag if needed.
 		 */
 		if (q->copy_timestamp)
-			vb->timestamp = timeval_to_ns(&b->timestamp);
-		vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE;
-		if (b->flags & V4L2_BUF_FLAG_TIMECODE)
-			vbuf->timecode = b->timecode;
+			vb->timestamp = b->timestamp;
 	}
 };
 
@@ -154,7 +136,7 @@ static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
 		pr_warn("use the actual size instead.\n");
 }
 
-static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
+static int vb2_queue_or_ext_prepare_buf(struct vb2_queue *q, struct v4l2_ext_buffer *b,
 				    const char *opname)
 {
 	if (b->type != q->type) {
@@ -187,7 +169,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
  */
 static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 {
-	struct v4l2_buffer *b = pb;
+	struct v4l2_ext_buffer *b = pb;
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct vb2_queue *q = vb->vb2_queue;
 	unsigned int plane;
@@ -196,50 +178,23 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 	b->index = vb->index;
 	b->type = vb->type;
 	b->memory = vb->memory;
-	b->bytesused = 0;
 
 	b->flags = vbuf->flags;
 	b->field = vbuf->field;
-	b->timestamp = ns_to_timeval(vb->timestamp);
-	b->timecode = vbuf->timecode;
+	b->timestamp = vb->timestamp;
 	b->sequence = vbuf->sequence;
-	b->reserved2 = 0;
-	b->reserved = 0;
+	memset(b->reserved, 0, sizeof(b->reserved));
 
-	if (q->is_multiplanar) {
-		/*
-		 * Fill in plane-related data if userspace provided an array
-		 * for it. The caller has already verified memory and size.
-		 */
-		b->length = vb->num_planes;
-		for (plane = 0; plane < vb->num_planes; ++plane) {
-			struct v4l2_plane *pdst = &b->m.planes[plane];
-			struct vb2_plane *psrc = &vb->planes[plane];
-
-			pdst->bytesused = psrc->bytesused;
-			pdst->length = psrc->length;
-			if (q->memory == VB2_MEMORY_MMAP)
-				pdst->m.mem_offset = psrc->m.offset;
-			else if (q->memory == VB2_MEMORY_USERPTR)
-				pdst->m.userptr = psrc->m.userptr;
-			else if (q->memory == VB2_MEMORY_DMABUF)
-				pdst->m.fd = psrc->m.fd;
-			pdst->data_offset = psrc->data_offset;
-			memset(pdst->reserved, 0, sizeof(pdst->reserved));
-		}
-	} else {
-		/*
-		 * We use length and offset in v4l2_planes array even for
-		 * single-planar buffers, but userspace does not.
-		 */
-		b->length = vb->planes[0].length;
-		b->bytesused = vb->planes[0].bytesused;
-		if (q->memory == VB2_MEMORY_MMAP)
-			b->m.offset = vb->planes[0].m.offset;
-		else if (q->memory == VB2_MEMORY_USERPTR)
-			b->m.userptr = vb->planes[0].m.userptr;
-		else if (q->memory == VB2_MEMORY_DMABUF)
-			b->m.fd = vb->planes[0].m.fd;
+	/*
+	 * Fill in plane-related data if userspace provided an array
+	 * for it. The caller has already verified memory and size.
+	 */
+	b->num_planes = vb->num_planes;
+	for (plane = 0; plane < vb->num_planes; ++plane) {
+		b->planes[plane].bytesused = vb->planes[plane].bytesused;
+		b->planes[plane].length = vb->planes[plane].length;
+		b->planes[plane].data_offset = vb->planes[plane].data_offset;
+		b->planes[plane].m.userptr = vb->planes[plane].m.userptr;
 	}
 
 	/*
@@ -295,7 +250,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
 		const void *pb, struct vb2_plane *planes)
 {
 	struct vb2_queue *q = vb->vb2_queue;
-	const struct v4l2_buffer *b = pb;
+	const struct v4l2_ext_buffer *b = pb;
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	unsigned int plane;
 	int ret;
@@ -321,94 +276,55 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
 	vb->timestamp = 0;
 	vbuf->sequence = 0;
 
-	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
-		if (b->memory == VB2_MEMORY_USERPTR) {
-			for (plane = 0; plane < vb->num_planes; ++plane) {
-				planes[plane].m.userptr =
-					b->m.planes[plane].m.userptr;
-				planes[plane].length =
-					b->m.planes[plane].length;
-			}
+	if (b->memory == VB2_MEMORY_USERPTR) {
+		for (plane = 0; plane < vb->num_planes; ++plane) {
+			planes[plane].m.userptr =
+				b->planes[plane].m.userptr;
+			planes[plane].length =
+				b->planes[plane].length;
 		}
-		if (b->memory == VB2_MEMORY_DMABUF) {
-			for (plane = 0; plane < vb->num_planes; ++plane) {
-				planes[plane].m.fd =
-					b->m.planes[plane].m.fd;
-				planes[plane].length =
-					b->m.planes[plane].length;
-			}
+	}
+	if (b->memory == VB2_MEMORY_DMABUF) {
+		for (plane = 0; plane < vb->num_planes; ++plane) {
+			planes[plane].m.fd =
+				b->planes[plane].m.fd;
+			planes[plane].length =
+				b->planes[plane].length;
 		}
+	}
 
-		/* Fill in driver-provided information for OUTPUT types */
-		if (V4L2_TYPE_IS_OUTPUT(b->type)) {
-			/*
-			 * Will have to go up to b->length when API starts
-			 * accepting variable number of planes.
-			 *
-			 * If bytesused == 0 for the output buffer, then fall
-			 * back to the full buffer size. In that case
-			 * userspace clearly never bothered to set it and
-			 * it's a safe assumption that they really meant to
-			 * use the full plane sizes.
-			 *
-			 * Some drivers, e.g. old codec drivers, use bytesused == 0
-			 * as a way to indicate that streaming is finished.
-			 * In that case, the driver should use the
-			 * allow_zero_bytesused flag to keep old userspace
-			 * applications working.
-			 */
-			for (plane = 0; plane < vb->num_planes; ++plane) {
-				struct vb2_plane *pdst = &planes[plane];
-				struct v4l2_plane *psrc = &b->m.planes[plane];
-
-				if (psrc->bytesused == 0)
-					vb2_warn_zero_bytesused(vb);
-
-				if (vb->vb2_queue->allow_zero_bytesused)
-					pdst->bytesused = psrc->bytesused;
-				else
-					pdst->bytesused = psrc->bytesused ?
-						psrc->bytesused : pdst->length;
-				pdst->data_offset = psrc->data_offset;
-			}
-		}
-	} else {
+	/* Fill in driver-provided information for OUTPUT types */
+	if (V4L2_TYPE_IS_OUTPUT(b->type)) {
 		/*
-		 * Single-planar buffers do not use planes array,
-		 * so fill in relevant v4l2_buffer struct fields instead.
-		 * In videobuf we use our internal V4l2_planes struct for
-		 * single-planar buffers as well, for simplicity.
+		 * Will have to go up to b->length when API starts
+		 * accepting variable number of planes.
 		 *
-		 * If bytesused == 0 for the output buffer, then fall back
-		 * to the full buffer size as that's a sensible default.
+		 * If bytesused == 0 for the output buffer, then fall
+		 * back to the full buffer size. In that case
+		 * userspace clearly never bothered to set it and
+		 * it's a safe assumption that they really meant to
+		 * use the full plane sizes.
 		 *
-		 * Some drivers, e.g. old codec drivers, use bytesused == 0 as
-		 * a way to indicate that streaming is finished. In that case,
-		 * the driver should use the allow_zero_bytesused flag to keep
-		 * old userspace applications working.
+		 * Some drivers, e.g. old codec drivers, use bytesused == 0
+		 * as a way to indicate that streaming is finished.
+		 * In that case, the driver should use the
+		 * allow_zero_bytesused flag to keep old userspace
+		 * applications working.
 		 */
-		if (b->memory == VB2_MEMORY_USERPTR) {
-			planes[0].m.userptr = b->m.userptr;
-			planes[0].length = b->length;
-		}
-
-		if (b->memory == VB2_MEMORY_DMABUF) {
-			planes[0].m.fd = b->m.fd;
-			planes[0].length = b->length;
-		}
+		for (plane = 0; plane < vb->num_planes; ++plane) {
+			struct vb2_plane *pdst = &planes[plane];
+			const struct v4l2_ext_plane *psrc = &b->planes[plane];
 
-		if (V4L2_TYPE_IS_OUTPUT(b->type)) {
-			if (b->bytesused == 0)
+			if (psrc->bytesused == 0)
 				vb2_warn_zero_bytesused(vb);
 
 			if (vb->vb2_queue->allow_zero_bytesused)
-				planes[0].bytesused = b->bytesused;
+				pdst->bytesused = psrc->bytesused;
 			else
-				planes[0].bytesused = b->bytesused ?
-					b->bytesused : planes[0].length;
-		} else
-			planes[0].bytesused = 0;
-
+				pdst->bytesused = psrc->bytesused ?
+					psrc->bytesused : pdst->length;
+			pdst->data_offset = psrc->data_offset;
+		}
 	}
 
 	/* Zero flags that the vb2 core handles */
@@ -422,14 +338,12 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
 		vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
 	}
 
+	vbuf->flags &= ~V4L2_BUF_FLAG_TIMECODE;
 	if (V4L2_TYPE_IS_OUTPUT(b->type)) {
 		/*
-		 * For output buffers mask out the timecode flag:
-		 * this will be handled later in vb2_qbuf().
 		 * The 'field' is valid metadata for this output buffer
 		 * and so that needs to be copied here.
 		 */
-		vbuf->flags &= ~V4L2_BUF_FLAG_TIMECODE;
 		vbuf->field = b->field;
 	} else {
 		/* Zero any output buffer flags as this is a capture buffer */
@@ -446,6 +360,38 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
 	.copy_timestamp		= __copy_timestamp,
 };
 
+int vb2_ext_querybuf(struct vb2_queue *q, struct v4l2_ext_buffer *b)
+{
+	struct vb2_buffer *vb;
+	int ret;
+
+	if (b->type != q->type) {
+		dprintk(1, "wrong buffer type\n");
+		return -EINVAL;
+	}
+
+	if (b->index >= q->num_buffers) {
+		dprintk(1, "buffer index out of range\n");
+		return -EINVAL;
+	}
+	vb = q->bufs[b->index];
+	ret = __verify_planes_array(vb, b);
+	if (!ret)
+		vb2_core_querybuf(q, b->index, b);
+	return ret;
+}
+EXPORT_SYMBOL(vb2_ext_querybuf);
+
+static int __buffer_to_ext_buffer(const struct v4l2_buffer *b,
+				  struct v4l2_ext_buffer *e)
+{
+	int ret = v4l2_buffer_to_ext_buffer(b, e);
+
+	if (ret)
+		dprintk(1, "multi-planar buffer passed but planes array not provided\n");
+	return ret;
+}
+
 /**
  * vb2_querybuf() - query video buffer information
  * @q:		videobuf queue
@@ -461,22 +407,14 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
  */
 int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
 {
-	struct vb2_buffer *vb;
+	struct v4l2_ext_buffer e;
 	int ret;
 
-	if (b->type != q->type) {
-		dprintk(1, "wrong buffer type\n");
-		return -EINVAL;
-	}
-
-	if (b->index >= q->num_buffers) {
-		dprintk(1, "buffer index out of range\n");
-		return -EINVAL;
-	}
-	vb = q->bufs[b->index];
-	ret = __verify_planes_array(vb, b);
+	ret = __buffer_to_ext_buffer(b, &e);
 	if (!ret)
-		vb2_core_querybuf(q, b->index, b);
+		ret = vb2_ext_querybuf(q, &e);
+	if (!ret)
+		v4l2_ext_buffer_to_buffer(&e, b);
 	return ret;
 }
 EXPORT_SYMBOL(vb2_querybuf);
@@ -489,7 +427,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
 }
 EXPORT_SYMBOL_GPL(vb2_reqbufs);
 
-int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
+int vb2_ext_prepare_buf(struct vb2_queue *q, struct v4l2_ext_buffer *b)
 {
 	int ret;
 
@@ -498,10 +436,24 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
 		return -EBUSY;
 	}
 
-	ret = vb2_queue_or_prepare_buf(q, b, "prepare_buf");
+	ret = vb2_queue_or_ext_prepare_buf(q, b, "ext_prepare_buf");
 
 	return ret ? ret : vb2_core_prepare_buf(q, b->index, b);
 }
+EXPORT_SYMBOL_GPL(vb2_ext_prepare_buf);
+
+int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+	struct v4l2_ext_buffer e;
+	int ret;
+
+	ret = __buffer_to_ext_buffer(b, &e);
+	if (!ret)
+		ret = vb2_ext_prepare_buf(q, &e);
+	if (!ret)
+		v4l2_ext_buffer_to_buffer(&e, b);
+	return ret;
+}
 EXPORT_SYMBOL_GPL(vb2_prepare_buf);
 
 int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
@@ -558,7 +510,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
 }
 EXPORT_SYMBOL_GPL(vb2_create_bufs);
 
-int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+int vb2_ext_qbuf(struct vb2_queue *q, struct v4l2_ext_buffer *b)
 {
 	int ret;
 
@@ -567,12 +519,26 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 		return -EBUSY;
 	}
 
-	ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
+	ret = vb2_queue_or_ext_prepare_buf(q, b, "qbuf");
 	return ret ? ret : vb2_core_qbuf(q, b->index, b);
 }
+EXPORT_SYMBOL_GPL(vb2_ext_qbuf);
+
+int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+	struct v4l2_ext_buffer e;
+	int ret;
+
+	ret = __buffer_to_ext_buffer(b, &e);
+	if (!ret)
+		ret = vb2_ext_qbuf(q, &e);
+	if (!ret)
+		v4l2_ext_buffer_to_buffer(&e, b);
+	return ret;
+}
 EXPORT_SYMBOL_GPL(vb2_qbuf);
 
-int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
+int vb2_ext_dqbuf(struct vb2_queue *q, struct v4l2_ext_buffer *b, bool nonblocking)
 {
 	int ret;
 
@@ -596,6 +562,20 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(vb2_ext_dqbuf);
+
+int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
+{
+	struct v4l2_ext_buffer e;
+	int ret;
+
+	ret = __buffer_to_ext_buffer(b, &e);
+	if (!ret)
+		ret = vb2_ext_dqbuf(q, &e, nonblocking);
+	if (!ret)
+		v4l2_ext_buffer_to_buffer(&e, b);
+	return ret;
+}
 EXPORT_SYMBOL_GPL(vb2_dqbuf);
 
 int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index aac8b7b6e691..b10d8655cee7 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -264,4 +264,9 @@ const struct v4l2_frmsize_discrete *v4l2_find_nearest_format(
 
 void v4l2_get_timestamp(struct timeval *tv);
 
+int v4l2_buffer_to_ext_buffer(const struct v4l2_buffer *b,
+			      struct v4l2_ext_buffer *e);
+void v4l2_ext_buffer_to_buffer(const struct v4l2_ext_buffer *e,
+			       struct v4l2_buffer *b);
+
 #endif /* V4L2_COMMON_H_ */
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index bd5312118013..4944a421074c 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -159,6 +159,14 @@ struct v4l2_fh;
  *	:ref:`VIDIOC_CREATE_BUFS <vidioc_create_bufs>` ioctl
  * @vidioc_prepare_buf: pointer to the function that implements
  *	:ref:`VIDIOC_PREPARE_BUF <vidioc_prepare_buf>` ioctl
+ * @vidioc_ext_querybuf: pointer to the function that implements
+ *	:ref:`VIDIOC_EXT_QUERYBUF <vidioc_querybuf>` ioctl
+ * @vidioc_ext_qbuf: pointer to the function that implements
+ *	:ref:`VIDIOC_EXT_QBUF <vidioc_qbuf>` ioctl
+ * @vidioc_ext_dqbuf: pointer to the function that implements
+ *	:ref:`VIDIOC_EXT_DQBUF <vidioc_qbuf>` ioctl
+ * @vidioc_ext_prepare_buf: pointer to the function that implements
+ *	:ref:`VIDIOC_EXT_PREPARE_BUF <vidioc_prepare_buf>` ioctl
  * @vidioc_overlay: pointer to the function that implements
  *	:ref:`VIDIOC_OVERLAY <vidioc_overlay>` ioctl
  * @vidioc_g_fbuf: pointer to the function that implements
@@ -419,6 +427,15 @@ struct v4l2_ioctl_ops {
 	int (*vidioc_prepare_buf)(struct file *file, void *fh,
 				  struct v4l2_buffer *b);
 
+	int (*vidioc_ext_querybuf)(struct file *file, void *fh,
+				   struct v4l2_ext_buffer *b);
+	int (*vidioc_ext_qbuf)(struct file *file, void *fh,
+			       struct v4l2_ext_buffer *b);
+	int (*vidioc_ext_dqbuf)(struct file *file, void *fh,
+				struct v4l2_ext_buffer *b);
+	int (*vidioc_ext_prepare_buf)(struct file *file, void *fh,
+				      struct v4l2_ext_buffer *b);
+
 	int (*vidioc_overlay)(struct file *file, void *fh, unsigned int i);
 	int (*vidioc_g_fbuf)(struct file *file, void *fh,
 			     struct v4l2_framebuffer *a);
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
index e157d5c9b224..bff83873aa1a 100644
--- a/include/media/v4l2-mem2mem.h
+++ b/include/media/v4l2-mem2mem.h
@@ -588,14 +588,22 @@ int v4l2_m2m_ioctl_create_bufs(struct file *file, void *fh,
 				struct v4l2_create_buffers *create);
 int v4l2_m2m_ioctl_querybuf(struct file *file, void *fh,
 				struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_ext_querybuf(struct file *file, void *fh,
+				struct v4l2_ext_buffer *buf);
 int v4l2_m2m_ioctl_expbuf(struct file *file, void *fh,
 				struct v4l2_exportbuffer *eb);
 int v4l2_m2m_ioctl_qbuf(struct file *file, void *fh,
 				struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_ext_qbuf(struct file *file, void *fh,
+				struct v4l2_ext_buffer *buf);
 int v4l2_m2m_ioctl_dqbuf(struct file *file, void *fh,
 				struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_ext_dqbuf(struct file *file, void *fh,
+				struct v4l2_ext_buffer *buf);
 int v4l2_m2m_ioctl_prepare_buf(struct file *file, void *fh,
 			       struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_ext_prepare_buf(struct file *file, void *fh,
+			       struct v4l2_ext_buffer *buf);
 int v4l2_m2m_ioctl_streamon(struct file *file, void *fh,
 				enum v4l2_buf_type type);
 int v4l2_m2m_ioctl_streamoff(struct file *file, void *fh,
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 036127c54bbf..e9ea84c65406 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -51,6 +51,7 @@ struct vb2_v4l2_buffer {
 	container_of(vb, struct vb2_v4l2_buffer, vb2_buf)
 
 int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_ext_querybuf(struct vb2_queue *q, struct v4l2_ext_buffer *b);
 
 /**
  * vb2_reqbufs() - Wrapper for vb2_core_reqbufs() that also verifies
@@ -90,6 +91,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create);
  * from vidioc_prepare_buf handler in driver.
  */
 int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_ext_prepare_buf(struct vb2_queue *q, struct v4l2_ext_buffer *b);
 
 /**
  * vb2_qbuf() - Queue a buffer from userspace
@@ -111,6 +113,7 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
  * from VIDIOC_QBUF() handler in driver.
  */
 int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
+int vb2_ext_qbuf(struct vb2_queue *q, struct v4l2_ext_buffer *b);
 
 /**
  * vb2_expbuf() - Export a buffer as a file descriptor
@@ -147,6 +150,7 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb);
  * from VIDIOC_DQBUF() handler in driver.
  */
 int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking);
+int vb2_ext_dqbuf(struct vb2_queue *q, struct v4l2_ext_buffer *b, bool nonblocking);
 
 /**
  * vb2_streamon - start streaming
@@ -245,9 +249,14 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
 			  struct v4l2_create_buffers *p);
 int vb2_ioctl_prepare_buf(struct file *file, void *priv,
 			  struct v4l2_buffer *p);
+int vb2_ioctl_ext_prepare_buf(struct file *file, void *priv,
+			  struct v4l2_ext_buffer *p);
 int vb2_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *p);
+int vb2_ioctl_ext_querybuf(struct file *file, void *priv, struct v4l2_ext_buffer *p);
 int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p);
+int vb2_ioctl_ext_qbuf(struct file *file, void *priv, struct v4l2_ext_buffer *p);
 int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p);
+int vb2_ioctl_ext_dqbuf(struct file *file, void *priv, struct v4l2_ext_buffer *p);
 int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i);
 int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i);
 int vb2_ioctl_expbuf(struct file *file, void *priv,
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 185d6a0acc06..908eeaa66c7a 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -875,6 +875,18 @@ struct v4l2_plane {
 	__u32			reserved[11];
 };
 
+struct v4l2_ext_plane {
+	__u32			bytesused;
+	__u32			length;
+	union {
+		__u32		mem_offset;
+		__u64		userptr;
+		__s32		fd;
+	} m;
+	__u32			data_offset;
+	__u32			reserved[11];
+};
+
 /**
  * struct v4l2_buffer - video buffer info
  * @index:	id number of the buffer
@@ -928,6 +940,36 @@ struct v4l2_buffer {
 	__u32			reserved;
 };
 
+/**
+ * struct v4l2_ext_buffer - video buffer info
+ * @index:	id number of the buffer
+ * @type:	enum v4l2_buf_type; buffer type (type == *_MPLANE for
+ *		multiplanar buffers);
+ * @flags:	buffer informational flags
+ * @field:	enum v4l2_field; field order of the image in the buffer
+ * @timestamp:	frame timestamp
+ * @sequence:	sequence count of this frame
+ * @memory:	enum v4l2_memory; the method, in which the actual video data is
+ *		passed
+ * @planes:	per-plane buffer information
+ * @num_planes:	number of plane buffers
+ *
+ * Contains data exchanged by application and driver using one of the Streaming
+ * I/O methods.
+ */
+struct v4l2_ext_buffer {
+	__u32			index;
+	__u32			type;
+	__u32			flags;
+	__u32			field;
+	__u64			timestamp;
+	__u32			sequence;
+	__u32			memory;
+	struct v4l2_ext_plane	planes[VIDEO_MAX_PLANES];
+	__u32			num_planes;
+	__u32			reserved[11];
+};
+
 /*  Flags for 'flags' field */
 /* Buffer is mapped (flag) */
 #define V4L2_BUF_FLAG_MAPPED			0x00000001
@@ -2397,6 +2439,11 @@ struct v4l2_create_buffers {
 
 #define VIDIOC_QUERY_EXT_CTRL	_IOWR('V', 103, struct v4l2_query_ext_ctrl)
 
+#define VIDIOC_EXT_QUERYBUF	_IOWR('V', 104, struct v4l2_ext_buffer)
+#define VIDIOC_EXT_QBUF		_IOWR('V', 105, struct v4l2_ext_buffer)
+#define VIDIOC_EXT_DQBUF	_IOWR('V', 106, struct v4l2_ext_buffer)
+#define VIDIOC_EXT_PREPARE_BUF	_IOWR('V', 107, struct v4l2_ext_buffer)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */
 
-- 
2.14.2




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux