}
};
-/**
- * __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;
}
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);
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:
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:
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;
}
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;
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;
}
#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
__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);
*/
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);
/* 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;
}
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);
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);
{
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))) {
entity->pipe = NULL;
}
- media_entity_graph_walk_cleanup(graph);
+ if (!--pipe->streaming_count)
+ media_entity_graph_walk_cleanup(graph);
mutex_unlock(&mdev->graph_mutex);
}
}
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;