summaryrefslogtreecommitdiff
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.c415
1 files changed, 237 insertions, 178 deletions
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 06ea30a689d7..a05aa271a1ba 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -23,6 +23,7 @@
#include <linux/poll.h>
#include <linux/semaphore.h>
#include <linux/module.h>
+#include <linux/nospec.h>
#include <linux/list.h>
#include <linux/freezer.h>
#include <linux/jiffies.h>
@@ -135,7 +136,7 @@ static void __dvb_frontend_free(struct dvb_frontend *fe)
struct dvb_frontend_private *fepriv = fe->frontend_priv;
if (fepriv)
- dvb_free_device(fepriv->dvbdev);
+ dvb_device_put(fepriv->dvbdev);
dvb_frontend_invoke_release(fe, fe->ops.release);
@@ -292,14 +293,22 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
}
if (events->eventw == events->eventr) {
- int ret;
+ struct wait_queue_entry wait;
+ int ret = 0;
if (flags & O_NONBLOCK)
return -EWOULDBLOCK;
- ret = wait_event_interruptible(events->wait_queue,
- dvb_frontend_test_event(fepriv, events));
-
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&events->wait_queue, &wait);
+ while (!dvb_frontend_test_event(fepriv, events)) {
+ wait_woken(&wait, TASK_INTERRUPTIBLE, 0);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ remove_wait_queue(&events->wait_queue, &wait);
if (ret < 0)
return ret;
}
@@ -434,8 +443,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
default:
fepriv->auto_step++;
- fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
- break;
+ fepriv->auto_sub_step = 0;
+ continue;
}
if (!ready) fepriv->auto_sub_step++;
@@ -481,6 +490,10 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
+ if (fepriv->max_drift)
+ dev_warn_once(fe->dvb->device,
+ "Frontend requested software zigzag, but didn't set the frequency step size\n");
+
/* if we've got no parameters, just keep idling */
if (fepriv->state & FESTATE_IDLE) {
fepriv->delay = 3 * HZ;
@@ -666,12 +679,10 @@ static int dvb_frontend_thread(void *data)
set_freezable();
while (1) {
up(&fepriv->sem); /* is locked when we enter the thread... */
-restart:
- wait_event_interruptible_timeout(fepriv->wait_queue,
- dvb_frontend_should_wakeup(fe) ||
- kthread_should_stop() ||
- freezing(current),
- fepriv->delay);
+ wait_event_freezable_timeout(fepriv->wait_queue,
+ dvb_frontend_should_wakeup(fe) ||
+ kthread_should_stop(),
+ fepriv->delay);
if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */
@@ -681,9 +692,6 @@ restart:
break;
}
- if (try_to_freeze())
- goto restart;
-
if (down_interruptible(&fepriv->sem))
break;
@@ -913,6 +921,7 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
/* If the standard is for satellite, convert frequencies to kHz */
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -938,6 +947,7 @@ static u32 dvb_frontend_get_stepsize(struct dvb_frontend *fe)
u32 step = max(fe_step, tuner_step);
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -969,6 +979,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
/* range check: symbol rate */
switch (c->delivery_system) {
+ case SYS_DSS:
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -984,6 +995,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
fe->ops.info.symbol_rate_max);
return -EINVAL;
}
+ break;
default:
break;
}
@@ -1034,6 +1046,10 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
c->scrambling_sequence_index = 0;/* default sequence */
switch (c->delivery_system) {
+ case SYS_DSS:
+ c->modulation = QPSK;
+ c->rolloff = ROLLOFF_20;
+ break;
case SYS_DVBS:
case SYS_DVBS2:
case SYS_TURBO:
@@ -1058,107 +1074,97 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
return 0;
}
-#define _DTV_CMD(n, s, b) \
-[n] = { \
- .name = #n, \
- .cmd = n, \
- .set = s,\
- .buffer = b \
-}
-
-struct dtv_cmds_h {
- char *name; /* A display name for debugging purposes */
-
- __u32 cmd; /* A unique ID */
-
- /* Flags */
- __u32 set:1; /* Either a set or get property */
- __u32 buffer:1; /* Does this property use the buffer? */
- __u32 reserved:30; /* Align */
-};
+#define _DTV_CMD(n) \
+ [n] = #n
-static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
- _DTV_CMD(DTV_TUNE, 1, 0),
- _DTV_CMD(DTV_CLEAR, 1, 0),
+static char *dtv_cmds[DTV_MAX_COMMAND + 1] = {
+ _DTV_CMD(DTV_TUNE),
+ _DTV_CMD(DTV_CLEAR),
/* Set */
- _DTV_CMD(DTV_FREQUENCY, 1, 0),
- _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
- _DTV_CMD(DTV_MODULATION, 1, 0),
- _DTV_CMD(DTV_INVERSION, 1, 0),
- _DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
- _DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
- _DTV_CMD(DTV_INNER_FEC, 1, 0),
- _DTV_CMD(DTV_VOLTAGE, 1, 0),
- _DTV_CMD(DTV_TONE, 1, 0),
- _DTV_CMD(DTV_PILOT, 1, 0),
- _DTV_CMD(DTV_ROLLOFF, 1, 0),
- _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
- _DTV_CMD(DTV_HIERARCHY, 1, 0),
- _DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
- _DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
- _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
- _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
- _DTV_CMD(DTV_INTERLEAVING, 1, 0),
-
- _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
- _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
- _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
- _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
- _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
- _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
-
- _DTV_CMD(DTV_STREAM_ID, 1, 0),
- _DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY, 1, 0),
- _DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX, 1, 0),
- _DTV_CMD(DTV_LNA, 1, 0),
+ _DTV_CMD(DTV_FREQUENCY),
+ _DTV_CMD(DTV_BANDWIDTH_HZ),
+ _DTV_CMD(DTV_MODULATION),
+ _DTV_CMD(DTV_INVERSION),
+ _DTV_CMD(DTV_DISEQC_MASTER),
+ _DTV_CMD(DTV_SYMBOL_RATE),
+ _DTV_CMD(DTV_INNER_FEC),
+ _DTV_CMD(DTV_VOLTAGE),
+ _DTV_CMD(DTV_TONE),
+ _DTV_CMD(DTV_PILOT),
+ _DTV_CMD(DTV_ROLLOFF),
+ _DTV_CMD(DTV_DELIVERY_SYSTEM),
+ _DTV_CMD(DTV_HIERARCHY),
+ _DTV_CMD(DTV_CODE_RATE_HP),
+ _DTV_CMD(DTV_CODE_RATE_LP),
+ _DTV_CMD(DTV_GUARD_INTERVAL),
+ _DTV_CMD(DTV_TRANSMISSION_MODE),
+ _DTV_CMD(DTV_INTERLEAVING),
+
+ _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION),
+ _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING),
+ _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID),
+ _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX),
+ _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT),
+ _DTV_CMD(DTV_ISDBT_LAYER_ENABLED),
+ _DTV_CMD(DTV_ISDBT_LAYERA_FEC),
+ _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION),
+ _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT),
+ _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING),
+ _DTV_CMD(DTV_ISDBT_LAYERB_FEC),
+ _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION),
+ _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT),
+ _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING),
+ _DTV_CMD(DTV_ISDBT_LAYERC_FEC),
+ _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION),
+ _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT),
+ _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING),
+
+ _DTV_CMD(DTV_STREAM_ID),
+ _DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY),
+ _DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX),
+ _DTV_CMD(DTV_LNA),
/* Get */
- _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
- _DTV_CMD(DTV_API_VERSION, 0, 0),
-
- _DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
-
- _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
- _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
-
- _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
- _DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
- _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
- _DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
- _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
- _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
+ _DTV_CMD(DTV_DISEQC_SLAVE_REPLY),
+ _DTV_CMD(DTV_API_VERSION),
+
+ _DTV_CMD(DTV_ENUM_DELSYS),
+
+ _DTV_CMD(DTV_ATSCMH_PARADE_ID),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE),
+
+ _DTV_CMD(DTV_ATSCMH_FIC_VER),
+ _DTV_CMD(DTV_ATSCMH_NOG),
+ _DTV_CMD(DTV_ATSCMH_TNOG),
+ _DTV_CMD(DTV_ATSCMH_SGN),
+ _DTV_CMD(DTV_ATSCMH_PRC),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE),
+ _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI),
+ _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC),
+ _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D),
/* Statistics API */
- _DTV_CMD(DTV_STAT_SIGNAL_STRENGTH, 0, 0),
- _DTV_CMD(DTV_STAT_CNR, 0, 0),
- _DTV_CMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_PRE_TOTAL_BIT_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_ERROR_BLOCK_COUNT, 0, 0),
- _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
+ _DTV_CMD(DTV_STAT_SIGNAL_STRENGTH),
+ _DTV_CMD(DTV_STAT_CNR),
+ _DTV_CMD(DTV_STAT_PRE_ERROR_BIT_COUNT),
+ _DTV_CMD(DTV_STAT_PRE_TOTAL_BIT_COUNT),
+ _DTV_CMD(DTV_STAT_POST_ERROR_BIT_COUNT),
+ _DTV_CMD(DTV_STAT_POST_TOTAL_BIT_COUNT),
+ _DTV_CMD(DTV_STAT_ERROR_BLOCK_COUNT),
+ _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT),
};
+static char *dtv_cmd_name(u32 cmd)
+{
+ cmd = array_index_nospec(cmd, DTV_MAX_COMMAND);
+ return dtv_cmds[cmd];
+}
+
/* Synchronise the legacy tuning parameters into the cache, so that demodulator
* drivers can use a single set_frontend tuning function, regardless of whether
* it's being used for the legacy or new API, reducing code and complexity.
@@ -1341,6 +1347,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
struct file *file)
{
int ncaps;
+ unsigned int len = 1;
switch (tvp->cmd) {
case DTV_ENUM_DELSYS:
@@ -1350,6 +1357,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
ncaps++;
}
tvp->u.buffer.len = ncaps;
+ len = ncaps;
break;
case DTV_FREQUENCY:
tvp->u.data = c->frequency;
@@ -1527,27 +1535,51 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
/* Fill quality measures */
case DTV_STAT_SIGNAL_STRENGTH:
tvp->u.st = c->strength;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_CNR:
tvp->u.st = c->cnr;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_PRE_ERROR_BIT_COUNT:
tvp->u.st = c->pre_bit_error;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_PRE_TOTAL_BIT_COUNT:
tvp->u.st = c->pre_bit_count;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_POST_ERROR_BIT_COUNT:
tvp->u.st = c->post_bit_error;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_POST_TOTAL_BIT_COUNT:
tvp->u.st = c->post_bit_count;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_ERROR_BLOCK_COUNT:
tvp->u.st = c->block_error;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
case DTV_STAT_TOTAL_BLOCK_COUNT:
tvp->u.st = c->block_count;
+ if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32))
+ tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32);
+ len = tvp->u.buffer.len;
break;
default:
dev_dbg(fe->dvb->device,
@@ -1556,18 +1588,13 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
return -EINVAL;
}
- if (!dtv_cmds[tvp->cmd].buffer)
- dev_dbg(fe->dvb->device,
- "%s: GET cmd 0x%08x (%s) = 0x%08x\n",
- __func__, tvp->cmd, dtv_cmds[tvp->cmd].name,
- tvp->u.data);
- else
- dev_dbg(fe->dvb->device,
- "%s: GET cmd 0x%08x (%s) len %d: %*ph\n",
- __func__,
- tvp->cmd, dtv_cmds[tvp->cmd].name,
- tvp->u.buffer.len,
- tvp->u.buffer.len, tvp->u.buffer.data);
+ if (len < 1)
+ len = 1;
+
+ dev_dbg(fe->dvb->device,
+ "%s: GET cmd 0x%08x (%s) len %d: %*ph\n",
+ __func__, tvp->cmd, dtv_cmd_name(tvp->cmd),
+ tvp->u.buffer.len, tvp->u.buffer.len, tvp->u.buffer.data);
return 0;
}
@@ -1790,6 +1817,54 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
return emulate_delivery_system(fe, delsys);
}
+static void prepare_tuning_algo_parameters(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dvb_frontend_tune_settings fetunesettings = { 0 };
+
+ /* get frontend-specific tuning settings */
+ if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
+ fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
+ fepriv->max_drift = fetunesettings.max_drift;
+ fepriv->step_size = fetunesettings.step_size;
+ } else {
+ /* default values */
+ switch (c->delivery_system) {
+ case SYS_DSS:
+ case SYS_DVBS:
+ case SYS_DVBS2:
+ case SYS_ISDBS:
+ case SYS_TURBO:
+ case SYS_DVBC_ANNEX_A:
+ case SYS_DVBC_ANNEX_C:
+ fepriv->min_delay = HZ / 20;
+ fepriv->step_size = c->symbol_rate / 16000;
+ fepriv->max_drift = c->symbol_rate / 2000;
+ break;
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ case SYS_ISDBT:
+ case SYS_DTMB:
+ fepriv->min_delay = HZ / 20;
+ fepriv->step_size = dvb_frontend_get_stepsize(fe) * 2;
+ fepriv->max_drift = fepriv->step_size + 1;
+ break;
+ default:
+ /*
+ * FIXME: This sounds wrong! if freqency_stepsize is
+ * defined by the frontend, why not use it???
+ */
+ fepriv->min_delay = HZ / 20;
+ fepriv->step_size = 0; /* no zigzag */
+ fepriv->max_drift = 0;
+ break;
+ }
+ }
+ if (dvb_override_tune_delay > 0)
+ fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
+}
+
/**
* dtv_property_process_set - Sets a single DTV property
* @fe: Pointer to &struct dvb_frontend
@@ -1818,7 +1893,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
else
dev_dbg(fe->dvb->device,
"%s: SET cmd 0x%08x (%s) to 0x%08x\n",
- __func__, cmd, dtv_cmds[cmd].name, data);
+ __func__, cmd, dtv_cmd_name(cmd), data);
switch (cmd) {
case DTV_CLEAR:
/*
@@ -2088,7 +2163,8 @@ static int dvb_frontend_handle_compat_ioctl(struct file *file, unsigned int cmd,
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = memdup_user(compat_ptr(tvps->props), tvps->num * sizeof(*tvp));
+ tvp = memdup_array_user(compat_ptr(tvps->props),
+ tvps->num, sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
@@ -2119,7 +2195,8 @@ static int dvb_frontend_handle_compat_ioctl(struct file *file, unsigned int cmd,
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = memdup_user(compat_ptr(tvps->props), tvps->num * sizeof(*tvp));
+ tvp = memdup_array_user(compat_ptr(tvps->props),
+ tvps->num, sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
@@ -2182,7 +2259,6 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct dvb_frontend_tune_settings fetunesettings;
u32 rolloff = 0;
if (dvb_frontend_check_parameters(fe) < 0)
@@ -2225,6 +2301,9 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
case SYS_DVBC_ANNEX_C:
rolloff = 113;
break;
+ case SYS_DSS:
+ rolloff = 120;
+ break;
case SYS_DVBS:
case SYS_TURBO:
case SYS_ISDBS:
@@ -2260,46 +2339,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE)
c->code_rate_LP = FEC_AUTO;
- /* get frontend-specific tuning settings */
- memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
- if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
- fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
- fepriv->max_drift = fetunesettings.max_drift;
- fepriv->step_size = fetunesettings.step_size;
- } else {
- /* default values */
- switch (c->delivery_system) {
- case SYS_DVBS:
- case SYS_DVBS2:
- case SYS_ISDBS:
- case SYS_TURBO:
- case SYS_DVBC_ANNEX_A:
- case SYS_DVBC_ANNEX_C:
- fepriv->min_delay = HZ / 20;
- fepriv->step_size = c->symbol_rate / 16000;
- fepriv->max_drift = c->symbol_rate / 2000;
- break;
- case SYS_DVBT:
- case SYS_DVBT2:
- case SYS_ISDBT:
- case SYS_DTMB:
- fepriv->min_delay = HZ / 20;
- fepriv->step_size = dvb_frontend_get_stepsize(fe) * 2;
- fepriv->max_drift = (dvb_frontend_get_stepsize(fe) * 2) + 1;
- break;
- default:
- /*
- * FIXME: This sounds wrong! if freqency_stepsize is
- * defined by the frontend, why not use it???
- */
- fepriv->min_delay = HZ / 20;
- fepriv->step_size = 0; /* no zigzag */
- fepriv->max_drift = 0;
- break;
- }
- }
- if (dvb_override_tune_delay > 0)
- fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
+ prepare_tuning_algo_parameters(fe);
fepriv->state = FESTATE_RETUNE;
@@ -2336,7 +2376,8 @@ static int dvb_get_property(struct dvb_frontend *fe, struct file *file,
if (!tvps->num || tvps->num > DTV_IOCTL_MAX_MSGS)
return -EINVAL;
- tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
+ tvp = memdup_array_user((void __user *)tvps->props,
+ tvps->num, sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
@@ -2414,7 +2455,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
return -EINVAL;
- tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp));
+ tvp = memdup_array_user((void __user *)tvps->props,
+ tvps->num, sizeof(*tvp));
if (IS_ERR(tvp))
return PTR_ERR(tvp);
@@ -2530,8 +2572,7 @@ static int dvb_frontend_handle_ioctl(struct file *file,
case FE_DISEQC_SEND_BURST:
if (fe->ops.diseqc_send_burst) {
- err = fe->ops.diseqc_send_burst(fe,
- (enum fe_sec_mini_cmd)parg);
+ err = fe->ops.diseqc_send_burst(fe, (long)parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2539,9 +2580,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
case FE_SET_TONE:
if (fe->ops.set_tone) {
- err = fe->ops.set_tone(fe,
- (enum fe_sec_tone_mode)parg);
- fepriv->tone = (enum fe_sec_tone_mode)parg;
+ fepriv->tone = (long)parg;
+ err = fe->ops.set_tone(fe, fepriv->tone);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2549,9 +2589,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
case FE_SET_VOLTAGE:
if (fe->ops.set_voltage) {
- err = fe->ops.set_voltage(fe,
- (enum fe_sec_voltage)parg);
- fepriv->voltage = (enum fe_sec_voltage)parg;
+ fepriv->voltage = (long)parg;
+ err = fe->ops.set_voltage(fe, fepriv->voltage);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
@@ -2733,7 +2772,17 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
if (fe->exit == DVB_FE_DEVICE_REMOVED)
return -ENODEV;
- if (adapter->mfe_shared) {
+ if (adapter->mfe_shared == 2) {
+ mutex_lock(&adapter->mfe_lock);
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if (adapter->mfe_dvbdev &&
+ !adapter->mfe_dvbdev->writers) {
+ mutex_unlock(&adapter->mfe_lock);
+ return -EBUSY;
+ }
+ adapter->mfe_dvbdev = dvbdev;
+ }
+ } else if (adapter->mfe_shared) {
mutex_lock(&adapter->mfe_lock);
if (!adapter->mfe_dvbdev)
@@ -2911,7 +2960,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe)
else if (fe->ops.tuner_ops.sleep)
ret = fe->ops.tuner_ops.sleep(fe);
- if (fe->ops.sleep)
+ if (fe->ops.suspend)
+ ret = fe->ops.suspend(fe);
+ else if (fe->ops.sleep)
ret = fe->ops.sleep(fe);
return ret;
@@ -2927,7 +2978,9 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
fe->id);
fe->exit = DVB_FE_DEVICE_RESUME;
- if (fe->ops.init)
+ if (fe->ops.resume)
+ ret = fe->ops.resume(fe);
+ else if (fe->ops.init)
ret = fe->ops.init(fe);
if (fe->ops.tuner_ops.resume)
@@ -2961,6 +3014,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
.name = fe->ops.info.name,
#endif
};
+ int ret;
dev_dbg(dvb->device, "%s:\n", __func__);
@@ -2994,8 +3048,13 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
"DVB: registering adapter %i frontend %i (%s)...\n",
fe->dvb->num, fe->id, fe->ops.info.name);
- dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template,
+ ret = dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND, 0);
+ if (ret) {
+ dvb_frontend_put(fe);
+ mutex_unlock(&frontend_mutex);
+ return ret;
+ }
/*
* Initialize the cache to the proper values according with the