diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-01-06 11:57:55 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-02-13 18:10:16 -0500 |
commit | 9239effd53d47e3cd9c653830c8465c0a3a427dc (patch) | |
tree | c5d2287f369a047aaeadaa4d0c711368fae1a205 /drivers/media/dvb-core | |
parent | 6bb0b1829bca35016be6ab662cff36bcfdf646c0 (diff) |
[media] dvb-frontend: enable tuner link when the FE thread starts
If the dvb frontend thread starts, the tuner should be switched
to the frontend. Add a code that ensures that this will happen,
using the media controller.
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media/dvb-core')
-rw-r--r-- | drivers/media/dvb-core/dvb_frontend.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 2564422278df..50bc6056e914 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c | |||
@@ -590,12 +590,99 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe) | |||
590 | wake_up_interruptible(&fepriv->wait_queue); | 590 | wake_up_interruptible(&fepriv->wait_queue); |
591 | } | 591 | } |
592 | 592 | ||
593 | /** | ||
594 | * dvb_enable_media_tuner() - tries to enable the DVB tuner | ||
595 | * | ||
596 | * @fe: struct dvb_frontend pointer | ||
597 | * | ||
598 | * This function ensures that just one media tuner is enabled for a given | ||
599 | * frontend. It has two different behaviors: | ||
600 | * - For trivial devices with just one tuner: | ||
601 | * it just enables the existing tuner->fe link | ||
602 | * - For devices with more than one tuner: | ||
603 | * It is up to the driver to implement the logic that will enable one tuner | ||
604 | * and disable the other ones. However, if more than one tuner is enabled for | ||
605 | * the same frontend, it will print an error message and return -EINVAL. | ||
606 | * | ||
607 | * At return, it will return the error code returned by media_entity_setup_link, | ||
608 | * or 0 if everything is OK, if no tuner is linked to the frontend or if the | ||
609 | * mdev is NULL. | ||
610 | */ | ||
611 | static int dvb_enable_media_tuner(struct dvb_frontend *fe) | ||
612 | { | ||
613 | #ifdef CONFIG_MEDIA_CONTROLLER_DVB | ||
614 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
615 | struct dvb_adapter *adapter = fe->dvb; | ||
616 | struct media_device *mdev = adapter->mdev; | ||
617 | struct media_entity *entity, *source; | ||
618 | struct media_link *link, *found_link = NULL; | ||
619 | int i, ret, n_links = 0, active_links = 0; | ||
620 | |||
621 | if (!mdev) | ||
622 | return 0; | ||
623 | |||
624 | entity = fepriv->dvbdev->entity; | ||
625 | for (i = 0; i < entity->num_links; i++) { | ||
626 | link = &entity->links[i]; | ||
627 | if (link->sink->entity == entity) { | ||
628 | found_link = link; | ||
629 | n_links++; | ||
630 | if (link->flags & MEDIA_LNK_FL_ENABLED) | ||
631 | active_links++; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | if (!n_links || active_links == 1 || !found_link) | ||
636 | return 0; | ||
637 | |||
638 | /* | ||
639 | * If a frontend has more than one tuner linked, it is up to the driver | ||
640 | * to select with one will be the active one, as the frontend core can't | ||
641 | * guess. If the driver doesn't do that, it is a bug. | ||
642 | */ | ||
643 | if (n_links > 1 && active_links != 1) { | ||
644 | dev_err(fe->dvb->device, | ||
645 | "WARNING: there are %d active links among %d tuners. This is a driver's bug!\n", | ||
646 | active_links, n_links); | ||
647 | return -EINVAL; | ||
648 | } | ||
649 | |||
650 | source = found_link->source->entity; | ||
651 | for (i = 0; i < source->num_links; i++) { | ||
652 | struct media_entity *sink; | ||
653 | int flags = 0; | ||
654 | |||
655 | link = &source->links[i]; | ||
656 | sink = link->sink->entity; | ||
657 | |||
658 | if (sink == entity) | ||
659 | flags = MEDIA_LNK_FL_ENABLED; | ||
660 | |||
661 | ret = media_entity_setup_link(link, flags); | ||
662 | if (ret) { | ||
663 | dev_err(fe->dvb->device, | ||
664 | "Couldn't change link %s->%s to %s. Error %d\n", | ||
665 | source->name, sink->name, | ||
666 | flags ? "enabled" : "disabled", | ||
667 | ret); | ||
668 | return ret; | ||
669 | } else | ||
670 | dev_dbg(fe->dvb->device, | ||
671 | "link %s->%s was %s\n", | ||
672 | source->name, sink->name, | ||
673 | flags ? "ENABLED" : "disabled"); | ||
674 | } | ||
675 | #endif | ||
676 | return 0; | ||
677 | } | ||
678 | |||
593 | static int dvb_frontend_thread(void *data) | 679 | static int dvb_frontend_thread(void *data) |
594 | { | 680 | { |
595 | struct dvb_frontend *fe = data; | 681 | struct dvb_frontend *fe = data; |
596 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | 682 | struct dvb_frontend_private *fepriv = fe->frontend_priv; |
597 | fe_status_t s; | 683 | fe_status_t s; |
598 | enum dvbfe_algo algo; | 684 | enum dvbfe_algo algo; |
685 | int ret; | ||
599 | 686 | ||
600 | bool re_tune = false; | 687 | bool re_tune = false; |
601 | bool semheld = false; | 688 | bool semheld = false; |
@@ -609,6 +696,13 @@ static int dvb_frontend_thread(void *data) | |||
609 | fepriv->wakeup = 0; | 696 | fepriv->wakeup = 0; |
610 | fepriv->reinitialise = 0; | 697 | fepriv->reinitialise = 0; |
611 | 698 | ||
699 | ret = dvb_enable_media_tuner(fe); | ||
700 | if (ret) { | ||
701 | /* FIXME: return an error if it fails */ | ||
702 | dev_info(fe->dvb->device, | ||
703 | "proceeding with FE task\n"); | ||
704 | } | ||
705 | |||
612 | dvb_frontend_init(fe); | 706 | dvb_frontend_init(fe); |
613 | 707 | ||
614 | set_freezable(); | 708 | set_freezable(); |