aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/media-entity.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/media-entity.c')
-rw-r--r--drivers/media/media-entity.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 3e7e2d569cec..6795c920d460 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -306,3 +306,158 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
306 return 0; 306 return 0;
307} 307}
308EXPORT_SYMBOL_GPL(media_entity_create_link); 308EXPORT_SYMBOL_GPL(media_entity_create_link);
309
310static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
311{
312 const u32 mask = MEDIA_LNK_FL_ENABLED;
313 int ret;
314
315 /* Notify both entities. */
316 ret = media_entity_call(link->source->entity, link_setup,
317 link->source, link->sink, flags);
318 if (ret < 0 && ret != -ENOIOCTLCMD)
319 return ret;
320
321 ret = media_entity_call(link->sink->entity, link_setup,
322 link->sink, link->source, flags);
323 if (ret < 0 && ret != -ENOIOCTLCMD) {
324 media_entity_call(link->source->entity, link_setup,
325 link->source, link->sink, link->flags);
326 return ret;
327 }
328
329 link->flags = (link->flags & ~mask) | (flags & mask);
330 link->reverse->flags = link->flags;
331
332 return 0;
333}
334
335/**
336 * __media_entity_setup_link - Configure a media link
337 * @link: The link being configured
338 * @flags: Link configuration flags
339 *
340 * The bulk of link setup is handled by the two entities connected through the
341 * link. This function notifies both entities of the link configuration change.
342 *
343 * If the link is immutable or if the current and new configuration are
344 * identical, return immediately.
345 *
346 * The user is expected to hold link->source->parent->mutex. If not,
347 * media_entity_setup_link() should be used instead.
348 */
349int __media_entity_setup_link(struct media_link *link, u32 flags)
350{
351 struct media_device *mdev;
352 struct media_entity *source, *sink;
353 int ret = -EBUSY;
354
355 if (link == NULL)
356 return -EINVAL;
357
358 if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
359 return link->flags == flags ? 0 : -EINVAL;
360
361 if (link->flags == flags)
362 return 0;
363
364 source = link->source->entity;
365 sink = link->sink->entity;
366
367 mdev = source->parent;
368
369 if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) {
370 ret = mdev->link_notify(link->source, link->sink,
371 MEDIA_LNK_FL_ENABLED);
372 if (ret < 0)
373 return ret;
374 }
375
376 ret = __media_entity_setup_link_notify(link, flags);
377 if (ret < 0)
378 goto err;
379
380 if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
381 mdev->link_notify(link->source, link->sink, 0);
382
383 return 0;
384
385err:
386 if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify)
387 mdev->link_notify(link->source, link->sink, 0);
388
389 return ret;
390}
391
392int media_entity_setup_link(struct media_link *link, u32 flags)
393{
394 int ret;
395
396 mutex_lock(&link->source->entity->parent->graph_mutex);
397 ret = __media_entity_setup_link(link, flags);
398 mutex_unlock(&link->source->entity->parent->graph_mutex);
399
400 return ret;
401}
402EXPORT_SYMBOL_GPL(media_entity_setup_link);
403
404/**
405 * media_entity_find_link - Find a link between two pads
406 * @source: Source pad
407 * @sink: Sink pad
408 *
409 * Return a pointer to the link between the two entities. If no such link
410 * exists, return NULL.
411 */
412struct media_link *
413media_entity_find_link(struct media_pad *source, struct media_pad *sink)
414{
415 struct media_link *link;
416 unsigned int i;
417
418 for (i = 0; i < source->entity->num_links; ++i) {
419 link = &source->entity->links[i];
420
421 if (link->source->entity == source->entity &&
422 link->source->index == source->index &&
423 link->sink->entity == sink->entity &&
424 link->sink->index == sink->index)
425 return link;
426 }
427
428 return NULL;
429}
430EXPORT_SYMBOL_GPL(media_entity_find_link);
431
432/**
433 * media_entity_remote_source - Find the source pad at the remote end of a link
434 * @pad: Sink pad at the local end of the link
435 *
436 * Search for a remote source pad connected to the given sink pad by iterating
437 * over all links originating or terminating at that pad until an enabled link
438 * is found.
439 *
440 * Return a pointer to the pad at the remote end of the first found enabled
441 * link, or NULL if no enabled link has been found.
442 */
443struct media_pad *media_entity_remote_source(struct media_pad *pad)
444{
445 unsigned int i;
446
447 for (i = 0; i < pad->entity->num_links; i++) {
448 struct media_link *link = &pad->entity->links[i];
449
450 if (!(link->flags & MEDIA_LNK_FL_ENABLED))
451 continue;
452
453 if (link->source == pad)
454 return link->sink;
455
456 if (link->sink == pad)
457 return link->source;
458 }
459
460 return NULL;
461
462}
463EXPORT_SYMBOL_GPL(media_entity_remote_source);