]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/video/em28xx/em28xx-cards.c
V4L/DVB (7607): CodingStyle fixes
[linux-2.6-omap-h63xx.git] / drivers / media / video / em28xx / em28xx-cards.c
index b1afc6c2d3726218291282ca60db33daf9bd485b..7dfea3ac9b2f392e70473db89b5bbe31f2fc99b0 100644 (file)
@@ -1,5 +1,6 @@
 /*
-   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>
 #include <media/v4l2-common.h>
 
 #include "em28xx.h"
-#include "tuner-xc2028.h"
 
 static int tuner = -1;
 module_param(tuner, int, 0444);
 MODULE_PARM_DESC(tuner, "tuner type");
 
+static unsigned int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+
 struct em28xx_hash_table {
        unsigned long hash;
        unsigned int  model;
@@ -52,407 +56,529 @@ struct em28xx_board em28xx_boards[] = {
                .name         = "Unknown EM2800 video grabber",
                .is_em2800    = 1,
                .vchannels    = 2,
-               .norm         = VIDEO_MODE_PAL,
                .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",
                .is_em2800    = 0,
+               .tuner_type   = TUNER_ABSENT,
        },
        [EM2820_BOARD_KWORLD_PVRTV2800RF] = {
                .name         = "Kworld PVR TV 2800 RF",
                .is_em2800    = 0,
                .vchannels    = 2,
-               .norm         = VIDEO_MODE_PAL,
+               .tuner_type   = TUNER_TEMIC_PAL,
                .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",
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .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",
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .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,
-               .norm         = VIDEO_MODE_NTSC,
                .tuner_type   = TUNER_PHILIPS_FM1236_MK3,
-               .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
-               .has_tuner    = 1,
+               .tda9887_conf = TDA9887_PRESENT |
+                               TDA9887_PORT1_ACTIVE|
+                               TDA9887_PORT2_ACTIVE,
                .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,
-               .norm         = VIDEO_MODE_PAL,
                .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,
+               .mts_firmware   = 1,
+               .has_12mhz_i2s  = 1,
+               .has_dvb        = 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,
-               }},
+               } },
        },
        [EM2880_BOARD_TERRATEC_HYBRID_XS] = {
                .name         = "Terratec Hybrid XS",
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
                .tda9887_conf = TDA9887_PRESENT,
-               .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,
-               .norm         = VIDEO_MODE_PAL,
                .tda9887_conf = TDA9887_PRESENT,
-               .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,
-               .norm           = VIDEO_MODE_PAL,
-               .tuner_type     = TUNER_LG_PAL_NEW_TAPC,
-               .tda9887_conf   = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
-               .has_tuner      = 1,
-               .decoder        = EM28XX_SAA7114,
-               .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,
-               }},
+               .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,
+               .max_range_640_480 = 1,
+
+               .decoder           = EM28XX_SAA7114,
+               .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",
                .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          = {{
+               .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",
                .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          = {{
+               .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",
                .is_em2800    = 1,
                .vchannels    = 3,
-               .norm         = VIDEO_MODE_PAL,
-               .tuner_type   = TUNER_PHILIPS_ATSC,
+               .tuner_type   = TUNER_PHILIPS_FCV1236D,
                .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,
-               .norm         = VIDEO_MODE_PAL,
-               .has_tuner    = 0,
+               .tuner_type   = TUNER_ABSENT,
                .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",
                .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          = {{
+               .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,
                .tda9887_conf = TDA9887_PRESENT,
-               .has_tuner    = 1,
+               .tuner_type   = TUNER_YMEC_TVF_5533MF,
                .decoder      = EM28XX_SAA7113,
-               .input          = {{
+               .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 1,
-               },{
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
-               },{
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
-               }},
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               } },
        },
 };
 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, 0x6502),
+                       .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 */
+/*
+ *  Reset sequences for analog/digital modes
+ */
+
+/* Board Hauppauge WinTV HVR 900 analog */
+struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+       {  -1,   -1,   6},
+       {0x08, 0x2d,  10},
+       {0x08, 0x3d,   5},
+       {  -1,   -1,  -1},
+};
+/* Board Hauppauge WinTV HVR 900 digital */
+struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+       {  -1,   -1,   6},
+       {0x08, 0x2e,   6},
+       {0x08, 0x3e,   6},
+       {0x04, 0x04,  10},
+       {0x04, 0x0c,  10},
+       { -1,    -1,  -1},
+};
+
+/*
+ * 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},
 };
 
+int em28xx_tuner_callback(void *ptr, int command, int arg)
+{
+       int rc = 0;
+       struct em28xx *dev = ptr;
+       struct em28xx_reg_seq *gpio;
+
+       if (dev->tuner_type != TUNER_XC2028)
+               return 0;
+
+       if (command != XC2028_TUNER_RESET)
+               return 0;
+
+       if (dev->mode == EM28XX_ANALOG_MODE)
+               gpio = dev->analog_gpio;
+       else
+               gpio = dev->digital_gpio;
+
+       /* djh - Not sure if these are still required */
+       dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+       if (dev->mode == EM28XX_ANALOG_MODE)
+               dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
+       else
+               dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1);
+       msleep(6);
+
+       if (!gpio)
+               return rc;
+
+       /* Send GPIO reset sequences specified at board entry */
+       while (gpio->sleep >= 0) {
+               if (gpio->reg >= 0)
+                       rc = dev->em28xx_write_regs(dev,
+                                                   gpio->reg,
+                                                   &gpio->val, 1);
+               if (gpio->sleep > 0)
+                       msleep(gpio->sleep);
+
+               gpio++;
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
+
+static void em28xx_set_model(struct em28xx *dev)
+{
+       dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
+       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;
+       dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
+       dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
+       dev->has_dvb = em28xx_boards[dev->model].has_dvb;
+}
+
 /* 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)
 {
+       em28xx_set_model(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_TERRATEC_HYBRID_XS:
-               /* reset through GPIO? */
-               em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1);
+       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+               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);
+
+               dev->analog_gpio = hauppauge_wintv_hvr_900_analog;
+               dev->digital_gpio = hauppauge_wintv_hvr_900_digital;
+
                break;
        }
 }
 
