Merge branch 'next-i2c' of git://aeryn.fluff.org.uk/bjdooks/linux
[safe/jmp/linux-2.6] / drivers / media / dvb / dvb-core / dvb_frontend.c
index 620c620..ebc7815 100644 (file)
 
 #include "dvb_frontend.h"
 #include "dvbdev.h"
+#include <linux/dvb/version.h>
 
 static int dvb_frontend_debug;
 static int dvb_shutdown_timeout;
 static int dvb_force_auto_inversion;
 static int dvb_override_tune_delay;
 static int dvb_powerdown_on_sleep = 1;
+static int dvb_mfe_wait_time = 5;
 
 module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
 MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
@@ -57,6 +59,8 @@ module_param(dvb_override_tune_delay, int, 0644);
 MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
 module_param(dvb_powerdown_on_sleep, int, 0644);
 MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
+module_param(dvb_mfe_wait_time, int, 0644);
+MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
 
 #define dprintk if (dvb_frontend_debug) printk
 
@@ -124,6 +128,7 @@ struct dvb_frontend_private {
        unsigned int step_size;
        int quality;
        unsigned int check_wrapped;
+       enum dvbfe_search algo_status;
 };
 
 static void dvb_frontend_wakeup(struct dvb_frontend *fe);
@@ -211,13 +216,16 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
 
 static void dvb_frontend_init(struct dvb_frontend *fe)
 {
-       dprintk ("DVB: initialising frontend %i (%s)...\n",
+       dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
                 fe->dvb->num,
+                fe->id,
                 fe->ops.info.name);
 
        if (fe->ops.init)
                fe->ops.init(fe);
        if (fe->ops.tuner_ops.init) {
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
                fe->ops.tuner_ops.init(fe);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
@@ -509,6 +517,8 @@ static int dvb_frontend_thread(void *data)
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        unsigned long timeout;
        fe_status_t s;
+       enum dvbfe_algo algo;
+
        struct dvb_frontend_parameters *params;
 
        dprintk("%s\n", __func__);
@@ -555,29 +565,88 @@ restart:
 
                /* do an iteration of the tuning loop */
                if (fe->ops.get_frontend_algo) {
-                       if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
-                               /* have we been asked to retune? */
-                               params = NULL;
+                       algo = fe->ops.get_frontend_algo(fe);
+                       switch (algo) {
+                       case DVBFE_ALGO_HW:
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
+                               params = NULL; /* have we been asked to RETUNE ? */
+
                                if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
                                        params = &fepriv->parameters;
                                        fepriv->state = FESTATE_TUNED;
                                }
 
-                               fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
-                               if (s != fepriv->status) {
+                               if (fe->ops.tune)
+                                       fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+
+                               if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
+                                       dprintk("%s: state changed, adding current state\n", __func__);
                                        dvb_frontend_add_event(fe, s);
                                        fepriv->status = s;
                                }
-                       } else
+                               break;
+                       case DVBFE_ALGO_SW:
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
                                dvb_frontend_swzigzag(fe);
-               } else
+                               break;
+                       case DVBFE_ALGO_CUSTOM:
+                               params = NULL; /* have we been asked to RETUNE ?        */
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
+                               if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
+                                       params = &fepriv->parameters;
+                                       fepriv->state = FESTATE_TUNED;
+                               }
+                               /* Case where we are going to search for a carrier
+                                * User asked us to retune again for some reason, possibly
+                                * requesting a search with a new set of parameters
+                                */
+                               if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
+                                       if (fe->ops.search) {
+                                               fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
+                                               /* We did do a search as was requested, the flags are
+                                                * now unset as well and has the flags wrt to search.
+                                                */
+                                       } else {
+                                               fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
+                                       }
+                               }
+                               /* Track the carrier if the search was successful */
+                               if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
+                                       if (fe->ops.track)
+                                               fe->ops.track(fe, &fepriv->parameters);
+                               } else {
+                                       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       fepriv->delay = HZ / 2;
+                               }
+                               fe->ops.read_status(fe, &s);
+                               if (s != fepriv->status) {
+                                       dvb_frontend_add_event(fe, s); /* update event list */
+                                       fepriv->status = s;
+                                       if (!(s & FE_HAS_LOCK)) {
+                                               fepriv->delay = HZ / 10;
+                                               fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       } else {
+                                               fepriv->delay = 60 * HZ;
+                                       }
+                               }
+                               break;
+                       default:
+                               dprintk("%s: UNDEFINED ALGO !\n", __func__);
+                               break;
+                       }
+               } else {
                        dvb_frontend_swzigzag(fe);
+               }
        }
 
        if (dvb_powerdown_on_sleep) {
                if (fe->ops.set_voltage)
                        fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
                if (fe->ops.tuner_ops.sleep) {
+                       if (fe->ops.i2c_gate_ctrl)
+                               fe->ops.i2c_gate_ctrl(fe, 1);
                        fe->ops.tuner_ops.sleep(fe);
                        if (fe->ops.i2c_gate_ctrl)
                                fe->ops.i2c_gate_ctrl(fe, 0);
@@ -685,7 +754,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
        mb();
 
        fe_thread = kthread_run(dvb_frontend_thread, fe,
-               "kdvb-fe-%i", fe->dvb->num);
+               "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
        if (IS_ERR(fe_thread)) {
                ret = PTR_ERR(fe_thread);
                printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
@@ -709,8 +778,8 @@ static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
                *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
 
        if (*freq_min == 0 || *freq_max == 0)
-               printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",
-                      fe->dvb->num);
+               printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
+                      fe->dvb->num,fe->id);
 }
 
 static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
