Commit 8227c92b authored by Sakari Ailus's avatar Sakari Ailus Committed by Mauro Carvalho Chehab

[media] v4l: Implement v4l2_subdev_link_validate()

v4l2_subdev_link_validate() is the default op for validating a link. In V4L2
subdev context, it is used to call a pad op which performs the proper link
check without much extra work.
Signed-off-by: default avatarSakari Ailus <sakari.ailus@iki.fi>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 48398f93
...@@ -316,6 +316,18 @@ If the subdev driver intends to process video and integrate with the media ...@@ -316,6 +316,18 @@ If the subdev driver intends to process video and integrate with the media
framework, it must implement format related functionality using framework, it must implement format related functionality using
v4l2_subdev_pad_ops instead of v4l2_subdev_video_ops. v4l2_subdev_pad_ops instead of v4l2_subdev_video_ops.
In that case, the subdev driver may set the link_validate field to provide
its own link validation function. The link validation function is called for
every link in the pipeline where both of the ends of the links are V4L2
sub-devices. The driver is still responsible for validating the correctness
of the format configuration between sub-devices and video nodes.
If link_validate op is not set, the default function
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
perform the checks mentioned above in addition to their own checks.
A device (bridge) driver needs to register the v4l2_subdev with the A device (bridge) driver needs to register the v4l2_subdev with the
v4l2_device: v4l2_device:
......
...@@ -387,6 +387,70 @@ const struct v4l2_file_operations v4l2_subdev_fops = { ...@@ -387,6 +387,70 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
.poll = subdev_poll, .poll = subdev_poll,
}; };
#ifdef CONFIG_MEDIA_CONTROLLER
int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
struct media_link *link,
struct v4l2_subdev_format *source_fmt,
struct v4l2_subdev_format *sink_fmt)
{
if (source_fmt->format.width != sink_fmt->format.width
|| source_fmt->format.height != sink_fmt->format.height
|| source_fmt->format.code != sink_fmt->format.code)
return -EINVAL;
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
static int
v4l2_subdev_link_validate_get_format(struct media_pad *pad,
struct v4l2_subdev_format *fmt)
{
switch (media_entity_type(pad->entity)) {
case MEDIA_ENT_T_V4L2_SUBDEV:
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
fmt->pad = pad->index;
return v4l2_subdev_call(media_entity_to_v4l2_subdev(
pad->entity),
pad, get_fmt, NULL, fmt);
default:
WARN(1, "Driver bug! Wrong media entity type %d, entity %s\n",
media_entity_type(pad->entity), pad->entity->name);
/* Fall through */
case MEDIA_ENT_T_DEVNODE_V4L:
return -EINVAL;
}
}
int v4l2_subdev_link_validate(struct media_link *link)
{
struct v4l2_subdev *sink;
struct v4l2_subdev_format sink_fmt, source_fmt;
int rval;
rval = v4l2_subdev_link_validate_get_format(
link->source, &source_fmt);
if (rval < 0)
return 0;
rval = v4l2_subdev_link_validate_get_format(
link->sink, &sink_fmt);
if (rval < 0)
return 0;
sink = media_entity_to_v4l2_subdev(link->sink->entity);
rval = v4l2_subdev_call(sink, pad, link_validate, link,
&source_fmt, &sink_fmt);
if (rval != -ENOIOCTLCMD)
return rval;
return v4l2_subdev_link_validate_default(
sink, link, &source_fmt, &sink_fmt);
}
EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
#endif /* CONFIG_MEDIA_CONTROLLER */
void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
{ {
INIT_LIST_HEAD(&sd->list); INIT_LIST_HEAD(&sd->list);
......
...@@ -470,6 +470,11 @@ struct v4l2_subdev_pad_ops { ...@@ -470,6 +470,11 @@ struct v4l2_subdev_pad_ops {
struct v4l2_subdev_selection *sel); struct v4l2_subdev_selection *sel);
int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_selection *sel); struct v4l2_subdev_selection *sel);
#ifdef CONFIG_MEDIA_CONTROLLER
int (*link_validate)(struct v4l2_subdev *sd, struct media_link *link,
struct v4l2_subdev_format *source_fmt,
struct v4l2_subdev_format *sink_fmt);
#endif /* CONFIG_MEDIA_CONTROLLER */
}; };
struct v4l2_subdev_ops { struct v4l2_subdev_ops {
...@@ -602,6 +607,13 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd) ...@@ -602,6 +607,13 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
return sd->host_priv; return sd->host_priv;
} }
#ifdef CONFIG_MEDIA_CONTROLLER
int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
struct media_link *link,
struct v4l2_subdev_format *source_fmt,
struct v4l2_subdev_format *sink_fmt);
int v4l2_subdev_link_validate(struct media_link *link);
#endif /* CONFIG_MEDIA_CONTROLLER */
void v4l2_subdev_init(struct v4l2_subdev *sd, void v4l2_subdev_init(struct v4l2_subdev *sd,
const struct v4l2_subdev_ops *ops); const struct v4l2_subdev_ops *ops);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment