Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
[deliverable/linux.git] / drivers / media / media-entity.c
index 85af715d2a20e1b522d2aebbd933f067e6b4a7cf..e89d85a7d31b56286a6d8c9d492b5565dc6a4d43 100644 (file)
@@ -70,25 +70,13 @@ static inline const char *intf_type(struct media_interface *intf)
        }
 };
 
-/**
- * __media_entity_enum_init - Initialise an entity enumeration
- *
- * @ent_enum: Entity enumeration to be initialised
- * @idx_max: Maximum number of entities in the enumeration
- *
- * Returns zero on success or a negative error code.
- */
 __must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
                                          int idx_max)
 {
-       if (idx_max > MEDIA_ENTITY_ENUM_MAX_ID) {
-               ent_enum->bmap = kcalloc(DIV_ROUND_UP(idx_max, BITS_PER_LONG),
-                                        sizeof(long), GFP_KERNEL);
-               if (!ent_enum->bmap)
-                       return -ENOMEM;
-       } else {
-               ent_enum->bmap = ent_enum->prealloc_bmap;
-       }
+       ent_enum->bmap = kcalloc(DIV_ROUND_UP(idx_max, BITS_PER_LONG),
+                                sizeof(long), GFP_KERNEL);
+       if (!ent_enum->bmap)
+               return -ENOMEM;
 
        bitmap_zero(ent_enum->bmap, idx_max);
        ent_enum->idx_max = idx_max;
@@ -97,16 +85,9 @@ __must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
 }
 EXPORT_SYMBOL_GPL(__media_entity_enum_init);
 
-/**
- * media_entity_enum_cleanup - Release resources of an entity enumeration
- *
- * @e: Entity enumeration to be released
- */
 void media_entity_enum_cleanup(struct media_entity_enum *ent_enum)
 {
-       if (ent_enum->bmap != ent_enum->prealloc_bmap)
-               kfree(ent_enum->bmap);
-       ent_enum->bmap = NULL;
+       kfree(ent_enum->bmap);
 }
 EXPORT_SYMBOL_GPL(media_entity_enum_cleanup);
 
@@ -125,8 +106,8 @@ static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
        switch (media_type(gobj)) {
        case MEDIA_GRAPH_ENTITY:
                dev_dbg(gobj->mdev->dev,
-                       "%s: id 0x%08x entity#%d: '%s'\n",
-                       event_name, gobj->id, media_localid(gobj),
+                       "%s id %u: entity '%s'\n",
+                       event_name, media_id(gobj),
                        gobj_to_entity(gobj)->name);
                break;
        case MEDIA_GRAPH_LINK:
@@ -134,14 +115,12 @@ static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
                struct media_link *link = gobj_to_link(gobj);
 
                dev_dbg(gobj->mdev->dev,
-                       "%s: id 0x%08x link#%d: %s#%d ==> %s#%d\n",
-                       event_name, gobj->id, media_localid(gobj),
-
-                       gobj_type(media_type(link->gobj0)),
-                       media_localid(link->gobj0),
-
-                       gobj_type(media_type(link->gobj1)),
-                       media_localid(link->gobj1));
+                       "%s id %u: %s link id %u ==> id %u\n",
+                       event_name, media_id(gobj),
+                       media_type(link->gobj0) == MEDIA_GRAPH_PAD ?
+                               "data" : "interface",
+                       media_id(link->gobj0),
+                       media_id(link->gobj1));
                break;
        }
        case MEDIA_GRAPH_PAD:
@@ -149,11 +128,10 @@ static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
                struct media_pad *pad = gobj_to_pad(gobj);
 
                dev_dbg(gobj->mdev->dev,
-                       "%s: id 0x%08x %s%spad#%d: '%s':%d\n",
-                       event_name, gobj->id,
-                       pad->flags & MEDIA_PAD_FL_SINK   ? "  sink " : "",
+                       "%s id %u: %s%spad '%s':%d\n",
+                       event_name, media_id(gobj),
+                       pad->flags & MEDIA_PAD_FL_SINK   ? "sink " : "",
                        pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "",
-                       media_localid(gobj),
                        pad->entity->name, pad->index);
                break;
        }
