1#!/usr/bin/perl 2use strict; 3 4# Copyright (C) 2014 Mauro Carvalho Chehab <mchehab@kernel.org> 5# Copyright (c) 2014 Samsung Electronics Co., Ltd. 6# 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation, version 2 of the License. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# This small script parses USB dumps generated by several drivers, 17# decoding USB bits. 18# 19# To use it, do: 20# dmesg | ./parse_usb.pl 21# 22# Also, there are other utilities that produce similar outputs, and it 23# is not hard to parse some USB analyzers log into the expected format. 24# 25 26my %speed_map = ( 27 0x07 => "250KHz", 28 0x14 => "100KHz", 29 0x40 => "30KHz", 30 0x60 => "20KHz", 31); 32 33sub type_req($) 34{ 35 my $reqtype = shift; 36 my $s; 37 38 if ($reqtype & 0x80) { 39 $s = "RD "; 40 } else { 41 $s = "WR "; 42 } 43 if (($reqtype & 0x60) == 0x20) { 44 $s .= "CLAS "; 45 } elsif (($reqtype & 0x60) == 0x40) { 46 $s .= "VEND "; 47 } elsif (($reqtype & 0x60) == 0x60) { 48 $s .= "RSVD "; 49 } 50 51 if (($reqtype & 0x1f) == 0x00) { 52 $s .= "DEV "; 53 } elsif (($reqtype & 0x1f) == 0x01) { 54 $s .= "INT "; 55 } elsif (($reqtype & 0x1f) == 0x02) { 56 $s .= "EP "; 57 } elsif (($reqtype & 0x1f) == 0x03) { 58 $s .= "OTHER "; 59 } elsif (($reqtype & 0x1f) == 0x04) { 60 $s .= "PORT "; 61 } elsif (($reqtype & 0x1f) == 0x05) { 62 $s .= "RPIPE "; 63 } else { 64 $s .= sprintf "RECIP 0x%02x ", $reqtype & 0x1f; 65 } 66 67 $s =~ s/\s+$//; 68 return $s; 69} 70 71my $i2c_speed = "unknown"; 72my $i2c_addr = "unknown"; 73my @i2c_sbuf; 74my @i2c_rbuf; 75my $i2c_hold; 76 77while (<>) { 78 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]+(.*)/) { 79 my $timestamp = $1; 80 my $reqtype = hex($2); 81 my $req = hex($3); 82 my $val = hex("$5$4"); 83 my $reg = hex("$7$6"); 84 my $wlen = hex("$9$8"); 85 my $payload = $10; 86 87 $timestamp =~ s/^\s+//; 88 $timestamp =~ s/\s+$//; 89 90 if (($reqtype == 0x40) && ($reg == 0x02ff)) { 91 # Start of an I2C tranfer 92 @i2c_sbuf = (); 93 @i2c_rbuf = (); 94 next; 95 } 96 if (($reqtype == 0x40) && ($reg == 0x0202)) { 97 # I2C speed 98 $i2c_speed = sprintf "0x%02x", $val; 99 $i2c_speed = $speed_map{$val} if defined($speed_map{$val}); 100 next; 101 } 102 103 if (($reqtype == 0x40) && ($reg == 0x0203)) { 104 # I2C addr 105 $i2c_addr = $val >> 1; 106 next; 107 } 108 109 if (($reqtype == 0x40) && ($reg == 0x0200)) { 110 # I2C trigger 111 $i2c_hold = ($val & 0x40) == 0x40; 112 113 if (!$i2c_hold && ($val & 0x01)) { 114 printf "$timestamp au0828 I2C write addr = 0x%02x (speed = %s) ", $i2c_addr, $i2c_speed; 115 printf "0x%02x ", $_ foreach (@i2c_sbuf); 116 print "\n"; 117 118 @i2c_sbuf = (); 119 } 120 121 next; 122 } 123 124 if (($reqtype == 0xc0) && ($reg == 0x0201)) { 125 # Wait to be ready 126 next; 127 } 128 129 130 if (($reqtype == 0x40) && ($reg == 0x0205)) { 131 # I2C write data 132 push @i2c_sbuf, $val; 133 134 next; 135 } 136 137 if (($reqtype == 0xc0) && ($reg == 0x0209)) { 138 # I2C read data 139 my @bytes = split(/ /, $payload); 140 push @i2c_rbuf, hex($_) foreach(@bytes); 141 142 if (!$i2c_hold) { 143 printf "$timestamp au0828 I2C read addr = 0x%02x (speed = %s, len=%d) ", $i2c_addr, $i2c_speed, scalar(@i2c_rbuf); 144 printf "0x%02x ", $_ foreach (@i2c_rbuf); 145 print "\n"; 146 147 @i2c_rbuf = (); 148 } 149 next; 150 } 151 152 printf("%s %s(0x%02x), Req 0x%02x, register 0x%04x, value 0x%04x, wlen %d: %s\n", 153 $timestamp, type_req($reqtype), $reqtype, $req, $reg, $val, $wlen, $payload); 154 } 155} 156