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 0ef9c2a..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,7 +824,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
        return 0;
 }
 
-struct dtv_cmds_h dtv_cmds[] = {
+static struct dtv_cmds_h dtv_cmds[] = {
        [DTV_TUNE] = {
                .name   = "DTV_TUNE",
                .cmd    = DTV_TUNE,
@@ -829,6 +898,31 @@ struct dtv_cmds_h dtv_cmds[] = {
                .cmd    = DTV_DELIVERY_SYSTEM,
                .set    = 1,
        },
+       [DTV_HIERARCHY] = {
+               .name   = "DTV_HIERARCHY",
+               .cmd    = DTV_HIERARCHY,
+               .set    = 1,
+       },
+       [DTV_CODE_RATE_HP] = {
+               .name   = "DTV_CODE_RATE_HP",
+               .cmd    = DTV_CODE_RATE_HP,
+               .set    = 1,
+       },
+       [DTV_CODE_RATE_LP] = {
+               .name   = "DTV_CODE_RATE_LP",
+               .cmd    = DTV_CODE_RATE_LP,
+               .set    = 1,
+       },
+       [DTV_GUARD_INTERVAL] = {
+               .name   = "DTV_GUARD_INTERVAL",
+               .cmd    = DTV_GUARD_INTERVAL,
+               .set    = 1,
+       },
+       [DTV_TRANSMISSION_MODE] = {
+               .name   = "DTV_TRANSMISSION_MODE",
+               .cmd    = DTV_TRANSMISSION_MODE,
+               .set    = 1,
+       },
        /* Get */
        [DTV_DISEQC_SLAVE_REPLY] = {
                .name   = "DTV_DISEQC_SLAVE_REPLY",
@@ -836,37 +930,74 @@ struct dtv_cmds_h dtv_cmds[] = {
                .set    = 0,
                .buffer = 1,
        },
+       [DTV_API_VERSION] = {
+               .name   = "DTV_API_VERSION",
+               .cmd    = DTV_API_VERSION,
+               .set    = 0,
+       },
+       [DTV_CODE_RATE_HP] = {
+               .name   = "DTV_CODE_RATE_HP",
+               .cmd    = DTV_CODE_RATE_HP,
+               .set    = 0,
+       },
+       [DTV_CODE_RATE_LP] = {
+               .name   = "DTV_CODE_RATE_LP",
+               .cmd    = DTV_CODE_RATE_LP,
+               .set    = 0,
+       },
+       [DTV_GUARD_INTERVAL] = {
+               .name   = "DTV_GUARD_INTERVAL",
+               .cmd    = DTV_GUARD_INTERVAL,
+               .set    = 0,
+       },
+       [DTV_TRANSMISSION_MODE] = {
+               .name   = "DTV_TRANSMISSION_MODE",
+               .cmd    = DTV_TRANSMISSION_MODE,
+               .set    = 0,
+       },
+       [DTV_HIERARCHY] = {
+               .name   = "DTV_HIERARCHY",
+               .cmd    = DTV_HIERARCHY,
+               .set    = 0,
+       },
 };
 
-void dtv_property_dump(struct dtv_property *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
                ,dtv_cmds[ tvp->cmd ].name);
 
        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;
@@ -876,17 +1007,18 @@ int is_legacy_delivery_system(fe_delivery_system_t s)
  * 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.
  */
-void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static void dtv_property_cache_sync(struct dvb_frontend *fe,
+                                   struct dvb_frontend_parameters *p)
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-       printk("%s()\n", __FUNCTION__);
-
        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;
@@ -928,33 +1060,31 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame
 /* Ensure the cached values are set correctly in the frontend
  * legacy tuning structures, for the advanced tuning API.
  */
-void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+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 = &fepriv->parameters;
 
-       printk("%s()\n", __FUNCTION__);
-
        p->frequency = c->frequency;
        p->inversion = c->inversion;
 
        switch (fe->ops.info.type) {
        case FE_QPSK:
-               printk("%s() Preparing QPSK req\n", __FUNCTION__);
+               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:
-               printk("%s() Preparing QAM req\n", __FUNCTION__);
+               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:
-               printk("%s() Preparing OFDM req\n", __FUNCTION__);
+               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)
@@ -972,7 +1102,7 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
                c->delivery_system = SYS_DVBT;
                break;
        case FE_ATSC:
-               printk("%s() Preparing VSB req\n", __FUNCTION__);
+               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;
@@ -985,21 +1115,20 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
 /* Ensure the cached values are set correctly in the frontend
  * legacy tuning structures, for the legacy tuning API.
  */
-void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+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;
 
-       printk("%s()\n", __FUNCTION__);
-
        p->frequency = c->frequency;
        p->inversion = c->inversion;
 
        switch(c->modulation) {
-       case _8PSK:
-       case _16APSK:
-       case NBC_QPSK:
+       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;
@@ -1021,23 +1150,21 @@ void dtv_property_adv_params_sync(struct dvb_frontend *fe)
        }
 }
 
-void dtv_property_cache_submit(struct dvb_frontend *fe)
+static void dtv_property_cache_submit(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 
-       printk("%s()\n", __FUNCTION__);
-
        /* 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)) {
 
-               printk("%s() legacy, modulation = %d\n", __FUNCTION__, c->modulation);
+               dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation);
                dtv_property_legacy_params_sync(fe);
 
        } else {
-               printk("%s() adv, modulation = %d\n", __FUNCTION__, c->modulation);
+               dprintk("%s() adv, modulation = %d\n", __func__, c->modulation);
 
                /* For advanced delivery systems / modulation types ...
                 * we seed the lecacy dvb_frontend_parameters structure
@@ -1054,13 +1181,12 @@ 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 dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *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;
 
-       printk("%s()\n", __FUNCTION__);
-
        dtv_property_dump(tvp);
 
        /* Allow the frontend to validate incoming properties */
@@ -1104,6 +1230,24 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
        case DTV_TONE:
                tvp->u.data = fe->dtv_property_cache.sectone;
                break;
+       case DTV_API_VERSION:
+               tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+               break;
+       case DTV_CODE_RATE_HP:
+               tvp->u.data = fe->dtv_property_cache.code_rate_HP;
+               break;
+       case DTV_CODE_RATE_LP:
+               tvp->u.data = fe->dtv_property_cache.code_rate_LP;
+               break;
+       case DTV_GUARD_INTERVAL:
+               tvp->u.data = fe->dtv_property_cache.guard_interval;
+               break;
+       case DTV_TRANSMISSION_MODE:
+               tvp->u.data = fe->dtv_property_cache.transmission_mode;
+               break;
+       case DTV_HIERARCHY:
+               tvp->u.data = fe->dtv_property_cache.hierarchy;
+               break;
        default:
                r = -1;
        }
@@ -1111,12 +1255,13 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
        return r;
 }
 
-int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
-       struct inode *inode, struct file *file)
+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;
-       printk("%s()\n", __FUNCTION__);
        dtv_property_dump(tvp);
 
        /* Allow the frontend to validate incoming properties */
