Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Media entity
0004  *
0005  * Copyright (C) 2010 Nokia Corporation
0006  *
0007  * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
0008  *       Sakari Ailus <sakari.ailus@iki.fi>
0009  */
0010 
0011 #include <linux/bitmap.h>
0012 #include <linux/list.h>
0013 #include <linux/property.h>
0014 #include <linux/slab.h>
0015 #include <media/media-entity.h>
0016 #include <media/media-device.h>
0017 
0018 static inline const char *intf_type(struct media_interface *intf)
0019 {
0020     switch (intf->type) {
0021     case MEDIA_INTF_T_DVB_FE:
0022         return "dvb-frontend";
0023     case MEDIA_INTF_T_DVB_DEMUX:
0024         return "dvb-demux";
0025     case MEDIA_INTF_T_DVB_DVR:
0026         return "dvb-dvr";
0027     case MEDIA_INTF_T_DVB_CA:
0028         return  "dvb-ca";
0029     case MEDIA_INTF_T_DVB_NET:
0030         return "dvb-net";
0031     case MEDIA_INTF_T_V4L_VIDEO:
0032         return "v4l-video";
0033     case MEDIA_INTF_T_V4L_VBI:
0034         return "v4l-vbi";
0035     case MEDIA_INTF_T_V4L_RADIO:
0036         return "v4l-radio";
0037     case MEDIA_INTF_T_V4L_SUBDEV:
0038         return "v4l-subdev";
0039     case MEDIA_INTF_T_V4L_SWRADIO:
0040         return "v4l-swradio";
0041     case MEDIA_INTF_T_V4L_TOUCH:
0042         return "v4l-touch";
0043     default:
0044         return "unknown-intf";
0045     }
0046 };
0047 
0048 static inline const char *link_type_name(struct media_link *link)
0049 {
0050     switch (link->flags & MEDIA_LNK_FL_LINK_TYPE) {
0051     case MEDIA_LNK_FL_DATA_LINK:
0052         return "data";
0053     case MEDIA_LNK_FL_INTERFACE_LINK:
0054         return "interface";
0055     case MEDIA_LNK_FL_ANCILLARY_LINK:
0056         return "ancillary";
0057     default:
0058         return "unknown";
0059     }
0060 }
0061 
0062 __must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
0063                       int idx_max)
0064 {
0065     idx_max = ALIGN(idx_max, BITS_PER_LONG);
0066     ent_enum->bmap = bitmap_zalloc(idx_max, GFP_KERNEL);
0067     if (!ent_enum->bmap)
0068         return -ENOMEM;
0069 
0070     ent_enum->idx_max = idx_max;
0071 
0072     return 0;
0073 }
0074 EXPORT_SYMBOL_GPL(__media_entity_enum_init);
0075 
0076 void media_entity_enum_cleanup(struct media_entity_enum *ent_enum)
0077 {
0078     bitmap_free(ent_enum->bmap);
0079 }
0080 EXPORT_SYMBOL_GPL(media_entity_enum_cleanup);
0081 
0082 /**
0083  *  dev_dbg_obj - Prints in debug mode a change on some object
0084  *
0085  * @event_name: Name of the event to report. Could be __func__
0086  * @gobj:   Pointer to the object
0087  *
0088  * Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it
0089  * won't produce any code.
0090  */
0091 static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
0092 {
0093 #if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG)
0094     switch (media_type(gobj)) {
0095     case MEDIA_GRAPH_ENTITY:
0096         dev_dbg(gobj->mdev->dev,
0097             "%s id %u: entity '%s'\n",
0098             event_name, media_id(gobj),
0099             gobj_to_entity(gobj)->name);
0100         break;
0101     case MEDIA_GRAPH_LINK:
0102     {
0103         struct media_link *link = gobj_to_link(gobj);
0104 
0105         dev_dbg(gobj->mdev->dev,
0106             "%s id %u: %s link id %u ==> id %u\n",
0107             event_name, media_id(gobj), link_type_name(link),
0108             media_id(link->gobj0),
0109             media_id(link->gobj1));
0110         break;
0111     }
0112     case MEDIA_GRAPH_PAD:
0113     {
0114         struct media_pad *pad = gobj_to_pad(gobj);
0115 
0116         dev_dbg(gobj->mdev->dev,
0117             "%s id %u: %s%spad '%s':%d\n",
0118             event_name, media_id(gobj),
0119             pad->flags & MEDIA_PAD_FL_SINK   ? "sink " : "",
0120             pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "",
0121             pad->entity->name, pad->index);
0122         break;
0123     }
0124     case MEDIA_GRAPH_INTF_DEVNODE:
0125     {
0126         struct media_interface *intf = gobj_to_intf(gobj);
0127         struct media_intf_devnode *devnode = intf_to_devnode(intf);
0128 
0129         dev_dbg(gobj->mdev->dev,
0130             "%s id %u: intf_devnode %s - major: %d, minor: %d\n",
0131             event_name, media_id(gobj),
0132             intf_type(intf),
0133             devnode->major, devnode->minor);
0134         break;
0135     }
0136     }
0137 #endif
0138 }
0139 
0140 void media_gobj_create(struct media_device *mdev,
0141                enum media_gobj_type type,
0142                struct media_gobj *gobj)
0143 {
0144     BUG_ON(!mdev);
0145 
0146     gobj->mdev = mdev;
0147 
0148     /* Create a per-type unique object ID */
0149     gobj->id = media_gobj_gen_id(type, ++mdev->id);
0150 
0151     switch (type) {
0152     case MEDIA_GRAPH_ENTITY:
0153         list_add_tail(&gobj->list, &mdev->entities);
0154         break;
0155     case MEDIA_GRAPH_PAD:
0156         list_add_tail(&gobj->list, &mdev->pads);
0157         break;
0158     case MEDIA_GRAPH_LINK:
0159         list_add_tail(&gobj->list, &mdev->links);
0160         break;
0161     case MEDIA_GRAPH_INTF_DEVNODE:
0162         list_add_tail(&gobj->list, &mdev->interfaces);
0163         break;
0164     }
0165 
0166     mdev->topology_version++;
0167 
0168     dev_dbg_obj(__func__, gobj);
0169 }
0170 
0171 void media_gobj_destroy(struct media_gobj *gobj)
0172 {
0173     /* Do nothing if the object is not linked. */
0174     if (gobj->mdev == NULL)
0175         return;
0176 
0177     dev_dbg_obj(__func__, gobj);
0178 
0179     gobj->mdev->topology_version++;
0180 
0181     /* Remove the object from mdev list */
0182     list_del(&gobj->list);
0183 
0184     gobj->mdev = NULL;
0185 }
0186 
0187 /*
0188  * TODO: Get rid of this.
0189  */
0190 #define MEDIA_ENTITY_MAX_PADS       512
0191 
0192 int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
0193                struct media_pad *pads)
0194 {
0195     struct media_device *mdev = entity->graph_obj.mdev;
0196     unsigned int i;
0197 
0198     if (num_pads >= MEDIA_ENTITY_MAX_PADS)
0199         return -E2BIG;
0200 
0201     entity->num_pads = num_pads;
0202     entity->pads = pads;
0203 
0204     if (mdev)
0205         mutex_lock(&mdev->graph_mutex);
0206 
0207     for (i = 0; i < num_pads; i++) {
0208         pads[i].entity = entity;
0209         pads[i].index = i;
0210         if (mdev)
0211             media_gobj_create(mdev, MEDIA_GRAPH_PAD,
0212                     &entity->pads[i].graph_obj);
0213     }
0214 
0215     if (mdev)
0216         mutex_unlock(&mdev->graph_mutex);
0217 
0218     return 0;
0219 }
0220 EXPORT_SYMBOL_GPL(media_entity_pads_init);
0221 
0222 /* -----------------------------------------------------------------------------
0223  * Graph traversal
0224  */
0225 
0226 static struct media_entity *
0227 media_entity_other(struct media_entity *entity, struct media_link *link)
0228 {
0229     if (link->source->entity == entity)
0230         return link->sink->entity;
0231     else
0232         return link->source->entity;
0233 }
0234 
0235 /* push an entity to traversal stack */
0236 static void stack_push(struct media_graph *graph,
0237                struct media_entity *entity)
0238 {
0239     if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
0240         WARN_ON(1);
0241         return;
0242     }
0243     graph->top++;
0244     graph->stack[graph->top].link = entity->links.next;
0245     graph->stack[graph->top].entity = entity;
0246 }
0247 
0248 static struct media_entity *stack_pop(struct media_graph *graph)
0249 {
0250     struct media_entity *entity;
0251 
0252     entity = graph->stack[graph->top].entity;
0253     graph->top--;
0254 
0255     return entity;
0256 }
0257 
0258 #define link_top(en)    ((en)->stack[(en)->top].link)
0259 #define stack_top(en)   ((en)->stack[(en)->top].entity)
0260 
0261 /**
0262  * media_graph_walk_init - Allocate resources for graph walk
0263  * @graph: Media graph structure that will be used to walk the graph
0264  * @mdev: Media device
0265  *
0266  * Reserve resources for graph walk in media device's current
0267  * state. The memory must be released using
0268  * media_graph_walk_free().
0269  *
0270  * Returns error on failure, zero on success.
0271  */
0272 __must_check int media_graph_walk_init(
0273     struct media_graph *graph, struct media_device *mdev)
0274 {
0275     return media_entity_enum_init(&graph->ent_enum, mdev);
0276 }
0277 EXPORT_SYMBOL_GPL(media_graph_walk_init);
0278 
0279 /**
0280  * media_graph_walk_cleanup - Release resources related to graph walking
0281  * @graph: Media graph structure that was used to walk the graph
0282  */
0283 void media_graph_walk_cleanup(struct media_graph *graph)
0284 {
0285     media_entity_enum_cleanup(&graph->ent_enum);
0286 }
0287 EXPORT_SYMBOL_GPL(media_graph_walk_cleanup);
0288 
0289 void media_graph_walk_start(struct media_graph *graph,
0290                 struct media_entity *entity)
0291 {
0292     media_entity_enum_zero(&graph->ent_enum);
0293     media_entity_enum_set(&graph->ent_enum, entity);
0294 
0295     graph->top = 0;
0296     graph->stack[graph->top].entity = NULL;
0297     stack_push(graph, entity);
0298     dev_dbg(entity->graph_obj.mdev->dev,
0299         "begin graph walk at '%s'\n", entity->name);
0300 }
0301 EXPORT_SYMBOL_GPL(media_graph_walk_start);
0302 
0303 static void media_graph_walk_iter(struct media_graph *graph)
0304 {
0305     struct media_entity *entity = stack_top(graph);
0306     struct media_link *link;
0307     struct media_entity *next;
0308 
0309     link = list_entry(link_top(graph), typeof(*link), list);
0310 
0311     /* If the link is not a data link, don't follow it */
0312     if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) != MEDIA_LNK_FL_DATA_LINK) {
0313         link_top(graph) = link_top(graph)->next;
0314         return;
0315     }
0316 
0317     /* The link is not enabled so we do not follow. */
0318     if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
0319         link_top(graph) = link_top(graph)->next;
0320         dev_dbg(entity->graph_obj.mdev->dev,
0321             "walk: skipping disabled link '%s':%u -> '%s':%u\n",
0322             link->source->entity->name, link->source->index,
0323             link->sink->entity->name, link->sink->index);
0324         return;
0325     }
0326 
0327     /* Get the entity at the other end of the link. */
0328     next = media_entity_other(entity, link);
0329 
0330     /* Has the entity already been visited? */
0331     if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
0332         link_top(graph) = link_top(graph)->next;
0333         dev_dbg(entity->graph_obj.mdev->dev,
0334             "walk: skipping entity '%s' (already seen)\n",
0335             next->name);
0336         return;
0337     }
0338 
0339     /* Push the new entity to stack and start over. */
0340     link_top(graph) = link_top(graph)->next;
0341     stack_push(graph, next);
0342     dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
0343         next->name);
0344     lockdep_assert_held(&entity->graph_obj.mdev->graph_mutex);
0345 }
0346 
0347 struct media_entity *media_graph_walk_next(struct media_graph *graph)
0348 {
0349     struct media_entity *entity;
0350 
0351     if (stack_top(graph) == NULL)
0352         return NULL;
0353 
0354     /*
0355      * Depth first search. Push entity to stack and continue from
0356      * top of the stack until no more entities on the level can be
0357      * found.
0358      */
0359     while (link_top(graph) != &stack_top(graph)->links)
0360         media_graph_walk_iter(graph);
0361 
0362     entity = stack_pop(graph);
0363     dev_dbg(entity->graph_obj.mdev->dev,
0364         "walk: returning entity '%s'\n", entity->name);
0365 
0366     return entity;
0367 }
0368 EXPORT_SYMBOL_GPL(media_graph_walk_next);
0369 
0370 int media_entity_get_fwnode_pad(struct media_entity *entity,
0371                 struct fwnode_handle *fwnode,
0372                 unsigned long direction_flags)
0373 {
0374     struct fwnode_endpoint endpoint;
0375     unsigned int i;
0376     int ret;
0377 
0378     if (!entity->ops || !entity->ops->get_fwnode_pad) {
0379         for (i = 0; i < entity->num_pads; i++) {
0380             if (entity->pads[i].flags & direction_flags)
0381                 return i;
0382         }
0383 
0384         return -ENXIO;
0385     }
0386 
0387     ret = fwnode_graph_parse_endpoint(fwnode, &endpoint);
0388     if (ret)
0389         return ret;
0390 
0391     ret = entity->ops->get_fwnode_pad(entity, &endpoint);
0392     if (ret < 0)
0393         return ret;
0394 
0395     if (ret >= entity->num_pads)
0396         return -ENXIO;
0397 
0398     if (!(entity->pads[ret].flags & direction_flags))
0399         return -ENXIO;
0400 
0401     return ret;
0402 }
0403 EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
0404 
0405 /* -----------------------------------------------------------------------------
0406  * Pipeline management
0407  */
0408 
0409 __must_check int __media_pipeline_start(struct media_entity *entity,
0410                     struct media_pipeline *pipe)
0411 {
0412     struct media_device *mdev = entity->graph_obj.mdev;
0413     struct media_graph *graph = &pipe->graph;
0414     struct media_entity *entity_err = entity;
0415     struct media_link *link;
0416     int ret;
0417 
0418     if (pipe->streaming_count) {
0419         pipe->streaming_count++;
0420         return 0;
0421     }
0422 
0423     ret = media_graph_walk_init(&pipe->graph, mdev);
0424     if (ret)
0425         return ret;
0426 
0427     media_graph_walk_start(&pipe->graph, entity);
0428 
0429     while ((entity = media_graph_walk_next(graph))) {
0430         DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
0431         DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
0432 
0433         if (entity->pipe && entity->pipe != pipe) {
0434             pr_err("Pipe active for %s. Can't start for %s\n",
0435                 entity->name,
0436                 entity_err->name);
0437             ret = -EBUSY;
0438             goto error;
0439         }
0440 
0441         /* Already streaming --- no need to check. */
0442         if (entity->pipe)
0443             continue;
0444 
0445         entity->pipe = pipe;
0446 
0447         if (!entity->ops || !entity->ops->link_validate)
0448             continue;
0449 
0450         bitmap_zero(active, entity->num_pads);
0451         bitmap_fill(has_no_links, entity->num_pads);
0452 
0453         for_each_media_entity_data_link(entity, link) {
0454             struct media_pad *pad = link->sink->entity == entity
0455                         ? link->sink : link->source;
0456 
0457             /* Mark that a pad is connected by a link. */
0458             bitmap_clear(has_no_links, pad->index, 1);
0459 
0460             /*
0461              * Pads that either do not need to connect or
0462              * are connected through an enabled link are
0463              * fine.
0464              */
0465             if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) ||
0466                 link->flags & MEDIA_LNK_FL_ENABLED)
0467                 bitmap_set(active, pad->index, 1);
0468 
0469             /*
0470              * Link validation will only take place for
0471              * sink ends of the link that are enabled.
0472              */
0473             if (link->sink != pad ||
0474                 !(link->flags & MEDIA_LNK_FL_ENABLED))
0475                 continue;
0476 
0477             ret = entity->ops->link_validate(link);
0478             if (ret < 0 && ret != -ENOIOCTLCMD) {
0479                 dev_dbg(entity->graph_obj.mdev->dev,
0480                     "link validation failed for '%s':%u -> '%s':%u, error %d\n",
0481                     link->source->entity->name,
0482                     link->source->index,
0483                     entity->name, link->sink->index, ret);
0484                 goto error;
0485             }
0486         }
0487 
0488         /* Either no links or validated links are fine. */
0489         bitmap_or(active, active, has_no_links, entity->num_pads);
0490 
0491         if (!bitmap_full(active, entity->num_pads)) {
0492             ret = -ENOLINK;
0493             dev_dbg(entity->graph_obj.mdev->dev,
0494                 "'%s':%u must be connected by an enabled link\n",
0495                 entity->name,
0496                 (unsigned)find_first_zero_bit(
0497                     active, entity->num_pads));
0498             goto error;
0499         }
0500     }
0501 
0502     pipe->streaming_count++;
0503 
0504     return 0;
0505 
0506 error:
0507     /*
0508      * Link validation on graph failed. We revert what we did and
0509      * return the error.
0510      */
0511     media_graph_walk_start(graph, entity_err);
0512 
0513     while ((entity_err = media_graph_walk_next(graph))) {
0514         entity_err->pipe = NULL;
0515 
0516         /*
0517          * We haven't started entities further than this so we quit
0518          * here.
0519          */
0520         if (entity_err == entity)
0521             break;
0522     }
0523 
0524     media_graph_walk_cleanup(graph);
0525 
0526     return ret;
0527 }
0528 EXPORT_SYMBOL_GPL(__media_pipeline_start);
0529 
0530 __must_check int media_pipeline_start(struct media_entity *entity,
0531                       struct media_pipeline *pipe)
0532 {
0533     struct media_device *mdev = entity->graph_obj.mdev;
0534     int ret;
0535 
0536     mutex_lock(&mdev->graph_mutex);
0537     ret = __media_pipeline_start(entity, pipe);
0538     mutex_unlock(&mdev->graph_mutex);
0539     return ret;
0540 }
0541 EXPORT_SYMBOL_GPL(media_pipeline_start);
0542 
0543 void __media_pipeline_stop(struct media_entity *entity)
0544 {
0545     struct media_graph *graph = &entity->pipe->graph;
0546     struct media_pipeline *pipe = entity->pipe;
0547 
0548     /*
0549      * If the following check fails, the driver has performed an
0550      * unbalanced call to media_pipeline_stop()
0551      */
0552     if (WARN_ON(!pipe))
0553         return;
0554 
0555     if (--pipe->streaming_count)
0556         return;
0557 
0558     media_graph_walk_start(graph, entity);
0559 
0560     while ((entity = media_graph_walk_next(graph)))
0561         entity->pipe = NULL;
0562 
0563     media_graph_walk_cleanup(graph);
0564 
0565 }
0566 EXPORT_SYMBOL_GPL(__media_pipeline_stop);
0567 
0568 void media_pipeline_stop(struct media_entity *entity)
0569 {
0570     struct media_device *mdev = entity->graph_obj.mdev;
0571 
0572     mutex_lock(&mdev->graph_mutex);
0573     __media_pipeline_stop(entity);
0574     mutex_unlock(&mdev->graph_mutex);
0575 }
0576 EXPORT_SYMBOL_GPL(media_pipeline_stop);
0577 
0578 /* -----------------------------------------------------------------------------
0579  * Links management
0580  */
0581 
0582 static struct media_link *media_add_link(struct list_head *head)
0583 {
0584     struct media_link *link;
0585 
0586     link = kzalloc(sizeof(*link), GFP_KERNEL);
0587     if (link == NULL)
0588         return NULL;
0589 
0590     list_add_tail(&link->list, head);
0591 
0592     return link;
0593 }
0594 
0595 static void __media_entity_remove_link(struct media_entity *entity,
0596                        struct media_link *link)
0597 {
0598     struct media_link *rlink, *tmp;
0599     struct media_entity *remote;
0600 
0601     /* Remove the reverse links for a data link. */
0602     if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == MEDIA_LNK_FL_DATA_LINK) {
0603         if (link->source->entity == entity)
0604             remote = link->sink->entity;
0605         else
0606             remote = link->source->entity;
0607 
0608         list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
0609             if (rlink != link->reverse)
0610                 continue;
0611 
0612             if (link->source->entity == entity)
0613                 remote->num_backlinks--;
0614 
0615             /* Remove the remote link */
0616             list_del(&rlink->list);
0617             media_gobj_destroy(&rlink->graph_obj);
0618             kfree(rlink);
0619 
0620             if (--remote->num_links == 0)
0621                 break;
0622         }
0623     }
0624 
0625     list_del(&link->list);
0626     media_gobj_destroy(&link->graph_obj);
0627     kfree(link);
0628 }
0629 
0630 int media_get_pad_index(struct media_entity *entity, bool is_sink,
0631             enum media_pad_signal_type sig_type)
0632 {
0633     int i;
0634     bool pad_is_sink;
0635 
0636     if (!entity)
0637         return -EINVAL;
0638 
0639     for (i = 0; i < entity->num_pads; i++) {
0640         if (entity->pads[i].flags & MEDIA_PAD_FL_SINK)
0641             pad_is_sink = true;
0642         else if (entity->pads[i].flags & MEDIA_PAD_FL_SOURCE)
0643             pad_is_sink = false;
0644         else
0645             continue;   /* This is an error! */
0646 
0647         if (pad_is_sink != is_sink)
0648             continue;
0649         if (entity->pads[i].sig_type == sig_type)
0650             return i;
0651     }
0652     return -EINVAL;
0653 }
0654 EXPORT_SYMBOL_GPL(media_get_pad_index);
0655 
0656 int
0657 media_create_pad_link(struct media_entity *source, u16 source_pad,
0658              struct media_entity *sink, u16 sink_pad, u32 flags)
0659 {
0660     struct media_link *link;
0661     struct media_link *backlink;
0662 
0663     if (WARN_ON(!source || !sink) ||
0664         WARN_ON(source_pad >= source->num_pads) ||
0665         WARN_ON(sink_pad >= sink->num_pads))
0666         return -EINVAL;
0667     if (WARN_ON(!(source->pads[source_pad].flags & MEDIA_PAD_FL_SOURCE)))
0668         return -EINVAL;
0669     if (WARN_ON(!(sink->pads[sink_pad].flags & MEDIA_PAD_FL_SINK)))
0670         return -EINVAL;
0671 
0672     link = media_add_link(&source->links);
0673     if (link == NULL)
0674         return -ENOMEM;
0675 
0676     link->source = &source->pads[source_pad];
0677     link->sink = &sink->pads[sink_pad];
0678     link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;
0679 
0680     /* Initialize graph object embedded at the new link */
0681     media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
0682             &link->graph_obj);
0683 
0684     /* Create the backlink. Backlinks are used to help graph traversal and
0685      * are not reported to userspace.
0686      */
0687     backlink = media_add_link(&sink->links);
0688     if (backlink == NULL) {
0689         __media_entity_remove_link(source, link);
0690         return -ENOMEM;
0691     }
0692 
0693     backlink->source = &source->pads[source_pad];
0694     backlink->sink = &sink->pads[sink_pad];
0695     backlink->flags = flags;
0696     backlink->is_backlink = true;
0697 
0698     /* Initialize graph object embedded at the new link */
0699     media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
0700             &backlink->graph_obj);
0701 
0702     link->reverse = backlink;
0703     backlink->reverse = link;
0704 
0705     sink->num_backlinks++;
0706     sink->num_links++;
0707     source->num_links++;
0708 
0709     return 0;
0710 }
0711 EXPORT_SYMBOL_GPL(media_create_pad_link);
0712 
0713 int media_create_pad_links(const struct media_device *mdev,
0714                const u32 source_function,
0715                struct media_entity *source,
0716                const u16 source_pad,
0717                const u32 sink_function,
0718                struct media_entity *sink,
0719                const u16 sink_pad,
0720                u32 flags,
0721                const bool allow_both_undefined)
0722 {
0723     struct media_entity *entity;
0724     unsigned function;
0725     int ret;
0726 
0727     /* Trivial case: 1:1 relation */
0728     if (source && sink)
0729         return media_create_pad_link(source, source_pad,
0730                          sink, sink_pad, flags);
0731 
0732     /* Worse case scenario: n:n relation */
0733     if (!source && !sink) {
0734         if (!allow_both_undefined)
0735             return 0;
0736         media_device_for_each_entity(source, mdev) {
0737             if (source->function != source_function)
0738                 continue;
0739             media_device_for_each_entity(sink, mdev) {
0740                 if (sink->function != sink_function)
0741                     continue;
0742                 ret = media_create_pad_link(source, source_pad,
0743                                 sink, sink_pad,
0744                                 flags);
0745                 if (ret)
0746                     return ret;
0747                 flags &= ~(MEDIA_LNK_FL_ENABLED |
0748                        MEDIA_LNK_FL_IMMUTABLE);
0749             }
0750         }
0751         return 0;
0752     }
0753 
0754     /* Handle 1:n and n:1 cases */
0755     if (source)
0756         function = sink_function;
0757     else
0758         function = source_function;
0759 
0760     media_device_for_each_entity(entity, mdev) {
0761         if (entity->function != function)
0762             continue;
0763 
0764         if (source)
0765             ret = media_create_pad_link(source, source_pad,
0766                             entity, sink_pad, flags);
0767         else
0768             ret = media_create_pad_link(entity, source_pad,
0769                             sink, sink_pad, flags);
0770         if (ret)
0771             return ret;
0772         flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
0773     }
0774     return 0;
0775 }
0776 EXPORT_SYMBOL_GPL(media_create_pad_links);
0777 
0778 void __media_entity_remove_links(struct media_entity *entity)
0779 {
0780     struct media_link *link, *tmp;
0781 
0782     list_for_each_entry_safe(link, tmp, &entity->links, list)
0783         __media_entity_remove_link(entity, link);
0784 
0785     entity->num_links = 0;
0786     entity->num_backlinks = 0;
0787 }
0788 EXPORT_SYMBOL_GPL(__media_entity_remove_links);
0789 
0790 void media_entity_remove_links(struct media_entity *entity)
0791 {
0792     struct media_device *mdev = entity->graph_obj.mdev;
0793 
0794     /* Do nothing if the entity is not registered. */
0795     if (mdev == NULL)
0796         return;
0797 
0798     mutex_lock(&mdev->graph_mutex);
0799     __media_entity_remove_links(entity);
0800     mutex_unlock(&mdev->graph_mutex);
0801 }
0802 EXPORT_SYMBOL_GPL(media_entity_remove_links);
0803 
0804 static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
0805 {
0806     int ret;
0807 
0808     /* Notify both entities. */
0809     ret = media_entity_call(link->source->entity, link_setup,
0810                 link->source, link->sink, flags);
0811     if (ret < 0 && ret != -ENOIOCTLCMD)
0812         return ret;
0813 
0814     ret = media_entity_call(link->sink->entity, link_setup,
0815                 link->sink, link->source, flags);
0816     if (ret < 0 && ret != -ENOIOCTLCMD) {
0817         media_entity_call(link->source->entity, link_setup,
0818                   link->source, link->sink, link->flags);
0819         return ret;
0820     }
0821 
0822     link->flags = flags;
0823     link->reverse->flags = link->flags;
0824 
0825     return 0;
0826 }
0827 
0828 int __media_entity_setup_link(struct media_link *link, u32 flags)
0829 {
0830     const u32 mask = MEDIA_LNK_FL_ENABLED;
0831     struct media_device *mdev;
0832     struct media_entity *source, *sink;
0833     int ret = -EBUSY;
0834 
0835     if (link == NULL)
0836         return -EINVAL;
0837 
0838     /* The non-modifiable link flags must not be modified. */
0839     if ((link->flags & ~mask) != (flags & ~mask))
0840         return -EINVAL;
0841 
0842     if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
0843         return link->flags == flags ? 0 : -EINVAL;
0844 
0845     if (link->flags == flags)
0846         return 0;
0847 
0848     source = link->source->entity;
0849     sink = link->sink->entity;
0850 
0851     if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
0852         (media_entity_is_streaming(source) ||
0853          media_entity_is_streaming(sink)))
0854         return -EBUSY;
0855 
0856     mdev = source->graph_obj.mdev;
0857 
0858     if (mdev->ops && mdev->ops->link_notify) {
0859         ret = mdev->ops->link_notify(link, flags,
0860                          MEDIA_DEV_NOTIFY_PRE_LINK_CH);
0861         if (ret < 0)
0862             return ret;
0863     }
0864 
0865     ret = __media_entity_setup_link_notify(link, flags);
0866 
0867     if (mdev->ops && mdev->ops->link_notify)
0868         mdev->ops->link_notify(link, flags,
0869                        MEDIA_DEV_NOTIFY_POST_LINK_CH);
0870 
0871     return ret;
0872 }
0873 EXPORT_SYMBOL_GPL(__media_entity_setup_link);
0874 
0875 int media_entity_setup_link(struct media_link *link, u32 flags)
0876 {
0877     int ret;
0878 
0879     mutex_lock(&link->graph_obj.mdev->graph_mutex);
0880     ret = __media_entity_setup_link(link, flags);
0881     mutex_unlock(&link->graph_obj.mdev->graph_mutex);
0882 
0883     return ret;
0884 }
0885 EXPORT_SYMBOL_GPL(media_entity_setup_link);
0886 
0887 struct media_link *
0888 media_entity_find_link(struct media_pad *source, struct media_pad *sink)
0889 {
0890     struct media_link *link;
0891 
0892     for_each_media_entity_data_link(source->entity, link) {
0893         if (link->source->entity == source->entity &&
0894             link->source->index == source->index &&
0895             link->sink->entity == sink->entity &&
0896             link->sink->index == sink->index)
0897             return link;
0898     }
0899 
0900     return NULL;
0901 }
0902 EXPORT_SYMBOL_GPL(media_entity_find_link);
0903 
0904 struct media_pad *media_pad_remote_pad_first(const struct media_pad *pad)
0905 {
0906     struct media_link *link;
0907 
0908     for_each_media_entity_data_link(pad->entity, link) {
0909         if (!(link->flags & MEDIA_LNK_FL_ENABLED))
0910             continue;
0911 
0912         if (link->source == pad)
0913             return link->sink;
0914 
0915         if (link->sink == pad)
0916             return link->source;
0917     }
0918 
0919     return NULL;
0920 
0921 }
0922 EXPORT_SYMBOL_GPL(media_pad_remote_pad_first);
0923 
0924 struct media_pad *
0925 media_entity_remote_pad_unique(const struct media_entity *entity,
0926                    unsigned int type)
0927 {
0928     struct media_pad *pad = NULL;
0929     struct media_link *link;
0930 
0931     list_for_each_entry(link, &entity->links, list) {
0932         struct media_pad *local_pad;
0933         struct media_pad *remote_pad;
0934 
0935         if (((link->flags & MEDIA_LNK_FL_LINK_TYPE) !=
0936              MEDIA_LNK_FL_DATA_LINK) ||
0937             !(link->flags & MEDIA_LNK_FL_ENABLED))
0938             continue;
0939 
0940         if (type == MEDIA_PAD_FL_SOURCE) {
0941             local_pad = link->sink;
0942             remote_pad = link->source;
0943         } else {
0944             local_pad = link->source;
0945             remote_pad = link->sink;
0946         }
0947 
0948         if (local_pad->entity == entity) {
0949             if (pad)
0950                 return ERR_PTR(-ENOTUNIQ);
0951 
0952             pad = remote_pad;
0953         }
0954     }
0955 
0956     if (!pad)
0957         return ERR_PTR(-ENOLINK);
0958 
0959     return pad;
0960 }
0961 EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
0962 
0963 struct media_pad *media_pad_remote_pad_unique(const struct media_pad *pad)
0964 {
0965     struct media_pad *found_pad = NULL;
0966     struct media_link *link;
0967 
0968     list_for_each_entry(link, &pad->entity->links, list) {
0969         struct media_pad *remote_pad;
0970 
0971         if (!(link->flags & MEDIA_LNK_FL_ENABLED))
0972             continue;
0973 
0974         if (link->sink == pad)
0975             remote_pad = link->source;
0976         else if (link->source == pad)
0977             remote_pad = link->sink;
0978         else
0979             continue;
0980 
0981         if (found_pad)
0982             return ERR_PTR(-ENOTUNIQ);
0983 
0984         found_pad = remote_pad;
0985     }
0986 
0987     if (!found_pad)
0988         return ERR_PTR(-ENOLINK);
0989 
0990     return found_pad;
0991 }
0992 EXPORT_SYMBOL_GPL(media_pad_remote_pad_unique);
0993 
0994 static void media_interface_init(struct media_device *mdev,
0995                  struct media_interface *intf,
0996                  u32 gobj_type,
0997                  u32 intf_type, u32 flags)
0998 {
0999     intf->type = intf_type;
1000     intf->flags = flags;
1001     INIT_LIST_HEAD(&intf->links);
1002 
1003     media_gobj_create(mdev, gobj_type, &intf->graph_obj);
1004 }
1005 
1006 /* Functions related to the media interface via device nodes */
1007 
1008 struct media_intf_devnode *media_devnode_create(struct media_device *mdev,
1009                         u32 type, u32 flags,
1010                         u32 major, u32 minor)
1011 {
1012     struct media_intf_devnode *devnode;
1013 
1014     devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
1015     if (!devnode)
1016         return NULL;
1017 
1018     devnode->major = major;
1019     devnode->minor = minor;
1020 
1021     media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE,
1022                  type, flags);
1023 
1024     return devnode;
1025 }
1026 EXPORT_SYMBOL_GPL(media_devnode_create);
1027 
1028 void media_devnode_remove(struct media_intf_devnode *devnode)
1029 {
1030     media_remove_intf_links(&devnode->intf);
1031     media_gobj_destroy(&devnode->intf.graph_obj);
1032     kfree(devnode);
1033 }
1034 EXPORT_SYMBOL_GPL(media_devnode_remove);
1035 
1036 struct media_link *media_create_intf_link(struct media_entity *entity,
1037                         struct media_interface *intf,
1038                         u32 flags)
1039 {
1040     struct media_link *link;
1041 
1042     link = media_add_link(&intf->links);
1043     if (link == NULL)
1044         return NULL;
1045 
1046     link->intf = intf;
1047     link->entity = entity;
1048     link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK;
1049 
1050     /* Initialize graph object embedded at the new link */
1051     media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK,
1052             &link->graph_obj);
1053 
1054     return link;
1055 }
1056 EXPORT_SYMBOL_GPL(media_create_intf_link);
1057 
1058 void __media_remove_intf_link(struct media_link *link)
1059 {
1060     list_del(&link->list);
1061     media_gobj_destroy(&link->graph_obj);
1062     kfree(link);
1063 }
1064 EXPORT_SYMBOL_GPL(__media_remove_intf_link);
1065 
1066 void media_remove_intf_link(struct media_link *link)
1067 {
1068     struct media_device *mdev = link->graph_obj.mdev;
1069 
1070     /* Do nothing if the intf is not registered. */
1071     if (mdev == NULL)
1072         return;
1073 
1074     mutex_lock(&mdev->graph_mutex);
1075     __media_remove_intf_link(link);
1076     mutex_unlock(&mdev->graph_mutex);
1077 }
1078 EXPORT_SYMBOL_GPL(media_remove_intf_link);
1079 
1080 void __media_remove_intf_links(struct media_interface *intf)
1081 {
1082     struct media_link *link, *tmp;
1083 
1084     list_for_each_entry_safe(link, tmp, &intf->links, list)
1085         __media_remove_intf_link(link);
1086 
1087 }
1088 EXPORT_SYMBOL_GPL(__media_remove_intf_links);
1089 
1090 void media_remove_intf_links(struct media_interface *intf)
1091 {
1092     struct media_device *mdev = intf->graph_obj.mdev;
1093 
1094     /* Do nothing if the intf is not registered. */
1095     if (mdev == NULL)
1096         return;
1097 
1098     mutex_lock(&mdev->graph_mutex);
1099     __media_remove_intf_links(intf);
1100     mutex_unlock(&mdev->graph_mutex);
1101 }
1102 EXPORT_SYMBOL_GPL(media_remove_intf_links);
1103 
1104 struct media_link *media_create_ancillary_link(struct media_entity *primary,
1105                            struct media_entity *ancillary)
1106 {
1107     struct media_link *link;
1108 
1109     link = media_add_link(&primary->links);
1110     if (!link)
1111         return ERR_PTR(-ENOMEM);
1112 
1113     link->gobj0 = &primary->graph_obj;
1114     link->gobj1 = &ancillary->graph_obj;
1115     link->flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED |
1116               MEDIA_LNK_FL_ANCILLARY_LINK;
1117 
1118     /* Initialize graph object embedded in the new link */
1119     media_gobj_create(primary->graph_obj.mdev, MEDIA_GRAPH_LINK,
1120               &link->graph_obj);
1121 
1122     return link;
1123 }
1124 EXPORT_SYMBOL_GPL(media_create_ancillary_link);
1125 
1126 struct media_link *__media_entity_next_link(struct media_entity *entity,
1127                         struct media_link *link,
1128                         unsigned long link_type)
1129 {
1130     link = link ? list_next_entry(link, list)
1131             : list_first_entry(&entity->links, typeof(*link), list);
1132 
1133     list_for_each_entry_from(link, &entity->links, list)
1134         if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == link_type)
1135             return link;
1136 
1137     return NULL;
1138 }
1139 EXPORT_SYMBOL_GPL(__media_entity_next_link);