From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Meng Wei Date: Fri, 26 Oct 2018 09:52:23 +0800 Subject: [PATCH] v4l: for multiplex pad add routing informaion in link validation for links have 2 multiplexed pad, validating all active streams. otherwise, all follow 1:1 pad link route with stream id 0 Signed-off-by: Chang Ying Signed-off-by: Meng Wei --- drivers/media/v4l2-core/v4l2-subdev.c | 135 +++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 5 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 5d0ee2fd384a..e95cda554215 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -668,19 +668,21 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad, return -EINVAL; } -int v4l2_subdev_link_validate(struct media_link *link) +static int v4l2_subdev_link_validate_one(struct media_link *link, + struct media_pad *source_pad, unsigned int source_stream, + struct media_pad *sink_pad, unsigned int sink_stream) { 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); + source_fmt.stream = source_stream; + rval = v4l2_subdev_link_validate_get_format(source_pad, &source_fmt); if (rval < 0) return 0; - rval = v4l2_subdev_link_validate_get_format( - link->sink, &sink_fmt); + sink_fmt.stream = sink_stream; + rval = v4l2_subdev_link_validate_get_format(sink_pad, &sink_fmt); if (rval < 0) return 0; @@ -694,6 +696,129 @@ int v4l2_subdev_link_validate(struct media_link *link) return v4l2_subdev_link_validate_default( sink, link, &source_fmt, &sink_fmt); } + +/* How many routes to assume there can be per a sub-device? */ +#define LINK_VALIDATE_ROUTES 8 + +int v4l2_subdev_link_validate(struct media_link *link) +{ + struct v4l2_subdev *sink; + struct v4l2_subdev_route sink_routes[LINK_VALIDATE_ROUTES]; + struct v4l2_subdev_routing sink_routing = { + .routes = sink_routes, + .num_routes = ARRAY_SIZE(sink_routes), + }; + struct v4l2_subdev_route src_routes[LINK_VALIDATE_ROUTES]; + struct v4l2_subdev_routing src_routing = { + .routes = src_routes, + .num_routes = ARRAY_SIZE(src_routes), + }; + unsigned int i, j; + int rval; + + sink = media_entity_to_v4l2_subdev(link->sink->entity); + + if (!(link->sink->flags & MEDIA_PAD_FL_MULTIPLEX && + link->source->flags & MEDIA_PAD_FL_MULTIPLEX)) + return v4l2_subdev_link_validate_one(link, link->source, 0, + link->sink, 0); + /* + * multiplex link cannot proceed without route information. + */ + rval = v4l2_subdev_call(sink, pad, get_routing, &sink_routing); + + if (rval) { + dev_err(sink->entity.graph_obj.mdev->dev, + "error %d in get_routing() on %s, sink pad %u\n", rval, + sink->entity.name, link->sink->index); + + return rval; + } + + rval = v4l2_subdev_call(media_entity_to_v4l2_subdev( + link->source->entity), + pad, get_routing, &src_routing); + if (rval) { + dev_dbg(sink->entity.graph_obj.mdev->dev, + "error %d in get_routing() on %s, source pad %u\n", + rval, sink->entity.name, link->source->index); + + return rval; + } + + dev_dbg(sink->entity.graph_obj.mdev->dev, + "validating multiplexed link \"%s\":%u -> \"%s\":%u; %u/%u routes\n", + link->source->entity->name, link->source->index, + sink->entity.name, link->sink->index, + src_routing.num_routes, sink_routing.num_routes); + + for (i = 0; i < sink_routing.num_routes; i++) { + /* Get the first active route for the sink pad. */ + if (sink_routes[i].sink_pad != link->sink->index || + !(sink_routes[i].flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) { + dev_dbg(sink->entity.graph_obj.mdev->dev, + "skipping sink route %u/%u -> %u/%u[%u]\n", + sink_routes[i].sink_pad, + sink_routes[i].sink_stream, + sink_routes[i].source_pad, + sink_routes[i].source_stream, + (bool)(sink_routes[i].flags + & V4L2_SUBDEV_ROUTE_FL_ACTIVE)); + continue; + } + + /* + * Get the corresponding route for the source pad. + * It's ok for the source pad to have routes active + * where the sink pad does not, but the routes that + * are active on the source pad have to be active on + * the sink pad as well. + */ + + for (j = 0; j < src_routing.num_routes; j++) { + if (src_routes[j].source_pad == link->source->index && + src_routes[j].source_stream + == sink_routes[i].sink_stream) + break; + } + + if (j == src_routing.num_routes) { + dev_err(sink->entity.graph_obj.mdev->dev, + "no corresponding source found.\n"); + return -EINVAL; + } + + /* The source route must be active. */ + if (!(src_routes[j].flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) { + dev_dbg(sink->entity.graph_obj.mdev->dev, + "source route not active\n"); + return -EINVAL; + } + + dev_dbg(sink->entity.graph_obj.mdev->dev, + "validating link \"%s\": %u/%u => \"%s\" %u/%u\n", + link->source->entity->name, src_routes[j].source_pad, + src_routes[j].source_stream, sink->entity.name, + sink_routes[i].sink_pad, sink_routes[i].sink_stream); + + rval = v4l2_subdev_link_validate_one( + link, link->source, src_routes[j].source_stream, + link->sink, sink_routes[j].sink_stream); + if (rval) { + dev_dbg(sink->entity.graph_obj.mdev->dev, + "error %d in link validation\n", rval); + return rval; + } + } + + if (i < sink_routing.num_routes) { + dev_dbg(sink->entity.graph_obj.mdev->dev, + "not all sink routes verified; out of source routes\n"); + return -EINVAL; + } + + return 0; +} EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate); struct v4l2_subdev_pad_config * -- https://clearlinux.org