summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c382
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c129
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c8
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c69
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h28
-rwxr-xr-xv4l2-apps/util/parse_em28xx.pl278
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;
+ }
+}