V4L/DVB (9026): Add support for ST STV0288 demodulator and cards with it.
[pandora-kernel.git] / drivers / media / video / cx88 / cx88-dvb.c
index f1251b8..cd368b5 100644 (file)
 #include "isl6421.h"
 #include "tuner-simple.h"
 #include "tda9887.h"
+#include "s5h1411.h"
+#include "stv0299.h"
+#include "z0194a.h"
+#include "stv0288.h"
+#include "stb6000.h"
+#include "cx24116.h"
 
 MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -374,6 +380,31 @@ static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
        return 0;
 }
 
+static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
+                                     fe_sec_voltage_t voltage)
+{
+       struct cx8802_dev *dev= fe->dvb->priv;
+       struct cx88_core *core = dev->core;
+
+       switch (voltage) {
+               case SEC_VOLTAGE_13:
+                       printk("LNB Voltage SEC_VOLTAGE_13\n");
+                       cx_write(MO_GP0_IO, 0x00006040);
+                       break;
+               case SEC_VOLTAGE_18:
+                       printk("LNB Voltage SEC_VOLTAGE_18\n");
+                       cx_write(MO_GP0_IO, 0x00006060);
+                       break;
+               case SEC_VOLTAGE_OFF:
+                       printk("LNB Voltage SEC_VOLTAGE_off\n");
+                       break;
+       }
+
+       if (core->prev_set_voltage)
+               return core->prev_set_voltage(fe, voltage);
+       return 0;
+}
+
 static int cx88_pci_nano_callback(void *ptr, int command, int arg)
 {
        struct cx88_core *core = ptr;
@@ -463,6 +494,22 @@ static struct zl10353_config cx88_geniatech_x8000_mt = {
        .no_tuner = 1,
 };
 
+static struct s5h1411_config dvico_fusionhdtv7_config = {
+       .output_mode   = S5H1411_SERIAL_OUTPUT,
+       .gpio          = S5H1411_GPIO_ON,
+       .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+       .qam_if        = S5H1411_IF_44000,
+       .vsb_if        = S5H1411_IF_44000,
+       .inversion     = S5H1411_INVERSION_OFF,
+       .status_mode   = S5H1411_DEMODLOCKING
+};
+
+static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
+       .i2c_address    = 0xc2 >> 1,
+       .if_khz         = 5380,
+       .tuner_callback = cx88_tuner_callback,
+};
+
 static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
 {
        struct dvb_frontend *fe;
@@ -492,9 +539,6 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
        if (!fe) {
                printk(KERN_ERR "%s/2: xc3028 attach failed\n",
                       dev->core->name);
-               dvb_frontend_detach(dev->dvb.frontend);
-               dvb_unregister_frontend(dev->dvb.frontend);
-               dev->dvb.frontend = NULL;
                return -EINVAL;
        }
 
@@ -504,22 +548,79 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
        return 0;
 }
 
