[media] media: Links setup
[deliverable/linux.git] / drivers / media / media-entity.c
index 3e7e2d569cec7e0eaf69ea0428f28846d7c020de..6795c920d460d74b11db9f33b6c9272f811b316d 100644 (file)
@@ -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);
This page took 0.0275 seconds and 5 git commands to generate.