media: subdev: add v4l2_subdev_routing_validate() helper
Add a v4l2_subdev_routing_validate() helper for verifying routing for common cases like only allowing non-overlapping 1-to-1 streams. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
5b0d85b379
commit
69c0fe7ae7
|
@ -1615,6 +1615,108 @@ v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_opposite_stream_format);
|
||||
|
||||
int v4l2_subdev_routing_validate(struct v4l2_subdev *sd,
|
||||
const struct v4l2_subdev_krouting *routing,
|
||||
enum v4l2_subdev_routing_restriction disallow)
|
||||
{
|
||||
u32 *remote_pads = NULL;
|
||||
unsigned int i, j;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (disallow & V4L2_SUBDEV_ROUTING_NO_STREAM_MIX) {
|
||||
remote_pads = kcalloc(sd->entity.num_pads, sizeof(*remote_pads),
|
||||
GFP_KERNEL);
|
||||
if (!remote_pads)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < sd->entity.num_pads; ++i)
|
||||
remote_pads[i] = U32_MAX;
|
||||
}
|
||||
|
||||
for (i = 0; i < routing->num_routes; ++i) {
|
||||
const struct v4l2_subdev_route *route = &routing->routes[i];
|
||||
|
||||
/* Validate the sink and source pad numbers. */
|
||||
if (route->sink_pad >= sd->entity.num_pads ||
|
||||
!(sd->entity.pads[route->sink_pad].flags & MEDIA_PAD_FL_SINK)) {
|
||||
dev_dbg(sd->dev, "route %u sink (%u) is not a sink pad\n",
|
||||
i, route->sink_pad);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (route->source_pad >= sd->entity.num_pads ||
|
||||
!(sd->entity.pads[route->source_pad].flags & MEDIA_PAD_FL_SOURCE)) {
|
||||
dev_dbg(sd->dev, "route %u source (%u) is not a source pad\n",
|
||||
i, route->source_pad);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* V4L2_SUBDEV_ROUTING_NO_STREAM_MIX: Streams on the same pad
|
||||
* may not be routed to streams on different pads.
|
||||
*/
|
||||
if (disallow & V4L2_SUBDEV_ROUTING_NO_STREAM_MIX) {
|
||||
if (remote_pads[route->sink_pad] != U32_MAX &&
|
||||
remote_pads[route->sink_pad] != route->source_pad) {
|
||||
dev_dbg(sd->dev,
|
||||
"route %u attempts to mix %s streams\n",
|
||||
i, "sink");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (remote_pads[route->source_pad] != U32_MAX &&
|
||||
remote_pads[route->source_pad] != route->sink_pad) {
|
||||
dev_dbg(sd->dev,
|
||||
"route %u attempts to mix %s streams\n",
|
||||
i, "source");
|
||||
goto out;
|
||||
}
|
||||
|
||||
remote_pads[route->sink_pad] = route->source_pad;
|
||||
remote_pads[route->source_pad] = route->sink_pad;
|
||||
}
|
||||
|
||||
for (j = i + 1; j < routing->num_routes; ++j) {
|
||||
const struct v4l2_subdev_route *r = &routing->routes[j];
|
||||
|
||||
/*
|
||||
* V4L2_SUBDEV_ROUTING_NO_1_TO_N: No two routes can
|
||||
* originate from the same (sink) stream.
|
||||
*/
|
||||
if ((disallow & V4L2_SUBDEV_ROUTING_NO_1_TO_N) &&
|
||||
route->sink_pad == r->sink_pad &&
|
||||
route->sink_stream == r->sink_stream) {
|
||||
dev_dbg(sd->dev,
|
||||
"routes %u and %u originate from same sink (%u/%u)\n",
|
||||
i, j, route->sink_pad,
|
||||
route->sink_stream);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* V4L2_SUBDEV_ROUTING_NO_N_TO_1: No two routes can end
|
||||
* at the same (source) stream.
|
||||
*/
|
||||
if ((disallow & V4L2_SUBDEV_ROUTING_NO_N_TO_1) &&
|
||||
route->source_pad == r->source_pad &&
|
||||
route->source_stream == r->source_stream) {
|
||||
dev_dbg(sd->dev,
|
||||
"routes %u and %u end at same source (%u/%u)\n",
|
||||
i, j, route->source_pad,
|
||||
route->source_stream);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
kfree(remote_pads);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_subdev_routing_validate);
|
||||
|
||||
#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */
|
||||
|
||||
#endif /* CONFIG_MEDIA_CONTROLLER */
|
||||
|
|
|
@ -1584,6 +1584,45 @@ struct v4l2_mbus_framefmt *
|
|||
v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state,
|
||||
u32 pad, u32 stream);
|
||||
|
||||
/**
|
||||
* enum v4l2_subdev_routing_restriction - Subdevice internal routing restrictions
|
||||
*
|
||||
* @V4L2_SUBDEV_ROUTING_NO_1_TO_N:
|
||||
* an input stream may not be routed to multiple output streams (stream
|
||||
* duplication)
|
||||
* @V4L2_SUBDEV_ROUTING_NO_N_TO_1:
|
||||
* multiple input streams may not be routed to the same output stream
|
||||
* (stream merging)
|
||||
* @V4L2_SUBDEV_ROUTING_NO_STREAM_MIX:
|
||||
* streams on the same pad may not be routed to streams on different pads
|
||||
* @V4L2_SUBDEV_ROUTING_ONLY_1_TO_1:
|
||||
* only non-overlapping 1-to-1 stream routing is allowed (a combination of
|
||||
* @V4L2_SUBDEV_ROUTING_NO_1_TO_N and @V4L2_SUBDEV_ROUTING_NO_N_TO_1)
|
||||
*/
|
||||
enum v4l2_subdev_routing_restriction {
|
||||
V4L2_SUBDEV_ROUTING_NO_1_TO_N = BIT(0),
|
||||
V4L2_SUBDEV_ROUTING_NO_N_TO_1 = BIT(1),
|
||||
V4L2_SUBDEV_ROUTING_NO_STREAM_MIX = BIT(2),
|
||||
V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 =
|
||||
V4L2_SUBDEV_ROUTING_NO_1_TO_N |
|
||||
V4L2_SUBDEV_ROUTING_NO_N_TO_1,
|
||||
};
|
||||
|
||||
/**
|
||||
* v4l2_subdev_routing_validate() - Verify that routes comply with driver
|
||||
* constraints
|
||||
* @sd: The subdevice
|
||||
* @routing: Routing to verify
|
||||
* @disallow: Restrictions on routes
|
||||
*
|
||||
* This verifies that the given routing complies with the @disallow constraints.
|
||||
*
|
||||
* Returns 0 on success, error value otherwise.
|
||||
*/
|
||||
int v4l2_subdev_routing_validate(struct v4l2_subdev *sd,
|
||||
const struct v4l2_subdev_krouting *routing,
|
||||
enum v4l2_subdev_routing_restriction disallow);
|
||||
|
||||
#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */
|
||||
|
||||
#endif /* CONFIG_MEDIA_CONTROLLER */
|
||||
|
|
Loading…
Reference in New Issue