summaryrefslogtreecommitdiff
path: root/v4l2-apps/util
diff options
context:
space:
mode:
Diffstat (limited to 'v4l2-apps/util')
-rwxr-xr-xv4l2-apps/util/parse_em28xx.pl278
1 files changed, 278 insertions, 0 deletions
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;
+ }
+}