|
@@ -196,6 +196,75 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
|
|
|
|
|
|
+/* -----------------------------------------------------------------------------
|
|
|
+ * Pipeline management
|
|
|
+ */
|
|
|
+
|
|
|
+/**
|
|
|
+ * media_entity_pipeline_start - Mark a pipeline as streaming
|
|
|
+ * @entity: Starting entity
|
|
|
+ * @pipe: Media pipeline to be assigned to all entities in the pipeline.
|
|
|
+ *
|
|
|
+ * Mark all entities connected to a given entity through enabled links, either
|
|
|
+ * directly or indirectly, as streaming. The given pipeline object is assigned to
|
|
|
+ * every entity in the pipeline and stored in the media_entity pipe field.
|
|
|
+ *
|
|
|
+ * Calls to this function can be nested, in which case the same number of
|
|
|
+ * media_entity_pipeline_stop() calls will be required to stop streaming. The
|
|
|
+ * pipeline pointer must be identical for all nested calls to
|
|
|
+ * media_entity_pipeline_start().
|
|
|
+ */
|
|
|
+void media_entity_pipeline_start(struct media_entity *entity,
|
|
|
+ struct media_pipeline *pipe)
|
|
|
+{
|
|
|
+ struct media_device *mdev = entity->parent;
|
|
|
+ struct media_entity_graph graph;
|
|
|
+
|
|
|
+ mutex_lock(&mdev->graph_mutex);
|
|
|
+
|
|
|
+ media_entity_graph_walk_start(&graph, entity);
|
|
|
+
|
|
|
+ while ((entity = media_entity_graph_walk_next(&graph))) {
|
|
|
+ entity->stream_count++;
|
|
|
+ WARN_ON(entity->pipe && entity->pipe != pipe);
|
|
|
+ entity->pipe = pipe;
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_unlock(&mdev->graph_mutex);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
|
|
|
+
|
|
|
+/**
|
|
|
+ * media_entity_pipeline_stop - Mark a pipeline as not streaming
|
|
|
+ * @entity: Starting entity
|
|
|
+ *
|
|
|
+ * Mark all entities connected to a given entity through enabled links, either
|
|
|
+ * directly or indirectly, as not streaming. The media_entity pipe field is
|
|
|
+ * reset to NULL.
|
|
|
+ *
|
|
|
+ * If multiple calls to media_entity_pipeline_start() have been made, the same
|
|
|
+ * number of calls to this function are required to mark the pipeline as not
|
|
|
+ * streaming.
|
|
|
+ */
|
|
|
+void media_entity_pipeline_stop(struct media_entity *entity)
|
|
|
+{
|
|
|
+ struct media_device *mdev = entity->parent;
|
|
|
+ struct media_entity_graph graph;
|
|
|
+
|
|
|
+ mutex_lock(&mdev->graph_mutex);
|
|
|
+
|
|
|
+ media_entity_graph_walk_start(&graph, entity);
|
|
|
+
|
|
|
+ while ((entity = media_entity_graph_walk_next(&graph))) {
|
|
|
+ entity->stream_count--;
|
|
|
+ if (entity->stream_count == 0)
|
|
|
+ entity->pipe = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_unlock(&mdev->graph_mutex);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
|
|
|
+
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
* Module use count
|
|
|
*/
|
|
@@ -364,6 +433,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags)
|
|
|
source = link->source->entity;
|
|
|
sink = link->sink->entity;
|
|
|
|
|
|
+ if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
|
|
|
+ (source->stream_count || sink->stream_count))
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
mdev = source->parent;
|
|
|
|
|
|
if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
|