1#!/usr/bin/perl 2 3# Copyright (C) 2008-2011 Mauro Carvalho Chehab 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, version 2 of the License. 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# This small script parses register dumps generated by em28xx driver 15# with debug options enabled, generating a source code with the results 16# of the dump. 17# 18# To use it, you may modprobe em28xx with reg_debug=1, and do: 19# dmesg | ./parse_em28xx.pl 20# 21# Also, there are other utilities that produce similar outputs, and it 22# is not hard to parse some USB analyzers log into the expected format. 23# 24# It will parse anything (including this file) with a format similar to: 25# 26# 40 00 00 00 48 00 01 00 >>> 00 27# 40 00 00 00 12 00 01 00 >>> 37 28# 40 00 00 00 08 00 01 00 >>> 3d 29# 40 00 00 00 08 00 01 00 >>> 2d 30# 40 00 00 00 08 00 01 00 >>> 3d 31# 40 00 00 00 48 00 01 00 >>> 00 32# 40 00 00 00 12 00 01 00 >>> 37 33# 40 00 00 00 08 00 01 00 >>> 3d 34# 40 00 00 00 08 00 01 00 >>> 2d 35# 40 00 00 00 08 00 01 00 >>> 3d 36# c0 00 00 00 43 00 01 00 <<< 00 37# 40 00 00 00 42 00 01 00 >>> fc 38# c0 00 00 00 40 00 02 00 <<< ff ff 39# c0 00 00 00 43 00 01 00 <<< 00 40# 40 00 00 00 42 00 01 00 >>> fe 41# c0 00 00 00 40 00 02 00 <<< ff ff 42# c0 00 00 00 43 00 01 00 <<< 00 43# 40 00 00 00 42 00 01 00 >>> 80 44# c0 00 00 00 40 00 02 00 <<< 90 6a 45# 46# Producing a much easier to understand series of C function calls: 47# 48# em28xx_write_reg(dev, 0x48, 0x00); 49# em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); 50# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x3d); 51# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x2d); 52# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x3d); 53# em28xx_write_reg(dev, 0x48, 0x00); 54# em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37); 55# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x3d); 56# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x2d); 57# em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x3d); 58# em28xx_read_ac97(dev, AC97_VENDOR_ID1); /* read 0x0xffff */ 59# em28xx_read_ac97(dev, AC97_VENDOR_ID2); /* read 0x0xffff */ 60# em28xx_read_ac97(dev, AC97_RESET); /* read 0x0x6a90 */ 61# 62# This way, it is easier to understand what the em28xx driver is doing. 63# 64# Known limitations: 65# - Currently, the tool only parses em28xx, i2c, ac97 and em202 registers. 66# - It is limited to read/write operations with 1 or 2 bytes of 67# arguments; 68# - Not all registers are documented; 69# - It doesn't parse em2800-only registers; 70# - em28xx currently doesn't implement em28xx_read_reg16() or 71# em28xx_write_reg16(). However, this tool uses those two "functions" 72# meaning to read or write 2 consecutive bytes, ordering arguments 73# in big-endian notation. 74# 75 76use strict; 77 78my %reg_map = ( 79 "0x00" => "EM28XX_R00_CHIPCFG", 80 "0x04" => "EM2880_R04_GPO", 81 "0x08" => "EM28XX_R08_GPIO", 82 "0x06" => "EM28XX_R06_I2C_CLK", 83 "0x0a" => "EM28XX_R0A_CHIPID", 84 "0x0c" => "EM28XX_R0C_USBSUSP", 85 "0x0e" => "EM28XX_R0E_AUDIOSRC", 86 "0x0f" => "EM28XX_R0F_XCLK", 87 "0x20" => "EM28XX_XCLK_IR_RC5_MODE", 88 "0x10" => "EM28XX_R10_VINMODE", 89 "0x11" => "EM28XX_R11_VINCTRL", 90 "0x12" => "EM28XX_R12_VINENABLE", 91 "0x14" => "EM28XX_R14_GAMMA", 92 "0x15" => "EM28XX_R15_RGAIN", 93 "0x16" => "EM28XX_R16_GGAIN", 94 "0x17" => "EM28XX_R17_BGAIN", 95 "0x18" => "EM28XX_R18_ROFFSET", 96 "0x19" => "EM28XX_R19_GOFFSET", 97 "0x1a" => "EM28XX_R1A_BOFFSET", 98 "0x1b" => "EM28XX_R1B_OFLOW", 99 "0x1c" => "EM28XX_R1C_HSTART", 100 "0x1d" => "EM28XX_R1D_VSTART", 101 "0x1e" => "EM28XX_R1E_CWIDTH", 102 "0x1f" => "EM28XX_R1F_CHEIGHT", 103 "0x20" => "EM28XX_R20_YGAIN", 104 "0x21" => "EM28XX_R21_YOFFSET", 105 "0x22" => "EM28XX_R22_UVGAIN", 106 "0x23" => "EM28XX_R23_UOFFSET", 107 "0x24" => "EM28XX_R24_VOFFSET", 108 "0x25" => "EM28XX_R25_SHARPNESS", 109 "0x26" => "EM28XX_R26_COMPR", 110 "0x27" => "EM28XX_R27_OUTFMT", 111 "0x28" => "EM28XX_R28_XMIN", 112 "0x29" => "EM28XX_R29_XMAX", 113 "0x2a" => "EM28XX_R2A_YMIN", 114 "0x2b" => "EM28XX_R2B_YMAX", 115 "0x30" => "EM28XX_R30_HSCALELOW", 116 "0x31" => "EM28XX_R31_HSCALEHIGH", 117 "0x32" => "EM28XX_R32_VSCALELOW", 118 "0x33" => "EM28XX_R33_VSCALEHIGH", 119 "0x34" => "EM28XX_R34_VBI_START_H", 120 "0x35" => "EM28XX_R35_VBI_START_V", 121 "0x36" => "EM28XX_R36_VBI_WIDTH", 122 "0x37" => "EM28XX_R37_VBI_HEIGHT", 123 "0x40" => "EM28XX_R40_AC97LSB", 124 "0x41" => "EM28XX_R41_AC97MSB", 125 "0x42" => "EM28XX_R42_AC97ADDR", 126 "0x43" => "EM28XX_R43_AC97BUSY", 127 "0x45" => "EM28XX_R45_IR", 128 "0x50" => "EM2874_R50_IR_CONFIG", 129 "0x51" => "EM2874_R51_IR", 130 "0x5f" => "EM2874_R5F_TS_ENABLE", 131 "0x80" => "EM2874_R80_GPIO", 132); 133 134my %ac97_map = ( 135 "0x00" => "AC97_RESET", 136 "0x02" => "AC97_MASTER_VOL", 137 "0x04" => "AC97_LINE_LEVEL_VOL", 138 "0x06" => "AC97_MASTER_MONO_VOL", 139 "0x0a" => "AC97_PC_BEEP_VOL", 140 "0x0c" => "AC97_PHONE_VOL", 141 "0x0e" => "AC97_MIC_VOL", 142 "0x10" => "AC97_LINEIN_VOL", 143 "0x12" => "AC97_CD_VOL", 144 "0x14" => "AC97_VIDEO_VOL", 145 "0x16" => "AC97_AUX_VOL", 146 "0x18" => "AC97_PCM_OUT_VOL", 147 "0x1a" => "AC97_RECORD_SELECT", 148 "0x1c" => "AC97_RECORD_GAIN", 149 "0x20" => "AC97_GENERAL_PURPOSE", 150 "0x22" => "AC97_3D_CTRL", 151 "0x24" => "AC97_AUD_INT_AND_PAG", 152 "0x26" => "AC97_POWER_DOWN_CTRL", 153 "0x28" => "AC97_EXT_AUD_ID", 154 "0x2a" => "AC97_EXT_AUD_CTRL", 155 "0x2c" => "AC97_PCM_OUT_FRONT_SRATE", 156 "0x2e" => "AC97_PCM_OUT_SURR_SRATE", 157 "0x30" => "AC97_PCM_OUT_LFE_SRATE", 158 "0x32" => "AC97_PCM_IN_SRATE", 159 "0x36" => "AC97_LFE_MASTER_VOL", 160 "0x38" => "AC97_SURR_MASTER_VOL", 161 "0x3a" => "AC97_SPDIF_OUT_CTRL", 162 "0x7c" => "AC97_VENDOR_ID1", 163 "0x7e" => "AC97_VENDOR_ID2", 164 165 # em202 specific AC97 registers 166 167 "0x3e" => "EM202_EXT_MODEM_CTRL", 168 "0x4c" => "EM202_GPIO_CONF", 169 "0x4e" => "EM202_GPIO_POLARITY", 170 "0x50" => "EM202_GPIO_STICKY", 171 "0x52" => "EM202_GPIO_MASK", 172 "0x54" => "EM202_GPIO_STATUS", 173 "0x6a" => "EM202_SPDIF_OUT_SEL", 174 "0x72" => "EM202_ANTIPOP", 175 "0x74" => "EM202_EAPD_GPIO_ACCESS", 176); 177 178my ($r40, $r42, $r43, $dir); 179 180sub output_ac97() 181{ 182 if (hex($r42) < 0x80) { 183 if ($dir < 0) { 184 return; 185 } 186 $r42 = $ac97_map{$r42} if defined($ac97_map{$r42}); 187 printf "em28xx_write_ac97(dev, %s, %s);\n",$r42, $r40; 188 $r43 = 0; 189 190 return; 191 } 192 193 if ($dir > 0) { 194 return; 195 } 196 $r42 = sprintf("0x%02x", hex($r42) - 0x80); 197 $r42 = $ac97_map{$r42} if defined($ac97_map{$r42}); 198 printf "em28xx_read_ac97(dev, %s);\t/* read 0x%s */\n",$r42, $r40; 199 $r43 = 0; 200} 201 202while (<>) { 203 tr/A-F/a-f/; 204 if (m/c0 00 00 00 ([0-9a-f].) 00 01 00\s+[\<]+\s+([0-9a-f].)/) { 205 if ($1 eq "43" && $2 eq "00") { 206 $r43 = 1; 207 $r40 = -1; 208 $r42 = -1; 209 $dir = 0; 210 next; 211 } 212 213 my $reg = "0x$1"; 214 $reg = $reg_map{$reg} if defined($reg_map{$reg}); 215 216 printf "em28xx_read_reg(dev, %s);\t\t/* read 0x%s */\n", 217 $reg, $2; 218 next; 219 } 220 if (m/40 00 00 00 ([0-9a-f].) 00 01 00\s+[\>]+\s+([0-9a-f].)/) { 221 if ($r43 == 1) { 222 if ($1 eq "42") { 223 $r42 = "0x$2"; 224 if ($r40 >= 0) { 225 output_ac97(); 226 next; 227 } 228 next; 229 } 230 $r43 = 0; 231 } 232 233 my $reg = "0x$1"; 234 $reg = $reg_map{$reg} if defined($reg_map{$reg}); 235 236 printf "em28xx_write_reg(dev, %s, 0x%s);\n", 237 $reg, $2; 238 next; 239 } 240 if (m/c0 00 00 00 ([0-9a-f].) 00 02 00\s+[\<]+\s+([0-9a-f].) ([0-9a-f].)/) { 241 if ($r43 == 1) { 242 if ($1 eq "40") { 243 $r40 = "0x$3$2"; 244 $dir = -1; 245 246 if ($r42 >= 0) { 247 output_ac97(); 248 next; 249 } 250 next; 251 } 252 $r43 = 0; 253 } 254 my $reg = "0x$1"; 255 $reg = $reg_map{$reg} if defined($reg_map{$reg}); 256 257 printf "em28xx_read_reg16(dev, %s);\t\t/*read 0x%s%s */\n", 258 $reg, $3, $2; 259 next; 260 } 261 if (m/40 00 00 00 ([0-9a-f].) 00 02 00\s+[\>]+\s+([0-9a-f].) ([0-9a-f].)/) { 262 if ($r43 == 1) { 263 if ($1 eq "40") { 264 $r40 = "0x$3$2"; 265 $dir = 1; 266 267 if ($r42 >= 0) { 268 output_ac97(); 269 next; 270 } 271 next; 272 } 273 $r43 = 0; 274 } 275 my $reg = "0x$1"; 276 $reg = $reg_map{$reg} if defined($reg_map{$reg}); 277 278 printf "em28xx_write_reg16(dev, %s,0x%s%s);\n", 279 $reg, $3, $2; 280 next; 281 } 282 283 if (m/40 0[23] 00 00 ([0-9a-f].) 00 ([0-9a-f].) 00\s+[\>]+\s+([0-9a-f ]+)/) { 284 printf "i2c_master_send(0x$1>>1, { $3 }, 0x$2);\n"; 285 next; 286 } 287 if (m/c0 0[23] 00 00 ([0-9a-f].) 00 ([0-9a-f].) 00\s+[\<]+\s+([0-9a-f ]+)/) { 288 printf "i2c_master_recv(0x$1>>1, &buf, 0x$2); /* $3 */\n"; 289 next; 290 } 291 if (m/c0 0[23] 00 00 ([0-9a-f].) 00 ([0-9a-f].) 00\s+[\<]+/) { 292 printf "i2c_master_recv(0x$1>>1, &buf, 0x$2); /* nothing returned */\n"; 293 next; 294 } 295} 296