aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c571
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h44
-rw-r--r--include/linux/dvb/frontend.h130
3 files changed, 737 insertions, 8 deletions
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 3526e3e..e68974b 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -755,6 +755,535 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
return 0;
}
+struct tv_cmds_h tv_cmds[] = {
+ [TV_SEQ_UNDEFINED] = {
+ .name = "TV_SEQ_UNDEFINED",
+ .cmd = TV_SEQ_UNDEFINED,
+ .set = 1,
+ },
+ [TV_SEQ_START] = {
+ .name = "TV_SEQ_START",
+ .cmd = TV_SEQ_START,
+ .set = 1,
+ },
+ [TV_SEQ_CONTINUE] = {
+ .name = "TV_SEQ_CONTINUE",
+ .cmd = TV_SEQ_CONTINUE,
+ .set = 1,
+ },
+ [TV_SEQ_COMPLETE] = {
+ .name = "TV_SEQ_COMPLETE",
+ .cmd = TV_SEQ_COMPLETE,
+ .set = 1,
+ },
+ [TV_SEQ_TERMINATE] = {
+ .name = "TV_SEQ_TERMINATE",
+ .cmd = TV_SEQ_TERMINATE,
+ .set = 1,
+ },
+
+ /* Set */
+ [TV_SET_FREQUENCY] = {
+ .name = "TV_SET_FREQUENCY",
+ .cmd = TV_SET_FREQUENCY,
+ .set = 1,
+ },
+ [TV_SET_BANDWIDTH] = {
+ .name = "TV_SET_BANDWIDTH",
+ .cmd = TV_SET_BANDWIDTH,
+ .set = 1,
+ },
+ [TV_SET_MODULATION] = {
+ .name = "TV_SET_MODULATION",
+ .cmd = TV_SET_MODULATION,
+ .set = 1,
+ },
+ [TV_SET_INVERSION] = {
+ .name = "TV_SET_INVERSION",
+ .cmd = TV_SET_INVERSION,
+ .set = 1,
+ },
+ [TV_SET_DISEQC_MASTER] = {
+ .name = "TV_SET_DISEQC_MASTER",
+ .cmd = TV_SET_DISEQC_MASTER,
+ .set = 1,
+ .buffer = 1,
+ },
+ [TV_SET_SYMBOLRATE] = {
+ .name = "TV_SET_SYMBOLRATE",
+ .cmd = TV_SET_SYMBOLRATE,
+ .set = 1,
+ },
+ [TV_SET_INNERFEC] = {
+ .name = "TV_SET_INNERFEC",
+ .cmd = TV_SET_INNERFEC,
+ .set = 1,
+ },
+ [TV_SET_VOLTAGE] = {
+ .name = "TV_SET_VOLTAGE",
+ .cmd = TV_SET_VOLTAGE,
+ .set = 1,
+ },
+ [TV_SET_TONE] = {
+ .name = "TV_SET_TONE",
+ .cmd = TV_SET_TONE,
+ .set = 1,
+ },
+ [TV_SET_PILOT] = {
+ .name = "TV_SET_PILOT",
+ .cmd = TV_SET_PILOT,
+ .set = 1,
+ },
+ [TV_SET_ROLLOFF] = {
+ .name = "TV_SET_ROLLOFF",
+ .cmd = TV_SET_ROLLOFF,
+ .set = 1,
+ },
+ [TV_SET_DELIVERY_SYSTEM] = {
+ .name = "TV_SET_DELIVERY_SYSTEM",
+ .cmd = TV_SET_DELIVERY_SYSTEM,
+ .set = 1,
+ },
+ [TV_SET_ISDB_SEGMENT_NUM] = {
+ .name = "TV_SET_ISDB_SEGMENT_NUM",
+ .cmd = TV_SET_ISDB_SEGMENT_NUM,
+ .set = 1,
+ },
+ [TV_SET_ISDB_SEGMENT_WIDTH] = {
+ .name = "TV_SET_ISDB_SEGMENT_WIDTH",
+ .cmd = TV_SET_ISDB_SEGMENT_WIDTH,
+ .set = 1,
+ },
+
+ /* Get */
+ [TV_GET_FREQUENCY] = {
+ .name = "TV_GET_FREQUENCY",
+ .cmd = TV_GET_FREQUENCY,
+ .set = 0,
+ },
+ [TV_GET_BANDWIDTH] = {
+ .name = "TV_GET_BANDWIDTH",
+ .cmd = TV_GET_BANDWIDTH,
+ .set = 0,
+ },
+ [TV_GET_MODULATION] = {
+ .name = "TV_GET_MODULATION",
+ .cmd = TV_GET_MODULATION,
+ .set = 0,
+ },
+ [TV_GET_INVERSION] = {
+ .name = "TV_GET_INVERSION",
+ .cmd = TV_GET_INVERSION,
+ .set = 0,
+ },
+ [TV_GET_DISEQC_SLAVE_REPLY] = {
+ .name = "TV_GET_DISEQC_SLAVE_REPLY",
+ .cmd = TV_GET_DISEQC_SLAVE_REPLY,
+ .set = 0,
+ .buffer = 1,
+ },
+ [TV_GET_SYMBOLRATE] = {
+ .name = "TV_GET_SYMBOLRATE",
+ .cmd = TV_GET_SYMBOLRATE,
+ .set = 0,
+ },
+ [TV_GET_INNERFEC] = {
+ .name = "TV_GET_INNERFEC",
+ .cmd = TV_GET_INNERFEC,
+ .set = 0,
+ },
+ [TV_GET_VOLTAGE] = {
+ .name = "TV_GET_VOLTAGE",
+ .cmd = TV_GET_VOLTAGE,
+ .set = 0,
+ },
+ [TV_GET_TONE] = {
+ .name = "TV_GET_TONE",
+ .cmd = TV_GET_TONE,
+ .set = 0,
+ },
+ [TV_GET_PILOT] = {
+ .name = "TV_GET_PILOT",
+ .cmd = TV_GET_PILOT,
+ .set = 0,
+ },
+ [TV_GET_ROLLOFF] = {
+ .name = "TV_GET_ROLLOFF",
+ .cmd = TV_GET_ROLLOFF,
+ .set = 0,
+ },
+ [TV_GET_DELIVERY_SYSTEM] = {
+ .name = "TV_GET_DELIVERY_SYSTEM",
+ .cmd = TV_GET_DELIVERY_SYSTEM,
+ .set = 0,
+ },
+ [TV_GET_ISDB_SEGMENT_NUM] = {
+ .name = "TV_GET_ISDB_SEGMENT_NUM",
+ .cmd = TV_GET_ISDB_SEGMENT_NUM,
+ .set = 0,
+ },
+ [TV_GET_ISDB_SEGMENT_WIDTH] = {
+ .name = "TV_GET_ISDB_SEGMENT_WIDTH",
+ .cmd = TV_GET_ISDB_SEGMENT_WIDTH,
+ .set = 0,
+ },
+ [TV_GET_ISDB_LAYERA_FEC] = {
+ .name = "TV_GET_ISDB_LAYERA_FEC",
+ .cmd = TV_GET_ISDB_LAYERA_FEC,
+ .set = 0,
+ },
+ [TV_GET_ISDB_LAYERA_MODULATION] = {
+ .name = "TV_GET_ISDB_LAYERA_MODULATION",
+ .cmd = TV_GET_ISDB_LAYERA_MODULATION,
+ .set = 0,
+ },
+ [TV_GET_ISDB_LAYERA_SEGMENT_WIDTH] = {
+ .name = "TV_GET_ISDB_LAYERA_SEGMENT_WIDTH",
+ .cmd = TV_GET_ISDB_LAYERA_SEGMENT_WIDTH,
+ .set = 0,
+ },
+ [TV_GET_ISDB_LAYERB_FEC] = {
+ .name = "TV_GET_ISDB_LAYERB_FEC",
+ .cmd = TV_GET_ISDB_LAYERB_FEC,
+ .set = 0,
+ },
+ [TV_GET_ISDB_LAYERB_MODULATION] = {
+ .name = "TV_GET_ISDB_LAYERB_MODULATION",
+ .cmd = TV_GET_ISDB_LAYERB_MODULATION,
+ .set = 0,
+ },
+ [TV_GET_ISDB_LAYERB_SEGMENT_WIDTH] = {
+ .name = "TV_GET_ISDB_LAYERB_SEGMENT_WIDTH",
+ .cmd = TV_GET_ISDB_LAYERB_SEGMENT_WIDTH,
+ .set = 0,
+ },
+ [TV_GET_ISDB_LAYERC_FEC] = {
+ .name = "TV_GET_ISDB_LAYERC_FEC",
+ .cmd = TV_GET_ISDB_LAYERC_FEC,
+ .set = 0,
+ },
+ [TV_GET_ISDB_LAYERC_MODULATION] = {
+ .name = "TV_GET_ISDB_LAYERC_MODULATION",
+ .cmd = TV_GET_ISDB_LAYERC_MODULATION,
+ .set = 0,
+ },
+ [TV_GET_ISDB_LAYERC_SEGMENT_WIDTH] = {
+ .name = "TV_GET_ISDB_LAYERC_SEGMENT_WIDTH",
+ .cmd = TV_GET_ISDB_LAYERC_SEGMENT_WIDTH,
+ .set = 0,
+ },
+};
+
+void tv_property_dump(tv_property_t *tvp)
+{
+ int i;
+
+ printk("%s() tvp.cmd = 0x%08x (%s)\n"
+ ,__FUNCTION__
+ ,tvp->cmd
+ ,tv_cmds[ tvp->cmd ].name);
+
+ if(tv_cmds[ tvp->cmd ].buffer) {
+
+ printk("%s() tvp.u.buffer.len = 0x%02x\n"
+ ,__FUNCTION__
+ ,tvp->u.buffer.len);
+
+ for(i = 0; i < tvp->u.buffer.len; i++)
+ printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+ ,__FUNCTION__
+ ,i
+ ,tvp->u.buffer.data[i]);
+
+ } else
+ printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
+}
+
+int is_legacy_delivery_system(fe_delivery_system_t s)
+{
+ if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
+ (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS))
+ return 1;
+
+ return 0;
+}
+
+int tv_property_cache_submit(struct dvb_frontend *fe)
+{
+
+ /* We have to do one of two things:
+ * To support legacy devices using the new API we take values from
+ * the tv_cache and generate a legacy truning structure.
+ *
+ * Or,
+ *
+ * To support advanced tuning devices with the new API we
+ * notify the new advance driver type that a tuning operation is required
+ * and let it pull values from the cache as is, we don't need to
+ * pass structures.
+ *
+ * We'll use the modulation type to assess how this is handled. as the API
+ * progresses we'll probably want to have a flag in dvb_frontend_ops
+ * to allow the frontend driver to dictate how it likes to be tuned.
+ *
+ * Because of how this is attached to the ioctl handler for legacy support,
+ * it's important to return an appropriate result code with atleast the following
+ * three meanings:
+ * < 0 = processing error
+ * 0 = lecagy ioctl handler to submit a traditional set_frontend() call.
+ * 1 = lecagy ioctl handler should NOT submit a traditional set_frontend() call.
+ */
+
+ int r;
+
+ struct tv_frontend_properties *c = &fe->tv_property_cache;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dvb_frontend_parameters p;
+
+ printk("%s()\n", __FUNCTION__);
+
+ /* For legacy delivery systems we don't need the delivery_system to be specified */
+ if(is_legacy_delivery_system(c->delivery_system)) {
+ switch(c->modulation) {
+ case QPSK:
+ printk("%s() Preparing QPSK req\n", __FUNCTION__);
+ p.frequency = c->frequency;
+ p.inversion = c->inversion;
+ p.u.qpsk.symbol_rate = c->symbol_rate;
+ p.u.qpsk.fec_inner = c->fec_inner;
+ memcpy(&fepriv->parameters, &p,
+ sizeof (struct dvb_frontend_parameters));
+
+ /* Call the traditional tuning mechanisms. */
+
+ r = 0;
+ break;
+ case QAM_16:
+ case QAM_32:
+ case QAM_64:
+ case QAM_128:
+ case QAM_256:
+ case QAM_AUTO:
+ printk("%s() Preparing QAM req\n", __FUNCTION__);
+ p.frequency = c->frequency;
+ p.inversion = c->inversion;
+ p.u.qam.symbol_rate = c->symbol_rate;
+ p.u.vsb.modulation = c->modulation;
+ printk("%s() frequency = %d\n", __FUNCTION__, p.frequency);
+ printk("%s() QAM = %d\n", __FUNCTION__, p.u.vsb.modulation);
+ memcpy(&fepriv->parameters, &p,
+ sizeof (struct dvb_frontend_parameters));
+
+ /* At this point we're fully formed for backwards
+ * compatability and we need to return this
+ * via the ioctl handler as SET_FRONTEND (arg).
+ * We've already patched the new values into the
+ * frontends tuning structures so the ioctl code just
+ * continues as if a legacy tune structure was passed
+ * from userspace.
+ */
+
+ r = 0;
+ break;
+ case VSB_8:
+ case VSB_16:
+ printk("%s() Preparing VSB req\n", __FUNCTION__);
+ p.frequency = c->frequency;
+ p.u.vsb.modulation = c->modulation;
+ memcpy(&fepriv->parameters, &p,
+ sizeof (struct dvb_frontend_parameters));
+
+ /* Call the traditional tuning mechanisms. */
+
+ r = 0;
+ break;
+ /* TODO: Add any missing modulation types */
+ default:
+ r = -1;
+ }
+ } else {
+ /* For advanced delivery systems / modulation types ...
+ * we seed the lecacy dvb_frontend_parameters structure
+ * so that the sanity checking code later in the IOCTL processing
+ * can validate our basic frequency ranges, symbolrates, modulation
+ * etc.
+ */
+ r = -1;
+
+ switch(c->modulation) {
+ case _8PSK:
+ case _16APSK:
+ case NBC_QPSK:
+ /* Just post a notification to the demod driver and let it pull
+ * the specific values it wants from its tv_property_cache.
+ * It can decide how best to use those parameters.
+ * IOCTL will call set_frontend (by default) due to zigzag
+ * support etc.
+ */
+ if (fe->ops.set_params)
+ r = fe->ops.set_params(fe);
+
+ p.frequency = c->frequency;
+ p.inversion = c->inversion;
+ p.u.qpsk.symbol_rate = c->symbol_rate;
+ p.u.qpsk.fec_inner = c->fec_inner;
+ memcpy(&fepriv->parameters, &p,
+ sizeof (struct dvb_frontend_parameters));
+
+ r = 0;
+ break;
+ default:
+ r = -1;
+ }
+
+ if(c->delivery_system == SYS_ISDBT) {
+ /* Fake out a generic DVB-T request so we pass validation in the ioctl */
+ p.frequency = c->frequency;
+ p.inversion = INVERSION_AUTO;
+ p.u.ofdm.constellation = QAM_AUTO;
+ p.u.ofdm.code_rate_HP = FEC_AUTO;
+ p.u.ofdm.code_rate_LP = FEC_AUTO;
+ p.u.ofdm.bandwidth = BANDWIDTH_AUTO;
+ p.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+ p.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+ p.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
+ memcpy(&fepriv->parameters, &p,
+ sizeof (struct dvb_frontend_parameters));
+
+ r = 0;
+ }
+ }
+ return r;
+}
+
+int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp)
+{
+ int r = 0;
+ printk("%s()\n", __FUNCTION__);
+ tv_property_dump(tvp);
+
+ switch(tvp->cmd) {
+ case TV_SEQ_START:
+ case TV_SEQ_TERMINATE:
+ /* Reset a cache of data specific to the frontend here. This does
+ * not effect hardware.
+ */
+ printk("%s() Flushing property cache\n", __FUNCTION__);
+ memset(&fe->tv_property_cache, 0, sizeof(struct tv_frontend_properties));
+ fe->tv_property_cache.state = TV_SEQ_START;
+ fe->tv_property_cache.delivery_system = SYS_UNDEFINED;
+ break;
+ case TV_SEQ_COMPLETE:
+ /* interpret the cache of data, build either a traditional frontend
+ * tunerequest and submit it to a subset of the ioctl handler,
+ * or, call a new undefined method on the frontend to deal with
+ * all new tune requests.
+ */
+ fe->tv_property_cache.state = TV_SEQ_COMPLETE;
+ printk("%s() Finalised property cache\n", __FUNCTION__);
+ r = tv_property_cache_submit(fe);
+ break;
+ case TV_SET_FREQUENCY:
+ fe->tv_property_cache.frequency = tvp->u.data;
+ break;
+ case TV_GET_FREQUENCY:
+ tvp->u.data = fe->tv_property_cache.frequency;
+ break;
+ case TV_SET_MODULATION:
+ fe->tv_property_cache.modulation = tvp->u.data;
+ break;
+ case TV_GET_MODULATION:
+ tvp->u.data = fe->tv_property_cache.modulation;
+ break;
+ case TV_SET_BANDWIDTH:
+ fe->tv_property_cache.bandwidth = tvp->u.data;
+ break;
+ case TV_GET_BANDWIDTH:
+ tvp->u.data = fe->tv_property_cache.bandwidth;
+ break;
+ case TV_SET_INVERSION:
+ fe->tv_property_cache.inversion = tvp->u.data;
+ break;
+ case TV_GET_INVERSION:
+ tvp->u.data = fe->tv_property_cache.inversion;
+ break;
+ case TV_SET_SYMBOLRATE:
+ fe->tv_property_cache.symbol_rate = tvp->u.data;
+ break;
+ case TV_GET_SYMBOLRATE:
+ tvp->u.data = fe->tv_property_cache.symbol_rate;
+ break;
+ case TV_SET_INNERFEC:
+ fe->tv_property_cache.fec_inner = tvp->u.data;
+ break;
+ case TV_GET_INNERFEC:
+ tvp->u.data = fe->tv_property_cache.fec_inner;
+ break;
+ case TV_SET_PILOT:
+ fe->tv_property_cache.pilot = tvp->u.data;
+ break;
+ case TV_GET_PILOT:
+ tvp->u.data = fe->tv_property_cache.pilot;
+ break;
+ case TV_SET_ROLLOFF:
+ fe->tv_property_cache.rolloff = tvp->u.data;
+ break;
+ case TV_GET_ROLLOFF:
+ tvp->u.data = fe->tv_property_cache.rolloff;
+ break;
+ case TV_SET_DELIVERY_SYSTEM:
+ fe->tv_property_cache.delivery_system = tvp->u.data;
+ break;
+ case TV_GET_DELIVERY_SYSTEM:
+ tvp->u.data = fe->tv_property_cache.delivery_system;
+ break;
+
+ /* ISDB-T Support here */
+ case TV_SET_ISDB_SEGMENT_NUM:
+ fe->tv_property_cache.isdb_segment_num = tvp->u.data;
+ break;
+ case TV_GET_ISDB_SEGMENT_NUM:
+ tvp->u.data = fe->tv_property_cache.isdb_segment_num;
+ break;
+ case TV_SET_ISDB_SEGMENT_WIDTH:
+ fe->tv_property_cache.isdb_segment_width = tvp->u.data;
+ break;
+ case TV_GET_ISDB_SEGMENT_WIDTH:
+ tvp->u.data = fe->tv_property_cache.isdb_segment_width;
+ break;
+ case TV_GET_ISDB_LAYERA_FEC:
+ tvp->u.data = fe->tv_property_cache.isdb_layera_fec;
+ break;
+ case TV_GET_ISDB_LAYERA_MODULATION:
+ tvp->u.data = fe->tv_property_cache.isdb_layera_modulation;
+ break;
+ case TV_GET_ISDB_LAYERA_SEGMENT_WIDTH:
+ tvp->u.data = fe->tv_property_cache.isdb_layera_segment_width;
+ break;
+ case TV_GET_ISDB_LAYERB_FEC:
+ tvp->u.data = fe->tv_property_cache.isdb_layerb_fec;
+ break;
+ case TV_GET_ISDB_LAYERB_MODULATION:
+ tvp->u.data = fe->tv_property_cache.isdb_layerb_modulation;
+ break;
+ case TV_GET_ISDB_LAYERB_SEGMENT_WIDTH:
+ tvp->u.data = fe->tv_property_cache.isdb_layerb_segment_width;
+ break;
+ case TV_GET_ISDB_LAYERC_FEC:
+ tvp->u.data = fe->tv_property_cache.isdb_layerc_fec;
+ break;
+ case TV_GET_ISDB_LAYERC_MODULATION:
+ tvp->u.data = fe->tv_property_cache.isdb_layerc_modulation;
+ break;
+ case TV_GET_ISDB_LAYERC_SEGMENT_WIDTH:
+ tvp->u.data = fe->tv_property_cache.isdb_layerc_segment_width;
+ break;
+
+ }
+
+ return 0;
+}
+
static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
@@ -762,6 +1291,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
struct dvb_frontend *fe = dvbdev->priv;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
int err = -EOPNOTSUPP;
+ tv_property_t* tvp;
dprintk ("%s\n", __func__);
@@ -776,6 +1306,27 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
if (down_interruptible (&fepriv->sem))
return -ERESTARTSYS;
+ if(cmd == FE_SET_PROPERTY) {
+ printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
+
+ /* TODO: basic property validation here */
+
+ /* TODO: ioctl userdata out of range check here */
+ tvp = parg;
+ while(tvp->cmd != TV_SEQ_UNDEFINED) {
+ tv_property_process(fe, tvp);
+ if( (tvp->cmd == TV_SEQ_TERMINATE) || (tvp->cmd == TV_SEQ_COMPLETE) )
+ break;
+ tvp++;
+ }
+
+ if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) {
+ printk("%s() Property cache is full, tuning\n", __FUNCTION__);
+ cmd = FE_SET_FRONTEND;
+ }
+ err = 0;
+ }
+
switch (cmd) {
case FE_GET_INFO: {
struct dvb_frontend_info* info = parg;
@@ -942,13 +1493,20 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_SET_FRONTEND: {
struct dvb_frontend_tune_settings fetunesettings;
- if (dvb_frontend_check_parameters(fe, parg) < 0) {
- err = -EINVAL;
- break;
- }
+ if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) {
+ if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
+ err = -EINVAL;
+ break;
+ }
+ } else {
+ if (dvb_frontend_check_parameters(fe, parg) < 0) {
+ err = -EINVAL;
+ break;
+ }
- memcpy (&fepriv->parameters, parg,
- sizeof (struct dvb_frontend_parameters));
+ memcpy (&fepriv->parameters, parg,
+ sizeof (struct dvb_frontend_parameters));
+ }
memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
memcpy(&fetunesettings.parameters, parg,
@@ -1031,6 +1589,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
return err;
}
+
static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
{
struct dvb_device *dvbdev = file->private_data;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index aa4133f..61d53ee 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -169,6 +169,10 @@ struct dvb_frontend_ops {
struct dvb_tuner_ops tuner_ops;
struct analog_demod_ops analog_ops;
+
+ int (*set_property)(struct dvb_frontend* fe, tv_property_t* tvp);
+ int (*get_property)(struct dvb_frontend* fe, tv_property_t* tvp);
+ int (*set_params)(struct dvb_frontend* fe);
};
#define MAX_EVENT 8
@@ -182,6 +186,45 @@ struct dvb_fe_events {
struct mutex mtx;
};
+struct tv_frontend_properties {
+
+ /* Cache State */
+ u32 state;
+
+ u32 frequency;
+ fe_modulation_t modulation;
+
+ fe_sec_voltage_t voltage;
+ fe_sec_tone_mode_t sectone;
+ fe_spectral_inversion_t inversion;
+ fe_code_rate_t fec_inner;
+ fe_transmit_mode_t transmission_mode;
+ fe_bandwidth_t bandwidth;
+ fe_guard_interval_t guard_interval;
+ fe_hierarchy_t hierarchy;
+ u32 symbol_rate;
+ fe_code_rate_t code_rate_HP;
+ fe_code_rate_t code_rate_LP;
+
+ fe_pilot_t pilot;
+ fe_rolloff_t rolloff;
+
+ fe_delivery_system_t delivery_system;
+
+ /* ISDB-T specifics */
+ u32 isdb_segment_num;
+ u32 isdb_segment_width;
+ fe_code_rate_t isdb_layera_fec;
+ fe_modulation_t isdb_layera_modulation;
+ u32 isdb_layera_segment_width;
+ fe_code_rate_t isdb_layerb_fec;
+ fe_modulation_t isdb_layerb_modulation;
+ u32 isdb_layerb_segment_width;
+ fe_code_rate_t isdb_layerc_fec;
+ fe_modulation_t isdb_layerc_modulation;
+ u32 isdb_layerc_segment_width;
+};
+
struct dvb_frontend {
struct dvb_frontend_ops ops;
struct dvb_adapter *dvb;
@@ -190,6 +233,7 @@ struct dvb_frontend {
void *frontend_priv;
void *sec_priv;
void *analog_demod_priv;
+ struct tv_frontend_properties tv_property_cache;
};
extern int dvb_register_frontend(struct dvb_adapter *dvb,
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index c8cbd90..4d37700 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -62,6 +62,7 @@ typedef enum fe_caps {
FE_CAN_HIERARCHY_AUTO = 0x100000,
FE_CAN_8VSB = 0x200000,
FE_CAN_16VSB = 0x400000,
+ FE_HAS_EXTENDED_CAPS = 0x800000, // We need more bitspace for newer APIs, indicate this.
FE_NEEDS_BENDING = 0x20000000, // not supported anymore, don't use (frontend requires frequency bending)
FE_CAN_RECOVER = 0x40000000, // frontend can recover from a cable unplug automatically
FE_CAN_MUTE_TS = 0x80000000 // frontend can stop spurious TS data output
@@ -147,7 +148,9 @@ typedef enum fe_code_rate {
FEC_6_7,
FEC_7_8,
FEC_8_9,
- FEC_AUTO
+ FEC_AUTO,
+ FEC_3_5,
+ FEC_9_10,
} fe_code_rate_t;
@@ -160,7 +163,11 @@ typedef enum fe_modulation {
QAM_256,
QAM_AUTO,
VSB_8,
- VSB_16
+ VSB_16,
+ _8PSK,
+ _16APSK,
+ NBC_QPSK,
+ DQPSK,
} fe_modulation_t;
typedef enum fe_transmit_mode {
@@ -239,6 +246,125 @@ struct dvb_frontend_event {
struct dvb_frontend_parameters parameters;
};
+/* TODO: Turn this into a series of defines, so future maintainers
+ * don't insert random new commands and break backwards
+ * binary compatability.
+ */
+typedef enum tv_cmd_types {
+ TV_SEQ_UNDEFINED,
+ TV_SEQ_START,
+ TV_SEQ_CONTINUE,
+ TV_SEQ_COMPLETE,
+ TV_SEQ_TERMINATE,
+
+ TV_SET_FREQUENCY,
+ TV_SET_MODULATION,
+ TV_SET_BANDWIDTH,
+ TV_SET_INVERSION,
+ TV_SET_DISEQC_MASTER,
+ TV_SET_SYMBOLRATE,
+ TV_SET_INNERFEC,
+ TV_SET_VOLTAGE,
+ TV_SET_TONE,
+ TV_SET_PILOT,
+ TV_SET_ROLLOFF,
+
+ TV_GET_FREQUENCY,
+ TV_GET_MODULATION,
+ TV_GET_BANDWIDTH,
+ TV_GET_INVERSION,
+ TV_GET_DISEQC_SLAVE_REPLY,
+ TV_GET_SYMBOLRATE,
+ TV_GET_INNERFEC,
+ TV_GET_VOLTAGE,
+ TV_GET_TONE,
+ TV_GET_PILOT,
+ TV_GET_ROLLOFF,
+
+ /* Basic enumeration set for querying unlimited capabilities */
+ TV_GET_FE_CAPABILITY_COUNT,
+ TV_GET_FE_CAPABILITY,
+
+ /* New commands are always appended */
+ TV_SET_DELIVERY_SYSTEM,
+ TV_GET_DELIVERY_SYSTEM,
+
+ /* ISDB-T */
+ TV_SET_ISDB_SEGMENT_NUM,
+ TV_GET_ISDB_SEGMENT_NUM,
+ TV_SET_ISDB_SEGMENT_WIDTH,
+ TV_GET_ISDB_SEGMENT_WIDTH,
+ TV_GET_ISDB_LAYERA_FEC,
+ TV_GET_ISDB_LAYERA_MODULATION,
+ TV_GET_ISDB_LAYERA_SEGMENT_WIDTH,
+ TV_GET_ISDB_LAYERB_FEC,
+ TV_GET_ISDB_LAYERB_MODULATION,
+ TV_GET_ISDB_LAYERB_SEGMENT_WIDTH,
+ TV_GET_ISDB_LAYERC_FEC,
+ TV_GET_ISDB_LAYERC_MODULATION,
+ TV_GET_ISDB_LAYERC_SEGMENT_WIDTH,
+
+} tv_cmd_types_t;
+
+typedef enum fe_pilot {
+ PILOT_ON,
+ PILOT_OFF,
+ PILOT_AUTO,
+} fe_pilot_t;
+
+typedef enum fe_rolloff {
+ ROLLOFF_20,
+ ROLLOFF_25,
+ ROLLOFF_35,
+ ROLLOFF_AUTO,
+} fe_rolloff_t;
+
+typedef enum fe_delivery_system {
+ SYS_UNDEFINED,
+ SYS_DVBC_ANNEX_AC,
+ SYS_DVBC_ANNEX_B,
+ SYS_DVBT,
+ SYS_DVBS,
+ SYS_DVBS2,
+ SYS_DVBH,
+ SYS_ISDBT,
+ SYS_ISDBS,
+ SYS_ISDBC,
+ SYS_ATSC,
+ SYS_ATSCMH,
+ SYS_DMBTH,
+ SYS_CMMB,
+ SYS_DAB,
+} fe_delivery_system_t;
+
+struct tv_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 */
+};
+
+typedef struct {
+ __u32 cmd;
+ union {
+ __u32 data;
+ struct {
+ __u8 data[32];
+ __u32 len;
+ } buffer;
+ } u;
+} tv_property_t;
+
+/* No more than 16 properties during any given ioctl */
+typedef tv_property_t tv_properties_t[16];
+
+#define FE_SET_PROPERTY _IOW('o', 82, tv_properties_t)
+#define FE_GET_PROPERTY _IOR('o', 83, tv_properties_t)
+
/**
* When set, this flag will disable any zigzagging or other "normal" tuning