@@ -1131,7 +1276,7 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
                /* Reset a cache of data specific to the frontend here. This does
                 * not effect hardware.
                 */
-               printk("%s() Flushing property cache\n", __FUNCTION__);
+               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;
@@ -1142,7 +1287,7 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
                 * ioctl.
                 */
                fe->dtv_property_cache.state = tvp->cmd;
-               printk("%s() Finalised property cache\n", __FUNCTION__);
+               dprintk("%s() Finalised property cache\n", __func__);
                dtv_property_cache_submit(fe);
 
                r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
@@ -1185,6 +1330,21 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
                r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,
                        (void *)fe->dtv_property_cache.sectone);
                break;
+       case DTV_CODE_RATE_HP:
+               fe->dtv_property_cache.code_rate_HP = tvp->u.data;
+               break;
+       case DTV_CODE_RATE_LP:
+               fe->dtv_property_cache.code_rate_LP = tvp->u.data;
+               break;
+       case DTV_GUARD_INTERVAL:
+               fe->dtv_property_cache.guard_interval = tvp->u.data;
+               break;
+       case DTV_TRANSMISSION_MODE:
+               fe->dtv_property_cache.transmission_mode = tvp->u.data;
+               break;
+       case DTV_HIERARCHY:
+               fe->dtv_property_cache.hierarchy = tvp->u.data;
+               break;
        default:
                r = -1;
        }
@@ -1238,16 +1398,14 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
        dprintk("%s\n", __func__);
 
        if(cmd == FE_SET_PROPERTY) {
-               printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
-
                tvps = (struct dtv_properties __user *)parg;
 
-               printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
-               printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+               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 > DTV_IOCTL_MAX_MSGS)
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
                        return -EINVAL;
 
                tvp = (struct dtv_property *) kmalloc(tvps->num *
@@ -1267,22 +1425,20 @@ static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
                        err |= (tvp + i)->result;
                }
 
-               if(fe->dtv_property_cache.state == DTV_TUNE) {
-                       printk("%s() Property cache is full, tuning\n", __FUNCTION__);
-               }
+               if(fe->dtv_property_cache.state == DTV_TUNE)
+                       dprintk("%s() Property cache is full, tuning\n", __func__);
 
        } else
        if(cmd == FE_GET_PROPERTY) {
-               printk("%s() FE_GET_PROPERTY\n", __FUNCTION__);
 
                tvps = (struct dtv_properties __user *)parg;
 
-               printk("%s() properties.num = %d\n", __FUNCTION__, tvps->num);
-               printk("%s() properties.props = %p\n", __FUNCTION__, tvps->props);
+               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 > DTV_IOCTL_MAX_MSGS)
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
                        return -EINVAL;
 
                tvp = (struct dtv_property *) kmalloc(tvps->num *
@@ -1558,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;
@@ -1607,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)
@@ -1633,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:
@@ -1640,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;
 }
 
@@ -1670,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,
@@ -1709,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,