+static int cx24116_set_ts_param(struct dvb_frontend *fe,
+       int is_punctured)
+{
+       struct cx8802_dev *dev = fe->dvb->priv;
+       dev->ts_gen_cntrl = 0x2;
+
+       return 0;
+}
+
+static int cx24116_reset_device(struct dvb_frontend *fe)
+{
+       struct cx8802_dev *dev = fe->dvb->priv;
+       struct cx88_core *core = dev->core;
+
+       /* Reset the part */
+       cx_write(MO_SRST_IO, 0);
+       msleep(10);
+       cx_write(MO_SRST_IO, 1);
+       msleep(10);
+
+       return 0;
+}
+
+static struct cx24116_config hauppauge_hvr4000_config = {
+       .demod_address          = 0x05,
+       .set_ts_params          = cx24116_set_ts_param,
+       .reset_device           = cx24116_reset_device,
+};
+
+static struct cx24116_config tevii_s460_config = {
+       .demod_address = 0x55,
+       .set_ts_params = cx24116_set_ts_param,
+       .reset_device  = cx24116_reset_device,
+};
+
+static struct stv0299_config tevii_tuner_sharp_config = {
+       .demod_address = 0x68,
+       .inittab = sharp_z0194a__inittab,
+       .mclk = 88000000UL,
+       .invert = 1,
+       .skip_reinit = 0,
+       .lock_output = 1,
+       .volt13_op0_op1 = STV0299_VOLT13_OP1,
+       .min_delay_ms = 100,
+       .set_symbol_rate = sharp_z0194a__set_symbol_rate,
+       .set_ts_params = cx24116_set_ts_param,
+};
+
+static struct stv0288_config tevii_tuner_earda_config = {
+       .demod_address = 0x68,
+       .min_delay_ms = 100,
+       .set_ts_params = cx24116_set_ts_param,
+};
+
 static int dvb_register(struct cx8802_dev *dev)
 {
+       struct cx88_core *core = dev->core;
+
        /* init struct videobuf_dvb */
-       dev->dvb.name = dev->core->name;
+       dev->dvb.name = core->name;
        dev->ts_gen_cntrl = 0x0c;
 
        /* init frontend */
-       switch (dev->core->boardnr) {
+       switch (core->boardnr) {
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
                dev->dvb.frontend = dvb_attach(cx22702_attach,
                                               &connexant_refboard_config,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  &dev->core->i2c_adap,
-                                  DVB_PLL_THOMSON_DTT759X);
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+                                       0x61, &core->i2c_adap,
+                                       DVB_PLL_THOMSON_DTT759X))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -528,11 +629,12 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_WINFAST_DTV1000:
                dev->dvb.frontend = dvb_attach(cx22702_attach,
                                               &connexant_refboard_config,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-                                  &dev->core->i2c_adap,
-                                  DVB_PLL_THOMSON_DTT7579);
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+                                       0x60, &core->i2c_adap,
+                                       DVB_PLL_THOMSON_DTT7579))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_WINFAST_DTV2000H:
@@ -542,29 +644,32 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_HAUPPAUGE_HVR3000:
                dev->dvb.frontend = dvb_attach(cx22702_attach,
                                               &hauppauge_hvr_config,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x61,
-                                  TUNER_PHILIPS_FMD1216ME_MK3);
+                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                                  &core->i2c_adap, 0x61,
+                                  TUNER_PHILIPS_FMD1216ME_MK3))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
                dev->dvb.frontend = dvb_attach(mt352_attach,
                                               &dvico_fusionhdtv,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-                                  NULL, DVB_PLL_THOMSON_DTT7579);
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+                                       0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+                               goto frontend_detach;
                        break;
                }
                /* ZL10353 replaces MT352 on later cards */
                dev->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_plus_v1_1,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-                                  NULL, DVB_PLL_THOMSON_DTT7579);
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+                                       0x60, NULL, DVB_PLL_THOMSON_DTT7579))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -572,28 +677,31 @@ static int dvb_register(struct cx8802_dev *dev)
                 * compatible, with a slightly different MT352 AGC gain. */
                dev->dvb.frontend = dvb_attach(mt352_attach,
                                               &dvico_fusionhdtv_dual,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, DVB_PLL_THOMSON_DTT7579);
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+                                       0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+                               goto frontend_detach;
                        break;
                }
                /* ZL10353 replaces MT352 on later cards */
                dev->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_plus_v1_1,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, DVB_PLL_THOMSON_DTT7579);
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+                                       0x61, NULL, DVB_PLL_THOMSON_DTT7579))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
                dev->dvb.frontend = dvb_attach(mt352_attach,
                                               &dvico_fusionhdtv,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, DVB_PLL_LG_Z201);
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+                                       0x61, NULL, DVB_PLL_LG_Z201))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_KWORLD_DVB_T:
@@ -601,10 +709,11 @@ static int dvb_register(struct cx8802_dev *dev)
        case CX88_BOARD_ADSTECH_DVB_T_PCI:
                dev->dvb.frontend = dvb_attach(mt352_attach,
                                               &dntv_live_dvbt_config,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-                                  NULL, DVB_PLL_UNKNOWN_1);
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend,
+                                       0x61, NULL, DVB_PLL_UNKNOWN_1))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
@@ -613,32 +722,35 @@ static int dvb_register(struct cx8802_dev *dev)
                dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
                                               &dev->vp3054->adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x61,
