linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6]  Some improvements for DVB media graph
@ 2015-12-30 13:48 Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 1/6] [media] dvbdev: remove two dead functions if !CONFIG_MEDIA_CONTROLLER_DVB Mauro Carvalho Chehab
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2015-12-30 13:48 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab

This patch series is the result of some additional tests with the media controller and
several different  pure digital TV devices, using the dvb-usb, dvb-usb-v2 core and 
the siano driver.

It addresses some minor issues, and improves the graph representation of
those devices. In particular, the DVB USB v2 mxl111sf driver supports one
device that has:
- one tuner, provided by the MXL chipset;
- three demodulators (one for ATSC, one for ClearQAM and one for DVB-T), each
  one using a different chip and different driver (lg2161, lgdt3305 and an internal
  DVB-T demodulator inside the MXL chipset);
- one demod, provided by the MXL chipset.

The graph for such design is at:
	https://mchehab.fedorapeople.org/mc-next-gen/mxl111sf.png
with is generated, after this changeset, using mc-nextgen-test tool, available
at:
	https://git.linuxtv.org/mchehab/experimental-v4l-utils.git/log/?h=mc-next-gen-v2

The .dot file produced by the tool is at:
	https://mchehab.fedorapeople.org/mc-next-gen/mxl111sf.dot

Before this patch series, the RF connector and tuner were not shown.
Also, the graph were missing the connections for the frontends 0 and 1.

Mauro Carvalho Chehab (6):
  [media] dvbdev: remove two dead functions if
    !CONFIG_MEDIA_CONTROLLER_DVB
  [media] dvbdev: Add RF connector if needed
  [media] dvb-usb-v2: postpone removal of media_device
  [media] media-entitiy: add a function to create multiple links
  [media] dvbdev: create links on devices with multiple frontends
  [media] mxl111sf: Add a tuner entity

 drivers/media/common/siano/smsdvb-main.c    |  2 +-
 drivers/media/dvb-core/dvbdev.c             | 98 +++++++++++++++++++++++++----
 drivers/media/dvb-core/dvbdev.h             | 33 +++++++++-
 drivers/media/media-entity.c                | 65 +++++++++++++++++++
 drivers/media/usb/au0828/au0828-dvb.c       |  2 +-
 drivers/media/usb/cx231xx/cx231xx-dvb.c     |  2 +-
 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c |  4 +-
 drivers/media/usb/dvb-usb-v2/mxl111sf.c     | 20 ++++++
 drivers/media/usb/dvb-usb-v2/mxl111sf.h     |  5 ++
 drivers/media/usb/dvb-usb/dvb-usb-dvb.c     |  2 +-
 include/media/media-entity.h                | 51 +++++++++++++++
 11 files changed, 264 insertions(+), 20 deletions(-)

-- 
2.5.0



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/6] [media] dvbdev: remove two dead functions if !CONFIG_MEDIA_CONTROLLER_DVB
  2015-12-30 13:48 [PATCH 0/6] Some improvements for DVB media graph Mauro Carvalho Chehab
