diff options
-rw-r--r-- | Documentation/media-framework.txt | 42 | ||||
-rw-r--r-- | drivers/media/media-entity.c | 115 | ||||
-rw-r--r-- | include/media/media-entity.h | 15 |
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 | |||
221 | Graph traversal | ||
222 | --------------- | ||
223 | |||
224 | The media framework provides APIs to iterate over entities in a graph. | ||
225 | |||
226 | To iterate over all entities belonging to a media device, drivers can use the | ||
227 | media_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 | |||
236 | Drivers might also need to iterate over all entities in a graph that can be | ||
237 | reached only through enabled links starting at a given entity. The media | ||
238 | framework provides a depth-first graph traversal API for that purpose. | ||
239 | |||
240 | Note that graphs with cycles (whether directed or undirected) are *NOT* | ||
241 | supported by the graph traversal API. To prevent infinite loops, the graph | ||
242 | traversal code limits the maximum depth to MEDIA_ENTITY_ENUM_MAX_DEPTH, | ||
243 | currently defined as 16. | ||
244 | |||
245 | Drivers initiate a graph traversal by calling | ||
246 | |||
247 | media_entity_graph_walk_start(struct media_entity_graph *graph, | ||
248 | struct media_entity *entity); | ||
249 | |||
250 | The graph structure, provided by the caller, is initialized to start graph | ||
251 | traversal at the given entity. | ||
252 | |||
253 | Drivers can then retrieve the next entity by calling | ||
254 | |||
255 | media_entity_graph_walk_next(struct media_entity_graph *graph); | ||
256 | |||
257 | When the graph traversal is complete the function will return NULL. | ||
258 | |||
259 | Graph traversal can be interrupted at any moment. No cleanup function call is | ||
260 | required 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 | } |
85 | EXPORT_SYMBOL_GPL(media_entity_cleanup); | 85 | EXPORT_SYMBOL_GPL(media_entity_cleanup); |
86 | 86 | ||
87 | /* ----------------------------------------------------------------------------- | ||
88 | * Graph traversal | ||
89 | */ | ||
90 | |||
91 | static struct media_entity * | ||
92 | media_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 */ | ||
101 | static 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 | |||
113 | static 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 | */ | ||
137 | void 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 | } | ||
144 | EXPORT_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 | */ | ||
158 | struct media_entity * | ||
159 | media_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 | } | ||
196 | EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); | ||
197 | |||
198 | /* ----------------------------------------------------------------------------- | ||
199 | * Links management | ||
200 | */ | ||
201 | |||
87 | static struct media_link *media_entity_add_link(struct media_entity *entity) | 202 | static 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 | |||
118 | struct 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 | |||
116 | int media_entity_init(struct media_entity *entity, u16 num_pads, | 126 | int 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); |
118 | void media_entity_cleanup(struct media_entity *entity); | 128 | void media_entity_cleanup(struct media_entity *entity); |
119 | int media_entity_create_link(struct media_entity *source, u16 source_pad, | 129 | int 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 | ||
132 | void media_entity_graph_walk_start(struct media_entity_graph *graph, | ||
133 | struct media_entity *entity); | ||
134 | struct media_entity * | ||
135 | media_entity_graph_walk_next(struct media_entity_graph *graph); | ||
136 | |||
122 | #endif | 137 | #endif |