From 5d5ad0f6a021a309c972b6ceaf61df0ba9a27dc8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Nov 2007 09:07:07 -0200 Subject: Fix: Adds the generic PCI IDs for em28xx From: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'linux/drivers/media/video/em28xx/em28xx-cards.c') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 29407d8d7..c689253b4 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -58,22 +58,8 @@ struct em28xx_board em28xx_boards[] = { }}, }, [EM2820_BOARD_UNKNOWN] = { - .name = "Unknown EM2820/2840 video grabber", + .name = "Unknown EM2750/28xx video grabber", .is_em2800 = 0, - .vchannels = 2, - .norm = VIDEO_MODE_PAL, - .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, - .decoder = EM28XX_SAA7113, - .input = {{ - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - },{ - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - }}, }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { .name = "Kworld PVR TV 2800 RF", @@ -338,8 +324,15 @@ 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_MSI_VOX_USB_2 }, + { 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 }, -- cgit v1.2.3 From 214fa1dbeaff3457ef8a7018af320e711cb25a86 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Nov 2007 22:20:59 -0200 Subject: Add a hint for boards without unique USB ID From: Mauro Carvalho Chehab This patch adds a function to allow trying to detect boards that shares the generic IDs. The current detection method is based at eeprom checksum. Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 198 +++++++++++++++++++----- 1 file changed, 158 insertions(+), 40 deletions(-) (limited to 'linux/drivers/media/video/em28xx/em28xx-cards.c') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index c689253b4..96eabac5b 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -38,6 +38,16 @@ #include "em28xx.h" #include "tuner-xc2028.h" +static int tuner = -1; +module_param(tuner, int, 0444); +MODULE_PARM_DESC(tuner, "tuner type"); + +struct em28xx_hash_table { + unsigned long hash; + unsigned int model; + unsigned int tuner; +}; + struct em28xx_board em28xx_boards[] = { [EM2800_BOARD_UNKNOWN] = { .name = "Unknown EM2800 video grabber", @@ -343,70 +353,178 @@ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { }, }; +MODULE_DEVICE_TABLE (usb, em28xx_id_table); + +static struct em28xx_hash_table em28xx_hash [] = { + { 0, 0, 0 }, +}; +/* Since em28xx_pre_card_setup() requires a proper dev->model, + * this won't work for boards with generic PCI IDs + */ void em28xx_pre_card_setup(struct em28xx *dev) { /* request some modules */ switch(dev->model){ - case EM2880_BOARD_TERRATEC_PRODIGY_XS: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_TERRATEC_HYBRID_XS: - { - em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO? - break; - } + case EM2880_BOARD_TERRATEC_PRODIGY_XS: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_TERRATEC_HYBRID_XS: + /* reset through GPIO? */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); + break; + } +} + +static int em28xx_tuner_callback(void *ptr, int command, int arg) +{ + int rc = 0; + struct em28xx *dev = ptr; + + if (dev->tuner_type != TUNER_XC2028) + return 0; + + switch (command) { + case XC2028_TUNER_RESET: + /* FIXME: This is device-dependent */ + dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); + dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); + + msleep(140); + break; } + return rc; } static void em28xx_config_tuner (struct em28xx *dev) { struct v4l2_priv_tun_config xc2028_cfg; struct xc2028_ctrl ctl; + struct tuner_setup tun_setup; + struct v4l2_frequency f; + + if (!dev->has_tuner) + return; + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + tun_setup.tuner_callback = em28xx_tuner_callback; + + em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + + if (dev->tuner_type == TUNER_XC2028) { + memset (&ctl, 0, sizeof(ctl)); + + ctl.fname = XC2028_DEFAULT_FIRMWARE; + ctl.max_len = 64; + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; - memset (&ctl,0,sizeof(ctl)); + em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + } + + /* configure tuner */ + f.tuner = 0; + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = 9076; /* just a magic number */ + dev->ctl_freq = f.frequency; + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); +} + +static int em28xx_hint_board(struct em28xx *dev) +{ + int i; - ctl.fname = XC2028_DEFAULT_FIRMWARE; - ctl.max_len = 64; + for (i = 0; i < ARRAY_SIZE(em28xx_hash); i++) { + if (dev->hash == em28xx_hash[i].hash) { + dev->model = em28xx_hash[i].model; + dev->tuner_type = em28xx_hash[i].tuner; - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on eeprom hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " \n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); - em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + return 0; + } + } + em28xx_errdev("Your board has no unique USB ID and thus need a " + "hint to be detected.\n"); + em28xx_errdev("You may try to use card= insmod option to " + "workaround that.\n"); + em28xx_errdev("Please send an email with this log to:\n"); + em28xx_errdev("\tV4L Mailing List \n"); + em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); + + em28xx_errdev("Here is a list of valid choices for the card=" + " insmod option:\n"); + for (i = 0; i < em28xx_bcount; i++) { + em28xx_errdev(" card=%d -> %s\n", + i, em28xx_boards[i].name); + } + return -1; } void em28xx_card_setup(struct em28xx *dev) { /* request some modules */ - switch(dev->model){ - case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - { - struct tveeprom tv; + switch (dev->model) { + case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: + { + struct tveeprom tv; #ifdef CONFIG_MODULES - request_module("tveeprom"); - request_module("ir-kbd-i2c"); - request_module("msp3400"); + request_module("tveeprom"); + request_module("ir-kbd-i2c"); #endif - /* Call first TVeeprom */ - - dev->i2c_client.addr = 0xa0 >> 1; - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); - - dev->tuner_type= tv.tuner_type; - if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { - dev->i2s_speed=2048000; - dev->has_msp34xx=1; - } else - dev->has_msp34xx=0; - break; - } - case EM2820_BOARD_KWORLD_PVRTV2800RF: - { - em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF - break; - } + /* Call first TVeeprom */ + + dev->i2c_client.addr = 0xa0 >> 1; + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); + dev->tuner_type = tv.tuner_type; + if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { + dev->i2s_speed = 2048000; + dev->has_msp34xx = 1; + } + break; } + case EM2820_BOARD_KWORLD_PVRTV2800RF: + /* GPIO enables sound on KWORLD PVR TV 2800RF */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1); + break; + case EM2820_BOARD_UNKNOWN: + case EM2800_BOARD_UNKNOWN: + em28xx_hint_board(dev); + } + + dev->is_em2800 = em28xx_boards[dev->model].is_em2800; + dev->has_tuner = em28xx_boards[dev->model].has_tuner; + dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; + dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; + dev->decoder = em28xx_boards[dev->model].decoder; + dev->video_inputs = em28xx_boards[dev->model].vchannels; + + if (tuner >= 0) + dev->tuner_type = tuner; + +#ifdef CONFIG_MODULES + /* request some modules */ + if (dev->has_msp34xx) + request_module("msp3400"); + if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) + request_module("saa7115"); + if (dev->decoder == EM28XX_TVP5150) + request_module("tvp5150"); + if (dev->has_tuner) + request_module("tuner"); +#endif + em28xx_config_tuner (dev); } - -MODULE_DEVICE_TABLE (usb, em28xx_id_table); -- cgit v1.2.3 From 3ed99c75c6b16c3365499e240d87a21123f37208 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Nov 2007 22:21:57 -0200 Subject: Add entry for Pixelview Prolink PlayTV USB 2.0 From: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/video/em28xx/em28xx-cards.c') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 96eabac5b..8069dc880 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -329,6 +329,26 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, }}, }, + [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { + .name = "Pixelview Prolink PlayTV USB 2.0", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .decoder = EM28XX_SAA7113, + .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); @@ -356,7 +376,8 @@ struct usb_device_id em28xx_id_table [] = { MODULE_DEVICE_TABLE (usb, em28xx_id_table); static struct em28xx_hash_table em28xx_hash [] = { - { 0, 0, 0 }, + /* P/N: SA 60002070465 Tuner: TVF7533-MF */ + { 0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF }, }; /* Since em28xx_pre_card_setup() requires a proper dev->model, -- cgit v1.2.3 From 62af2ba09181e8b6c7db6fc777770860ae7674b5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 3 Nov 2007 19:05:07 +0100 Subject: em28xx: add support for vgear pockettv From: Sascha Sommer attached patch adds support for the vgear pockettv. It seems to require a write to another register for audio to work. I checked my old cinergydrv and we did the same register write there. I therefore enabled it for all em2800 based devices. Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'linux/drivers/media/video/em28xx/em28xx-cards.c') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 8069dc880..510896dbe 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -329,6 +329,29 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, }}, }, + [EM2800_BOARD_VGEAR_POCKETTV] = { + .name = "V-Gear PocketTV", + .is_em2800 = 1, + .vchannels = 3, + .norm = VIDEO_MODE_PAL, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .decoder = EM28XX_SAA7113, + .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", .vchannels = 3, -- cgit v1.2.3 From 398fa9b90714b59f76f253bd3d787484d6f89ebf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 4 Nov 2007 09:06:48 -0200 Subject: em28xx: autodetect Cinergy 200 USB and VGear PocketTV From: Sascha Sommer Adds autodetection support for the Cinergy200 USB and the VGear PocketTV. Whenever a usb device with generic empia em2800 usb ids is detected the device gets scanned for connected i2c devices. If the device list matches an em2800 device in the device list the model id gets changed accordingly. Signed-off-by: Sascha Sommer Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'linux/drivers/media/video/em28xx/em28xx-cards.c') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 510896dbe..1ee7391b9 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -403,6 +403,11 @@ static struct em28xx_hash_table em28xx_hash [] = { { 0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF }, }; +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 }, +}; + /* Since em28xx_pre_card_setup() requires a proper dev->model, * this won't work for boards with generic PCI IDs */ @@ -499,6 +504,30 @@ static int em28xx_hint_board(struct em28xx *dev) return 0; } } + + /* user did not request i2c scanning => do it now */ + if (!dev->i2c_hash) + em28xx_do_i2c_scan(dev); + + for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) { + if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { + dev->model = em28xx_i2c_hash[i].model; + dev->tuner_type = em28xx_i2c_hash[i].tuner; + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on i2c devicelist hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " \n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); + + return 0; + } + } + em28xx_errdev("Your board has no unique USB ID and thus need a " "hint to be detected.\n"); em28xx_errdev("You may try to use card= insmod option to " @@ -506,6 +535,7 @@ static int em28xx_hint_board(struct em28xx *dev) em28xx_errdev("Please send an email with this log to:\n"); em28xx_errdev("\tV4L Mailing List \n"); em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); + em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); em28xx_errdev("Here is a list of valid choices for the card=" " insmod option:\n"); -- cgit v1.2.3 From 0f194c3b96b49491833dd2bc4e89e9bbc7d0945e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 4 Nov 2007 09:32:42 -0200 Subject: Add comments for the hint methods From: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/em28xx/em28xx-cards.c | 29 ++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'linux/drivers/media/video/em28xx/em28xx-cards.c') diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 1ee7391b9..624d3c37f 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -398,11 +398,13 @@ struct usb_device_id em28xx_id_table [] = { }; MODULE_DEVICE_TABLE (usb, em28xx_id_table); -static struct em28xx_hash_table em28xx_hash [] = { +/* 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 }, }; +/* 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 }, @@ -485,10 +487,18 @@ static int em28xx_hint_board(struct em28xx *dev) { int i; - for (i = 0; i < ARRAY_SIZE(em28xx_hash); i++) { - if (dev->hash == em28xx_hash[i].hash) { - dev->model = em28xx_hash[i].model; - dev->tuner_type = em28xx_hash[i].tuner; + /* HINT method: EEPROM + * + * This method works only for boards with eeprom. + * Uses a hash of all eeprom bytes. The hash should be + * unique for a vendor/tuner pair. + * There are a high chance that tuners for different + * video standards produce different hashes. + */ + for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) { + if (dev->hash == em28xx_eeprom_hash[i].hash) { + dev->model = em28xx_eeprom_hash[i].model; + dev->tuner_type = em28xx_eeprom_hash[i].tuner; em28xx_errdev("Your board has no unique USB ID.\n"); em28xx_errdev("A hint were successfully done, " @@ -505,6 +515,15 @@ static int em28xx_hint_board(struct em28xx *dev) } } + /* HINT method: I2C attached devices + * + * This method works for all boards. + * Uses a hash of i2c scanned devices. + * Devices with the same i2c attached chips will + * be considered equal. + * This method is less precise than the eeprom one. + */ + /* user did not request i2c scanning => do it now */ if (!dev->i2c_hash) em28xx_do_i2c_scan(dev); -- cgit v1.2.3