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