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