aboutsummaryrefslogtreecommitdiffstats
path: root/extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch
diff options
context:
space:
mode:
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch')
-rw-r--r--extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch517
1 files changed, 517 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch b/extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch
new file mode 100644
index 00000000..4ea39740
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/media/0015-media-Links-setup.patch
@@ -0,0 +1,517 @@
+From 9991c219079532183cc33f16064f86680b80237c Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 9 Dec 2009 12:40:03 +0100
+Subject: [PATCH 15/43] 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@maxwell.research.nokia.com>
+---
+ Documentation/DocBook/media-entities.tmpl | 2 +
+ Documentation/DocBook/v4l/media-controller.xml | 1 +
+ Documentation/DocBook/v4l/media-ioc-setup-link.xml | 90 +++++++++++
+ Documentation/media-framework.txt | 42 ++++++
+ drivers/media/media-device.c | 45 ++++++
+ drivers/media/media-entity.c | 155 ++++++++++++++++++++
+ include/linux/media.h | 1 +
+ include/media/media-device.h | 3 +
+ include/media/media-entity.h | 17 ++
+ 9 files changed, 356 insertions(+), 0 deletions(-)
+ create mode 100644 Documentation/DocBook/v4l/media-ioc-setup-link.xml
+
+diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
+index 6e7dae4..679c585 100644
+--- a/Documentation/DocBook/media-entities.tmpl
++++ b/Documentation/DocBook/media-entities.tmpl
+@@ -94,6 +94,7 @@
+ <!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
+ <!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
+ <!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
++<!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>">
+
+ <!-- Types -->
+ <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
+@@ -342,6 +343,7 @@
+ <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
+ <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
+ <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
++<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml">
+
+ <!-- Function Reference -->
+ <!ENTITY close SYSTEM "v4l/func-close.xml">
+diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
+index 2c4fd2b..2dc25e1 100644
+--- a/Documentation/DocBook/v4l/media-controller.xml
++++ b/Documentation/DocBook/v4l/media-controller.xml
+@@ -85,4 +85,5 @@
+ &sub-media-ioc-device-info;
+ &sub-media-ioc-enum-entities;
+ &sub-media-ioc-enum-links;
++ &sub-media-ioc-setup-link;
+ </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 0000000..09ab3d2
+--- /dev/null
++++ b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
+@@ -0,0 +1,90 @@
++<refentry id="media-ioc-setup-link">
++ <refmeta>
++ <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle>
++ &manvol;
++ </refmeta>
++
++ <refnamediv>
++ <refname>MEDIA_IOC_SETUP_LINK</refname>
++ <refpurpose>Modify the properties of a link</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <funcsynopsis>
++ <funcprototype>
++ <funcdef>int <function>ioctl</function></funcdef>
++ <paramdef>int <parameter>fd</parameter></paramdef>
++ <paramdef>int <parameter>request</parameter></paramdef>
++ <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef>
++ </funcprototype>
++ </funcsynopsis>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Arguments</title>
++
++ <variablelist>
++ <varlistentry>
++ <term><parameter>fd</parameter></term>
++ <listitem>
++ <para>File descriptor returned by
++ <link linkend='media-func-open'><function>open()</function></link>.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>request</parameter></term>
++ <listitem>
++ <para>MEDIA_IOC_ENUM_LINKS</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><parameter>argp</parameter></term>
++ <listitem>
++ <para></para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para>To change link properties applications fill a &media-link-desc; with
++ link identification information (source and sink pad) and the new requested
++ link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to
++ that structure.</para>
++ <para>The only configurable property is the <constant>ENABLED</constant>
++ link flag to enable/disable a link. Links marked with the
++ <constant>IMMUTABLE</constant> link flag can not be enabled or disabled.
++ </para>
++ <para>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;.</para>
++ <para>If the specified link can't be found the driver returns with an
++ &EINVAL;.</para>
++ </refsect1>
++
++ <refsect1>
++ &return-value;
++
++ <variablelist>
++ <varlistentry>
++ <term><errorcode>EBUSY</errorcode></term>
++ <listitem>
++ <para>The link properties can't be changed because the link is
++ currently busy. This can be caused, for instance, by an active media
++ stream (audio or video) on the link. The ioctl shouldn't be retried if
++ no other action is performed before to fix the problem.</para>
++ </listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><errorcode>EINVAL</errorcode></term>
++ <listitem>
++ <para>The &media-link-desc; references a non-existing link, or the
++ link is immutable and an attempt to modify its configuration was made.
++ </para>
++ </listitem>
++ </varlistentry>
++ </variablelist>
++ </refsect1>
++</refentry>
+diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
+index 9017a41..634845e 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.
+ Graph traversal can be interrupted at any moment. No cleanup function call is
+ required and the graph structure can be freed normally.
+
++Helper functions can be used to find a link between two given pads, or a pad
++connected to another pad through an enabled link
++
++ media_entity_find_link(struct media_pad *source,
++ struct media_pad *sink);
++
++ media_entity_remote_source(struct media_pad *pad);
++
++Refer to the kerneldoc documentation for more information.
++
+
+ Use count and power handling
+ ----------------------------
+@@ -271,3 +281,35 @@ track the number of users of every entity for power management needs.
+ The use_count field is owned by media drivers and must not be touched by entity
+ drivers. Access to the field must be protected by the media device graph_mutex
+ lock.
++
++
++Links setup
++-----------
++
++Link properties can be modified at runtime by calling
++
++ media_entity_setup_link(struct media_link *link, u32 flags);
++
++The flags argument contains the requested new link flags.
++
++The only configurable property is the ENABLED link flag to enable/disable a
++link. Links marked with the IMMUTABLE link flag can not be enabled or disabled.
++
++When a link is enabled or disabled, the media framework calls the
++link_setup operation for the two entities at the source and sink of the link,
++in that order. If the second link_setup call fails, another link_setup call is
++made on the first entity to restore the original link flags.
++
++Media device drivers can be notified of link setup operations by setting the
++media_device::link_notify pointer to a callback function. If provided, the
++notification callback will be called before enabling and after disabling
++links.
++
++Entity drivers must implement the link_setup operation if any of their links
++is non-immutable. The operation must either configure the hardware or store
++the configuration information to be applied later.
++
++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.
+diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
+index 1f46acb..719deba 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,
+ return 0;
+ }
+
++static long media_device_setup_link(struct media_device *mdev,
++ struct media_link_desc __user *_ulink)
++{
++ struct media_link *link = NULL;
++ struct media_link_desc ulink;
++ struct media_entity *source;
++ struct media_entity *sink;
++ int ret;
++
++ if (copy_from_user(&ulink, _ulink, sizeof(ulink)))
++ return -EFAULT;
++
++ /* Find the source and sink entities and link.
++ */
++ source = find_entity(mdev, ulink.source.entity);
++ sink = find_entity(mdev, ulink.sink.entity);
++
++ if (source == NULL || sink == NULL)
++ return -EINVAL;
++
++ if (ulink.source.index >= source->num_pads ||
++ ulink.sink.index >= sink->num_pads)
++ return -EINVAL;
++
++ link = media_entity_find_link(&source->pads[ulink.source.index],
++ &sink->pads[ulink.sink.index]);
++ if (link == NULL)
++ return -EINVAL;
++
++ /* Setup the link on both entities. */
++ ret = __media_entity_setup_link(link, ulink.flags);
++
++ if (copy_to_user(_ulink, &ulink, sizeof(ulink)))
++ return -EFAULT;
++
++ return ret;
++}
++
+ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+ {
+@@ -197,6 +235,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
+ mutex_unlock(&dev->graph_mutex);
+ break;
+
++ case MEDIA_IOC_SETUP_LINK:
++ mutex_lock(&dev->graph_mutex);
++ ret = media_device_setup_link(dev,
++ (struct media_link_desc __user *)arg);
++ mutex_unlock(&dev->graph_mutex);
++ break;
++
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
+index fe6bfd2..d703ce8 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,
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(media_entity_create_link);
++
++static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
++{
++ const u32 mask = MEDIA_LNK_FL_ENABLED;
++ int ret;
++
++ /* Notify both entities. */
++ ret = media_entity_call(link->source->entity, link_setup,
++ link->source, link->sink, flags);
++ if (ret < 0 && ret != -ENOIOCTLCMD)
++ return ret;
++
++ ret = media_entity_call(link->sink->entity, link_setup,
++ link->sink, link->source, flags);
++ if (ret < 0 && ret != -ENOIOCTLCMD) {
++ media_entity_call(link->source->entity, link_setup,
++ link->source, link->sink, link->flags);
++ return ret;
++ }
++
++ link->flags = (link->flags & ~mask) | (flags & mask);
++ link->reverse->flags = link->flags;
++
++ return 0;
++}
++
++/**
++ * __media_entity_setup_link - Configure a media link
++ * @link: The link being configured
++ * @flags: Link configuration flags
++ *
++ * The bulk of link setup is handled by the two entities connected through the
++ * link. This function notifies both entities of the link configuration change.
++ *
++ * If the link is immutable or if the current and new configuration are
++ * identical, return immediately.
++ *
++ * The user is expected to hold link->source->parent->mutex. If not,
++ * media_entity_setup_link() should be used instead.
++ */
++int __media_entity_setup_link(struct media_link *link, u32 flags)
++{
++ struct media_device *mdev;
++ struct media_entity *source, *sink;
++ int ret = -EBUSY;
++
++ if (link == NULL)
++ return -EINVAL;
++
++ if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
++ return link->flags == flags ? 0 : -EINVAL;
++
++ if (link->flags == flags)
++ return 0;
++
++ source = link->source->entity;
++ sink = link->sink->entity;
++
++ mdev = source->parent;
++
++ if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
++ ret = mdev->link_notify(link->source, link->sink,
++ MEDIA_LNK_FL_ENABLED);
++ if (ret < 0)
++ return ret;
++ }
++
++ ret = __media_entity_setup_link_notify(link, flags);
++ if (ret < 0)
++ goto err;
++
++ if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
++ mdev->link_notify(link->source, link->sink, 0);
++
++ return 0;
++
++err:
++ if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
++ mdev->link_notify(link->source, link->sink, 0);
++
++ return ret;
++}
++
++int media_entity_setup_link(struct media_link *link, u32 flags)
++{
++ int ret;
++
++ mutex_lock(&link->source->entity->parent->graph_mutex);
++ ret = __media_entity_setup_link(link, flags);
++ mutex_unlock(&link->source->entity->parent->graph_mutex);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(media_entity_setup_link);
++
++/**
++ * media_entity_find_link - Find a link between two pads
++ * @source: Source pad
++ * @sink: Sink pad
++ *
++ * Return a pointer to the link between the two entities. If no such link
++ * exists, return NULL.
++ */
++struct media_link *
++media_entity_find_link(struct media_pad *source, struct media_pad *sink)
++{
++ struct media_link *link;
++ unsigned int i;
++
++ for (i = 0; i < source->entity->num_links; ++i) {
++ link = &source->entity->links[i];
++
++ if (link->source->entity == source->entity &&
++ link->source->index == source->index &&
++ link->sink->entity == sink->entity &&
++ link->sink->index == sink->index)
++ return link;
++ }
++
++ return NULL;
++}
++EXPORT_SYMBOL_GPL(media_entity_find_link);
++
++/**
++ * media_entity_remote_source - Find the source pad at the remote end of a link
++ * @pad: Sink pad at the local end of the link
++ *
++ * Search for a remote source pad connected to the given sink pad by iterating
++ * over all links originating or terminating at that pad until an enabled link
++ * is found.
++ *
++ * Return a pointer to the pad at the remote end of the first found enabled
++ * link, or NULL if no enabled link has been found.
++ */
++struct media_pad *media_entity_remote_source(struct media_pad *pad)
++{
++ unsigned int i;
++
++ for (i = 0; i < pad->entity->num_links; i++) {
++ struct media_link *link = &pad->entity->links[i];
++
++ if (!(link->flags & MEDIA_LNK_FL_ENABLED))
++ continue;
++
++ if (link->source == pad)
++ return link->sink;
++
++ if (link->sink == pad)
++ return link->source;
++ }
++
++ return NULL;
++
++}
++EXPORT_SYMBOL_GPL(media_entity_remote_source);
+diff --git a/include/linux/media.h b/include/linux/media.h
+index 64c0313..2f67ed2 100644
+--- a/include/linux/media.h
++++ b/include/linux/media.h
+@@ -126,5 +126,6 @@ struct media_links_enum {
+ #define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info)
+ #define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc)
+ #define MEDIA_IOC_ENUM_LINKS _IOWR('M', 3, struct media_links_enum)
++#define MEDIA_IOC_SETUP_LINK _IOWR('M', 4, struct media_link_desc)
+
+ #endif /* __LINUX_MEDIA_H */
+diff --git a/include/media/media-device.h b/include/media/media-device.h
+index 260d59c..ad93e66 100644
+--- a/include/media/media-device.h
++++ b/include/media/media-device.h
+@@ -73,6 +73,9 @@ struct media_device {
+ spinlock_t lock;
+ /* Serializes graph operations. */
+ struct mutex graph_mutex;
++
++ int (*link_notify)(struct media_pad *source,
++ struct media_pad *sink, u32 flags);
+ };
+
+ /* media_devnode to media_device */
+diff --git a/include/media/media-entity.h b/include/media/media-entity.h
+index 0954490..60fc7bd 100644
+--- a/include/media/media-entity.h
++++ b/include/media/media-entity.h
+@@ -39,6 +39,12 @@ struct media_pad {
+ unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */
+ };
+
++struct media_entity_operations {
++ int (*link_setup)(struct media_entity *entity,
++ const struct media_pad *local,
++ const struct media_pad *remote, u32 flags);
++};
++
+ struct media_entity {
+ struct list_head list;
+ struct media_device *parent; /* Media device this entity belongs to*/
+@@ -59,6 +65,8 @@ struct media_entity {
+ struct media_pad *pads; /* Pads array (num_pads elements) */
+ struct media_link *links; /* Links array (max_links elements)*/
+
++ const struct media_entity_operations *ops; /* Entity operations */
++
+ int use_count; /* Use count for the entity. */
+
+ union {
+@@ -108,6 +116,11 @@ int media_entity_init(struct media_entity *entity, u16 num_pads,
+ 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);
++int media_entity_setup_link(struct media_link *link, u32 flags);
++struct media_link *media_entity_find_link(struct media_pad *source,
++ struct media_pad *sink);
++struct media_pad *media_entity_remote_source(struct media_pad *pad);
+
+ struct media_entity *media_entity_get(struct media_entity *entity);
+ void media_entity_put(struct media_entity *entity);
+@@ -117,4 +130,8 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
+ struct media_entity *
+ media_entity_graph_walk_next(struct media_entity_graph *graph);
+
++#define media_entity_call(entity, operation, args...) \
++ (((entity)->ops && (entity)->ops->operation) ? \
++ (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
++
+ #endif
+--
+1.6.6.1
+