aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb-core
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-01-06 11:57:55 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-02-13 18:10:16 -0500
commit9239effd53d47e3cd9c653830c8465c0a3a427dc (patch)
treec5d2287f369a047aaeadaa4d0c711368fae1a205 /drivers/media/dvb-core
parent6bb0b1829bca35016be6ab662cff36bcfdf646c0 (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.c94
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 */
611static 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
593static int dvb_frontend_thread(void *data) 679static 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();