diff options
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-cards.c | 382 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-core.c | 129 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-dvb.c | 8 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-video.c | 69 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx.h | 28 | ||||
-rwxr-xr-x | v4l2-apps/util/parse_em28xx.pl | 278 |
6 files changed, 655 insertions, 239 deletions
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index f400f80f0..d38b3ba72 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -52,10 +52,87 @@ struct em28xx_hash_table { unsigned int tuner; }; +/* + * Reset sequences for analog/digital modes + */ + +/* Reset for the most [analog] boards */ +static struct em28xx_reg_seq default_analog[] = { + {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Reset for the most [digital] boards */ +static struct em28xx_reg_seq default_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Board Hauppauge WinTV HVR 900 analog */ +static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { + {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10}, + {0x05, 0xff, 0x10, 10}, + { -1, -1, -1, -1}, +}; + +/* Board Hauppauge WinTV HVR 900 digital */ +static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { + {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x04, 0x0f, 10}, + {EM2880_R04_GPO, 0x0c, 0x0f, 10}, + { -1, -1, -1, -1}, +}; + +/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ +static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { + {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ +#if 0 /* Still missing the dvb setup */ +static struct em28xx_reg_seq em2880_msi_digivox_ad_digital[] = { + {EM28XX_R08_GPIO, 0x6a, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; +#endif + +/* Board - EM2870 Kworld 355u + Analog - No input analog */ +#if 0 /* Still missing the dvb setup */ +static struct em28xx_reg_seq em2870_kworld_355u_digital[] = { + {EM2880_R04_GPO, 0x01, 0xff, 10}, + { -1, -1, -1, -1}, +}; +#endif + +/* Callback for the most boards */ +static struct em28xx_reg_seq default_tuner_gpio[] = { + {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, + {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10}, + {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Pinnacle PCTV HD Mini (80e) GPIOs + 0-5: not used + 6: demod reset, active low + 7: LED on, active high */ +static struct em28xx_reg_seq em2874_pinnacle_80e_digital[] = { + {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ + {EM2874_R80_GPIO, 0x80, 0xff, 100},/*Demod reset*/ + {EM2874_R80_GPIO, 0xc0, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +/* + * Board definitions + */ struct em28xx_board em28xx_boards[] = { [EM2750_BOARD_UNKNOWN] = { .name = "Unknown EM2750/EM2751 webcam grabber", .xclk = EM28XX_XCLK_FREQUENCY_48MHZ, + .tuner_type = TUNER_ABSENT, /* This is a webcam */ .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -67,6 +144,7 @@ struct em28xx_board em28xx_boards[] = { .is_em2800 = 1, .tda9887_conf = TDA9887_PRESENT, .decoder = EM28XX_SAA711X, + .tuner_type = TUNER_ABSENT, .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, @@ -86,6 +164,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Huaqi DLCW-130", .valid = EM28XX_BOARD_NOT_VALIDATED, .xclk = EM28XX_XCLK_FREQUENCY_48MHZ, + .tuner_type = TUNER_ABSENT, /* This is a webcam */ .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -252,22 +331,22 @@ struct em28xx_board em28xx_boards[] = { .decoder = EM28XX_SAA711X, .input = { { .type = EM28XX_VMUX_TELEVISION, - .vmux = 2, + .vmux = SAA7115_COMPOSITE2, .amux = EM28XX_AMUX_VIDEO, }, { .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, + .vmux = SAA7115_COMPOSITE0, .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, - .vmux = 9, + .vmux = SAA7115_COMPOSITE0, .amux = EM28XX_AMUX_LINE_IN, } }, }, [EM2820_BOARD_PINNACLE_DVC_100] = { .name = "Pinnacle Dazzle DVC 100", - .valid = EM28XX_BOARD_NOT_VALIDATED, .decoder = EM28XX_SAA711X, + .tuner_type = TUNER_ABSENT, /* Capture only device */ .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, @@ -281,6 +360,7 @@ struct em28xx_board em28xx_boards[] = { [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { .name = "Videology 20K14XUSB USB2.0", .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* This is a webcam */ .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -332,6 +412,7 @@ struct em28xx_board em28xx_boards[] = { [EM2821_BOARD_USBGEAR_VD204] = { .name = "Usbgear VD204v9", .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* Capture only device */ .decoder = EM28XX_SAA711X, .input = { { .type = EM28XX_VMUX_COMPOSITE1, @@ -347,6 +428,7 @@ struct em28xx_board em28xx_boards[] = { /* Beijing Huaqi Information Digital Technology Co., Ltd */ .name = "NetGMBH Cam", .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* This is a webcam */ .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -355,8 +437,8 @@ struct em28xx_board em28xx_boards[] = { }, [EM2860_BOARD_TYPHOON_DVD_MAKER] = { .name = "Typhoon DVD Maker", - .valid = EM28XX_BOARD_NOT_VALIDATED, .decoder = EM28XX_SAA711X, + .tuner_type = TUNER_ABSENT, /* Capture only device */ .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, @@ -391,25 +473,35 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Cinergy A Hybrid XS", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, + +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2861_BOARD_KWORLD_PVRTV_300U] = { .name = "KWorld PVRTV 300U", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -427,7 +519,7 @@ struct em28xx_board em28xx_boards[] = { }, [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = { .name = "Yakumo MovieMixer", - .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* Capture only device */ .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -463,10 +555,18 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, + + /* Those boards with em2870 are DVB Only*/ + [EM2870_BOARD_TERRATEC_XS] = { .name = "Terratec Cinergy T XS", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = default_digital, +#endif }, [EM2870_BOARD_TERRATEC_XS_MT2060] = { .name = "Terratec Cinergy T XS (MT2060)", @@ -477,10 +577,19 @@ struct em28xx_board em28xx_boards[] = { .name = "Kworld 350 U DVB-T", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = default_digital, +#endif }, [EM2870_BOARD_KWORLD_355U] = { .name = "Kworld 355 U DVB-T", .valid = EM28XX_BOARD_NOT_VALIDATED, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = em2870_kworld_355u_digital, +#endif }, [EM2870_BOARD_PINNACLE_PCTV_DVB] = { .name = "Pinnacle PCTV DVB-T", @@ -495,147 +604,189 @@ struct em28xx_board em28xx_boards[] = { .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_ABSENT, /* MT2060 */ }, + [EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = { .name = "Terratec Hybrid XS Secam", .valid = EM28XX_BOARD_NOT_VALIDATED, .has_msp34xx = 1, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = default_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, } }, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { .name = "Hauppauge WinTV HVR 900", .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .mts_firmware = 1, .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = { .name = "Hauppauge WinTV HVR 900 (R2)", .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .mts_firmware = 1, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, - .amux = 3, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { .name = "Hauppauge WinTV HVR 950", .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .mts_firmware = 1, .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, .ir_codes = ir_codes_hauppauge_new, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { .name = "Pinnacle PCTV HD Pro Stick", .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .mts_firmware = 1, .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, .ir_codes = ir_codes_pinnacle_pctv_hd, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { .name = "AMD ATI TV Wonder HD 600", .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .mts_firmware = 1, .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, .ir_codes = ir_codes_ati_tv_wonder_hd_600, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, .has_dvb = 1, + .dvb_gpio = default_analog, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, } }, }, /* maybe there's a reason behind it why Terratec sells the Hybrid XS @@ -644,19 +795,27 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { .name = "Terratec Prodigy XS", .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2820_BOARD_MSI_VOX_USB_2] = { @@ -705,6 +864,7 @@ struct em28xx_board em28xx_boards[] = { .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder", .is_em2800 = 1, .decoder = EM28XX_SAA711X, + .tuner_type = TUNER_ABSENT, /* capture only board */ .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, @@ -757,7 +917,7 @@ struct em28xx_board em28xx_boards[] = { }, [EM2820_BOARD_PINNACLE_DVC_90] = { .name = "Pinnacle Dazzle DVC 90/DVC 100", - .tuner_type = TUNER_ABSENT, + .tuner_type = TUNER_ABSENT, /* capture only board */ .decoder = EM28XX_SAA711X, .input = { { .type = EM28XX_VMUX_COMPOSITE1, @@ -826,44 +986,61 @@ struct em28xx_board em28xx_boards[] = { .name = "MSI DigiVox A/D", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = em2880_msi_digivox_ad_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = em2880_msi_digivox_ad_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2880_msi_digivox_ad_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2880_msi_digivox_ad_analog, } }, }, [EM2880_BOARD_MSI_DIGIVOX_AD_II] = { .name = "MSI DigiVox A/D II", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = em2880_msi_digivox_ad_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = em2880_msi_digivox_ad_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2880_msi_digivox_ad_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = em2880_msi_digivox_ad_analog, } }, }, [EM2880_BOARD_KWORLD_DVB_305U] = { .name = "KWorld DVB-T 305U", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -882,85 +1059,115 @@ struct em28xx_board em28xx_boards[] = { [EM2880_BOARD_KWORLD_DVB_310U] = { .name = "KWorld DVB-T 310U", .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .has_dvb = 1, + .dvb_gpio = default_digital, .mts_firmware = 1, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, }, { /* S-video has not been tested yet */ .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, } }, }, [EM2881_BOARD_DNT_DA2_HYBRID] = { .name = "DNT DA2 Hybrid", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = default_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, } }, }, [EM2881_BOARD_PINNACLE_HYBRID_PRO] = { .name = "Pinnacle Hybrid Pro", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = default_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = default_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = default_analog, } }, }, [EM2882_BOARD_PINNACLE_HYBRID_PRO] = { .name = "Pinnacle Hybrid Pro (2)", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .mts_firmware = 1, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2882_BOARD_KWORLD_VS_DVBT] = { .name = "Kworld VS-DVB-T 323UR", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -980,38 +1187,54 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Hybrid XS (em2882)", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2883_BOARD_KWORLD_HYBRID_A316] = { .name = "Kworld PlusTV HD Hybrid 330", .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, +#if 0 /* FIXME: add an entry at em28xx-dvb */ + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, +#endif .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, } }, }, [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { @@ -1029,10 +1252,14 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, + + /* em2874 tuners are DVB only */ + [EM2874_BOARD_PINNACLE_PCTV_80E] = { .name = "Pinnacle PCTV HD Mini", .tuner_type = TUNER_ABSENT, .has_dvb = 1, + .dvb_gpio = em2874_pinnacle_80e_digital, .ir_codes = ir_codes_pinnacle_pctv_hd, .decoder = EM28XX_NODECODER, .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | @@ -1154,75 +1381,6 @@ struct usb_device_id em28xx_id_table [] = { MODULE_DEVICE_TABLE(usb, em28xx_id_table); /* - * Reset sequences for analog/digital modes - */ - -/* Reset for the most [analog] boards */ -static struct em28xx_reg_seq default_analog[] = { - {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Reset for the most [digital] boards */ -static struct em28xx_reg_seq default_digital[] = { - {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Board Hauppauge WinTV HVR 900 analog */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { - {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10}, - {0x05, 0xff, 0x10, 10}, - { -1, -1, -1, -1}, -}; - -/* Board Hauppauge WinTV HVR 900 digital */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { - {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10}, - {EM2880_R04_GPO, 0x04, 0x0f, 10}, - {EM2880_R04_GPO, 0x0c, 0x0f, 10}, - { -1, -1, -1, -1}, -}; - -/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ -static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { - {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ -static struct em28xx_reg_seq em2880_msi_digivox_ad_digital[] = { - {EM28XX_R08_GPIO, 0x6a, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Board - EM2870 Kworld 355u - Analog - No input analog */ -static struct em28xx_reg_seq em2870_kworld_355u_digital[] = { - {EM2880_R04_GPO, 0x01, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -/* Callback for the most boards */ -static struct em28xx_reg_seq default_callback[] = { - {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, - {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10}, - {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Pinnacle PCTV HD Mini (80e) GPIOs - 0-5: not used - 6: demod reset, active low - 7: LED on, active high */ -static struct em28xx_reg_seq em2874_pinnacle_80e_digital[] = { - {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ - {EM2874_R80_GPIO, 0x80, 0xff, 100},/*Demod reset*/ - {EM2874_R80_GPIO, 0xc0, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -/* * EEPROM hash table for devices with generic USB IDs */ static struct em28xx_hash_table em28xx_eeprom_hash [] = { @@ -1249,7 +1407,7 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg) if (command != XC2028_TUNER_RESET) return 0; - rc = em28xx_gpio_set(dev, dev->tuner_gpio); + rc = em28xx_gpio_set(dev, dev->board.tuner_gpio); return rc; } @@ -1269,7 +1427,8 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_set_model(dev); - em28xx_info("Found %s\n", dev->board.name); + em28xx_info("Identified as %s (card=%d)\n", + dev->board.name, dev->model); /* Set the default GPO/GPIO for legacy devices */ dev->reg_gpo_num = EM2880_R04_GPO; @@ -1331,55 +1490,11 @@ 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_HAUPPAUGE_WINTV_HVR_900_R2: - case EM2860_BOARD_TERRATEC_HYBRID_XS: - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: - case EM2882_BOARD_PINNACLE_HYBRID_PRO: - case EM2883_BOARD_KWORLD_HYBRID_A316: - case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: - /* Sets GPO/GPIO sequences for this device */ - dev->analog_gpio = hauppauge_wintv_hvr_900_analog; - dev->digital_gpio = hauppauge_wintv_hvr_900_digital; - break; - - case EM2882_BOARD_TERRATEC_HYBRID_XS: - /* Sets GPO/GPIO sequences for this device */ - dev->analog_gpio = hauppauge_wintv_hvr_900_analog; - dev->digital_gpio = hauppauge_wintv_hvr_900_digital; - break; - - case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: - case EM2880_BOARD_TERRATEC_HYBRID_XS: - case EM2870_BOARD_TERRATEC_XS: - case EM2881_BOARD_PINNACLE_HYBRID_PRO: - case EM2880_BOARD_KWORLD_DVB_310U: - case EM2870_BOARD_KWORLD_350U: - case EM2881_BOARD_DNT_DA2_HYBRID: - /* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital - and analog commands. If this commands doesn't work, - add this timer. */ - - /* Sets GPO/GPIO sequences for this device */ - dev->analog_gpio = default_analog; - dev->digital_gpio = default_digital; - break; - - case EM2880_BOARD_MSI_DIGIVOX_AD: - case EM2880_BOARD_MSI_DIGIVOX_AD_II: - /* Sets GPO/GPIO sequences for this device */ - dev->analog_gpio = em2880_msi_digivox_ad_analog; - dev->digital_gpio = em2880_msi_digivox_ad_digital; - break; - case EM2861_BOARD_PLEXTOR_PX_TV100U: /* FIXME guess */ /* Turn on analog audio output */ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); break; - case EM2861_BOARD_KWORLD_PVRTV_300U: case EM2880_BOARD_KWORLD_DVB_305U: em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x6d); @@ -1387,12 +1502,6 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x7d); msleep(10); break; - - case EM2870_BOARD_KWORLD_355U: - /* Sets GPO/GPIO sequences for this device */ - dev->digital_gpio = em2870_kworld_355u_digital; - break; - case EM2870_BOARD_COMPRO_VIDEOMATE: /* TODO: someone can do some cleanup here... not everything's needed */ @@ -1409,7 +1518,6 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc); mdelay(70); break; - case EM2870_BOARD_TERRATEC_XS_MT2060: /* this device needs some gpio writes to get the DVB-T demod work */ @@ -1420,7 +1528,6 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); mdelay(70); break; - case EM2870_BOARD_PINNACLE_PCTV_DVB: /* this device needs some gpio writes to get the DVB-T demod work */ @@ -1431,27 +1538,18 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe); mdelay(70); break; - case EM2820_BOARD_GADMEI_UTV310: case EM2820_BOARD_MSI_VOX_USB_2: /* enables audio for that devices */ em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); break; - - case EM2874_BOARD_PINNACLE_PCTV_80E: - dev->digital_gpio = em2874_pinnacle_80e_digital; - break; } - /* Sets the default callback. Used only for certain tuners */ - if (!dev->tuner_gpio) - dev->tuner_gpio = default_callback; - - em28xx_gpio_set(dev, dev->tuner_gpio); + em28xx_gpio_set(dev, dev->board.tuner_gpio); em28xx_set_mode(dev, EM28XX_ANALOG_MODE); /* Unlock device */ - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); + em28xx_set_mode(dev, EM28XX_SUSPEND); } static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 339913c0d..f62b05eae 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -66,7 +66,8 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, char *buf, int len) { - int ret, byte; + int ret; + int pipe = usb_rcvctrlpipe(dev->udev, 0); if (dev->state & DEV_DISCONNECTED) return -ENODEV; @@ -74,10 +75,18 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, if (len > URB_MAX_CTRL_SIZE) return -EINVAL; - em28xx_regdbg("req=%02x, reg=%02x ", req, reg); + if (reg_debug) { + printk( KERN_DEBUG "(pipe 0x%08x): " + "IN: %02x %02x %02x %02x %02x %02x %02x %02x ", + pipe, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8); + } mutex_lock(&dev->ctrl_urb_lock); - ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, + ret = usb_control_msg(dev->udev, pipe, req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, dev->urb_buf, len, HZ); if (ret < 0) { @@ -93,7 +102,9 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, mutex_unlock(&dev->ctrl_urb_lock); if (reg_debug) { - printk("%02x values: ", ret); + int byte; + + printk("<<<"); for (byte = 0; byte < len; byte++) printk(" %02x", (unsigned char)buf[byte]); printk("\n"); @@ -108,28 +119,12 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, */ int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg) { - u8 val; int ret; + u8 val; - if (dev->state & DEV_DISCONNECTED) - return(-ENODEV); - - em28xx_regdbg("req=%02x, reg=%02x:", req, reg); - - mutex_lock(&dev->ctrl_urb_lock); - ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, dev->urb_buf, 1, HZ); - val = dev->urb_buf[0]; - mutex_unlock(&dev->ctrl_urb_lock); - - if (ret < 0) { - printk(" failed!\n"); + ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1); + if (ret < 0) return ret; - } - - if (reg_debug) - printk("%02x\n", (unsigned char) val); return val; } @@ -147,6 +142,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int len) { int ret; + int pipe = usb_sndctrlpipe(dev->udev, 0); if (dev->state & DEV_DISCONNECTED) return -ENODEV; @@ -154,17 +150,25 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) return -EINVAL; - em28xx_regdbg("req=%02x reg=%02x:", req, reg); if (reg_debug) { - int i; - for (i = 0; i < len; ++i) - printk(" %02x", (unsigned char)buf[i]); + int byte; + + printk( KERN_DEBUG "(pipe 0x%08x): " + "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", + pipe, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8); + + for (byte = 0; byte < len; byte++) + printk(" %02x", (unsigned char)buf[byte]); printk("\n"); } mutex_lock(&dev->ctrl_urb_lock); memcpy(dev->urb_buf, buf, len); - ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req, + ret = usb_control_msg(dev->udev, pipe, req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, dev->urb_buf, len, HZ); mutex_unlock(&dev->ctrl_urb_lock); @@ -554,20 +558,20 @@ EXPORT_SYMBOL_GPL(em28xx_audio_setup); int em28xx_colorlevels_set_default(struct em28xx *dev) { - em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */ - em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1); /* brightness */ - em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1); /* saturation */ - em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1); - em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1); - em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1); - - em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1); - em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1); - em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1); - em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1); - em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1); - em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1); - return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1); + em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10); /* contrast */ + em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00); /* brightness */ + em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */ + em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00); + em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00); + em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00); + + em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); + em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); + em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20); + em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20); + em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00); + em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00); + return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00); } int em28xx_capture_start(struct em28xx *dev, int start) @@ -600,17 +604,17 @@ int em28xx_capture_start(struct em28xx *dev, int start) if (!start) { /* disable video capture */ - rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x27", 1); + rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27); return rc; } /* enable video capture */ - rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); + rc = em28xx_write_reg(dev, 0x48, 0x00); if (dev->mode == EM28XX_ANALOG_MODE) - rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x67", 1); + rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); else - rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x37", 1); + rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); msleep(6); @@ -619,9 +623,9 @@ int em28xx_capture_start(struct em28xx *dev, int start) int em28xx_outfmt_set_yuv422(struct em28xx *dev) { - em28xx_write_regs(dev, EM28XX_R27_OUTFMT, "\x34", 1); - em28xx_write_regs(dev, EM28XX_R10_VINMODE, "\x10", 1); - return em28xx_write_regs(dev, EM28XX_R11_VINCTRL, "\x11", 1); + em28xx_write_reg(dev, EM28XX_R27_OUTFMT, 0x34); + em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10); + return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x11); } static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, @@ -737,12 +741,14 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) if (!gpio) return rc; - 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 (dev->mode != EM28XX_SUSPEND) { + em28xx_write_reg(dev, 0x48, 0x00); + if (dev->mode == EM28XX_ANALOG_MODE) + em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67); + else + em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); + msleep(6); + } /* Send GPIO reset sequences specified at board entry */ while (gpio->sleep >= 0) { @@ -767,22 +773,25 @@ int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode) if (dev->mode == set_mode) return 0; - if (set_mode == EM28XX_MODE_UNDEFINED) { + if (set_mode == EM28XX_SUSPEND) { dev->mode = set_mode; - return 0; + + /* FIXME: add suspend support for ac97 */ + + return em28xx_gpio_set(dev, dev->board.suspend_gpio); } #if 0 /* Resource is locked */ - if (dev->mode != EM28XX_MODE_UNDEFINED) + if (dev->mode != EM28XX_SUSPEND) return -EINVAL; #endif dev->mode = set_mode; if (dev->mode == EM28XX_DIGITAL_MODE) - return em28xx_gpio_set(dev, dev->digital_gpio); + return em28xx_gpio_set(dev, dev->board.dvb_gpio); else - return em28xx_gpio_set(dev, dev->analog_gpio); + return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio); } EXPORT_SYMBOL_GPL(em28xx_set_mode); diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c index 6e6509c7a..a06659f28 100644 --- a/linux/drivers/media/video/em28xx/em28xx-dvb.c +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -162,7 +162,7 @@ static int stop_streaming(struct em28xx_dvb *dvb) em28xx_uninit_isoc(dev); - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); + em28xx_set_mode(dev, EM28XX_SUSPEND); return 0; } @@ -216,7 +216,7 @@ static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) if (acquire) return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); else - return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); + return em28xx_set_mode(dev, EM28XX_SUSPEND); } /* ------------------------------------------------------------------ */ @@ -467,12 +467,12 @@ static int dvb_init(struct em28xx *dev) if (result < 0) goto out_free; - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); + em28xx_set_mode(dev, EM28XX_SUSPEND); printk(KERN_INFO "Successfully loaded em28xx-dvb\n"); return 0; out_free: - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); + em28xx_set_mode(dev, EM28XX_SUSPEND); kfree(dvb); dev->dvb = NULL; return result; diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 12f7fa0a3..00d49c45f 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -522,7 +522,7 @@ static int em28xx_config(struct em28xx *dev) /* Sets I2C speed to 100 KHz */ if (!dev->board.is_em2800) { - retval = em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1); + retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); if (retval < 0) { em28xx_errdev("%s: em28xx_write_regs_req failed! retval [%d]\n", __func__, retval); @@ -533,9 +533,9 @@ static int em28xx_config(struct em28xx *dev) #if 1 /* enable vbi capturing */ -/* em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */ -/* em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */ - em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1); +/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */ +/* em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */ + em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51); #endif dev->mute = 1; /* maybe not the right place... */ @@ -1760,7 +1760,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) /* do this before setting alternate! */ em28xx_uninit_isoc(dev); - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); + em28xx_set_mode(dev, EM28XX_SUSPEND); /* set alternate 0 */ dev->alt = 0; @@ -2165,7 +2165,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, if (dev->board.has_msp34xx) { /* Send a reset to other chips via gpio */ - errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); + errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); if (errCode < 0) { em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(1) failed! errCode [%d]\n", __func__, errCode); @@ -2173,7 +2173,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } msleep(3); - errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); + errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff); if (errCode < 0) { em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(2) failed! errCode [%d]\n", __func__, errCode); @@ -2258,6 +2258,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, struct em28xx *dev = NULL; int retval = -ENODEV; int i, nr, ifnum, isoc_pipe; + char *speed; + char descr[255] = ""; udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; @@ -2268,11 +2270,12 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n", - udev->descriptor.idVendor, - udev->descriptor.idProduct, - ifnum, - interface->altsetting[0].desc.bInterfaceClass); + em28xx_err(DRIVER_NAME " audio device (%04x:%04x): " + "interface %i, class %i\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting[0].desc.bInterfaceClass); em28xx_devused &= ~(1<<nr); return -ENODEV; @@ -2301,8 +2304,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (!check_interface) { em28xx_err(DRIVER_NAME " video device (%04x:%04x): " "interface %i, class %i found.\n", - udev->descriptor.idVendor, - udev->descriptor.idProduct, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), ifnum, interface->altsetting[0].desc.bInterfaceClass); @@ -2312,14 +2315,42 @@ static int em28xx_usb_probe(struct usb_interface *interface, em28xx_devused &= ~(1<<nr); return -ENODEV; } + } + switch (udev->speed) { + case USB_SPEED_LOW: + speed = "1.5"; + break; + case USB_SPEED_UNKNOWN: + case USB_SPEED_FULL: + speed = "12"; + break; + case USB_SPEED_HIGH: + speed = "480"; + break; + default: + speed = "unknown"; } - em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n", - udev->descriptor.idVendor, - udev->descriptor.idProduct, - ifnum, - interface->altsetting[0].desc.bInterfaceClass); + if (udev->manufacturer) + strlcpy(descr, udev->manufacturer, sizeof(descr)); + + if (udev->product) { + if (*descr) + strlcat(descr, " ", sizeof(descr)); + strlcat(descr, udev->product, sizeof(descr)); + } + if (*descr) + strlcat(descr, " ", sizeof(descr)); + + printk(DRIVER_NAME ": New device %s@ %s Mbps " + "(%04x:%04x, interface %d, class %d)\n", + descr, + speed, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + ifnum, + interface->altsetting->desc.bInterfaceNumber); if (nr >= EM28XX_MAXBOARDS) { printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index bea105250..667cb70cf 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -161,7 +161,7 @@ #define EM2800_I2C_WRITE_TIMEOUT 20 enum em28xx_mode { - EM28XX_MODE_UNDEFINED, + EM28XX_SUSPEND, EM28XX_ANALOG_MODE, EM28XX_DIGITAL_MODE, }; @@ -305,11 +305,18 @@ enum em28xx_aout { EM28XX_AOUT_SURR = 1 << 4, }; +struct em28xx_reg_seq { + int reg; + unsigned char val, mask; + int sleep; +}; + struct em28xx_input { enum enum28xx_itype type; unsigned int vmux; enum em28xx_amux amux; enum em28xx_aout aout; + struct em28xx_reg_seq *gpio; }; #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) @@ -320,12 +327,6 @@ enum em28xx_decoder { EM28XX_SAA711X, }; -struct em28xx_reg_seq { - int reg; - unsigned char val, mask; - int sleep; -}; - struct em28xx_board { char *name; int vchannels; @@ -335,6 +336,11 @@ struct em28xx_board { /* i2c flags */ unsigned int tda9887_conf; + /* GPIO sequences */ + struct em28xx_reg_seq *dvb_gpio; + struct em28xx_reg_seq *suspend_gpio; + struct em28xx_reg_seq *tuner_gpio; + unsigned int is_em2800:1; unsigned int has_msp34xx:1; unsigned int mts_firmware:1; @@ -437,12 +443,6 @@ struct em28xx { /* Some older em28xx chips needs a waiting time after writing */ unsigned int wait_after_write; - /* GPIO sequences for analog and digital mode */ - struct em28xx_reg_seq *analog_gpio, *digital_gpio; - - /* GPIO sequences for tuner callbacks */ - struct em28xx_reg_seq *tuner_gpio; - struct list_head devlist; u32 i2s_speed; /* I2S speed for audio digital stream */ @@ -630,7 +630,7 @@ int em28xx_ir_fini(struct em28xx *dev); static inline int em28xx_compression_disable(struct em28xx *dev) { /* side effect of disabling scaler and mixer */ - return em28xx_write_regs(dev, EM28XX_R26_COMPR, "\x00", 1); + return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00); } static inline int em28xx_contrast_get(struct em28xx *dev) diff --git a/v4l2-apps/util/parse_em28xx.pl b/v4l2-apps/util/parse_em28xx.pl new file mode 100755 index 000000000..d1bbb0f0d --- /dev/null +++ b/v4l2-apps/util/parse_em28xx.pl @@ -0,0 +1,278 @@ +#!/usr/bin/perl + +# Copyright (C) 2008 Mauro Carvalho Chehab <mchehab@redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# This small script parses register dumps generated by em28xx driver +# with debug options enabled, generating a source code with the results +# of the dump. +# +# To use it, you may modprobe em28xx with reg_debug=1, and do: +# dmesg | ./parse_em28xx.pl +# +# Also, there are other utilities that produce similar outputs, and it +# is not hard to parse some USB analyzers log into the expected format. +# +# It will parse anything (including this file) with a format similar to: +# +# 40 00 00 00 48 00 01 00 >>> 00 +# 40 00 00 00 12 00 01 00 >>> 37 +# 40 00 00 00 08 00 01 00 >>> 3d +# 40 00 00 00 08 00 01 00 >>> 2d +# 40 00 00 00 08 00 01 00 >>> 3d +# 40 00 00 00 48 00 01 00 >>> 00 +# 40 00 00 00 12 00 01 00 >>> 37 +# 40 00 00 00 08 00 01 00 >>> 3d +# 40 00 00 00 08 00 01 00 >>> 2d +# 40 00 00 00 08 00 01 00 >>> 3d +# c0 00 00 00 43 00 01 00 <<< 00 +# 40 00 00 00 42 00 01 00 >>> fc +# c0 00 00 00 40 00 02 00 <<< ff ff +# c0 00 00 00 43 00 01 00 <<< 00 +# 40 00 00 00 42 00 01 00 >>> fe +# c0 00 00 00 40 00 02 00 <<< ff ff +# c0 00 00 00 43 00 01 00 <<< 00 +# 40 00 00 00 42 00 01 00 >>> 80 +# c0 00 00 00 40 00 02 00 <<< 90 6a +# +# Producing a much easier to understand series of C function calls: +# +# em28xx_write_reg(dev, 0x48, 0x00); +# em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); +# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x3d); +# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x2d); +# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x3d); +# em28xx_write_reg(dev, 0x48, 0x00); +# em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); +# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x3d); +# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x2d); +# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x3d); +# em28xx_read_ac97(dev, AC97_VENDOR_ID1); /* read 0x0xffff */ +# em28xx_read_ac97(dev, AC97_VENDOR_ID2); /* read 0x0xffff */ +# em28xx_read_ac97(dev, AC97_RESET); /* read 0x0x6a90 */ +# +# This way, it is easier to understand what the em28xx driver is doing. +# +# Known limitations: +# - Currently, the tool only parses em28xx, ac97 and em202 registers. +# - It is limited to read/write operations with 1 or 2 bytes of +# arguments; +# - Not all registers are documented; +# - It doesn't parse em2800-only registers; +# - em28xx currently doesn't implement em28xx_read_reg16() or +# em28xx_write_reg16(). However, this tool uses those two "functions" +# meaning to read or write 2 consecutive bytes, ordering arguments +# in big-endian notation. +# + +use strict; + +my %reg_map = ( + "0x00" => "EM28XX_R00_CHIPCFG", + "0x04" => "EM2880_R04_GPO", + "0x08" => "EM28XX_R08_GPIO", + "0x06" => "EM28XX_R06_I2C_CLK", + "0x0a" => "EM28XX_R0A_CHIPID", + "0x0c" => "EM28XX_R0C_USBSUSP", + "0x0e" => "EM28XX_R0E_AUDIOSRC", + "0x0f" => "EM28XX_R0F_XCLK", + "0x20" => "EM28XX_XCLK_IR_RC5_MODE", + "0x10" => "EM28XX_R10_VINMODE", + "0x11" => "EM28XX_R11_VINCTRL", + "0x12" => "EM28XX_R12_VINENABLE", + "0x14" => "EM28XX_R14_GAMMA", + "0x15" => "EM28XX_R15_RGAIN", + "0x16" => "EM28XX_R16_GGAIN", + "0x17" => "EM28XX_R17_BGAIN", + "0x18" => "EM28XX_R18_ROFFSET", + "0x19" => "EM28XX_R19_GOFFSET", + "0x1a" => "EM28XX_R1A_BOFFSET", + "0x1b" => "EM28XX_R1B_OFLOW", + "0x1c" => "EM28XX_R1C_HSTART", + "0x1d" => "EM28XX_R1D_VSTART", + "0x1e" => "EM28XX_R1E_CWIDTH", + "0x1f" => "EM28XX_R1F_CHEIGHT", + "0x20" => "EM28XX_R20_YGAIN", + "0x21" => "EM28XX_R21_YOFFSET", + "0x22" => "EM28XX_R22_UVGAIN", + "0x23" => "EM28XX_R23_UOFFSET", + "0x24" => "EM28XX_R24_VOFFSET", + "0x25" => "EM28XX_R25_SHARPNESS", + "0x26" => "EM28XX_R26_COMPR", + "0x27" => "EM28XX_R27_OUTFMT", + "0x28" => "EM28XX_R28_XMIN", + "0x29" => "EM28XX_R29_XMAX", + "0x2a" => "EM28XX_R2A_YMIN", + "0x2b" => "EM28XX_R2B_YMAX", + "0x30" => "EM28XX_R30_HSCALELOW", + "0x31" => "EM28XX_R31_HSCALEHIGH", + "0x32" => "EM28XX_R32_VSCALELOW", + "0x33" => "EM28XX_R33_VSCALEHIGH", + "0x40" => "EM28XX_R40_AC97LSB", + "0x41" => "EM28XX_R41_AC97MSB", + "0x42" => "EM28XX_R42_AC97ADDR", + "0x43" => "EM28XX_R43_AC97BUSY", + "0x45" => "EM28XX_R45_IR", + "0x50" => "EM2874_R50_IR_CONFIG", + "0x51" => "EM2874_R51_IR", + "0x5f" => "EM2874_R5F_TS_ENABLE", + "0x80" => "EM2874_R80_GPIO", +); + +my %ac97_map = ( + "0x00" => "AC97_RESET", + "0x02" => "AC97_MASTER_VOL", + "0x04" => "AC97_LINE_LEVEL_VOL", + "0x06" => "AC97_MASTER_MONO_VOL", + "0x0a" => "AC97_PC_BEEP_VOL", + "0x0c" => "AC97_PHONE_VOL", + "0x0e" => "AC97_MIC_VOL", + "0x10" => "AC97_LINEIN_VOL", + "0x12" => "AC97_CD_VOL", + "0x14" => "AC97_VIDEO_VOL", + "0x16" => "AC97_AUX_VOL", + "0x18" => "AC97_PCM_OUT_VOL", + "0x1a" => "AC97_RECORD_SELECT", + "0x1c" => "AC97_RECORD_GAIN", + "0x20" => "AC97_GENERAL_PURPOSE", + "0x22" => "AC97_3D_CTRL", + "0x24" => "AC97_AUD_INT_AND_PAG", + "0x26" => "AC97_POWER_DOWN_CTRL", + "0x28" => "AC97_EXT_AUD_ID", + "0x2a" => "AC97_EXT_AUD_CTRL", + "0x2c" => "AC97_PCM_OUT_FRONT_SRATE", + "0x2e" => "AC97_PCM_OUT_SURR_SRATE", + "0x30" => "AC97_PCM_OUT_LFE_SRATE", + "0x32" => "AC97_PCM_IN_SRATE", + "0x36" => "AC97_LFE_MASTER_VOL", + "0x38" => "AC97_SURR_MASTER_VOL", + "0x3a" => "AC97_SPDIF_OUT_CTRL", + "0x7c" => "AC97_VENDOR_ID1", + "0x7e" => "AC97_VENDOR_ID2", + + # em202 specific AC97 registers + + "0x3e" => "EM202_EXT_MODEM_CTRL", + "0x4c" => "EM202_GPIO_CONF", + "0x4e" => "EM202_GPIO_POLARITY", + "0x50" => "EM202_GPIO_STICKY", + "0x52" => "EM202_GPIO_MASK", + "0x54" => "EM202_GPIO_STATUS", + "0x6a" => "EM202_SPDIF_OUT_SEL", + "0x72" => "EM202_ANTIPOP", + "0x74" => "EM202_EAPD_GPIO_ACCESS", +); + +my ($r40, $r42, $r43, $dir); + +sub output_ac97() +{ + if (hex($r42) < 0x80) { + if ($dir < 0) { + return; + } + $r42 = $ac97_map{$r42} if defined($ac97_map{$r42}); + printf "em28xx_write_ac97(dev, %s, %s);\n",$r42, $r40; + $r43 = 0; + + return; + } + + if ($dir > 0) { + return; + } + $r42 = sprintf("0x%02x", hex($r42) - 0x80); + $r42 = $ac97_map{$r42} if defined($ac97_map{$r42}); + printf "em28xx_read_ac97(dev, %s);\t/* read 0x%s */\n",$r42, $r40; + $r43 = 0; +} + +while (<>) { + tr/A-F/a-f/; + if (m/c0 00 00 00 ([0-9a-f].) 00 01 00\s+[\<]+\s+([0-9a-f].)/) { + if ($1 eq "43" && $2 eq "00") { + $r43 = 1; + $r40 = -1; + $r42 = -1; + $dir = 0; + next; + } + + my $reg = "0x$1"; + $reg = $reg_map{$reg} if defined($reg_map{$reg}); + + printf "em28xx_read_reg(dev, %s);\t\t/* read 0x%s */\n", + $reg, $2; + next; + } + if (m/40 00 00 00 ([0-9a-f].) 00 01 00\s+[\>]+\s+([0-9a-f].)/) { + if ($r43 == 1) { + if ($1 eq "42") { + $r42 = "0x$2"; + if ($r40 >= 0) { + output_ac97(); + next; + } + next; + } + $r43 = 0; + } + + my $reg = "0x$1"; + $reg = $reg_map{$reg} if defined($reg_map{$reg}); + + printf "em28xx_write_reg(dev, %s, 0x%s);\n", + $reg, $2; + next; + } + if (m/c0 00 00 00 ([0-9a-f].) 00 02 00\s+[\<]+\s+([0-9a-f].) ([0-9a-f].)/) { + if ($r43 == 1) { + if ($1 eq "40") { + $r40 = "0x$3$2"; + $dir = -1; + + if ($r42 >= 0) { + output_ac97(); + next; + } + next; + } + $r43 = 0; + } + my $reg = "0x$1"; + $reg = $reg_map{$reg} if defined($reg_map{$reg}); + + printf "em28xx_read_reg16(dev, %s);\t\t/*read 0x%s%s */\n", + $reg, $3, $2; + next; + } + if (m/40 00 00 00 ([0-9a-f].) 00 02 00\s+[\>]+\s+([0-9a-f].) ([0-9a-f].)/) { + if ($r43 == 1) { + if ($1 eq "40") { + $r40 = "0x$3$2"; + $dir = 1; + + if ($r42 >= 0) { + output_ac97(); + next; + } + next; + } + $r43 = 0; + } + my $reg = "0x$1"; + $reg = $reg_map{$reg} if defined($reg_map{$reg}); + + printf "em28xx_write_reg16(dev, %s,0x%s%s);\n", + $reg, $3, $2; + next; + } +} |