@@ -700,12 +700,30 @@ static void determine_valid_ioctls(struct video_device *vdev)
if (is_vid || is_vbi || is_sdr || is_tch) {
/* ioctls valid for video, metadata, vbi or sdr */
SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
- SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
- SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
- SET_VALID_IOCTL(ops, VIDIOC_EXPBUF, vidioc_expbuf);
- SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf);
- SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs);
- SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
+ if (ops->vidioc_querybuf || ops->vidioc_ext_querybuf) {
+ set_bit(_IOC_NR(VIDIOC_QUERYBUF), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_EXT_QUERYBUF), valid_ioctls);
+ }
+ if (ops->vidioc_qbuf || ops->vidioc_ext_qbuf) {
+ set_bit(_IOC_NR(VIDIOC_QBUF), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_EXT_QBUF), valid_ioctls);
+ }
+ if (ops->vidioc_expbuf || ops->vidioc_ext_expbuf) {
+ set_bit(_IOC_NR(VIDIOC_EXPBUF), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_EXT_EXPBUF), valid_ioctls);
+ }
+ if (ops->vidioc_dqbuf || ops->vidioc_ext_dqbuf) {
+ set_bit(_IOC_NR(VIDIOC_DQBUF), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_EXT_DQBUF), valid_ioctls);
+ }
+ if (ops->vidioc_create_bufs || ops->vidioc_ext_create_bufs) {
+ set_bit(_IOC_NR(VIDIOC_CREATE_BUFS), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_EXT_CREATE_BUFS), valid_ioctls);
+ }
+ if (ops->vidioc_prepare_buf || ops->vidioc_ext_prepare_buf) {
+ set_bit(_IOC_NR(VIDIOC_PREPARE_BUF), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_EXT_PREPARE_BUF), valid_ioctls);
+ }
SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
}
@@ -583,6 +583,25 @@ 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];
+ pr_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;
@@ -592,6 +611,18 @@ static void v4l_print_exportbuffer(const void *arg, bool write_only)
p->index, p->plane, p->flags);
}
+static void v4l_print_ext_exportbuffer(const void *arg, bool write_only)
+{
+ const struct v4l2_ext_exportbuffer *p = arg;
+ unsigned int i;
+
+ pr_cont("type=%s, index=%u, first_plane=%u num_planes=%u, flags=%08x\n",
+ prt_names(p->type, v4l2_type_names), p->index, p->first_plane,
+ p->num_planes, p->flags);
+ for (i = p->first_plane; i < p->first_plane + p->num_planes; ++i)
+ pr_debug("plane %u: fd=%d\n", i, p->fds[i]);
+}
+
static void v4l_print_create_buffers(const void *arg, bool write_only)
{
const struct v4l2_create_buffers *p = arg;
@@ -602,6 +633,15 @@ static void v4l_print_create_buffers(const void *arg, bool write_only)
v4l_print_format(&p->format, write_only);
}
+static void v4l_print_ext_create_buffers(const void *arg, bool write_only)
+{
+ const struct v4l2_ext_create_buffers *p = arg;
+
+ pr_cont("index=%d, count=%d, memory=%s, ", p->index, p->count,
+ prt_names(p->memory, v4l2_memory_names));
+ v4l_print_ext_format(&p->format, write_only);
+}
+
static void v4l_print_streamparm(const void *arg, bool write_only)
{
const struct v4l2_streamparm *p = arg;
@@ -1323,6 +1363,123 @@ int v4l2_format_to_ext_format(const struct v4l2_format *f,
}
EXPORT_SYMBOL_GPL(v4l2_format_to_ext_format);
+int v4l2_ext_buffer_to_buffer(const struct v4l2_ext_buffer *e,
+ struct v4l2_buffer *b, bool mplane_cap)
+{
+ u64 nsecs;
+
+ if (!mplane_cap && e->num_planes > 1)
+ return -EINVAL;
+
+ memset(b, 0, sizeof(*b));
+
+ b->index = e->index;
+ b->flags = e->flags;
+ b->field = e->field;
+ b->sequence = e->sequence;
+ b->memory = e->memory;
+ b->request_fd = e->request_fd;
+ b->timestamp.tv_sec = div64_u64_rem(e->timestamp, NSEC_PER_SEC, &nsecs);
+ b->timestamp.tv_usec = (u32)nsecs / NSEC_PER_USEC;
+ if (mplane_cap) {
+ unsigned int i;
+
+ if (e->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ b->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ else
+ b->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+ b->length = e->num_planes;
+ for (i = 0; i < e->num_planes; i++) {
+ if (b->memory == V4L2_MEMORY_DMABUF) {
+ if (e->planes[i].m.dmabuf.offset)
+ return -EINVAL;
+
+ b->m.planes[i].m.fd = e->planes[i].m.dmabuf.fd;
+ } else {
+ b->m.planes[i].m.userptr = e->planes[i].m.userptr;
+ }
+ b->m.planes[i].length = e->planes[i].length;
+ b->m.planes[i].bytesused = e->planes[i].bytesused;
+ 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->type = e->type;
+ b->bytesused = e->planes[0].bytesused;
+ b->length = e->planes[0].length;
+ if (b->memory == V4L2_MEMORY_DMABUF) {
+ if (e->planes[0].m.dmabuf.offset)
+ return -EINVAL;
+
+ b->m.fd = e->planes[0].m.dmabuf.fd;
+ } else {
+ b->m.userptr = e->planes[0].m.userptr;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_ext_buffer_to_buffer);
+
+int v4l2_buffer_to_ext_buffer(const struct v4l2_buffer *b,
+ struct v4l2_ext_buffer *e)
+{
+ memset(e, 0, sizeof(*e));
+
+ e->index = b->index;
+ e->flags = b->flags;
+ e->field = b->field;
+ e->sequence = b->sequence;
+ e->memory = b->memory;
+ e->request_fd = b->request_fd;
+ 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)
+ return -EINVAL;
+
+ if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ e->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ else
+ e->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+ e->num_planes = b->length;
+ for (i = 0; i < e->num_planes; i++) {
+ if (b->memory == V4L2_MEMORY_DMABUF) {
+ e->planes[i].m.dmabuf.fd = b->m.planes[i].m.fd;
+ e->planes[i].m.dmabuf.offset = 0;
+ } else {
+ e->planes[i].m.userptr = b->m.planes[i].m.userptr;
+ }
+ e->planes[i].length = b->m.planes[i].length;
+ e->planes[i].bytesused = b->m.planes[i].bytesused;
+ e->planes[i].data_offset = b->m.planes[i].data_offset;
+ memset(e->planes[i].reserved, 0,
+ sizeof(e->planes[i].reserved));
+ }
+ } else {
+ e->type = b->type;
+ e->num_planes = 1;
+ e->planes[0].bytesused = b->bytesused;
+ e->planes[0].length = b->length;
+ if (b->memory == V4L2_MEMORY_DMABUF) {
+ e->planes[0].m.dmabuf.fd = b->m.fd;
+ e->planes[0].m.dmabuf.offset = 0;
+ } else {
+ e->planes[0].m.userptr = b->m.userptr;
+ }
+ e->planes[0].m.userptr = b->m.userptr;
+ e->planes[0].data_offset = 0;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_buffer_to_ext_buffer);
+
static int v4l_querycap(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
@@ -2474,31 +2631,109 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops,
return ops->vidioc_reqbufs(file, fh, p);
}
-static int v4l_querybuf(const struct v4l2_ioctl_ops *ops,
- struct file *file, void *fh, void *arg)
+static int v4l_do_buf_op(int (*op)(struct file *, void *,
+ struct v4l2_buffer *),
+ int (*ext_op)(struct file *, void *,
+ struct v4l2_ext_buffer *),
+ struct file *file, void *fh, struct v4l2_buffer *b)
{
- struct v4l2_buffer *p = arg;
- int ret = check_fmt(file, p->type);
+ struct v4l2_ext_buffer eb;
+ int ret;
- return ret ? ret : ops->vidioc_querybuf(file, fh, p);
+ ret = check_fmt(file, b->type);
+ if (ret)
+ return ret;
+
+ if (op)
+ return op(file, fh, b);
+
+ ret = v4l2_buffer_to_ext_buffer(b, &eb);
+ if (ret)
+ return ret;
+
+ ret = ext_op(file, fh, &eb);
+ if (ret)
+ return ret;
+
+ v4l2_ext_buffer_to_buffer(&eb, b, V4L2_TYPE_IS_MULTIPLANAR(b->type));
+ return 0;
+}
+
+static int v4l_do_ext_buf_op(int (*op)(struct file *, void *,
+ struct v4l2_buffer *),
+ int (*ext_op)(struct file *, void *,
+ struct v4l2_ext_buffer *),
+ struct file *file, void *fh,
+ struct v4l2_ext_buffer *eb)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_buffer b;
+ bool mplane_cap;
+ int ret;
+
+ ret = check_fmt(file, eb->type);
+ if (ret)
+ return ret;
+
+ if (ext_op)
+ return ext_op(file, fh, eb);
+
+ mplane_cap = !!(vdev->device_caps &
+ (V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_VIDEO_M2M_MPLANE));
+ ret = v4l2_ext_buffer_to_buffer(eb, &b, mplane_cap);
+ if (ret)
+ return ret;
+
+ ret = op(file, fh, &b);
+ if (ret)
+ return ret;
+
+ v4l2_buffer_to_ext_buffer(&b, eb);
+ return 0;
+}
+
+static int v4l_querybuf(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ return v4l_do_buf_op(ops->vidioc_querybuf, ops->vidioc_ext_querybuf,
+ file, fh, arg);
+}
+
+static int v4l_ext_querybuf(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ return v4l_do_ext_buf_op(ops->vidioc_querybuf,
+ ops->vidioc_ext_querybuf, file, fh, arg);
}
static int v4l_qbuf(const struct v4l2_ioctl_ops *ops,
- struct file *file, void *fh, void *arg)
+ struct file *file, void *fh, void *arg)
{
- struct v4l2_buffer *p = arg;
- int ret = check_fmt(file, p->type);
+ return v4l_do_buf_op(ops->vidioc_qbuf, ops->vidioc_ext_qbuf,
+ file, fh, arg);
+}
- return ret ? ret : ops->vidioc_qbuf(file, fh, p);
+static int v4l_ext_qbuf(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ return v4l_do_ext_buf_op(ops->vidioc_qbuf, ops->vidioc_ext_qbuf,
+ file, fh, arg);
}
static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops,
- struct file *file, void *fh, void *arg)
+ struct file *file, void *fh, void *arg)
{
- struct v4l2_buffer *p = arg;
- int ret = check_fmt(file, p->type);
+ return v4l_do_buf_op(ops->vidioc_dqbuf, ops->vidioc_ext_dqbuf,
+ file, fh, arg);
+}
- 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)
+{
+ return v4l_do_ext_buf_op(ops->vidioc_dqbuf, ops->vidioc_ext_dqbuf,
+ file, fh, arg);
}
static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
@@ -2514,7 +2749,27 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
v4l_sanitize_format(&create->format);
- ret = ops->vidioc_create_bufs(file, fh, create);
+ if (ops->vidioc_create_bufs) {
+ ret = ops->vidioc_create_bufs(file, fh, create);
+ } else {
+ struct v4l2_ext_create_buffers ecreate = {
+ .count = create->count,
+ .memory = create->memory,
+ };
+
+ ret = v4l2_format_to_ext_format(&create->format,
+ &ecreate.format, true);
+ if (ret)
+ return ret;
+
+ ret = ops->vidioc_ext_create_bufs(file, fh, &ecreate);
+ if (ret)
+ return ret;
+
+ create->index = ecreate.index;
+ create->count = ecreate.count;
+ create->capabilities = ecreate.capabilities;
+ }
if (create->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
create->format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
@@ -2523,13 +2778,59 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
return ret;
}
-static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops,
- struct file *file, void *fh, void *arg)
+static int v4l_ext_create_bufs(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
{
- struct v4l2_buffer *b = arg;
- int ret = check_fmt(file, b->type);
+ struct v4l2_ext_create_buffers *ecreate = arg;
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_create_buffers create = {
+ .count = ecreate->count,
+ .memory = ecreate->memory,
+ };
+ bool mplane_cap;
+ int ret;
- return ret ? ret : ops->vidioc_prepare_buf(file, fh, b);
+ ret = check_fmt(file, ecreate->format.type);
+ if (ret)
+ return ret;
+
+ if (ops->vidioc_ext_create_bufs)
+ return ops->vidioc_ext_create_bufs(file, fh, ecreate);
+
+ mplane_cap = !!(vdev->device_caps &
+ (V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_VIDEO_M2M_MPLANE));
+ ret = v4l2_ext_format_to_format(&ecreate->format,
+ &create.format, mplane_cap, true);
+ if (ret)
+ return ret;
+
+ ret = v4l_create_bufs(ops, file, fh, &create);
+ if (ret)
+ return ret;
+
+ ecreate->index = create.index;
+ ecreate->count = create.count;
+ ecreate->capabilities = create.capabilities;
+
+ return 0;
+}
+
+static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ return v4l_do_buf_op(ops->vidioc_prepare_buf,
+ ops->vidioc_ext_prepare_buf,
+ file, fh, arg);
+}
+
+static int v4l_ext_prepare_buf(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ return v4l_do_ext_buf_op(ops->vidioc_prepare_buf,
+ ops->vidioc_ext_prepare_buf,
+ file, fh, arg);
}
static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
@@ -3121,6 +3422,86 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
return -ENOTTY;
}
+static int v4l_expbuf(const struct v4l2_ioctl_ops *ops, struct file *file,
+ void *fh, void *arg)
+{
+ struct v4l2_exportbuffer *b = arg;
+ struct v4l2_ext_exportbuffer eb = {
+ .type = b->type,
+ .index = b->index,
+ .first_plane = b->plane,
+ .num_planes = 1,
+ .flags = b->flags,
+ };
+ int ret;
+
+ if (ops->vidioc_expbuf)
+ return ops->vidioc_expbuf(file, fh, b);
+
+ if (b->plane >= VIDEO_MAX_PLANES)
+ return -EINVAL;
+
+ ret = ops->vidioc_ext_expbuf(file, fh, &eb);
+ if (ret)
+ return ret;
+
+ b->fd = eb.fds[b->plane];
+ return 0;
+}
+
+static int v4l_ext_expbuf(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ struct v4l2_ext_exportbuffer *eb = arg;
+ unsigned int i;
+ int ret;
+
+ if (eb->first_plane >= VIDEO_MAX_PLANES ||
+ eb->num_planes > VIDEO_MAX_PLANES ||
+ eb->first_plane + eb->num_planes > VIDEO_MAX_PLANES)
+ return -EINVAL;
+
+ if (ops->vidioc_ext_expbuf)
+ return ops->vidioc_ext_expbuf(file, fh, eb);
+
+ for (i = eb->first_plane; i < eb->first_plane + eb->num_planes; i++) {
+ struct v4l2_exportbuffer b = {
+ .type = eb->type,
+ .index = eb->index,
+ .plane = i,
+ .flags = eb->flags,
+ };
+
+ ret = ops->vidioc_expbuf(file, fh, &b);
+ if (ret)
+ goto err_put_dmabufs;
+
+ eb->fds[i] = b.fd;
+ }
+
+ return 0;
+
+err_put_dmabufs:
+ for (i = eb->first_plane; i < eb->first_plane + eb->num_planes; i++) {
+ struct dma_buf *dmabuf;
+
+ if (eb->fds[i] <= 0)
+ break;
+
+ /*
+ * We must call dma_buf_put() twice because we got one
+ * reference taken at dmabuf creation time one taken when
+ * calling dma_buf_get().
+ * FIXME: not entirely sure this works correctly.
+ */
+ dmabuf = dma_buf_get(eb->fds[i]);
+ dma_buf_put(dmabuf);
+ dma_buf_put(dmabuf);
+ }
+
+ return ret;
+}
+
struct v4l2_ioctl_info {
unsigned int ioctl;
u32 flags;
@@ -3163,7 +3544,6 @@ struct v4l2_ioctl_info {
DEFINE_V4L_STUB_FUNC(g_fbuf)
DEFINE_V4L_STUB_FUNC(s_fbuf)
-DEFINE_V4L_STUB_FUNC(expbuf)
DEFINE_V4L_STUB_FUNC(g_std)
DEFINE_V4L_STUB_FUNC(g_audio)
DEFINE_V4L_STUB_FUNC(s_audio)
@@ -3199,12 +3579,16 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO(VIDIOC_S_EXT_FMT, v4l_s_ext_fmt, v4l_print_ext_format, INFO_FL_PRIO),
IOCTL_INFO(VIDIOC_REQBUFS, v4l_reqbufs, v4l_print_requestbuffers, INFO_FL_PRIO | INFO_FL_QUEUE),
IOCTL_INFO(VIDIOC_QUERYBUF, v4l_querybuf, v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)),
+ IOCTL_INFO(VIDIOC_EXT_QUERYBUF, v4l_ext_querybuf, v4l_print_ext_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_ext_buffer, num_planes)),
IOCTL_INFO(VIDIOC_G_FBUF, v4l_stub_g_fbuf, v4l_print_framebuffer, 0),
IOCTL_INFO(VIDIOC_S_FBUF, v4l_stub_s_fbuf, v4l_print_framebuffer, INFO_FL_PRIO),
IOCTL_INFO(VIDIOC_OVERLAY, v4l_overlay, v4l_print_u32, INFO_FL_PRIO),
IOCTL_INFO(VIDIOC_QBUF, v4l_qbuf, v4l_print_buffer, INFO_FL_QUEUE),
- IOCTL_INFO(VIDIOC_EXPBUF, v4l_stub_expbuf, v4l_print_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)),
+ IOCTL_INFO(VIDIOC_EXT_QBUF, v4l_ext_qbuf, v4l_print_ext_buffer, INFO_FL_QUEUE),
+ IOCTL_INFO(VIDIOC_EXPBUF, v4l_expbuf, v4l_print_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)),
+ IOCTL_INFO(VIDIOC_EXT_EXPBUF, v4l_ext_expbuf, v4l_print_ext_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)),
IOCTL_INFO(VIDIOC_DQBUF, v4l_dqbuf, v4l_print_buffer, INFO_FL_QUEUE),
+ IOCTL_INFO(VIDIOC_EXT_DQBUF, v4l_ext_dqbuf, v4l_print_ext_buffer, INFO_FL_QUEUE),
IOCTL_INFO(VIDIOC_STREAMON, v4l_streamon, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE),
IOCTL_INFO(VIDIOC_STREAMOFF, v4l_streamoff, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE),
IOCTL_INFO(VIDIOC_G_PARM, v4l_g_parm, v4l_print_streamparm, INFO_FL_CLEAR(v4l2_streamparm, type)),
@@ -3269,7 +3653,9 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO(VIDIOC_SUBSCRIBE_EVENT, v4l_subscribe_event, v4l_print_event_subscription, 0),
IOCTL_INFO(VIDIOC_UNSUBSCRIBE_EVENT, v4l_unsubscribe_event, v4l_print_event_subscription, 0),
IOCTL_INFO(VIDIOC_CREATE_BUFS, v4l_create_bufs, v4l_print_create_buffers, INFO_FL_PRIO | INFO_FL_QUEUE),
+ IOCTL_INFO(VIDIOC_EXT_CREATE_BUFS, v4l_ext_create_bufs, v4l_print_ext_create_buffers, INFO_FL_PRIO | INFO_FL_QUEUE),
IOCTL_INFO(VIDIOC_PREPARE_BUF, v4l_prepare_buf, v4l_print_buffer, INFO_FL_QUEUE),
+ IOCTL_INFO(VIDIOC_EXT_PREPARE_BUF, v4l_ext_prepare_buf, v4l_print_ext_buffer, INFO_FL_QUEUE),
IOCTL_INFO(VIDIOC_ENUM_DV_TIMINGS, v4l_stub_enum_dv_timings, v4l_print_enum_dv_timings, INFO_FL_CLEAR(v4l2_enum_dv_timings, pad)),
IOCTL_INFO(VIDIOC_QUERY_DV_TIMINGS, v4l_stub_query_dv_timings, v4l_print_dv_timings, INFO_FL_ALWAYS_COPY),
IOCTL_INFO(VIDIOC_DV_TIMINGS_CAP, v4l_stub_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, pad)),
@@ -168,16 +168,28 @@ struct v4l2_fh;
* :ref:`VIDIOC_REQBUFS <vidioc_reqbufs>` ioctl
* @vidioc_querybuf: pointer to the function that implements
* :ref:`VIDIOC_QUERYBUF <vidioc_querybuf>` ioctl
+ * @vidioc_ext_querybuf: pointer to the function that implements
+ * :ref:`VIDIOC_EXT_QUERYBUF <vidioc_ext_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_ext_expbuf: pointer to the function that implements
+ * :ref:`VIDIOC_EXT_EXPBUF <vidioc_ext_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_ext_create_bufs: pointer to the function that implements
+ * :ref:`VIDIOC_EXT_CREATE_BUFS <vidioc_ext_create_bufs>` ioctl
* @vidioc_prepare_buf: pointer to the function that implements
* :ref:`VIDIOC_PREPARE_BUF <vidioc_prepare_buf>` ioctl
+ * @vidioc_ext_prepare_buf: pointer to the function that implements
+ * :ref:`VIDIOC_EXT_PREPARE_BUF <vidioc_ext_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
@@ -438,17 +450,29 @@ struct v4l2_ioctl_ops {
struct v4l2_requestbuffers *b);
int (*vidioc_querybuf)(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_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_ext_expbuf)(struct file *file, void *fh,
+ struct v4l2_ext_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);
+ int (*vidioc_ext_create_bufs)(struct file *file, void *fh,
+ struct v4l2_ext_create_buffers *b);
int (*vidioc_prepare_buf)(struct file *file, void *fh,
struct v4l2_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,
@@ -755,4 +779,10 @@ int v4l2_ext_format_to_format(const struct v4l2_ext_format *e,
struct v4l2_format *f,
bool mplane_cap, bool strict);
+int v4l2_ext_buffer_to_buffer(const struct v4l2_ext_buffer *e,
+ struct v4l2_buffer *b,
+ bool mplane_cap);
+int v4l2_buffer_to_ext_buffer(const struct v4l2_buffer *b,
+ struct v4l2_ext_buffer *e);
+
#endif /* _V4L2_IOCTL_H */
@@ -928,6 +928,49 @@ struct v4l2_plane {
__u32 reserved[11];
};
+/**
+ * struct v4l2_ext_plane - extended plane buffer info
+ * @bytesused: number of bytes occupied by data in the plane (payload)
+ * @length: size of this plane (NOT the payload) in bytes
+ * @mem_offset: when memory in the associated struct v4l2_ext_buffer is
+ * V4L2_MEMORY_MMAP, equals the offset from the start of the
+ * device memory for this plane (or is 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
+ * @dmabuf.offset: where the plane starts inside the DMABUF buffer. All planes
+ * might share the same buffer object. In this case we need to
+ * know where the plane start inside this buffer.
+ * @data_offset: offset in the plane to the start of data; usually 0, unless
+ * there is a header in front of the data. data_offset is
+ * relative to start_offset, so absolute data_offset is actually
+ * start_offset + data_offset
+ *
+ *
+ * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
+ * with two planes can have one plane for Y, and another for interleaved CbCr
+ * components. Each plane can reside in a separate memory buffer, or even in
+ * a completely separate memory node (e.g. in embedded devices).
+ * Note that this struct is also used for uni-planar buffers, but in that case
+ * you'll only have one plane defined.
+ */
+struct v4l2_ext_plane {
+ __u32 bytesused;
+ __u32 length;
+ union {
+ __u32 mem_offset;
+ __u64 userptr;
+ struct {
+ __s32 fd;
+ __u32 offset;
+ } dmabuf;
+ } m;
+ __u32 data_offset;
+ __u32 reserved[10];
+};
+
/**
* struct v4l2_buffer - video buffer info
* @index: id number of the buffer
@@ -985,6 +1028,40 @@ struct v4l2_buffer {
};
};
+/**
+ * struct v4l2_ext_buffer - extended video buffer info
+ * @index: id number of the buffer
+ * @type: enum v4l2_buf_type; buffer type. _MPLANE and _OVERLAY formats are
+ * invalid
+ * @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
+ * @request_fd: fd of the request that this buffer should use
+ * @reserved: some extra space reserved to add future fields (like timecode).
+ * 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 flags;
+ __u32 field;
+ __u64 timestamp;
+ __u32 sequence;
+ __u32 memory;
+ struct v4l2_ext_plane planes[VIDEO_MAX_PLANES];
+ __u32 num_planes;
+ __u32 request_fd;
+ __u32 reserved[10];
+};
+
/**
* v4l2_timeval_to_ns - Convert timeval to nanoseconds
* @ts: pointer to the timeval variable to be converted
@@ -1062,6 +1139,35 @@ struct v4l2_exportbuffer {
__u32 reserved[11];
};
+/**
+ * struct v4l2_ext_exportbuffer - export of video buffer as DMABUF file
+ * descriptor using extended format
+ *
+ * @index: id number of the buffer
+ * @type: enum v4l2_buf_type; buffer type
+ * @flags: flags for newly created file(s), currently only O_CLOEXEC is
+ * supported, refer to manual of open syscall for more details
+ * @first_plane: first plane to export. Most likely set to 0
+ * @num_planes: number of planes to export. Most set to the number of planes
+ * attached to the buffer
+ * @fds: file descriptors associated with DMABUF (set by driver). Note that all
+ * planes might share the same buffer and then be returned the same FD
+ *
+ * Contains data used for exporting a video buffer as DMABUF file descriptor.
+ * The buffer is identified by a 'cookie' returned by VIDIOC_QUERYBUF
+ * (identical to the cookie used to mmap() the buffer to userspace). All
+ * reserved fields must be set to zero.
+ */
+struct v4l2_ext_exportbuffer {
+ __u32 type; /* enum v4l2_buf_type */
+ __u32 index;
+ __u32 flags;
+ __u32 first_plane;
+ __u32 num_planes;
+ __s32 fds[VIDEO_MAX_PLANES];
+ __u32 reserved;
+};
+
/*
* O V E R L A Y P R E V I E W
*/
@@ -2458,6 +2564,23 @@ struct v4l2_create_buffers {
__u32 reserved[7];
};
+/**
+ * struct v4l2_ext_create_buffers - VIDIOC_EXT_CREATE_BUFS argument
+ * @index: on return, index of the first created buffer
+ * @count: entry: number of requested buffers,
+ * return: number of created buffers
+ * @memory: enum v4l2_memory; buffer memory type
+ * @capabilities: capabilities of this buffer type.
+ * @format: frame format, for which buffers are requested
+ */
+struct v4l2_ext_create_buffers {
+ __u32 index;
+ __u32 count;
+ __u32 memory;
+ __u32 capabilities;
+ struct v4l2_ext_format format;
+};
+
/*
* I O C T L C O D E S F O R V I D E O D E V I C E S
*
@@ -2561,6 +2684,13 @@ struct v4l2_create_buffers {
#define VIDIOC_G_EXT_FMT _IOWR('V', 104, struct v4l2_ext_format)
#define VIDIOC_S_EXT_FMT _IOWR('V', 105, struct v4l2_ext_format)
#define VIDIOC_TRY_EXT_FMT _IOWR('V', 106, struct v4l2_ext_format)
+#define VIDIOC_EXT_CREATE_BUFS _IOWR('V', 107, struct v4l2_ext_create_buffers)
+#define VIDIOC_EXT_QUERYBUF _IOWR('V', 108, struct v4l2_ext_buffer)
+#define VIDIOC_EXT_QBUF _IOWR('V', 109, struct v4l2_ext_buffer)
+#define VIDIOC_EXT_DQBUF _IOWR('V', 110, struct v4l2_ext_buffer)
+#define VIDIOC_EXT_PREPARE_BUF _IOWR('V', 111, struct v4l2_ext_buffer)
+#define VIDIOC_EXT_EXPBUF _IOWR('V', 112, struct v4l2_ext_exportbuffer)
+
/* Reminder: when adding new ioctls please add support for them to
drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */