• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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