@@ -723,8 +792,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
        dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
        if ((freq_min && parms->frequency < freq_min) ||
            (freq_max && parms->frequency > freq_max)) {
-               printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
-                      fe->dvb->num, parms->frequency, freq_min, freq_max);
+               printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
+                      fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max);
                return -EINVAL;
        }
 
@@ -734,8 +803,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
                     parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
                    (fe->ops.info.symbol_rate_max &&
                     parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
-                       printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
-                              fe->dvb->num, parms->u.qpsk.symbol_rate,
+                       printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
+                              fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate,
                               fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
                        return -EINVAL;
                }
@@ -745,8 +814,8 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
                     parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
                    (fe->ops.info.symbol_rate_max &&
                     parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
-                       printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
-                              fe->dvb->num, parms->u.qam.symbol_rate,
+                       printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
+                              fe->dvb->num, fe->id, parms->u.qam.symbol_rate,
                               fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
                        return -EINVAL;
                }
@@ -755,405 +824,356 @@ 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,
+static struct dtv_cmds_h dtv_cmds[] = {
+       [DTV_TUNE] = {
+               .name   = "DTV_TUNE",
+               .cmd    = DTV_TUNE,
                .set    = 1,
        },
-       [TV_SEQ_START] = {
-               .name   = "TV_SEQ_START",
-               .cmd    = TV_SEQ_START,
+       [DTV_CLEAR] = {
+               .name   = "DTV_CLEAR",
+               .cmd    = DTV_CLEAR,
                .set    = 1,
        },
-       [TV_SEQ_CONTINUE] = {
-               .name   = "TV_SEQ_CONTINUE",
-               .cmd    = TV_SEQ_CONTINUE,
+
+       /* Set */
+       [DTV_FREQUENCY] = {
+               .name   = "DTV_FREQUENCY",
+               .cmd    = DTV_FREQUENCY,
                .set    = 1,
        },
-       [TV_SEQ_COMPLETE] = {
-               .name   = "TV_SEQ_COMPLETE",
-               .cmd    = TV_SEQ_COMPLETE,
+       [DTV_BANDWIDTH_HZ] = {
+               .name   = "DTV_BANDWIDTH_HZ",
+               .cmd    = DTV_BANDWIDTH_HZ,
                .set    = 1,
        },
-       [TV_SEQ_TERMINATE] = {
-               .name   = "TV_SEQ_TERMINATE",
-               .cmd    = TV_SEQ_TERMINATE,
+       [DTV_MODULATION] = {
+               .name   = "DTV_MODULATION",
+               .cmd    = DTV_MODULATION,
                .set    = 1,
        },
-
-       /* Set */
-       [TV_SET_FREQUENCY] = {
-               .name   = "TV_SET_FREQUENCY",
-               .cmd    = TV_SET_FREQUENCY,
+       [DTV_INVERSION] = {
+               .name   = "DTV_INVERSION",
+               .cmd    = DTV_INVERSION,
                .set    = 1,
        },
-       [TV_SET_BANDWIDTH] = {
-               .name   = "TV_SET_BANDWIDTH",
-               .cmd    = TV_SET_BANDWIDTH,
+       [DTV_DISEQC_MASTER] = {
+               .name   = "DTV_DISEQC_MASTER",
+               .cmd    = DTV_DISEQC_MASTER,
                .set    = 1,
+               .buffer = 1,
        },
-       [TV_SET_MODULATION] = {
-               .name   = "TV_SET_MODULATION",
-               .cmd    = TV_SET_MODULATION,
+       [DTV_SYMBOL_RATE] = {
+               .name   = "DTV_SYMBOL_RATE",
+               .cmd    = DTV_SYMBOL_RATE,
                .set    = 1,
        },
-       [TV_SET_INVERSION] = {
-               .name   = "TV_SET_INVERSION",
-               .cmd    = TV_SET_INVERSION,
+       [DTV_INNER_FEC] = {
+               .name   = "DTV_INNER_FEC",
+               .cmd    = DTV_INNER_FEC,
                .set    = 1,
        },
-       [TV_SET_DISEQC_MASTER] = {
-               .name   = "TV_SET_DISEQC_MASTER",
-               .cmd    = TV_SET_DISEQC_MASTER,
+       [DTV_VOLTAGE] = {
+               .name   = "DTV_VOLTAGE",
+               .cmd    = DTV_VOLTAGE,
                .set    = 1,
-               .buffer = 1,
        },
-       [TV_SET_SYMBOLRATE] = {
-               .name   = "TV_SET_SYMBOLRATE",
-               .cmd    = TV_SET_SYMBOLRATE,
+       [DTV_TONE] = {
+               .name   = "DTV_TONE",
+               .cmd    = DTV_TONE,
                .set    = 1,
        },
-       [TV_SET_INNERFEC] = {
-               .name   = "TV_SET_INNERFEC",
-               .cmd    = TV_SET_INNERFEC,
+       [DTV_PILOT] = {
+               .name   = "DTV_PILOT",
+               .cmd    = DTV_PILOT,
                .set    = 1,
        },
-       [TV_SET_VOLTAGE] = {
-               .name   = "TV_SET_VOLTAGE",
-               .cmd    = TV_SET_VOLTAGE,
+       [DTV_ROLLOFF] = {
+               .name   = "DTV_ROLLOFF",
+               .cmd    = DTV_ROLLOFF,
                .set    = 1,
        },
-       [TV_SET_TONE] = {
-               .name   = "TV_SET_TONE",
-               .cmd    = TV_SET_TONE,
+       [DTV_DELIVERY_SYSTEM] = {
+               .name   = "DTV_DELIVERY_SYSTEM",
+               .cmd    = DTV_DELIVERY_SYSTEM,
                .set    = 1,
        },
-       [TV_SET_PILOT] = {
-               .name   = "TV_SET_PILOT",
-               .cmd    = TV_SET_PILOT,
+       [DTV_HIERARCHY] = {
+               .name   = "DTV_HIERARCHY",
+               .cmd    = DTV_HIERARCHY,
                .set    = 1,
        },
-       [TV_SET_ROLLOFF] = {
-               .name   = "TV_SET_ROLLOFF",
-               .cmd    = TV_SET_ROLLOFF,
+       [DTV_CODE_RATE_HP] = {
+               .name   = "DTV_CODE_RATE_HP",
+               .cmd    = DTV_CODE_RATE_HP,
                .set    = 1,
        },
-       [TV_SET_DELIVERY_SYSTEM] = {
-               .name   = "TV_SET_DELIVERY_SYSTEM",
-               .cmd    = TV_SET_DELIVERY_SYSTEM,
+       [DTV_CODE_RATE_LP] = {
+               .name   = "DTV_CODE_RATE_LP",
+               .cmd    = DTV_CODE_RATE_LP,
                .set    = 1,
        },
-       [TV_SET_ISDB_SEGMENT_NUM] = {
-               .name   = "TV_SET_ISDB_SEGMENT_NUM",
-               .cmd    = TV_SET_ISDB_SEGMENT_NUM,
+       [DTV_GUARD_INTERVAL] = {
+               .name   = "DTV_GUARD_INTERVAL",
+               .cmd    = DTV_GUARD_INTERVAL,
                .set    = 1,
        },
-       [TV_SET_ISDB_SEGMENT_WIDTH] = {
-               .name   = "TV_SET_ISDB_SEGMENT_WIDTH",
-               .cmd    = TV_SET_ISDB_SEGMENT_WIDTH,
+       [DTV_TRANSMISSION_MODE] = {
+               .name   = "DTV_TRANSMISSION_MODE",
+               .cmd    = DTV_TRANSMISSION_MODE,
                .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,
+       [DTV_DISEQC_SLAVE_REPLY] = {
+               .name   = "DTV_DISEQC_SLAVE_REPLY",
+               .cmd    = DTV_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,
+       [DTV_API_VERSION] = {
+               .name   = "DTV_API_VERSION",
+               .cmd    = DTV_API_VERSION,
                .set    = 0,
        },
-       [TV_GET_ISDB_LAYERA_SEGMENT_WIDTH] = {
-               .name   = "TV_GET_ISDB_LAYERA_SEGMENT_WIDTH",
-               .cmd    = TV_GET_ISDB_LAYERA_SEGMENT_WIDTH,
+       [DTV_CODE_RATE_HP] = {
+               .name   = "DTV_CODE_RATE_HP",
+               .cmd    = DTV_CODE_RATE_HP,
                .set    = 0,
        },
-       [TV_GET_ISDB_LAYERB_FEC] = {
-               .name   = "TV_GET_ISDB_LAYERB_FEC",
-               .cmd    = TV_GET_ISDB_LAYERB_FEC,
+       [DTV_CODE_RATE_LP] = {
+               .name   = "DTV_CODE_RATE_LP",
+               .cmd    = DTV_CODE_RATE_LP,
                .set    = 0,
        },
-       [TV_GET_ISDB_LAYERB_MODULATION] = {
-               .name   = "TV_GET_ISDB_LAYERB_MODULATION",
-               .cmd    = TV_GET_ISDB_LAYERB_MODULATION,
+       [DTV_GUARD_INTERVAL] = {
+               .name   = "DTV_GUARD_INTERVAL",
+               .cmd    = DTV_GUARD_INTERVAL,
                .set    = 0,
        },
-       [TV_GET_ISDB_LAYERB_SEGMENT_WIDTH] = {
-               .name   = "TV_GET_ISDB_LAYERB_SEGMENT_WIDTH",
-               .cmd    = TV_GET_ISDB_LAYERB_SEGMENT_WIDTH,
+       [DTV_TRANSMISSION_MODE] = {
+               .name   = "DTV_TRANSMISSION_MODE",
+               .cmd    = DTV_TRANSMISSION_MODE,
                .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,
+       [DTV_HIERARCHY] = {
+               .name   = "DTV_HIERARCHY",
+               .cmd    = DTV_HIERARCHY,
                .set    = 0,
        },
 };
 
-void tv_property_dump(tv_property_t *tvp)
+static void dtv_property_dump(struct dtv_property *tvp)
 {
        int i;
 
-       printk("%s() tvp.cmd    = 0x%08x (%s)\n"
-               ,__FUNCTION__
+       if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
+               printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
+                       __func__, tvp->cmd);
+               return;
+       }
+
+       dprintk("%s() tvp.cmd    = 0x%08x (%s)\n"
+               ,__func__
                ,tvp->cmd
-               ,tv_cmds[ tvp->cmd ].name);
+               ,dtv_cmds[ tvp->cmd ].name);
 
-       if(tv_cmds[ tvp->cmd ].buffer) {
+       if(dtv_cmds[ tvp->cmd ].buffer) {
 
-               printk("%s() tvp.u.buffer.len = 0x%02x\n"
-                       ,__FUNCTION__
+               dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
+                       ,__func__
                        ,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__
+                       dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+                               ,__func__
                                ,i
                                ,tvp->u.buffer.data[i]);
 
        } else
-               printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
+               dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
 }
 
-int is_legacy_delivery_system(fe_delivery_system_t s)
+static 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))
+          (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) ||
+          (s == SYS_ATSC))
                return 1;
 
        return 0;
 }
 
-int tv_property_cache_submit(struct dvb_frontend *fe)
+/* 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.
+ */
+static void dtv_property_cache_sync(struct dvb_frontend *fe,
+                                   struct dvb_frontend_parameters *p)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       c->frequency = p->frequency;
+       c->inversion = p->inversion;
+
+       switch (fe->ops.info.type) {
+       case FE_QPSK:
+               c->modulation = QPSK;   /* implied for DVB-S in legacy API */
+               c->rolloff = ROLLOFF_35;/* implied for DVB-S */
+               c->symbol_rate = p->u.qpsk.symbol_rate;
+               c->fec_inner = p->u.qpsk.fec_inner;
+               c->delivery_system = SYS_DVBS;
+               break;
+       case FE_QAM:
+               c->symbol_rate = p->u.qam.symbol_rate;
+               c->fec_inner = p->u.qam.fec_inner;
+               c->modulation = p->u.qam.modulation;
+               c->delivery_system = SYS_DVBC_ANNEX_AC;
+               break;
+       case FE_OFDM:
+               if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
+                       c->bandwidth_hz = 6000000;
+               else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
+                       c->bandwidth_hz = 7000000;
+               else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+                       c->bandwidth_hz = 8000000;
+               else
+                       /* Including BANDWIDTH_AUTO */
+                       c->bandwidth_hz = 0;
+               c->code_rate_HP = p->u.ofdm.code_rate_HP;
+               c->code_rate_LP = p->u.ofdm.code_rate_LP;
+               c->modulation = p->u.ofdm.constellation;
+               c->transmission_mode = p->u.ofdm.transmission_mode;
+               c->guard_interval = p->u.ofdm.guard_interval;
+               c->hierarchy = p->u.ofdm.hierarchy_information;
+               c->delivery_system = SYS_DVBT;
+               break;
+       case FE_ATSC:
+               c->modulation = p->u.vsb.modulation;
+               if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+                       c->delivery_system = SYS_ATSC;
+               else
+                       c->delivery_system = SYS_DVBC_ANNEX_B;
+               break;
+       }
+}
 
-       /* 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;
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the advanced tuning API.
+ */
+static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dvb_frontend_parameters p;
+       struct dvb_frontend_parameters *p = &fepriv->parameters;
 
-       printk("%s()\n", __FUNCTION__);
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
 
-       /* 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));
+       switch (fe->ops.info.type) {
+       case FE_QPSK:
+               dprintk("%s() Preparing QPSK req\n", __func__);
+               p->u.qpsk.symbol_rate = c->symbol_rate;
+               p->u.qpsk.fec_inner = c->fec_inner;
+               c->delivery_system = SYS_DVBS;
+               break;
+       case FE_QAM:
+               dprintk("%s() Preparing QAM req\n", __func__);
+               p->u.qam.symbol_rate = c->symbol_rate;
+               p->u.qam.fec_inner = c->fec_inner;
+               p->u.qam.modulation = c->modulation;
+               c->delivery_system = SYS_DVBC_ANNEX_AC;
+               break;
+       case FE_OFDM:
+               dprintk("%s() Preparing OFDM req\n", __func__);
+               if (c->bandwidth_hz == 6000000)
+                       p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+               else if (c->bandwidth_hz == 7000000)
+                       p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+               else if (c->bandwidth_hz == 8000000)
+                       p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+               else
+                       p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+               p->u.ofdm.code_rate_HP = c->code_rate_HP;
+               p->u.ofdm.code_rate_LP = c->code_rate_LP;
+               p->u.ofdm.constellation = c->modulation;
+               p->u.ofdm.transmission_mode = c->transmission_mode;
+               p->u.ofdm.guard_interval = c->guard_interval;
+               p->u.ofdm.hierarchy_information = c->hierarchy;
+               c->delivery_system = SYS_DVBT;
+               break;
+       case FE_ATSC:
+               dprintk("%s() Preparing VSB req\n", __func__);
+               p->u.vsb.modulation = c->modulation;
+               if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+                       c->delivery_system = SYS_ATSC;
+               else
+                       c->delivery_system = SYS_DVBC_ANNEX_B;
+               break;
+       }
+}
 
-                       /* Call the traditional tuning mechanisms. */
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the legacy tuning API.
+ */
+static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_frontend_parameters *p = &fepriv->parameters;
+
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+
+       switch(c->modulation) {
+       case PSK_8:
+       case APSK_16:
+       case APSK_32:
+       case QPSK:
+               p->u.qpsk.symbol_rate = c->symbol_rate;
+               p->u.qpsk.fec_inner = c->fec_inner;
+               break;
+       default:
+               break;
+       }
 
-                       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));
+       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;
+       }
+}
 
-                       /* 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.
-                        */
+static void dtv_property_cache_submit(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-                       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));
+       /* For legacy delivery systems we don't need the delivery_system to
+        * be specified, but we populate the older structures from the cache
+        * so we can call set_frontend on older drivers.
+        */
+       if(is_legacy_delivery_system(c->delivery_system)) {
 
-                       /* Call the traditional tuning mechanisms. */
+               dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation);
+               dtv_property_legacy_params_sync(fe);
 
-                       r = 0;
-                       break;
-               /* TODO: Add any missing modulation types */
-               default:
-                       r = -1;
-               }
        } else {
+               dprintk("%s() adv, modulation = %d\n", __func__, c->modulation);
+
                /* 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;
-               }
+               dtv_property_adv_params_sync(fe);
        }
-       return r;
 }
 
 static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
@@ -1161,148 +1181,172 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
 static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
                        unsigned int cmd, void *parg);
 
-int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp,
-       struct inode *inode, struct file *file)
+static int dtv_property_process_get(struct dvb_frontend *fe,
+                                   struct dtv_property *tvp,
+                                   struct inode *inode, struct file *file)
 {
        int r = 0;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       printk("%s()\n", __FUNCTION__);
-       tv_property_dump(tvp);
+
+       dtv_property_dump(tvp);
+
+       /* Allow the frontend to validate incoming properties */
+       if (fe->ops.get_property)
+               r = fe->ops.get_property(fe, tvp);
+
+       if (r < 0)
+               return r;
 
        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;
+       case DTV_FREQUENCY:
+               tvp->u.data = fe->dtv_property_cache.frequency;
                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);
-               r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
-                       &fepriv->parameters);
+       case DTV_MODULATION:
+               tvp->u.data = fe->dtv_property_cache.modulation;
                break;
-       case TV_SET_FREQUENCY:
-               fe->tv_property_cache.frequency = tvp->u.data;
+       case DTV_BANDWIDTH_HZ:
+               tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
                break;
-       case TV_GET_FREQUENCY:
-               tvp->u.data = fe->tv_property_cache.frequency;
+       case DTV_INVERSION:
+               tvp->u.data = fe->dtv_property_cache.inversion;
                break;
-       case TV_SET_MODULATION:
-               fe->tv_property_cache.modulation = tvp->u.data;
+       case DTV_SYMBOL_RATE:
+               tvp->u.data = fe->dtv_property_cache.symbol_rate;
                break;
-       case TV_GET_MODULATION:
-               tvp->u.data = fe->tv_property_cache.modulation;
+       case DTV_INNER_FEC:
+               tvp->u.data = fe->dtv_property_cache.fec_inner;
                break;
-       case TV_SET_BANDWIDTH:
-               fe->tv_property_cache.bandwidth = tvp->u.data;
+       case DTV_PILOT:
+               tvp->u.data = fe->dtv_property_cache.pilot;
                break;
-       case TV_GET_BANDWIDTH:
-               tvp->u.data = fe->tv_property_cache.bandwidth;
+       case DTV_ROLLOFF:
+               tvp->u.data = fe->dtv_property_cache.rolloff;
                break;
-       case TV_SET_INVERSION:
-               fe->tv_property_cache.inversion = tvp->u.data;
+       case DTV_DELIVERY_SYSTEM:
+               tvp->u.data = fe->dtv_property_cache.delivery_system;
                break;
-       case TV_GET_INVERSION:
-               tvp->u.data = fe->tv_property_cache.inversion;
+       case DTV_VOLTAGE:
+               tvp->u.data = fe->dtv_property_cache.voltage;
                break;
-       case TV_SET_SYMBOLRATE:
-               fe->tv_property_cache.symbol_rate = tvp->u.data;
+       case DTV_TONE:
+               tvp->u.data = fe->dtv_property_cache.sectone;
                break;
-       case TV_GET_SYMBOLRATE:
-               tvp->u.data = fe->tv_property_cache.symbol_rate;
+       case DTV_API_VERSION:
+               tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
                break;
-       case TV_SET_INNERFEC:
-               fe->tv_property_cache.fec_inner = tvp->u.data;
+       case DTV_CODE_RATE_HP:
+               tvp->u.data = fe->dtv_property_cache.code_rate_HP;
                break;
-       case TV_GET_INNERFEC:
-               tvp->u.data = fe->tv_property_cache.fec_inner;
+       case DTV_CODE_RATE_LP:
+               tvp->u.data = fe->dtv_property_cache.code_rate_LP;
                break;
-       case TV_SET_PILOT:
-               fe->tv_property_cache.pilot = tvp->u.data;
+       case DTV_GUARD_INTERVAL:
+               tvp->u.data = fe->dtv_property_cache.guard_interval;
                break;
-       case TV_GET_PILOT:
-               tvp->u.data = fe->tv_property_cache.pilot;
+       case DTV_TRANSMISSION_MODE:
+               tvp->u.data = fe->dtv_property_cache.transmission_mode;
                break;
-       case TV_SET_ROLLOFF:
-               fe->tv_property_cache.rolloff = tvp->u.data;
+       case DTV_HIERARCHY:
+               tvp->u.data = fe->dtv_property_cache.hierarchy;
                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;
+       default:
+               r = -1;
+       }
+
+       return r;
+}
+
+static int dtv_property_process_set(struct dvb_frontend *fe,
+                                   struct dtv_property *tvp,
+                                   struct inode *inode,
+                                   struct file *file)
+{
+       int r = 0;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       dtv_property_dump(tvp);
+
+       /* Allow the frontend to validate incoming properties */
+       if (fe->ops.set_property)
+               r = fe->ops.set_property(fe, tvp);
+
+       if (r < 0)
+               return r;
+
+       switch(tvp->cmd) {
+       case DTV_CLEAR:
+               /* Reset a cache of data specific to the frontend here. This does
+                * not effect hardware.
+                */
+               dprintk("%s() Flushing property cache\n", __func__);
+               memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));
+               fe->dtv_property_cache.state = tvp->cmd;
+               fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
                break;
+       case DTV_TUNE:
+               /* interpret the cache of data, build either a traditional frontend
+                * tunerequest so we can pass validation in the FE_SET_FRONTEND
+                * ioctl.
+                */
+               fe->dtv_property_cache.state = tvp->cmd;
+               dprintk("%s() Finalised property cache\n", __func__);
+               dtv_property_cache_submit(fe);
 
-       /* ISDB-T Support here */
-       case TV_SET_ISDB_SEGMENT_NUM:
-               fe->tv_property_cache.isdb_segment_num = tvp->u.data;
+               r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
+                       &fepriv->parameters);
                break;
-       case TV_GET_ISDB_SEGMENT_NUM:
-               tvp->u.data = fe->tv_property_cache.isdb_segment_num;
+       case DTV_FREQUENCY:
+               fe->dtv_property_cache.frequency = tvp->u.data;
                break;
-       case TV_SET_ISDB_SEGMENT_WIDTH:
-               fe->tv_property_cache.isdb_segment_width = tvp->u.data;
+       case DTV_MODULATION:
+               fe->dtv_property_cache.modulation = tvp->u.data;
                break;
-       case TV_GET_ISDB_SEGMENT_WIDTH:
-               tvp->u.data = fe->tv_property_cache.isdb_segment_width;
+       case DTV_BANDWIDTH_HZ:
+               fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
                break;
-       case TV_GET_ISDB_LAYERA_FEC:
-               tvp->u.data = fe->tv_property_cache.isdb_layera_fec;
+       case DTV_INVERSION:
+               fe->dtv_property_cache.inversion = tvp->u.data;
                break;
-       case TV_GET_ISDB_LAYERA_MODULATION:
-               tvp->u.data = fe->tv_property_cache.isdb_layera_modulation;
+       case DTV_SYMBOL_RATE:
+               fe->dtv_property_cache.symbol_rate = tvp->u.data;
                break;
-       case TV_GET_ISDB_LAYERA_SEGMENT_WIDTH:
-               tvp->u.data = fe->tv_property_cache.isdb_layera_segment_width;
+       case DTV_INNER_FEC:
+               fe->dtv_property_cache.fec_inner = tvp->u.data;
                break;
-       case TV_GET_ISDB_LAYERB_FEC:
-               tvp->u.data = fe->tv_property_cache.isdb_layerb_fec;
+       case DTV_PILOT:
+               fe->dtv_property_cache.pilot = tvp->u.data;
                break;
-       case TV_GET_ISDB_LAYERB_MODULATION:
-               tvp->u.data = fe->tv_property_cache.isdb_layerb_modulation;
+       case DTV_ROLLOFF:
+               fe->dtv_property_cache.rolloff = tvp->u.data;
                break;
-       case TV_GET_ISDB_LAYERB_SEGMENT_WIDTH:
-               tvp->u.data = fe->tv_property_cache.isdb_layerb_segment_width;
+       case DTV_DELIVERY_SYSTEM:
+               fe->dtv_property_cache.delivery_system = tvp->u.data;
                break;
-       case TV_GET_ISDB_LAYERC_FEC:
-               tvp->u.data = fe->tv_property_cache.isdb_layerc_fec;
+       case DTV_VOLTAGE:
+               fe->dtv_property_cache.voltage = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE,
+                       (void *)fe->dtv_property_cache.voltage);
                break;
-       case TV_GET_ISDB_LAYERC_MODULATION:
-               tvp->u.data = fe->tv_property_cache.isdb_layerc_modulation;
+       case DTV_TONE:
+               fe->dtv_property_cache.sectone = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,
+                       (void *)fe->dtv_property_cache.sectone);
                break;
-       case TV_GET_ISDB_LAYERC_SEGMENT_WIDTH:
-               tvp->u.data = fe->tv_property_cache.isdb_layerc_segment_width;
+       case DTV_CODE_RATE_HP:
+               fe->dtv_property_cache.code_rate_HP = tvp->u.data;
                break;
-       case TV_SET_VOLTAGE:
-               fe->tv_property_cache.voltage = tvp->u.data;
-               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE,
-                       (void *)fe->tv_property_cache.voltage);
+       case DTV_CODE_RATE_LP:
+               fe->dtv_property_cache.code_rate_LP = tvp->u.data;
                break;
-       case TV_GET_VOLTAGE:
-               tvp->u.data = fe->tv_property_cache.voltage;
+       case DTV_GUARD_INTERVAL:
+               fe->dtv_property_cache.guard_interval = tvp->u.data;
                break;
-       case TV_SET_TONE:
-               fe->tv_property_cache.sectone = tvp->u.data;
-               r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,
-                       (void *)fe->tv_property_cache.sectone);
+       case DTV_TRANSMISSION_MODE:
+               fe->dtv_property_cache.transmission_mode = tvp->u.data;
                break;
-       case TV_GET_TONE:
-               tvp->u.data = fe->tv_property_cache.sectone;
+       case DTV_HIERARCHY:
+               fe->dtv_property_cache.hierarchy = tvp->u.data;
                break;
+       default:
+               r = -1;
        }
 
        return r;
@@ -1331,8 +1375,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 
        if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
                err = dvb_frontend_ioctl_properties(inode, file, cmd, parg);
-       else
+       else {
+               fe->dtv_property_cache.state = DTV_UNDEFINED;
                err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg);
+       }
 
        up(&fepriv->sem);
        return err;
@@ -1343,31 +1389,85 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dvb_frontend *fe = dvbdev->priv;
-       int err = -EOPNOTSUPP;
-       tv_property_t *tvp;
+       int err = 0;
+
+       struct dtv_properties *tvps = NULL;
+       struct dtv_property *tvp = NULL;
+       int i;
 
        dprintk("%s\n", __func__);
 
        if(cmd == FE_SET_PROPERTY) {
-               printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
+               tvps = (struct dtv_properties __user *)parg;
 
-               /* TODO: basic property validation here */
+               dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+               dprintk("%s() properties.props = %p\n", __func__, tvps->props);
 
-               /* TODO: ioctl userdata out of range check here */
-               tvp = parg;
-               while(tvp->cmd != TV_SEQ_UNDEFINED) {
-                       tv_property_process(fe, tvp, inode, file);
-                       if( (tvp->cmd == TV_SEQ_TERMINATE) || (tvp->cmd == TV_SEQ_COMPLETE) )
-                               break;
-                       tvp++;
+               /* Put an arbitrary limit on the number of messages that can
+                * be sent at once */
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = (struct dtv_property *) kmalloc(tvps->num *
+                       sizeof(struct dtv_property), GFP_KERNEL);
+               if (!tvp) {
+                       err = -ENOMEM;
+                       goto out;
                }
 
-               if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) {
-                       printk("%s() Property cache is full, tuning\n", __FUNCTION__);
+               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
                }
-               err = 0;
-       }
 
+               for (i = 0; i < tvps->num; i++) {
+                       (tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file);
+                       err |= (tvp + i)->result;
+               }
+
+               if(fe->dtv_property_cache.state == DTV_TUNE)
+                       dprintk("%s() Property cache is full, tuning\n", __func__);
+
+       } else
+       if(cmd == FE_GET_PROPERTY) {
+
+               tvps = (struct dtv_properties __user *)parg;
+
+               dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+               dprintk("%s() properties.props = %p\n", __func__, tvps->props);
+
+               /* Put an arbitrary limit on the number of messages that can
+                * be sent at once */
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = (struct dtv_property *) kmalloc(tvps->num *
+                       sizeof(struct dtv_property), GFP_KERNEL);
+               if (!tvp) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+               for (i = 0; i < tvps->num; i++) {
+                       (tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file);
+                       err |= (tvp + i)->result;
+               }
+
+               if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+       } else
+               err = -EOPNOTSUPP;
+
+out:
+       kfree(tvp);
        return err;
 }
 
