File Index
Files and directories
Sign in
FILE

mc-entity.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/mc/mc-entity.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Media entity
   4 *
   5 * Copyright (C) 2010 Nokia Corporation
   6 *
   7 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
   8 *	     Sakari Ailus <sakari.ailus@iki.fi>
   9 */
  10
  11#include <linux/bitmap.h>
  12#include <linux/list.h>
  13#include <linux/property.h>
  14#include <linux/slab.h>
  15#include <media/media-entity.h>
  16#include <media/media-device.h>
  17
  18static inline const char *intf_type(struct media_interface *intf)
  19{
  20	switch (intf->type) {
  21	case MEDIA_INTF_T_DVB_FE:
  22		return "dvb-frontend";
  23	case MEDIA_INTF_T_DVB_DEMUX:
  24		return "dvb-demux";
  25	case MEDIA_INTF_T_DVB_DVR:
  26		return "dvb-dvr";
  27	case MEDIA_INTF_T_DVB_CA:
  28		return  "dvb-ca";
  29	case MEDIA_INTF_T_DVB_NET:
  30		return "dvb-net";
  31	case MEDIA_INTF_T_V4L_VIDEO:
  32		return "v4l-video";
  33	case MEDIA_INTF_T_V4L_VBI:
  34		return "v4l-vbi";
  35	case MEDIA_INTF_T_V4L_RADIO:
  36		return "v4l-radio";
  37	case MEDIA_INTF_T_V4L_SUBDEV:
  38		return "v4l-subdev";
  39	case MEDIA_INTF_T_V4L_SWRADIO:
  40		return "v4l-swradio";
  41	case MEDIA_INTF_T_V4L_TOUCH:
  42		return "v4l-touch";
  43	default:
  44		return "unknown-intf";
  45	}
  46};
  47
  48static inline const char *link_type_name(struct media_link *link)
  49{
  50	switch (link->flags & MEDIA_LNK_FL_LINK_TYPE) {
  51	case MEDIA_LNK_FL_DATA_LINK:
  52		return "data";
  53	case MEDIA_LNK_FL_INTERFACE_LINK:
  54		return "interface";
  55	case MEDIA_LNK_FL_ANCILLARY_LINK:
  56		return "ancillary";
  57	default:
  58		return "unknown";
  59	}
  60}
  61
  62__must_check int media_entity_enum_init(struct media_entity_enum *ent_enum,
  63					struct media_device *mdev)
  64{
  65	int idx_max;
  66
  67	idx_max = ALIGN(mdev->entity_internal_idx_max + 1, BITS_PER_LONG);
  68	ent_enum->bmap = bitmap_zalloc(idx_max, GFP_KERNEL);
  69	if (!ent_enum->bmap)
  70		return -ENOMEM;
  71
  72	ent_enum->idx_max = idx_max;
  73
  74	return 0;
  75}
  76EXPORT_SYMBOL_GPL(media_entity_enum_init);
  77
  78void media_entity_enum_cleanup(struct media_entity_enum *ent_enum)
  79{
  80	bitmap_free(ent_enum->bmap);
  81}
  82EXPORT_SYMBOL_GPL(media_entity_enum_cleanup);
  83
  84/**
  85 *  dev_dbg_obj - Prints in debug mode a change on some object
  86 *
  87 * @event_name:	Name of the event to report. Could be __func__
  88 * @gobj:	Pointer to the object
  89 *
  90 * Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it
  91 * won't produce any code.
  92 */
  93static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
  94{
  95#if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG)
  96	switch (media_type(gobj)) {
  97	case MEDIA_GRAPH_ENTITY:
  98		dev_dbg(gobj->mdev->dev,
  99			"%s id %u: entity '%s'\n",
 100			event_name, media_id(gobj),
 101			gobj_to_entity(gobj)->name);
 102		break;
 103	case MEDIA_GRAPH_LINK:
 104	{
 105		struct media_link *link = gobj_to_link(gobj);
 106
 107		dev_dbg(gobj->mdev->dev,
 108			"%s id %u: %s link id %u ==> id %u\n",
 109			event_name, media_id(gobj), link_type_name(link),
 110			media_id(link->gobj0),
 111			media_id(link->gobj1));
 112		break;
 113	}
 114	case MEDIA_GRAPH_PAD:
 115	{
 116		struct media_pad *pad = gobj_to_pad(gobj);
 117
 118		dev_dbg(gobj->mdev->dev,
 119			"%s id %u: %s%spad '%s':%d\n",
 120			event_name, media_id(gobj),
 121			pad->flags & MEDIA_PAD_FL_SINK   ? "sink " : "",
 122			pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "",
 123			pad->entity->name, pad->index);
 124		break;
 125	}
 126	case MEDIA_GRAPH_INTF_DEVNODE:
 127	{
 128		struct media_interface *intf = gobj_to_intf(gobj);
 129		struct media_intf_devnode *devnode = intf_to_devnode(intf);
 130
 131		dev_dbg(gobj->mdev->dev,
 132			"%s id %u: intf_devnode %s - major: %d, minor: %d\n",
 133			event_name, media_id(gobj),
 134			intf_type(intf),
 135			devnode->major, devnode->minor);
 136		break;
 137	}
 138	}
 139#endif
 140}
 141
 142void media_gobj_create(struct media_device *mdev,
 143			   enum media_gobj_type type,
 144			   struct media_gobj *gobj)
 145{
 146	BUG_ON(!mdev);
 147
 148	gobj->mdev = mdev;
 149
 150	/* Create a per-type unique object ID */
 151	gobj->id = media_gobj_gen_id(type, ++mdev->id);
 152
 153	switch (type) {
 154	case MEDIA_GRAPH_ENTITY:
 155		list_add_tail(&gobj->list, &mdev->entities);
 156		break;
 157	case MEDIA_GRAPH_PAD:
 158		list_add_tail(&gobj->list, &mdev->pads);
 159		break;
 160	case MEDIA_GRAPH_LINK:
 161		list_add_tail(&gobj->list, &mdev->links);
 162		break;
 163	case MEDIA_GRAPH_INTF_DEVNODE:
 164		list_add_tail(&gobj->list, &mdev->interfaces);
 165		break;
 166	}
 167
 168	mdev->topology_version++;
 169
 170	dev_dbg_obj(__func__, gobj);
 171}
 172
 173void media_gobj_destroy(struct media_gobj *gobj)
 174{
 175	/* Do nothing if the object is not linked. */
 176	if (gobj->mdev == NULL)
 177		return;
 178
 179	dev_dbg_obj(__func__, gobj);
 180
 181	gobj->mdev->topology_version++;
 182
 183	/* Remove the object from mdev list */
 184	list_del(&gobj->list);
 185
 186	gobj->mdev = NULL;
 187}
 188
 189/*
 190 * TODO: Get rid of this.
 191 */
 192#define MEDIA_ENTITY_MAX_PADS		512
 193
 194int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
 195			   struct media_pad *pads)
 196{
 197	struct media_device *mdev = entity->graph_obj.mdev;
 198	struct media_pad *iter;
 199	unsigned int i = 0;
 200	int ret = 0;
 201
 202	if (num_pads >= MEDIA_ENTITY_MAX_PADS)
 203		return -E2BIG;
 204
 205	entity->num_pads = num_pads;
 206	entity->pads = pads;
 207
 208	if (mdev)
 209		mutex_lock(&mdev->graph_mutex);
 210
 211	media_entity_for_each_pad(entity, iter) {
 212		iter->entity = entity;
 213		iter->index = i++;
 214
 215		if (hweight32(iter->flags & (MEDIA_PAD_FL_SINK |
 216					     MEDIA_PAD_FL_SOURCE)) != 1) {
 217			ret = -EINVAL;
 218			break;
 219		}
 220
 221		if (mdev)
 222			media_gobj_create(mdev, MEDIA_GRAPH_PAD,
 223					  &iter->graph_obj);
 224	}
 225
 226	if (ret && mdev) {
 227		media_entity_for_each_pad(entity, iter)
 228			media_gobj_destroy(&iter->graph_obj);
 229	}
 230
 231	if (mdev)
 232		mutex_unlock(&mdev->graph_mutex);
 233
 234	return ret;
 235}
 236EXPORT_SYMBOL_GPL(media_entity_pads_init);
 237
 238/* -----------------------------------------------------------------------------
 239 * Graph traversal
 240 */
 241
 242/**
 243 * media_entity_has_pad_interdep - Check interdependency between two pads
 244 *
 245 * @entity: The entity
 246 * @pad0: The first pad index
 247 * @pad1: The second pad index
 248 *
 249 * This function checks the interdependency inside the entity between @pad0
 250 * and @pad1. If two pads are interdependent they are part of the same pipeline
 251 * and enabling one of the pads means that the other pad will become "locked"
 252 * and doesn't allow configuration changes.
 253 *
 254 * This function uses the &media_entity_operations.has_pad_interdep() operation
 255 * to check the dependency inside the entity between @pad0 and @pad1. If the
 256 * has_pad_interdep operation is not implemented, all pads of the entity are
 257 * considered to be interdependent.
 258 *
 259 * One of @pad0 and @pad1 must be a sink pad and the other one a source pad.
 260 * The function returns false if both pads are sinks or sources.
 261 *
 262 * The caller must hold entity->graph_obj.mdev->mutex.
 263 *
 264 * Return: true if the pads are connected internally and false otherwise.
 265 */
 266static bool media_entity_has_pad_interdep(struct media_entity *entity,
 267					  unsigned int pad0, unsigned int pad1)
 268{
 269	if (pad0 >= entity->num_pads || pad1 >= entity->num_pads)
 270		return false;
 271
 272	if (entity->pads[pad0].flags & entity->pads[pad1].flags &
 273	    (MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_SOURCE))
 274		return false;
 275
 276	if (!entity->ops || !entity->ops->has_pad_interdep)
 277		return true;
 278
 279	return entity->ops->has_pad_interdep(entity, pad0, pad1);
 280}
 281
 282static struct media_entity *
 283media_entity_other(struct media_entity *entity, struct media_link *link)
 284{
 285	if (link->source->entity == entity)
 286		return link->sink->entity;
 287	else
 288		return link->source->entity;
 289}
 290
 291/* push an entity to traversal stack */
 292static void stack_push(struct media_graph *graph,
 293		       struct media_entity *entity)
 294{
 295	if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
 296		WARN_ON(1);
 297		return;
 298	}
 299	graph->top++;
 300	graph->stack[graph->top].link = entity->links.next;
 301	graph->stack[graph->top].entity = entity;
 302}
 303
 304static struct media_entity *stack_pop(struct media_graph *graph)
 305{
 306	struct media_entity *entity;
 307
 308	entity = graph->stack[graph->top].entity;
 309	graph->top--;
 310
 311	return entity;
 312}
 313
 314#define link_top(en)	((en)->stack[(en)->top].link)
 315#define stack_top(en)	((en)->stack[(en)->top].entity)
 316
 317/**
 318 * media_graph_walk_init - Allocate resources for graph walk
 319 * @graph: Media graph structure that will be used to walk the graph
 320 * @mdev: Media device
 321 *
 322 * Reserve resources for graph walk in media device's current
 323 * state. The memory must be released using
 324 * media_graph_walk_cleanup().
 325 *
 326 * Returns error on failure, zero on success.
 327 */
 328__must_check int media_graph_walk_init(
 329	struct media_graph *graph, struct media_device *mdev)
 330{
 331	return media_entity_enum_init(&graph->ent_enum, mdev);
 332}
 333EXPORT_SYMBOL_GPL(media_graph_walk_init);
 334
 335/**
 336 * media_graph_walk_cleanup - Release resources related to graph walking
 337 * @graph: Media graph structure that was used to walk the graph
 338 */
 339void media_graph_walk_cleanup(struct media_graph *graph)
 340{
 341	media_entity_enum_cleanup(&graph->ent_enum);
 342}
 343EXPORT_SYMBOL_GPL(media_graph_walk_cleanup);
 344
 345void media_graph_walk_start(struct media_graph *graph,
 346			    struct media_entity *entity)
 347{
 348	media_entity_enum_zero(&graph->ent_enum);
 349	media_entity_enum_set(&graph->ent_enum, entity);
 350
 351	graph->top = 0;
 352	graph->stack[graph->top].entity = NULL;
 353	stack_push(graph, entity);
 354	dev_dbg(entity->graph_obj.mdev->dev,
 355		"begin graph walk at '%s'\n", entity->name);
 356}
 357EXPORT_SYMBOL_GPL(media_graph_walk_start);
 358
 359static void media_graph_walk_iter(struct media_graph *graph)
 360{
 361	struct media_entity *entity = stack_top(graph);
 362	struct media_link *link;
 363	struct media_entity *next;
 364
 365	link = list_entry(link_top(graph), typeof(*link), list);
 366
 367	/* If the link is not a data link, don't follow it */
 368	if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) != MEDIA_LNK_FL_DATA_LINK) {
 369		link_top(graph) = link_top(graph)->next;
 370		return;
 371	}
 372
 373	/* The link is not enabled so we do not follow. */
 374	if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
 375		link_top(graph) = link_top(graph)->next;
 376		dev_dbg(entity->graph_obj.mdev->dev,
 377			"walk: skipping disabled link '%s':%u -> '%s':%u\n",
 378			link->source->entity->name, link->source->index,
 379			link->sink->entity->name, link->sink->index);
 380		return;
 381	}
 382
 383	/* Get the entity at the other end of the link. */
 384	next = media_entity_other(entity, link);
 385
 386	/* Has the entity already been visited? */
 387	if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
 388		link_top(graph) = link_top(graph)->next;
 389		dev_dbg(entity->graph_obj.mdev->dev,
 390			"walk: skipping entity '%s' (already seen)\n",
 391			next->name);
 392		return;
 393	}
 394
 395	/* Push the new entity to stack and start over. */
 396	link_top(graph) = link_top(graph)->next;
 397	stack_push(graph, next);
 398	dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
 399		next->name);
 400	lockdep_assert_held(&entity->graph_obj.mdev->graph_mutex);
 401}
 402
 403struct media_entity *media_graph_walk_next(struct media_graph *graph)
 404{
 405	struct media_entity *entity;
 406
 407	if (stack_top(graph) == NULL)
 408		return NULL;
 409
 410	/*
 411	 * Depth first search. Push entity to stack and continue from
 412	 * top of the stack until no more entities on the level can be
 413	 * found.
 414	 */
 415	while (link_top(graph) != &stack_top(graph)->links)
 416		media_graph_walk_iter(graph);
 417
 418	entity = stack_pop(graph);
 419	dev_dbg(entity->graph_obj.mdev->dev,
 420		"walk: returning entity '%s'\n", entity->name);
 421
 422	return entity;
 423}
 424EXPORT_SYMBOL_GPL(media_graph_walk_next);
 425
 426/* -----------------------------------------------------------------------------
 427 * Pipeline management
 428 */
 429
 430/*
 431 * The pipeline traversal stack stores pads that are reached during graph
 432 * traversal, with a list of links to be visited to continue the traversal.
 433 * When a new pad is reached, an entry is pushed on the top of the stack and
 434 * points to the incoming pad and the first link of the entity.
 435 *
 436 * To find further pads in the pipeline, the traversal algorithm follows
 437 * internal pad dependencies in the entity, and then links in the graph. It
 438 * does so by iterating over all links of the entity, and following enabled
 439 * links that originate from a pad that is internally connected to the incoming
 440 * pad, as reported by the media_entity_has_pad_interdep() function.
 441 */
 442
 443/**
 444 * struct media_pipeline_walk_entry - Entry in the pipeline traversal stack
 445 *
 446 * @pad: The media pad being visited
 447 * @links: Links left to be visited
 448 */
 449struct media_pipeline_walk_entry {
 450	struct media_pad *pad;
 451	struct list_head *links;
 452};
 453
 454/**
 455 * struct media_pipeline_walk - State used by the media pipeline traversal
 456 *				algorithm
 457 *
 458 * @mdev: The media device
 459 * @stack: Depth-first search stack
 460 * @stack.size: Number of allocated entries in @stack.entries
 461 * @stack.top: Index of the top stack entry (-1 if the stack is empty)
 462 * @stack.entries: Stack entries
 463 */
 464struct media_pipeline_walk {
 465	struct media_device *mdev;
 466
 467	struct {
 468		unsigned int size;
 469		int top;
 470		struct media_pipeline_walk_entry *entries;
 471	} stack;
 472};
 473
 474#define MEDIA_PIPELINE_STACK_GROW_STEP		16
 475
 476static struct media_pipeline_walk_entry *
 477media_pipeline_walk_top(struct media_pipeline_walk *walk)
 478{
 479	return &walk->stack.entries[walk->stack.top];
 480}
 481
 482static bool media_pipeline_walk_empty(struct media_pipeline_walk *walk)
 483{
 484	return walk->stack.top == -1;
 485}
 486
 487/* Increase the stack size by MEDIA_PIPELINE_STACK_GROW_STEP elements. */
 488static int media_pipeline_walk_resize(struct media_pipeline_walk *walk)
 489{
 490	struct media_pipeline_walk_entry *entries;
 491	unsigned int new_size;
 492
 493	/* Safety check, to avoid stack overflows in case of bugs. */
 494	if (walk->stack.size >= 256)
 495		return -E2BIG;
 496
 497	new_size = walk->stack.size + MEDIA_PIPELINE_STACK_GROW_STEP;
 498
 499	entries = krealloc(walk->stack.entries,
 500			   new_size * sizeof(*walk->stack.entries),
 501			   GFP_KERNEL);
 502	if (!entries)
 503		return -ENOMEM;
 504
 505	walk->stack.entries = entries;
 506	walk->stack.size = new_size;
 507
 508	return 0;
 509}
 510
 511/* Push a new entry on the stack. */
 512static int media_pipeline_walk_push(struct media_pipeline_walk *walk,
 513				    struct media_pad *pad)
 514{
 515	struct media_pipeline_walk_entry *entry;
 516	int ret;
 517
 518	if (walk->stack.top + 1 >= walk->stack.size) {
 519		ret = media_pipeline_walk_resize(walk);
 520		if (ret)
 521			return ret;
 522	}
 523
 524	walk->stack.top++;
 525	entry = media_pipeline_walk_top(walk);
 526	entry->pad = pad;
 527	entry->links = pad->entity->links.next;
 528
 529	dev_dbg(walk->mdev->dev,
 530		"media pipeline: pushed entry %u: '%s':%u\n",
 531		walk->stack.top, pad->entity->name, pad->index);
 532
 533	return 0;
 534}
 535
 536/*
 537 * Move the top entry link cursor to the next link. If all links of the entry
 538 * have been visited, pop the entry itself. Return true if the entry has been
 539 * popped.
 540 */
 541static bool media_pipeline_walk_pop(struct media_pipeline_walk *walk)
 542{
 543	struct media_pipeline_walk_entry *entry;
 544
 545	if (WARN_ON(walk->stack.top < 0))
 546		return false;
 547
 548	entry = media_pipeline_walk_top(walk);
 549
 550	if (entry->links->next == &entry->pad->entity->links) {
 551		dev_dbg(walk->mdev->dev,
 552			"media pipeline: entry %u has no more links, popping\n",
 553			walk->stack.top);
 554
 555		walk->stack.top--;
 556		return true;
 557	}
 558
 559	entry->links = entry->links->next;
 560
 561	dev_dbg(walk->mdev->dev,
 562		"media pipeline: moved entry %u to next link\n",
 563		walk->stack.top);
 564
 565	return false;
 566}
 567
 568/* Free all memory allocated while walking the pipeline. */
 569static void media_pipeline_walk_destroy(struct media_pipeline_walk *walk)
 570{
 571	kfree(walk->stack.entries);
 572}
 573
 574/* Add a pad to the pipeline and push it to the stack. */
 575static int media_pipeline_add_pad(struct media_pipeline *pipe,
 576				  struct media_pipeline_walk *walk,
 577				  struct media_pad *pad)
 578{
 579	struct media_pipeline_pad *ppad;
 580
 581	list_for_each_entry(ppad, &pipe->pads, list) {
 582		if (ppad->pad == pad) {
 583			dev_dbg(pad->graph_obj.mdev->dev,
 584				"media pipeline: already contains pad '%s':%u\n",
 585				pad->entity->name, pad->index);
 586			return 0;
 587		}
 588	}
 589
 590	ppad = kzalloc(sizeof(*ppad), GFP_KERNEL);
 591	if (!ppad)
 592		return -ENOMEM;
 593
 594	ppad->pipe = pipe;
 595	ppad->pad = pad;
 596
 597	list_add_tail(&ppad->list, &pipe->pads);
 598
 599	dev_dbg(pad->graph_obj.mdev->dev,
 600		"media pipeline: added pad '%s':%u\n",
 601		pad->entity->name, pad->index);
 602
 603	return media_pipeline_walk_push(walk, pad);
 604}
 605
 606/* Explore the next link of the entity at the top of the stack. */
 607static int media_pipeline_explore_next_link(struct media_pipeline *pipe,
 608					    struct media_pipeline_walk *walk)
 609{
 610	struct media_pipeline_walk_entry *entry = media_pipeline_walk_top(walk);
 611	struct media_pad *origin;
 612	struct media_link *link;
 613	struct media_pad *local;
 614	struct media_pad *remote;
 615	bool last_link;
 616	int ret;
 617
 618	origin = entry->pad;
 619	link = list_entry(entry->links, typeof(*link), list);
 620	last_link = media_pipeline_walk_pop(walk);
 621
 622	if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) != MEDIA_LNK_FL_DATA_LINK) {
 623		dev_dbg(walk->mdev->dev,
 624			"media pipeline: skipping link (not data-link)\n");
 625		return 0;
 626	}
 627
 628	dev_dbg(walk->mdev->dev,
 629		"media pipeline: exploring link '%s':%u -> '%s':%u\n",
 630		link->source->entity->name, link->source->index,
 631		link->sink->entity->name, link->sink->index);
 632
 633	/* Get the local pad and remote pad. */
 634	if (link->source->entity == origin->entity) {
 635		local = link->source;
 636		remote = link->sink;
 637	} else {
 638		local = link->sink;
 639		remote = link->source;
 640	}
 641
 642	/*
 643	 * Skip links that originate from a different pad than the incoming pad
 644	 * that is not connected internally in the entity to the incoming pad.
 645	 */
 646	if (origin != local &&
 647	    !media_entity_has_pad_interdep(origin->entity, origin->index,
 648					   local->index)) {
 649		dev_dbg(walk->mdev->dev,
 650			"media pipeline: skipping link (no route)\n");
 651		goto done;
 652	}
 653
 654	/*
 655	 * Add the local pad of the link to the pipeline and push it to the
 656	 * stack, if not already present.
 657	 */
 658	ret = media_pipeline_add_pad(pipe, walk, local);
 659	if (ret)
 660		return ret;
 661
 662	/* Similarly, add the remote pad, but only if the link is enabled. */
 663	if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
 664		dev_dbg(walk->mdev->dev,
 665			"media pipeline: skipping link (disabled)\n");
 666		goto done;
 667	}
 668
 669	ret = media_pipeline_add_pad(pipe, walk, remote);
 670	if (ret)
 671		return ret;
 672
 673done:
 674	/*
 675	 * If we're done iterating over links, iterate over pads of the entity.
 676	 * This is necessary to discover pads that are not connected with any
 677	 * link. Those are dead ends from a pipeline exploration point of view,
 678	 * but are still part of the pipeline and need to be added to enable
 679	 * proper validation.
 680	 */
 681	if (!last_link)
 682		return 0;
 683
 684	dev_dbg(walk->mdev->dev,
 685		"media pipeline: adding unconnected pads of '%s' reachable from pad %u\n",
 686		origin->entity->name, origin->index);
 687
 688	media_entity_for_each_pad(origin->entity, local) {
 689		/*
 690		 * Skip the origin pad (already handled), pad that have links
 691		 * (already discovered through iterating over links) and pads
 692		 * not internally connected.
 693		 */
 694		if (origin == local || local->num_links ||
 695		    !media_entity_has_pad_interdep(origin->entity, origin->index,
 696						   local->index))
 697			continue;
 698
 699		ret = media_pipeline_add_pad(pipe, walk, local);
 700		if (ret)
 701			return ret;
 702	}
 703
 704	return 0;
 705}
 706
 707static void media_pipeline_cleanup(struct media_pipeline *pipe)
 708{
 709	while (!list_empty(&pipe->pads)) {
 710		struct media_pipeline_pad *ppad;
 711
 712		ppad = list_first_entry(&pipe->pads, typeof(*ppad), list);
 713		list_del(&ppad->list);
 714		kfree(ppad);
 715	}
 716}
 717
 718static int media_pipeline_populate(struct media_pipeline *pipe,
 719				   struct media_pad *pad)
 720{
 721	struct media_pipeline_walk walk = { };
 722	struct media_pipeline_pad *ppad;
 723	int ret;
 724
 725	/*
 726	 * Populate the media pipeline by walking the media graph, starting
 727	 * from @pad.
 728	 */
 729	INIT_LIST_HEAD(&pipe->pads);
 730	pipe->mdev = pad->graph_obj.mdev;
 731
 732	walk.mdev = pipe->mdev;
 733	walk.stack.top = -1;
 734	ret = media_pipeline_add_pad(pipe, &walk, pad);
 735	if (ret)
 736		goto done;
 737
 738	/*
 739	 * Use a depth-first search algorithm: as long as the stack is not
 740	 * empty, explore the next link of the top entry. The
 741	 * media_pipeline_explore_next_link() function will either move to the
 742	 * next link, pop the entry if fully visited, or add new entries on
 743	 * top.
 744	 */
 745	while (!media_pipeline_walk_empty(&walk)) {
 746		ret = media_pipeline_explore_next_link(pipe, &walk);
 747		if (ret)
 748			goto done;
 749	}
 750
 751	dev_dbg(pad->graph_obj.mdev->dev,
 752		"media pipeline populated, found pads:\n");
 753
 754	list_for_each_entry(ppad, &pipe->pads, list)
 755		dev_dbg(pad->graph_obj.mdev->dev, "- '%s':%u\n",
 756			ppad->pad->entity->name, ppad->pad->index);
 757
 758	WARN_ON(walk.stack.top != -1);
 759
 760	ret = 0;
 761
 762done:
 763	media_pipeline_walk_destroy(&walk);
 764
 765	if (ret)
 766		media_pipeline_cleanup(pipe);
 767
 768	return ret;
 769}
 770
 771__must_check int __media_pipeline_start(struct media_pad *origin,
 772					struct media_pipeline *pipe)
 773{
 774	struct media_device *mdev = origin->graph_obj.mdev;
 775	struct media_pipeline_pad *err_ppad;
 776	struct media_pipeline_pad *ppad;
 777	int ret;
 778
 779	lockdep_assert_held(&mdev->graph_mutex);
 780
 781	/*
 782	 * If the pad is already part of a pipeline, that pipeline must be the
 783	 * same as the pipe given to media_pipeline_start().
 784	 */
 785	if (WARN_ON(origin->pipe && origin->pipe != pipe))
 786		return -EINVAL;
 787
 788	/*
 789	 * If the pipeline has already been started, it is guaranteed to be
 790	 * valid, so just increase the start count.
 791	 */
 792	if (pipe->start_count) {
 793		pipe->start_count++;
 794		return 0;
 795	}
 796
 797	/*
 798	 * Populate the pipeline. This populates the media_pipeline pads list
 799	 * with media_pipeline_pad instances for each pad found during graph
 800	 * walk.
 801	 */
 802	ret = media_pipeline_populate(pipe, origin);
 803	if (ret)
 804		return ret;
 805
 806	/*
 807	 * Now that all the pads in the pipeline have been gathered, perform
 808	 * the validation steps.
 809	 */
 810
 811	list_for_each_entry(ppad, &pipe->pads, list) {
 812		struct media_pad *pad = ppad->pad;
 813		struct media_entity *entity = pad->entity;
 814		bool has_enabled_link = false;
 815		struct media_link *link;
 816
 817		dev_dbg(mdev->dev, "Validating pad '%s':%u\n", pad->entity->name,
 818			pad->index);
 819
 820		/*
 821		 * 1. Ensure that the pad doesn't already belong to a different
 822		 * pipeline.
 823		 */
 824		if (pad->pipe) {
 825			dev_dbg(mdev->dev, "Failed to start pipeline: pad '%s':%u busy\n",
 826				pad->entity->name, pad->index);
 827			ret = -EBUSY;
 828			goto error;
 829		}
 830
 831		/*
 832		 * 2. Validate all active links whose sink is the current pad.
 833		 * Validation of the source pads is performed in the context of
 834		 * the connected sink pad to avoid duplicating checks.
 835		 */
 836		for_each_media_entity_data_link(entity, link) {
 837			/* Skip links unrelated to the current pad. */
 838			if (link->sink != pad && link->source != pad)
 839				continue;
 840
 841			/* Record if the pad has links and enabled links. */
 842			if (link->flags & MEDIA_LNK_FL_ENABLED)
 843				has_enabled_link = true;
 844
 845			/*
 846			 * Validate the link if it's enabled and has the
 847			 * current pad as its sink.
 848			 */
 849			if (!(link->flags & MEDIA_LNK_FL_ENABLED))
 850				continue;
 851
 852			if (link->sink != pad)
 853				continue;
 854
 855			if (!entity->ops || !entity->ops->link_validate)
 856				continue;
 857
 858			ret = entity->ops->link_validate(link);
 859			if (ret) {
 860				dev_dbg(mdev->dev,
 861					"Link '%s':%u -> '%s':%u failed validation: %d\n",
 862					link->source->entity->name,
 863					link->source->index,
 864					link->sink->entity->name,
 865					link->sink->index, ret);
 866				goto error;
 867			}
 868
 869			dev_dbg(mdev->dev,
 870				"Link '%s':%u -> '%s':%u is valid\n",
 871				link->source->entity->name,
 872				link->source->index,
 873				link->sink->entity->name,
 874				link->sink->index);
 875		}
 876
 877		/*
 878		 * 3. If the pad has the MEDIA_PAD_FL_MUST_CONNECT flag set,
 879		 * ensure that it has either no link or an enabled link.
 880		 */
 881		if ((pad->flags & MEDIA_PAD_FL_MUST_CONNECT) &&
 882		    !has_enabled_link) {
 883			dev_dbg(mdev->dev,
 884				"Pad '%s':%u must be connected by an enabled link\n",
 885				pad->entity->name, pad->index);
 886			ret = -ENOLINK;
 887			goto error;
 888		}
 889
 890		/* Validation passed, store the pipe pointer in the pad. */
 891		pad->pipe = pipe;
 892	}
 893
 894	pipe->start_count++;
 895
 896	return 0;
 897
 898error:
 899	/*
 900	 * Link validation on graph failed. We revert what we did and
 901	 * return the error.
 902	 */
 903
 904	list_for_each_entry(err_ppad, &pipe->pads, list) {
 905		if (err_ppad == ppad)
 906			break;
 907
 908		err_ppad->pad->pipe = NULL;
 909	}
 910
 911	media_pipeline_cleanup(pipe);
 912
 913	return ret;
 914}
 915EXPORT_SYMBOL_GPL(__media_pipeline_start);
 916
 917__must_check int media_pipeline_start(struct media_pad *origin,
 918				      struct media_pipeline *pipe)
 919{
 920	struct media_device *mdev = origin->graph_obj.mdev;
 921	int ret;
 922
 923	mutex_lock(&mdev->graph_mutex);
 924	ret = __media_pipeline_start(origin, pipe);
 925	mutex_unlock(&mdev->graph_mutex);
 926	return ret;
 927}
 928EXPORT_SYMBOL_GPL(media_pipeline_start);
 929
 930void __media_pipeline_stop(struct media_pad *pad)
 931{
 932	struct media_pipeline *pipe = pad->pipe;
 933	struct media_pipeline_pad *ppad;
 934
 935	/*
 936	 * If the following check fails, the driver has performed an
 937	 * unbalanced call to media_pipeline_stop()
 938	 */
 939	if (WARN_ON(!pipe))
 940		return;
 941
 942	if (--pipe->start_count)
 943		return;
 944
 945	list_for_each_entry(ppad, &pipe->pads, list)
 946		ppad->pad->pipe = NULL;
 947
 948	media_pipeline_cleanup(pipe);
 949
 950	if (pipe->allocated)
 951		kfree(pipe);
 952}
 953EXPORT_SYMBOL_GPL(__media_pipeline_stop);
 954
 955void media_pipeline_stop(struct media_pad *pad)
 956{
 957	struct media_device *mdev = pad->graph_obj.mdev;
 958
 959	mutex_lock(&mdev->graph_mutex);
 960	__media_pipeline_stop(pad);
 961	mutex_unlock(&mdev->graph_mutex);
 962}
 963EXPORT_SYMBOL_GPL(media_pipeline_stop);
 964
 965__must_check int media_pipeline_alloc_start(struct media_pad *pad)
 966{
 967	struct media_device *mdev = pad->graph_obj.mdev;
 968	struct media_pipeline *new_pipe = NULL;
 969	struct media_pipeline *pipe;
 970	int ret;
 971
 972	mutex_lock(&mdev->graph_mutex);
 973
 974	/*
 975	 * Is the pad already part of a pipeline? If not, we need to allocate
 976	 * a pipe.
 977	 */
 978	pipe = media_pad_pipeline(pad);
 979	if (!pipe) {
 980		new_pipe = kzalloc(sizeof(*new_pipe), GFP_KERNEL);
 981		if (!new_pipe) {
 982			ret = -ENOMEM;
 983			goto out;
 984		}
 985
 986		pipe = new_pipe;
 987		pipe->allocated = true;
 988	}
 989
 990	ret = __media_pipeline_start(pad, pipe);
 991	if (ret)
 992		kfree(new_pipe);
 993
 994out:
 995	mutex_unlock(&mdev->graph_mutex);
 996
 997	return ret;
 998}
 999EXPORT_SYMBOL_GPL(media_pipeline_alloc_start);
