Add new variant of media_pipeline_start(), media_pipeline_alloc_start(). media_pipeline_alloc_start() can be used by drivers that do not need to extend the media_pipeline. The function will either use the pipeline already associated with the entity, if such exists, or allocate a new pipeline. When media_pipeline_stop() is called and the pipeline's use count drops to zero, the pipeline is automatically freed. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@xxxxxxxxxxxxxxxx> --- drivers/media/mc/mc-entity.c | 41 ++++++++++++++++++++++++++++++ drivers/media/v4l2-core/v4l2-dev.c | 11 ++++++++ include/media/media-entity.h | 14 ++++++++++ include/media/v4l2-dev.h | 14 ++++++++++ 4 files changed, 80 insertions(+) diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index b1abaa333d13..d277eed11caf 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -529,6 +529,8 @@ void __media_pipeline_stop(struct media_entity *entity) media_graph_walk_cleanup(graph); + if (pipe->allocated) + kfree(pipe); } EXPORT_SYMBOL_GPL(__media_pipeline_stop); @@ -542,6 +544,45 @@ void media_pipeline_stop(struct media_entity *entity) } EXPORT_SYMBOL_GPL(media_pipeline_stop); +__must_check int media_pipeline_alloc_start(struct media_entity *entity) +{ + struct media_device *mdev = entity->graph_obj.mdev; + struct media_pipeline *pipe; + int ret; + bool new_pipe = false; + + mutex_lock(&mdev->graph_mutex); + + /* + * Is the entity already part of a pipeline? If not, we need to allocate + * a pipe. + */ + pipe = media_entity_pipeline(entity); + if (!pipe) { + pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); + + if (!pipe) { + ret = -ENOMEM; + goto out; + } + + new_pipe = true; + pipe->allocated = true; + } + + ret = __media_pipeline_start(entity, pipe); + if (ret) { + if (new_pipe) + kfree(pipe); + } + +out: + mutex_unlock(&mdev->graph_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(media_pipeline_alloc_start); + /* ----------------------------------------------------------------------------- * Links management */ diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 7f933ff89fd4..945bb867a4c1 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -1143,6 +1143,17 @@ void __video_device_pipeline_stop(struct video_device *vdev) } EXPORT_SYMBOL_GPL(__video_device_pipeline_stop); +__must_check int video_device_pipeline_alloc_start(struct video_device *vdev) +{ + struct media_entity *entity = &vdev->entity; + + if (entity->num_pads != 1) + return -ENODEV; + + return media_pipeline_alloc_start(entity); +} +EXPORT_SYMBOL_GPL(video_device_pipeline_alloc_start); + struct media_pipeline *video_device_pipeline(struct video_device *vdev) { struct media_entity *entity = &vdev->entity; diff --git a/include/media/media-entity.h b/include/media/media-entity.h index 3438954892b7..3d0d5e3c3333 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -104,6 +104,7 @@ struct media_graph { * @graph: Media graph walk during pipeline start / stop */ struct media_pipeline { + bool allocated; int start_count; struct media_graph graph; }; @@ -1028,6 +1029,19 @@ void media_pipeline_stop(struct media_entity *entity); */ void __media_pipeline_stop(struct media_entity *entity); +/** + * media_pipeline_alloc_start - Mark a pipeline as streaming + * @entity: Starting entity + * + * media_pipeline_alloc_start() is similar to media_pipeline_start() but instead + * of working on a given pipeline the function will use an existing pipeline if + * the entity is already part of a pipeline, or allocate a new pipeline. + * + * Calls to media_pipeline_alloc_start() must be matched with + * media_pipeline_stop(). + */ +__must_check int media_pipeline_alloc_start(struct media_entity *entity); + /** * media_devnode_create() - creates and initializes a device node interface * diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 4ccc24f5918a..29eb61244d1f 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -609,6 +609,20 @@ void video_device_pipeline_stop(struct video_device *vdev); */ void __video_device_pipeline_stop(struct video_device *vdev); +/** + * video_device_pipeline_alloc_start - Mark a pipeline as streaming + * @vdev: Starting video device + * + * video_device_pipeline_alloc_start() is similar to video_device_pipeline_start() + * but instead of working on a given pipeline the function will use an + * existing pipeline if the video device is already part of a pipeline, or + * allocate a new pipeline. + * + * Calls to video_device_pipeline_alloc_start() must be matched with + * video_device_pipeline_stop(). + */ +__must_check int video_device_pipeline_alloc_start(struct video_device *vdev); + /** * video_device_pipeline - Get the media pipeline a video device is part of * @vdev: The video device -- 2.34.1