@@ -628,6 +628,10 @@ static void determine_valid_ioctls(struct video_device *vdev)
__set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls);
if (is_vid) {
+#ifdef CONFIG_MEDIA_CONTROLLER
+ __set_bit(_IOC_NR(VIDIOC_BIND_CONTEXT), valid_ioctls);
+#endif
+
/* video specific ioctls */
if ((is_rx && (ops->vidioc_enum_fmt_vid_cap ||
ops->vidioc_enum_fmt_vid_overlay)) ||
@@ -681,12 +685,18 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_cap);
SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_cap);
SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_cap);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ __set_bit(_IOC_NR(VIDIOC_BIND_CONTEXT), valid_ioctls);
+#endif
} else if (is_meta && is_tx) {
/* metadata output specific ioctls */
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_meta_out);
SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_out);
SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_out);
SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_out);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ __set_bit(_IOC_NR(VIDIOC_BIND_CONTEXT), valid_ioctls);
+#endif
}
if (is_vbi) {
/* vbi specific ioctls */
@@ -93,6 +93,7 @@ int v4l2_fh_release(struct file *filp)
struct v4l2_fh *fh = filp->private_data;
if (fh) {
+ video_device_context_put(fh->context);
v4l2_fh_del(fh);
v4l2_fh_exit(fh);
kfree(fh);
@@ -9,6 +9,7 @@
*/
#include <linux/compat.h>
+#include <linux/file.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -349,6 +350,13 @@ static void v4l_print_format(const void *arg, bool write_only)
}
}
+static void v4l_print_context(const void *arg, bool write_only)
+{
+ const struct v4l2_context *c = arg;
+
+ pr_cont("context=%u\n", c->context_fd);
+}
+
static void v4l_print_framebuffer(const void *arg, bool write_only)
{
const struct v4l2_framebuffer *p = arg;
@@ -2110,6 +2118,61 @@ static int v4l_overlay(const struct v4l2_ioctl_ops *ops,
return ops->vidioc_overlay(file, fh, *(unsigned int *)arg);
}
+static int v4l_bind_context(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct media_device_context *mdev_context;
+ struct v4l2_fh *vfh =
+ test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags) ? fh : NULL;
+ struct v4l2_context *c = arg;
+ int ret;
+
+ /*
+ * TODO: do not __set_bit(_IOC_NR(VIDIOC_BIND_CONTEXT), valid_ioctls)
+ * if V4L2_FL_USES_V4L2_FH isn't set or the driver does not implement
+ * alloc_context and destroy_context.
+ */
+ if (!vfh)
+ return -ENOTTY;
+
+ if (!vdev->entity.ops || !vdev->entity.ops->alloc_context ||
+ !vdev->entity.ops->destroy_context)
+ return -ENOTTY;
+
+ mdev_context = media_device_context_get_from_fd(c->context_fd);
+ if (!mdev_context)
+ return -EINVAL;
+
+ /* Let the driver allocate the per-file handle context. */
+ ret = vdev->entity.ops->alloc_context(&vdev->entity,
+ (struct media_entity_context **)
+ &vfh->context);
+ if (ret)
+ goto err_put_mdev_context;
+
+ /*
+ * Bind the newly created video device context to the media device
+ * context identified by the file descriptor.
+ */
+ ret = media_device_bind_context(mdev_context,
+ (struct media_entity_context *)
+ vfh->context);
+ if (ret)
+ goto err_put_context;
+
+ media_device_context_put(mdev_context);
+
+ return 0;
+
+err_put_context:
+ video_device_context_put(vfh->context);
+err_put_mdev_context:
+ media_device_context_put(mdev_context);
+
+ return ret;
+}
+
static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
@@ -2853,6 +2916,7 @@ static const struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, 0),
IOCTL_INFO(VIDIOC_G_FMT, v4l_g_fmt, v4l_print_format, 0),
IOCTL_INFO(VIDIOC_S_FMT, v4l_s_fmt, v4l_print_format, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_BIND_CONTEXT, v4l_bind_context, v4l_print_context, 0),
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_G_FBUF, v4l_stub_g_fbuf, v4l_print_framebuffer, 0),
@@ -18,6 +18,7 @@
#include <linux/videodev2.h>
struct v4l2_fh;
+struct video_device_context;
/**
* struct v4l2_ioctl_ops - describe operations for each V4L2 ioctl
@@ -406,6 +407,10 @@ struct v4l2_ioctl_ops {
int (*vidioc_try_fmt_meta_out)(struct file *file, void *fh,
struct v4l2_format *f);
+ /* Context handlers */
+ int (*vidioc_bind_context)(struct file *file, void *fh,
+ struct video_device_context *c);
+
/* Buffer handlers */
int (*vidioc_reqbufs)(struct file *file, void *fh,
struct v4l2_requestbuffers *b);
@@ -1035,6 +1035,14 @@ struct v4l2_jpegcompression {
* always use APP0 */
};
+/*
+ * V I D E O D E V I C E C O N T E X T
+ */
+
+struct v4l2_context {
+ __u32 context_fd;
+};
+
/*
* M E M O R Y - M A P P I N G B U F F E R S
*/
@@ -2758,6 +2766,9 @@ struct v4l2_create_buffers {
#define VIDIOC_QUERY_EXT_CTRL _IOWR('V', 103, struct v4l2_query_ext_ctrl)
+/* Context handling */
+#define VIDIOC_BIND_CONTEXT _IOW('V', 104, struct v4l2_context)
+
/* Reminder: when adding new ioctls please add support for them to
drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */