1#!/usr/bin/perl
2
3#   Copyright (C) 2010 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 cx231xx 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 cx231xx 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
25use strict;
26
27my %cfg_reg_map = (
28	0x0 => "BOARD_CFG_STAT",
29	0x4 => "TS_MODE_REG",
30	0x8 => "TS1_CFG_REG",
31	0xc => "TS1_LENGTH_REG",
32	0x10 => "TS2_CFG_REG",
33	0x14 => "TS2_LENGTH_REG",
34	0x18 => "EP_MODE_SET",
35	0x1c => "CIR_PWR_PTN1",
36	0x20 => "CIR_PWR_PTN2",
37	0x24 => "CIR_PWR_PTN3",
38	0x28 => "CIR_PWR_MASK0",
39	0x2c => "CIR_PWR_MASK1",
40	0x30 => "CIR_PWR_MASK2",
41	0x34 => "CIR_GAIN",
42	0x38 => "CIR_CAR_REG",
43	0x40 => "CIR_OT_CFG1",
44	0x44 => "CIR_OT_CFG2",
45	0x68 => "GBULK_BIT_EN",
46	0x74 => "PWR_CTL_EN",
47);
48
49sub parse_i2c($$$$$$)
50{
51	my $reqtype = shift;
52	my $req = shift;
53	my $wvalue = shift;
54	my $windex = shift;
55	my $wlen = shift;
56	my $payload = shift;
57
58	my $daddr = $wvalue >> 9;
59	my $reserved = ($wvalue >>6 ) & 0x07;
60	my $period = ($wvalue >> 4) & 0x03;
61	my $addr_len = ($wvalue >> 2) & 0x03;
62	my $nostop = ($wvalue >>1) & 0x01;
63	my $sync = $wvalue & 0x01;
64
65	if ($nostop) {
66		$nostop="nostop ";
67	} else {
68		$nostop="";
69	}
70	if ($sync) {
71		$sync="sync ";
72	} else {
73		$sync="";
74	}
75	my $type;
76	my $i2c_channel;
77	if ($reqtype > 128) {
78		$type = "IN ";
79		$i2c_channel = $req - 4;
80	} else {
81		$type = "OUT";
82		$i2c_channel = $req;
83	}
84	if ($period == 0) {
85		$period = "1Mbps";
86	} elsif ($period == 1) {
87		$period = "400kbps";
88	} elsif ($period == 2) {
89		$period = "100kbps";
90	} else {
91		$period = "???kbps";
92	}
93	printf("$type i2c channel#%d daddr 0x%02x %s addr_len %d %s%slen %d = ",
94		$i2c_channel, $daddr, $period, $addr_len, $nostop, $sync,
95		$wlen);
96	if ($addr_len == 1) {
97		printf("(saddr)%02x ", $windex & 0xff);
98	} elsif ($addr_len == 2) {
99		printf("(saddr)%04x ", $windex);
100	}
101	printf("$payload\n");
102}
103
104sub parse_gpio($$$$$$)
105{
106	my $reqtype = shift;
107	my $req = shift;
108	my $wvalue = shift;
109	my $windex = shift;
110	my $wlen = shift;
111	my $payload = shift;
112
113	my $type;
114	if ($req == 8) {
115		$type .= "SET gpio";
116	} elsif ($req == 9) {
117		$type .= "GET gpio";
118	} elsif ($req == 0xa) {
119		$type .= "SET gpie";
120	} elsif ($req == 0xb) {
121		$type .= "GET gpie";
122	}
123
124	my $gpio_bit = ($wvalue << 16) | $windex;
125
126	$payload =~ s/([a-f\d].)\s([a-f\d].)\s([a-f\d].)\s([a-f\d].)/0x$4$3$2$1/;
127
128	printf("$type: Reqtype %3d Req %3d len %d wvalue 0x%04x windex 0x%02x => direction=0x%04x val = %s\n",
129		$reqtype, $req, $wlen, $wvalue, $windex, $gpio_bit, $payload);
130}
131
132while (<>) {
133	tr/A-F/a-f/;
134	if (m/([4c]0) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].)[\<\>\s]+(.*)/) {
135		my $reqtype = hex($1);
136		my $req = hex($2);
137		my $wvalue = hex("$4$3");
138		my $windex = hex("$6$5");
139		my $wlen = hex("$8$7");
140		my $payload = $9;
141
142		if ($reqtype > 128 && (($req >= 4) && ($req <= 6))) {
143			parse_i2c($reqtype, $req, $wvalue, $windex, $wlen, $payload);
144		} elsif ($req < 3) {
145			parse_i2c($reqtype, $req, $wvalue, $windex, $wlen, $payload);
146		} elsif ($req >= 8 && $req <= 0xb) {
147			parse_gpio($reqtype, $req, $wvalue, $windex, $wlen, $payload);
148		} elsif ($req == 0xc) {
149			my $cfg_len;
150			if ($wvalue == 1) {
151				$cfg_len = 1;
152			} elsif($wvalue == 3) {
153				$cfg_len = 2;
154			} elsif($wvalue == 7) {
155				$cfg_len = 3;
156			} elsif($wvalue == 0xf) {
157				$cfg_len = 4;
158			} else {
159				printf("Invalid get len for ");
160				printf("Reqtype: %3d, Req %3d, wValue: 0x%04x, wIndex 0x%04x, wlen %d: %s\n",
161					$reqtype, $req, $wvalue, $windex, $wlen, $payload);
162			}
163
164			if ($cfg_len) {
165				my $reg = $windex;
166				$reg = $cfg_reg_map{$windex} if defined($cfg_reg_map{$windex});
167
168				printf "cx231xx_write_ctrl_reg(dev, $reg, $payload, $cfg_len);\n";
169			}
170		} elsif ($req == 0xd) {
171			my $cfg_len;
172			if ($wvalue == 1) {
173				$cfg_len = 1;
174			} elsif($wvalue == 3) {
175				$cfg_len = 2;
176			} elsif($wvalue == 7) {
177				$cfg_len = 3;
178			} elsif($wvalue == 0xf) {
179				$cfg_len = 4;
180			} else {
181				printf("Invalid get len for ");
182				printf("Reqtype: %3d, Req %3d, wValue: 0x%04x, wIndex 0x%04x, wlen %d: %s\n",
183					$reqtype, $req, $wvalue, $windex, $wlen, $payload);
184			}
185			if ($cfg_len) {
186				my $reg = $windex;
187				$reg = $cfg_reg_map{$windex} if defined($cfg_reg_map{$windex});
188
189				printf "cx231xx_read_ctrl_reg(dev, $reg, $cfg_len);\t\t/* read %s */\n",
190					$payload;
191			}
192		} else {
193			printf("Reqtype: %3d, Req %3d, wValue: 0x%04x, wIndex 0x%04x, wlen %d: %s\n",
194				$reqtype, $req, $wvalue, $windex, $wlen, $payload);
195		}
196	}
197}
198