-static int em28xx_tuner_callback(void *ptr, int command, int arg)
+void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
 {
-       int rc = 0;
-       struct em28xx *dev = ptr;
+       memset(ctl, 0, sizeof(*ctl));
 
-       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);
+       ctl->fname   = XC2028_DEFAULT_FIRMWARE;
+       ctl->max_len = 64;
+       ctl->mts = em28xx_boards[dev->model].mts_firmware;
 
-               msleep(140);
+       switch (dev->model) {
+       /* Add card-specific parameters for xc3028 here */
+       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+               ctl->demod = XC3028_FE_DEFAULT;
                break;
+       default:
+               ctl->demod = XC3028_FE_OREN538;
        }
-       return rc;
 }
+EXPORT_SYMBOL_GPL(em28xx_setup_xc3028);
 
-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;
        struct tuner_setup           tun_setup;
        struct v4l2_frequency        f;
 
-       if (!dev->has_tuner)
+       if (dev->tuner_type == TUNER_ABSENT)
                return;
 
        tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
@@ -463,10 +589,9 @@ static void em28xx_config_tuner (struct em28xx *dev)
        em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
 
        if (dev->tuner_type == TUNER_XC2028) {
-               memset (&ctl, 0, sizeof(ctl));
+               struct xc2028_ctrl           ctl;
 
-               ctl.fname   = XC2028_DEFAULT_FIRMWARE;
-               ctl.max_len = 64;
+               em28xx_setup_xc3028(dev, &ctl);
 
                xc2028_cfg.tuner = TUNER_XC2028;
                xc2028_cfg.priv  = &ctl;
@@ -564,18 +689,46 @@ static int em28xx_hint_board(struct em28xx *dev)
        return -1;
 }
 
-
-static void em28xx_set_model(struct em28xx *dev)
+/* ----------------------------------------------------------------------- */
+void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
 {
-       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 (disable_ir) {
+               ir->get_key = NULL;
+               return ;
+       }
 
-       if (!em28xx_boards[dev->model].has_tuner)
-               dev->tuner_type = UNSET;
+       /* detect & configure */
+       switch (dev->model) {
+       case (EM2800_BOARD_UNKNOWN):
+               break;
+       case (EM2820_BOARD_UNKNOWN):
+               break;
+       case (EM2800_BOARD_TERRATEC_CINERGY_200):
+       case (EM2820_BOARD_TERRATEC_CINERGY_250):
+               ir->ir_codes = ir_codes_em_terratec;
+               ir->get_key = em28xx_get_key_terratec;
+               snprintf(ir->c.name, sizeof(ir->c.name),
+                        "i2c IR (EM28XX Terratec)");
+               break;
+       case (EM2820_BOARD_PINNACLE_USB_2):
+               ir->ir_codes = ir_codes_pinnacle_grey;
+               ir->get_key = em28xx_get_key_pinnacle_usb_grey;
+               snprintf(ir->c.name, sizeof(ir->c.name),
+                        "i2c IR (EM28XX Pinnacle PCTV)");
+               break;
+       case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+               ir->ir_codes = ir_codes_hauppauge_new;
+               ir->get_key = em28xx_get_key_em_haup;
+               snprintf(ir->c.name, sizeof(ir->c.name),
+                        "i2c IR (EM2840 Hauppauge)");
+               break;
+       case (EM2820_BOARD_MSI_VOX_USB_2):
+               break;
+       case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
+               break;
+       case (EM2800_BOARD_KWORLD_USB2800):
+               break;
+       }
 }
 
 void em28xx_card_setup(struct em28xx *dev)
@@ -587,11 +740,12 @@ void em28xx_card_setup(struct em28xx *dev)
        /* request some modules */
        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
                request_module("tveeprom");
-               request_module("ir-kbd-i2c");
 #endif
                /* Call first TVeeprom */
 
@@ -599,10 +753,15 @@ void em28xx_card_setup(struct em28xx *dev)
                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;
                }
+#ifdef CONFIG_MODULES
+               if (tv.has_ir)
+                       request_module("ir-kbd-i2c");
+#endif
                break;
        }
        case EM2820_BOARD_KWORLD_PVRTV2800RF:
@@ -627,9 +786,9 @@ void em28xx_card_setup(struct em28xx *dev)
                request_module("saa7115");
        if (dev->decoder == EM28XX_TVP5150)
                request_module("tvp5150");
-       if (dev->has_tuner)
+       if (dev->tuner_type != TUNER_ABSENT)
                request_module("tuner");
 #endif
 
-       em28xx_config_tuner (dev);
+       em28xx_config_tuner(dev);
 }