@@ -1545,7 +1645,7 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
        case FE_SET_FRONTEND: {
                struct dvb_frontend_tune_settings fetunesettings;
 
-               if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) {
+               if(fe->dtv_property_cache.state == DTV_TUNE) {
                        if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
                                err = -EINVAL;
                                break;
@@ -1558,6 +1658,7 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
 
                        memcpy (&fepriv->parameters, parg,
                                sizeof (struct dvb_frontend_parameters));
+                       dtv_property_cache_sync(fe, &fepriv->parameters);
                }
 
                memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
@@ -1613,6 +1714,10 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
                        fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
 
                fepriv->state = FESTATE_RETUNE;
+
+               /* Request the search algorithm to search */
+               fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+
                dvb_frontend_wakeup(fe);
                dvb_frontend_add_event(fe, 0);
                fepriv->status = 0;
@@ -1662,13 +1767,53 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
        struct dvb_device *dvbdev = file->private_data;
        struct dvb_frontend *fe = dvbdev->priv;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_adapter *adapter = fe->dvb;
        int ret;
 
        dprintk ("%s\n", __func__);
 
+       if (adapter->mfe_shared) {
+               mutex_lock (&adapter->mfe_lock);
+
+               if (adapter->mfe_dvbdev == NULL)
+                       adapter->mfe_dvbdev = dvbdev;
+
+               else if (adapter->mfe_dvbdev != dvbdev) {
+                       struct dvb_device
+                               *mfedev = adapter->mfe_dvbdev;
+                       struct dvb_frontend
+                               *mfe = mfedev->priv;
+                       struct dvb_frontend_private
+                               *mfepriv = mfe->frontend_priv;
+                       int mferetry = (dvb_mfe_wait_time << 1);
+
+                       mutex_unlock (&adapter->mfe_lock);
+                       while (mferetry-- && (mfedev->users != -1 ||
+                                       mfepriv->thread != NULL)) {
+                               if(msleep_interruptible(500)) {
+                                       if(signal_pending(current))
+                                               return -EINTR;
+                               }
+                       }
+
+                       mutex_lock (&adapter->mfe_lock);
+                       if(adapter->mfe_dvbdev != dvbdev) {
+                               mfedev = adapter->mfe_dvbdev;
+                               mfe = mfedev->priv;
+                               mfepriv = mfe->frontend_priv;
+                               if (mfedev->users != -1 ||
+                                               mfepriv->thread != NULL) {
+                                       mutex_unlock (&adapter->mfe_lock);
+                                       return -EBUSY;
+                               }
+                               adapter->mfe_dvbdev = dvbdev;
+                       }
+               }
+       }
+
        if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
                if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
-                       return ret;
+                       goto err0;
        }
 
        if ((ret = dvb_generic_open (inode, file)) < 0)
@@ -1688,6 +1833,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
                fepriv->events.eventr = fepriv->events.eventw = 0;
        }
 
+       if (adapter->mfe_shared)
+               mutex_unlock (&adapter->mfe_lock);
        return ret;
 
 err2:
@@ -1695,6 +1842,9 @@ err2:
 err1:
        if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
                fe->ops.ts_bus_ctrl(fe, 0);
+err0:
+       if (adapter->mfe_shared)
+               mutex_unlock (&adapter->mfe_lock);
        return ret;
 }
 
@@ -1725,7 +1875,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
        return ret;
 }
 
-static struct file_operations dvb_frontend_fops = {
+static const struct file_operations dvb_frontend_fops = {
        .owner          = THIS_MODULE,
        .ioctl          = dvb_generic_ioctl,
        .poll           = dvb_frontend_poll,
@@ -1764,8 +1914,9 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
        fe->dvb = dvb;
        fepriv->inversion = INVERSION_OFF;
 
-       printk ("DVB: registering frontend %i (%s)...\n",
+       printk ("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,