[PATCH 15/37] [media] v4l: subdev: Add function to validate frame interval

From: Steve Longerbeam
Date: Mon Feb 20 2017 - 18:13:15 EST


If the pads on both sides of a link specify a frame interval, then
those frame intervals should match. Create the exported function
v4l2_subdev_link_validate_frame_interval() for this purpose. This
function is also added to v4l2_subdev_link_validate_default().

Signed-off-by: Steve Longerbeam <steve_longerbeam@xxxxxxxxxx>
---
Documentation/media/kapi/v4l2-subdev.rst | 5 ++--
drivers/media/v4l2-core/v4l2-subdev.c | 50 +++++++++++++++++++++++++++++++-
include/media/v4l2-subdev.h | 10 +++++++
3 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/Documentation/media/kapi/v4l2-subdev.rst b/Documentation/media/kapi/v4l2-subdev.rst
index e1f0b72..5e424f6 100644
--- a/Documentation/media/kapi/v4l2-subdev.rst
+++ b/Documentation/media/kapi/v4l2-subdev.rst
@@ -132,8 +132,9 @@ of the format configuration between sub-devices and video nodes.

If link_validate op is not set, the default function
:c:func:`v4l2_subdev_link_validate_default` is used instead. This function
-ensures that width, height and the media bus pixel code are equal on both source
-and sink of the link. Subdev drivers are also free to use this function to
+ensures that width, height, the media bus pixel code, and the frame
+interval (if indicated by both sides), are equal on both source and
+sink of the link. Subdev drivers are also free to use this function to
perform the checks mentioned above in addition to their own checks.

There are currently two ways to register subdevices with the V4L2 core. The
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index da78497..23a3e74 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -497,6 +497,50 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
};

#ifdef CONFIG_MEDIA_CONTROLLER
+static int
+v4l2_subdev_link_validate_get_fi(struct media_pad *pad,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ if (is_media_entity_v4l2_subdev(pad->entity)) {
+ struct v4l2_subdev *sd =
+ media_entity_to_v4l2_subdev(pad->entity);
+
+ fi->pad = pad->index;
+ return v4l2_subdev_call(sd, video, g_frame_interval, fi);
+ }
+
+ WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
+ "Driver bug! Wrong media entity type 0x%08x, entity %s\n",
+ pad->entity->function, pad->entity->name);
+
+ return -EINVAL;
+}
+
+int v4l2_subdev_link_validate_frame_interval(struct media_link *link)
+{
+ struct v4l2_subdev_frame_interval src_fi, sink_fi;
+ unsigned long src_usec, sink_usec;
+ int rval;
+
+ rval = v4l2_subdev_link_validate_get_fi(link->source, &src_fi);
+ if (rval < 0)
+ return 0;
+
+ rval = v4l2_subdev_link_validate_get_fi(link->sink, &sink_fi);
+ if (rval < 0)
+ return 0;
+
+ src_usec = DIV_ROUND_CLOSEST_ULL(
+ (u64)src_fi.interval.numerator * USEC_PER_SEC,
+ src_fi.interval.denominator);
+ sink_usec = DIV_ROUND_CLOSEST_ULL(
+ (u64)sink_fi.interval.numerator * USEC_PER_SEC,
+ sink_fi.interval.denominator);
+
+ return (src_usec != sink_usec) ? -EPIPE : 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_frame_interval);
+
int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
struct media_link *link,
struct v4l2_subdev_format *source_fmt,
@@ -516,7 +560,11 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
sink_fmt->format.field != V4L2_FIELD_NONE)
return -EPIPE;

- return 0;
+ /*
+ * The frame interval must match if specified on both ends
+ * of the link.
+ */
+ return v4l2_subdev_link_validate_frame_interval(link);
}
EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 0ab1c5d..60c941d 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -929,6 +929,16 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sink_fmt);

/**
+ * v4l2_subdev_link_validate_frame_interval - validates a media link
+ *
+ * @link: pointer to &struct media_link
+ *
+ * This function ensures that the frame intervals, if specified by
+ * both the source and sink subdevs of the link, are equal.
+ */
+int v4l2_subdev_link_validate_frame_interval(struct media_link *link);
+
+/**
* v4l2_subdev_link_validate - validates a media link
*
* @link: pointer to &struct media_link
--
2.7.4


--------------9BF81ECCD238175A2E1BCC1C--