@@ -662,6 +662,10 @@ static void determine_valid_ioctls(struct video_device *vdev)
__set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
+ SET_VALID_IOCTL(ops, VIDIOC_EXT_QBUF, vidioc_ext_qbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_EXT_QBUF, vidioc_qbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_EXT_DQBUF, vidioc_ext_dqbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_EXT_DQBUF, vidioc_dqbuf);
}
if (is_meta && is_rx) {
/* metadata capture specific ioctls */
@@ -502,6 +502,24 @@ 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 *e = arg;
+ unsigned int i;
+
+ pr_cont("%lld index=%d, type=%s, request_fd=%d, flags=0x%08llx, field=%s, sequence=%d, memory=%s\n",
+ e->timestamp, e->index, prt_names(e->type, v4l2_type_names),
+ e->request_fd, e->flags, prt_names(e->field, v4l2_field_names),
+ e->sequence, prt_names(e->memory, v4l2_memory_names));
+
+ for (i = 0; i < VIDEO_MAX_PLANES && e->planes[i].m.userptr; i++) {
+ const struct v4l2_ext_plane *plane = &e->planes[i];
+
+ pr_cont("plane %d: bytesused=%d, offset=0x%08x, userptr=0x%llx\n",
+ i, plane->bytesused, plane->offset, plane->m.userptr);
+ }
+}
+
static void v4l_print_exportbuffer(const void *arg, bool write_only)
{
const struct v4l2_exportbuffer *p = arg;
@@ -2456,6 +2474,130 @@ static int v4l_qbuf(const struct v4l2_ioctl_ops *ops,
return ret ? ret : ops->vidioc_qbuf(file, fh, p);
}
+static bool v4l2_ext_buffer_is_single_membuf(const struct v4l2_ext_buffer *eb)
+{
+ unsigned int i;
+
+ for (i = 1; i < VIDEO_MAX_PLANES && eb->planes[i].m.userptr; i++)
+ if (eb->planes[i].m.userptr != eb->planes[i - 1].m.userptr)
+ return false;
+ return true;
+}
+
+static int v4l2_fill_buffer_from_ext_buffer(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh,
+ const struct v4l2_ext_buffer *eb,
+ struct v4l2_buffer *b,
+ struct v4l2_plane *bplanes)
+{
+ const struct v4l2_ext_plane *eplanes = (struct v4l2_ext_plane *)&eb->planes;
+ struct video_device *vfd = video_devdata(file);
+ bool is_mplane = V4L2_IS_CAP_MULTIPLANAR(vfd);
+ unsigned int i;
+ u64 nsecs;
+ int ret;
+
+ b->index = eb->index;
+ if (is_mplane) {
+ b->m.planes = bplanes;
+ b->length = VIDEO_MAX_PLANES;
+ if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ b->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ else if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ b->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ } else {
+ b->type = eb->type;
+ }
+
+ /* Fill the rest of the v4l2_buffer */
+ ret = v4l_querybuf(ops, file, fh, b);
+ if (ret)
+ return ret;
+
+ /* Fill other fields from v4l2_ext_buffer */
+ b->flags = eb->flags;
+ b->field = eb->field;
+ b->timestamp.tv_sec = div64_u64_rem(eb->timestamp, NSEC_PER_SEC, &nsecs);
+ b->timestamp.tv_usec = (u32)nsecs / NSEC_PER_USEC;
+ b->sequence = eb->sequence;
+
+ if (!is_mplane) {
+ for (i = 0; i < VIDEO_MAX_PLANES; i++) {
+ b->bytesused += eplanes[i].bytesused;
+ WARN_ON(eplanes[i].offset);
+ }
+
+ /* MMAP info was filled by querybuf */
+ if (b->memory == V4L2_MEMORY_MMAP)
+ return 0 ;
+
+ /*
+ * TODO: get the length of the buffer, for now, just
+ * set to max to avoid errors in checks.
+ */
+ b->length = U32_MAX;
+ b->m.userptr = eplanes[0].m.userptr;
+ return 0;
+ }
+
+ bplanes[0].bytesused = eplanes[0].bytesused + eplanes[0].offset;
+ bplanes[0].data_offset = eplanes[0].offset;
+ if (v4l2_ext_buffer_is_single_membuf(eb))
+ for (i = 1; i < VIDEO_MAX_PLANES && eplanes[i].bytesused; i++) {
+ bplanes[0].bytesused += eplanes[i].bytesused;
+ WARN_ON(eplanes[i].offset);
+ }
+ else
+ for (i = 1; i < VIDEO_MAX_PLANES && eplanes[i].bytesused; i++) {
+ bplanes[i].bytesused = eplanes[i].bytesused +
+ eplanes[i].offset;
+ bplanes[i].data_offset = eplanes[i].offset;
+ }
+
+ /* MMAP info was filled by querybuf */
+ if (b->memory == V4L2_MEMORY_MMAP)
+ return 0;
+
+ for (i = 0; i < VIDEO_MAX_PLANES && eplanes[i].m.userptr; i++) {
+ bplanes[i].m.userptr = eplanes[i].m.userptr;
+ /*
+ * TODO: get the length of the buffer, for now, just
+ * set to max to avoid errors in checks.
+ */
+ bplanes[i].length = U32_MAX;
+ }
+ return 0;
+}
+
+static int v4l_ext_qbuf(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ struct v4l2_plane planes[VIDEO_MAX_PLANES] = {0};
+ struct v4l2_ext_buffer *eb = arg;
+ struct v4l2_buffer b = {0};
+
+ int ret = check_fmt(file, eb->type);
+
+ if (!ret)
+ return ret;
+
+ if (ops->vidioc_ext_qbuf)
+ return ops->vidioc_ext_qbuf(file, fh, eb);
+
+ /* Fill other fields from v4l2_ext_buffer */
+ ret = v4l2_fill_buffer_from_ext_buffer(ops, file, fh, eb, &b, planes);
+ if (ret)
+ return ret;
+
+ ret = v4l_qbuf(ops, file, fh, &b);
+ if (ret)
+ return ret;
+
+ /* TODO: check if we need to fill other fields */
+ eb->flags = b.flags;
+ return 0;
+}
+
static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
@@ -2465,6 +2607,46 @@ static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops,
return ret ? ret : ops->vidioc_dqbuf(file, fh, p);
}
+static int v4l_ext_dqbuf(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ struct v4l2_plane planes[VIDEO_MAX_PLANES] = {0};
+ struct v4l2_ext_buffer *eb = arg;
+ struct v4l2_buffer b = {0};
+ unsigned int i;
+
+ int ret = check_fmt(file, eb->type);
+
+ if (!ret)
+ return ret;
+
+ if (ops->vidioc_ext_qbuf)
+ return ops->vidioc_ext_qbuf(file, fh, eb);
+
+ /* Fill other fields from v4l2_ext_buffer */
+ ret = v4l2_fill_buffer_from_ext_buffer(ops, file, fh, eb, &b, planes);
+ if (ret)
+ return ret;
+
+ ret = v4l_qbuf(ops, file, fh, &b);
+ if (ret)
+ return ret;
+
+ /* TODO: check if we need to fill other fields */
+ eb->flags = b.flags;
+
+ /*
+ * Set buffer pointers to zero. Usecase: DMA-fd might have being
+ * alread closed, so just request userspace to fill it again in queue
+ * time.
+ */
+ for (i = 0; i < VIDEO_MAX_PLANES && eb->planes[i].m.userptr; i++) {
+ eb->planes[i].m.userptr = 0;
+ }
+
+ return 0;
+}
+
static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
@@ -3249,6 +3431,8 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO(VIDIOC_G_EXT_PIX_FMT, v4l_g_ext_pix_fmt, v4l_print_ext_pix_format, 0),
IOCTL_INFO(VIDIOC_S_EXT_PIX_FMT, v4l_s_ext_pix_fmt, v4l_print_ext_pix_format, INFO_FL_PRIO),
IOCTL_INFO(VIDIOC_TRY_EXT_PIX_FMT, v4l_try_ext_pix_fmt, v4l_print_ext_pix_format, 0),
+ IOCTL_INFO(VIDIOC_EXT_QBUF, v4l_ext_qbuf, v4l_print_ext_buffer, INFO_FL_QUEUE),
+ IOCTL_INFO(VIDIOC_EXT_DQBUF, v4l_ext_dqbuf, v4l_print_ext_buffer, INFO_FL_QUEUE),
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -171,10 +171,14 @@ struct v4l2_fh;
* :ref:`VIDIOC_QUERYBUF <vidioc_querybuf>` ioctl
* @vidioc_qbuf: pointer to the function that implements
* :ref:`VIDIOC_QBUF <vidioc_qbuf>` ioctl
+ * @vidioc_ext_qbuf: pointer to the function that implements
+ * :ref:`VIDIOC_EXT_QBUF <vidioc_ext_qbuf>` ioctl
* @vidioc_expbuf: pointer to the function that implements
* :ref:`VIDIOC_EXPBUF <vidioc_expbuf>` ioctl
* @vidioc_dqbuf: pointer to the function that implements
* :ref:`VIDIOC_DQBUF <vidioc_qbuf>` ioctl
+ * @vidioc_ext_dqbuf: pointer to the function that implements
+ * :ref:`VIDIOC_EXT_DQBUF <vidioc_ext_qbuf>` ioctl
* @vidioc_create_bufs: pointer to the function that implements
* :ref:`VIDIOC_CREATE_BUFS <vidioc_create_bufs>` ioctl
* @vidioc_prepare_buf: pointer to the function that implements
@@ -441,10 +445,14 @@ struct v4l2_ioctl_ops {
struct v4l2_buffer *b);
int (*vidioc_qbuf)(struct file *file, void *fh,
struct v4l2_buffer *b);
+ int (*vidioc_ext_qbuf)(struct file *file, void *fh,
+ struct v4l2_ext_buffer *b);
int (*vidioc_expbuf)(struct file *file, void *fh,
struct v4l2_exportbuffer *e);
int (*vidioc_dqbuf)(struct file *file, void *fh,
struct v4l2_buffer *b);
+ int (*vidioc_ext_dqbuf)(struct file *file, void *fh,
+ struct v4l2_ext_buffer *b);
int (*vidioc_create_bufs)(struct file *file, void *fh,
struct v4l2_create_buffers *b);
@@ -1120,6 +1120,59 @@ struct v4l2_buffer {
};
};
+/**
+ * struct v4l2_ext_plane - extended plane buffer info
+ * @offset: offset in the memory buffer where the plane starts.
+ * @bytesused: number of bytes occupied by data in the plane (payload).
+ * @mmap_offset: If V4L2_MEMORY_MMAP is used, then it can be a "cookie"
+ * that should be passed to mmap() called on the video node.
+ * @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer pointing
+ * to this plane.
+ * @dmabuf_fd: when memory is V4L2_MEMORY_DMABUF, a userspace file descriptor
+ * associated with this plane.
+ * @reserved: extra space reserved for future fields, must be set to 0.
+ */
+struct v4l2_ext_plane {
+ __u32 offset;
+ __u32 bytesused;
+ union {
+ __u32 mmap_offset;
+ __u64 userptr;
+ __s32 dmabuf_fd;
+ } m;
+ __u32 reserved[6];
+};
+
+/**
+ * struct v4l2_ext_buffer - extended video buffer info
+ * @index: id number of the buffer
+ * @type: V4L2_BUF_TYPE_VIDEO_CAPTURE or V4L2_BUF_TYPE_VIDEO_OUTPUT
+ * @field: enum v4l2_field; field order of the image in the buffer
+ * @sequence: sequence count of this frame
+ * @flags: buffer informational flags
+ * @timestamp: frame timestamp
+ * @memory: enum v4l2_memory; the method, in which the actual video
+ * data is passed
+ * @request_fd: fd of the request that this buffer should use
+ * @planes: per-plane buffer information
+ * @reserved: extra space reserved for future fields, must be set to 0
+ *
+ * Contains data exchanged by application and driver using one of the Streaming
+ * I/O methods.
+ */
+struct v4l2_ext_buffer {
+ __u32 index;
+ __u32 type;
+ __u32 field;
+ __u32 sequence;
+ __u64 flags;
+ __u64 timestamp;
+ __u32 memory;
+ __s32 request_fd;
+ struct v4l2_ext_plane planes[VIDEO_MAX_PLANES];
+ __u32 reserved[10];
+};
+
#ifndef __KERNEL__
/**
* v4l2_timeval_to_ns - Convert timeval to nanoseconds
@@ -2733,6 +2786,8 @@ struct v4l2_create_buffers {
#define VIDIOC_G_EXT_PIX_FMT _IOWR('V', 104, struct v4l2_ext_pix_format)
#define VIDIOC_S_EXT_PIX_FMT _IOWR('V', 105, struct v4l2_ext_pix_format)
#define VIDIOC_TRY_EXT_PIX_FMT _IOWR('V', 106, struct v4l2_ext_pix_format)
+#define VIDIOC_EXT_QBUF _IOWR('V', 107, struct v4l2_ext_buffer)
+#define VIDIOC_EXT_DQBUF _IOWR('V', 118, 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! */