diff options
-rw-r--r-- | Documentation/DocBook/v4l/media-ioc-enum-links.xml | 5 | ||||
-rw-r--r-- | Documentation/DocBook/v4l/media-ioc-setup-link.xml | 3 | ||||
-rw-r--r-- | Documentation/media-framework.txt | 38 | ||||
-rw-r--r-- | drivers/media/media-entity.c | 73 | ||||
-rw-r--r-- | include/linux/media.h | 1 | ||||
-rw-r--r-- | include/media/media-entity.h | 10 |
6 files changed, 130 insertions, 0 deletions
diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml index 6da884159cab..d2fc73ef8d56 100644 --- a/Documentation/DocBook/v4l/media-ioc-enum-links.xml +++ b/Documentation/DocBook/v4l/media-ioc-enum-links.xml | |||
@@ -179,6 +179,11 @@ | |||
179 | <entry>The link enabled state can't be modified at runtime. An | 179 | <entry>The link enabled state can't be modified at runtime. An |
180 | immutable link is always enabled.</entry> | 180 | immutable link is always enabled.</entry> |
181 | </row> | 181 | </row> |
182 | <row> | ||
183 | <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry> | ||
184 | <entry>The link enabled state can be modified during streaming. This | ||
185 | flag is set by drivers and is read-only for applications.</entry> | ||
186 | </row> | ||
182 | </tbody> | 187 | </tbody> |
183 | </tgroup> | 188 | </tgroup> |
184 | </table> | 189 | </table> |
diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml index 09ab3d2b3a52..2331e76ded17 100644 --- a/Documentation/DocBook/v4l/media-ioc-setup-link.xml +++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml | |||
@@ -60,6 +60,9 @@ | |||
60 | <para>Link configuration has no side effect on other links. If an enabled | 60 | <para>Link configuration has no side effect on other links. If an enabled |
61 | link at the sink pad prevents the link from being enabled, the driver | 61 | link at the sink pad prevents the link from being enabled, the driver |
62 | returns with an &EBUSY;.</para> | 62 | returns with an &EBUSY;.</para> |
63 | <para>Only links marked with the <constant>DYNAMIC</constant> link flag can | ||
64 | be enabled/disabled while streaming media data. Attempting to enable or | ||
65 | disable a streaming non-dynamic link will return an &EBUSY;.</para> | ||
63 | <para>If the specified link can't be found the driver returns with an | 66 | <para>If the specified link can't be found the driver returns with an |
64 | &EINVAL;.</para> | 67 | &EINVAL;.</para> |
65 | </refsect1> | 68 | </refsect1> |
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt index 4809221c0ff9..fd48add02cb0 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 | |||
313 | link at a sink pad prevents another link at the same pad from being disabled, | 313 | link at a sink pad prevents another link at the same pad from being disabled, |
314 | the link_setup operation must return -EBUSY and can't implicitly disable the | 314 | the link_setup operation must return -EBUSY and can't implicitly disable the |
315 | first enabled link. | 315 | first enabled link. |
316 | |||
317 | |||
318 | Pipelines and media streams | ||
319 | --------------------------- | ||
320 | |||
321 | When starting streaming, drivers must notify all entities in the pipeline to | ||
322 | prevent link states from being modified during streaming by calling | ||
323 | |||
324 | media_entity_pipeline_start(struct media_entity *entity, | ||
325 | struct media_pipeline *pipe); | ||
326 | |||
327 | The function will mark all entities connected to the given entity through | ||
328 | enabled links, either directly or indirectly, as streaming. | ||
329 | |||
330 | The media_pipeline instance pointed to by the pipe argument will be stored in | ||
331 | every entity in the pipeline. Drivers should embed the media_pipeline structure | ||
332 | in higher-level pipeline structures and can then access the pipeline through | ||
333 | the media_entity pipe field. | ||
334 | |||
335 | Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must | ||
336 | be identical for all nested calls to the function. | ||
337 | |||
338 | When stopping the stream, drivers must notify the entities with | ||
339 | |||
340 | media_entity_pipeline_stop(struct media_entity *entity); | ||
341 | |||
342 | If multiple calls to media_entity_pipeline_start() have been made the same | ||
343 | number of media_entity_pipeline_stop() calls are required to stop streaming. The | ||
344 | media_entity pipe field is reset to NULL on the last nested stop call. | ||
345 | |||
346 | Link configuration will fail with -EBUSY by default if either end of the link is | ||
347 | a streaming entity. Links that can be modified while streaming must be marked | ||
348 | with the MEDIA_LNK_FL_DYNAMIC flag. | ||
349 | |||
350 | If other operations need to be disallowed on streaming entities (such as | ||
351 | changing entities configuration parameters) drivers can explictly check the | ||
352 | media_entity stream_count field to find out if an entity is streaming. This | ||
353 | 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 6795c920d460..23640ed44d85 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) | |||
197 | EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); | 197 | EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); |
198 | 198 | ||
199 | /* ----------------------------------------------------------------------------- | 199 | /* ----------------------------------------------------------------------------- |
200 | * Pipeline management | ||
201 | */ | ||
202 | |||
203 | /** | ||
204 | * media_entity_pipeline_start - Mark a pipeline as streaming | ||
205 | * @entity: Starting entity | ||
206 | * @pipe: Media pipeline to be assigned to all entities in the pipeline. | ||
207 | * | ||
208 | * Mark all entities connected to a given entity through enabled links, either | ||
209 | * directly or indirectly, as streaming. The given pipeline object is assigned to | ||
210 | * every entity in the pipeline and stored in the media_entity pipe field. | ||
211 | * | ||
212 | * Calls to this function can be nested, in which case the same number of | ||
213 | * media_entity_pipeline_stop() calls will be required to stop streaming. The | ||
214 | * pipeline pointer must be identical for all nested calls to | ||
215 | * media_entity_pipeline_start(). | ||
216 | */ | ||
217 | void media_entity_pipeline_start(struct media_entity *entity, | ||
218 | struct media_pipeline *pipe) | ||
219 | { | ||
220 | struct media_device *mdev = entity->parent; | ||
221 | struct media_entity_graph graph; | ||
222 | |||
223 | mutex_lock(&mdev->graph_mutex); | ||
224 | |||
225 | media_entity_graph_walk_start(&graph, entity); | ||
226 | |||
227 | while ((entity = media_entity_graph_walk_next(&graph))) { | ||
228 | entity->stream_count++; | ||
229 | WARN_ON(entity->pipe && entity->pipe != pipe); | ||
230 | entity->pipe = pipe; | ||
231 | } | ||
232 | |||
233 | mutex_unlock(&mdev->graph_mutex); | ||
234 | } | ||
235 | EXPORT_SYMBOL_GPL(media_entity_pipeline_start); | ||
236 | |||
237 | /** | ||
238 | * media_entity_pipeline_stop - Mark a pipeline as not streaming | ||
239 | * @entity: Starting entity | ||
240 | * | ||
241 | * Mark all entities connected to a given entity through enabled links, either | ||
242 | * directly or indirectly, as not streaming. The media_entity pipe field is | ||
243 | * reset to NULL. | ||
244 | * | ||
245 | * If multiple calls to media_entity_pipeline_start() have been made, the same | ||
246 | * number of calls to this function are required to mark the pipeline as not | ||
247 | * streaming. | ||
248 | */ | ||
249 | void media_entity_pipeline_stop(struct media_entity *entity) | ||
250 | { | ||
251 | struct media_device *mdev = entity->parent; | ||
252 | struct media_entity_graph graph; | ||
253 | |||
254 | mutex_lock(&mdev->graph_mutex); | ||
255 | |||
256 | media_entity_graph_walk_start(&graph, entity); | ||
257 | |||
258 | while ((entity = media_entity_graph_walk_next(&graph))) { | ||
259 | entity->stream_count--; | ||
260 | if (entity->stream_count == 0) | ||
261 | entity->pipe = NULL; | ||
262 | } | ||
263 | |||
264 | mutex_unlock(&mdev->graph_mutex); | ||
265 | } | ||
266 | EXPORT_SYMBOL_GPL(media_entity_pipeline_stop); | ||
267 | |||
268 | /* ----------------------------------------------------------------------------- | ||
200 | * Module use count | 269 | * Module use count |
201 | */ | 270 | */ |
202 | 271 | ||
@@ -364,6 +433,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) | |||
364 | source = link->source->entity; | 433 | source = link->source->entity; |
365 | sink = link->sink->entity; | 434 | sink = link->sink->entity; |
366 | 435 | ||
436 | if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) && | ||
437 | (source->stream_count || sink->stream_count)) | ||
438 | return -EBUSY; | ||
439 | |||
367 | mdev = source->parent; | 440 | mdev = source->parent; |
368 | 441 | ||
369 | if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) { | 442 | if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) { |
diff --git a/include/linux/media.h b/include/linux/media.h index 7c69913c0ad2..7ed23b43f43b 100644 --- a/include/linux/media.h +++ b/include/linux/media.h | |||
@@ -106,6 +106,7 @@ struct media_pad_desc { | |||
106 | 106 | ||
107 | #define MEDIA_LNK_FL_ENABLED (1 << 0) | 107 | #define MEDIA_LNK_FL_ENABLED (1 << 0) |
108 | #define MEDIA_LNK_FL_IMMUTABLE (1 << 1) | 108 | #define MEDIA_LNK_FL_IMMUTABLE (1 << 1) |
109 | #define MEDIA_LNK_FL_DYNAMIC (1 << 2) | ||
109 | 110 | ||
110 | struct media_link_desc { | 111 | struct media_link_desc { |
111 | struct media_pad_desc source; | 112 | struct media_pad_desc source; |
diff --git a/include/media/media-entity.h b/include/media/media-entity.h index d889dcc67d0d..cd8bca63a502 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h | |||
@@ -26,6 +26,9 @@ | |||
26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
27 | #include <linux/media.h> | 27 | #include <linux/media.h> |
28 | 28 | ||
29 | struct media_pipeline { | ||
30 | }; | ||
31 | |||
29 | struct media_link { | 32 | struct media_link { |
30 | struct media_pad *source; /* Source pad */ | 33 | struct media_pad *source; /* Source pad */ |
31 | struct media_pad *sink; /* Sink pad */ | 34 | struct media_pad *sink; /* Sink pad */ |
@@ -71,8 +74,11 @@ struct media_entity { | |||
71 | * purpose: a simple WARN_ON(<0) check can be used to detect reference | 74 | * purpose: a simple WARN_ON(<0) check can be used to detect reference |
72 | * count bugs that would make them negative. | 75 | * count bugs that would make them negative. |
73 | */ | 76 | */ |
77 | int stream_count; /* Stream count for the entity. */ | ||
74 | int use_count; /* Use count for the entity. */ | 78 | int use_count; /* Use count for the entity. */ |
75 | 79 | ||
80 | struct media_pipeline *pipe; /* Pipeline this entity belongs to. */ | ||
81 | |||
76 | union { | 82 | union { |
77 | /* Node specifications */ | 83 | /* Node specifications */ |
78 | struct { | 84 | struct { |
@@ -118,6 +124,7 @@ struct media_entity_graph { | |||
118 | int media_entity_init(struct media_entity *entity, u16 num_pads, | 124 | int media_entity_init(struct media_entity *entity, u16 num_pads, |
119 | struct media_pad *pads, u16 extra_links); | 125 | struct media_pad *pads, u16 extra_links); |
120 | void media_entity_cleanup(struct media_entity *entity); | 126 | void media_entity_cleanup(struct media_entity *entity); |
127 | |||
121 | int media_entity_create_link(struct media_entity *source, u16 source_pad, | 128 | int media_entity_create_link(struct media_entity *source, u16 source_pad, |
122 | struct media_entity *sink, u16 sink_pad, u32 flags); | 129 | struct media_entity *sink, u16 sink_pad, u32 flags); |
123 | int __media_entity_setup_link(struct media_link *link, u32 flags); | 130 | int __media_entity_setup_link(struct media_link *link, u32 flags); |
@@ -133,6 +140,9 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph, | |||
133 | struct media_entity *entity); | 140 | struct media_entity *entity); |
134 | struct media_entity * | 141 | struct media_entity * |
135 | media_entity_graph_walk_next(struct media_entity_graph *graph); | 142 | media_entity_graph_walk_next(struct media_entity_graph *graph); |
143 | void media_entity_pipeline_start(struct media_entity *entity, | ||
144 | struct media_pipeline *pipe); | ||
145 | void media_entity_pipeline_stop(struct media_entity *entity); | ||
136 | 146 | ||
137 | #define media_entity_call(entity, operation, args...) \ | 147 | #define media_entity_call(entity, operation, args...) \ |
138 | (((entity)->ops && (entity)->ops->operation) ? \ | 148 | (((entity)->ops && (entity)->ops->operation) ? \ |