/*
- em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+ em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB
+ video capture devices
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2820_BOARD_UNKNOWN] = {
.name = "Unknown EM2750/28xx video grabber",
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2820_BOARD_TERRATEC_CINERGY_250] = {
.name = "Terratec Cinergy 250 USB",
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2820_BOARD_PINNACLE_USB_2] = {
.name = "Pinnacle PCTV USB 2",
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = 0,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
.name = "Hauppauge WinTV USB 2",
.vchannels = 3,
.tuner_type = TUNER_PHILIPS_FM1236_MK3,
- .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+ .tda9887_conf = TDA9887_PRESENT |
+ TDA9887_PORT1_ACTIVE|
+ TDA9887_PORT2_ACTIVE,
.has_tuner = 1,
.decoder = EM28XX_TVP5150,
.has_msp34xx = 1,
/*FIXME: S-Video not tested */
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = MSP_INPUT_DEFAULT,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
- }},
+ } },
},
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
- .name = "Hauppauge WinTV HVR 900/950",
+ .name = "Hauppauge WinTV HVR 900",
.vchannels = 3,
.tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_XC2028,
.has_tuner = 1,
+ .mts_firmware = 1,
.decoder = EM28XX_TVP5150,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = 0,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = 1,
- }},
+ } },
+ },
+ [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
+ .name = "Hauppauge WinTV HVR 950",
+ .vchannels = 3,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_XC2028,
+ .has_tuner = 1,
+ .mts_firmware = 1,
+ .has_12mhz_i2s = 1,
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = 0,
+ }, {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = 1,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = 1,
+ } },
+
+ /* gpio's 4, 1, 0 */
+ .analog_gpio = 0x003d2d,
},
[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Hybrid XS",
.has_tuner = 1,
.tuner_type = TUNER_XC2028,
.decoder = EM28XX_TVP5150,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = 0,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = 1,
- }},
+ } },
},
- /* maybe there's a reason behind it why Terratec sells the Hybrid XS as Prodigy XS with a
- * different PID, let's keep it separated for now maybe we'll need it lateron */
+ /* maybe there's a reason behind it why Terratec sells the Hybrid XS
+ as Prodigy XS with a different PID, let's keep it separated for now
+ maybe we'll need it lateron */
[EM2880_BOARD_TERRATEC_PRODIGY_XS] = {
.name = "Terratec Prodigy XS",
.vchannels = 3,
.has_tuner = 1,
.tuner_type = TUNER_XC2028,
.decoder = EM28XX_TVP5150,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = 0,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = 1,
- }},
+ } },
},
[EM2820_BOARD_MSI_VOX_USB_2] = {
.name = "MSI VOX USB 2.0",
.vchannels = 3,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
- .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+ .tda9887_conf = TDA9887_PRESENT |
+ TDA9887_PORT1_ACTIVE |
+ TDA9887_PORT2_ACTIVE,
.has_tuner = 1,
.decoder = EM28XX_SAA7114,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE4,
.amux = 0,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2800_BOARD_TERRATEC_CINERGY_200] = {
.name = "Terratec Cinergy 200 USB",
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = 0,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
.name = "Leadtek Winfast USB II",
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = 0,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2800_BOARD_KWORLD_USB2800] = {
.name = "Kworld USB2800",
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = 0,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2820_BOARD_PINNACLE_DVC_90] = {
- .name = "Pinnacle Dazzle DVC 90",
+ .name = "Pinnacle Dazzle DVC 90/DVC 100",
.vchannels = 3,
.has_tuner = 0,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2800_BOARD_VGEAR_POCKETTV] = {
.name = "V-Gear PocketTV",
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = 0,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
[EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
.name = "Pixelview Prolink PlayTV USB 2.0",
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM28XX_SAA7113,
- .input = {{
+ .input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
.amux = 1,
- },{
+ }, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
.amux = 1,
- }},
+ } },
},
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
/* table of devices that work with this driver */
struct usb_device_id em28xx_id_table [] = {
- { USB_DEVICE(0xeb1a, 0x2750), .driver_info = EM2820_BOARD_UNKNOWN },
- { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
- { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_UNKNOWN },
- { USB_DEVICE(0xeb1a, 0x2821), .driver_info = EM2820_BOARD_UNKNOWN },
- { USB_DEVICE(0xeb1a, 0x2860), .driver_info = EM2820_BOARD_UNKNOWN },
- { USB_DEVICE(0xeb1a, 0x2861), .driver_info = EM2820_BOARD_UNKNOWN },
- { USB_DEVICE(0xeb1a, 0x2870), .driver_info = EM2820_BOARD_UNKNOWN },
- { USB_DEVICE(0xeb1a, 0x2881), .driver_info = EM2820_BOARD_UNKNOWN },
- { USB_DEVICE(0xeb1a, 0x2883), .driver_info = EM2820_BOARD_UNKNOWN },
- { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
- { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
- { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
- { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
- { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
- { USB_DEVICE(0x2040, 0x6513), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
- { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
- { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
+ { USB_DEVICE(0xeb1a, 0x2750),
+ .driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2800),
+ .driver_info = EM2800_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2820),
+ .driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2821),
+ .driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2860),
+ .driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2861),
+ .driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2870),
+ .driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2881),
+ .driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2883),
+ .driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0x0ccd, 0x0036),
+ .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+ { USB_DEVICE(0x2304, 0x0208),
+ .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
+ { USB_DEVICE(0x2040, 0x4200),
+ .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+ { USB_DEVICE(0x2040, 0x4201),
+ .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+ { USB_DEVICE(0x2304, 0x0207),
+ .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+ { USB_DEVICE(0x2304, 0x021a),
+ .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+ { USB_DEVICE(0x2040, 0x6500),
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
+ { USB_DEVICE(0x2040, 0x6513),
+ .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+ { USB_DEVICE(0x0ccd, 0x0042),
+ .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
+ { USB_DEVICE(0x0ccd, 0x0047),
+ .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
{ },
};
-MODULE_DEVICE_TABLE (usb, em28xx_id_table);
+MODULE_DEVICE_TABLE(usb, em28xx_id_table);
/* EEPROM hash table for devices with generic USB IDs */
static struct em28xx_hash_table em28xx_eeprom_hash [] = {
/* P/N: SA 60002070465 Tuner: TVF7533-MF */
- { 0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF },
+ {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
};
/* I2C devicelist hash table for devices with generic USB IDs */
static struct em28xx_hash_table em28xx_i2c_hash[] = {
- { 0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC },
- { 0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC },
+ {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
+ {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
};
/* Since em28xx_pre_card_setup() requires a proper dev->model,
void em28xx_pre_card_setup(struct em28xx *dev)
{
/* request some modules */
- switch(dev->model){
+ switch (dev->model) {
case EM2880_BOARD_TERRATEC_PRODIGY_XS:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_TERRATEC_HYBRID_XS:
- /* reset through GPIO? */
- em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1);
+ em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
+ em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
+ em28xx_write_regs(dev, 0x08, "\xff", 1);
+ em28xx_write_regs(dev, 0x04, "\x00", 1);
+ msleep(100);
+ em28xx_write_regs(dev, 0x04, "\x08", 1);
+ msleep(100);
+ em28xx_write_regs(dev, 0x08, "\xff", 1);
+ msleep(50);
+ em28xx_write_regs(dev, 0x08, "\x2d", 1);
+ msleep(50);
+ em28xx_write_regs(dev, 0x08, "\x3d", 1);
break;
}
}
switch (command) {
case XC2028_TUNER_RESET:
- /* FIXME: This is device-dependent */
+ {
+ /* GPIO and initialization codes for analog TV and radio
+ This code should be complemented for DTV, since reset
+ codes are different.
+ */
+
dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
- msleep(140);
+ if (dev->analog_gpio) {
+ char gpio0 = dev->analog_gpio & 0xff;
+ char gpio1 = (dev->analog_gpio >> 8) & 0xff;
+ char gpio4 = dev->analog_gpio >> 24;
+
+ if (gpio4) {
+ dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
+ msleep(140);
+ }
+
+ msleep(6);
+ dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
+ msleep(10);
+ dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
+ msleep(5);
+ }
+
break;
}
+ }
return rc;
}
-static void em28xx_config_tuner (struct em28xx *dev)
+static void em28xx_config_tuner(struct em28xx *dev)
{
struct v4l2_priv_tun_config xc2028_cfg;
struct xc2028_ctrl ctl;
em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
if (dev->tuner_type == TUNER_XC2028) {
- memset (&ctl, 0, sizeof(ctl));
+ memset(&ctl, 0, sizeof(ctl));
ctl.fname = XC2028_DEFAULT_FIRMWARE;
ctl.max_len = 64;
+ ctl.mts = em28xx_boards[dev->model].mts_firmware;
xc2028_cfg.tuner = TUNER_XC2028;
xc2028_cfg.priv = &ctl;
dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
dev->decoder = em28xx_boards[dev->model].decoder;
dev->video_inputs = em28xx_boards[dev->model].vchannels;
+ dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
+ dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
if (!em28xx_boards[dev->model].has_tuner)
dev->tuner_type = UNSET;
switch (dev->model) {
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
{
struct tveeprom tv;
#ifdef CONFIG_MODULES
if (tv.has_ir)
request_module("ir-kbd-i2c");
#endif
- /* FIXME: Should also retrieve decoder processor type */
-
break;
}
case EM2820_BOARD_KWORLD_PVRTV2800RF:
request_module("tuner");
#endif
- em28xx_config_tuner (dev);
+ em28xx_config_tuner(dev);
}