diff options
Diffstat (limited to 'linux/drivers/media/video/cx88')
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-cards.c | 37 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-dvb.c | 399 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-i2c.c | 17 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-mpeg.c | 22 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88.h | 6 |
5 files changed, 338 insertions, 143 deletions
diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index a351a2220..eac3508d6 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1303,27 +1303,36 @@ static const struct cx88_board cx88_boards[] = { .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_HVR3000] = { - /* FIXME: Add dvb & radio support */ .name = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T", .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, + .audio_chip = V4L2_IDENT_WM8775, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x84bf, + .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x84bf, + .audioroute = 2, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x84bf, + .audioroute = 2, }}, + /* FIXME Radio tunes but only noise is heard */ + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x84bf, + }, .mpeg = CX88_MPEG_DVB, + .num_frontends = 2, }, [CX88_BOARD_NORWOOD_MICRO] = { .name = "Norwood Micro TV Tuner", @@ -1749,6 +1758,7 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, + .audio_chip = V4L2_IDENT_WM8775, /* * GPIO0 (WINTV2000) * @@ -1762,7 +1772,7 @@ static const struct cx88_board cx88_boards[] = { * BIT VALUE FUNCTION GP{x}_IO * 0 1 I:? * 1 1 I:? - * 2 1 O:DVB-T DEMOD ENABLE LOW/ANALOG DEMOD ENABLE HIGH + * 2 1 O:MPEG PORT 0=DVB-T 1=DVB-S * 3 1 I:? * 4 1 I:? * 5 1 I:? @@ -1783,17 +1793,25 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xc4bf, + .audioroute = 1, }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xc4bf, + .audioroute = 2, }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xc4bf, + .audioroute = 2, } }, - /* fixme: Add radio support */ + /* FIXME Radio tunes but only noise is heard */ + .radio = { + .type = CX88_RADIO, + .gpio0 = 0xc4bf, + }, .mpeg = CX88_MPEG_DVB, + .num_frontends = 2, }, [CX88_BOARD_HAUPPAUGE_HVR4000LITE] = { .name = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2", @@ -2695,10 +2713,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR4000: - case CX88_BOARD_HAUPPAUGE_HVR4000LITE: /* Init GPIO */ cx_write(MO_GP0_IO, core->board.input[0].gpio0); udelay(1000); + cx_clear(MO_GP0_IO, 0x00000080); + udelay(50); + cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */ + udelay(1000); break; } } @@ -3037,10 +3058,14 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); - info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + if (!core->board.num_frontends) + core->board.num_frontends=1; + + info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n", pci->subsystem_vendor, pci->subsystem_device, core->board.name, core->boardnr, card[core->nr] == core->boardnr ? - "insmod option" : "autodetected"); + "insmod option" : "autodetected", + core->board.num_frontends); if (tuner[core->nr] != UNSET) core->board.tuner_type = tuner[core->nr]; diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 84f235ba0..1a0f971c6 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -117,13 +117,23 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) struct cx8802_dev *dev= fe->dvb->priv; struct cx8802_driver *drv = NULL; int ret = 0; + int fe_id; + + fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe); + if (!fe_id) { + printk(KERN_ERR "%s() No frontend found\n", __FUNCTION__); + return -EINVAL; + } drv = cx8802_get_driver(dev, CX88_MPEG_DVB); if (drv) { - if (acquire) + if (acquire){ + dev->frontends.active_fe_id = fe_id; ret = drv->request_acquire(drv); - else + } else { ret = drv->request_release(drv); + dev->frontends.active_fe_id = 0; + } } return ret; @@ -490,6 +500,7 @@ static struct xc5000_config dvico_fusionhdtv7_tuner_config = { static int attach_xc3028(u8 addr, struct cx8802_dev *dev) { struct dvb_frontend *fe; + struct videobuf_dvb_frontend *fe0 = NULL; struct xc2028_ctrl ctl; struct xc2028_config cfg = { .i2c_adap = &dev->core->i2c_adap, @@ -497,7 +508,12 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) .ctrl = &ctl, }; - if (!dev->dvb.frontend) { + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); + if (!fe0) + return -EINVAL; + + if (!fe0->dvb.frontend) { printk(KERN_ERR "%s/2: dvb frontend not attached. " "Can't attach xc3028\n", dev->core->name); @@ -511,10 +527,13 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) */ cx88_setup_xc3028(dev->core, &ctl); - fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg); + fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); if (!fe) { printk(KERN_ERR "%s/2: xc3028 attach failed\n", dev->core->name); + dvb_frontend_detach(fe0->dvb.frontend); + dvb_unregister_frontend(fe0->dvb.frontend); + fe0->dvb.frontend = NULL; return -EINVAL; } @@ -539,8 +558,10 @@ static int cx24116_reset_device(struct dvb_frontend *fe) struct cx88_core *core = dev->core; /* Reset the part */ + /* Put the cx24116 into reset */ cx_write(MO_SRST_IO, 0); msleep(10); + /* Take the cx24116 out of reset */ cx_write(MO_SRST_IO, 1); msleep(10); @@ -581,19 +602,25 @@ static struct stv0288_config tevii_tuner_earda_config = { static int dvb_register(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; + struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + int mfe_shared = 0; /* bus not shared by default */ - /* init struct videobuf_dvb */ - dev->dvb.name = core->name; - dev->ts_gen_cntrl = 0x0c; + /* Get the first frontend */ + fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); + if (!fe0) + return -EINVAL; - /* init frontend */ + /* multi-frontend gate control is undefined or defaults to fe0 */ + dev->frontends.gate = 0; + + /* init frontend(s) */ switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_DVB_T1: - dev->dvb.frontend = dvb_attach(cx22702_attach, + fe0->dvb.frontend = dvb_attach(cx22702_attach, &connexant_refboard_config, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61, &core->i2c_adap, DVB_PLL_THOMSON_DTT759X)) goto frontend_detach; @@ -603,11 +630,11 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_CONEXANT_DVB_T1: case CX88_BOARD_KWORLD_DVB_T_CX22702: case CX88_BOARD_WINFAST_DTV1000: - dev->dvb.frontend = dvb_attach(cx22702_attach, + fe0->dvb.frontend = dvb_attach(cx22702_attach, &connexant_refboard_config, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, &core->i2c_adap, DVB_PLL_THOMSON_DTT7579)) goto frontend_detach; @@ -617,33 +644,67 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1100LP: case CX88_BOARD_HAUPPAUGE_HVR1300: - case CX88_BOARD_HAUPPAUGE_HVR3000: - dev->dvb.frontend = dvb_attach(cx22702_attach, + fe0->dvb.frontend = dvb_attach(cx22702_attach, &hauppauge_hvr_config, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) goto frontend_detach; } break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + /* DVB-S init */ + fe0->dvb.frontend = dvb_attach(cx24123_attach, + &hauppauge_novas_config, + &dev->core->i2c_adap); + if (fe0->dvb.frontend) { + if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, + &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) { + dprintk( 1, "%s(): HVR3000 - DVB-S LNB Init: failed\n", __FUNCTION__); + } + } else { + dprintk( 1, "%s(): HVR3000 - DVB-S Init: failed\n", __FUNCTION__); + } + /* DVB-T init */ + fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); + if (fe1) { + dev->frontends.gate = 2; + mfe_shared = 1; + fe1->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (fe1->dvb.frontend) { + fe1->dvb.frontend->id = 1; + if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend, + &dev->core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3)) { + dprintk( 1, "%s(): HVR3000 - DVB-T misc Init: failed\n", __FUNCTION__); + } + } else { + dprintk( 1, "%s(): HVR3000 - DVB-T Init: failed\n", __FUNCTION__); + } + } else { + dprintk( 1, "%s(): HVR3000 - DVB-T Init: can't find frontend 2.\n", __FUNCTION__); + } + break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: - dev->dvb.frontend = dvb_attach(mt352_attach, + fe0->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->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, + fe0->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_plus_v1_1, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, NULL, DVB_PLL_THOMSON_DTT7579)) goto frontend_detach; } @@ -651,31 +712,31 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: /* The tin box says DEE1601, but it seems to be DTT7579 * compatible, with a slightly different MT352 AGC gain. */ - dev->dvb.frontend = dvb_attach(mt352_attach, + fe0->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv_dual, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->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, + fe0->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_plus_v1_1, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->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, + fe0->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61, NULL, DVB_PLL_LG_Z201)) goto frontend_detach; } @@ -683,11 +744,11 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_KWORLD_DVB_T: case CX88_BOARD_DNTV_LIVE_DVB_T: case CX88_BOARD_ADSTECH_DVB_T_PCI: - dev->dvb.frontend = dvb_attach(mt352_attach, + fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_config, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(dvb_pll_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61, NULL, DVB_PLL_UNKNOWN_1)) goto frontend_detach; } @@ -695,10 +756,10 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: #if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) /* MT352 is on a secondary I2C bus made from some GPIO lines */ - dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config, + fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config, &dev->vp3054->adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) goto frontend_detach; @@ -709,22 +770,22 @@ static int dvb_register(struct cx8802_dev *dev) #endif break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: - dev->dvb.frontend = dvb_attach(zl10353_attach, + fe0->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_hybrid, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->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, + fe0->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_xc3028, &core->i2c_adap); - if (dev->dvb.frontend == NULL) - dev->dvb.frontend = dvb_attach(mt352_attach, + if (fe0->dvb.frontend == NULL) + fe0->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv_mt352_xc3028, &core->i2c_adap); /* @@ -732,16 +793,16 @@ static int dvb_register(struct cx8802_dev *dev) * We must not permit gate_ctrl to be performed, or * the xc3028 cannot communicate on the bus. */ - if (dev->dvb.frontend) - dev->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (fe0->dvb.frontend) + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; if (attach_xc3028(0x61, dev) < 0) return -EINVAL; break; case CX88_BOARD_PCHDTV_HD3000: - dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000, + fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) goto frontend_detach; @@ -758,11 +819,11 @@ static int dvb_register(struct cx8802_dev *dev) /* Select RF connector callback */ fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set; - dev->dvb.frontend = dvb_attach(lgdt330x_attach, + fe0->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_3_gold, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_MICROTUNE_4042FI5)) goto frontend_detach; @@ -776,11 +837,11 @@ static int dvb_register(struct cx8802_dev *dev) mdelay(100); cx_set(MO_GP0_IO, 9); mdelay(200); - dev->dvb.frontend = dvb_attach(lgdt330x_attach, + fe0->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_3_gold, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) goto frontend_detach; @@ -794,15 +855,15 @@ static int dvb_register(struct cx8802_dev *dev) mdelay(100); cx_set(MO_GP0_IO, 1); mdelay(200); - dev->dvb.frontend = dvb_attach(lgdt330x_attach, + fe0->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_5_gold, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF)) goto frontend_detach; - if (!dvb_attach(tda9887_attach, dev->dvb.frontend, + if (!dvb_attach(tda9887_attach, fe0->dvb.frontend, &core->i2c_adap, 0x43)) goto frontend_detach; } @@ -815,25 +876,25 @@ static int dvb_register(struct cx8802_dev *dev) mdelay(100); cx_set(MO_GP0_IO, 1); mdelay(200); - dev->dvb.frontend = dvb_attach(lgdt330x_attach, + fe0->dvb.frontend = dvb_attach(lgdt330x_attach, &pchdtv_hd5500, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF)) goto frontend_detach; - if (!dvb_attach(tda9887_attach, dev->dvb.frontend, + if (!dvb_attach(tda9887_attach, fe0->dvb.frontend, &core->i2c_adap, 0x43)) goto frontend_detach; } break; case CX88_BOARD_ATI_HDTVWONDER: - dev->dvb.frontend = dvb_attach(nxt200x_attach, + fe0->dvb.frontend = dvb_attach(nxt200x_attach, &ati_hdtvwonder, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(simple_tuner_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_PHILIPS_TUV1236D)) goto frontend_detach; @@ -841,49 +902,49 @@ static int dvb_register(struct cx8802_dev *dev) break; case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: - dev->dvb.frontend = dvb_attach(cx24123_attach, + fe0->dvb.frontend = dvb_attach(cx24123_attach, &hauppauge_novas_config, &core->i2c_adap); - if (dev->dvb.frontend) { - if (!dvb_attach(isl6421_attach, dev->dvb.frontend, + if (fe0->dvb.frontend) { + if (!dvb_attach(isl6421_attach, fe0->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, + fe0->dvb.frontend = dvb_attach(cx24123_attach, &kworld_dvbs_100_config, &core->i2c_adap); - if (dev->dvb.frontend) { - core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage; - dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage; + if (fe0->dvb.frontend) { + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage; } break; case CX88_BOARD_GENIATECH_DVBS: - dev->dvb.frontend = dvb_attach(cx24123_attach, + fe0->dvb.frontend = dvb_attach(cx24123_attach, &geniatech_dvbs_config, &core->i2c_adap); - if (dev->dvb.frontend) { - core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage; - dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; + if (fe0->dvb.frontend) { + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; } break; case CX88_BOARD_PINNACLE_PCTV_HD_800i: - dev->dvb.frontend = dvb_attach(s5h1409_attach, + fe0->dvb.frontend = dvb_attach(s5h1409_attach, &pinnacle_pctv_hd_800i_config, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { - if (!dvb_attach(xc5000_attach, dev->dvb.frontend, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(xc5000_attach, fe0->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, + fe0->dvb.frontend = dvb_attach(s5h1409_attach, &dvico_hdtv5_pci_nano_config, &core->i2c_adap); - if (dev->dvb.frontend != NULL) { + if (fe0->dvb.frontend != NULL) { struct dvb_frontend *fe; struct xc2028_config cfg = { .i2c_adap = &core->i2c_adap, @@ -896,17 +957,17 @@ static int dvb_register(struct cx8802_dev *dev) }; fe = dvb_attach(xc2028_attach, - dev->dvb.frontend, &cfg); + fe0->dvb.frontend, &cfg); if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) fe->ops.tuner_ops.set_config(fe, &ctl); } break; case CX88_BOARD_PINNACLE_HYBRID_PCTV: - dev->dvb.frontend = dvb_attach(zl10353_attach, + fe0->dvb.frontend = dvb_attach(zl10353_attach, &cx88_pinnacle_hybrid_pctv, &core->i2c_adap); - if (dev->dvb.frontend) { - dev->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (fe0->dvb.frontend) { + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; if (attach_xc3028(0x61, dev) < 0) goto frontend_detach; } @@ -914,85 +975,118 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_GENIATECH_X8000_MT: dev->ts_gen_cntrl = 0x00; - dev->dvb.frontend = dvb_attach(zl10353_attach, + fe0->dvb.frontend = dvb_attach(zl10353_attach, &cx88_geniatech_x8000_mt, &core->i2c_adap); if (attach_xc3028(0x61, dev) < 0) goto frontend_detach; break; case CX88_BOARD_KWORLD_ATSC_120: - dev->dvb.frontend = dvb_attach(s5h1409_attach, + fe0->dvb.frontend = dvb_attach(s5h1409_attach, &kworld_atsc_120_config, &core->i2c_adap); if (attach_xc3028(0x61, dev) < 0) goto frontend_detach; break; case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: - dev->dvb.frontend = dvb_attach(s5h1411_attach, + fe0->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, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(xc5000_attach, fe0->dvb.frontend, &core->i2c_adap, &dvico_fusionhdtv7_tuner_config)) goto frontend_detach; } break; case CX88_BOARD_HAUPPAUGE_HVR4000: + /* DVB-S/S2 Init */ + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &hauppauge_hvr4000_config, + &dev->core->i2c_adap); + if (fe0->dvb.frontend) { + if(!dvb_attach(isl6421_attach, fe0->dvb.frontend, + &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) { + dprintk( 1, "%s(): HVR4000 - DVB-S LNB Init: failed\n", __FUNCTION__); + } + } else { + dprintk( 1, "%s(): HVR4000 - DVB-S Init: failed\n", __FUNCTION__); + } + /* DVB-T Init */ + fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); + if (fe1) { + dev->frontends.gate = 2; + mfe_shared = 1; + fe1->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (fe1->dvb.frontend) { + fe1->dvb.frontend->id = 1; + if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend, + &dev->core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3)) { + dprintk( 1, "%s(): HVR4000 - DVB-T misc Init: failed\n", __FUNCTION__); + } + } else { + dprintk( 1, "%s(): HVR4000 - DVB-T Init: failed\n", __FUNCTION__); + } + } else { + dprintk( 1, "%s(): HVR4000 - DVB-T Init: can't find frontend 2.\n", __FUNCTION__); + } + break; case CX88_BOARD_HAUPPAUGE_HVR4000LITE: - /* Support for DVB-S only, not DVB-T support */ - dev->dvb.frontend = dvb_attach(cx24116_attach, + fe0->dvb.frontend = dvb_attach(cx24116_attach, &hauppauge_hvr4000_config, &dev->core->i2c_adap); - if (dev->dvb.frontend) { - dvb_attach(isl6421_attach, dev->dvb.frontend, + if (fe0->dvb.frontend) { + dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00); } break; case CX88_BOARD_TEVII_S420: - dev->dvb.frontend = dvb_attach(stv0299_attach, + fe0->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, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(dvb_pll_attach, fe0->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; + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; } else { - dev->dvb.frontend = dvb_attach(stv0288_attach, + fe0->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, + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(stb6000_attach, fe0->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; + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; } } break; case CX88_BOARD_TEVII_S460: - dev->dvb.frontend = dvb_attach(cx24116_attach, + fe0->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; + if (fe0->dvb.frontend != NULL) { + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; } break; case CX88_BOARD_OMICOM_SS4_PCI: case CX88_BOARD_TBS_8920: case CX88_BOARD_PROF_7300: - dev->dvb.frontend = dvb_attach(cx24116_attach, + fe0->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; + if (fe0->dvb.frontend != NULL) { + core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; } break; default: @@ -1000,29 +1094,32 @@ static int dvb_register(struct cx8802_dev *dev) core->name); break; } - if (NULL == dev->dvb.frontend) { + + if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) { printk(KERN_ERR "%s/2: frontend initialization failed\n", core->name); return -EINVAL; } /* define general-purpose callback pointer */ - dev->dvb.frontend->callback = cx88_tuner_callback; + fe0->dvb.frontend->callback = cx88_tuner_callback; /* Ensure all frontends negotiate bus access */ - dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; + fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; + if (fe1) + fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; /* Put the analog decoder in standby to keep it quiet */ 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); + return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, + &dev->pci->dev, adapter_nr, mfe_shared); frontend_detach: - if (dev->dvb.frontend) { - dvb_frontend_detach(dev->dvb.frontend); - dev->dvb.frontend = NULL; + if (fe0->dvb.frontend) { + dvb_frontend_detach(fe0->dvb.frontend); + fe0->dvb.frontend = NULL; } return -EINVAL; } @@ -1046,6 +1143,38 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) cx_clear(MO_GP0_IO, 0x00000004); udelay(1000); break; + + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + if(core->dvbdev->frontends.active_fe_id == 1) { + /* DVB-S/S2 Enabled */ + + /* Toggle reset on cx22702 leaving i2c active */ + cx_write(MO_GP0_IO, (core->board.input[0].gpio0 & 0x0000ff00) | 0x00000080); + udelay(1000); + cx_clear(MO_GP0_IO, 0x00000080); + udelay(50); + cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset */ + cx_set(MO_GP0_IO, 0x00000004); /* tri-state the cx22702 pins */ + udelay(1000); + + cx_write(MO_SRST_IO, 1); /* Take the cx24116/cx24123 out of reset */ + core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */ + } else + if (core->dvbdev->frontends.active_fe_id == 2) { + /* DVB-T Enabled */ + + /* Put the cx24116/cx24123 into reset */ + cx_write(MO_SRST_IO, 0); + + /* cx22702 out of reset and enable it */ + cx_set(MO_GP0_IO, 0x00000080); + cx_clear(MO_GP0_IO, 0x00000004); + core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */ + udelay(1000); + } + break; + default: err = -ENODEV; } @@ -1066,6 +1195,9 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv) cx_set(MO_GP0_IO, 0x00000004); #endif break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + break; default: err = -ENODEV; } @@ -1076,7 +1208,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) { struct cx88_core *core = drv->core; struct cx8802_dev *dev = drv->core->dvbdev; - int err; + int err, i; + struct videobuf_dvb_frontend *fe; dprintk( 1, "%s\n", __func__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", @@ -1096,18 +1229,28 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) /* dvb stuff */ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); - videobuf_queue_sg_init(&dev->dvb.dvbq, &dvb_qops, + dev->ts_gen_cntrl = 0x0c; + + for (i = 1; i <= core->board.num_frontends; i++) { + fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i); + if (!fe) { + printk(KERN_ERR "%s() failed to get frontend(%d)\n", __FUNCTION__, i); + continue; + } + videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops, &dev->pci->dev, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, sizeof(struct cx88_buffer), dev); + /* init struct videobuf_dvb */ + fe->dvb.name = dev->core->name; + } err = dvb_register(dev); if (err != 0) printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n", core->name, err); - - fail_core: +fail_core: return err; } @@ -1115,9 +1258,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv) { struct cx8802_dev *dev = drv->core->dvbdev; - /* dvb */ - if (dev->dvb.frontend) - videobuf_dvb_unregister(&dev->dvb); + videobuf_dvb_unregister_bus(&dev->frontends); vp3054_i2c_remove(dev); diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c index 8e74d64fd..01de23007 100644 --- a/linux/drivers/media/video/cx88/cx88-i2c.c +++ b/linux/drivers/media/video/cx88/cx88-i2c.c @@ -116,18 +116,25 @@ static int detach_inform(struct i2c_client *client) void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg) { + struct videobuf_dvb_frontends *f = &core->dvbdev->frontends; + struct videobuf_dvb_frontend *fe = NULL; if (0 != core->i2c_rc) return; #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) - if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) { - if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl) - core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1); + if (core->dvbdev && f) { + if(f->gate <= 1) /* undefined or fe0 */ + fe = videobuf_dvb_get_frontend(f, 1); + else + fe = videobuf_dvb_get_frontend(f, f->gate); + + if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) + fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, 1); i2c_clients_command(&core->i2c_adap, cmd, arg); - if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl) - core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0); + if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) + fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, 0); } else #endif i2c_clients_command(&core->i2c_adap, cmd, arg); diff --git a/linux/drivers/media/video/cx88/cx88-mpeg.c b/linux/drivers/media/video/cx88/cx88-mpeg.c index 4af6604ec..88c237790 100644 --- a/linux/drivers/media/video/cx88/cx88-mpeg.c +++ b/linux/drivers/media/video/cx88/cx88-mpeg.c @@ -808,7 +808,8 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, { struct cx8802_dev *dev; struct cx88_core *core; - int err; + struct videobuf_dvb_frontend *demod; + int err,i; /* general setup */ core = cx88_core_get(pci_dev); @@ -821,6 +822,11 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, if (!core->board.mpeg) goto fail_core; + if (!core->board.num_frontends) { + printk(KERN_ERR "%s() .num_frontends should be non-zero, err = %d\n", __FUNCTION__, err); + goto fail_core; + } + err = -ENOMEM; dev = kzalloc(sizeof(*dev),GFP_KERNEL); if (NULL == dev) @@ -835,6 +841,20 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, INIT_LIST_HEAD(&dev->drvlist); list_add_tail(&dev->devlist,&cx8802_devlist); + mutex_init(&dev->frontends.lock); + INIT_LIST_HEAD(&dev->frontends.frontend.felist); + + printk(KERN_INFO "%s() allocating %d frontend(s)\n", __FUNCTION__, core->board.num_frontends); + + for (i = 1; i <= core->board.num_frontends; i++) { + demod = videobuf_dvb_alloc_frontend(dev, &dev->frontends, i); + if(demod == NULL) { + printk(KERN_ERR "%s() failed to alloc\n", __FUNCTION__); + err = -ENOMEM; + goto fail_free; + } + } + /* Maintain a reference so cx88-video can query the 8802 device. */ core->dvbdev = dev; diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 778e1f707..774c0b9b1 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -248,7 +248,7 @@ struct cx88_input { enum cx88_itype type; u32 gpio0, gpio1, gpio2, gpio3; unsigned int vmux:2; - unsigned int audioroute:2; + unsigned int audioroute:4; }; struct cx88_board { @@ -262,6 +262,7 @@ struct cx88_board { struct cx88_input radio; enum cx88_board_type mpeg; unsigned int audio_chip; + int num_frontends; }; struct cx88_subid { @@ -360,6 +361,7 @@ struct cx88_core { struct cx8802_dev *dvbdev; enum cx88_board_type active_type_id; int active_ref; + int active_fe_id; }; struct cx8800_dev; @@ -511,7 +513,7 @@ struct cx8802_dev { #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) /* for dvb only */ - struct videobuf_dvb dvb; + struct videobuf_dvb_frontends frontends; #endif #if defined(CONFIG_VIDEO_CX88_VP3054) || \ |