[media] move documentation to the header files
[linux-2.6-microblaze.git] / drivers / media / media-entity.c
1 /*
2  * Media entity
3  *
4  * Copyright (C) 2010 Nokia Corporation
5  *
6  * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
7  *           Sakari Ailus <sakari.ailus@iki.fi>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <linux/bitmap.h>
24 #include <linux/module.h>
25 #include <linux/slab.h>
26 #include <media/media-entity.h>
27 #include <media/media-device.h>
28
29 static inline const char *gobj_type(enum media_gobj_type type)
30 {
31         switch (type) {
32         case MEDIA_GRAPH_ENTITY:
33                 return "entity";
34         case MEDIA_GRAPH_PAD:
35                 return "pad";
36         case MEDIA_GRAPH_LINK:
37                 return "link";
38         case MEDIA_GRAPH_INTF_DEVNODE:
39                 return "intf-devnode";
40         default:
41                 return "unknown";
42         }
43 }
44
45 static inline const char *intf_type(struct media_interface *intf)
46 {
47         switch (intf->type) {
48         case MEDIA_INTF_T_DVB_FE:
49                 return "frontend";
50         case MEDIA_INTF_T_DVB_DEMUX:
51                 return "demux";
52         case MEDIA_INTF_T_DVB_DVR:
53                 return "DVR";
54         case MEDIA_INTF_T_DVB_CA:
55                 return  "CA";
56         case MEDIA_INTF_T_DVB_NET:
57                 return "dvbnet";
58         case MEDIA_INTF_T_V4L_VIDEO:
59                 return "video";
60         case MEDIA_INTF_T_V4L_VBI:
61                 return "vbi";
62         case MEDIA_INTF_T_V4L_RADIO:
63                 return "radio";
64         case MEDIA_INTF_T_V4L_SUBDEV:
65                 return "v4l2-subdev";
66         case MEDIA_INTF_T_V4L_SWRADIO:
67                 return "swradio";
68         default:
69                 return "unknown-intf";
70         }
71 };
72
73 __must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
74                                           int idx_max)
75 {
76         ent_enum->bmap = kcalloc(DIV_ROUND_UP(idx_max, BITS_PER_LONG),
77                                  sizeof(long), GFP_KERNEL);
78         if (!ent_enum->bmap)
79                 return -ENOMEM;
80
81         bitmap_zero(ent_enum->bmap, idx_max);
82         ent_enum->idx_max = idx_max;
83
84         return 0;
85 }
86 EXPORT_SYMBOL_GPL(__media_entity_enum_init);
87
88 void media_entity_enum_cleanup(struct media_entity_enum *ent_enum)
89 {
90         kfree(ent_enum->bmap);
91 }
92 EXPORT_SYMBOL_GPL(media_entity_enum_cleanup);
93
94 /**
95  *  dev_dbg_obj - Prints in debug mode a change on some object
96  *
97  * @event_name: Name of the event to report. Could be __func__
98  * @gobj:       Pointer to the object
99  *
100  * Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it
101  * won't produce any code.
102  */
103 static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
104 {
105 #if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG)
106         switch (media_type(gobj)) {
107         case MEDIA_GRAPH_ENTITY:
108                 dev_dbg(gobj->mdev->dev,
109                         "%s: id 0x%08x entity#%d: '%s'\n",
110                         event_name, gobj->id, media_localid(gobj),
111                         gobj_to_entity(gobj)->name);
112                 break;
113         case MEDIA_GRAPH_LINK:
114         {
115                 struct media_link *link = gobj_to_link(gobj);
116
117                 dev_dbg(gobj->mdev->dev,
118                         "%s: id 0x%08x link#%d: %s#%d ==> %s#%d\n",
119                         event_name, gobj->id, media_localid(gobj),
120
121                         gobj_type(media_type(link->gobj0)),
122                         media_localid(link->gobj0),
123
124                         gobj_type(media_type(link->gobj1)),
125                         media_localid(link->gobj1));
126                 break;
127         }
128         case MEDIA_GRAPH_PAD:
129         {
130                 struct media_pad *pad = gobj_to_pad(gobj);
131
132                 dev_dbg(gobj->mdev->dev,
133                         "%s: id 0x%08x %s%spad#%d: '%s':%d\n",
134                         event_name, gobj->id,
135                         pad->flags & MEDIA_PAD_FL_SINK   ? "  sink " : "",
136                         pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "",
137                         media_localid(gobj),
138                         pad->entity->name, pad->index);
139                 break;
140         }
141         case MEDIA_GRAPH_INTF_DEVNODE:
142         {
143                 struct media_interface *intf = gobj_to_intf(gobj);
144                 struct media_intf_devnode *devnode = intf_to_devnode(intf);
145
146                 dev_dbg(gobj->mdev->dev,
147                         "%s: id 0x%08x intf_devnode#%d: %s - major: %d, minor: %d\n",
148                         event_name, gobj->id, media_localid(gobj),
149                         intf_type(intf),
150                         devnode->major, devnode->minor);
151                 break;
152         }
153         }
154 #endif
155 }
156
157 void media_gobj_create(struct media_device *mdev,
158                            enum media_gobj_type type,
159                            struct media_gobj *gobj)
160 {
161         BUG_ON(!mdev);
162
163         gobj->mdev = mdev;
164
165         /* Create a per-type unique object ID */
166         switch (type) {
167         case MEDIA_GRAPH_ENTITY:
168                 gobj->id = media_gobj_gen_id(type, ++mdev->entity_id);
169                 list_add_tail(&gobj->list, &mdev->entities);
170                 break;
171         case MEDIA_GRAPH_PAD:
172                 gobj->id = media_gobj_gen_id(type, ++mdev->pad_id);
173                 list_add_tail(&gobj->list, &mdev->pads);
174                 break;
175         case MEDIA_GRAPH_LINK:
176                 gobj->id = media_gobj_gen_id(type, ++mdev->link_id);
177                 list_add_tail(&gobj->list, &mdev->links);
178                 break;
179         case MEDIA_GRAPH_INTF_DEVNODE:
180                 gobj->id = media_gobj_gen_id(type, ++mdev->intf_devnode_id);
181                 list_add_tail(&gobj->list, &mdev->interfaces);
182                 break;
183         }
184
185         mdev->topology_version++;
186
187         dev_dbg_obj(__func__, gobj);
188 }
189
190 void media_gobj_destroy(struct media_gobj *gobj)
191 {
192         dev_dbg_obj(__func__, gobj);
193
194         gobj->mdev->topology_version++;
195
196         /* Remove the object from mdev list */
197         list_del(&gobj->list);
198 }
199
200 int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
201                            struct media_pad *pads)
202 {
203         struct media_device *mdev = entity->graph_obj.mdev;
204         unsigned int i;
205
206         entity->num_pads = num_pads;
207         entity->pads = pads;
208
209         if (mdev)
210                 spin_lock(&mdev->lock);
211
212         for (i = 0; i < num_pads; i++) {
213                 pads[i].entity = entity;
214                 pads[i].index = i;
215                 if (mdev)
216                         media_gobj_create(mdev, MEDIA_GRAPH_PAD,
217                                         &entity->pads[i].graph_obj);
218         }
219
220         if (mdev)
221                 spin_unlock(&mdev->lock);
222
223         return 0;
224 }
225 EXPORT_SYMBOL_GPL(media_entity_pads_init);
226
227 /* -----------------------------------------------------------------------------
228  * Graph traversal
229  */
230
231 static struct media_entity *
232 media_entity_other(struct media_entity *entity, struct media_link *link)
233 {
234         if (link->source->entity == entity)
235                 return link->sink->entity;
236         else
237                 return link->source->entity;
238 }
239
240 /* push an entity to traversal stack */
241 static void stack_push(struct media_entity_graph *graph,
242                        struct media_entity *entity)
243 {
244         if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
245                 WARN_ON(1);
246                 return;
247         }
248         graph->top++;
249         graph->stack[graph->top].link = entity->links.next;
250         graph->stack[graph->top].entity = entity;
251 }
252
253 static struct media_entity *stack_pop(struct media_entity_graph *graph)
254 {
255         struct media_entity *entity;
256
257         entity = graph->stack[graph->top].entity;
258         graph->top--;
259
260         return entity;
261 }
262
263 #define link_top(en)    ((en)->stack[(en)->top].link)
264 #define stack_top(en)   ((en)->stack[(en)->top].entity)
265
266 /*
267  * TODO: Get rid of this.
268  */
269 #define MEDIA_ENTITY_MAX_PADS           63
270
271 /**
272  * media_entity_graph_walk_init - Allocate resources for graph walk
273  * @graph: Media graph structure that will be used to walk the graph
274  * @mdev: Media device
275  *
276  * Reserve resources for graph walk in media device's current
277  * state. The memory must be released using
278  * media_entity_graph_walk_free().
279  *
280  * Returns error on failure, zero on success.
281  */
282 __must_check int media_entity_graph_walk_init(
283         struct media_entity_graph *graph, struct media_device *mdev)
284 {
285         return media_entity_enum_init(&graph->ent_enum, mdev);
286 }
287 EXPORT_SYMBOL_GPL(media_entity_graph_walk_init);
288
289 /**
290  * media_entity_graph_walk_cleanup - Release resources related to graph walking
291  * @graph: Media graph structure that was used to walk the graph
292  */
293 void media_entity_graph_walk_cleanup(struct media_entity_graph *graph)
294 {
295         media_entity_enum_cleanup(&graph->ent_enum);
296 }
297 EXPORT_SYMBOL_GPL(media_entity_graph_walk_cleanup);
298
299 void media_entity_graph_walk_start(struct media_entity_graph *graph,
300                                    struct media_entity *entity)
301 {
302         media_entity_enum_zero(&graph->ent_enum);
303         media_entity_enum_set(&graph->ent_enum, entity);
304
305         graph->top = 0;
306         graph->stack[graph->top].entity = NULL;
307         stack_push(graph, entity);
308 }
309 EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
310
311 struct media_entity *
312 media_entity_graph_walk_next(struct media_entity_graph *graph)
313 {
314         if (stack_top(graph) == NULL)
315                 return NULL;
316
317         /*
318          * Depth first search. Push entity to stack and continue from
319          * top of the stack until no more entities on the level can be
320          * found.
321          */
322         while (link_top(graph) != &stack_top(graph)->links) {
323                 struct media_entity *entity = stack_top(graph);
324                 struct media_link *link;
325                 struct media_entity *next;
326
327                 link = list_entry(link_top(graph), typeof(*link), list);
328
329                 /* The link is not enabled so we do not follow. */
330                 if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
331                         link_top(graph) = link_top(graph)->next;
332                         continue;
333                 }
334
335                 /* Get the entity in the other end of the link . */
336                 next = media_entity_other(entity, link);
337
338                 /* Has the entity already been visited? */
339                 if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
340                         link_top(graph) = link_top(graph)->next;
341                         continue;
342                 }
343
344                 /* Push the new entity to stack and start over. */
345                 link_top(graph) = link_top(graph)->next;
346                 stack_push(graph, next);
347         }
348
349         return stack_pop(graph);
350 }
351 EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
352
353 /* -----------------------------------------------------------------------------
354  * Pipeline management
355  */
356
357 __must_check int media_entity_pipeline_start(struct media_entity *entity,
358                                              struct media_pipeline *pipe)
359 {
360         struct media_device *mdev = entity->graph_obj.mdev;
361         struct media_entity_graph *graph = &pipe->graph;
362         struct media_entity *entity_err = entity;
363         struct media_link *link;
364         int ret;
365
366         mutex_lock(&mdev->graph_mutex);
367
368         if (!pipe->streaming_count++) {
369                 ret = media_entity_graph_walk_init(&pipe->graph, mdev);
370                 if (ret)
371                         goto error_graph_walk_start;
372         }
373
374         media_entity_graph_walk_start(&pipe->graph, entity);
375
376         while ((entity = media_entity_graph_walk_next(graph))) {
377                 DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
378                 DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
379
380                 entity->stream_count++;
381
382                 if (WARN_ON(entity->pipe && entity->pipe != pipe)) {
383                         ret = -EBUSY;
384                         goto error;
385                 }
386
387                 entity->pipe = pipe;
388
389                 /* Already streaming --- no need to check. */
390                 if (entity->stream_count > 1)
391                         continue;
392
393                 if (!entity->ops || !entity->ops->link_validate)
394                         continue;
395
396                 bitmap_zero(active, entity->num_pads);
397                 bitmap_fill(has_no_links, entity->num_pads);
398
399                 list_for_each_entry(link, &entity->links, list) {
400                         struct media_pad *pad = link->sink->entity == entity
401                                                 ? link->sink : link->source;
402
403                         /* Mark that a pad is connected by a link. */
404                         bitmap_clear(has_no_links, pad->index, 1);
405
406                         /*
407                          * Pads that either do not need to connect or
408                          * are connected through an enabled link are
409                          * fine.
410                          */
411                         if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) ||
412                             link->flags & MEDIA_LNK_FL_ENABLED)
413                                 bitmap_set(active, pad->index, 1);
414
415                         /*
416                          * Link validation will only take place for
417                          * sink ends of the link that are enabled.
418                          */
419                         if (link->sink != pad ||
420                             !(link->flags & MEDIA_LNK_FL_ENABLED))
421                                 continue;
422
423                         ret = entity->ops->link_validate(link);
424                         if (ret < 0 && ret != -ENOIOCTLCMD) {
425                                 dev_dbg(entity->graph_obj.mdev->dev,
426                                         "link validation failed for \"%s\":%u -> \"%s\":%u, error %d\n",
427                                         link->source->entity->name,
428                                         link->source->index,
429                                         entity->name, link->sink->index, ret);
430                                 goto error;
431                         }
432                 }
433
434                 /* Either no links or validated links are fine. */
435                 bitmap_or(active, active, has_no_links, entity->num_pads);
436
437                 if (!bitmap_full(active, entity->num_pads)) {
438                         ret = -EPIPE;
439                         dev_dbg(entity->graph_obj.mdev->dev,
440                                 "\"%s\":%u must be connected by an enabled link\n",
441                                 entity->name,
442                                 (unsigned)find_first_zero_bit(
443                                         active, entity->num_pads));
444                         goto error;
445                 }
446         }
447
448         mutex_unlock(&mdev->graph_mutex);
449
450         return 0;
451
452 error:
453         /*
454          * Link validation on graph failed. We revert what we did and
455          * return the error.
456          */
457         media_entity_graph_walk_start(graph, entity_err);
458
459         while ((entity_err = media_entity_graph_walk_next(graph))) {
460                 entity_err->stream_count--;
461                 if (entity_err->stream_count == 0)
462                         entity_err->pipe = NULL;
463
464                 /*
465                  * We haven't increased stream_count further than this
466                  * so we quit here.
467                  */
468                 if (entity_err == entity)
469                         break;
470         }
471
472 error_graph_walk_start:
473         if (!--pipe->streaming_count)
474                 media_entity_graph_walk_cleanup(graph);
475
476         mutex_unlock(&mdev->graph_mutex);
477
478         return ret;
479 }
480 EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
481
482 void media_entity_pipeline_stop(struct media_entity *entity)
483 {
484         struct media_device *mdev = entity->graph_obj.mdev;
485         struct media_entity_graph *graph = &entity->pipe->graph;
486         struct media_pipeline *pipe = entity->pipe;
487
488         mutex_lock(&mdev->graph_mutex);
489
490         WARN_ON(!pipe->streaming_count);
491         media_entity_graph_walk_start(graph, entity);
492
493         while ((entity = media_entity_graph_walk_next(graph))) {
494                 entity->stream_count--;
495                 if (entity->stream_count == 0)
496                         entity->pipe = NULL;
497         }
498
499         if (!--pipe->streaming_count)
500                 media_entity_graph_walk_cleanup(graph);
501
502         mutex_unlock(&mdev->graph_mutex);
503 }
504 EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
505
506 /* -----------------------------------------------------------------------------
507  * Module use count
508  */
509
510 struct media_entity *media_entity_get(struct media_entity *entity)
511 {
512         if (entity == NULL)
513                 return NULL;
514
515         if (entity->graph_obj.mdev->dev &&
516             !try_module_get(entity->graph_obj.mdev->dev->driver->owner))
517                 return NULL;
518
519         return entity;
520 }
521 EXPORT_SYMBOL_GPL(media_entity_get);
522
523 void media_entity_put(struct media_entity *entity)
524 {
525         if (entity == NULL)
526                 return;
527
528         if (entity->graph_obj.mdev->dev)
529                 module_put(entity->graph_obj.mdev->dev->driver->owner);
530 }
531 EXPORT_SYMBOL_GPL(media_entity_put);
532
533 /* -----------------------------------------------------------------------------
534  * Links management
535  */
536
537 static struct media_link *media_add_link(struct list_head *head)
538 {
539         struct media_link *link;
540
541         link = kzalloc(sizeof(*link), GFP_KERNEL);
542         if (link == NULL)
543                 return NULL;
544
545         list_add_tail(&link->list, head);
546
547         return link;
548 }
549
550 static void __media_entity_remove_link(struct media_entity *entity,
551                                        struct media_link *link)
552 {
553         struct media_link *rlink, *tmp;
554         struct media_entity *remote;
555
556         if (link->source->entity == entity)
557                 remote = link->sink->entity;
558         else
559                 remote = link->source->entity;
560
561         list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
562                 if (rlink != link->reverse)
563                         continue;
564
565                 if (link->source->entity == entity)
566                         remote->num_backlinks--;
567
568                 /* Remove the remote link */
569                 list_del(&rlink->list);
570                 media_gobj_destroy(&rlink->graph_obj);
571                 kfree(rlink);
572
573                 if (--remote->num_links == 0)
574                         break;
575         }
576         list_del(&link->list);
577         media_gobj_destroy(&link->graph_obj);
578         kfree(link);
579 }
580
581 int
582 media_create_pad_link(struct media_entity *source, u16 source_pad,
583                          struct media_entity *sink, u16 sink_pad, u32 flags)
584 {
585         struct media_link *link;
586         struct media_link *backlink;
587
588         BUG_ON(source == NULL || sink == NULL);
589         BUG_ON(source_pad >= source->num_pads);
590         BUG_ON(sink_pad >= sink->num_pads);
591
592         link = media_add_link(&source->links);
593         if (link == NULL)
594                 return -ENOMEM;
595
596         link->source = &source->pads[source_pad];
597         link->sink = &sink->pads[sink_pad];
598         link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;
599
600         /* Initialize graph object embedded at the new link */
601         media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
602                         &link->graph_obj);
603
604         /* Create the backlink. Backlinks are used to help graph traversal and
605          * are not reported to userspace.
606          */
607         backlink = media_add_link(&sink->links);
608         if (backlink == NULL) {
609                 __media_entity_remove_link(source, link);
610                 return -ENOMEM;
611         }
612
613         backlink->source = &source->pads[source_pad];
614         backlink->sink = &sink->pads[sink_pad];
615         backlink->flags = flags;
616         backlink->is_backlink = true;
617
618         /* Initialize graph object embedded at the new link */
619         media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
620                         &backlink->graph_obj);
621
622         link->reverse = backlink;
623         backlink->reverse = link;
624
625         sink->num_backlinks++;
626         sink->num_links++;
627         source->num_links++;
628
629         return 0;
630 }
631 EXPORT_SYMBOL_GPL(media_create_pad_link);
632
633 void __media_entity_remove_links(struct media_entity *entity)
634 {
635         struct media_link *link, *tmp;
636
637         list_for_each_entry_safe(link, tmp, &entity->links, list)
638                 __media_entity_remove_link(entity, link);
639
640         entity->num_links = 0;
641         entity->num_backlinks = 0;
642 }
643 EXPORT_SYMBOL_GPL(__media_entity_remove_links);
644
645 void media_entity_remove_links(struct media_entity *entity)
646 {
647         struct media_device *mdev = entity->graph_obj.mdev;
648
649         /* Do nothing if the entity is not registered. */
650         if (mdev == NULL)
651                 return;
652
653         spin_lock(&mdev->lock);
654         __media_entity_remove_links(entity);
655         spin_unlock(&mdev->lock);
656 }
657 EXPORT_SYMBOL_GPL(media_entity_remove_links);
658
659 static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
660 {
661         int ret;
662
663         /* Notify both entities. */
664         ret = media_entity_call(link->source->entity, link_setup,
665                                 link->source, link->sink, flags);
666         if (ret < 0 && ret != -ENOIOCTLCMD)
667                 return ret;
668
669         ret = media_entity_call(link->sink->entity, link_setup,
670                                 link->sink, link->source, flags);
671         if (ret < 0 && ret != -ENOIOCTLCMD) {
672                 media_entity_call(link->source->entity, link_setup,
673                                   link->source, link->sink, link->flags);
674                 return ret;
675         }
676
677         link->flags = flags;
678         link->reverse->flags = link->flags;
679
680         return 0;
681 }
682
683 int __media_entity_setup_link(struct media_link *link, u32 flags)
684 {
685         const u32 mask = MEDIA_LNK_FL_ENABLED;
686         struct media_device *mdev;
687         struct media_entity *source, *sink;
688         int ret = -EBUSY;
689
690         if (link == NULL)
691                 return -EINVAL;
692
693         /* The non-modifiable link flags must not be modified. */
694         if ((link->flags & ~mask) != (flags & ~mask))
695                 return -EINVAL;
696
697         if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
698                 return link->flags == flags ? 0 : -EINVAL;
699
700         if (link->flags == flags)
701                 return 0;
702
703         source = link->source->entity;
704         sink = link->sink->entity;
705
706         if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
707             (source->stream_count || sink->stream_count))
708                 return -EBUSY;
709
710         mdev = source->graph_obj.mdev;
711
712         if (mdev->link_notify) {
713                 ret = mdev->link_notify(link, flags,
714                                         MEDIA_DEV_NOTIFY_PRE_LINK_CH);
715                 if (ret < 0)
716                         return ret;
717         }
718
719         ret = __media_entity_setup_link_notify(link, flags);
720
721         if (mdev->link_notify)
722                 mdev->link_notify(link, flags, MEDIA_DEV_NOTIFY_POST_LINK_CH);
723
724         return ret;
725 }
726
727 int media_entity_setup_link(struct media_link *link, u32 flags)
728 {
729         int ret;
730
731         mutex_lock(&link->graph_obj.mdev->graph_mutex);
732         ret = __media_entity_setup_link(link, flags);
733         mutex_unlock(&link->graph_obj.mdev->graph_mutex);
734
735         return ret;
736 }
737 EXPORT_SYMBOL_GPL(media_entity_setup_link);
738
739 struct media_link *
740 media_entity_find_link(struct media_pad *source, struct media_pad *sink)
741 {
742         struct media_link *link;
743
744         list_for_each_entry(link, &source->entity->links, list) {
745                 if (link->source->entity == source->entity &&
746                     link->source->index == source->index &&
747                     link->sink->entity == sink->entity &&
748                     link->sink->index == sink->index)
749                         return link;
750         }
751
752         return NULL;
753 }
754 EXPORT_SYMBOL_GPL(media_entity_find_link);
755
756 struct media_pad *media_entity_remote_pad(struct media_pad *pad)
757 {
758         struct media_link *link;
759
760         list_for_each_entry(link, &pad->entity->links, list) {
761                 if (!(link->flags & MEDIA_LNK_FL_ENABLED))
762                         continue;
763
764                 if (link->source == pad)
765                         return link->sink;
766
767                 if (link->sink == pad)
768                         return link->source;
769         }
770
771         return NULL;
772
773 }
774 EXPORT_SYMBOL_GPL(media_entity_remote_pad);
775
776 static void media_interface_init(struct media_device *mdev,
777                                  struct media_interface *intf,
778                                  u32 gobj_type,
779                                  u32 intf_type, u32 flags)
780 {
781         intf->type = intf_type;
782         intf->flags = flags;
783         INIT_LIST_HEAD(&intf->links);
784
785         media_gobj_create(mdev, gobj_type, &intf->graph_obj);
786 }
787
788 /* Functions related to the media interface via device nodes */
789
790 struct media_intf_devnode *media_devnode_create(struct media_device *mdev,
791                                                 u32 type, u32 flags,
792                                                 u32 major, u32 minor)
793 {
794         struct media_intf_devnode *devnode;
795
796         devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
797         if (!devnode)
798                 return NULL;
799
800         devnode->major = major;
801         devnode->minor = minor;
802
803         media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE,
804                              type, flags);
805
806         return devnode;
807 }
808 EXPORT_SYMBOL_GPL(media_devnode_create);
809
810 void media_devnode_remove(struct media_intf_devnode *devnode)
811 {
812         media_remove_intf_links(&devnode->intf);
813         media_gobj_destroy(&devnode->intf.graph_obj);
814         kfree(devnode);
815 }
816 EXPORT_SYMBOL_GPL(media_devnode_remove);
817
818 struct media_link *media_create_intf_link(struct media_entity *entity,
819                                             struct media_interface *intf,
820                                             u32 flags)
821 {
822         struct media_link *link;
823
824         link = media_add_link(&intf->links);
825         if (link == NULL)
826                 return NULL;
827
828         link->intf = intf;
829         link->entity = entity;
830         link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK;
831
832         /* Initialize graph object embedded at the new link */
833         media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK,
834                         &link->graph_obj);
835
836         return link;
837 }
838 EXPORT_SYMBOL_GPL(media_create_intf_link);
839
840 void __media_remove_intf_link(struct media_link *link)
841 {
842         list_del(&link->list);
843         media_gobj_destroy(&link->graph_obj);
844         kfree(link);
845 }
846 EXPORT_SYMBOL_GPL(__media_remove_intf_link);
847
848 void media_remove_intf_link(struct media_link *link)
849 {
850         struct media_device *mdev = link->graph_obj.mdev;
851
852         /* Do nothing if the intf is not registered. */
853         if (mdev == NULL)
854                 return;
855
856         spin_lock(&mdev->lock);
857         __media_remove_intf_link(link);
858         spin_unlock(&mdev->lock);
859 }
860 EXPORT_SYMBOL_GPL(media_remove_intf_link);
861
862 void __media_remove_intf_links(struct media_interface *intf)
863 {
864         struct media_link *link, *tmp;
865
866         list_for_each_entry_safe(link, tmp, &intf->links, list)
867                 __media_remove_intf_link(link);
868
869 }
870 EXPORT_SYMBOL_GPL(__media_remove_intf_links);
871
872 void media_remove_intf_links(struct media_interface *intf)
873 {
874         struct media_device *mdev = intf->graph_obj.mdev;
875
876         /* Do nothing if the intf is not registered. */
877         if (mdev == NULL)
878                 return;
879
880         spin_lock(&mdev->lock);
881         __media_remove_intf_links(intf);
882         spin_unlock(&mdev->lock);
883 }
884 EXPORT_SYMBOL_GPL(media_remove_intf_links);