root/i2c-tools/trunk/stub/i2c-stub-from-dump

Revision 5293, 4.7 kB (checked in by khali, 5 months ago)

Stop on i2cset error.

  • Property svn:executable set to *
Line 
1 #!/usr/bin/perl -w
2 #
3 # Copyright (C) 2007-2008  Jean Delvare <khali@linux-fr.org>
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; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA  02110-1301, USA
19 #
20 # This script feeds the i2c-stub driver with dump data from a real
21 # I2C or SMBus chip. This can be useful when writing a driver for
22 # a device you do not have access to, but of which you have a dump.
23
24 use strict;
25 use vars qw($bus_nr $addr $bytes $words $err);
26
27 # Kernel version detection code by Mark M. Hoffman,
28 # copied from sensors-detect.
29 use vars qw(@kernel_version);
30
31 sub initialize_kernel_version
32 {
33         `uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/;
34         @kernel_version = ($1, $2, $3, $4);
35 }
36
37 sub kernel_version_at_least
38 {
39         my ($vers, $plvl, $slvl) = @_;
40         return 1 if ($kernel_version[0]  > $vers ||
41                       ($kernel_version[0] == $vers &&
42                         ($kernel_version[1]  > $plvl ||
43                           ($kernel_version[1] == $plvl &&
44                             ($kernel_version[2] >= $slvl)))));
45         return 0;
46 }
47
48 # Find out the i2c bus number of i2c-stub
49 sub get_i2c_stub_bus_number
50 {
51         my $nr;
52
53         open(FH, "i2cdetect -l |") || die "Can't run i2cdetect";
54         while (<FH>) {
55                 next unless m/^i2c-(\d+).*\tSMBus stub/;
56                 $nr = $1;
57                 last;
58         }
59         close(FH);
60
61         return $nr;
62 }
63
64 # Load the required kernel drivers if needed
65 sub load_kernel_drivers
66 {
67         local $_;
68         my $addr = oct shift;
69         my $nr;
70
71         # Maybe everything is already loaded
72         $nr = get_i2c_stub_bus_number();
73         if (defined $nr) {
74                 if (kernel_version_at_least(2, 6, 19)) {
75                         # Check if the chip address we need is there
76                         open(CHIP_ADDR, "/sys/module/i2c_stub/parameters/chip_addr");
77                         $_ = <CHIP_ADDR>;
78                         chomp;
79                         my @stub_addr = split ',';
80                         close(CHIP_ADDR);
81
82                         foreach (@stub_addr) {
83                                 return $nr if $addr == $_;
84                         }
85                         printf STDERR "i2c-stub already loaded without support for address 0x%02x\n", $addr;
86                         exit 2;
87                 }
88                 return $nr;
89         }
90
91         system("/sbin/modprobe", "i2c-dev") == 0 || exit 1;
92         if (kernel_version_at_least(2, 6, 19)) {
93                 system("/sbin/modprobe", "i2c-stub", "chip_addr=$addr") == 0 || exit 1;
94         } else {
95                 system("/sbin/modprobe", "i2c-stub") == 0 || exit 1;
96         }
97         sleep(1); # udev may take some time to create the device node
98
99         $nr = get_i2c_stub_bus_number();
100         if (!defined($nr)) {
101                 print STDERR "Please load i2c-stub first\n";
102                 exit 2;
103         }
104
105         return $nr;
106 }
107
108 sub process_dump
109 {
110         my $dump = shift;
111         my $err = 0;
112
113         open(DUMP, $dump) || die "Can't open $dump: $!\n";
114  OUTER_LOOP:
115         while (<DUMP>) {
116                 if (m/^([0-9a-f]0):(( [0-9a-fX]{2}){16})/) {
117                         # Byte dump
118                         my $offset = hex($1);
119                         my @values = split(/ /, $2);
120                         shift(@values);
121                         for (my $i = 0; $i < 16 && (my $val = shift(@values)); $i++) {
122                                 next if $val =~ m/X/;
123                                 if (system("i2cset", "-y", $bus_nr, $addr,
124                                            sprintf("0x\%02x", $offset+$i),
125                                            "0x$val", "b")) {
126                                         $err = 3;
127                                         last OUTER_LOOP;
128                                 }
129                                 $bytes++;
130                         }
131                 } elsif (m/^([0-9a-f][08]):(( [0-9a-fX]{4}){8})/) {
132                         # Word dump
133                         my $offset = hex($1);
134                         my @values = split(/ /, $2);
135                         shift(@values);
136                         for (my $i = 0; $i < 8 && (my $val = shift(@values)); $i++) {
137                                 next if $val =~ m/X/;
138                                 if (system("i2cset", "-y", $bus_nr, $addr,
139                                            sprintf("0x\%02x", $offset+$i),
140                                            "0x$val", "w")) {
141                                         $err = 3;
142                                         last OUTER_LOOP;
143                                 }
144                                 $words++;
145                         }
146                 }
147         }
148         close(DUMP);
149
150         return $err;
151 }
152
153 if ($>) {
154         print "You must be root to use this script\n";
155         exit 1;
156 }
157
158 if (@ARGV != 2) {
159         print STDERR "Usage: i2c-stub-from-dump <addr> <dump file>\n";
160         exit 1;
161 }
162
163 # Check the parameters
164 $addr = $ARGV[0];
165 if ($addr !~ m/^0x[0-7][0-9a-f]$/i) {
166         print STDERR "Invalid address $addr\n";
167         exit 1;
168 }
169
170 initialize_kernel_version();
171
172 $bus_nr = load_kernel_drivers($addr);
173 $bytes = $words = 0;
174
175 # We don't want to see the output of 256 i2cset
176 open(SAVEOUT, ">&STDOUT");
177 open(STDOUT, ">/dev/null");
178 $err = process_dump($ARGV[1]);
179 close(STDOUT);
180
181 if ($bytes) {
182         printf SAVEOUT "$bytes byte values written to \%d-\%04x\n",
183                 $bus_nr, oct($addr);
184 }
185
186 if ($words) {
187         printf SAVEOUT "$words word values written to \%d-\%04x\n",
188                 $bus_nr, oct($addr);
189 }
190
191 if (!$err && ($bytes + $words == 0)) {
192         printf SAVEOUT "Only garbage found in dump file $ARGV[1]\n";
193         exit(1);
194 }
195
196 exit($err);
Note: See TracBrowser for help on using the browser.