@ 2015-12-30 13:48 ` Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 2/6] [media] dvbdev: Add RF connector if needed Mauro Carvalho Chehab
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2015-12-30 13:48 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Hans Verkuil

Those functions are used only if CONFIG_MEDIA_CONTROLLER_DVB.
Without that, if !CONFIG_MEDIA_CONTROLLER_DVB, it would produce
two warnings:

drivers/media/dvb-core/dvbdev.c:219:12: warning: 'dvb_create_tsout_entity' defined but not used [-Wunused-function]
 static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
            ^
drivers/media/dvb-core/dvbdev.c:264:12: warning: 'dvb_create_media_entity' defined but not used [-Wunused-function]
 static int dvb_create_media_entity(struct dvb_device *dvbdev,
            ^

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
---
 drivers/media/dvb-core/dvbdev.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index b56e00817d3f..860dd7d06b60 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -216,10 +216,10 @@ static void dvb_media_device_free(struct dvb_device *dvbdev)
 #endif
 }
 
+#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
 static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
 				    const char *name, int npads)
 {
-#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
 	int i, ret = 0;
 
 	dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads),
@@ -254,7 +254,6 @@ static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
 		if (ret < 0)
 			return ret;
 	}
-#endif
 	return 0;
 }
 
@@ -264,7 +263,6 @@ static int dvb_create_tsout_entity(struct dvb_device *dvbdev,
 static int dvb_create_media_entity(struct dvb_device *dvbdev,
 				   int type, int demux_sink_pads)
 {
-#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
 	int i, ret, npads;
 
 	switch (type) {
@@ -352,9 +350,9 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
 	printk(KERN_DEBUG "%s: media entity '%s' registered.\n",
 		__func__, dvbdev->entity->name);
 
-#endif
 	return 0;
 }
+#endif
 
 static int dvb_register_media_device(struct dvb_device *dvbdev,
 				     int type, int minor,
-- 
2.5.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/6] [media] dvbdev: Add RF connector if needed
  2015-12-30 13:48 [PATCH 0/6] Some improvements for DVB media graph Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 1/6] [media] dvbdev: remove two dead functions if !CONFIG_MEDIA_CONTROLLER_DVB Mauro Carvalho Chehab
@ 2015-12-30 13:48 ` Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 3/6] [media] dvb-usb-v2: postpone removal of media_device Mauro Carvalho Chehab
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2015-12-30 13:48 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Antti Palosaari,
	Hans Verkuil, Stefan Richter, Sakari Ailus,
	Javier Martinez Canillas, Jonathan Corbet,
	Rafael Lourenço de Lima Chehab, Olli Salonen,
	Matthias Schwarzott, Luis de Bethencourt

Several pure digital TV devices have a frontend with the tuner
integrated on it. Add the RF connector when dvb_create_media_graph()
is called on such devices.

Tested with siano and dvb_usb_mxl111sf drivers.

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
---
 drivers/media/common/siano/smsdvb-main.c    |  2 +-
 drivers/media/dvb-core/dvbdev.c             | 49 +++++++++++++++++++++++++++--
 drivers/media/dvb-core/dvbdev.h             | 20 ++++++++++--
 drivers/media/usb/au0828/au0828-dvb.c       |  2 +-
 drivers/media/usb/cx231xx/cx231xx-dvb.c     |  2 +-
 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c |  2 +-
 drivers/media/usb/dvb-usb/dvb-usb-dvb.c     |  2 +-
 7 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c
index 8a1ea2192439..d31f468830cf 100644
--- a/drivers/media/common/siano/smsdvb-main.c
+++ b/drivers/media/common/siano/smsdvb-main.c
@@ -1184,7 +1184,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
 	if (smsdvb_debugfs_create(client) < 0)
 		pr_info("failed to create debugfs node\n");
 
-	rc = dvb_create_media_graph(&client->adapter);
+	rc = dvb_create_media_graph(&client->adapter, true);
 	if (rc < 0) {
 		pr_err("dvb_create_media_graph failed %d\n", rc);
 		goto client_error;
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 860dd7d06b60..28e340583ede 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -213,6 +213,13 @@ static void dvb_media_device_free(struct dvb_device *dvbdev)
 		media_devnode_remove(dvbdev->intf_devnode);
 		dvbdev->intf_devnode = NULL;
 	}
+
+	if (dvbdev->adapter->conn) {
+		media_device_unregister_entity(dvbdev->adapter->conn);
+		dvbdev->adapter->conn = NULL;
+		kfree(dvbdev->adapter->conn_pads);
+		dvbdev->adapter->conn_pads = NULL;
+	}
 #endif
 }
 
@@ -559,16 +566,18 @@ static int dvb_create_io_intf_links(struct dvb_adapter *adap,
 	return 0;
 }
 