@@ -163,8 +141,8 @@ static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
                struct media_intf_devnode *devnode = intf_to_devnode(intf);
 
                dev_dbg(gobj->mdev->dev,
-                       "%s: id 0x%08x intf_devnode#%d: %s - major: %d, minor: %d\n",
-                       event_name, gobj->id, media_localid(gobj),
+                       "%s id %u: intf_devnode %s - major: %d, minor: %d\n",
+                       event_name, media_id(gobj),
                        intf_type(intf),
                        devnode->major, devnode->minor);
                break;
@@ -182,21 +160,19 @@ void media_gobj_create(struct media_device *mdev,
        gobj->mdev = mdev;
 
        /* Create a per-type unique object ID */
+       gobj->id = media_gobj_gen_id(type, ++mdev->id);
+
        switch (type) {
        case MEDIA_GRAPH_ENTITY:
-               gobj->id = media_gobj_gen_id(type, ++mdev->entity_id);
                list_add_tail(&gobj->list, &mdev->entities);
                break;
        case MEDIA_GRAPH_PAD:
-               gobj->id = media_gobj_gen_id(type, ++mdev->pad_id);
                list_add_tail(&gobj->list, &mdev->pads);
                break;
        case MEDIA_GRAPH_LINK:
-               gobj->id = media_gobj_gen_id(type, ++mdev->link_id);
                list_add_tail(&gobj->list, &mdev->links);
                break;
        case MEDIA_GRAPH_INTF_DEVNODE:
-               gobj->id = media_gobj_gen_id(type, ++mdev->intf_devnode_id);
                list_add_tail(&gobj->list, &mdev->interfaces);
                break;
        }
@@ -282,6 +258,11 @@ static struct media_entity *stack_pop(struct media_entity_graph *graph)
 #define link_top(en)   ((en)->stack[(en)->top].link)
 #define stack_top(en)  ((en)->stack[(en)->top].entity)
 
+/*
+ * TODO: Get rid of this.
+ */
+#define MEDIA_ENTITY_MAX_PADS          512
+
 /**
  * media_entity_graph_walk_init - Allocate resources for graph walk
  * @graph: Media graph structure that will be used to walk the graph
@@ -296,7 +277,7 @@ static struct media_entity *stack_pop(struct media_entity_graph *graph)
 __must_check int media_entity_graph_walk_init(
        struct media_entity_graph *graph, struct media_device *mdev)
 {
-       return 0;
+       return media_entity_enum_init(&graph->ent_enum, mdev);
 }
 EXPORT_SYMBOL_GPL(media_entity_graph_walk_init);
 
@@ -306,20 +287,18 @@ EXPORT_SYMBOL_GPL(media_entity_graph_walk_init);
  */
 void media_entity_graph_walk_cleanup(struct media_entity_graph *graph)
 {
+       media_entity_enum_cleanup(&graph->ent_enum);
 }
 EXPORT_SYMBOL_GPL(media_entity_graph_walk_cleanup);
 
 void media_entity_graph_walk_start(struct media_entity_graph *graph,
                                   struct media_entity *entity)
 {
+       media_entity_enum_zero(&graph->ent_enum);
+       media_entity_enum_set(&graph->ent_enum, entity);
+
        graph->top = 0;
        graph->stack[graph->top].entity = NULL;
-       bitmap_zero(graph->entities, MEDIA_ENTITY_ENUM_MAX_ID);
-
-       if (WARN_ON(media_entity_id(entity) >= MEDIA_ENTITY_ENUM_MAX_ID))
-               return;
-
-       __set_bit(media_entity_id(entity), graph->entities);
        stack_push(graph, entity);
 }
 EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
@@ -350,11 +329,9 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
 
                /* Get the entity in the other end of the link . */
                next = media_entity_other(entity, link);
-               if (WARN_ON(media_entity_id(next) >= MEDIA_ENTITY_ENUM_MAX_ID))
-                       return NULL;
 
                /* Has the entity already been visited? */
-               if (__test_and_set_bit(media_entity_id(next), graph->entities)) {
+               if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
                        link_top(graph) = link_top(graph)->next;
                        continue;
                }
@@ -383,10 +360,10 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
 
        mutex_lock(&mdev->graph_mutex);
 
-       ret = media_entity_graph_walk_init(&pipe->graph, mdev);
-       if (ret) {
-               mutex_unlock(&mdev->graph_mutex);
-               return ret;
+       if (!pipe->streaming_count++) {
+               ret = media_entity_graph_walk_init(&pipe->graph, mdev);
+               if (ret)
+                       goto error_graph_walk_start;
        }
 
        media_entity_graph_walk_start(&pipe->graph, entity);
@@ -487,7 +464,9 @@ error:
                        break;
        }
 
-       media_entity_graph_walk_cleanup(graph);
+error_graph_walk_start:
+       if (!--pipe->streaming_count)
+               media_entity_graph_walk_cleanup(graph);
 
        mutex_unlock(&mdev->graph_mutex);
 
@@ -499,9 +478,11 @@ void media_entity_pipeline_stop(struct media_entity *entity)
 {
        struct media_device *mdev = entity->graph_obj.mdev;
        struct media_entity_graph *graph = &entity->pipe->graph;
+       struct media_pipeline *pipe = entity->pipe;
 
        mutex_lock(&mdev->graph_mutex);
 
+       WARN_ON(!pipe->streaming_count);
        media_entity_graph_walk_start(graph, entity);
 
        while ((entity = media_entity_graph_walk_next(graph))) {
@@ -510,7 +491,8 @@ void media_entity_pipeline_stop(struct media_entity *entity)
                        entity->pipe = NULL;
        }
 
-       media_entity_graph_walk_cleanup(graph);
+       if (!--pipe->streaming_count)
+               media_entity_graph_walk_cleanup(graph);
 
        mutex_unlock(&mdev->graph_mutex);
 }
@@ -643,6 +625,71 @@ media_create_pad_link(struct media_entity *source, u16 source_pad,
 }
 EXPORT_SYMBOL_GPL(media_create_pad_link);
 
+int media_create_pad_links(const struct media_device *mdev,
+                          const u32 source_function,
+                          struct media_entity *source,
+                          const u16 source_pad,
+                          const u32 sink_function,
+                          struct media_entity *sink,
+                          const u16 sink_pad,
+                          u32 flags,
+                          const bool allow_both_undefined)
+{
+       struct media_entity *entity;
+       unsigned function;
+       int ret;
+
+       /* Trivial case: 1:1 relation */
+       if (source && sink)
+               return media_create_pad_link(source, source_pad,
+                                            sink, sink_pad, flags);
+
+       /* Worse case scenario: n:n relation */
+       if (!source && !sink) {
+               if (!allow_both_undefined)
+                       return 0;
+               media_device_for_each_entity(source, mdev) {
+                       if (source->function != source_function)
+                               continue;
+                       media_device_for_each_entity(sink, mdev) {
+                               if (sink->function != sink_function)
+                                       continue;
+                               ret = media_create_pad_link(source, source_pad,
+                                                           sink, sink_pad,
+                                                           flags);
+                               if (ret)
+                                       return ret;
+                               flags &= ~(MEDIA_LNK_FL_ENABLED |
+                                          MEDIA_LNK_FL_IMMUTABLE);
+                       }
+               }
+               return 0;
+       }
+
+       /* Handle 1:n and n:1 cases */
+       if (source)
+               function = sink_function;
+       else
+               function = source_function;
+
+       media_device_for_each_entity(entity, mdev) {
+               if (entity->function != function)
+                       continue;
+
+               if (source)
+                       ret = media_create_pad_link(source, source_pad,
+                                                   entity, sink_pad, flags);
+               else
+                       ret = media_create_pad_link(entity, source_pad,
+                                                   sink, sink_pad, flags);
+               if (ret)
+                       return ret;
+               flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_create_pad_links);
+
 void __media_entity_remove_links(struct media_entity *entity)
 {
        struct media_link *link, *tmp;
This page took 0.028943 seconds and 5 git commands to generate.