From patchwork Thu Jan 27 12:30:34 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 511871 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p0RCYMDG004898 for ; Thu, 27 Jan 2011 12:34:40 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753869Ab1A0MdA (ORCPT ); Thu, 27 Jan 2011 07:33:00 -0500 Received: from perceval.ideasonboard.com ([95.142.166.194]:59804 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753267Ab1A0Map (ORCPT ); Thu, 27 Jan 2011 07:30:45 -0500 Received: from localhost.localdomain (unknown [91.178.11.103]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DCABD35CC7; Thu, 27 Jan 2011 12:30:39 +0000 (UTC) From: Laurent Pinchart To: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, alsa-devel@alsa-project.org Cc: sakari.ailus@maxwell.research.nokia.com, broonie@opensource.wolfsonmicro.com, clemens@ladisch.de Subject: [PATCH v8 09/12] media: Pipelines and media streams Date: Thu, 27 Jan 2011 13:30:34 +0100 Message-Id: <1296131437-29954-10-git-send-email-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 1.7.3.4 In-Reply-To: <1296131437-29954-1-git-send-email-laurent.pinchart@ideasonboard.com> References: <1296131437-29954-1-git-send-email-laurent.pinchart@ideasonboard.com> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 27 Jan 2011 12:34:40 +0000 (UTC) diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml index daf0360..b204bfb 100644 --- a/Documentation/DocBook/v4l/media-ioc-enum-links.xml +++ b/Documentation/DocBook/v4l/media-ioc-enum-links.xml @@ -179,6 +179,11 @@ The link enabled state can't be modified at runtime. An immutable link is always enabled. + + MEDIA_LNK_FL_DYNAMIC + The link enabled state can be modified during streaming. This + flag is set by drivers and is read-only for applications. + diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml index 09ab3d2..2331e76 100644 --- a/Documentation/DocBook/v4l/media-ioc-setup-link.xml +++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml @@ -60,6 +60,9 @@ Link configuration has no side effect on other links. If an enabled link at the sink pad prevents the link from being enabled, the driver returns with an &EBUSY;. + Only links marked with the DYNAMIC link flag can + be enabled/disabled while streaming media data. Attempting to enable or + disable a streaming non-dynamic link will return an &EBUSY;. If the specified link can't be found the driver returns with an &EINVAL;. diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt index 634845e..435d0c4 100644 --- a/Documentation/media-framework.txt +++ b/Documentation/media-framework.txt @@ -313,3 +313,41 @@ Link configuration must not have any side effect on other links. If an enabled link at a sink pad prevents another link at the same pad from being disabled, the link_setup operation must return -EBUSY and can't implicitly disable the first enabled link. + + +Pipelines and media streams +--------------------------- + +When starting streaming, drivers must notify all entities in the pipeline to +prevent link states from being modified during streaming by calling + + media_entity_pipeline_start(struct media_entity *entity, + struct media_pipeline *pipe); + +The function will mark all entities connected to the given entity through +enabled links, either directly or indirectly, as streaming. + +The media_pipeline instance pointed to by the pipe argument will be stored in +every entity in the pipeline. Drivers should embed the media_pipeline structure +in higher-level pipeline structures and can then access the pipeline through +the media_entity pipe field. + +Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must +be identical for all nested calls to the function. + +When stopping the stream, drivers must notify the entities with + + media_entity_pipeline_stop(struct media_entity *entity); + +If multiple calls to media_entity_pipeline_start() have been made the same +number of media_entity_pipeline_stop() calls are required to stop streaming. The +media_entity pipe field is reset to NULL on the last nested stop call. + +Link configuration will fail with -EBUSY by default if either end of the link is +a streaming entity. Links that can be modified while streaming must be marked +with the MEDIA_LNK_FL_DYNAMIC flag. + +If other operations need to be disallowed on streaming entities (such as +changing entities configuration parameters) drivers can explictly check the +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. diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index d703ce8..e63e089 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -197,6 +197,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) { diff --git a/include/linux/media.h b/include/linux/media.h index 2f67ed2..29039e8 100644 --- a/include/linux/media.h +++ b/include/linux/media.h @@ -106,6 +106,7 @@ struct media_pad_desc { #define MEDIA_LNK_FL_ENABLED (1 << 0) #define MEDIA_LNK_FL_IMMUTABLE (1 << 1) +#define MEDIA_LNK_FL_DYNAMIC (1 << 2) struct media_link_desc { struct media_pad_desc source; diff --git a/include/media/media-entity.h b/include/media/media-entity.h index 60fc7bd..450ba12 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -26,6 +26,9 @@ #include #include +struct media_pipeline { +}; + struct media_link { struct media_pad *source; /* Source pad */ struct media_pad *sink; /* Sink pad */ @@ -67,8 +70,11 @@ struct media_entity { const struct media_entity_operations *ops; /* Entity operations */ + int stream_count; /* Stream count for the entity. */ int use_count; /* Use count for the entity. */ + struct media_pipeline *pipe; /* Pipeline this entity belongs to. */ + union { /* Node specifications */ struct { @@ -114,6 +120,7 @@ struct media_entity_graph { int media_entity_init(struct media_entity *entity, u16 num_pads, struct media_pad *pads, u16 extra_links); void media_entity_cleanup(struct media_entity *entity); + int media_entity_create_link(struct media_entity *source, u16 source_pad, struct media_entity *sink, u16 sink_pad, u32 flags); int __media_entity_setup_link(struct media_link *link, u32 flags); @@ -129,6 +136,9 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph, struct media_entity *entity); struct media_entity * media_entity_graph_walk_next(struct media_entity_graph *graph); +void media_entity_pipeline_start(struct media_entity *entity, + struct media_pipeline *pipe); +void media_entity_pipeline_stop(struct media_entity *entity); #define media_entity_call(entity, operation, args...) \ (((entity)->ops && (entity)->ops->operation) ? \