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