-int dvb_create_media_graph(struct dvb_adapter *adap)
+int dvb_create_media_graph(struct dvb_adapter *adap,
+			   bool create_rf_connector)
 {
 	struct media_device *mdev = adap->mdev;
-	struct media_entity *entity, *tuner = NULL, *demod = NULL;
+	struct media_entity *entity, *tuner = NULL, *demod = NULL, *conn;
 	struct media_entity *demux = NULL, *ca = NULL;
 	struct media_link *link;
 	struct media_interface *intf;
 	unsigned demux_pad = 0;
 	unsigned dvr_pad = 0;
 	int ret;
+	static const char *connector_name = "Television";
 
 	if (!mdev)
 		return 0;
@@ -590,6 +599,42 @@ int dvb_create_media_graph(struct dvb_adapter *adap)
 		}
 	}
 
+	if (create_rf_connector) {
+		conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+		if (!conn)
+			return -ENOMEM;
+		adap->conn = conn;
+
+		adap->conn_pads = kcalloc(1, sizeof(*adap->conn_pads),
+					    GFP_KERNEL);
+		if (!adap->conn_pads)
+			return -ENOMEM;
+
+		conn->flags = MEDIA_ENT_FL_CONNECTOR;
+		conn->function = MEDIA_ENT_F_CONN_RF;
+		conn->name = connector_name;
+		adap->conn_pads->flags = MEDIA_PAD_FL_SOURCE;
+
+		ret = media_entity_pads_init(conn, 1, adap->conn_pads);
+		if (ret)
+			return ret;
+
+		ret = media_device_register_entity(mdev, conn);
+		if (ret)
+			return ret;
+
+		if (!tuner)
+			ret = media_create_pad_link(conn, 0,
+						    demod, 0,
+						    MEDIA_LNK_FL_ENABLED);
+		else
+			ret = media_create_pad_link(conn, 0,
+						    tuner, TUNER_PAD_RF_INPUT,
+						    MEDIA_LNK_FL_ENABLED);
+		if (ret)
+			return ret;
+	}
+
 	if (tuner && demod) {
 		ret = media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT,
 					    demod, 0, MEDIA_LNK_FL_ENABLED);
diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
index abee18a402e1..b622d6a3b95e 100644
--- a/drivers/media/dvb-core/dvbdev.h
+++ b/drivers/media/dvb-core/dvbdev.h
@@ -75,6 +75,9 @@ struct dvb_frontend;
  *			used.
  * @mdev:		pointer to struct media_device, used when the media
  *			controller is used.
