From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/media/v4l2-core/v4l2-subdev.c | 461 +++++++++++++++++++++++++++++++++++++++++----------------
1 files changed, 330 insertions(+), 131 deletions(-)
diff --git a/kernel/drivers/media/v4l2-core/v4l2-subdev.c b/kernel/drivers/media/v4l2-core/v4l2-subdev.c
index 8abea17..4a95991 100644
--- a/kernel/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/kernel/drivers/media/v4l2-core/v4l2-subdev.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* V4L2 sub-device
*
@@ -5,48 +6,42 @@
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/ioctl.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <linux/export.h>
+#include <linux/version.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
+#ifndef __GENKSYMS__
+#include <trace/hooks/v4l2core.h>
+#endif
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
{
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
if (sd->entity.num_pads) {
fh->pad = v4l2_subdev_alloc_pad_config(sd);
if (fh->pad == NULL)
return -ENOMEM;
}
-#endif
+
return 0;
}
static void subdev_fh_free(struct v4l2_subdev_fh *fh)
{
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
v4l2_subdev_free_pad_config(fh->pad);
fh->pad = NULL;
-#endif
}
static int subdev_open(struct file *file)
@@ -54,9 +49,6 @@
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_subdev_fh *subdev_fh;
-#if defined(CONFIG_MEDIA_CONTROLLER)
- struct media_entity *entity = NULL;
-#endif
int ret;
subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL);
@@ -73,12 +65,15 @@
v4l2_fh_add(&subdev_fh->vfh);
file->private_data = &subdev_fh->vfh;
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (sd->v4l2_dev->mdev) {
- entity = media_entity_get(&sd->entity);
- if (!entity) {
+ if (sd->v4l2_dev->mdev && sd->entity.graph_obj.mdev->dev) {
+ struct module *owner;
+
+ owner = sd->entity.graph_obj.mdev->dev->driver->owner;
+ if (!try_module_get(owner)) {
ret = -EBUSY;
goto err;
}
+ subdev_fh->owner = owner;
}
#endif
@@ -91,9 +86,7 @@
return 0;
err:
-#if defined(CONFIG_MEDIA_CONTROLLER)
- media_entity_put(entity);
-#endif
+ module_put(subdev_fh->owner);
v4l2_fh_del(&subdev_fh->vfh);
v4l2_fh_exit(&subdev_fh->vfh);
subdev_fh_free(subdev_fh);
@@ -111,10 +104,7 @@
if (sd->internal_ops && sd->internal_ops->close)
sd->internal_ops->close(sd, subdev_fh);
-#if defined(CONFIG_MEDIA_CONTROLLER)
- if (sd->v4l2_dev->mdev)
- media_entity_put(&sd->entity);
-#endif
+ module_put(subdev_fh->owner);
v4l2_fh_del(vfh);
v4l2_fh_exit(vfh);
subdev_fh_free(subdev_fh);
@@ -123,69 +113,267 @@
return 0;
}
+#else /* CONFIG_VIDEO_V4L2_SUBDEV_API */
+static int subdev_open(struct file *file)
+{
+ return -ENODEV;
+}
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static int check_format(struct v4l2_subdev *sd,
+static int subdev_close(struct file *file)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */
+
+static inline int check_which(u32 which)
+{
+ if (which != V4L2_SUBDEV_FORMAT_TRY &&
+ which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static inline int check_pad(struct v4l2_subdev *sd, u32 pad)
+{
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (sd->entity.num_pads) {
+ if (pad >= sd->entity.num_pads)
+ return -EINVAL;
+ return 0;
+ }
+#endif
+ /* allow pad 0 on subdevices not registered as media entities */
+ if (pad > 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int check_cfg(u32 which, struct v4l2_subdev_pad_config *cfg)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg)
+ return -EINVAL;
+
+ return 0;
+}
+
+static inline int check_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ if (!format)
+ return -EINVAL;
+
+ return check_which(format->which) ? : check_pad(sd, format->pad) ? :
+ check_cfg(format->which, cfg);
+}
+
+static int call_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
- if (format->which != V4L2_SUBDEV_FORMAT_TRY &&
- format->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
- if (format->pad >= sd->entity.num_pads)
- return -EINVAL;
-
- return 0;
+ return check_format(sd, cfg, format) ? :
+ sd->ops->pad->get_fmt(sd, cfg, format);
}
-static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop)
+static int call_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
{
- if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
- crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
- if (crop->pad >= sd->entity.num_pads)
- return -EINVAL;
-
- return 0;
+ return check_format(sd, cfg, format) ? :
+ sd->ops->pad->set_fmt(sd, cfg, format);
}
-static int check_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_selection *sel)
+static int call_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
{
- if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
- sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ if (!code)
return -EINVAL;
- if (sel->pad >= sd->entity.num_pads)
- return -EINVAL;
-
- return 0;
+ return check_which(code->which) ? : check_pad(sd, code->pad) ? :
+ check_cfg(code->which, cfg) ? :
+ sd->ops->pad->enum_mbus_code(sd, cfg, code);
}
-static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+static int call_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
{
- if (edid->pad >= sd->entity.num_pads)
+ if (!fse)
+ return -EINVAL;
+
+ return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
+ check_cfg(fse->which, cfg) ? :
+ sd->ops->pad->enum_frame_size(sd, cfg, fse);
+}
+
+static inline int check_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ if (!fi)
+ return -EINVAL;
+
+ return check_pad(sd, fi->pad);
+}
+
+static int call_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ return check_frame_interval(sd, fi) ? :
+ sd->ops->video->g_frame_interval(sd, fi);
+}
+
+static int call_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ return check_frame_interval(sd, fi) ? :
+ sd->ops->video->s_frame_interval(sd, fi);
+}
+
+static int call_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ if (!fie)
+ return -EINVAL;
+
+ return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
+ check_cfg(fie->which, cfg) ? :
+ sd->ops->pad->enum_frame_interval(sd, cfg, fie);
+}
+
+static inline int check_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ if (!sel)
+ return -EINVAL;
+
+ return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
+ check_cfg(sel->which, cfg);
+}
+
+static int call_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ return check_selection(sd, cfg, sel) ? :
+ sd->ops->pad->get_selection(sd, cfg, sel);
+}
+
+static int call_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ return check_selection(sd, cfg, sel) ? :
+ sd->ops->pad->set_selection(sd, cfg, sel);
+}
+
+static inline int check_edid(struct v4l2_subdev *sd,
+ struct v4l2_subdev_edid *edid)
+{
+ if (!edid)
return -EINVAL;
if (edid->blocks && edid->edid == NULL)
return -EINVAL;
- return 0;
+ return check_pad(sd, edid->pad);
}
-#endif
+static int call_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+{
+ return check_edid(sd, edid) ? : sd->ops->pad->get_edid(sd, edid);
+}
+
+static int call_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+{
+ return check_edid(sd, edid) ? : sd->ops->pad->set_edid(sd, edid);
+}
+
+static int call_dv_timings_cap(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap)
+{
+ if (!cap)
+ return -EINVAL;
+
+ return check_pad(sd, cap->pad) ? :
+ sd->ops->pad->dv_timings_cap(sd, cap);
+}
+
+static int call_enum_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_enum_dv_timings *dvt)
+{
+ if (!dvt)
+ return -EINVAL;
+
+ return check_pad(sd, dvt->pad) ? :
+ sd->ops->pad->enum_dv_timings(sd, dvt);
+}
+
+static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_config *config)
+{
+ return check_pad(sd, pad) ? :
+ sd->ops->pad->get_mbus_config(sd, pad, config);
+}
+
+static int call_set_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_config *config)
+{
+ return check_pad(sd, pad) ? :
+ sd->ops->pad->get_mbus_config(sd, pad, config);
+}
+
+static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
+ .get_fmt = call_get_fmt,
+ .set_fmt = call_set_fmt,
+ .enum_mbus_code = call_enum_mbus_code,
+ .enum_frame_size = call_enum_frame_size,
+ .enum_frame_interval = call_enum_frame_interval,
+ .get_selection = call_get_selection,
+ .set_selection = call_set_selection,
+ .get_edid = call_get_edid,
+ .set_edid = call_set_edid,
+ .dv_timings_cap = call_dv_timings_cap,
+ .enum_dv_timings = call_enum_dv_timings,
+ .get_mbus_config = call_get_mbus_config,
+ .set_mbus_config = call_set_mbus_config,
+};
+
+static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = {
+ .g_frame_interval = call_g_frame_interval,
+ .s_frame_interval = call_s_frame_interval,
+};
+
+const struct v4l2_subdev_ops v4l2_subdev_call_wrappers = {
+ .pad = &v4l2_subdev_call_pad_wrappers,
+ .video = &v4l2_subdev_call_video_wrappers,
+};
+EXPORT_SYMBOL(v4l2_subdev_call_wrappers);
+
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_fh *vfh = file->private_data;
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
+ bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags);
int rval;
-#endif
switch (cmd) {
+ case VIDIOC_SUBDEV_QUERYCAP: {
+ struct v4l2_subdev_capability *cap = arg;
+
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ cap->version = LINUX_VERSION_CODE;
+ cap->capabilities = ro_subdev ? V4L2_SUBDEV_CAP_RO_SUBDEV : 0;
+
+ return 0;
+ }
+
case VIDIOC_QUERYCTRL:
/*
* TODO: this really should be folded into v4l2_queryctrl (this
@@ -222,17 +410,20 @@
case VIDIOC_G_EXT_CTRLS:
if (!vfh->ctrl_handler)
return -ENOTTY;
- return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg);
+ return v4l2_g_ext_ctrls(vfh->ctrl_handler,
+ vdev, sd->v4l2_dev->mdev, arg);
case VIDIOC_S_EXT_CTRLS:
if (!vfh->ctrl_handler)
return -ENOTTY;
- return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg);
+ return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler,
+ vdev, sd->v4l2_dev->mdev, arg);
case VIDIOC_TRY_EXT_CTRLS:
if (!vfh->ctrl_handler)
return -ENOTTY;
- return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg);
+ return v4l2_try_ext_ctrls(vfh->ctrl_handler,
+ vdev, sd->v4l2_dev->mdev, arg);
case VIDIOC_DQEVENT:
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
@@ -273,7 +464,7 @@
p->flags |= V4L2_CHIP_FL_WRITABLE;
if (sd->ops->core && sd->ops->core->g_register)
p->flags |= V4L2_CHIP_FL_READABLE;
- strlcpy(p->name, sd->name, sizeof(p->name));
+ strscpy(p->name, sd->name, sizeof(p->name));
return 0;
}
#endif
@@ -289,13 +480,8 @@
return ret;
}
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
case VIDIOC_SUBDEV_G_FMT: {
struct v4l2_subdev_format *format = arg;
-
- rval = check_format(sd, format);
- if (rval)
- return rval;
memset(format->reserved, 0, sizeof(format->reserved));
memset(format->format.reserved, 0, sizeof(format->format.reserved));
@@ -304,10 +490,17 @@
case VIDIOC_SUBDEV_S_FMT: {
struct v4l2_subdev_format *format = arg;
+ int ret = 0;
- rval = check_format(sd, format);
- if (rval)
- return rval;
+ if (format->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
+ return -EPERM;
+
+ trace_android_vh_v4l2subdev_set_fmt(sd, subdev_fh->pad,
+ format, &ret);
+ trace_android_rvh_v4l2subdev_set_fmt(sd, subdev_fh->pad,
+ format, &ret);
+ if (ret)
+ return ret;
memset(format->reserved, 0, sizeof(format->reserved));
memset(format->format.reserved, 0, sizeof(format->format.reserved));
@@ -317,10 +510,6 @@
case VIDIOC_SUBDEV_G_CROP: {
struct v4l2_subdev_crop *crop = arg;
struct v4l2_subdev_selection sel;
-
- rval = check_crop(sd, crop);
- if (rval)
- return rval;
memset(crop->reserved, 0, sizeof(crop->reserved));
memset(&sel, 0, sizeof(sel));
@@ -340,11 +529,10 @@
struct v4l2_subdev_crop *crop = arg;
struct v4l2_subdev_selection sel;
- memset(crop->reserved, 0, sizeof(crop->reserved));
- rval = check_crop(sd, crop);
- if (rval)
- return rval;
+ if (crop->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
+ return -EPERM;
+ memset(crop->reserved, 0, sizeof(crop->reserved));
memset(&sel, 0, sizeof(sel));
sel.which = crop->which;
sel.pad = crop->pad;
@@ -362,13 +550,6 @@
case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
struct v4l2_subdev_mbus_code_enum *code = arg;
- if (code->which != V4L2_SUBDEV_FORMAT_TRY &&
- code->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
- if (code->pad >= sd->entity.num_pads)
- return -EINVAL;
-
memset(code->reserved, 0, sizeof(code->reserved));
return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad,
code);
@@ -376,13 +557,6 @@
case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
struct v4l2_subdev_frame_size_enum *fse = arg;
-
- if (fse->which != V4L2_SUBDEV_FORMAT_TRY &&
- fse->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
- if (fse->pad >= sd->entity.num_pads)
- return -EINVAL;
memset(fse->reserved, 0, sizeof(fse->reserved));
return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad,
@@ -392,18 +566,21 @@
case VIDIOC_SUBDEV_G_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval *fi = arg;
- if (fi->pad >= sd->entity.num_pads)
- return -EINVAL;
-
memset(fi->reserved, 0, sizeof(fi->reserved));
return v4l2_subdev_call(sd, video, g_frame_interval, arg);
}
case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval *fi = arg;
+ int ret = 0;
- if (fi->pad >= sd->entity.num_pads)
- return -EINVAL;
+ if (ro_subdev)
+ return -EPERM;
+
+ trace_android_vh_v4l2subdev_set_frame_interval(sd, fi, &ret);
+ trace_android_rvh_v4l2subdev_set_frame_interval(sd, fi, &ret);
+ if (ret)
+ return ret;
memset(fi->reserved, 0, sizeof(fi->reserved));
return v4l2_subdev_call(sd, video, s_frame_interval, arg);
@@ -411,13 +588,6 @@
case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval_enum *fie = arg;
-
- if (fie->which != V4L2_SUBDEV_FORMAT_TRY &&
- fie->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
- if (fie->pad >= sd->entity.num_pads)
- return -EINVAL;
memset(fie->reserved, 0, sizeof(fie->reserved));
return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad,
@@ -427,10 +597,6 @@
case VIDIOC_SUBDEV_G_SELECTION: {
struct v4l2_subdev_selection *sel = arg;
- rval = check_selection(sd, sel);
- if (rval)
- return rval;
-
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
sd, pad, get_selection, subdev_fh->pad, sel);
@@ -438,10 +604,17 @@
case VIDIOC_SUBDEV_S_SELECTION: {
struct v4l2_subdev_selection *sel = arg;
+ int ret = 0;
- rval = check_selection(sd, sel);
- if (rval)
- return rval;
+ if (sel->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
+ return -EPERM;
+
+ trace_android_vh_v4l2subdev_set_selection(sd, subdev_fh->pad,
+ sel, &ret);
+ trace_android_rvh_v4l2subdev_set_selection(sd, subdev_fh->pad,
+ sel, &ret);
+ if (ret)
+ return ret;
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
@@ -451,19 +624,11 @@
case VIDIOC_G_EDID: {
struct v4l2_subdev_edid *edid = arg;
- rval = check_edid(sd, edid);
- if (rval)
- return rval;
-
return v4l2_subdev_call(sd, pad, get_edid, edid);
}
case VIDIOC_S_EDID: {
struct v4l2_subdev_edid *edid = arg;
-
- rval = check_edid(sd, edid);
- if (rval)
- return rval;
return v4l2_subdev_call(sd, pad, set_edid, edid);
}
@@ -471,17 +636,11 @@
case VIDIOC_SUBDEV_DV_TIMINGS_CAP: {
struct v4l2_dv_timings_cap *cap = arg;
- if (cap->pad >= sd->entity.num_pads)
- return -EINVAL;
-
return v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
}
case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: {
struct v4l2_enum_dv_timings *dvt = arg;
-
- if (dvt->pad >= sd->entity.num_pads)
- return -EINVAL;
return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt);
}
@@ -493,16 +652,19 @@
return v4l2_subdev_call(sd, video, g_dv_timings, arg);
case VIDIOC_SUBDEV_S_DV_TIMINGS:
- return v4l2_subdev_call(sd, video, s_dv_timings, arg);
+ if (ro_subdev)
+ return -EPERM;
- case VIDIOC_G_INPUT:
- return v4l2_subdev_call(sd, video, g_input_status, arg);
+ return v4l2_subdev_call(sd, video, s_dv_timings, arg);
case VIDIOC_SUBDEV_G_STD:
return v4l2_subdev_call(sd, video, g_std, arg);
case VIDIOC_SUBDEV_S_STD: {
v4l2_std_id *std = arg;
+
+ if (ro_subdev)
+ return -EPERM;
return v4l2_subdev_call(sd, video, s_std, *std);
}
@@ -519,7 +681,7 @@
case VIDIOC_SUBDEV_QUERYSTD:
return v4l2_subdev_call(sd, video, querystd, arg);
-#endif
+
default:
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
}
@@ -559,6 +721,22 @@
}
#endif
+#else /* CONFIG_VIDEO_V4L2_SUBDEV_API */
+static long subdev_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return -ENODEV;
+}
+
+#ifdef CONFIG_COMPAT
+static long subdev_compat_ioctl32(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return -ENODEV;
+}
+#endif
+#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */
+
static __poll_t subdev_poll(struct file *file, poll_table *wait)
{
struct video_device *vdev = video_devdata(file);
@@ -586,9 +764,30 @@
.release = subdev_close,
.poll = subdev_poll,
};
-EXPORT_SYMBOL_GPL(v4l2_subdev_fops);
#ifdef CONFIG_MEDIA_CONTROLLER
+
+int v4l2_subdev_get_fwnode_pad_1_to_1(struct media_entity *entity,
+ struct fwnode_endpoint *endpoint)
+{
+ struct fwnode_handle *fwnode;
+ struct v4l2_subdev *sd;
+
+ if (!is_media_entity_v4l2_subdev(entity))
+ return -EINVAL;
+
+ sd = media_entity_to_v4l2_subdev(entity);
+
+ fwnode = fwnode_graph_get_port_parent(endpoint->local_fwnode);
+ fwnode_handle_put(fwnode);
+
+ if (dev_fwnode(sd->dev) == fwnode)
+ return endpoint->port;
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_get_fwnode_pad_1_to_1);
+
int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
struct media_link *link,
struct v4l2_subdev_format *source_fmt,
--
Gitblit v1.6.2