summaryrefslogtreecommitdiff
path: root/stub
diff options
context:
space:
mode:
Diffstat (limited to 'stub')
-rw-r--r--stub/Module.mk24
-rwxr-xr-xstub/i2c-stub-from-dump196
-rw-r--r--stub/i2c-stub-from-dump.852
3 files changed, 272 insertions, 0 deletions
diff --git a/stub/Module.mk b/stub/Module.mk
new file mode 100644
index 0000000..8ebcfcb
--- /dev/null
+++ b/stub/Module.mk
@@ -0,0 +1,24 @@
+# Helper for the Linux i2c-stub bus driver
+#
+# Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
+#
+# Licensed under the GNU General Public License.
+
+STUB_DIR := stub
+
+#
+# Commands
+#
+
+install-stub: $(STUB_DIR)/i2c-stub-from-dump
+ $(INSTALL_DIR) $(DESTDIR)$(sbindir) $(DESTDIR)$(man8dir)
+ $(INSTALL_PROGRAM) $(STUB_DIR)/i2c-stub-from-dump $(DESTDIR)$(sbindir)
+ $(INSTALL_DATA) $(STUB_DIR)/i2c-stub-from-dump.8 $(DESTDIR)$(man8dir)
+
+uninstall-stub:
+ $(RM) $(DESTDIR)$(sbindir)/i2c-stub-from-dump
+ $(RM) $(DESTDIR)$(man8dir)/i2c-stub-from-dump.8
+
+install: install-stub
+
+uninstall: uninstall-stub
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);
diff --git a/stub/i2c-stub-from-dump.8 b/stub/i2c-stub-from-dump.8
new file mode 100644
index 0000000..b594839
--- /dev/null
+++ b/stub/i2c-stub-from-dump.8
@@ -0,0 +1,52 @@
+.TH I2C-STUB-FROM-DUMP 8 "April 2008"
+.SH NAME
+i2c-stub-from-dump \- feed i2c-stub with a dump file
+
+.SH SYNOPSIS
+.B i2c-stub-from-dump
+.I address
+.I dump-file
+
+.SH DESCRIPTION
+i2c-stub-from-dump is a small helper script for the i2c-stub kernel driver.
+It lets you setup a fake I2C chip on the i2c-stub bus based on a dump of
+the chip you want to emulate.
+
+i2c-stub-from-dump requires i2cdetect and i2cset to be installed and
+reachable through the user's PATH. The former is used to find out the i2c-stub
+bus number, while the latter is used to write to the fake I2C chip.
+
+.SH EXAMPLE
+You have an I2C chip on system A. You would like to do some development on its
+driver on system B. Here are the few steps you have to follow.
+
+On system A, use i2cdump to capture a dump from the chip. Assuming that the
+chip in question lives at address 0x4c on I2C bus 0, you would run:
+
+ i2cdump -y 0 0x4c b > chip.dump
+
+Adjust the bus number and chip address for your case. i2cdetect can help
+you find out their values. If the device uses word (16-bit) register
+access instead of the traditional byte (8-bit) access, use mode \fBw\fR
+instead of \fBb\fR.
+
+Copy the dump file to system B.
+
+On system B, run:
+
+ i2c-stub-from-dump 0x4c chip.dump
+
+This will load the required i2c-dev and i2c-stub kernel drivers if needed,
+then write all the register values to the emulated I2C chip at address 0x4c.
+Again, adjust the address as needed.
+
+.SH LIMITATIONS
+There are some limitations to the kind of devices that can be handled:
+.IP \(bu
+Device must not have banks (as most Winbond devices do).
+
+.SH SEE ALSO
+i2cdump(8), i2cdetect(8), i2cset(8)
+
+.SH AUTHOR
+Jean Delvare