-                                  TUNER_PHILIPS_FMD1216ME_MK3);
+                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                                       &core->i2c_adap, 0x61,
+                                       TUNER_PHILIPS_FMD1216ME_MK3))
+                               goto frontend_detach;
                }
 #else
-               printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name);
+               printk(KERN_ERR "%s/2: built without vp3054 support\n",
+                               core->name);
 #endif
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
                dev->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_hybrid,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x61,
-                                  TUNER_THOMSON_FE6600);
+                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                                  &core->i2c_adap, 0x61,
+                                  TUNER_THOMSON_FE6600))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
                dev->dvb.frontend = dvb_attach(zl10353_attach,
                                               &dvico_fusionhdtv_xc3028,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend == NULL)
                        dev->dvb.frontend = dvb_attach(mt352_attach,
                                                &dvico_fusionhdtv_mt352_xc3028,
-                                               &dev->core->i2c_adap);
+                                               &core->i2c_adap);
                /*
                 * On this board, the demod provides the I2C bus pullup.
                 * We must not permit gate_ctrl to be performed, or
@@ -651,19 +763,18 @@ static int dvb_register(struct cx8802_dev *dev)
                break;
        case CX88_BOARD_PCHDTV_HD3000:
                dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x61,
-                                  TUNER_THOMSON_DTT761X);
+                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                                       &core->i2c_adap, 0x61,
+                                       TUNER_THOMSON_DTT761X))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
                dev->ts_gen_cntrl = 0x08;
-               {
-               /* Do a hardware reset of chip before using it. */
-               struct cx88_core *core = dev->core;
 
+               /* Do a hardware reset of chip before using it. */
                cx_clear(MO_GP0_IO, 1);
                mdelay(100);
                cx_set(MO_GP0_IO, 1);
@@ -673,144 +784,138 @@ static int dvb_register(struct cx8802_dev *dev)
                fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
                dev->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &fusionhdtv_3_gold,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x61,
-                                  TUNER_MICROTUNE_4042FI5);
-               }
+                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                                       &core->i2c_adap, 0x61,
+                                       TUNER_MICROTUNE_4042FI5))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
                dev->ts_gen_cntrl = 0x08;
-               {
-               /* Do a hardware reset of chip before using it. */
-               struct cx88_core *core = dev->core;
 
+               /* Do a hardware reset of chip before using it. */
                cx_clear(MO_GP0_IO, 1);
                mdelay(100);
                cx_set(MO_GP0_IO, 9);
                mdelay(200);
                dev->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &fusionhdtv_3_gold,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x61,
-                                  TUNER_THOMSON_DTT761X);
-               }
+                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                                       &core->i2c_adap, 0x61,
+                                       TUNER_THOMSON_DTT761X))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
                dev->ts_gen_cntrl = 0x08;
-               {
-               /* Do a hardware reset of chip before using it. */
-               struct cx88_core *core = dev->core;
 
+               /* Do a hardware reset of chip before using it. */
                cx_clear(MO_GP0_IO, 1);
                mdelay(100);
                cx_set(MO_GP0_IO, 1);
                mdelay(200);
                dev->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &fusionhdtv_5_gold,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x61,
-                                  TUNER_LG_TDVS_H06XF);
-                       dvb_attach(tda9887_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x43);
-               }
+                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                                       &core->i2c_adap, 0x61,
+                                       TUNER_LG_TDVS_H06XF))
+                               goto frontend_detach;
+                       if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+                                  &core->i2c_adap, 0x43))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_PCHDTV_HD5500:
                dev->ts_gen_cntrl = 0x08;
