linux-omap 2.6.37: sync with OE .dev
[glsdk/meta-ti-glsdk.git] / recipes-bsp / linux / linux-omap / media / 0015-media-Links-setup.patch
1 From 9991c219079532183cc33f16064f86680b80237c Mon Sep 17 00:00:00 2001
2 From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
3 Date: Wed, 9 Dec 2009 12:40:03 +0100
4 Subject: [PATCH 15/43] media: Links setup
6 Create the following ioctl and implement it at the media device level to
7 setup links.
9 - MEDIA_IOC_SETUP_LINK: Modify the properties of a given link
11 The only property that can currently be modified is the ENABLED link
12 flag to enable/disable a link. Links marked with the IMMUTABLE link flag
13 can not be enabled or disabled.
15 Enabling or disabling a link has effects on entities' use count. Those
16 changes are automatically propagated through the graph.
18 Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
19 Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
20 Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
21 ---
22  Documentation/DocBook/media-entities.tmpl          |    2 +
23  Documentation/DocBook/v4l/media-controller.xml     |    1 +
24  Documentation/DocBook/v4l/media-ioc-setup-link.xml |   90 +++++++++++
25  Documentation/media-framework.txt                  |   42 ++++++
26  drivers/media/media-device.c                       |   45 ++++++
27  drivers/media/media-entity.c                       |  155 ++++++++++++++++++++
28  include/linux/media.h                              |    1 +
29  include/media/media-device.h                       |    3 +
30  include/media/media-entity.h                       |   17 ++
31  9 files changed, 356 insertions(+), 0 deletions(-)
32  create mode 100644 Documentation/DocBook/v4l/media-ioc-setup-link.xml
34 diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
35 index 6e7dae4..679c585 100644
36 --- a/Documentation/DocBook/media-entities.tmpl
37 +++ b/Documentation/DocBook/media-entities.tmpl
38 @@ -94,6 +94,7 @@
39  <!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
40  <!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
41  <!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
42 +<!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>">
43  
44  <!-- Types -->
45  <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
46 @@ -342,6 +343,7 @@
47  <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
48  <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
49  <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
50 +<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml">
51  
52  <!-- Function Reference -->
53  <!ENTITY close SYSTEM "v4l/func-close.xml">
54 diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
55 index 2c4fd2b..2dc25e1 100644
56 --- a/Documentation/DocBook/v4l/media-controller.xml
57 +++ b/Documentation/DocBook/v4l/media-controller.xml
58 @@ -85,4 +85,5 @@
59    &sub-media-ioc-device-info;
60    &sub-media-ioc-enum-entities;
61    &sub-media-ioc-enum-links;
62 +  &sub-media-ioc-setup-link;
63  </appendix>
64 diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
65 new file mode 100644
66 index 0000000..09ab3d2
67 --- /dev/null
68 +++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
69 @@ -0,0 +1,90 @@
70 +<refentry id="media-ioc-setup-link">
71 +  <refmeta>
72 +    <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle>
73 +    &manvol;
74 +  </refmeta>
75 +
76 +  <refnamediv>
77 +    <refname>MEDIA_IOC_SETUP_LINK</refname>
78 +    <refpurpose>Modify the properties of a link</refpurpose>
79 +  </refnamediv>
80 +
81 +  <refsynopsisdiv>
82 +    <funcsynopsis>
83 +      <funcprototype>
84 +       <funcdef>int <function>ioctl</function></funcdef>
85 +       <paramdef>int <parameter>fd</parameter></paramdef>
86 +       <paramdef>int <parameter>request</parameter></paramdef>
87 +       <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef>
88 +      </funcprototype>
89 +    </funcsynopsis>
90 +  </refsynopsisdiv>
91 +
92 +  <refsect1>
93 +    <title>Arguments</title>
94 +
95 +    <variablelist>
96 +      <varlistentry>
97 +       <term><parameter>fd</parameter></term>
98 +       <listitem>
99 +         <para>File descriptor returned by
100 +         <link linkend='media-func-open'><function>open()</function></link>.</para>
101 +       </listitem>
102 +      </varlistentry>
103 +      <varlistentry>
104 +       <term><parameter>request</parameter></term>
105 +       <listitem>
106 +         <para>MEDIA_IOC_ENUM_LINKS</para>
107 +       </listitem>
108 +      </varlistentry>
109 +      <varlistentry>
110 +       <term><parameter>argp</parameter></term>
111 +       <listitem>
112 +         <para></para>
113 +       </listitem>
114 +      </varlistentry>
115 +    </variablelist>
116 +  </refsect1>
118 +  <refsect1>
119 +    <title>Description</title>
121 +    <para>To change link properties applications fill a &media-link-desc; with
122 +    link identification information (source and sink pad) and the new requested
123 +    link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to
124 +    that structure.</para>
125 +    <para>The only configurable property is the <constant>ENABLED</constant>
126 +    link flag to enable/disable a link. Links marked with the
127 +    <constant>IMMUTABLE</constant> link flag can not be enabled or disabled.
128 +    </para>
129 +    <para>Link configuration has no side effect on other links. If an enabled
130 +    link at the sink pad prevents the link from being enabled, the driver
131 +    returns with an &EBUSY;.</para>
132 +    <para>If the specified link can't be found the driver returns with an
133 +    &EINVAL;.</para>
134 +  </refsect1>
136 +  <refsect1>
137 +    &return-value;
139 +    <variablelist>
140 +      <varlistentry>
141 +       <term><errorcode>EBUSY</errorcode></term>
142 +       <listitem>
143 +         <para>The link properties can't be changed because the link is
144 +         currently busy. This can be caused, for instance, by an active media
145 +         stream (audio or video) on the link. The ioctl shouldn't be retried if
146 +         no other action is performed before to fix the problem.</para>
147 +       </listitem>
148 +      </varlistentry>
149 +      <varlistentry>
150 +       <term><errorcode>EINVAL</errorcode></term>
151 +       <listitem>
152 +         <para>The &media-link-desc; references a non-existing link, or the
153 +         link is immutable and an attempt to modify its configuration was made.
154 +         </para>
155 +       </listitem>
156 +      </varlistentry>
157 +    </variablelist>
158 +  </refsect1>
159 +</refentry>
160 diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
161 index 9017a41..634845e 100644
162 --- a/Documentation/media-framework.txt
163 +++ b/Documentation/media-framework.txt
164 @@ -259,6 +259,16 @@ When the graph traversal is complete the function will return NULL.
165  Graph traversal can be interrupted at any moment. No cleanup function call is
166  required and the graph structure can be freed normally.
167  
168 +Helper functions can be used to find a link between two given pads, or a pad
169 +connected to another pad through an enabled link
171 +       media_entity_find_link(struct media_pad *source,
172 +                              struct media_pad *sink);
174 +       media_entity_remote_source(struct media_pad *pad);
176 +Refer to the kerneldoc documentation for more information.
178  
179  Use count and power handling
180  ----------------------------
181 @@ -271,3 +281,35 @@ track the number of users of every entity for power management needs.
182  The use_count field is owned by media drivers and must not be touched by entity
183  drivers. Access to the field must be protected by the media device graph_mutex
184  lock.
187 +Links setup
188 +-----------
190 +Link properties can be modified at runtime by calling
192 +       media_entity_setup_link(struct media_link *link, u32 flags);
194 +The flags argument contains the requested new link flags.
196 +The only configurable property is the ENABLED link flag to enable/disable a
197 +link. Links marked with the IMMUTABLE link flag can not be enabled or disabled.
199 +When a link is enabled or disabled, the media framework calls the
200 +link_setup operation for the two entities at the source and sink of the link,
201 +in that order. If the second link_setup call fails, another link_setup call is
202 +made on the first entity to restore the original link flags.
204 +Media device drivers can be notified of link setup operations by setting the
205 +media_device::link_notify pointer to a callback function. If provided, the
206 +notification callback will be called before enabling and after disabling
207 +links.
209 +Entity drivers must implement the link_setup operation if any of their links
210 +is non-immutable. The operation must either configure the hardware or store
211 +the configuration information to be applied later.
213 +Link configuration must not have any side effect on other links. If an enabled
214 +link at a sink pad prevents another link at the same pad from being disabled,
215 +the link_setup operation must return -EBUSY and can't implicitly disable the
216 +first enabled link.
217 diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
218 index 1f46acb..719deba 100644
219 --- a/drivers/media/media-device.c
220 +++ b/drivers/media/media-device.c
221 @@ -172,6 +172,44 @@ static long media_device_enum_links(struct media_device *mdev,
222         return 0;
223  }
224  
225 +static long media_device_setup_link(struct media_device *mdev,
226 +                                   struct media_link_desc __user *_ulink)
227 +{
228 +       struct media_link *link = NULL;
229 +       struct media_link_desc ulink;
230 +       struct media_entity *source;
231 +       struct media_entity *sink;
232 +       int ret;
234 +       if (copy_from_user(&ulink, _ulink, sizeof(ulink)))
235 +               return -EFAULT;
237 +       /* Find the source and sink entities and link.
238 +        */
239 +       source = find_entity(mdev, ulink.source.entity);
240 +       sink = find_entity(mdev, ulink.sink.entity);
242 +       if (source == NULL || sink == NULL)
243 +               return -EINVAL;
245 +       if (ulink.source.index >= source->num_pads ||
246 +           ulink.sink.index >= sink->num_pads)
247 +               return -EINVAL;
249 +       link = media_entity_find_link(&source->pads[ulink.source.index],
250 +                                     &sink->pads[ulink.sink.index]);
251 +       if (link == NULL)
252 +               return -EINVAL;
254 +       /* Setup the link on both entities. */
255 +       ret = __media_entity_setup_link(link, ulink.flags);
257 +       if (copy_to_user(_ulink, &ulink, sizeof(ulink)))
258 +               return -EFAULT;
260 +       return ret;
261 +}
263  static long media_device_ioctl(struct file *filp, unsigned int cmd,
264                                unsigned long arg)
265  {
266 @@ -197,6 +235,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
267                 mutex_unlock(&dev->graph_mutex);
268                 break;
269  
270 +       case MEDIA_IOC_SETUP_LINK:
271 +               mutex_lock(&dev->graph_mutex);
272 +               ret = media_device_setup_link(dev,
273 +                               (struct media_link_desc __user *)arg);
274 +               mutex_unlock(&dev->graph_mutex);
275 +               break;
277         default:
278                 ret = -ENOIOCTLCMD;
279         }
280 diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
281 index fe6bfd2..d703ce8 100644
282 --- a/drivers/media/media-entity.c
283 +++ b/drivers/media/media-entity.c
284 @@ -306,3 +306,158 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
285         return 0;
286  }
287  EXPORT_SYMBOL_GPL(media_entity_create_link);
289 +static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
290 +{
291 +       const u32 mask = MEDIA_LNK_FL_ENABLED;
292 +       int ret;
294 +       /* Notify both entities. */
295 +       ret = media_entity_call(link->source->entity, link_setup,
296 +                               link->source, link->sink, flags);
297 +       if (ret < 0 && ret != -ENOIOCTLCMD)
298 +               return ret;
300 +       ret = media_entity_call(link->sink->entity, link_setup,
301 +                               link->sink, link->source, flags);
302 +       if (ret < 0 && ret != -ENOIOCTLCMD) {
303 +               media_entity_call(link->source->entity, link_setup,
304 +                                 link->source, link->sink, link->flags);
305 +               return ret;
306 +       }
308 +       link->flags = (link->flags & ~mask) | (flags & mask);
309 +       link->reverse->flags = link->flags;
311 +       return 0;
312 +}
314 +/**
315 + * __media_entity_setup_link - Configure a media link
316 + * @link: The link being configured
317 + * @flags: Link configuration flags
318 + *
319 + * The bulk of link setup is handled by the two entities connected through the
320 + * link. This function notifies both entities of the link configuration change.
321 + *
322 + * If the link is immutable or if the current and new configuration are
323 + * identical, return immediately.
324 + *
325 + * The user is expected to hold link->source->parent->mutex. If not,
326 + * media_entity_setup_link() should be used instead.
327 + */
328 +int __media_entity_setup_link(struct media_link *link, u32 flags)
329 +{
330 +       struct media_device *mdev;
331 +       struct media_entity *source, *sink;
332 +       int ret = -EBUSY;
334 +       if (link == NULL)
335 +               return -EINVAL;
337 +       if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
338 +               return link->flags == flags ? 0 : -EINVAL;
340 +       if (link->flags == flags)
341 +               return 0;
343 +       source = link->source->entity;
344 +       sink = link->sink->entity;
346 +       mdev = source->parent;
348 +       if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
349 +               ret = mdev->link_notify(link->source, link->sink,
350 +                                       MEDIA_LNK_FL_ENABLED);
351 +               if (ret < 0)
352 +                       return ret;
353 +       }
355 +       ret = __media_entity_setup_link_notify(link, flags);
356 +       if (ret < 0)
357 +               goto err;
359 +       if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
360 +               mdev->link_notify(link->source, link->sink, 0);
362 +       return 0;
364 +err:
365 +       if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
366 +               mdev->link_notify(link->source, link->sink, 0);
368 +       return ret;
369 +}
371 +int media_entity_setup_link(struct media_link *link, u32 flags)
372 +{
373 +       int ret;
375 +       mutex_lock(&link->source->entity->parent->graph_mutex);
376 +       ret = __media_entity_setup_link(link, flags);
377 +       mutex_unlock(&link->source->entity->parent->graph_mutex);
379 +       return ret;
380 +}
381 +EXPORT_SYMBOL_GPL(media_entity_setup_link);
383 +/**
384 + * media_entity_find_link - Find a link between two pads
385 + * @source: Source pad
386 + * @sink: Sink pad
387 + *
388 + * Return a pointer to the link between the two entities. If no such link
389 + * exists, return NULL.
390 + */
391 +struct media_link *
392 +media_entity_find_link(struct media_pad *source, struct media_pad *sink)
393 +{
394 +       struct media_link *link;
395 +       unsigned int i;
397 +       for (i = 0; i < source->entity->num_links; ++i) {
398 +               link = &source->entity->links[i];
400 +               if (link->source->entity == source->entity &&
401 +                   link->source->index == source->index &&
402 +                   link->sink->entity == sink->entity &&
403 +                   link->sink->index == sink->index)
404 +                       return link;
405 +       }
407 +       return NULL;
408 +}
409 +EXPORT_SYMBOL_GPL(media_entity_find_link);
411 +/**
412 + * media_entity_remote_source - Find the source pad at the remote end of a link
413 + * @pad: Sink pad at the local end of the link
414 + *
415 + * Search for a remote source pad connected to the given sink pad by iterating
416 + * over all links originating or terminating at that pad until an enabled link
417 + * is found.
418 + *
419 + * Return a pointer to the pad at the remote end of the first found enabled
420 + * link, or NULL if no enabled link has been found.
421 + */
422 +struct media_pad *media_entity_remote_source(struct media_pad *pad)
423 +{
424 +       unsigned int i;
426 +       for (i = 0; i < pad->entity->num_links; i++) {
427 +               struct media_link *link = &pad->entity->links[i];
429 +               if (!(link->flags & MEDIA_LNK_FL_ENABLED))
430 +                       continue;
432 +               if (link->source == pad)
433 +                       return link->sink;
435 +               if (link->sink == pad)
436 +                       return link->source;
437 +       }
439 +       return NULL;
441 +}
442 +EXPORT_SYMBOL_GPL(media_entity_remote_source);
443 diff --git a/include/linux/media.h b/include/linux/media.h
444 index 64c0313..2f67ed2 100644
445 --- a/include/linux/media.h
446 +++ b/include/linux/media.h
447 @@ -126,5 +126,6 @@ struct media_links_enum {
448  #define MEDIA_IOC_DEVICE_INFO          _IOWR('M', 1, struct media_device_info)
449  #define MEDIA_IOC_ENUM_ENTITIES                _IOWR('M', 2, struct media_entity_desc)
450  #define MEDIA_IOC_ENUM_LINKS           _IOWR('M', 3, struct media_links_enum)
451 +#define MEDIA_IOC_SETUP_LINK           _IOWR('M', 4, struct media_link_desc)
452  
453  #endif /* __LINUX_MEDIA_H */
454 diff --git a/include/media/media-device.h b/include/media/media-device.h
455 index 260d59c..ad93e66 100644
456 --- a/include/media/media-device.h
457 +++ b/include/media/media-device.h
458 @@ -73,6 +73,9 @@ struct media_device {
459         spinlock_t lock;
460         /* Serializes graph operations. */
461         struct mutex graph_mutex;
463 +       int (*link_notify)(struct media_pad *source,
464 +                          struct media_pad *sink, u32 flags);
465  };
466  
467  /* media_devnode to media_device */
468 diff --git a/include/media/media-entity.h b/include/media/media-entity.h
469 index 0954490..60fc7bd 100644
470 --- a/include/media/media-entity.h
471 +++ b/include/media/media-entity.h
472 @@ -39,6 +39,12 @@ struct media_pad {
473         unsigned long flags;            /* Pad flags (MEDIA_PAD_FL_*) */
474  };
475  
476 +struct media_entity_operations {
477 +       int (*link_setup)(struct media_entity *entity,
478 +                         const struct media_pad *local,
479 +                         const struct media_pad *remote, u32 flags);
480 +};
482  struct media_entity {
483         struct list_head list;
484         struct media_device *parent;    /* Media device this entity belongs to*/
485 @@ -59,6 +65,8 @@ struct media_entity {
486         struct media_pad *pads;         /* Pads array (num_pads elements) */
487         struct media_link *links;       /* Links array (max_links elements)*/
488  
489 +       const struct media_entity_operations *ops;      /* Entity operations */
491         int use_count;                  /* Use count for the entity. */
492  
493         union {
494 @@ -108,6 +116,11 @@ int media_entity_init(struct media_entity *entity, u16 num_pads,
495  void media_entity_cleanup(struct media_entity *entity);
496  int media_entity_create_link(struct media_entity *source, u16 source_pad,
497                 struct media_entity *sink, u16 sink_pad, u32 flags);
498 +int __media_entity_setup_link(struct media_link *link, u32 flags);
499 +int media_entity_setup_link(struct media_link *link, u32 flags);
500 +struct media_link *media_entity_find_link(struct media_pad *source,
501 +               struct media_pad *sink);
502 +struct media_pad *media_entity_remote_source(struct media_pad *pad);
503  
504  struct media_entity *media_entity_get(struct media_entity *entity);
505  void media_entity_put(struct media_entity *entity);
506 @@ -117,4 +130,8 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
507  struct media_entity *
508  media_entity_graph_walk_next(struct media_entity_graph *graph);
509  
510 +#define media_entity_call(entity, operation, args...)                  \
511 +       (((entity)->ops && (entity)->ops->operation) ?                  \
512 +        (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
514  #endif
515 -- 
516 1.6.6.1