1000
1001struct media_pad *
1002__media_pipeline_pad_iter_next(struct media_pipeline *pipe,
1003			       struct media_pipeline_pad_iter *iter,
1004			       struct media_pad *pad)
1005{
1006	if (!pad)
1007		iter->cursor = pipe->pads.next;
1008
1009	if (iter->cursor == &pipe->pads)
1010		return NULL;
1011
1012	pad = list_entry(iter->cursor, struct media_pipeline_pad, list)->pad;
1013	iter->cursor = iter->cursor->next;
1014
1015	return pad;
1016}
1017EXPORT_SYMBOL_GPL(__media_pipeline_pad_iter_next);
1018
1019int media_pipeline_entity_iter_init(struct media_pipeline *pipe,
1020				    struct media_pipeline_entity_iter *iter)
1021{
1022	return media_entity_enum_init(&iter->ent_enum, pipe->mdev);
1023}
1024EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_init);
1025
1026void media_pipeline_entity_iter_cleanup(struct media_pipeline_entity_iter *iter)
1027{
1028	media_entity_enum_cleanup(&iter->ent_enum);
1029}
1030EXPORT_SYMBOL_GPL(media_pipeline_entity_iter_cleanup);
1031
1032struct media_entity *
1033__media_pipeline_entity_iter_next(struct media_pipeline *pipe,
1034				  struct media_pipeline_entity_iter *iter,
1035				  struct media_entity *entity)
1036{
1037	if (!entity)
1038		iter->cursor = pipe->pads.next;
1039
1040	while (iter->cursor != &pipe->pads) {
1041		struct media_pipeline_pad *ppad;
1042		struct media_entity *entity;
1043
1044		ppad = list_entry(iter->cursor, struct media_pipeline_pad, list);
1045		entity = ppad->pad->entity;
1046		iter->cursor = iter->cursor->next;
1047
1048		if (!media_entity_enum_test_and_set(&iter->ent_enum, entity))
1049			return entity;
1050	}
1051
1052	return NULL;
1053}
1054EXPORT_SYMBOL_GPL(__media_pipeline_entity_iter_next);
1055
1056/* -----------------------------------------------------------------------------
1057 * Links management
1058 */
1059
1060static struct media_link *media_add_link(struct list_head *head)
1061{
1062	struct media_link *link;
1063
1064	link = kzalloc(sizeof(*link), GFP_KERNEL);
1065	if (link == NULL)
1066		return NULL;
1067
1068	list_add_tail(&link->list, head);
1069
1070	return link;
1071}
1072
1073static void __media_entity_remove_link(struct media_entity *entity,
1074				       struct media_link *link)
1075{
1076	struct media_link *rlink, *tmp;
1077	struct media_entity *remote;
1078
1079	/* Remove the reverse links for a data link. */
1080	if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == MEDIA_LNK_FL_DATA_LINK) {
1081		link->source->num_links--;
1082		link->sink->num_links--;
1083
1084		if (link->source->entity == entity)
1085			remote = link->sink->entity;
1086		else
1087			remote = link->source->entity;
1088
1089		list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
1090			if (rlink != link->reverse)
1091				continue;
1092
1093			if (link->source->entity == entity)
1094				remote->num_backlinks--;
1095
1096			/* Remove the remote link */
1097			list_del(&rlink->list);
1098			media_gobj_destroy(&rlink->graph_obj);
1099			kfree(rlink);
1100
1101			if (--remote->num_links == 0)
1102				break;
1103		}
1104	}
1105
1106	list_del(&link->list);
1107	media_gobj_destroy(&link->graph_obj);
1108	kfree(link);
1109}
1110
1111int media_get_pad_index(struct media_entity *entity, u32 pad_type,
1112			enum media_pad_signal_type sig_type)
1113{
1114	unsigned int i;
1115
1116	if (!entity)
1117		return -EINVAL;
1118
1119	for (i = 0; i < entity->num_pads; i++) {
1120		if ((entity->pads[i].flags &
1121		     (MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_SOURCE)) != pad_type)
1122			continue;
1123
1124		if (entity->pads[i].sig_type == sig_type)
1125			return i;
1126	}
1127	return -EINVAL;
1128}
1129EXPORT_SYMBOL_GPL(media_get_pad_index);
1130
1131int
1132media_create_pad_link(struct media_entity *source, u16 source_pad,
1133			 struct media_entity *sink, u16 sink_pad, u32 flags)
1134{
1135	struct media_link *link;
1136	struct media_link *backlink;
1137
1138	if (flags & MEDIA_LNK_FL_LINK_TYPE)
1139		return -EINVAL;
1140
1141	flags |= MEDIA_LNK_FL_DATA_LINK;
1142
1143	if (WARN_ON(!source || !sink) ||
1144	    WARN_ON(source_pad >= source->num_pads) ||
1145	    WARN_ON(sink_pad >= sink->num_pads))
1146		return -EINVAL;
1147	if (WARN_ON(!(source->pads[source_pad].flags & MEDIA_PAD_FL_SOURCE)))
1148		return -EINVAL;
1149	if (WARN_ON(!(sink->pads[sink_pad].flags & MEDIA_PAD_FL_SINK)))
1150		return -EINVAL;
1151
1152	link = media_add_link(&source->links);
1153	if (link == NULL)
1154		return -ENOMEM;
1155
1156	link->source = &source->pads[source_pad];
1157	link->sink = &sink->pads[sink_pad];
1158	link->flags = flags;
1159
1160	/* Initialize graph object embedded at the new link */
1161	media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
1162			&link->graph_obj);
1163
1164	/* Create the backlink. Backlinks are used to help graph traversal and
1165	 * are not reported to userspace.
1166	 */
1167	backlink = media_add_link(&sink->links);
1168	if (backlink == NULL) {
1169		__media_entity_remove_link(source, link);
1170		return -ENOMEM;
1171	}
1172
1173	backlink->source = &source->pads[source_pad];
1174	backlink->sink = &sink->pads[sink_pad];
1175	backlink->flags = flags;
1176	backlink->is_backlink = true;
1177
1178	/* Initialize graph object embedded at the new link */
1179	media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
1180			&backlink->graph_obj);
1181
1182	link->reverse = backlink;
1183	backlink->reverse = link;
1184
1185	sink->num_backlinks++;
1186	sink->num_links++;
1187	source->num_links++;
1188
1189	link->source->num_links++;
1190	link->sink->num_links++;
1191
1192	return 0;
1193}
1194EXPORT_SYMBOL_GPL(media_create_pad_link);
1195
1196int media_create_pad_links(const struct media_device *mdev,
1197			   const u32 source_function,
1198			   struct media_entity *source,
1199			   const u16 source_pad,
1200			   const u32 sink_function,
1201			   struct media_entity *sink,
1202			   const u16 sink_pad,
1203			   u32 flags,
1204			   const bool allow_both_undefined)
1205{
1206	struct media_entity *entity;
1207	unsigned function;
1208	int ret;
1209
1210	/* Trivial case: 1:1 relation */
1211	if (source && sink)
1212		return media_create_pad_link(source, source_pad,
1213					     sink, sink_pad, flags);
1214
1215	/* Worse case scenario: n:n relation */
1216	if (!source && !sink) {
1217		if (!allow_both_undefined)
1218			return 0;
1219		media_device_for_each_entity(source, mdev) {
1220			if (source->function != source_function)
1221				continue;
1222			media_device_for_each_entity(sink, mdev) {
1223				if (sink->function != sink_function)
1224					continue;
1225				ret = media_create_pad_link(source, source_pad,
1226							    sink, sink_pad,
1227							    flags);
1228				if (ret)
1229					return ret;
1230				flags &= ~(MEDIA_LNK_FL_ENABLED |
1231					   MEDIA_LNK_FL_IMMUTABLE);
1232			}
1233		}
1234		return 0;
1235	}
1236
1237	/* Handle 1:n and n:1 cases */
1238	if (source)
1239		function = sink_function;
1240	else
1241		function = source_function;
1242
1243	media_device_for_each_entity(entity, mdev) {
1244		if (entity->function != function)
1245			continue;
1246
1247		if (source)
1248			ret = media_create_pad_link(source, source_pad,
1249						    entity, sink_pad, flags);
1250		else
1251			ret = media_create_pad_link(entity, source_pad,
1252						    sink, sink_pad, flags);
1253		if (ret)
1254			return ret;
1255		flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
1256	}
1257	return 0;
1258}
1259EXPORT_SYMBOL_GPL(media_create_pad_links);
1260
1261void __media_entity_remove_links(struct media_entity *entity)
1262{
1263	struct media_link *link, *tmp;
1264
1265	list_for_each_entry_safe(link, tmp, &entity->links, list)
1266		__media_entity_remove_link(entity, link);
1267
1268	entity->num_links = 0;
1269	entity->num_backlinks = 0;
1270}
1271EXPORT_SYMBOL_GPL(__media_entity_remove_links);
1272
1273void media_entity_remove_links(struct media_entity *entity)
1274{
1275	struct media_device *mdev = entity->graph_obj.mdev;
1276
1277	/* Do nothing if the entity is not registered. */
1278	if (mdev == NULL)
1279		return;
1280
1281	mutex_lock(&mdev->graph_mutex);
1282	__media_entity_remove_links(entity);
1283	mutex_unlock(&mdev->graph_mutex);
1284}
1285EXPORT_SYMBOL_GPL(media_entity_remove_links);
1286
1287static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
1288{
1289	int ret;
1290
1291	/* Notify both entities. */
1292	ret = media_entity_call(link->source->entity, link_setup,
1293				link->source, link->sink, flags);
1294	if (ret < 0 && ret != -ENOIOCTLCMD)
1295		return ret;
1296
1297	ret = media_entity_call(link->sink->entity, link_setup,
1298				link->sink, link->source, flags);
1299	if (ret < 0 && ret != -ENOIOCTLCMD) {
1300		media_entity_call(link->source->entity, link_setup,
1301				  link->source, link->sink, link->flags);
1302		return ret;
1303	}
1304
1305	link->flags = flags;
1306	link->reverse->flags = link->flags;
1307
1308	return 0;
1309}
1310
1311int __media_entity_setup_link(struct media_link *link, u32 flags)
1312{
1313	const u32 mask = MEDIA_LNK_FL_ENABLED;
1314	struct media_device *mdev;
1315	struct media_pad *source, *sink;
1316	int ret = -EBUSY;
1317
1318	if (link == NULL)
1319		return -EINVAL;
1320
1321	/* The non-modifiable link flags must not be modified. */
1322	if ((link->flags & ~mask) != (flags & ~mask))
1323		return -EINVAL;
1324
1325	if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
1326		return link->flags == flags ? 0 : -EINVAL;
1327
1328	if (link->flags == flags)
1329		return 0;
1330
1331	source = link->source;
1332	sink = link->sink;
1333
1334	if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
1335	    (media_pad_is_streaming(source) || media_pad_is_streaming(sink)))
1336		return -EBUSY;
1337
1338	mdev = source->graph_obj.mdev;
1339
1340	if (mdev->ops && mdev->ops->link_notify) {
1341		ret = mdev->ops->link_notify(link, flags,
1342					     MEDIA_DEV_NOTIFY_PRE_LINK_CH);
1343		if (ret < 0)
1344			return ret;
1345	}
1346
1347	ret = __media_entity_setup_link_notify(link, flags);
1348
1349	if (mdev->ops && mdev->ops->link_notify)
1350		mdev->ops->link_notify(link, flags,
1351				       MEDIA_DEV_NOTIFY_POST_LINK_CH);
1352
1353	return ret;
1354}
1355EXPORT_SYMBOL_GPL(__media_entity_setup_link);
1356
1357int media_entity_setup_link(struct media_link *link, u32 flags)
1358{
1359	int ret;
1360
1361	mutex_lock(&link->graph_obj.mdev->graph_mutex);
1362	ret = __media_entity_setup_link(link, flags);
1363	mutex_unlock(&link->graph_obj.mdev->graph_mutex);
1364
1365	return ret;
1366}
1367EXPORT_SYMBOL_GPL(media_entity_setup_link);
1368
1369struct media_link *
1370media_entity_find_link(struct media_pad *source, struct media_pad *sink)
1371{
1372	struct media_link *link;
1373
1374	for_each_media_entity_data_link(source->entity, link) {
1375		if (link->source->entity == source->entity &&
1376		    link->source->index == source->index &&
1377		    link->sink->entity == sink->entity &&
1378		    link->sink->index == sink->index)
1379			return link;
1380	}
1381
1382	return NULL;
1383}
1384EXPORT_SYMBOL_GPL(media_entity_find_link);
1385
1386struct media_pad *media_pad_remote_pad_first(const struct media_pad *pad)
1387{
1388	struct media_link *link;
1389
1390	for_each_media_entity_data_link(pad->entity, link) {
1391		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
1392			continue;
1393
1394		if (link->source == pad)
1395			return link->sink;
1396
1397		if (link->sink == pad)
1398			return link->source;
1399	}
1400
1401	return NULL;
1402
1403}
1404EXPORT_SYMBOL_GPL(media_pad_remote_pad_first);
1405
1406struct media_pad *
1407media_entity_remote_pad_unique(const struct media_entity *entity,
1408			       unsigned int type)
1409{
1410	struct media_pad *pad = NULL;
1411	struct media_link *link;
1412
1413	list_for_each_entry(link, &entity->links, list) {
1414		struct media_pad *local_pad;
1415		struct media_pad *remote_pad;
1416
1417		if (((link->flags & MEDIA_LNK_FL_LINK_TYPE) !=
1418		     MEDIA_LNK_FL_DATA_LINK) ||
1419		    !(link->flags & MEDIA_LNK_FL_ENABLED))
1420			continue;
1421
1422		if (type == MEDIA_PAD_FL_SOURCE) {
1423			local_pad = link->sink;
1424			remote_pad = link->source;
1425		} else {
1426			local_pad = link->source;
1427			remote_pad = link->sink;
1428		}
1429
1430		if (local_pad->entity == entity) {
1431			if (pad)
1432				return ERR_PTR(-ENOTUNIQ);
1433
1434			pad = remote_pad;
1435		}
1436	}
1437
1438	if (!pad)
1439		return ERR_PTR(-ENOLINK);
1440
1441	return pad;
1442}
1443EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
1444
1445struct media_pad *media_pad_remote_pad_unique(const struct media_pad *pad)
1446{
1447	struct media_pad *found_pad = NULL;
1448	struct media_link *link;
1449
1450	list_for_each_entry(link, &pad->entity->links, list) {
1451		struct media_pad *remote_pad;
1452
1453		if (!(link->flags & MEDIA_LNK_FL_ENABLED))
1454			continue;
1455
1456		if (link->sink == pad)
1457			remote_pad = link->source;
1458		else if (link->source == pad)
1459			remote_pad = link->sink;
1460		else
1461			continue;
1462
1463		if (found_pad)
1464			return ERR_PTR(-ENOTUNIQ);
1465
1466		found_pad = remote_pad;
1467	}
1468
1469	if (!found_pad)
1470		return ERR_PTR(-ENOLINK);
1471
1472	return found_pad;
1473}
1474EXPORT_SYMBOL_GPL(media_pad_remote_pad_unique);
1475
1476int media_entity_get_fwnode_pad(struct media_entity *entity,
1477				const struct fwnode_handle *fwnode,
1478				unsigned long direction_flags)
1479{
1480	struct fwnode_endpoint endpoint;
1481	unsigned int i;
1482	int ret;
1483
1484	if (!entity->ops || !entity->ops->get_fwnode_pad) {
1485		for (i = 0; i < entity->num_pads; i++) {
1486			if (entity->pads[i].flags & direction_flags)
1487				return i;
1488		}
1489
1490		return -ENXIO;
1491	}
1492
1493	ret = fwnode_graph_parse_endpoint(fwnode, &endpoint);
1494	if (ret)
1495		return ret;
1496
1497	ret = entity->ops->get_fwnode_pad(entity, &endpoint);
1498	if (ret < 0)
1499		return ret;
1500
1501	if (ret >= entity->num_pads)
1502		return -ENXIO;
1503
1504	if (!(entity->pads[ret].flags & direction_flags))
1505		return -ENXIO;
1506
1507	return ret;
1508}
1509EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
1510
1511struct media_pipeline *media_entity_pipeline(struct media_entity *entity)
1512{
1513	struct media_pad *pad;
1514
1515	media_entity_for_each_pad(entity, pad) {
1516		if (pad->pipe)
1517			return pad->pipe;
1518	}
1519
1520	return NULL;
1521}
1522EXPORT_SYMBOL_GPL(media_entity_pipeline);
1523
1524struct media_pipeline *media_pad_pipeline(struct media_pad *pad)
1525{
1526	return pad->pipe;
1527}
1528EXPORT_SYMBOL_GPL(media_pad_pipeline);
1529
1530static void media_interface_init(struct media_device *mdev,
1531				 struct media_interface *intf,
1532				 u32 gobj_type,
1533				 u32 intf_type, u32 flags)
1534{
1535	intf->type = intf_type;
1536	intf->flags = flags;
1537	INIT_LIST_HEAD(&intf->links);
1538
1539	media_gobj_create(mdev, gobj_type, &intf->graph_obj);
1540}
1541
1542/* Functions related to the media interface via device nodes */
1543
1544struct media_intf_devnode *media_devnode_create(struct media_device *mdev,
1545						u32 type, u32 flags,
1546						u32 major, u32 minor)
1547{
1548	struct media_intf_devnode *devnode;
1549
1550	devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
1551	if (!devnode)
1552		return NULL;
1553
1554	devnode->major = major;
1555	devnode->minor = minor;
1556
1557	media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE,
1558			     type, flags);
1559
1560	return devnode;
1561}
1562EXPORT_SYMBOL_GPL(media_devnode_create);
1563
1564void media_devnode_remove(struct media_intf_devnode *devnode)
1565{
1566	media_remove_intf_links(&devnode->intf);
1567	media_gobj_destroy(&devnode->intf.graph_obj);
1568	kfree(devnode);
1569}
1570EXPORT_SYMBOL_GPL(media_devnode_remove);
1571
1572struct media_link *media_create_intf_link(struct media_entity *entity,
1573					    struct media_interface *intf,
1574					    u32 flags)
1575{
1576	struct media_link *link;
1577
1578	link = media_add_link(&intf->links);
1579	if (link == NULL)
1580		return NULL;
1581
1582	link->intf = intf;
1583	link->entity = entity;
1584	link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK;
1585
1586	/* Initialize graph object embedded at the new link */
1587	media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK,
1588			&link->graph_obj);
1589
1590	return link;
1591}
1592EXPORT_SYMBOL_GPL(media_create_intf_link);
1593
1594void __media_remove_intf_link(struct media_link *link)
1595{
1596	list_del(&link->list);
1597	media_gobj_destroy(&link->graph_obj);
1598	kfree(link);
1599}
1600EXPORT_SYMBOL_GPL(__media_remove_intf_link);
1601
1602void media_remove_intf_link(struct media_link *link)
1603{
1604	struct media_device *mdev = link->graph_obj.mdev;
1605
1606	/* Do nothing if the intf is not registered. */
1607	if (mdev == NULL)
1608		return;
1609
1610	mutex_lock(&mdev->graph_mutex);
1611	__media_remove_intf_link(link);
1612	mutex_unlock(&mdev->graph_mutex);
1613}
1614EXPORT_SYMBOL_GPL(media_remove_intf_link);
1615
1616void __media_remove_intf_links(struct media_interface *intf)
1617{
1618	struct media_link *link, *tmp;
1619
1620	list_for_each_entry_safe(link, tmp, &intf->links, list)
1621		__media_remove_intf_link(link);
1622
1623}
1624EXPORT_SYMBOL_GPL(__media_remove_intf_links);
1625
1626void media_remove_intf_links(struct media_interface *intf)
1627{
1628	struct media_device *mdev = intf->graph_obj.mdev;
1629
1630	/* Do nothing if the intf is not registered. */
1631	if (mdev == NULL)
1632		return;
1633
1634	mutex_lock(&mdev->graph_mutex);
1635	__media_remove_intf_links(intf);
1636	mutex_unlock(&mdev->graph_mutex);
1637}
1638EXPORT_SYMBOL_GPL(media_remove_intf_links);
1639
1640struct media_link *media_create_ancillary_link(struct media_entity *primary,
1641					       struct media_entity *ancillary)
1642{
1643	struct media_link *link;
1644
1645	link = media_add_link(&primary->links);
1646	if (!link)
1647		return ERR_PTR(-ENOMEM);
1648
1649	link->gobj0 = &primary->graph_obj;
1650	link->gobj1 = &ancillary->graph_obj;
1651	link->flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED |
1652		      MEDIA_LNK_FL_ANCILLARY_LINK;
1653
1654	/* Initialize graph object embedded in the new link */
1655	media_gobj_create(primary->graph_obj.mdev, MEDIA_GRAPH_LINK,
1656			  &link->graph_obj);
1657
1658	return link;
1659}
1660EXPORT_SYMBOL_GPL(media_create_ancillary_link);
1661
1662struct media_link *__media_entity_next_link(struct media_entity *entity,
1663					    struct media_link *link,
1664					    unsigned long link_type)
1665{
1666	link = link ? list_next_entry(link, list)
1667		    : list_first_entry(&entity->links, typeof(*link), list);
1668
1669	list_for_each_entry_from(link, &entity->links, list)
1670		if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == link_type)
1671			return link;
1672
1673	return NULL;
1674}
1675EXPORT_SYMBOL_GPL(__media_entity_next_link);
~/ Read-only file preview.