-               {
-               /* Do a hardware reset of chip before using it. */
-               struct cx88_core *core = dev->core;
 
+               /* Do a hardware reset of chip before using it. */
                cx_clear(MO_GP0_IO, 1);
                mdelay(100);
                cx_set(MO_GP0_IO, 1);
                mdelay(200);
                dev->dvb.frontend = dvb_attach(lgdt330x_attach,
                                               &pchdtv_hd5500,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x61,
-                                  TUNER_LG_TDVS_H06XF);
-                       dvb_attach(tda9887_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x43);
-               }
+                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                                       &core->i2c_adap, 0x61,
+                                       TUNER_LG_TDVS_H06XF))
+                               goto frontend_detach;
+                       if (!dvb_attach(tda9887_attach, dev->dvb.frontend,
+                                  &core->i2c_adap, 0x43))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_ATI_HDTVWONDER:
                dev->dvb.frontend = dvb_attach(nxt200x_attach,
                                               &ati_hdtvwonder,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       dvb_attach(simple_tuner_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x61,
-                                  TUNER_PHILIPS_TUV1236D);
+                       if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+                                       &core->i2c_adap, 0x61,
+                                       TUNER_PHILIPS_TUV1236D))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
                dev->dvb.frontend = dvb_attach(cx24123_attach,
                                               &hauppauge_novas_config,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend) {
-                       dvb_attach(isl6421_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap, 0x08, 0x00, 0x00);
+                       if (!dvb_attach(isl6421_attach, dev->dvb.frontend,
+                                       &core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_KWORLD_DVBS_100:
                dev->dvb.frontend = dvb_attach(cx24123_attach,
                                               &kworld_dvbs_100_config,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend) {
-                       dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
                        dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
                }
                break;
        case CX88_BOARD_GENIATECH_DVBS:
                dev->dvb.frontend = dvb_attach(cx24123_attach,
                                               &geniatech_dvbs_config,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend) {
-                       dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
                        dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
                }
                break;
        case CX88_BOARD_PINNACLE_PCTV_HD_800i:
                dev->dvb.frontend = dvb_attach(s5h1409_attach,
                                               &pinnacle_pctv_hd_800i_config,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
-                       /* tuner_config.video_dev must point to
-                        * i2c_adap.algo_data
-                        */
-                       pinnacle_pctv_hd_800i_tuner_config.priv =
-                                               dev->core->i2c_adap.algo_data;
-                       dvb_attach(xc5000_attach, dev->dvb.frontend,
-                                  &dev->core->i2c_adap,
-                                  &pinnacle_pctv_hd_800i_tuner_config);
+                       if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+                                       &core->i2c_adap,
+                                       &pinnacle_pctv_hd_800i_tuner_config))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
                dev->dvb.frontend = dvb_attach(s5h1409_attach,
                                                &dvico_hdtv5_pci_nano_config,
-                                               &dev->core->i2c_adap);
+                                               &core->i2c_adap);
                if (dev->dvb.frontend != NULL) {
                        struct dvb_frontend *fe;
                        struct xc2028_config cfg = {
-                               .i2c_adap  = &dev->core->i2c_adap,
+                               .i2c_adap  = &core->i2c_adap,
                                .i2c_addr  = 0x61,
                                .callback  = cx88_pci_nano_callback,
                        };
                        static struct xc2028_ctrl ctl = {
-                               .fname       = "xc3028-v27.fw",
+                               .fname       = XC2028_DEFAULT_FIRMWARE,
                                .max_len     = 64,
                                .scode_table = XC3028_FE_OREN538,
                        };
@@ -824,35 +929,110 @@ static int dvb_register(struct cx8802_dev *dev)
         case CX88_BOARD_PINNACLE_HYBRID_PCTV:
                dev->dvb.frontend = dvb_attach(zl10353_attach,
                                               &cx88_geniatech_x8000_mt,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (attach_xc3028(0x61, dev) < 0)
-                       return -EINVAL;
+                       goto frontend_detach;
                break;
         case CX88_BOARD_GENIATECH_X8000_MT:
                dev->ts_gen_cntrl = 0x00;
 
                dev->dvb.frontend = dvb_attach(zl10353_attach,
                                               &cx88_geniatech_x8000_mt,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (attach_xc3028(0x61, dev) < 0)
-                       return -EINVAL;
+                       goto frontend_detach;
                break;
         case CX88_BOARD_KWORLD_ATSC_120:
                dev->dvb.frontend = dvb_attach(s5h1409_attach,
                                               &kworld_atsc_120_config,
-                                              &dev->core->i2c_adap);
+                                              &core->i2c_adap);
                if (attach_xc3028(0x61, dev) < 0)
-                       return -EINVAL;
+                       goto frontend_detach;
+               break;
+       case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+               dev->dvb.frontend = dvb_attach(s5h1411_attach,
+                                              &dvico_fusionhdtv7_config,
+                                              &core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       if (!dvb_attach(xc5000_attach, dev->dvb.frontend,
+                                       &core->i2c_adap,
+                                       &dvico_fusionhdtv7_tuner_config))
+                               goto frontend_detach;
+               }
+               break;
+       case CX88_BOARD_HAUPPAUGE_HVR4000:
+       case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+               /* Support for DVB-S only, not DVB-T support */
+               dev->dvb.frontend = dvb_attach(cx24116_attach,
+                       &hauppauge_hvr4000_config,
+                       &dev->core->i2c_adap);
+               if (dev->dvb.frontend) {
+                       dvb_attach(isl6421_attach, dev->dvb.frontend,
+                               &dev->core->i2c_adap,
+                               0x08, ISL6421_DCL, 0x00);
+               }
+               break;
+       case CX88_BOARD_TEVII_S420:
+               dev->dvb.frontend = dvb_attach(stv0299_attach,
+                                               &tevii_tuner_sharp_config,
+                                               &core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+                                       &core->i2c_adap, DVB_PLL_OPERA1))
+                               goto frontend_detach;
+                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+
+               } else {
+                       dev->dvb.frontend = dvb_attach(stv0288_attach,
+                                                           &tevii_tuner_earda_config,
+                                                           &core->i2c_adap);
+                               if (dev->dvb.frontend != NULL) {
+                                       if (!dvb_attach(stb6000_attach, dev->dvb.frontend, 0x61,
+                                               &core->i2c_adap))
+                                       goto frontend_detach;
+                               core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                               dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+
+                       }
+               }
+               break;
+       case CX88_BOARD_TEVII_S460:
+               dev->dvb.frontend = dvb_attach(cx24116_attach,
+                                              &tevii_s460_config,
+                                              &core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+               }
+               break;
+       case CX88_BOARD_OMICOM_SS4_PCI:
+               dev->dvb.frontend = dvb_attach(cx24116_attach,
+                                              &hauppauge_hvr4000_config,
+                                              &core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+               }
+               break;
+       case CX88_BOARD_TBS_8920:
+               dev->dvb.frontend = dvb_attach(cx24116_attach,
+                                              &hauppauge_hvr4000_config,
+                                              &core->i2c_adap);
+               if (dev->dvb.frontend != NULL) {
+                       core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+                       dev->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
+               }
                break;
        default:
                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
-                      dev->core->name);
+                      core->name);
                break;
        }
        if (NULL == dev->dvb.frontend) {
                printk(KERN_ERR
                       "%s/2: frontend initialization failed\n",
-                      dev->core->name);
+                      core->name);
                return -EINVAL;
        }
 
@@ -860,11 +1040,18 @@ static int dvb_register(struct cx8802_dev *dev)
        dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
        /* Put the analog decoder in standby to keep it quiet */
-       cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+       cx88_call_i2c_clients(core, TUNER_SET_STANDBY, NULL);
 
        /* register everything */
        return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
                                     &dev->pci->dev, adapter_nr);
+
+frontend_detach:
+       if (dev->dvb.frontend) {
+               dvb_frontend_detach(dev->dvb.frontend);
+               dev->dvb.frontend = NULL;
+       }
+       return -EINVAL;
 }
 
 /* ----------------------------------------------------------- */