+ * @conn:		RF connector. Used only if the device has no separate
+ *			tuner.
+ * @conn_pads:		pointer to struct media_pad associated with @conn;
  */
 struct dvb_adapter {
 	int num;
@@ -94,6 +97,8 @@ struct dvb_adapter {
 
 #if defined(CONFIG_MEDIA_CONTROLLER_DVB)
 	struct media_device *mdev;
+	struct media_entity *conn;
+	struct media_pad *conn_pads;
 #endif
 };
 
@@ -214,7 +219,16 @@ int dvb_register_device(struct dvb_adapter *adap,
 void dvb_unregister_device(struct dvb_device *dvbdev);
 
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
-__must_check int dvb_create_media_graph(struct dvb_adapter *adap);
+/**
+ * dvb_create_media_graph - Creates media graph for the Digital TV part of the
+ * 				device.
+ *
+ * @adap:			pointer to struct dvb_adapter
+ * @create_rf_connector:	if true, it creates the RF connector too
+ */
+__must_check int dvb_create_media_graph(struct dvb_adapter *adap,
+					bool create_rf_connector);
+
 static inline void dvb_register_media_controller(struct dvb_adapter *adap,
 						 struct media_device *mdev)
 {
@@ -222,7 +236,9 @@ static inline void dvb_register_media_controller(struct dvb_adapter *adap,
 }
 
 #else
-static inline int dvb_create_media_graph(struct dvb_adapter *adap)
+static inline
+int dvb_create_media_graph(struct dvb_adapter *adap,
+			   bool create_rf_connector)
 {
 	return 0;
 };
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index cd542b49a6c2..94363a3ba400 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -486,7 +486,7 @@ static int dvb_register(struct au0828_dev *dev)
 	dvb->start_count = 0;
 	dvb->stop_count = 0;
 
-	result = dvb_create_media_graph(&dvb->adapter);
+	result = dvb_create_media_graph(&dvb->adapter, false);
 	if (result < 0)
 		goto fail_create_graph;
 
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index b7552d20ebdb..b8d5b2be9293 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -551,7 +551,7 @@ static int register_dvb(struct cx231xx_dvb *dvb,
 
 	/* register network adapter */
 	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
-	result = dvb_create_media_graph(&dvb->adapter);
+	result = dvb_create_media_graph(&dvb->adapter, false);
 	if (result < 0)
 		goto fail_create_graph;
 
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 0fa2c45917b0..e8491f73c0d9 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -706,7 +706,7 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
 		}
 	}
 
-	ret = dvb_create_media_graph(&adap->dvb_adap);
+	ret = dvb_create_media_graph(&adap->dvb_adap, true);
 	if (ret < 0)
 		goto err_dvb_unregister_frontend;
 
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
index 241463ef631e..9ddfcab268be 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c
@@ -330,7 +330,7 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
 	if (ret)
 		return ret;
 
-	ret = dvb_create_media_graph(&adap->dvb_adap);
+	ret = dvb_create_media_graph(&adap->dvb_adap, true);
 	if (ret)
 		return ret;
 
-- 
2.5.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/6] [media] dvb-usb-v2: postpone removal of media_device
  2015-12-30 13:48 [PATCH 0/6] Some improvements for DVB media graph Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 1/6] [media] dvbdev: remove two dead functions if !CONFIG_MEDIA_CONTROLLER_DVB Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 2/6] [media] dvbdev: Add RF connector if needed Mauro Carvalho Chehab
@ 2015-12-30 13:48 ` Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 4/6] [media] media-entitiy: add a function to create multiple links Mauro Carvalho Chehab
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2015-12-30 13:48 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Antti Palosaari

We should not remove the media_device until its last usage,
or we may have use after free troubles.

So, move the per-adapter media_device removal to happen at
the end of the adapter removal code.

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
---
 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index e8491f73c0d9..f0565bf3673e 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -542,7 +542,6 @@ static int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
 		adap->demux.dmx.close(&adap->demux.dmx);
 		dvb_dmxdev_release(&adap->dmxdev);
 		dvb_dmx_release(&adap->demux);
-		dvb_usbv2_media_device_unregister(adap);
 		dvb_unregister_adapter(&adap->dvb_adap);
 	}
 
@@ -852,6 +851,7 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d)
 			dvb_usbv2_adapter_dvb_exit(&d->adapter[i]);
 			dvb_usbv2_adapter_stream_exit(&d->adapter[i]);
 			dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
+			dvb_usbv2_media_device_unregister(&d->adapter[i]);
 		}
 	}
 
-- 
2.5.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/6] [media] media-entitiy: add a function to create multiple links
  2015-12-30 13:48 [PATCH 0/6] Some improvements for DVB media graph Mauro Carvalho Chehab
                   ` (2 preceding siblings ...)
  2015-12-30 13:48 ` [PATCH 3/6] [media] dvb-usb-v2: postpone removal of media_device Mauro Carvalho Chehab
@ 2015-12-30 13:48 ` Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 5/6] [media] dvbdev: create links on devices with multiple frontends Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 6/6] [media] mxl111sf: Add a tuner entity Mauro Carvalho Chehab
  5 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2015-12-30 13:48 UTC (permalink / raw)
  To: Linux Media Mailing List; +Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab

