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