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

[media] media: Add link_validate() op to check links to the sink pad

The purpose of the link_validate() op is to allow an entity driver to ensure
that the properties of the pads at the both ends of the link are suitable
for starting the pipeline. link_validate is called on sink pads on active
links which belong to the active part of the graph.
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 440f0fad
...@@ -335,6 +335,9 @@ the media_entity pipe field. ...@@ -335,6 +335,9 @@ the media_entity pipe field.
Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must
be identical for all nested calls to the function. be identical for all nested calls to the function.
media_entity_pipeline_start() may return an error. In that case, it will
clean up any the changes it did by itself.
When stopping the stream, drivers must notify the entities with When stopping the stream, drivers must notify the entities with
media_entity_pipeline_stop(struct media_entity *entity); media_entity_pipeline_stop(struct media_entity *entity);
...@@ -351,3 +354,19 @@ If other operations need to be disallowed on streaming entities (such as ...@@ -351,3 +354,19 @@ If other operations need to be disallowed on streaming entities (such as
changing entities configuration parameters) drivers can explicitly check the changing entities configuration parameters) drivers can explicitly check the
media_entity stream_count field to find out if an entity is streaming. This media_entity stream_count field to find out if an entity is streaming. This
operation must be done with the media_device graph_mutex held. operation must be done with the media_device graph_mutex held.
Link validation
---------------
Link validation is performed by media_entity_pipeline_start() for any
entity which has sink pads in the pipeline. The
media_entity::link_validate() callback is used for that purpose. In
link_validate() callback, entity driver should check that the properties of
the source pad of the connected entity and its own sink pad match. It is up
to the type of the entity (and in the end, the properties of the hardware)
what matching actually means.
Subsystems should facilitate link validation by providing subsystem specific
helper functions to provide easy access for commonly needed information, and
in the end provide a way to use driver-specific callbacks.
...@@ -214,23 +214,76 @@ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); ...@@ -214,23 +214,76 @@ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
* pipeline pointer must be identical for all nested calls to * pipeline pointer must be identical for all nested calls to
* media_entity_pipeline_start(). * media_entity_pipeline_start().
*/ */
void media_entity_pipeline_start(struct media_entity *entity, __must_check int media_entity_pipeline_start(struct media_entity *entity,
struct media_pipeline *pipe) struct media_pipeline *pipe)
{ {
struct media_device *mdev = entity->parent; struct media_device *mdev = entity->parent;
struct media_entity_graph graph; struct media_entity_graph graph;
struct media_entity *entity_err = entity;
int ret;
mutex_lock(&mdev->graph_mutex); mutex_lock(&mdev->graph_mutex);
media_entity_graph_walk_start(&graph, entity); media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) { while ((entity = media_entity_graph_walk_next(&graph))) {
unsigned int i;
entity->stream_count++; entity->stream_count++;
WARN_ON(entity->pipe && entity->pipe != pipe); WARN_ON(entity->pipe && entity->pipe != pipe);
entity->pipe = pipe; entity->pipe = pipe;
/* Already streaming --- no need to check. */
if (entity->stream_count > 1)
continue;
if (!entity->ops || !entity->ops->link_validate)
continue;
for (i = 0; i < entity->num_links; i++) {
struct media_link *link = &entity->links[i];
/* Is this pad part of an enabled link? */
if (!(link->flags & MEDIA_LNK_FL_ENABLED))
continue;
/* Are we the sink or not? */
if (link->sink->entity != entity)
continue;
ret = entity->ops->link_validate(link);
if (ret < 0 && ret != -ENOIOCTLCMD)
goto error;
}
} }
mutex_unlock(&mdev->graph_mutex); mutex_unlock(&mdev->graph_mutex);
return 0;
error:
/*
* Link validation on graph failed. We revert what we did and
* return the error.
*/
media_entity_graph_walk_start(&graph, entity_err);
while ((entity_err = media_entity_graph_walk_next(&graph))) {
entity_err->stream_count--;
if (entity_err->stream_count == 0)
entity_err->pipe = NULL;
/*
* We haven't increased stream_count further than this
* so we quit here.
*/
if (entity_err == entity)
break;
}
mutex_unlock(&mdev->graph_mutex);
return ret;
} }
EXPORT_SYMBOL_GPL(media_entity_pipeline_start); EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
......
...@@ -46,6 +46,7 @@ struct media_entity_operations { ...@@ -46,6 +46,7 @@ struct media_entity_operations {
int (*link_setup)(struct media_entity *entity, int (*link_setup)(struct media_entity *entity,
const struct media_pad *local, const struct media_pad *local,
const struct media_pad *remote, u32 flags); const struct media_pad *remote, u32 flags);
int (*link_validate)(struct media_link *link);
}; };
struct media_entity { struct media_entity {
...@@ -140,8 +141,8 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph, ...@@ -140,8 +141,8 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
struct media_entity *entity); struct media_entity *entity);
struct media_entity * struct media_entity *
media_entity_graph_walk_next(struct media_entity_graph *graph); media_entity_graph_walk_next(struct media_entity_graph *graph);
void media_entity_pipeline_start(struct media_entity *entity, __must_check int media_entity_pipeline_start(struct media_entity *entity,
struct media_pipeline *pipe); struct media_pipeline *pipe);
void media_entity_pipeline_stop(struct media_entity *entity); void media_entity_pipeline_stop(struct media_entity *entity);
#define media_entity_call(entity, operation, args...) \ #define media_entity_call(entity, operation, args...) \
......
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