aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@iki.fi>2010-03-07 14:14:14 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-22 03:53:11 -0400
commita5ccc48a7c48610e7f92fa599406738d69195d51 (patch)
tree8b82352250fa0cef0bcbb7b4db760d98844d746d
parent53e269c102fbaf77e7dc526b1606ad4a48e57200 (diff)
[media] media: Entity graph traversal
Add media entity graph traversal. The traversal follows enabled links by depth first. Traversing graph backwards is prevented by comparing the next possible entity in the graph with the previous one. Multiply connected graphs are thus not supported. Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@gmail.com> Acked-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--Documentation/media-framework.txt42
-rw-r--r--drivers/media/media-entity.c115
-rw-r--r--include/media/media-entity.h15
3 files changed, 172 insertions, 0 deletions
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 0257bad2a104..ab17f33ddedc 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -216,3 +216,45 @@ Links have flags that describe the link capabilities and state.
216 modified at runtime. If MEDIA_LNK_FL_IMMUTABLE is set, then 216 modified at runtime. If MEDIA_LNK_FL_IMMUTABLE is set, then
217 MEDIA_LNK_FL_ENABLED must also be set since an immutable link is always 217 MEDIA_LNK_FL_ENABLED must also be set since an immutable link is always
218 enabled. 218 enabled.
219
220
221Graph traversal
222---------------
223
224The media framework provides APIs to iterate over entities in a graph.
225
226To iterate over all entities belonging to a media device, drivers can use the
227media_device_for_each_entity macro, defined in include/media/media-device.h.
228
229 struct media_entity *entity;
230
231 media_device_for_each_entity(entity, mdev) {
232 /* entity will point to each entity in turn */
233 ...
234 }
235
236Drivers might also need to iterate over all entities in a graph that can be
237reached only through enabled links starting at a given entity. The media
238framework provides a depth-first graph traversal API for that purpose.
239
240Note that graphs with cycles (whether directed or undirected) are *NOT*
241supported by the graph traversal API. To prevent infinite loops, the graph
242traversal code limits the maximum depth to MEDIA_ENTITY_ENUM_MAX_DEPTH,
243currently defined as 16.
244
245Drivers initiate a graph traversal by calling
246
247 media_entity_graph_walk_start(struct media_entity_graph *graph,
248 struct media_entity *entity);
249
250The graph structure, provided by the caller, is initialized to start graph
251traversal at the given entity.
252
253Drivers can then retrieve the next entity by calling
254
255 media_entity_graph_walk_next(struct media_entity_graph *graph);
256
257When the graph traversal is complete the function will return NULL.
258
259Graph traversal can be interrupted at any moment. No cleanup function call is
260required and the graph structure can be freed normally.
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 5c31df9ed765..166f2b5505ce 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -84,6 +84,121 @@ media_entity_cleanup(struct media_entity *entity)
84} 84}
85EXPORT_SYMBOL_GPL(media_entity_cleanup); 85EXPORT_SYMBOL_GPL(media_entity_cleanup);
86 86
87/* -----------------------------------------------------------------------------
88 * Graph traversal
89 */
90
91static struct media_entity *
92media_entity_other(struct media_entity *entity, struct media_link *link)
93{
94 if (link->source->entity == entity)
95 return link->sink->entity;
96 else
97 return link->source->entity;
98}
99
100/* push an entity to traversal stack */
101static void stack_push(struct media_entity_graph *graph,
102 struct media_entity *entity)
103{
104 if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
105 WARN_ON(1);
106 return;
107 }
108 graph->top++;
109 graph->stack[graph->top].link = 0;
110 graph->stack[graph->top].entity = entity;
111}
112
113static struct media_entity *stack_pop(struct media_entity_graph *graph)
114{
115 struct media_entity *entity;
116
117 entity = graph->stack[graph->top].entity;
118 graph->top--;
119
120 return entity;
121}
122
123#define stack_peek(en) ((en)->stack[(en)->top - 1].entity)
124#define link_top(en) ((en)->stack[(en)->top].link)
125#define stack_top(en) ((en)->stack[(en)->top].entity)
126
127/**
128 * media_entity_graph_walk_start - Start walking the media graph at a given entity
129 * @graph: Media graph structure that will be used to walk the graph
130 * @entity: Starting entity
131 *
132 * This function initializes the graph traversal structure to walk the entities
133 * graph starting at the given entity. The traversal structure must not be
134 * modified by the caller during graph traversal. When done the structure can
135 * safely be freed.
136 */
137void media_entity_graph_walk_start(struct media_entity_graph *graph,
138 struct media_entity *entity)
139{
140 graph->top = 0;
141 graph->stack[graph->top].entity = NULL;
142 stack_push(graph, entity);
143}
144EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
145
146/**
147 * media_entity_graph_walk_next - Get the next entity in the graph
148 * @graph: Media graph structure
149 *
150 * Perform a depth-first traversal of the given media entities graph.
151 *
152 * The graph structure must have been previously initialized with a call to
153 * media_entity_graph_walk_start().
154 *
155 * Return the next entity in the graph or NULL if the whole graph have been
156 * traversed.
157 */
158struct media_entity *
159media_entity_graph_walk_next(struct media_entity_graph *graph)
160{
161 if (stack_top(graph) == NULL)
162 return NULL;
163
164 /*
165 * Depth first search. Push entity to stack and continue from
166 * top of the stack until no more entities on the level can be
167 * found.
168 */
169 while (link_top(graph) < stack_top(graph)->num_links) {
170 struct media_entity *entity = stack_top(graph);
171 struct media_link *link = &entity->links[link_top(graph)];
172 struct media_entity *next;
173
174 /* The link is not enabled so we do not follow. */
175 if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
176 link_top(graph)++;
177 continue;
178 }
179
180 /* Get the entity in the other end of the link . */
181 next = media_entity_other(entity, link);
182
183 /* Was it the entity we came here from? */
184 if (next == stack_peek(graph)) {
185 link_top(graph)++;
186 continue;
187 }
188
189 /* Push the new entity to stack and start over. */
190 link_top(graph)++;
191 stack_push(graph, next);
192 }
193
194 return stack_pop(graph);
195}
196EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
197
198/* -----------------------------------------------------------------------------
199 * Links management
200 */
201
87static struct media_link *media_entity_add_link(struct media_entity *entity) 202static struct media_link *media_entity_add_link(struct media_entity *entity)
88{ 203{
89 if (entity->num_links >= entity->max_links) { 204 if (entity->num_links >= entity->max_links) {
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index f6c856c9ac16..28f61f6ee549 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -113,10 +113,25 @@ static inline u32 media_entity_subtype(struct media_entity *entity)
113 return entity->type & MEDIA_ENT_SUBTYPE_MASK; 113 return entity->type & MEDIA_ENT_SUBTYPE_MASK;
114} 114}
115 115
116#define MEDIA_ENTITY_ENUM_MAX_DEPTH 16
117
118struct media_entity_graph {
119 struct {
120 struct media_entity *entity;
121 int link;
122 } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
123 int top;
124};
125
116int media_entity_init(struct media_entity *entity, u16 num_pads, 126int media_entity_init(struct media_entity *entity, u16 num_pads,
117 struct media_pad *pads, u16 extra_links); 127 struct media_pad *pads, u16 extra_links);
118void media_entity_cleanup(struct media_entity *entity); 128void media_entity_cleanup(struct media_entity *entity);
119int media_entity_create_link(struct media_entity *source, u16 source_pad, 129int media_entity_create_link(struct media_entity *source, u16 source_pad,
120 struct media_entity *sink, u16 sink_pad, u32 flags); 130 struct media_entity *sink, u16 sink_pad, u32 flags);
121 131
132void media_entity_graph_walk_start(struct media_entity_graph *graph,
133 struct media_entity *entity);
134struct media_entity *
135media_entity_graph_walk_next(struct media_entity_graph *graph);
136
122#endif 137#endif