diff options
author | Graydon, Tracy <tracy.graydon@intel.com> | 2013-01-31 18:44:07 -0800 |
---|---|---|
committer | Graydon, Tracy <tracy.graydon@intel.com> | 2013-01-31 18:44:07 -0800 |
commit | b19d79bf9028f58e3e4226bd9410b59f19fe3c8d (patch) | |
tree | a84dec919322f3d19c7c0cf3050c8c134a0d4fc6 /stub/i2c-stub-from-dump | |
download | i2c-tools-2.0alpha.tar.gz i2c-tools-2.0alpha.tar.bz2 i2c-tools-2.0alpha.zip |
Initial commitHEADsubmit/tizen_common/20150126.093738submit/tizen_3.0_common/20161104.104000submit/2.0alpha/20130201.222745accepted/tizen/common/20150126.100451accepted/tizen/3.0/common/20161114.112238accepted/2.0alpha/20130201.222208tizen_3.0.m2tizen_3.0.2015.q2_commontizen_3.0.2014.q4_commonaccepted/tizen_commonaccepted/tizen_3.0_common2.0alpha
Diffstat (limited to 'stub/i2c-stub-from-dump')
-rwxr-xr-x | stub/i2c-stub-from-dump | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/stub/i2c-stub-from-dump b/stub/i2c-stub-from-dump new file mode 100755 index 0000000..f91da1c --- /dev/null +++ b/stub/i2c-stub-from-dump @@ -0,0 +1,196 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2007-2008 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 $bytes $words $err); + +# Kernel version detection code by Mark M. Hoffman, +# copied from sensors-detect. +use vars qw(@kernel_version); + +sub initialize_kernel_version +{ + `uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/; + @kernel_version = ($1, $2, $3, $4); +} + +sub kernel_version_at_least +{ + my ($vers, $plvl, $slvl) = @_; + return 1 if ($kernel_version[0] > $vers || + ($kernel_version[0] == $vers && + ($kernel_version[1] > $plvl || + ($kernel_version[1] == $plvl && + ($kernel_version[2] >= $slvl))))); + return 0; +} + +# 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); + + return $nr; +} + +# Load the required kernel drivers if needed +sub load_kernel_drivers +{ + local $_; + my $addr = oct shift; + my $nr; + + # Maybe everything is already loaded + $nr = get_i2c_stub_bus_number(); + if (defined $nr) { + if (kernel_version_at_least(2, 6, 19)) { + # Check if the chip address we need is there + open(CHIP_ADDR, "/sys/module/i2c_stub/parameters/chip_addr"); + $_ = <CHIP_ADDR>; + chomp; + my @stub_addr = split ','; + close(CHIP_ADDR); + + foreach (@stub_addr) { + return $nr if $addr == $_; + } + printf STDERR "i2c-stub already loaded without support for address 0x%02x\n", $addr; + exit 2; + } + return $nr; + } + + system("/sbin/modprobe", "i2c-dev") == 0 || exit 1; + if (kernel_version_at_least(2, 6, 19)) { + system("/sbin/modprobe", "i2c-stub", "chip_addr=$addr") == 0 || exit 1; + } else { + system("/sbin/modprobe", "i2c-stub") == 0 || exit 1; + } + sleep(1); # udev may take some time to create the device node + + $nr = get_i2c_stub_bus_number(); + if (!defined($nr)) { + print STDERR "Please load i2c-stub first\n"; + exit 2; + } + + return $nr; +} + +sub process_dump +{ + my $dump = shift; + my $err = 0; + + open(DUMP, $dump) || die "Can't open $dump: $!\n"; + OUTER_LOOP: + while (<DUMP>) { + if (m/^([0-9a-f]0):(( [0-9a-fX]{2}){16})/) { + # Byte dump + my $offset = hex($1); + my @values = split(/ /, $2); + shift(@values); + for (my $i = 0; $i < 16 && (my $val = shift(@values)); $i++) { + next if $val =~ m/X/; + if (system("i2cset", "-y", $bus_nr, $addr, + sprintf("0x\%02x", $offset+$i), + "0x$val", "b")) { + $err = 3; + last OUTER_LOOP; + } + $bytes++; + } + } elsif (m/^([0-9a-f][08]):(( [0-9a-fX]{4}){8})/) { + # Word dump + my $offset = hex($1); + my @values = split(/ /, $2); + shift(@values); + for (my $i = 0; $i < 8 && (my $val = shift(@values)); $i++) { + next if $val =~ m/X/; + if (system("i2cset", "-y", $bus_nr, $addr, + sprintf("0x\%02x", $offset+$i), + "0x$val", "w")) { + $err = 3; + last OUTER_LOOP; + } + $words++; + } + } + } + close(DUMP); + + return $err; +} + +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; +} + +initialize_kernel_version(); + +$bus_nr = load_kernel_drivers($addr); +$bytes = $words = 0; + +# We don't want to see the output of 256 i2cset +open(SAVEOUT, ">&STDOUT"); +open(STDOUT, ">/dev/null"); +$err = process_dump($ARGV[1]); +close(STDOUT); + +if ($bytes) { + printf SAVEOUT "$bytes byte values written to \%d-\%04x\n", + $bus_nr, oct($addr); +} + +if ($words) { + printf SAVEOUT "$words word values written to \%d-\%04x\n", + $bus_nr, oct($addr); +} + +if (!$err && ($bytes + $words == 0)) { + printf SAVEOUT "Only garbage found in dump file $ARGV[1]\n"; + exit(1); +} + +exit($err); |