diff options
Diffstat (limited to 'drivers/media/dvb-core')
-rw-r--r-- | drivers/media/dvb-core/dmxdev.c | 11 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvb-usb-ids.h | 3 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvb_ca_en50221.c | 30 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvb_frontend.c | 124 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvb_net.c | 6 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvbdev.c | 144 | ||||
-rw-r--r-- | drivers/media/dvb-core/dvbdev.h | 27 |
7 files changed, 324 insertions, 21 deletions
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index abff803ad69a..d0e3f9d85f34 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1136,10 +1136,13 @@ static const struct file_operations dvb_demux_fops = { .llseek = default_llseek, }; -static struct dvb_device dvbdev_demux = { +static const struct dvb_device dvbdev_demux = { .priv = NULL, .users = 1, .writers = 1, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = "dvb-demux", +#endif .fops = &dvb_demux_fops }; @@ -1209,13 +1212,15 @@ static const struct file_operations dvb_dvr_fops = { .llseek = default_llseek, }; -static struct dvb_device dvbdev_dvr = { +static const struct dvb_device dvbdev_dvr = { .priv = NULL, .readers = 1, .users = 1, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = "dvb-dvr", +#endif .fops = &dvb_dvr_fops }; - int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) { int i; diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 80ab8d0ff6e0..c117fb3b4aff 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -245,6 +245,7 @@ #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 #define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d +#define USB_PID_TECHNOTREND_CONNECT_S2_4600 0x3011 #define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI 0x3012 #define USB_PID_TECHNOTREND_TVSTICK_CT2_4400 0x3014 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a @@ -318,6 +319,7 @@ #define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6 #define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7 #define USB_PID_WINFAST_DTV2000DS 0x6a04 +#define USB_PID_WINFAST_DTV2000DS_PLUS 0x6f12 #define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 @@ -385,4 +387,5 @@ #define USB_PID_PCTV_2002E 0x025c #define USB_PID_PCTV_2002E_SE 0x025d #define USB_PID_SVEON_STV27 0xd3af +#define USB_PID_TURBOX_DTT_2000 0xd3a4 #endif diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 0aac3096728e..72937756f60c 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -1638,15 +1638,17 @@ static const struct file_operations dvb_ca_fops = { .llseek = noop_llseek, }; -static struct dvb_device dvbdev_ca = { +static const struct dvb_device dvbdev_ca = { .priv = NULL, .users = 1, .readers = 1, .writers = 1, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = "dvb-ca-en50221", +#endif .fops = &dvb_ca_fops, }; - /* ******************************************************************************** */ /* Initialisation/shutdown functions */ @@ -1676,14 +1678,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, /* initialise the system data */ if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { ret = -ENOMEM; - goto error; + goto exit; } ca->pub = pubca; ca->flags = flags; ca->slot_count = slot_count; if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) { ret = -ENOMEM; - goto error; + goto free_ca; } init_waitqueue_head(&ca->wait_queue); ca->open = 0; @@ -1694,7 +1696,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, /* register the DVB device */ ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); if (ret) - goto error; + goto free_slot_info; /* now initialise each slot */ for (i = 0; i < slot_count; i++) { @@ -1709,7 +1711,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, if (signal_pending(current)) { ret = -EINTR; - goto error; + goto unregister_device; } mb(); @@ -1720,17 +1722,17 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ret = PTR_ERR(ca->thread); printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret); - goto error; + goto unregister_device; } return 0; -error: - if (ca != NULL) { - if (ca->dvbdev != NULL) - dvb_unregister_device(ca->dvbdev); - kfree(ca->slot_info); - kfree(ca); - } +unregister_device: + dvb_unregister_device(ca->dvbdev); +free_slot_info: + kfree(ca->slot_info); +free_ca: + kfree(ca); +exit: pubca->private = NULL; return ret; } diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 2cf30576bf39..882ca417f328 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -131,6 +131,11 @@ struct dvb_frontend_private { int quality; unsigned int check_wrapped; enum dvbfe_search algo_status; + +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + struct media_pipeline pipe; + struct media_entity *pipe_start_entity; +#endif }; static void dvb_frontend_wakeup(struct dvb_frontend *fe); @@ -590,12 +595,106 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe) wake_up_interruptible(&fepriv->wait_queue); } +/** + * dvb_enable_media_tuner() - tries to enable the DVB tuner + * + * @fe: struct dvb_frontend pointer + * + * This function ensures that just one media tuner is enabled for a given + * frontend. It has two different behaviors: + * - For trivial devices with just one tuner: + * it just enables the existing tuner->fe link + * - For devices with more than one tuner: + * It is up to the driver to implement the logic that will enable one tuner + * and disable the other ones. However, if more than one tuner is enabled for + * the same frontend, it will print an error message and return -EINVAL. + * + * At return, it will return the error code returned by media_entity_setup_link, + * or 0 if everything is OK, if no tuner is linked to the frontend or if the + * mdev is NULL. + */ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB +static int dvb_enable_media_tuner(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_adapter *adapter = fe->dvb; + struct media_device *mdev = adapter->mdev; + struct media_entity *entity, *source; + struct media_link *link, *found_link = NULL; + int i, ret, n_links = 0, active_links = 0; + + fepriv->pipe_start_entity = NULL; + + if (!mdev) + return 0; + + entity = fepriv->dvbdev->entity; + fepriv->pipe_start_entity = entity; + + for (i = 0; i < entity->num_links; i++) { + link = &entity->links[i]; + if (link->sink->entity == entity) { + found_link = link; + n_links++; + if (link->flags & MEDIA_LNK_FL_ENABLED) + active_links++; + } + } + + if (!n_links || active_links == 1 || !found_link) + return 0; + + /* + * If a frontend has more than one tuner linked, it is up to the driver + * to select with one will be the active one, as the frontend core can't + * guess. If the driver doesn't do that, it is a bug. + */ + if (n_links > 1 && active_links != 1) { + dev_err(fe->dvb->device, + "WARNING: there are %d active links among %d tuners. This is a driver's bug!\n", + active_links, n_links); + return -EINVAL; + } + + source = found_link->source->entity; + fepriv->pipe_start_entity = source; + for (i = 0; i < source->num_links; i++) { + struct media_entity *sink; + int flags = 0; + + link = &source->links[i]; + sink = link->sink->entity; + + if (sink == entity) + flags = MEDIA_LNK_FL_ENABLED; + + ret = media_entity_setup_link(link, flags); + if (ret) { + dev_err(fe->dvb->device, + "Couldn't change link %s->%s to %s. Error %d\n", + source->name, sink->name, + flags ? "enabled" : "disabled", + ret); + return ret; + } else + dev_dbg(fe->dvb->device, + "link %s->%s was %s\n", + source->name, sink->name, + flags ? "ENABLED" : "disabled"); + } + return 0; +} +#endif + static int dvb_frontend_thread(void *data) { struct dvb_frontend *fe = data; struct dvb_frontend_private *fepriv = fe->frontend_priv; fe_status_t s; enum dvbfe_algo algo; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + int ret; +#endif bool re_tune = false; bool semheld = false; @@ -609,6 +708,20 @@ static int dvb_frontend_thread(void *data) fepriv->wakeup = 0; fepriv->reinitialise = 0; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + ret = dvb_enable_media_tuner(fe); + if (ret) { + /* FIXME: return an error if it fails */ + dev_info(fe->dvb->device, + "proceeding with FE task\n"); + } else if (fepriv->pipe_start_entity) { + ret = media_entity_pipeline_start(fepriv->pipe_start_entity, + &fepriv->pipe); + if (ret) + return ret; + } +#endif + dvb_frontend_init(fe); set_freezable(); @@ -718,6 +831,12 @@ restart: } } +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + if (fepriv->pipe_start_entity) + media_entity_pipeline_stop(fepriv->pipe_start_entity); + fepriv->pipe_start_entity = NULL; +#endif + if (dvb_powerdown_on_sleep) { if (fe->ops.set_voltage) fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); @@ -2612,11 +2731,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb, struct dvb_frontend* fe) { struct dvb_frontend_private *fepriv; - static const struct dvb_device dvbdev_template = { + const struct dvb_device dvbdev_template = { .users = ~0, .writers = 1, .readers = (~0)-1, .fops = &dvb_frontend_fops, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = fe->ops.info.name, +#endif .kernel_ioctl = dvb_frontend_ioctl }; diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 686d3277dad1..1508d918205d 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -1462,14 +1462,16 @@ static const struct file_operations dvb_net_fops = { .llseek = noop_llseek, }; -static struct dvb_device dvbdev_net = { +static const struct dvb_device dvbdev_net = { .priv = NULL, .users = 1, .writers = 1, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = "dvb-net", +#endif .fops = &dvb_net_fops, }; - void dvb_net_release (struct dvb_net *dvbnet) { int i; diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 983db75de350..13bb57f0457f 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -180,6 +180,93 @@ skip: return -ENFILE; } +static void dvb_register_media_device(struct dvb_device *dvbdev, + int type, int minor) +{ +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + int ret = 0, npads; + + if (!dvbdev->adapter->mdev) + return; + + dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL); + if (!dvbdev->entity) + return; + + dvbdev->entity->info.dev.major = DVB_MAJOR; + dvbdev->entity->info.dev.minor = minor; + dvbdev->entity->name = dvbdev->name; + + switch (type) { + case DVB_DEVICE_CA: + case DVB_DEVICE_DEMUX: + case DVB_DEVICE_FRONTEND: + npads = 2; + break; + case DVB_DEVICE_NET: + npads = 0; + break; + default: + npads = 1; + } + + if (npads) { + dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), + GFP_KERNEL); + if (!dvbdev->pads) { + kfree(dvbdev->entity); + return; + } + } + + switch (type) { + case DVB_DEVICE_FRONTEND: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_FE; + dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; + dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; + break; + case DVB_DEVICE_DEMUX: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DEMUX; + dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; + dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; + break; + case DVB_DEVICE_DVR: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DVR; + dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; + break; + case DVB_DEVICE_CA: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_CA; + dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; + dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; + break; + case DVB_DEVICE_NET: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_NET; + break; + default: + kfree(dvbdev->entity); + dvbdev->entity = NULL; + return; + } + + if (npads) + ret = media_entity_init(dvbdev->entity, npads, dvbdev->pads, 0); + if (!ret) + ret = media_device_register_entity(dvbdev->adapter->mdev, + dvbdev->entity); + if (ret < 0) { + printk(KERN_ERR + "%s: media_device_register_entity failed for %s\n", + __func__, dvbdev->entity->name); + kfree(dvbdev->pads); + kfree(dvbdev->entity); + dvbdev->entity = NULL; + return; + } + + printk(KERN_DEBUG "%s: media device '%s' registered.\n", + __func__, dvbdev->entity->name); +#endif +} int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, const struct dvb_device *template, void *priv, int type) @@ -258,10 +345,11 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); return PTR_ERR(clsdev); } - dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, minor, minor); + dvb_register_media_device(dvbdev, type, minor); + return 0; } EXPORT_SYMBOL(dvb_register_device); @@ -278,12 +366,66 @@ void dvb_unregister_device(struct dvb_device *dvbdev) device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + if (dvbdev->entity) { + media_device_unregister_entity(dvbdev->entity); + kfree(dvbdev->entity); + kfree(dvbdev->pads); + } +#endif + list_del (&dvbdev->list_head); kfree (dvbdev->fops); kfree (dvbdev); } EXPORT_SYMBOL(dvb_unregister_device); + +#ifdef CONFIG_MEDIA_CONTROLLER_DVB +void dvb_create_media_graph(struct dvb_adapter *adap) +{ + struct media_device *mdev = adap->mdev; + struct media_entity *entity, *tuner = NULL, *fe = NULL; + struct media_entity *demux = NULL, *dvr = NULL, *ca = NULL; + + if (!mdev) + return; + + media_device_for_each_entity(entity, mdev) { + switch (entity->type) { + case MEDIA_ENT_T_V4L2_SUBDEV_TUNER: + tuner = entity; + break; + case MEDIA_ENT_T_DEVNODE_DVB_FE: + fe = entity; + break; + case MEDIA_ENT_T_DEVNODE_DVB_DEMUX: + demux = entity; + break; + case MEDIA_ENT_T_DEVNODE_DVB_DVR: + dvr = entity; + break; + case MEDIA_ENT_T_DEVNODE_DVB_CA: + ca = entity; + break; + } + } + + if (tuner && fe) + media_entity_create_link(tuner, 0, fe, 0, 0); + + if (fe && demux) + media_entity_create_link(fe, 1, demux, 0, MEDIA_LNK_FL_ENABLED); + + if (demux && dvr) + media_entity_create_link(demux, 1, dvr, 0, MEDIA_LNK_FL_ENABLED); + + if (demux && ca) + media_entity_create_link(demux, 1, ca, 0, MEDIA_LNK_FL_ENABLED); +} +EXPORT_SYMBOL_GPL(dvb_create_media_graph); +#endif + static int dvbdev_check_free_adapter_num(int num) { struct list_head *entry; diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h index f96b28e7fc95..12629b8ecb0c 100644 --- a/drivers/media/dvb-core/dvbdev.h +++ b/drivers/media/dvb-core/dvbdev.h @@ -27,6 +27,7 @@ #include <linux/poll.h> #include <linux/fs.h> #include <linux/list.h> +#include <media/media-device.h> #define DVB_MAJOR 212 @@ -71,6 +72,10 @@ struct dvb_adapter { int mfe_shared; /* indicates mutually exclusive frontends */ struct dvb_device *mfe_dvbdev; /* frontend device in use */ struct mutex mfe_lock; /* access lock for thread creation */ + +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + struct media_device *mdev; +#endif }; @@ -92,6 +97,15 @@ struct dvb_device { /* don't really need those !? -- FIXME: use video_usercopy */ int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg); + /* Needed for media controller register/unregister */ +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + const char *name; + + /* Allocated and filled inside dvbdev.c */ + struct media_entity *entity; + struct media_pad *pads; +#endif + void *priv; }; @@ -109,6 +123,19 @@ extern int dvb_register_device (struct dvb_adapter *adap, extern void dvb_unregister_device (struct dvb_device *dvbdev); +#ifdef CONFIG_MEDIA_CONTROLLER_DVB +void dvb_create_media_graph(struct dvb_adapter *adap); +static inline void dvb_register_media_controller(struct dvb_adapter *adap, + struct media_device *mdev) +{ + adap->mdev = mdev; +} + +#else +static inline void dvb_create_media_graph(struct dvb_adapter *adap) {} +#define dvb_register_media_controller(a, b) {} +#endif + extern int dvb_generic_open (struct inode *inode, struct file *file); extern int dvb_generic_release (struct inode *inode, struct file *file); extern long dvb_generic_ioctl (struct file *file, |