Some improvements for DVB media graph
Subsystems (5)
cover Some improvements for DVB media graph
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(-)
Signature · 1 line
2.5.0
PATCH 1/6 dvbdev: remove two dead functions if !CONFIG_MEDIA_CONTROLLER_DVB
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,
^--- drivers/media/dvb-core/dvbdev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/media/dvb-core/dvbdev.c +2 -4
@@ -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,
Signature · 1 line
2.5.0
PATCH 2/6 dvbdev: Add RF connector if needed
In reply to Mauro Carvalho ChehabSeveral 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.
--- 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(-)
drivers/media/common/siano/smsdvb-main.c +1 -1
@@ -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;
drivers/media/dvb-core/dvbdev.c +47 -2
75 lines not on this page · raw message
drivers/media/dvb-core/dvbdev.h +18 -2
@@ -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 ; };
drivers/media/usb/au0828/au0828-dvb.c +1 -1
@@ -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;
drivers/media/usb/cx231xx/cx231xx-dvb.c +1 -1
@@ -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;
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +1 -1
@@ -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;
drivers/media/usb/dvb-usb/dvb-usb-dvb.c +1 -1
@@ -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;
Signature · 1 line
2.5.0
PATCH 3/6 dvb-usb-v2: postpone removal of media_device
In reply to Mauro Carvalho ChehabWe 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.
--- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +1 -1
@@ -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]); } }
Signature · 1 line
2.5.0
PATCH 4/6 media-entitiy: add a function to create multiple links
In reply to Mauro Carvalho ChehabSometimes, 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.
--- drivers/media/media-entity.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ include/media/media-entity.h | 51 ++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+)
drivers/media/media-entity.c +65 -0
@@ -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;
include/media/media-entity.h +51 -0
57 lines not on this page · raw message
Signature · 1 line
2.5.0
PATCH 5/6 dvbdev: create links on devices with multiple frontends
In reply to Mauro Carvalho ChehabDevices 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.
--- drivers/media/dvb-core/dvbdev.c | 57 +++++++++++++++++++++++++++++++---------- drivers/media/dvb-core/dvbdev.h | 7 +++++ 2 files changed, 51 insertions(+), 13 deletions(-)
drivers/media/dvb-core/dvbdev.c +44 -13
@@ -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 ; }
drivers/media/dvb-core/dvbdev.h +7 -0
@@ -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);
Signature · 1 line
2.5.0
PATCH 6/6 mxl111sf: Add a tuner entity
In reply to Mauro Carvalho ChehabWhile mxl111sf may have multiple frontends, it has just one tuner. Reflect that on the media graph.
--- 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(+)
drivers/media/dvb-core/dvbdev.h +6 -0
@@ -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);
drivers/media/usb/dvb-usb-v2/mxl111sf.c +20 -0
@@ -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 ; }
drivers/media/usb/dvb-usb-v2/mxl111sf.h +5 -0
@@ -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);
Signature · 1 line
2.5.0