Sometimes, it is desired to create 1:n and n:1 or even
n:n links between different entities with the same
function.

This is actually needed to support DVB devices that
have multiple frontends. While we could do a function
like that internally at the DVB core, such function is
generic enough to be at media-entity, and it could be
useful on some other places.

So, add such function.

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
---
 drivers/media/media-entity.c | 65 ++++++++++++++++++++++++++++++++++++++++++++
 include/media/media-entity.h | 51 ++++++++++++++++++++++++++++++++++
 2 files changed, 116 insertions(+)

diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index eb38bc35320a..e89d85a7d31b 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -625,6 +625,71 @@ media_create_pad_link(struct media_entity *source, u16 source_pad,
 }
 EXPORT_SYMBOL_GPL(media_create_pad_link);
 
+int media_create_pad_links(const struct media_device *mdev,
+			   const u32 source_function,
+			   struct media_entity *source,
+			   const u16 source_pad,
+			   const u32 sink_function,
+			   struct media_entity *sink,
+			   const u16 sink_pad,
+			   u32 flags,
+			   const bool allow_both_undefined)
+{
+	struct media_entity *entity;
+	unsigned function;
+	int ret;
+
+	/* Trivial case: 1:1 relation */
+	if (source && sink)
+		return media_create_pad_link(source, source_pad,
+					     sink, sink_pad, flags);
+
+	/* Worse case scenario: n:n relation */
+	if (!source && !sink) {
+		if (!allow_both_undefined)
+			return 0;
+		media_device_for_each_entity(source, mdev) {
+			if (source->function != source_function)
+				continue;
+			media_device_for_each_entity(sink, mdev) {
+				if (sink->function != sink_function)
+					continue;
+				ret = media_create_pad_link(source, source_pad,
+							    sink, sink_pad,
+							    flags);
+				if (ret)
+					return ret;
+				flags &= ~(MEDIA_LNK_FL_ENABLED |
+					   MEDIA_LNK_FL_IMMUTABLE);
+			}
+		}
+		return 0;
+	}
+
+	/* Handle 1:n and n:1 cases */
+	if (source)
+		function = sink_function;
+	else
+		function = source_function;
+
+	media_device_for_each_entity(entity, mdev) {
+		if (entity->function != function)
+			continue;
+
+		if (source)
+			ret = media_create_pad_link(source, source_pad,
+						    entity, sink_pad, flags);
+		else
+			ret = media_create_pad_link(entity, source_pad,
+						    sink, sink_pad, flags);
+		if (ret)
+			return ret;
+		flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(media_create_pad_links);
+
 void __media_entity_remove_links(struct media_entity *entity)
 {
 	struct media_link *link, *tmp;
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 79dd81fd463e..fe485d367985 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -613,6 +613,57 @@ static inline void media_entity_cleanup(struct media_entity *entity) {};
 __must_check int media_create_pad_link(struct media_entity *source,
 			u16 source_pad, struct media_entity *sink,
 			u16 sink_pad, u32 flags);
+
+/**
+ * media_create_pad_links() - creates a link between two entities.
+ *
+ * @mdev: Pointer to the media_device that contains the object
+ * @source_function: Function of the source entities. Used only if @source is
+ *	NULL.
+ * @source: pointer to &media_entity of the source pad. If NULL, it will use
+ * 	all entities that matches the @sink_function.
+ * @source_pad: number of the source pad in the pads array
+ * @sink_function: Function of the sink entities. Used only if @sink is NULL.
+ * @sink: pointer to &media_entity of the sink pad. If NULL, it will use
+ * 	all entities that matches the @sink_function.
+ * @sink_pad: number of the sink pad in the pads array.
+ * @flags: Link flags, as defined in include/uapi/linux/media.h.
+ * @allow_both_undefined: if true, then both @source and @sink can be NULL.
+ *	In such case, it will create a crossbar between all entities that
+ *	matches @source_function to all entities that matches @sink_function.
+ *	If false, it will return 0 and won't create any link if both @source
+ *	and @sink are NULL.
+ *
+ * Valid values for flags:
+ * A %MEDIA_LNK_FL_ENABLED flag indicates that the link is enabled and can be
+ *	used to transfer media data. If multiple links are created and this
+ *	flag is passed as an argument, only the first created link will have
+ *	this flag.
+ *
+ * A %MEDIA_LNK_FL_IMMUTABLE flag indicates that the link enabled state can't
+ *	be modified at runtime. If %MEDIA_LNK_FL_IMMUTABLE is set, then
+ *	%MEDIA_LNK_FL_ENABLED must also be set since an immutable link is
+ *	always enabled.
+ *
+ * It is common for some devices to have multiple source and/or sink entities
+ * of the same type that should be linked. While media_create_pad_link()
+ * creates link by link, this function is meant to allow 1:n, n:1 and even
+ * cross-bar (n:n) links.
+ *
+ * NOTE: Before calling this function, media_entity_pads_init() and
+ * media_device_register_entity() should be called previously for the entities
+ * to be linked.
+ */
+int media_create_pad_links(const struct media_device *mdev,
+			   const u32 source_function,
+			   struct media_entity *source,
+			   const u16 source_pad,
+			   const u32 sink_function,
+			   struct media_entity *sink,
+			   const u16 sink_pad,
+			   u32 flags,
+			   const bool allow_both_undefined);
+
 void __media_entity_remove_links(struct media_entity *entity);
 
 /**
-- 
2.5.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 5/6] [media] dvbdev: create links on devices with multiple frontends
  2015-12-30 13:48 [PATCH 0/6] Some improvements for DVB media graph Mauro Carvalho Chehab
                   ` (3 preceding siblings ...)
  2015-12-30 13:48 ` [PATCH 4/6] [media] media-entitiy: add a function to create multiple links Mauro Carvalho Chehab
@ 2015-12-30 13:48 ` Mauro Carvalho Chehab
  2015-12-30 13:48 ` [PATCH 6/6] [media] mxl111sf: Add a tuner entity Mauro Carvalho Chehab
  5 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2015-12-30 13:48 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Hans Verkuil,
	Jonathan Corbet

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 | 57 +++++++++++++++++++++++++++++++----------
 drivers/media/dvb-core/dvbdev.h |  7 +++++
 2 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 28e340583ede..560450a0b32a 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -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;
 	}
diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
index b622d6a3b95e..d7c67baa885e 100644
--- a/drivers/media/dvb-core/dvbdev.h
+++ b/drivers/media/dvb-core/dvbdev.h
@@ -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);
-- 
2.5.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 6/6] [media] mxl111sf: Add a tuner entity
  2015-12-30 13:48 [PATCH 0/6] Some improvements for DVB media graph Mauro Carvalho Chehab
                   ` (4 preceding siblings ...)
  2015-12-30 13:48 ` [PATCH 5/6] [media] dvbdev: create links on devices with multiple frontends Mauro Carvalho Chehab
@ 2015-12-30 13:48 ` Mauro Carvalho Chehab
  5 siblings, 0 replies; 7+ messages in thread
From: Mauro Carvalho Chehab @ 2015-12-30 13:48 UTC (permalink / raw)
  To: Linux Media Mailing List
  Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Michael Krufky,
	Hans Verkuil, Jonathan Corbet

While mxl111sf may have multiple frontends, it has just one
tuner. Reflect that on the media graph.

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
---
 drivers/media/dvb-core/dvbdev.h         |  6 ++++++
 drivers/media/usb/dvb-usb-v2/mxl111sf.c | 20 ++++++++++++++++++++
 drivers/media/usb/dvb-usb-v2/mxl111sf.h |  5 +++++
 3 files changed, 31 insertions(+)

diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
index d7c67baa885e..4aff7bd3dea8 100644
--- a/drivers/media/dvb-core/dvbdev.h
+++ b/drivers/media/dvb-core/dvbdev.h
@@ -242,6 +242,11 @@ static inline void dvb_register_media_controller(struct dvb_adapter *adap,
 	adap->mdev = mdev;
 }
 
+static inline struct media_device
+*dvb_get_media_controller(struct dvb_adapter *adap)
+{
+	return adap->mdev;
+}
 #else
 static inline
 int dvb_create_media_graph(struct dvb_adapter *adap,
@@ -250,6 +255,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
 	return 0;
 };
 #define dvb_register_media_controller(a, b) {}
+#define dvb_get_media_controller(a) NULL
 #endif
 
 int dvb_generic_open (struct inode *inode, struct file *file);
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index 1710f9038d75..b669deccc34c 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -10,6 +10,7 @@
 
 #include <linux/vmalloc.h>
 #include <linux/i2c.h>
+#include <media/tuner.h>
 
 #include "mxl111sf.h"
 #include "mxl111sf-reg.h"
@@ -868,6 +869,10 @@ static struct mxl111sf_tuner_config mxl_tuner_config = {
 static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
 {
 	struct mxl111sf_state *state = adap_to_priv(adap);
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+	struct media_device *mdev = dvb_get_media_controller(&adap->dvb_adap);
+	int ret;
+#endif
 	int i;
 
 	pr_debug("%s()\n", __func__);
@@ -879,6 +884,21 @@ static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
 		adap->fe[i]->ops.read_signal_strength = adap->fe[i]->ops.tuner_ops.get_rf_strength;
 	}
 
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+	state->tuner.function = MEDIA_ENT_F_TUNER;
+	state->tuner.name = "mxl111sf tuner";
+	state->tuner_pads[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+	state->tuner_pads[TUNER_PAD_IF_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&state->tuner,
+				     TUNER_NUM_PADS, state->tuner_pads);
+	if (ret)
+		return ret;
+
+	ret = media_device_register_entity(mdev, &state->tuner);
+	if (ret)
+		return ret;
+#endif
 	return 0;
 }
 
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
index ee70df1f1e94..846260e0eec0 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
@@ -17,6 +17,7 @@
 #define DVB_USB_LOG_PREFIX "mxl111sf"
 #include "dvb_usb.h"
 #include <media/tveeprom.h>
+#include <media/media-entity.h>
 
 #define MXL_EP1_REG_READ     1
 #define MXL_EP2_REG_WRITE    2
@@ -85,6 +86,10 @@ struct mxl111sf_state {
 	struct mutex fe_lock;
 	u8 num_frontends;
 	struct mxl111sf_adap_state adap_state[3];
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+	struct media_entity tuner;
+	struct media_pad tuner_pads[2];
+#endif
 };
 
 int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
-- 
2.5.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-12-30 13:49 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-30 13:48 [PATCH 0/6] Some improvements for DVB media graph Mauro Carvalho Chehab
2015-12-30 13:48 ` [PATCH 1/6] [media] dvbdev: remove two dead functions if !CONFIG_MEDIA_CONTROLLER_DVB Mauro Carvalho Chehab
2015-12-30 13:48 ` [PATCH 2/6] [media] dvbdev: Add RF connector if needed Mauro Carvalho Chehab
2015-12-30 13:48 ` [PATCH 3/6] [media] dvb-usb-v2: postpone removal of media_device Mauro Carvalho Chehab
2015-12-30 13:48 ` [PATCH 4/6] [media] media-entitiy: add a function to create multiple links Mauro Carvalho Chehab
2015-12-30 13:48 ` [PATCH 5/6] [media] dvbdev: create links on devices with multiple frontends Mauro Carvalho Chehab
2015-12-30 13:48 ` [PATCH 6/6] [media] mxl111sf: Add a tuner entity Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).