summaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb-core/dvb_frontend.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb-core/dvb_frontend.c')
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c218
1 files changed, 75 insertions, 143 deletions
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 40080645341e..c0142614c408 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -134,15 +134,17 @@ struct dvb_frontend_private {
#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);
static int dtv_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p_out);
-static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p);
+static int
+dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+ const struct dtv_frontend_properties *c,
+ struct dvb_frontend_parameters *p);
static bool has_get_frontend(struct dvb_frontend *fe)
{
@@ -202,6 +204,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe,
enum fe_status status)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_fe_events *events = &fepriv->events;
struct dvb_frontend_event *e;
int wp;
@@ -209,7 +212,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe,
dev_dbg(fe->dvb->device, "%s:\n", __func__);
if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
- dtv_get_frontend(fe, &fepriv->parameters_out);
+ dtv_get_frontend(fe, c, &fepriv->parameters_out);
mutex_lock(&events->mtx);
@@ -596,104 +599,13 @@ 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 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;
-
- list_for_each_entry(link, &entity->links, list) {
- 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;
- list_for_each_entry(link, &source->links, list) {
- struct media_entity *sink;
- int flags = 0;
-
- 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 dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
enum fe_status s;
enum dvbfe_algo algo;
-#ifdef CONFIG_MEDIA_CONTROLLER_DVB
- int ret;
-#endif
-
bool re_tune = false;
bool semheld = false;
@@ -706,20 +618,6 @@ 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();
@@ -807,7 +705,7 @@ restart:
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
fepriv->delay = HZ / 2;
}
- dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
+ dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s); /* update event list */
@@ -829,12 +727,6 @@ 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);
@@ -899,10 +791,10 @@ void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec)
s32 delta;
*waketime = ktime_add_us(*waketime, add_usec);
- delta = ktime_us_delta(ktime_get_real(), *waketime);
+ delta = ktime_us_delta(ktime_get_boottime(), *waketime);
if (delta > 2500) {
msleep((delta - 1500) / 1000);
- delta = ktime_us_delta(ktime_get_real(), *waketime);
+ delta = ktime_us_delta(ktime_get_boottime(), *waketime);
}
if (delta > 0)
udelay(delta);
@@ -1162,18 +1054,24 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
};
-static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp)
+static void dtv_property_dump(struct dvb_frontend *fe,
+ bool is_set,
+ struct dtv_property *tvp)
{
int i;
if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
- dev_warn(fe->dvb->device, "%s: tvp.cmd = 0x%08x undefined\n",
- __func__, tvp->cmd);
+ dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n",
+ __func__,
+ is_set ? "SET" : "GET",
+ tvp->cmd);
return;
}
- dev_dbg(fe->dvb->device, "%s: tvp.cmd = 0x%08x (%s)\n", __func__,
- tvp->cmd, dtv_cmds[tvp->cmd].name);
+ dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__,
+ is_set ? "SET" : "GET",
+ tvp->cmd,
+ dtv_cmds[tvp->cmd].name);
if (dtv_cmds[tvp->cmd].buffer) {
dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n",
@@ -1268,11 +1166,11 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe,
/* Ensure the cached values are set correctly in the frontend
* legacy tuning structures, for the advanced tuning API.
*/
-static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int
+dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+ const struct dtv_frontend_properties *c,
+ struct dvb_frontend_parameters *p)
{
- const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
p->frequency = c->frequency;
p->inversion = c->inversion;
@@ -1344,16 +1242,17 @@ static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
* If p_out is not null, it will update the DVBv3 params pointed by it.
*/
static int dtv_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *c,
struct dvb_frontend_parameters *p_out)
{
int r;
if (fe->ops.get_frontend) {
- r = fe->ops.get_frontend(fe);
+ r = fe->ops.get_frontend(fe, c);
if (unlikely(r < 0))
return r;
if (p_out)
- dtv_property_legacy_params_sync(fe, p_out);
+ dtv_property_legacy_params_sync(fe, c, p_out);
return 0;
}
@@ -1589,7 +1488,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
return r;
}
- dtv_property_dump(fe, tvp);
+ dtv_property_dump(fe, false, tvp);
return 0;
}
@@ -1830,6 +1729,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
return r;
}
+ dtv_property_dump(fe, true, tvp);
+
switch(tvp->cmd) {
case DTV_CLEAR:
/*
@@ -2073,6 +1974,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
} else if (cmd == FE_GET_PROPERTY) {
+ struct dtv_frontend_properties getp = fe->dtv_property_cache;
+
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
@@ -2094,17 +1997,18 @@ static int dvb_frontend_ioctl_properties(struct file *file,
}
/*
- * Fills the cache out struct with the cache contents, plus
- * the data retrieved from get_frontend, if the frontend
- * is not idle. Otherwise, returns the cached content
+ * Let's use our own copy of property cache, in order to
+ * avoid mangling with DTV zigzag logic, as drivers might
+ * return crap, if they don't check if the data is available
+ * before updating the properties cache.
*/
if (fepriv->state != FESTATE_IDLE) {
- err = dtv_get_frontend(fe, NULL);
+ err = dtv_get_frontend(fe, &getp, NULL);
if (err < 0)
goto out;
}
for (i = 0; i < tvps->num; i++) {
- err = dtv_property_process_get(fe, c, tvp + i, file);
+ err = dtv_property_process_get(fe, &getp, tvp + i, file);
if (err < 0)
goto out;
(tvp + i)->result = err;
@@ -2139,7 +2043,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
* the user. FE_SET_FRONTEND triggers an initial frontend event
* with status = 0, which copies output parameters to userspace.
*/
- dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
+ dtv_property_legacy_params_sync(fe, c, &fepriv->parameters_out);
/*
* Be sure that the bandwidth will be filled for all
@@ -2451,7 +2355,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
u8 last = 1;
if (dvb_frontend_debug)
printk("%s switch command: 0x%04lx\n", __func__, swcmd);
- nexttime = ktime_get_real();
+ nexttime = ktime_get_boottime();
if (dvb_frontend_debug)
tv[0] = nexttime;
/* before sending a command, initialize by sending
@@ -2462,7 +2366,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
for (i = 0; i < 9; i++) {
if (dvb_frontend_debug)
- tv[i+1] = ktime_get_real();
+ tv[i+1] = ktime_get_boottime();
if ((swcmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */
fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
@@ -2509,10 +2413,18 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
err = dvb_frontend_get_event (fe, parg, file->f_flags);
break;
- case FE_GET_FRONTEND:
- err = dtv_get_frontend(fe, parg);
- break;
+ case FE_GET_FRONTEND: {
+ struct dtv_frontend_properties getp = fe->dtv_property_cache;
+ /*
+ * Let's use our own copy of property cache, in order to
+ * avoid mangling with DTV zigzag logic, as drivers might
+ * return crap, if they don't check if the data is available
+ * before updating the properties cache.
+ */
+ err = dtv_get_frontend(fe, &getp, parg);
+ break;
+ }
case FE_SET_FRONTEND_TUNE_MODE:
fepriv->tune_mode_flags = (unsigned long) parg;
err = 0;
@@ -2612,9 +2524,20 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
fepriv->tone = -1;
fepriv->voltage = -1;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (fe->dvb->mdev && fe->dvb->mdev->enable_source) {
+ ret = fe->dvb->mdev->enable_source(dvbdev->entity,
+ &fepriv->pipe);
+ if (ret) {
+ dev_err(fe->dvb->device,
+ "Tuner is busy. Error %d\n", ret);
+ goto err2;
+ }
+ }
+#endif
ret = dvb_frontend_start (fe);
if (ret)
- goto err2;
+ goto err3;
/* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0;
@@ -2624,7 +2547,12 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
mutex_unlock (&adapter->mfe_lock);
return ret;
+err3:
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (fe->dvb->mdev && fe->dvb->mdev->disable_source)
+ fe->dvb->mdev->disable_source(dvbdev->entity);
err2:
+#endif
dvb_generic_release(inode, file);
err1:
if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
@@ -2653,6 +2581,10 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if (dvbdev->users == -1) {
wake_up(&fepriv->wait_queue);
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ if (fe->dvb->mdev && fe->dvb->mdev->disable_source)
+ fe->dvb->mdev->disable_source(dvbdev->entity);
+#endif
if (fe->exit != DVB_FE_NO_EXIT)
wake_up(&dvbdev->wait_queue);
if (fe->ops.ts_bus_ctrl)
OpenPOWER on IntegriCloud