|
@ -0,0 +1,100 @@ |
|
|
|
|
|
#!/usr/bin/perl -w |
|
|
|
|
|
# |
|
|
|
|
|
# Copyright (C) 2007 Jean Delvare <khali@linux-fr.org> |
|
|
|
|
|
# |
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify |
|
|
|
|
|
# it under the terms of the GNU General Public License as published by |
|
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or |
|
|
|
|
|
# (at your option) any later version. |
|
|
|
|
|
# |
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
|
|
# GNU General Public License for more details. |
|
|
|
|
|
# |
|
|
|
|
|
# You should have received a copy of the GNU General Public License |
|
|
|
|
|
# along with this program; if not, write to the Free Software |
|
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
|
|
|
|
# MA 02110-1301, USA |
|
|
|
|
|
# |
|
|
|
|
|
# This script feeds the i2c-stub driver with dump data from a real |
|
|
|
|
|
# I2C or SMBus chip. This can be useful when writing a driver for |
|
|
|
|
|
# a device you do not have access to, but of which you have a dump. |
|
|
|
|
|
|
|
|
|
|
|
use strict; |
|
|
|
|
|
use vars qw($bus_nr $addr $count); |
|
|
|
|
|
|
|
|
|
|
|
# Find out the i2c bus number of i2c-stub |
|
|
|
|
|
sub get_i2c_stub_bus_number |
|
|
|
|
|
{ |
|
|
|
|
|
my $nr; |
|
|
|
|
|
|
|
|
|
|
|
open(FH, "i2cdetect -l |") || die "Can't run i2cdetect"; |
|
|
|
|
|
while (<FH>) { |
|
|
|
|
|
next unless m/^i2c-(\d+).*\tSMBus stub/; |
|
|
|
|
|
$nr = $1; |
|
|
|
|
|
last; |
|
|
|
|
|
} |
|
|
|
|
|
close(FH); |
|
|
|
|
|
|
|
|
|
|
|
if (!defined($nr)) { |
|
|
|
|
|
print STDERR "Please load i2c-stub first\n"; |
|
|
|
|
|
exit 2; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return $nr; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ($>) { |
|
|
|
|
|
print "You must be root to use this script\n"; |
|
|
|
|
|
exit 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (@ARGV != 2) { |
|
|
|
|
|
print STDERR "Usage: i2c-stub-from-dump <addr> <dump file>\n"; |
|
|
|
|
|
exit 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
# Check the parameters |
|
|
|
|
|
$addr = $ARGV[0]; |
|
|
|
|
|
if ($addr !~ m/^0x[0-7][0-9a-f]$/i) { |
|
|
|
|
|
print STDERR "Invalid address $addr\n"; |
|
|
|
|
|
exit 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
# Load the required kernel drivers if needed |
|
|
|
|
|
system("/sbin/modprobe", "i2c-dev") == 0 || exit 1; |
|
|
|
|
|
system("/sbin/modprobe", "i2c-stub", "chip_addr=$addr") == 0 || exit 1; |
|
|
|
|
|
sleep(1); # udev may take some time to create the device node |
|
|
|
|
|
|
|
|
|
|
|
$bus_nr = get_i2c_stub_bus_number(); |
|
|
|
|
|
|
|
|
|
|
|
# We don't want to see the output of 256 i2cset |
|
|
|
|
|
open(SAVEOUT, ">&STDOUT"); |
|
|
|
|
|
open(STDOUT, ">/dev/null"); |
|
|
|
|
|
|
|
|
|
|
|
$count = 0; |
|
|
|
|
|
open(DUMP, $ARGV[1]) || die "Can't open $ARGV[1]: $!\n"; |
|
|
|
|
|
OUTER_LOOP: |
|
|
|
|
|
while (<DUMP>) { |
|
|
|
|
|
next unless m/^([0-9a-f]0):(( [0-9a-f]{2}){16})/; |
|
|
|
|
|
my $offset = hex($1); |
|
|
|
|
|
my @values = split(/ /, $2); |
|
|
|
|
|
shift(@values); |
|
|
|
|
|
for (my $i = 0; $i < 16 && (my $val = shift(@values)); $i++) { |
|
|
|
|
|
last OUTER_LOOP if system("i2cset", "-y", |
|
|
|
|
|
$bus_nr, $addr, |
|
|
|
|
|
sprintf("0x\%02x", $offset+$i), |
|
|
|
|
|
sprintf("0x\%02x", hex($val)), "b"); |
|
|
|
|
|
$count++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
close(DUMP); |
|
|
|
|
|
close(STDOUT); |
|
|
|
|
|
|
|
|
|
|
|
if ($count) { |
|
|
|
|
|
printf SAVEOUT "$count byte values written to \%d-\%04x\n", |
|
|
|
|
|
$bus_nr, oct($addr); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
exit($count == 0); |