Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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