aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2009-12-09 06:40:03 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-22 03:53:16 -0400
commit97548ed4c4661502cdfd1aabd5d3876fa4f5cc2e (patch)
treec85b85954f53e3a97b6590de8d5d5396e7c43358
parent1651333b09743887bc2dd3d158a11853a2be3fe7 (diff)
[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>
-rw-r--r--Documentation/DocBook/media-entities.tmpl2
-rw-r--r--Documentation/DocBook/v4l/media-controller.xml1
-rw-r--r--Documentation/DocBook/v4l/media-ioc-setup-link.xml90
-rw-r--r--Documentation/media-framework.txt42
-rw-r--r--drivers/media/media-device.c45
-rw-r--r--drivers/media/media-entity.c155
-rw-r--r--include/linux/media.h1
-rw-r--r--include/media/media-device.h3
-rw-r--r--include/media/media-entity.h17
9 files changed, 356 insertions, 0 deletions
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index 2bd7b27f855..121db154924 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -94,6 +94,7 @@
94<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>"> 94<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
95<!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>"> 95<!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
96<!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>"> 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<!-- Types --> 99<!-- Types -->
99<!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>"> 100<!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
@@ -348,6 +349,7 @@
348<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml"> 349<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
349<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml"> 350<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
350<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml"> 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<!-- Function Reference --> 354<!-- Function Reference -->
353<!ENTITY close SYSTEM "v4l/func-close.xml"> 355<!ENTITY close SYSTEM "v4l/func-close.xml">
diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
index 2c4fd2b2768..2dc25e1d408 100644
--- a/Documentation/DocBook/v4l/media-controller.xml
+++ b/Documentation/DocBook/v4l/media-controller.xml
@@ -85,4 +85,5 @@
85 &sub-media-ioc-device-info; 85 &sub-media-ioc-device-info;
86 &sub-media-ioc-enum-entities; 86 &sub-media-ioc-enum-entities;
87 &sub-media-ioc-enum-links; 87 &sub-media-ioc-enum-links;
88 &sub-media-ioc-setup-link;
88</appendix> 89</appendix>
diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
new file mode 100644
index 00000000000..09ab3d2b3a5
--- /dev/null
+++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
@@ -0,0 +1,90 @@
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>
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 78ae0209537..4809221c0ff 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -259,6 +259,16 @@ When the graph traversal is complete the function will return NULL.
259Graph traversal can be interrupted at any moment. No cleanup function call is 259Graph traversal can be interrupted at any moment. No cleanup function call is
260required and the graph structure can be freed normally. 260required and the graph structure can be freed normally.
261 261
262Helper functions can be used to find a link between two given pads, or a pad
263connected to another pad through an enabled link
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
270Refer to the kerneldoc documentation for more information.
271
262 272
263Use count and power handling 273Use count and power handling
264---------------------------- 274----------------------------
@@ -271,3 +281,35 @@ track the number of users of every entity for power management needs.
271The use_count field is owned by media drivers and must not be touched by entity 281The use_count field is owned by media drivers and must not be touched by entity
272drivers. Access to the field must be protected by the media device graph_mutex 282drivers. Access to the field must be protected by the media device graph_mutex
273lock. 283lock.
284
285
286Links setup
287-----------
288
289Link properties can be modified at runtime by calling
290
291 media_entity_setup_link(struct media_link *link, u32 flags);
292
293The flags argument contains the requested new link flags.
294
295The only configurable property is the ENABLED link flag to enable/disable a
296link. Links marked with the IMMUTABLE link flag can not be enabled or disabled.
297
298When a link is enabled or disabled, the media framework calls the
299link_setup operation for the two entities at the source and sink of the link,
300in that order. If the second link_setup call fails, another link_setup call is
301made on the first entity to restore the original link flags.
302
303Media device drivers can be notified of link setup operations by setting the
304media_device::link_notify pointer to a callback function. If provided, the
305notification callback will be called before enabling and after disabling
306links.
307
308Entity drivers must implement the link_setup operation if any of their links
309is non-immutable. The operation must either configure the hardware or store
310the configuration information to be applied later.
311
312Link configuration must not have any side effect on other links. If an enabled
313link at a sink pad prevents another link at the same pad from being disabled,
314the link_setup operation must return -EBUSY and can't implicitly disable the
315first enabled link.
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 648a9d892ac..16b70b4412f 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -172,6 +172,44 @@ static long media_device_enum_links(struct media_device *mdev,
172 return 0; 172 return 0;
173} 173}
174 174
175static 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
175static long media_device_ioctl(struct file *filp, unsigned int cmd, 213static long media_device_ioctl(struct file *filp, unsigned int cmd,
176 unsigned long arg) 214 unsigned long arg)
177{ 215{
@@ -197,6 +235,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
197 mutex_unlock(&dev->graph_mutex); 235 mutex_unlock(&dev->graph_mutex);
198 break; 236 break;
199 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);
242 mutex_unlock(&dev->graph_mutex);
243 break;
244
200 default: 245 default:
201 ret = -ENOIOCTLCMD; 246 ret = -ENOIOCTLCMD;
202 } 247 }
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 3e7e2d569ce..6795c920d46 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -306,3 +306,158 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
306 return 0; 306 return 0;
307} 307}
308EXPORT_SYMBOL_GPL(media_entity_create_link); 308EXPORT_SYMBOL_GPL(media_entity_create_link);
309
310static 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 */
349int __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
385err:
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
392int 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}
402EXPORT_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 */
412struct media_link *
413media_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}
430EXPORT_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 */
443struct 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}
463EXPORT_SYMBOL_GPL(media_entity_remote_source);
diff --git a/include/linux/media.h b/include/linux/media.h
index 17c93a41367..7c69913c0ad 100644
--- a/include/linux/media.h
+++ b/include/linux/media.h
@@ -126,5 +126,6 @@ struct media_links_enum {
126#define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info) 126#define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info)
127#define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc) 127#define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc)
128#define MEDIA_IOC_ENUM_LINKS _IOWR('M', 3, struct media_links_enum) 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#endif /* __LINUX_MEDIA_H */ 131#endif /* __LINUX_MEDIA_H */
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 5d2bff4fc9e..6a27d916c25 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -73,6 +73,9 @@ struct media_device {
73 spinlock_t lock; 73 spinlock_t lock;
74 /* Serializes graph operations. */ 74 /* Serializes graph operations. */
75 struct mutex graph_mutex; 75 struct mutex graph_mutex;
76
77 int (*link_notify)(struct media_pad *source,
78 struct media_pad *sink, u32 flags);
76}; 79};
77 80
78/* media_devnode to media_device */ 81/* media_devnode to media_device */
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 51bdafce72c..d889dcc67d0 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -39,6 +39,12 @@ struct media_pad {
39 unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */ 39 unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */
40}; 40};
41 41
42struct 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
42struct media_entity { 48struct media_entity {
43 struct list_head list; 49 struct list_head list;
44 struct media_device *parent; /* Media device this entity belongs to*/ 50 struct media_device *parent; /* Media device this entity belongs to*/
@@ -59,6 +65,8 @@ struct media_entity {
59 struct media_pad *pads; /* Pads array (num_pads elements) */ 65 struct media_pad *pads; /* Pads array (num_pads elements) */
60 struct media_link *links; /* Links array (max_links elements)*/ 66 struct media_link *links; /* Links array (max_links elements)*/
61 67
68 const struct media_entity_operations *ops; /* Entity operations */
69
62 /* Reference counts must never be negative, but are signed integers on 70 /* Reference counts must never be negative, but are signed integers on
63 * purpose: a simple WARN_ON(<0) check can be used to detect reference 71 * purpose: a simple WARN_ON(<0) check can be used to detect reference
64 * count bugs that would make them negative. 72 * count bugs that would make them negative.
@@ -112,6 +120,11 @@ int media_entity_init(struct media_entity *entity, u16 num_pads,
112void media_entity_cleanup(struct media_entity *entity); 120void media_entity_cleanup(struct media_entity *entity);
113int media_entity_create_link(struct media_entity *source, u16 source_pad, 121int media_entity_create_link(struct media_entity *source, u16 source_pad,
114 struct media_entity *sink, u16 sink_pad, u32 flags); 122 struct media_entity *sink, u16 sink_pad, u32 flags);
123int __media_entity_setup_link(struct media_link *link, u32 flags);
124int media_entity_setup_link(struct media_link *link, u32 flags);
125struct media_link *media_entity_find_link(struct media_pad *source,
126 struct media_pad *sink);
127struct media_pad *media_entity_remote_source(struct media_pad *pad);
115 128
116struct media_entity *media_entity_get(struct media_entity *entity); 129struct media_entity *media_entity_get(struct media_entity *entity);
117void media_entity_put(struct media_entity *entity); 130void media_entity_put(struct media_entity *entity);
@@ -121,4 +134,8 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
121struct media_entity * 134struct media_entity *
122media_entity_graph_walk_next(struct media_entity_graph *graph); 135media_entity_graph_walk_next(struct media_entity_graph *graph);
123 136
137#define media_entity_call(entity, operation, args...) \
138 (((entity)->ops && (entity)->ops->operation) ? \
139 (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
140
124#endif 141#endif