diff options
Diffstat (limited to 'drivers/media/media-entity.c')
-rw-r--r-- | drivers/media/media-entity.c | 155 |
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 | } |
308 | EXPORT_SYMBOL_GPL(media_entity_create_link); | 308 | EXPORT_SYMBOL_GPL(media_entity_create_link); |
309 | |||
310 | static 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 | */ | ||
349 | int __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 | |||
385 | err: | ||
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 | |||
392 | int 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 | } | ||
402 | EXPORT_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 | */ | ||
412 | struct media_link * | ||
413 | media_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 | } | ||
430 | EXPORT_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 | */ | ||
443 | struct 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 | } | ||
463 | EXPORT_SYMBOL_GPL(media_entity_remote_source); | ||