Commit 97548ed4c4661502cdfd1aabd5d3876fa4f5cc2e
Committed by
Mauro Carvalho Chehab
1 parent
1651333b09
Exists in
master
and in
39 other branches
[media] media: Links setup
Create the following ioctl and implement it at the media device level to setup links. - MEDIA_IOC_SETUP_LINK: Modify the properties of a given link The only property that can currently be modified is the ENABLED link flag to enable/disable a link. Links marked with the IMMUTABLE link flag can not be enabled or disabled. Enabling or disabling a link has effects on entities' use count. Those changes are automatically propagated through the graph. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com> Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi> Acked-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Showing 9 changed files with 356 additions and 0 deletions Side-by-side Diff
- Documentation/DocBook/media-entities.tmpl
- Documentation/DocBook/v4l/media-controller.xml
- Documentation/DocBook/v4l/media-ioc-setup-link.xml
- Documentation/media-framework.txt
- drivers/media/media-device.c
- drivers/media/media-entity.c
- include/linux/media.h
- include/media/media-device.h
- include/media/media-entity.h
Documentation/DocBook/media-entities.tmpl
... | ... | @@ -94,6 +94,7 @@ |
94 | 94 | <!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>"> |
95 | 95 | <!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>"> |
96 | 96 | <!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>"> |
97 | +<!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>"> | |
97 | 98 | |
98 | 99 | <!-- Types --> |
99 | 100 | <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>"> |
... | ... | @@ -348,6 +349,7 @@ |
348 | 349 | <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml"> |
349 | 350 | <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml"> |
350 | 351 | <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml"> |
352 | +<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml"> | |
351 | 353 | |
352 | 354 | <!-- Function Reference --> |
353 | 355 | <!ENTITY close SYSTEM "v4l/func-close.xml"> |
Documentation/DocBook/v4l/media-controller.xml
Documentation/DocBook/v4l/media-ioc-setup-link.xml
1 | +<refentry id="media-ioc-setup-link"> | |
2 | + <refmeta> | |
3 | + <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle> | |
4 | + &manvol; | |
5 | + </refmeta> | |
6 | + | |
7 | + <refnamediv> | |
8 | + <refname>MEDIA_IOC_SETUP_LINK</refname> | |
9 | + <refpurpose>Modify the properties of a link</refpurpose> | |
10 | + </refnamediv> | |
11 | + | |
12 | + <refsynopsisdiv> | |
13 | + <funcsynopsis> | |
14 | + <funcprototype> | |
15 | + <funcdef>int <function>ioctl</function></funcdef> | |
16 | + <paramdef>int <parameter>fd</parameter></paramdef> | |
17 | + <paramdef>int <parameter>request</parameter></paramdef> | |
18 | + <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef> | |
19 | + </funcprototype> | |
20 | + </funcsynopsis> | |
21 | + </refsynopsisdiv> | |
22 | + | |
23 | + <refsect1> | |
24 | + <title>Arguments</title> | |
25 | + | |
26 | + <variablelist> | |
27 | + <varlistentry> | |
28 | + <term><parameter>fd</parameter></term> | |
29 | + <listitem> | |
30 | + <para>File descriptor returned by | |
31 | + <link linkend='media-func-open'><function>open()</function></link>.</para> | |
32 | + </listitem> | |
33 | + </varlistentry> | |
34 | + <varlistentry> | |
35 | + <term><parameter>request</parameter></term> | |
36 | + <listitem> | |
37 | + <para>MEDIA_IOC_ENUM_LINKS</para> | |
38 | + </listitem> | |
39 | + </varlistentry> | |
40 | + <varlistentry> | |
41 | + <term><parameter>argp</parameter></term> | |
42 | + <listitem> | |
43 | + <para></para> | |
44 | + </listitem> | |
45 | + </varlistentry> | |
46 | + </variablelist> | |
47 | + </refsect1> | |
48 | + | |
49 | + <refsect1> | |
50 | + <title>Description</title> | |
51 | + | |
52 | + <para>To change link properties applications fill a &media-link-desc; with | |
53 | + link identification information (source and sink pad) and the new requested | |
54 | + link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to | |
55 | + that structure.</para> | |
56 | + <para>The only configurable property is the <constant>ENABLED</constant> | |
57 | + link flag to enable/disable a link. Links marked with the | |
58 | + <constant>IMMUTABLE</constant> link flag can not be enabled or disabled. | |
59 | + </para> | |
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 | |
62 | + returns with an &EBUSY;.</para> | |
63 | + <para>If the specified link can't be found the driver returns with an | |
64 | + &EINVAL;.</para> | |
65 | + </refsect1> | |
66 | + | |
67 | + <refsect1> | |
68 | + &return-value; | |
69 | + | |
70 | + <variablelist> | |
71 | + <varlistentry> | |
72 | + <term><errorcode>EBUSY</errorcode></term> | |
73 | + <listitem> | |
74 | + <para>The link properties can't be changed because the link is | |
75 | + currently busy. This can be caused, for instance, by an active media | |
76 | + stream (audio or video) on the link. The ioctl shouldn't be retried if | |
77 | + no other action is performed before to fix the problem.</para> | |
78 | + </listitem> | |
79 | + </varlistentry> | |
80 | + <varlistentry> | |
81 | + <term><errorcode>EINVAL</errorcode></term> | |
82 | + <listitem> | |
83 | + <para>The &media-link-desc; references a non-existing link, or the | |
84 | + link is immutable and an attempt to modify its configuration was made. | |
85 | + </para> | |
86 | + </listitem> | |
87 | + </varlistentry> | |
88 | + </variablelist> | |
89 | + </refsect1> | |
90 | +</refentry> |
Documentation/media-framework.txt
... | ... | @@ -259,7 +259,17 @@ |
259 | 259 | Graph traversal can be interrupted at any moment. No cleanup function call is |
260 | 260 | required and the graph structure can be freed normally. |
261 | 261 | |
262 | +Helper functions can be used to find a link between two given pads, or a pad | |
263 | +connected to another pad through an enabled link | |
262 | 264 | |
265 | + media_entity_find_link(struct media_pad *source, | |
266 | + struct media_pad *sink); | |
267 | + | |
268 | + media_entity_remote_source(struct media_pad *pad); | |
269 | + | |
270 | +Refer to the kerneldoc documentation for more information. | |
271 | + | |
272 | + | |
263 | 273 | Use count and power handling |
264 | 274 | ---------------------------- |
265 | 275 | |
... | ... | @@ -271,4 +281,36 @@ |
271 | 281 | The use_count field is owned by media drivers and must not be touched by entity |
272 | 282 | drivers. Access to the field must be protected by the media device graph_mutex |
273 | 283 | lock. |
284 | + | |
285 | + | |
286 | +Links setup | |
287 | +----------- | |
288 | + | |
289 | +Link properties can be modified at runtime by calling | |
290 | + | |
291 | + media_entity_setup_link(struct media_link *link, u32 flags); | |
292 | + | |
293 | +The flags argument contains the requested new link flags. | |
294 | + | |
295 | +The only configurable property is the ENABLED link flag to enable/disable a | |
296 | +link. Links marked with the IMMUTABLE link flag can not be enabled or disabled. | |
297 | + | |
298 | +When a link is enabled or disabled, the media framework calls the | |
299 | +link_setup operation for the two entities at the source and sink of the link, | |
300 | +in that order. If the second link_setup call fails, another link_setup call is | |
301 | +made on the first entity to restore the original link flags. | |
302 | + | |
303 | +Media device drivers can be notified of link setup operations by setting the | |
304 | +media_device::link_notify pointer to a callback function. If provided, the | |
305 | +notification callback will be called before enabling and after disabling | |
306 | +links. | |
307 | + | |
308 | +Entity drivers must implement the link_setup operation if any of their links | |
309 | +is non-immutable. The operation must either configure the hardware or store | |
310 | +the configuration information to be applied later. | |
311 | + | |
312 | +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, | |
314 | +the link_setup operation must return -EBUSY and can't implicitly disable the | |
315 | +first enabled link. |
drivers/media/media-device.c
... | ... | @@ -172,6 +172,44 @@ |
172 | 172 | return 0; |
173 | 173 | } |
174 | 174 | |
175 | +static long media_device_setup_link(struct media_device *mdev, | |
176 | + struct media_link_desc __user *_ulink) | |
177 | +{ | |
178 | + struct media_link *link = NULL; | |
179 | + struct media_link_desc ulink; | |
180 | + struct media_entity *source; | |
181 | + struct media_entity *sink; | |
182 | + int ret; | |
183 | + | |
184 | + if (copy_from_user(&ulink, _ulink, sizeof(ulink))) | |
185 | + return -EFAULT; | |
186 | + | |
187 | + /* Find the source and sink entities and link. | |
188 | + */ | |
189 | + source = find_entity(mdev, ulink.source.entity); | |
190 | + sink = find_entity(mdev, ulink.sink.entity); | |
191 | + | |
192 | + if (source == NULL || sink == NULL) | |
193 | + return -EINVAL; | |
194 | + | |
195 | + if (ulink.source.index >= source->num_pads || | |
196 | + ulink.sink.index >= sink->num_pads) | |
197 | + return -EINVAL; | |
198 | + | |
199 | + link = media_entity_find_link(&source->pads[ulink.source.index], | |
200 | + &sink->pads[ulink.sink.index]); | |
201 | + if (link == NULL) | |
202 | + return -EINVAL; | |
203 | + | |
204 | + /* Setup the link on both entities. */ | |
205 | + ret = __media_entity_setup_link(link, ulink.flags); | |
206 | + | |
207 | + if (copy_to_user(_ulink, &ulink, sizeof(ulink))) | |
208 | + return -EFAULT; | |
209 | + | |
210 | + return ret; | |
211 | +} | |
212 | + | |
175 | 213 | static long media_device_ioctl(struct file *filp, unsigned int cmd, |
176 | 214 | unsigned long arg) |
177 | 215 | { |
... | ... | @@ -194,6 +232,13 @@ |
194 | 232 | mutex_lock(&dev->graph_mutex); |
195 | 233 | ret = media_device_enum_links(dev, |
196 | 234 | (struct media_links_enum __user *)arg); |
235 | + mutex_unlock(&dev->graph_mutex); | |
236 | + break; | |
237 | + | |
238 | + case MEDIA_IOC_SETUP_LINK: | |
239 | + mutex_lock(&dev->graph_mutex); | |
240 | + ret = media_device_setup_link(dev, | |
241 | + (struct media_link_desc __user *)arg); | |
197 | 242 | mutex_unlock(&dev->graph_mutex); |
198 | 243 | break; |
199 | 244 |
drivers/media/media-entity.c
... | ... | @@ -306,4 +306,159 @@ |
306 | 306 | return 0; |
307 | 307 | } |
308 | 308 | EXPORT_SYMBOL_GPL(media_entity_create_link); |
309 | + | |
310 | +static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) | |
311 | +{ | |
312 | + const u32 mask = MEDIA_LNK_FL_ENABLED; | |
313 | + int ret; | |
314 | + | |
315 | + /* Notify both entities. */ | |
316 | + ret = media_entity_call(link->source->entity, link_setup, | |
317 | + link->source, link->sink, flags); | |
318 | + if (ret < 0 && ret != -ENOIOCTLCMD) | |
319 | + return ret; | |
320 | + | |
321 | + ret = media_entity_call(link->sink->entity, link_setup, | |
322 | + link->sink, link->source, flags); | |
323 | + if (ret < 0 && ret != -ENOIOCTLCMD) { | |
324 | + media_entity_call(link->source->entity, link_setup, | |
325 | + link->source, link->sink, link->flags); | |
326 | + return ret; | |
327 | + } | |
328 | + | |
329 | + link->flags = (link->flags & ~mask) | (flags & mask); | |
330 | + link->reverse->flags = link->flags; | |
331 | + | |
332 | + return 0; | |
333 | +} | |
334 | + | |
335 | +/** | |
336 | + * __media_entity_setup_link - Configure a media link | |
337 | + * @link: The link being configured | |
338 | + * @flags: Link configuration flags | |
339 | + * | |
340 | + * The bulk of link setup is handled by the two entities connected through the | |
341 | + * link. This function notifies both entities of the link configuration change. | |
342 | + * | |
343 | + * If the link is immutable or if the current and new configuration are | |
344 | + * identical, return immediately. | |
345 | + * | |
346 | + * The user is expected to hold link->source->parent->mutex. If not, | |
347 | + * media_entity_setup_link() should be used instead. | |
348 | + */ | |
349 | +int __media_entity_setup_link(struct media_link *link, u32 flags) | |
350 | +{ | |
351 | + struct media_device *mdev; | |
352 | + struct media_entity *source, *sink; | |
353 | + int ret = -EBUSY; | |
354 | + | |
355 | + if (link == NULL) | |
356 | + return -EINVAL; | |
357 | + | |
358 | + if (link->flags & MEDIA_LNK_FL_IMMUTABLE) | |
359 | + return link->flags == flags ? 0 : -EINVAL; | |
360 | + | |
361 | + if (link->flags == flags) | |
362 | + return 0; | |
363 | + | |
364 | + source = link->source->entity; | |
365 | + sink = link->sink->entity; | |
366 | + | |
367 | + mdev = source->parent; | |
368 | + | |
369 | + if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) { | |
370 | + ret = mdev->link_notify(link->source, link->sink, | |
371 | + MEDIA_LNK_FL_ENABLED); | |
372 | + if (ret < 0) | |
373 | + return ret; | |
374 | + } | |
375 | + | |
376 | + ret = __media_entity_setup_link_notify(link, flags); | |
377 | + if (ret < 0) | |
378 | + goto err; | |
379 | + | |
380 | + if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) | |
381 | + mdev->link_notify(link->source, link->sink, 0); | |
382 | + | |
383 | + return 0; | |
384 | + | |
385 | +err: | |
386 | + if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) | |
387 | + mdev->link_notify(link->source, link->sink, 0); | |
388 | + | |
389 | + return ret; | |
390 | +} | |
391 | + | |
392 | +int media_entity_setup_link(struct media_link *link, u32 flags) | |
393 | +{ | |
394 | + int ret; | |
395 | + | |
396 | + mutex_lock(&link->source->entity->parent->graph_mutex); | |
397 | + ret = __media_entity_setup_link(link, flags); | |
398 | + mutex_unlock(&link->source->entity->parent->graph_mutex); | |
399 | + | |
400 | + return ret; | |
401 | +} | |
402 | +EXPORT_SYMBOL_GPL(media_entity_setup_link); | |
403 | + | |
404 | +/** | |
405 | + * media_entity_find_link - Find a link between two pads | |
406 | + * @source: Source pad | |
407 | + * @sink: Sink pad | |
408 | + * | |
409 | + * Return a pointer to the link between the two entities. If no such link | |
410 | + * exists, return NULL. | |
411 | + */ | |
412 | +struct media_link * | |
413 | +media_entity_find_link(struct media_pad *source, struct media_pad *sink) | |
414 | +{ | |
415 | + struct media_link *link; | |
416 | + unsigned int i; | |
417 | + | |
418 | + for (i = 0; i < source->entity->num_links; ++i) { | |
419 | + link = &source->entity->links[i]; | |
420 | + | |
421 | + if (link->source->entity == source->entity && | |
422 | + link->source->index == source->index && | |
423 | + link->sink->entity == sink->entity && | |
424 | + link->sink->index == sink->index) | |
425 | + return link; | |
426 | + } | |
427 | + | |
428 | + return NULL; | |
429 | +} | |
430 | +EXPORT_SYMBOL_GPL(media_entity_find_link); | |
431 | + | |
432 | +/** | |
433 | + * media_entity_remote_source - Find the source pad at the remote end of a link | |
434 | + * @pad: Sink pad at the local end of the link | |
435 | + * | |
436 | + * Search for a remote source pad connected to the given sink pad by iterating | |
437 | + * over all links originating or terminating at that pad until an enabled link | |
438 | + * is found. | |
439 | + * | |
440 | + * Return a pointer to the pad at the remote end of the first found enabled | |
441 | + * link, or NULL if no enabled link has been found. | |
442 | + */ | |
443 | +struct media_pad *media_entity_remote_source(struct media_pad *pad) | |
444 | +{ | |
445 | + unsigned int i; | |
446 | + | |
447 | + for (i = 0; i < pad->entity->num_links; i++) { | |
448 | + struct media_link *link = &pad->entity->links[i]; | |
449 | + | |
450 | + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) | |
451 | + continue; | |
452 | + | |
453 | + if (link->source == pad) | |
454 | + return link->sink; | |
455 | + | |
456 | + if (link->sink == pad) | |
457 | + return link->source; | |
458 | + } | |
459 | + | |
460 | + return NULL; | |
461 | + | |
462 | +} | |
463 | +EXPORT_SYMBOL_GPL(media_entity_remote_source); |
include/linux/media.h
... | ... | @@ -126,6 +126,7 @@ |
126 | 126 | #define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info) |
127 | 127 | #define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc) |
128 | 128 | #define MEDIA_IOC_ENUM_LINKS _IOWR('M', 3, struct media_links_enum) |
129 | +#define MEDIA_IOC_SETUP_LINK _IOWR('M', 4, struct media_link_desc) | |
129 | 130 | |
130 | 131 | #endif /* __LINUX_MEDIA_H */ |
include/media/media-device.h
include/media/media-entity.h
... | ... | @@ -39,6 +39,12 @@ |
39 | 39 | unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */ |
40 | 40 | }; |
41 | 41 | |
42 | +struct media_entity_operations { | |
43 | + int (*link_setup)(struct media_entity *entity, | |
44 | + const struct media_pad *local, | |
45 | + const struct media_pad *remote, u32 flags); | |
46 | +}; | |
47 | + | |
42 | 48 | struct media_entity { |
43 | 49 | struct list_head list; |
44 | 50 | struct media_device *parent; /* Media device this entity belongs to*/ |
... | ... | @@ -59,6 +65,8 @@ |
59 | 65 | struct media_pad *pads; /* Pads array (num_pads elements) */ |
60 | 66 | struct media_link *links; /* Links array (max_links elements)*/ |
61 | 67 | |
68 | + const struct media_entity_operations *ops; /* Entity operations */ | |
69 | + | |
62 | 70 | /* Reference counts must never be negative, but are signed integers on |
63 | 71 | * purpose: a simple WARN_ON(<0) check can be used to detect reference |
64 | 72 | * count bugs that would make them negative. |
... | ... | @@ -112,6 +120,11 @@ |
112 | 120 | void media_entity_cleanup(struct media_entity *entity); |
113 | 121 | int media_entity_create_link(struct media_entity *source, u16 source_pad, |
114 | 122 | struct media_entity *sink, u16 sink_pad, u32 flags); |
123 | +int __media_entity_setup_link(struct media_link *link, u32 flags); | |
124 | +int media_entity_setup_link(struct media_link *link, u32 flags); | |
125 | +struct media_link *media_entity_find_link(struct media_pad *source, | |
126 | + struct media_pad *sink); | |
127 | +struct media_pad *media_entity_remote_source(struct media_pad *pad); | |
115 | 128 | |
116 | 129 | struct media_entity *media_entity_get(struct media_entity *entity); |
117 | 130 | void media_entity_put(struct media_entity *entity); |
... | ... | @@ -120,6 +133,10 @@ |
120 | 133 | struct media_entity *entity); |
121 | 134 | struct media_entity * |
122 | 135 | media_entity_graph_walk_next(struct media_entity_graph *graph); |
136 | + | |
137 | +#define media_entity_call(entity, operation, args...) \ | |
138 | + (((entity)->ops && (entity)->ops->operation) ? \ | |
139 | + (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD) | |
123 | 140 | |
124 | 141 | #endif |