diff options
Diffstat (limited to 'v4l2-apps/util')
-rwxr-xr-x | v4l2-apps/util/parse_em28xx.pl | 278 |
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; + } +} |