Merge tag 'media/v6.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[linux-2.6-microblaze.git] / drivers / media / mc / mc-entity.c
index 543a392..0e28b9a 100644 (file)
@@ -535,14 +535,15 @@ static int media_pipeline_walk_push(struct media_pipeline_walk *walk,
 
 /*
  * Move the top entry link cursor to the next link. If all links of the entry
- * have been visited, pop the entry itself.
+ * have been visited, pop the entry itself. Return true if the entry has been
+ * popped.
  */
-static void media_pipeline_walk_pop(struct media_pipeline_walk *walk)
+static bool media_pipeline_walk_pop(struct media_pipeline_walk *walk)
 {
        struct media_pipeline_walk_entry *entry;
 
        if (WARN_ON(walk->stack.top < 0))
-               return;
+               return false;
 
        entry = media_pipeline_walk_top(walk);
 
@@ -552,7 +553,7 @@ static void media_pipeline_walk_pop(struct media_pipeline_walk *walk)
                        walk->stack.top);
 
                walk->stack.top--;
-               return;
+               return true;
        }
 
        entry->links = entry->links->next;
@@ -560,6 +561,8 @@ static void media_pipeline_walk_pop(struct media_pipeline_walk *walk)
        dev_dbg(walk->mdev->dev,
                "media pipeline: moved entry %u to next link\n",
                walk->stack.top);
+
+       return false;
 }
 
 /* Free all memory allocated while walking the pipeline. */
@@ -605,30 +608,24 @@ static int media_pipeline_explore_next_link(struct media_pipeline *pipe,
                                            struct media_pipeline_walk *walk)
 {
        struct media_pipeline_walk_entry *entry = media_pipeline_walk_top(walk);
-       struct media_pad *pad;
+       struct media_pad *origin;
        struct media_link *link;
        struct media_pad *local;
        struct media_pad *remote;
+       bool last_link;
        int ret;
 
-       pad = entry->pad;
+       origin = entry->pad;
        link = list_entry(entry->links, typeof(*link), list);
-       media_pipeline_walk_pop(walk);
+       last_link = media_pipeline_walk_pop(walk);
 
        dev_dbg(walk->mdev->dev,
                "media pipeline: exploring link '%s':%u -> '%s':%u\n",
                link->source->entity->name, link->source->index,
                link->sink->entity->name, link->sink->index);
 
-       /* Skip links that are not enabled. */
-       if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
-               dev_dbg(walk->mdev->dev,
-                       "media pipeline: skipping link (disabled)\n");
-               return 0;
-       }
-
        /* Get the local pad and remote pad. */
-       if (link->source->entity == pad->entity) {
+       if (link->source->entity == origin->entity) {
                local = link->source;
                remote = link->sink;
        } else {
@@ -640,25 +637,64 @@ static int media_pipeline_explore_next_link(struct media_pipeline *pipe,
         * Skip links that originate from a different pad than the incoming pad
         * that is not connected internally in the entity to the incoming pad.
         */
-       if (pad != local &&
-           !media_entity_has_pad_interdep(pad->entity, pad->index, local->index)) {
+       if (origin != local &&
+           !media_entity_has_pad_interdep(origin->entity, origin->index,
+                                          local->index)) {
                dev_dbg(walk->mdev->dev,
                        "media pipeline: skipping link (no route)\n");
-               return 0;
+               goto done;
        }
 
        /*
-        * Add the local and remote pads of the link to the pipeline and push
-        * them to the stack, if they're not already present.
+        * Add the local pad of the link to the pipeline and push it to the
+        * stack, if not already present.
         */
        ret = media_pipeline_add_pad(pipe, walk, local);
        if (ret)
                return ret;
 
+       /* Similarly, add the remote pad, but only if the link is enabled. */
+       if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
+               dev_dbg(walk->mdev->dev,
+                       "media pipeline: skipping link (disabled)\n");
+               goto done;
+       }
+
        ret = media_pipeline_add_pad(pipe, walk, remote);
        if (ret)
                return ret;
 
+done:
+       /*
+        * If we're done iterating over links, iterate over pads of the entity.
+        * This is necessary to discover pads that are not connected with any
+        * link. Those are dead ends from a pipeline exploration point of view,
+        * but are still part of the pipeline and need to be added to enable
+        * proper validation.
+        */
+       if (!last_link)
+               return 0;
+
+       dev_dbg(walk->mdev->dev,
+               "media pipeline: adding unconnected pads of '%s'\n",
+               local->entity->name);
+
+       media_entity_for_each_pad(origin->entity, local) {
+               /*
+                * Skip the origin pad (already handled), pad that have links
+                * (already discovered through iterating over links) and pads
+                * not internally connected.
+                */
+               if (origin == local || !local->num_links ||
+                   !media_entity_has_pad_interdep(origin->entity, origin->index,
+                                                  local->index))
+                       continue;
+
+               ret = media_pipeline_add_pad(pipe, walk, local);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -770,7 +806,6 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
                struct media_pad *pad = ppad->pad;
                struct media_entity *entity = pad->entity;
                bool has_enabled_link = false;
-               bool has_link = false;
                struct media_link *link;
 
                dev_dbg(mdev->dev, "Validating pad '%s':%u\n", pad->entity->name,
@@ -800,7 +835,6 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
                        /* Record if the pad has links and enabled links. */
                        if (link->flags & MEDIA_LNK_FL_ENABLED)
                                has_enabled_link = true;
-                       has_link = true;
 
                        /*
                         * Validate the link if it's enabled and has the
@@ -838,7 +872,7 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
                 * 3. If the pad has the MEDIA_PAD_FL_MUST_CONNECT flag set,
                 * ensure that it has either no link or an enabled link.
                 */
-               if ((pad->flags & MEDIA_PAD_FL_MUST_CONNECT) && has_link &&
+               if ((pad->flags & MEDIA_PAD_FL_MUST_CONNECT) &&
                    !has_enabled_link) {
                        dev_dbg(mdev->dev,
                                "Pad '%s':%u must be connected by an enabled link\n",
@@ -1038,6 +1072,9 @@ static void __media_entity_remove_link(struct media_entity *entity,
 
        /* Remove the reverse links for a data link. */
        if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == MEDIA_LNK_FL_DATA_LINK) {
+               link->source->num_links--;
+               link->sink->num_links--;
+
                if (link->source->entity == entity)
                        remote = link->sink->entity;
                else
@@ -1092,6 +1129,11 @@ media_create_pad_link(struct media_entity *source, u16 source_pad,
        struct media_link *link;
        struct media_link *backlink;
 
+       if (flags & MEDIA_LNK_FL_LINK_TYPE)
+               return -EINVAL;
+
+       flags |= MEDIA_LNK_FL_DATA_LINK;
+
        if (WARN_ON(!source || !sink) ||
            WARN_ON(source_pad >= source->num_pads) ||
            WARN_ON(sink_pad >= sink->num_pads))
@@ -1107,7 +1149,7 @@ media_create_pad_link(struct media_entity *source, u16 source_pad,
 
        link->source = &source->pads[source_pad];
        link->sink = &sink->pads[sink_pad];
-       link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;
+       link->flags = flags;
 
        /* Initialize graph object embedded at the new link */
        media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
@@ -1138,6 +1180,9 @@ media_create_pad_link(struct media_entity *source, u16 source_pad,
        sink->num_links++;
        source->num_links++;
 
+       link->source->num_links++;
+       link->sink->num_links++;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(media_create_pad_link);