[media] dvbdev: create links on devices with multiple frontends
authorMauro Carvalho Chehab <mchehab@osg.samsung.com>
Wed, 30 Dec 2015 12:11:53 +0000 (10:11 -0200)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Mon, 11 Jan 2016 14:19:26 +0000 (12:19 -0200)
Devices like mxl111sf-based WinTV Aero-m have multiple
frontends, all linked on the same demod. Currently, the
dvb_create_graph() function is not smart enough to create
multiple links. Fix it.

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/dvb-core/dvbdev.c
drivers/media/dvb-core/dvbdev.h

index 28e340583edee3075e84896de2fec8567788fe90..560450a0b32a5b2399196aa2a9a8d0ff161534e9 100644 (file)
@@ -576,6 +576,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
        struct media_interface *intf;
        unsigned demux_pad = 0;
        unsigned dvr_pad = 0;
+       unsigned ntuner = 0, ndemod = 0;
        int ret;
        static const char *connector_name = "Television";
 
@@ -586,9 +587,11 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
                switch (entity->function) {
                case MEDIA_ENT_F_TUNER:
                        tuner = entity;
+                       ntuner++;
                        break;
                case MEDIA_ENT_F_DTV_DEMOD:
                        demod = entity;
+                       ndemod++;
                        break;
                case MEDIA_ENT_F_TS_DEMUX:
                        demux = entity;
@@ -599,6 +602,18 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
                }
        }
 
+       /*
+        * Prepare to signalize to media_create_pad_links() that multiple
+        * entities of the same type exists and a 1:n or n:1 links need to be
+        * created.
+        * NOTE: if both tuner and demod have multiple instances, it is up
+        * to the caller driver to create such links.
+        */
+       if (ntuner > 1)
+               tuner = NULL;
+       if (ndemod > 1)
+               demod = NULL;
+
        if (create_rf_connector) {
                conn = kzalloc(sizeof(*conn), GFP_KERNEL);
                if (!conn)
@@ -623,28 +638,44 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
                if (ret)
                        return ret;
 
-               if (!tuner)
-                       ret = media_create_pad_link(conn, 0,
-                                                   demod, 0,
-                                                   MEDIA_LNK_FL_ENABLED);
+               if (!ntuner)
+                       ret = media_create_pad_links(mdev,
+                                                    MEDIA_ENT_F_CONN_RF,
+                                                    conn, 0,
+                                                    MEDIA_ENT_F_DTV_DEMOD,
+                                                    demod, 0,
+                                                    MEDIA_LNK_FL_ENABLED,
+                                                    false);
                else
-                       ret = media_create_pad_link(conn, 0,
-                                                   tuner, TUNER_PAD_RF_INPUT,
-                                                   MEDIA_LNK_FL_ENABLED);
+                       ret = media_create_pad_links(mdev,
+                                                    MEDIA_ENT_F_CONN_RF,
+                                                    conn, 0,
+                                                    MEDIA_ENT_F_TUNER,
+                                                    tuner, TUNER_PAD_RF_INPUT,
+                                                    MEDIA_LNK_FL_ENABLED,
+                                                    false);
                if (ret)
                        return ret;
        }
 
-       if (tuner && demod) {
-               ret = media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT,
-                                           demod, 0, MEDIA_LNK_FL_ENABLED);
+       if (ntuner && ndemod) {
+               ret = media_create_pad_links(mdev,
+                                            MEDIA_ENT_F_TUNER,
+                                            tuner, TUNER_PAD_IF_OUTPUT,
+                                            MEDIA_ENT_F_DTV_DEMOD,
+                                            demod, 0, MEDIA_LNK_FL_ENABLED,
+                                            false);
                if (ret)
                        return ret;
        }
 
-       if (demod && demux) {
-               ret = media_create_pad_link(demod, 1, demux,
-                                           0, MEDIA_LNK_FL_ENABLED);
+       if (ndemod && demux) {
+               ret = media_create_pad_links(mdev,
+                                            MEDIA_ENT_F_DTV_DEMOD,
+                                            demod, 1,
+                                            MEDIA_ENT_F_TS_DEMUX,
+                                            demux, 0, MEDIA_LNK_FL_ENABLED,
+                                            false);
                if (ret)
                        return -ENOMEM;
        }
index b622d6a3b95e00d10492dfa9e336a789df1092a0..d7c67baa885e38ec02d073eb422ee01e1501de09 100644 (file)
@@ -225,6 +225,13 @@ void dvb_unregister_device(struct dvb_device *dvbdev);
  *
  * @adap:                      pointer to struct dvb_adapter
  * @create_rf_connector:       if true, it creates the RF connector too
+ *
+ * This function checks all DVB-related functions at the media controller
+ * entities and creates the needed links for the media graph. It is
+ * capable of working with multiple tuners or multiple frontends, but it
+ * won't create links if the device has multiple tuners and multiple frontends
+ * or if the device has multiple muxes. In such case, the caller driver should
+ * manually create the remaining links.
  */
 __must_check int dvb_create_media_graph(struct dvb_adapter *adap,
                                        bool create_rf_connector);