Linux Audio

Check our new training course

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