0001
0002
0003
0004
0005
0006
0007
0008
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
0084
0085
0086
0087
0088
0089
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
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
0174 if (gobj->mdev == NULL)
0175 return;
0176
0177 dev_dbg_obj(__func__, gobj);
0178
0179 gobj->mdev->topology_version++;
0180
0181
0182 list_del(&gobj->list);
0183
0184 gobj->mdev = NULL;
0185 }
0186
0187
0188
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
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
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
0263
0264
0265
0266
0267
0268
0269
0270
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
0281
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
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
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
0328 next = media_entity_other(entity, link);
0329
0330
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
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
0356
0357
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
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
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
0458 bitmap_clear(has_no_links, pad->index, 1);
0459
0460
0461
0462
0463
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
0471
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
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
0509
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
0518
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
0550
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
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
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
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;
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
0681 media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
0682 &link->graph_obj);
0683
0684
0685
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
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
0728 if (source && sink)
0729 return media_create_pad_link(source, source_pad,
0730 sink, sink_pad, flags);
0731
0732
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
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
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
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
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
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
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
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
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
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);