• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 USB dumps generated by several drivers,
15# decoding USB bits.
16#
17# To use it, do:
18# dmesg | ./parse_usb.pl
19#
20# Also, there are other utilities that produce similar outputs, and it
21# is not hard to parse some USB analyzers log into the expected format.
22#
23use strict;
24use Getopt::Long;
25
26my $debug = 0;
27GetOptions('d' => \$debug);
28
29# FIXME: How to handle multiple registers being changed at the same time?
30
31my %reg_map = (
32	0x10e0 => "SN9C201_R10E0_IMG_FMT",
33	0x1180 => "SN9C201_R1180_HSTART_LOW",
34	0x1181 => "SN9C201_R1181_HSTART_HIGH",
35	0x1182 => "SN9C201_R1182_VSTART_LOW",
36	0x1183 => "SN9C201_R1183_VSTART_HIGH",
37	0x1184 => "SN9C201_R1184_HSIZE",
38	0x1185 => "SN9C201_R1185_VSIZE",
39	0x1189 => "SN9C201_R1189_SCALE",
40	0x11b8 => "SN9C201_R11B8_CLK_CTRL",
41);
42
43
44sub i2c_reg($)
45{
46	my %decode;
47	my $reg = shift;
48
49	$reg =~ s/\s+.*//;
50	$reg = hex("$reg");
51
52	if ($reg & 0x01) {
53		$decode{"speed"} = "400kbps";
54	} else {
55		$decode{"speed"} = "100kbps";
56	}
57	if ($reg & 0x02) {
58		$decode{"op"} = "RD";
59	} else {
60		$decode{"op"} = "WR";
61	}
62	$decode{"busy"} = "BUSY" if (($reg & 0x04) == 0);
63	$decode{"err"} = "ERR" if ($reg & 0x08);
64	$decode{"size"} = ($reg >> 4) & 7;
65	$decode{"i2c"} = "3wire" if (($reg & 0x80) == 0);
66
67	return %decode;
68}
69
70sub type_req($)
71{
72	my $reqtype = shift;
73	my $s;
74
75	if ($reqtype & 0x80) {
76		$s = "RD ";
77	} else {
78		$s = "WR ";
79	}
80	if (($reqtype & 0x60) == 0x20) {
81		$s .= "CLAS ";
82	} elsif (($reqtype & 0x60) == 0x40) {
83		$s .= "VEND ";
84	} elsif (($reqtype & 0x60) == 0x60) {
85		$s .= "RSVD ";
86	}
87
88	if (($reqtype & 0x1f) == 0x00) {
89		$s .= "DEV ";
90	} elsif (($reqtype & 0x1f) == 0x01) {
91		$s .= "INT ";
92	} elsif (($reqtype & 0x1f) == 0x02) {
93		$s .= "EP ";
94	} elsif (($reqtype & 0x1f) == 0x03) {
95		$s .= "OTHER ";
96	} elsif (($reqtype & 0x1f) == 0x04) {
97		$s .= "PORT ";
98	} elsif (($reqtype & 0x1f) == 0x05) {
99		$s .= "RPIPE ";
100	} else {
101		$s .= sprintf "RECIP 0x%02x ", $reqtype & 0x1f;
102	}
103
104	$s =~ s/\s+$//;
105	return $s;
106}
107
108my %i2c;
109my $i2c_id;
110while (<>) {
111	tr/A-F/a-f/;
112	if (m/([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].) ([0-9a-f].)[\<\>\s]+(.*)/) {
113		my $reqtype = hex($1);
114		my $req = hex($2);
115		my $wvalue = hex("$4$3");
116		my $windex = hex("$6$5");
117		my $wlen = hex("$8$7");
118		my $payload = $9;
119		my $fullpayload = $9;
120
121		%i2c = i2c_reg($payload) if ($wvalue == 0x10c0);
122
123		if (($wvalue >= 0x10c0) && ($wvalue <= 0x10c2)) {
124			my $reg = $wvalue;
125			if ($reg == 0x10c0) {
126				$payload =~ s/^([0-9a-f].)//;
127				$payload =~ s/^\s+//;
128				$reg++;
129			}
130			if ($reg == 0x10c1 && $payload ne "") {
131				$i2c_id = $payload;
132				$i2c_id =~ s/\s+.*//;
133				$i2c_id = "addr=0x$i2c_id, ";
134				$payload =~ s/^([0-9a-f].)//;
135				$payload =~ s/^\s+//;
136				$reg++;
137			}
138
139			my $data;
140			for (my $i = 0; ($i < $i2c{"size"}) && ($payload ne ""); $i++) {
141				my $tmp = $payload;
142				$tmp =~ s/\s+.*//;
143				$payload =~ s/^([0-9a-f].)//;
144				$payload =~ s/^\s+//;
145				$data .= "0x$tmp, ";
146			}
147			$data =~ s/\,\s+$//;
148
149			my $discard;
150			for (my $i = 0; ($i < 5) && ($payload ne ""); $i++) {
151				my $tmp = $payload;
152				$tmp =~ s/\s+.*//;
153				$payload =~ s/^([0-9a-f].)//;
154				$payload =~ s/^\s+//;
155				$discard .= "0x$tmp, ";
156			}
157			$discard =~ s/\,\s+$//;
158
159			my $s = sprintf "%s %s %s %s %s size=%d",
160				$i2c{"op"}, $i2c{"speed"}, $i2c{"busy"}, $i2c{"err"}, $i2c{"i2c"}, $i2c{"size"};
161			$s =~ s/\s+/ /g;
162
163			if ($debug) {
164				if ($reqtype & 0x80) {
165					printf "Read I2C: $s $i2c_id$data";
166				} else {
167					printf "I2C $s $i2c_id$data";
168				}
169				printf " ($discard)" if ($discard);
170				printf "Extra: $payload" if ($payload);
171				print "\n";
172
173				printf("\t%s, Req %3d, wValue: 0x%04x, wIndex 0x%04x, wlen %d: %s\n",
174					type_req($reqtype), $req, $wvalue, $windex, $wlen, $fullpayload);
175			}
176			next if ($reg < 0x10c2);
177			if (($i2c{"size"} == 1) && ($reqtype & 0x80)) {
178				printf "i2c_r1(gspca_dev, $data);\n";
179			} elsif (($i2c{"size"} == 2) && (($reqtype & 0x80) == 0)) {
180				printf "i2c_w1(gspca_dev, $data);\n";
181			} else {
182				if ($reqtype & 0x80) {
183					printf "i2c_r(gspca_dev, { $data }, %d);\n", $i2c{"size"};
184				} else {
185					printf "i2c_w(gspca_dev, { $data }, %d);\n", $i2c{"size"};
186				}
187			}
188		} else {
189			printf("%s, Req %3d, wValue: 0x%04x, wIndex 0x%04x, wlen %d: %s\n",
190				type_req($reqtype), $req, $wvalue, $windex, $wlen, $payload) if ($debug);
191
192			my $reg;
193			if (defined($reg_map{$wvalue})) {
194				$reg = $reg_map{$wvalue};
195			} else {
196				$reg = sprintf "0x%04x", $wvalue;
197			}
198
199			if ($reqtype == 0xc1) {
200				printf "reg_r(gspcadev, %s);\t/* read %s*/\n", $reg, $payload;
201			} elsif ($reqtype == 0x41) {
202				printf "reg_w(gspcadev, %s, { %s });*/\n", $reg, $payload;
203			}
204		}
205	}
206}
207