diff options
Diffstat (limited to 'drivers/media/video/cx88')
-rw-r--r-- | drivers/media/video/cx88/Kconfig | 4 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-blackbird.c | 8 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-cards.c | 306 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-dvb.c | 198 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-i2c.c | 16 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-input.c | 33 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-video.c | 15 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88.h | 11 |
8 files changed, 521 insertions, 70 deletions
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 9dd7bdf659b9..0b9e5fac6239 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -58,6 +58,10 @@ config VIDEO_CX88_DVB select DVB_ISL6421 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE + select DVB_CX24116 if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_STV0288 if !DVB_FE_CUSTOMISE + select DVB_STB6000 if !DVB_FE_CUSTOMISE ---help--- This adds support for DVB/ATSC cards based on the Conexant 2388x chip. diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 6b922066a660..e71369754305 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1057,12 +1057,15 @@ static int mpeg_open(struct inode *inode, struct file *file) struct cx8802_driver *drv = NULL; int err; + lock_kernel(); dev = cx8802_get_device(inode); dprintk( 1, "%s\n", __func__); - if (dev == NULL) + if (dev == NULL) { + unlock_kernel(); return -ENODEV; + } /* Make sure we can acquire the hardware */ drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); @@ -1078,6 +1081,7 @@ static int mpeg_open(struct inode *inode, struct file *file) if (blackbird_initialize_codec(dev) < 0) { if (drv) drv->request_release(drv); + unlock_kernel(); return -EINVAL; } dprintk(1,"open minor=%d\n",minor); @@ -1087,6 +1091,7 @@ static int mpeg_open(struct inode *inode, struct file *file) if (NULL == fh) { if (drv) drv->request_release(drv); + unlock_kernel(); return -ENOMEM; } file->private_data = fh; @@ -1102,6 +1107,7 @@ static int mpeg_open(struct inode *inode, struct file *file) /* FIXME: locking against other video device */ cx88_set_scale(dev->core, dev->width, dev->height, fh->mpegq.field); + unlock_kernel(); return 0; } diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index de199a206a15..5da04e811ca2 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1349,27 +1349,30 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .audio_chip = V4L2_IDENT_WM8775, + /* + * gpio0 as reported by Mike Crash <mike AT mikecrash.com> + */ .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0xe780, + .gpio0 = 0xef88, .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio0 = 0xe780, + .gpio0 = 0xef88, .audioroute = 2, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, - .gpio0 = 0xe780, + .gpio0 = 0xef88, .audioroute = 2, }}, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, .radio = { .type = CX88_RADIO, - .gpio0 = 0xe780, + .gpio0 = 0xef88, }, }, [CX88_BOARD_ADSTECH_PTV_390] = { @@ -1446,15 +1449,26 @@ static const struct cx88_board cx88_boards[] = { .name = "Pinnacle Hybrid PCTV", .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, + .radio_type = TUNER_XC2028, + .radio_addr = 0x61, .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, + .gpio0 = 0x004ff, + .gpio1 = 0x010ff, + .gpio2 = 0x00001, }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, + .gpio0 = 0x004fb, + .gpio1 = 0x010ef, + .audioroute = 1, }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, + .gpio0 = 0x004fb, + .gpio1 = 0x010ef, + .audioroute = 1, } }, .radio = { .type = CX88_RADIO, @@ -1462,6 +1476,7 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0x010ff, .gpio2 = 0x0ff, }, + .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = { .name = "Winfast TV2000 XP Global", @@ -1566,9 +1581,9 @@ static const struct cx88_board cx88_boards[] = { }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO] = { .name = "DViCO FusionHDTV DVB-T PRO", - .tuner_type = TUNER_ABSENT, /* XXX: Has XC3028 */ + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .input = { { .type = CX88_VMUX_COMPOSITE1, @@ -1625,6 +1640,36 @@ static const struct cx88_board cx88_boards[] = { .gpio2 = 0x0cfb, }, }, + [CX88_BOARD_PROLINK_PV_GLOBAL_XTREME] = { + .name = "Prolink Pixelview Global Extreme", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x04fb, + .gpio1 = 0x04080, + .gpio2 = 0x0cf7, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x04fb, + .gpio1 = 0x04080, + .gpio2 = 0x0cfb, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x04fb, + .gpio1 = 0x04080, + .gpio2 = 0x0cfb, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x04ff, + .gpio1 = 0x04080, + .gpio2 = 0x0cf7, + }, + }, /* Both radio, analog and ATSC work with this board. However, for analog to work, s5h1409 gate should be open, otherwise, tuner-xc3028 won't be detected. @@ -1664,6 +1709,131 @@ static const struct cx88_board cx88_boards[] = { }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_HAUPPAUGE_HVR4000] = { + .name = "Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + /* + * GPIO0 (WINTV2000) + * + * Analogue SAT DVB-T + * Antenna 0xc4bf 0xc4bb + * Composite 0xc4bf 0xc4bb + * S-Video 0xc4bf 0xc4bb + * Composite1 0xc4ff 0xc4fb + * S-Video1 0xc4ff 0xc4fb + * + * BIT VALUE FUNCTION GP{x}_IO + * 0 1 I:? + * 1 1 I:? + * 2 1 O:DVB-T DEMOD ENABLE LOW/ANALOG DEMOD ENABLE HIGH + * 3 1 I:? + * 4 1 I:? + * 5 1 I:? + * 6 0 O:INPUT SELECTOR 0=INTERNAL 1=EXPANSION + * 7 1 O:DVB-T DEMOD RESET LOW + * + * BIT VALUE FUNCTION GP{x}_OE + * 8 0 I + * 9 0 I + * a 1 O + * b 0 I + * c 0 I + * d 0 I + * e 1 O + * f 1 O + */ + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0xc4bf, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0xc4bf, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0xc4bf, + } }, + /* fixme: Add radio support */ + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_HAUPPAUGE_HVR4000LITE] = { + .name = "Hauppauge WinTV-HVR4000(Lite) DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TEVII_S420] = { + .name = "TeVii S420 DVB-S", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TEVII_S460] = { + .name = "TeVii S460 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_OMICOM_SS4_PCI] = { + .name = "Omicom SS4 DVB-S/S2 PCI", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_TBS_8920] = { + .name = "TBS 8920 DVB-S/S2", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 1, + } }, + .mpeg = CX88_MPEG_DVB, + }, + [CX88_BOARD_PROF_7300] = { + .name = "PROF 7300 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, }; /* ------------------------------------------------------------------ */ @@ -2010,9 +2180,53 @@ static const struct cx88_subid cx88_subids[] = { .subdevice = 0x4935, .card = CX88_BOARD_PROLINK_PV_8000GT, }, { + .subvendor = 0x1554, + .subdevice = 0x4976, + .card = CX88_BOARD_PROLINK_PV_GLOBAL_XTREME, + }, { .subvendor = 0x17de, .subdevice = 0x08c1, .card = CX88_BOARD_KWORLD_ATSC_120, + }, { + .subvendor = 0x0070, + .subdevice = 0x6900, + .card = CX88_BOARD_HAUPPAUGE_HVR4000, + }, { + .subvendor = 0x0070, + .subdevice = 0x6904, + .card = CX88_BOARD_HAUPPAUGE_HVR4000, + }, { + .subvendor = 0x0070, + .subdevice = 0x6902, + .card = CX88_BOARD_HAUPPAUGE_HVR4000, + }, { + .subvendor = 0x0070, + .subdevice = 0x6905, + .card = CX88_BOARD_HAUPPAUGE_HVR4000LITE, + }, { + .subvendor = 0x0070, + .subdevice = 0x6906, + .card = CX88_BOARD_HAUPPAUGE_HVR4000LITE, + }, { + .subvendor = 0xd420, + .subdevice = 0x9022, + .card = CX88_BOARD_TEVII_S420, + }, { + .subvendor = 0xd460, + .subdevice = 0x9022, + .card = CX88_BOARD_TEVII_S460, + }, { + .subvendor = 0xA044, + .subdevice = 0x2011, + .card = CX88_BOARD_OMICOM_SS4_PCI, + }, { + .subvendor = 0x8920, + .subdevice = 0x8888, + .card = CX88_BOARD_TBS_8920, + }, { + .subvendor = 0xB033, + .subdevice = 0x3033, + .card = CX88_BOARD_PROF_7300, }, }; @@ -2065,6 +2279,13 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */ case 28552: /* WinTV-PVR 'Roslyn' (No IR) */ case 34519: /* WinTV-PCI-FM */ + case 69009: + /* WinTV-HVR4000 (DVBS/S2/T, Video and IR, back panel inputs) */ + case 69100: /* WinTV-HVR4000LITE (DVBS/S2, IR) */ + case 69500: /* WinTV-HVR4000LITE (DVBS/S2, No IR) */ + case 69559: + /* WinTV-HVR4000 (DVBS/S2/T, Video no IR, back panel inputs) */ + case 69569: /* WinTV-HVR4000 (DVBS/S2/T, Video no IR) */ case 90002: /* Nova-T-PCI (9002) */ case 92001: /* Nova-S-Plus (Video and IR) */ case 92002: /* Nova-S-Plus (Video and IR) */ @@ -2149,9 +2370,21 @@ static int cx88_dvico_xc2028_callback(struct cx88_core *core, { switch (command) { case XC2028_TUNER_RESET: - cx_write(MO_GP0_IO, 0x101000); - mdelay(5); - cx_set(MO_GP0_IO, 0x101010); + switch (core->boardnr) { + case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: + /* GPIO-4 xc3028 tuner */ + + cx_set(MO_GP0_IO, 0x00001000); + cx_clear(MO_GP0_IO, 0x00000010); + msleep(100); + cx_set(MO_GP0_IO, 0x00000010); + msleep(100); + break; + default: + cx_write(MO_GP0_IO, 0x101000); + mdelay(5); + cx_set(MO_GP0_IO, 0x101010); + } break; default: return -EINVAL; @@ -2258,8 +2491,10 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core, return cx88_xc3028_geniatech_tuner_callback(core, command, arg); case CX88_BOARD_PROLINK_PV_8000GT: + case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: return cx88_pv_8000gt_callback(core, command, arg); case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: + case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: return cx88_dvico_xc2028_callback(core, command, arg); } @@ -2327,7 +2562,7 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core, return 0; /* Should never be here */ } -int cx88_tuner_callback(void *priv, int command, int arg) +int cx88_tuner_callback(void *priv, int component, int command, int arg) { struct i2c_algo_bit_data *i2c_algo = priv; struct cx88_core *core; @@ -2344,6 +2579,9 @@ int cx88_tuner_callback(void *priv, int command, int arg) return -EINVAL; } + if (component != DVB_FRONTEND_COMPONENT_TUNER) + return -EINVAL; + switch (core->board.tuner_type) { case TUNER_XC2028: info_printk(core, "Calling XC2028/3028 callback\n"); @@ -2392,16 +2630,22 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) { switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: - /* Bring the 702 demod up before i2c scanning/attach or devices are hidden */ - /* We leave here with the 702 on the bus */ - cx_write(MO_GP0_IO, 0x0000e780); + /* + * Bring the 702 demod up before i2c scanning/attach or devices are hidden + * We leave here with the 702 on the bus + * + * "reset the IR receiver on GPIO[3]" + * Reported by Mike Crash <mike AT mikecrash.com> + */ + cx_write(MO_GP0_IO, 0x0000ef88); udelay(1000); - cx_clear(MO_GP0_IO, 0x00000080); + cx_clear(MO_GP0_IO, 0x00000088); udelay(50); - cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */ + cx_set(MO_GP0_IO, 0x00000088); /* 702 out of reset */ udelay(1000); break; + case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: case CX88_BOARD_PROLINK_PV_8000GT: cx_write(MO_GP2_IO, 0xcf7); mdelay(50); @@ -2411,10 +2655,18 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) msleep(10); break; - case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: + case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: /* Enable the xc5000 tuner */ cx_set(MO_GP0_IO, 0x00001010); break; + + 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); + break; } } @@ -2435,17 +2687,22 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl) core->i2c_algo.udelay = 16; break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: - ctl->scode_table = XC3028_FE_ZARLINK456; + ctl->demod = XC3028_FE_ZARLINK456; break; case CX88_BOARD_KWORLD_ATSC_120: case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: ctl->demod = XC3028_FE_OREN538; break; + case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: case CX88_BOARD_PROLINK_PV_8000GT: /* - * This board uses non-MTS firmware + * Those boards uses non-MTS firmware */ break; + case CX88_BOARD_PINNACLE_HYBRID_PCTV: + ctl->demod = XC3028_FE_ZARLINK456; + ctl->mts = 1; + break; default: ctl->demod = XC3028_FE_OREN538; ctl->mts = 1; @@ -2489,6 +2746,8 @@ static void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR1100LP: case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR1300: + case CX88_BOARD_HAUPPAUGE_HVR4000: + case CX88_BOARD_HAUPPAUGE_HVR4000LITE: if (0 == core->i2c_rc) hauppauge_eeprom(core, eeprom); break; @@ -2570,7 +2829,18 @@ static void cx88_card_setup(struct cx88_core *core) tea5767_cfg.priv = &ctl; cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg); + break; } + case CX88_BOARD_TEVII_S420: + case CX88_BOARD_TEVII_S460: + case CX88_BOARD_OMICOM_SS4_PCI: + case CX88_BOARD_TBS_8920: + case CX88_BOARD_PROF_7300: + cx_write(MO_SRST_IO, 0); + msleep(100); + cx_write(MO_SRST_IO, 1); + msleep(100); + break; } /*end switch() */ diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index d96173ff1dba..344ed2626e59 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -48,6 +48,11 @@ #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>"); @@ -375,37 +380,28 @@ static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, return 0; } -static int cx88_pci_nano_callback(void *ptr, int command, int arg) +static int tevii_dvbs_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) { - struct cx88_core *core = ptr; - - switch (command) { - case XC2028_TUNER_RESET: - /* Send the tuner in then out of reset */ - dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg); - - switch (core->boardnr) { - case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: - /* GPIO-4 xc3028 tuner */ - - cx_set(MO_GP0_IO, 0x00001000); - cx_clear(MO_GP0_IO, 0x00000010); - msleep(100); - cx_set(MO_GP0_IO, 0x00000010); - msleep(100); - break; - } + struct cx8802_dev *dev= fe->dvb->priv; + struct cx88_core *core = dev->core; - break; - case XC2028_RESET_CLK: - dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg); - break; - default: - dprintk(1, "%s: unknown command %d, arg %d\n", __func__, - command, arg); - return -EINVAL; + 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; } @@ -456,7 +452,12 @@ static struct s5h1409_config kworld_atsc_120_config = { static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { .i2c_address = 0x64, .if_khz = 5380, - .tuner_callback = cx88_tuner_callback, +}; + +static struct zl10353_config cx88_pinnacle_hybrid_pctv = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .if2 = 45600, }; static struct zl10353_config cx88_geniatech_x8000_mt = { @@ -477,7 +478,6 @@ static struct s5h1411_config dvico_fusionhdtv7_config = { 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) @@ -488,7 +488,6 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) .i2c_adap = &dev->core->i2c_adap, .i2c_addr = addr, .ctrl = &ctl, - .callback = cx88_tuner_callback, }; if (!dev->dvb.frontend) { @@ -518,6 +517,60 @@ 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; @@ -786,7 +839,7 @@ static int dvb_register(struct cx8802_dev *dev) &core->i2c_adap); if (dev->dvb.frontend) { if (!dvb_attach(isl6421_attach, dev->dvb.frontend, - &core->i2c_adap, 0x08, 0x00, 0x00)) + &core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) goto frontend_detach; } break; @@ -813,13 +866,9 @@ static int dvb_register(struct cx8802_dev *dev) &pinnacle_pctv_hd_800i_config, &core->i2c_adap); if (dev->dvb.frontend != NULL) { - /* tuner_config.video_dev must point to - * i2c_adap.algo_data - */ if (!dvb_attach(xc5000_attach, dev->dvb.frontend, &core->i2c_adap, - &pinnacle_pctv_hd_800i_tuner_config, - core->i2c_adap.algo_data)) + &pinnacle_pctv_hd_800i_tuner_config)) goto frontend_detach; } break; @@ -832,10 +881,9 @@ static int dvb_register(struct cx8802_dev *dev) struct xc2028_config cfg = { .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, }; @@ -848,10 +896,13 @@ static int dvb_register(struct cx8802_dev *dev) break; case CX88_BOARD_PINNACLE_HYBRID_PCTV: dev->dvb.frontend = dvb_attach(zl10353_attach, - &cx88_geniatech_x8000_mt, + &cx88_pinnacle_hybrid_pctv, &core->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) - goto frontend_detach; + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (attach_xc3028(0x61, dev) < 0) + goto frontend_detach; + } break; case CX88_BOARD_GENIATECH_X8000_MT: dev->ts_gen_cntrl = 0x00; @@ -874,16 +925,69 @@ static int dvb_register(struct cx8802_dev *dev) &dvico_fusionhdtv7_config, &core->i2c_adap); if (dev->dvb.frontend != NULL) { - /* tuner_config.video_dev must point to - * i2c_adap.algo_data - */ if (!dvb_attach(xc5000_attach, dev->dvb.frontend, &core->i2c_adap, - &dvico_fusionhdtv7_tuner_config, - core->i2c_adap.algo_data)) + &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: + case CX88_BOARD_TBS_8920: + case CX88_BOARD_PROF_7300: + 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", core->name); @@ -895,6 +999,8 @@ static int dvb_register(struct cx8802_dev *dev) core->name); return -EINVAL; } + /* define general-purpose callback pointer */ + dev->dvb.frontend->callback = cx88_tuner_callback; /* Ensure all frontends negotiate bus access */ dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index d7406a994f09..8e74d64fdcd2 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -201,7 +201,23 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap); if (0 == core->i2c_rc) { + static u8 tuner_data[] = + { 0x0b, 0xdc, 0x86, 0x52 }; + static struct i2c_msg tuner_msg = + { .flags = 0, .addr = 0xc2 >> 1, .buf = tuner_data, .len = 4 }; + dprintk(1, "i2c register ok\n"); + switch( core->boardnr ) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + printk("%s: i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n", + core->name); + i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1); + break; + default: + break; + } if (i2c_scan) do_i2c_scan(core->name,&core->i2c_client); } else diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 53526d997a4e..8683d104de72 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -224,6 +224,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + case CX88_BOARD_HAUPPAUGE_HVR4000LITE: ir_codes = ir_codes_hauppauge_new; ir_type = IR_TYPE_RC5; ir->sampling = 1; @@ -259,6 +261,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->polling = 1; /* ms */ break; case CX88_BOARD_PROLINK_PV_8000GT: + case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: ir_codes = ir_codes_pixelview_new; ir->gpio_addr = MO_GP1_IO; ir->mask_keycode = 0x3f; @@ -392,7 +395,7 @@ void cx88_ir_irq(struct cx88_core *core) { struct cx88_IR *ir = core->ir; u32 samples, ircode; - int i; + int i, start, range, toggle, dev, code; if (NULL == ir) return; @@ -461,6 +464,34 @@ void cx88_ir_irq(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + case CX88_BOARD_HAUPPAUGE_HVR4000LITE: + ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); + ir_dprintk("biphase decoded: %x\n", ircode); + /* + * RC5 has an extension bit which adds a new range + * of available codes, this is detected here. Also + * hauppauge remotes (black/silver) always use + * specific device ids. If we do not filter the + * device ids then messages destined for devices + * such as TVs (id=0) will get through to the + * device causing mis-fired events. + */ + /* split rc5 data block ... */ + start = (ircode & 0x2000) >> 13; + range = (ircode & 0x1000) >> 12; + toggle= (ircode & 0x0800) >> 11; + dev = (ircode & 0x07c0) >> 6; + code = (ircode & 0x003f) | ((range << 6) ^ 0x0040); + if( start != 1) + /* no key pressed */ + break; + if ( dev != 0x1e && dev != 0x1f ) + /* not a hauppauge remote */ + break; + ir_input_keydown(ir->input, &ir->ir, code, ircode); + ir->release = jiffies + msecs_to_jiffies(120); + break; case CX88_BOARD_PINNACLE_PCTV_HD_800i: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index ef4d56ea0027..be45955dff68 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -773,6 +773,7 @@ static int video_open(struct inode *inode, struct file *file) enum v4l2_buf_type type = 0; int radio = 0; + lock_kernel(); list_for_each_entry(h, &cx8800_devlist, devlist) { if (h->video_dev->minor == minor) { dev = h; @@ -788,8 +789,10 @@ static int video_open(struct inode *inode, struct file *file) dev = h; } } - if (NULL == dev) + if (NULL == dev) { + unlock_kernel(); return -ENODEV; + } core = dev->core; @@ -798,8 +801,10 @@ static int video_open(struct inode *inode, struct file *file) /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) + if (NULL == fh) { + unlock_kernel(); return -ENOMEM; + } file->private_data = fh; fh->dev = dev; fh->radio = radio; @@ -832,6 +837,9 @@ static int video_open(struct inode *inode, struct file *file) cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL); } + unlock_kernel(); + + atomic_inc(&core->users); return 0; } @@ -920,7 +928,8 @@ static int video_release(struct inode *inode, struct file *file) file->private_data = NULL; kfree(fh); - cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); + if(atomic_dec_and_test(&dev->core->users)) + cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); return 0; } diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 54fe65094711..dbf01b8b57a5 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -221,6 +221,14 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65 #define CX88_BOARD_PROLINK_PV_8000GT 66 #define CX88_BOARD_KWORLD_ATSC_120 67 +#define CX88_BOARD_HAUPPAUGE_HVR4000 68 +#define CX88_BOARD_HAUPPAUGE_HVR4000LITE 69 +#define CX88_BOARD_TEVII_S460 70 +#define CX88_BOARD_OMICOM_SS4_PCI 71 +#define CX88_BOARD_TBS_8920 72 +#define CX88_BOARD_TEVII_S420 73 +#define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74 +#define CX88_BOARD_PROF_7300 75 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -342,6 +350,7 @@ struct cx88_core { struct mutex lock; /* various v4l controls */ u32 freq; + atomic_t users; /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ struct cx8802_dev *dvbdev; @@ -601,7 +610,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern int cx88_tuner_callback(void *dev, int command, int arg); +extern int cx88_tuner_callback(void *dev, int component, int command, int arg); extern int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci); extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); |