Project import
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5df142e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,95 @@
+#
+#    Copyright (c) 2010-2011 Nest, Inc.
+#    All rights reserved.
+#
+#    This document is the property of Nest. It is considered
+#    confidential and proprietary information.
+#
+#    This document may not be reproduced or transmitted in any form,
+#    in whole or in part, without the express written permission of
+#    Nest.
+#
+#    Description:
+#      This file is the make file for i2c-tools, a heterogeneous set
+#      of I2C tools for Linux.
+#
+
+BuildConfigSpecialized	:= No
+BuildProductSpecialized	:= No
+
+include pre.mak
+
+PackageName		:= i2c-tools
+
+PackageExtension	:= tar.bz2
+PackageSeparator	:= -
+
+PackageArchive		:= $(PackageName).$(PackageExtension)
+PackageSourceDir	:= $(PackageName)$(PackageSeparator)$(PackageVersion)
+
+PackageBuildMakefile	= $(call GenerateBuildPaths,Makefile)
+
+CleanPaths		+= $(PackageLicenseFile)
+
+all: $(PackageDefaultGoal)
+
+# Generate the package license contents.
+
+$(PackageSourceDir)/COPYING: source
+
+$(PackageLicenseFile): $(PackageSourceDir)/COPYING
+	$(copy-result)
+
+# Extract the source from the archive and apply patches, if any.
+
+$(PackageSourceDir): $(PackageArchive) $(PackagePatchPaths)
+	$(expand-and-patch-package)
+
+# Prepare the sources.
+
+.PHONY: source
+source: | $(PackageSourceDir)
+
+# Patch the sources, if necessary.
+
+.PHONY: patch
+patch: source
+
+# Generate the package build makefile.
+
+$(PackageBuildMakefile): | $(PackageSourceDir) $(BuildDirectory)
+	$(call create-links,$(CURDIR)/$(PackageSourceDir),$(BuildDirectory))
+
+# Configure the source for building.
+
+.PHONY: configure
+configure: source $(PackageBuildMakefile)
+
+# Build the source.
+
+.PHONY: build
+build: configure
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+	INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	CC="$(CC)" CXX="$(CXX)" AR=$(AR) RANLIB=$(RANLIB) STRIP=$(STRIP) \
+	prefix=/usr \
+	all
+
+# Stage the build to a temporary installation area.
+
+.PHONY: stage
+stage: build | $(ResultDirectory)
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \
+	INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	prefix=/usr \
+	DESTDIR=$(ResultDirectory) \
+	install
+
+clean:
+	$(Verbose)$(RM) $(RMFLAGS) -r $(PackageSourceDir)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(BuildDirectory)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(ResultDirectory)
+
+include post.mak
diff --git a/i2c-tools-3.0.2/CHANGES b/i2c-tools-3.0.2/CHANGES
new file mode 100644
index 0000000..3534ea0
--- /dev/null
+++ b/i2c-tools-3.0.2/CHANGES
@@ -0,0 +1,51 @@
+i2c-tools CHANGES
+-----------------
+
+3.0.2 (2008-11-29)
+  i2c-dev.h: Drop I2C_FUNC_SMBUS_*I2C_BLOCK_2 defines
+  decode-dimms: Add support for little-endian word hexdumps
+                Only export the ceil function from POSIX
+  decode-vaio: Remove history
+  i2cdetect: Support i2c bus passed by name
+             Shorten the usage message
+  i2cdump: Support i2c bus passed by name
+           Shorten the usage message
+           Restrict the chip address to 0x03-0x77
+           Split the functionality checking code into a separate function
+           Better error message on missing adapter functionality
+  i2cget: Support i2c bus passed by name
+          Shorten the usage message
+          Better error message on missing adapter functionality
+  i2cset: Support i2c bus passed by name
+          Shorten the usage message
+          Restrict the chip address to 0x03-0x77
+          Split the code into several functions for clarity
+          Add support for short writes (SMBus send byte)
+          Better error message on missing adapter functionality
+          Set the data value mask with -m
+          Make reading back the written value optional
+  i2c-stub-from-dump: Add support for partial dumps
+                      Report if only garbage is found in dump file
+                      Behave properly when i2c-stub is already loaded
+                      Stop on i2cset error
+
+3.0.1 (2008-04-04)
+  Drop the trailing .pl from all perl script names
+  decode-dimms: Fix DDR2 SDRAM module speed decoding
+                Update manufacturer IDs
+                Don't print anything by default if checksum fails
+                Decode all DDR2 SDRAM timing information
+                Add support for reading SPD data from hexdumps
+                Make command line parsing more robust
+  decode-vaio: Private data might not be readable by non-root users
+               Print the asset tag
+               Fix the timestamp decoding
+  i2cdump: Fix I2C block mode error code
+           Remove man page reference to hardware monitoring chips
+           Let the user specify a register range
+  i2cset: Final status messages go to stdout
+          Return success even when readback fails or doesn't match
+  i2c-stub-from-dump: New helper script to use with i2c-stub
+
+3.0.0 (2007-10-14)
+  Initial release
diff --git a/i2c-tools-3.0.2/COPYING b/i2c-tools-3.0.2/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/i2c-tools-3.0.2/COPYING
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/i2c-tools-3.0.2/Makefile b/i2c-tools-3.0.2/Makefile
new file mode 100644
index 0000000..a2bf718
--- /dev/null
+++ b/i2c-tools-3.0.2/Makefile
@@ -0,0 +1,37 @@
+# I2C tools for Linux
+#
+# Copyright (C) 2007  Jean Delvare <khali@linux-fr.org>
+#
+# Licensed under the GNU General Public License.
+
+DESTDIR	=
+prefix	= /usr/local
+bindir	= $(prefix)/bin
+sbindir	= $(prefix)/sbin
+mandir	= $(prefix)/share/man
+man8dir	= $(mandir)/man8
+incdir	= $(prefix)/include
+
+INSTALL		:= install
+INSTALL_DATA	:= $(INSTALL) -m 644
+INSTALL_DIR	:= $(INSTALL) -m 755 -d
+INSTALL_PROGRAM	:= $(INSTALL) -m 755
+RM		:= rm -f
+
+CC	:= gcc
+CFLAGS	:= -Wall
+
+CFLAGS	+= -O2
+# When debugging, use the following instead
+#CFLAGS	+= -O -g
+
+KERNELVERSION	:= $(shell uname -r)
+
+.PHONY: all strip clean install uninstall
+
+all:
+
+include eeprom/Module.mk
+include include/Module.mk
+include stub/Module.mk
+include tools/Module.mk
diff --git a/i2c-tools-3.0.2/README b/i2c-tools-3.0.2/README
new file mode 100644
index 0000000..700bf88
--- /dev/null
+++ b/i2c-tools-3.0.2/README
@@ -0,0 +1,61 @@
+I2C TOOLS FOR LINUX
+===================
+
+This package contains an heterogeneous set of I2C tools for Linux. These tools
+were originally part of the lm-sensors package but were finally split into
+their own package for convenience.
+
+
+CONTENTS
+--------
+
+The various tools included in this package are grouped by category, each
+category has its own sub-directory:
+
+* eeprom
+  Perl scripts for decoding different types of EEPROMs (SPD, EDID...) These
+  scripts rely on the "eeprom" kernel driver. They are installed by default.
+
+* eepromer
+  Tools for writing to EEPROMs. These tools rely on the "i2c-dev" kernel
+  driver. They are not installed by default.
+
+* include
+  C/C++ header files for I2C and SMBus access over i2c-dev. Installed by
+  default.
+
+* py-smbus
+  Python wrapper for SMBus access over i2c-dev. Not installed by default.
+
+* stub
+  A helper script to use with the i2c-stub kernel driver. Installed by
+  default.
+
+* tools
+  I2C device detection and register dump tools. These tools rely on the
+  "i2c-dev" kernel driver. They are installed by default.
+
+
+INSTALLATION
+------------
+
+There's no configure script, so simply run "make" to build the tools, and
+"make install" to install them. You also can use "make uninstall" to remove
+all the files you installed. By default, files are installed in /usr/local
+but you can change this behavior by editing the Makefile file and setting
+prefix to wherever you want. You may change the C compiler and the
+compilation flags as well.
+
+Optionally, you can run "make strip" prior to "make install" if you want
+smaller binaries. However, be aware that this will prevent any further
+attempt to debug the programs.
+
+
+DOCUMENTATION
+-------------
+
+The main tools have manual pages, which are installed by "make install".
+See these manual pages for command line interface details and tool specific
+information.
+
+The other tools come with simple text documentation, which isn't installed.
diff --git a/i2c-tools-3.0.2/eeprom/Module.mk b/i2c-tools-3.0.2/eeprom/Module.mk
new file mode 100644
index 0000000..950bee5
--- /dev/null
+++ b/i2c-tools-3.0.2/eeprom/Module.mk
@@ -0,0 +1,31 @@
+# EEPROM decoding scripts for the Linux eeprom driver
+#
+# Copyright (C) 2007-2008  Jean Delvare <khali@linux-fr.org>
+#
+# Licensed under the GNU General Public License.
+
+EEPROM_DIR	:= eeprom
+
+EEPROM_TARGETS	:= decode-dimms decode-vaio ddcmon decode-edid
+
+# decode-xeon was not yet ported to the Linux 2.6 sysfs interface
+ifeq (,$(findstring /2.6., /$(KERNELVERSION)))
+EEPROM_TARGETS	+= decode-xeon
+endif
+
+#
+# Commands
+#
+
+install-eeprom: $(addprefix $(EEPROM_DIR)/,$(EEPROM_TARGETS))
+	$(INSTALL_DIR) $(DESTDIR)$(bindir)
+	for program in $(EEPROM_TARGETS) ; do \
+	$(INSTALL_PROGRAM) $(EEPROM_DIR)/$$program $(DESTDIR)$(bindir) ; done
+
+uninstall-eeprom:
+	for program in $(EEPROM_TARGETS) ; do \
+	$(RM) $(DESTDIR)$(bindir)/$$program ; done
+
+install: install-eeprom
+
+uninstall: uninstall-eeprom
diff --git a/i2c-tools-3.0.2/eeprom/README b/i2c-tools-3.0.2/eeprom/README
new file mode 100644
index 0000000..efca1d0
--- /dev/null
+++ b/i2c-tools-3.0.2/eeprom/README
@@ -0,0 +1,22 @@
+This directory contains scripts to decode the data exposed by the eeprom
+Linux kernel driver.
+
+* decode-dimms (perl script)
+  Decode the information found in memory module SPD EEPROMs. The SPD
+  data is read either from the running system or from dump files.
+
+* decode-vaio (perl script)
+  Decode the information found in Sony Vaio laptop identification EEPROMs.
+
+* ddcmon (perl script)
+  decode-edid (perl script)
+  Decode the information found in monitor EEPROMs. Both scripts require
+  an access to the DDC channel of the monitor. This is typically provided
+  by framebuffer drivers. decode-edid additionally requires parse-edid,
+  which is part of the read-edid package. ddcmon prints general
+  information, while decode-edid prints timing information for
+  inclusion into your X11 configuration file.
+
+* decode-xeon (perl script)
+  ID ROM data decoding for Xeon processors. Support for sysfs is still
+  missing, so this script doesn't work with 2.6 kernels yet.
diff --git a/i2c-tools-3.0.2/eeprom/ddcmon b/i2c-tools-3.0.2/eeprom/ddcmon
new file mode 100755
index 0000000..3c3caf0
--- /dev/null
+++ b/i2c-tools-3.0.2/eeprom/ddcmon
@@ -0,0 +1,567 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2004-2005  Jean Delvare <khali@linux-fr.org>
+#
+# Parts inspired from decode-edid.
+# Copyright (C) 2003-2004  Jean Delvare <khali@linux-fr.org>
+#
+# Parts inspired from the ddcmon driver and sensors' print_ddcmon function.
+# Copyright (C) 1998-2004  Mark D. Studebaker
+#
+# Parts inspired from the fbmon driver (Linux 2.6.10).
+# Copyright (C) 2002  James Simmons <jsimmons@users.sf.net>
+#
+#    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.
+#
+# Version 1.0  2005-01-04  Jean Delvare <khali@linux-fr.org>
+#
+# This script is a replacement for the now deprecated ddcmon kernel driver.
+# Instead of having a dedicated driver, it is better to reuse the standard
+# eeprom driver and implement the EDID-specific code in user-space.
+#
+# EDID (Extended Display Identification Data) is a VESA standard which
+# allows storing (on manufacturer's side) and retrieving (on user's side)
+# of configuration information about displays, such as manufacturer,
+# serial number, physical dimensions and allowed horizontal and vertical
+# refresh rates.
+#
+# Syntax: ddcmon [bus [address]]
+# Address can be given in decimal or hexadecimal (with a 0x prefix).
+# If no address is given, default is 0x50.
+# Bus number must be given in decimal. If no bus number is given,
+# try them all.
+
+use strict;
+use Fcntl qw(:DEFAULT :seek);
+use vars qw(@standard_scales);
+
+@standard_scales = ([1, 1], [3, 4], [4, 5], [16, 9]);
+
+# Make sure the eeprom module is loaded.
+# For non-modular kernels, we can't help.
+if (-r '/proc/modules')
+{
+	my $found = 0;
+	open(MODULES, '/proc/modules');
+	while (!$found && defined ($_ = <MODULES>))
+	{
+		$found++ if m/^eeprom\s+/;
+	}
+	close(MODULES);
+
+	unless ($found)
+	{
+		print STDERR
+			"This script requires the eeprom module to be loaded.\n";
+		exit 1;
+	}
+}
+
+# Only used for sysfs
+sub rawread
+{
+	my $filename = shift;
+	my $length = shift;
+	my $offset = shift || 0;
+	my $bytes = '';
+	
+	sysopen(FH, $filename, O_RDONLY)
+		or die "Can't open $filename";
+	if ($offset)
+	{
+		sysseek(FH, $offset, SEEK_SET)
+			or die "Can't seek in $filename";
+	}
+
+	$offset = 0;
+	while ($length)
+	{
+		my $r = sysread(FH, $bytes, $length, $offset);
+		die "Can't read $filename"
+			unless defined($r);
+		die "Unexpected EOF in $filename"
+			unless $r;
+		$offset += $r;
+		$length -= $r;
+	}
+	close(FH);
+
+	return $bytes;
+}
+
+sub get_edid_sysfs
+{
+	my ($bus, $addr) = @_;
+
+	my @bytes = unpack("C*", rawread("/sys/bus/i2c/devices/$bus-00$addr/eeprom", 128));
+
+	return \@bytes;
+}
+
+sub get_edid_procfs
+{
+	my ($bus, $addr) = @_;
+
+	my @bytes;
+
+	for (my $i = 0 ; $i < 0x80; $i += 0x10)
+	{
+		my $filename = sprintf("/proc/sys/dev/sensors/eeprom-i2c-\%s-\%s/\%02x",
+				       $bus, $addr, $i);
+		open(EEDATA, $filename)
+			or die "Can't read $filename";
+		push @bytes, split(/\s+/, <EEDATA>);
+		close(EEDATA);
+	}
+
+	return \@bytes;
+}
+
+sub print_line
+{
+	my $label = shift;
+	my $pattern = shift;
+
+	printf("\%-24s$pattern\n", $label.':', @_);
+}
+
+sub extract_byte
+{
+	my ($bytes, $offset) = @_;
+	
+	return $bytes->[$offset];
+}
+
+sub extract_word
+{
+	my ($bytes, $offset) = @_;
+	
+	return ($bytes->[$offset]
+	      | ($bytes->[$offset+1] << 8));
+}
+
+sub extract_manufacturer
+{
+	my ($bytes, $offset) = @_;
+	my $i = ($bytes->[$offset+1] | ($bytes->[$offset] << 8));
+
+	return sprintf('%c%c%c',
+		       (($i >> 10) & 0x1f) + ord('A') - 1,
+		       (($i >> 5) & 0x1f) + ord('A') - 1,
+		       ($i & 0x1f) + ord('A') - 1);
+}
+
+sub extract_sesquiword
+{
+	my ($bytes, $offset) = @_;
+	
+	return ($bytes->[$offset]
+	      | ($bytes->[$offset+1] << 8)
+	      | ($bytes->[$offset+2] << 16));
+}
+
+sub extract_dword
+{
+	my ($bytes, $offset) = @_;
+	
+	return ($bytes->[$offset]
+	      | ($bytes->[$offset+1] << 8)
+	      | ($bytes->[$offset+2] << 16)
+	      | ($bytes->[$offset+3] << 24));
+}
+
+sub extract_display_input
+{
+	my ($bytes, $offset) = @_;
+
+	my @voltage = ('0.700V/0.300V', '0.714V/0.286V',
+		       '1.000V/0.400V', '0.700V/0.000V');
+
+	return 'Digital'
+		if ($bytes->[$offset] & 0x80);
+
+	return 'Analog ('.$voltage[($bytes->[$offset] & 0x60) >> 5].')';
+}
+
+sub extract_dpms
+{
+	my ($bytes, $offset) = @_;
+
+	my @supported;
+
+	push @supported, 'Active Off' if ($bytes->[$offset] & 0x20);
+	push @supported, 'Suspend' if ($bytes->[$offset] & 0x40);
+	push @supported, 'Standby' if ($bytes->[$offset] & 0x80);
+
+	return join(', ', @supported)
+		if (@supported);
+
+	return 'None supported';
+}
+
+sub extract_color_mode
+{
+	my ($bytes, $offset) = @_;
+
+	my @mode = ('Monochrome', 'RGB Multicolor', 'Non-RGB Multicolor');
+
+	return $mode[($bytes->[$offset] >> 3) & 0x03];
+}
+  
+sub good_signature
+{
+	my $bytes = shift;
+	
+	return $bytes->[0] == 0x00
+	    && $bytes->[1] == 0xff
+	    && $bytes->[2] == 0xff
+	    && $bytes->[3] == 0xff
+	    && $bytes->[4] == 0xff
+	    && $bytes->[5] == 0xff
+	    && $bytes->[6] == 0xff
+	    && $bytes->[7] == 0x00;
+}
+
+sub verify_checksum
+{
+	my $bytes = shift;
+	my $cs;
+
+	for (my $i = 0, $cs = 0; $i < 0x80; $i++)
+	{
+		$cs += $bytes->[$i];
+	}
+	
+	return (($cs & 0xff) == 0 ? 'OK' : 'Not OK');
+}
+
+sub add_timing
+{
+	my ($timings, $new) = @_;
+
+	my $mode = sprintf('%ux%u@%u%s', $new->[0], $new->[1],
+			$new->[2], defined ($new->[3]) &&
+			$new->[3] eq 'interlaced' ? 'i' : '');
+
+	$timings->{$mode} = $new;
+}
+
+sub add_standard_timing
+{
+	my ($timings, $byte0, $byte1) = @_;
+
+	# Unused slot
+	return if ($byte0 == $byte1)
+	       && ($byte0 == 0x01 || $byte0 == 0x00 || $byte0 == 0x20);
+
+	my $width = ($byte0 + 31) * 8;
+	my $height = $width * $standard_scales[$byte1 >> 6]->[0]
+			    / $standard_scales[$byte1 >> 6]->[1];
+	my $refresh = 60 + ($byte1 & 0x3f);
+
+	add_timing($timings, [$width, $height, $refresh]);
+}
+
+sub sort_timings
+{
+	# First order by width
+	return -1 if  $a->[0] < $b->[0];
+	return 1 if  $a->[0] > $b->[0];
+
+	# Second by height
+	return -1 if  $a->[1] < $b->[1];
+	return 1 if  $a->[1] > $b->[1];
+
+	# Third by frequency
+	# Interlaced modes count for half their frequency
+	my $freq_a = $a->[2];
+	my $freq_b = $b->[2];
+	$freq_a /= 2 if defined $a->[3] && $a->[3] eq 'interlaced';
+	$freq_b /= 2 if defined $b->[3] && $b->[3] eq 'interlaced';
+	return -1 if $freq_a < $freq_b;
+	return 1 if $freq_a > $freq_b;
+
+	return 0;
+}
+
+sub print_timings
+{
+	my ($bytes, $timings) = @_;
+
+	# Established Timings
+	my @established =
+	(
+		[720, 400, 70],
+		[720, 400, 88],
+		[640, 480, 60],
+		[640, 480, 67],
+		[640, 480, 72],
+		[640, 480, 75],
+		[800, 600, 56],
+		[800, 600, 60],
+		[800, 600, 72],
+		[800, 600, 75],
+		[832, 624, 75],
+		[1024, 768, 87, 'interlaced'],
+		[1024, 768, 60],
+		[1024, 768, 70],
+		[1024, 768, 75],
+		[1280, 1024, 75],
+		undef, undef, undef,
+		[1152, 870, 75],
+	);
+	my $temp = extract_sesquiword($bytes, 0x23);
+	for (my $i = 0; $i < 24; $i++)
+	{
+		next unless defined($established[$i]);
+		add_timing($timings, $established[$i])
+			if ($temp & (1 << $i));
+	}
+
+	# Standard Timings
+	for (my $i = 0x26; $i < 0x36; $i += 2)
+	{
+		add_standard_timing($timings, $bytes->[$i], $bytes->[$i+1]);
+	}
+
+	foreach my $v (sort sort_timings values(%{$timings}))
+	{
+		print_line("Timing", '%ux%u @ %u Hz%s',
+			   $v->[0], $v->[1], $v->[2],
+			   defined($v->[3]) ? ' ('.$v->[3].')' : '');
+	}
+}
+
+sub extract_string
+{
+	my ($bytes, $offset) = @_;
+	my $string = '';
+
+	for (my $i = 5; $i < 18; $i++)
+	{
+		last if $bytes->[$offset+$i] == 0x0a
+		     || $bytes->[$offset+$i] == 0x00;
+		$string .= chr($bytes->[$offset+$i])
+			if ($bytes->[$offset+$i] >= 32
+			&& $bytes->[$offset+$i] < 127);
+	}
+	$string =~ s/\s+$//;
+
+	return $string;
+}
+
+# Some blocks contain different information:
+#   0x00, 0x00, 0x00, 0xfa: Additional standard timings block
+#   0x00, 0x00, 0x00, 0xfc: Monitor block
+#   0x00, 0x00, 0x00, 0xfd: Limits block
+#   0x00, 0x00, 0x00, 0xfe: Ascii block
+#   0x00, 0x00, 0x00, 0xff: Serial block
+# Return a reference to a hash containing all information.
+sub extract_detailed_timings
+{
+	my ($bytes) = @_;
+
+	my %info = ('timings' => {});
+
+	for (my $offset = 0x36; $offset < 0x7e; $offset += 18)
+	{
+		if ($bytes->[$offset] == 0x00
+		 && $bytes->[$offset+1] == 0x00
+		 && $bytes->[$offset+2] == 0x00
+		 && $bytes->[$offset+4] == 0x00)
+		{
+			if ($bytes->[$offset+3] == 0xfa)
+			{
+				for (my $i = $offset + 5; $i < $offset + 17; $i += 2)
+				{
+					add_standard_timing($info{'timings'},
+							    $bytes->[$i],
+							    $bytes->[$i+1]);
+				}
+			}
+
+			elsif ($bytes->[$offset+3] == 0xfc)
+			{
+				$info{'monitor'} .= extract_string($bytes, $offset);
+			}
+
+			elsif ($bytes->[$offset+3] == 0xfd)
+			{
+				$info{'limits'}{'vsync_min'} = $bytes->[$offset+5];
+				$info{'limits'}{'vsync_max'} = $bytes->[$offset+6];
+				$info{'limits'}{'hsync_min'} = $bytes->[$offset+7];
+				$info{'limits'}{'hsync_max'} = $bytes->[$offset+8];
+				$info{'limits'}{'clock_max'} = $bytes->[$offset+9];
+			}
+
+			elsif ($bytes->[$offset+3] == 0xfe)
+			{
+				$info{'ascii'} .= extract_string($bytes, $offset);
+			}
+
+			elsif ($bytes->[$offset+3] == 0xff)
+			{
+				$info{'serial'} .= extract_string($bytes, $offset);
+			}
+
+			next;
+		}
+
+		# Detailed Timing
+		my $width = $bytes->[$offset+2] + (($bytes->[$offset+4] & 0xf0) << 4);
+		my $height = $bytes->[$offset+5] + (($bytes->[$offset+7] & 0xf0) << 4);
+		my $clock = extract_word($bytes, $offset) * 10000;
+		my $hblank = $bytes->[$offset+3] + (($bytes->[$offset+4] & 0x0f) << 8);
+		my $vblank = $bytes->[$offset+6] + (($bytes->[$offset+7] & 0x0f) << 8);
+		my $area = ($width + $hblank) * ($height + $vblank);
+		next unless $area; # Should not happen, but...
+		my $refresh = ($clock + $area / 2) / $area; # Proper rounding
+		add_timing($info{'timings'}, [$width, $height, $refresh]);
+	}
+
+	return \%info;
+}
+
+sub print_edid
+{
+	my ($bus, $address) = @_;
+	my $bytes;
+
+	if (-r "/sys/bus/i2c/devices/$bus-00$address/eeprom")
+	{
+		$bytes = get_edid_sysfs($bus, $address);
+	}
+	elsif (-r "/proc/sys/dev/sensors/eeprom-i2c-$bus-$address/00")
+	{
+		$bytes = get_edid_procfs($bus, $address);
+	}
+
+	return 1 unless defined $bytes;
+	return 2 unless good_signature($bytes);
+
+	print_line('Checksum', '%s', verify_checksum($bytes));
+	my $edid_version = extract_byte($bytes, 0x12);
+	my $edid_revision = extract_byte($bytes, 0x13);
+	print_line('EDID Version', '%u.%u', $edid_version,
+		   $edid_revision);
+	if ($edid_version > 1 || $edid_revision > 2)
+	{
+		$standard_scales[0][0] = 16;
+		$standard_scales[0][1] = 10;
+	}
+	else
+	{
+		$standard_scales[0][0] = 1;
+		$standard_scales[0][1] = 1;
+	}
+
+	my $info = extract_detailed_timings($bytes);
+
+	print_line('Manufacturer ID', '%s', extract_manufacturer($bytes, 0x08));
+	print_line('Model Number', '0x%04X', extract_word($bytes, 0x0A));
+	print_line('Model Name', '%s', $info->{'monitor'})
+		if defined $info->{'monitor'};
+
+	if ($info->{'serial'})
+	{
+		print_line('Serial Number', '%s', $info->{'serial'})
+	}
+	elsif ((my $temp = extract_dword($bytes, 0x0C)))
+	{
+		print_line('Serial Number', '%u', $temp)
+	}
+
+	print_line('Manufacture Time', '%u-W%02u',
+		   1990 + extract_byte($bytes, 0x11),
+		   extract_byte($bytes, 0x10));
+	print_line('Display Input', '%s', extract_display_input($bytes, 0x14));
+	print_line('Monitor Size (cm)', '%ux%u', extract_byte($bytes, 0x15),
+		   extract_byte($bytes, 0x16));
+	print_line('Gamma Factor', '%.2f',
+		   1 + extract_byte($bytes, 0x17) / 100.0);
+	print_line('DPMS Modes', '%s', extract_dpms($bytes, 0x18));
+	print_line('Color Mode', '%s', extract_color_mode($bytes, 0x18))
+		if (($bytes->[0x18] & 0x18) != 0x18);
+	print_line('Additional Info', '%s', $info->{'ascii'})
+		if $info->{'ascii'};
+
+	if (defined($info->{'limits'}))
+	{
+		print_line('Vertical Sync (Hz)', '%u-%u',
+			   $info->{'limits'}{'vsync_min'},
+			   $info->{'limits'}{'vsync_max'});
+		print_line('Horizontal Sync (kHz)', '%u-%u',
+			   $info->{'limits'}{'hsync_min'},
+			   $info->{'limits'}{'hsync_max'});
+		print_line('Max Pixel Clock (MHz)', '%u',
+			   $info->{'limits'}{'clock_max'} * 10)
+			unless $info->{'limits'}{'clock_max'} == 0xff;
+	}
+
+	print_timings($bytes, $info->{'timings'});
+	print("\n");
+	return 0;
+}
+
+# Get the address. Default to 0x50 if not given.
+my $address;
+if (defined($ARGV[1]))
+{
+	$address = $ARGV[1];
+	# Convert to decimal, whatever the value.
+	$address = oct $address if $address =~ m/^0/;
+	# Convert to an hexadecimal string.
+	$address = sprintf '%02x', $address;
+}
+else
+{
+	$address = '50';
+}
+
+if (defined($ARGV[0]))
+{
+	my $error = print_edid($ARGV[0], $address);
+	
+	if ($error == 1)
+	{
+		print STDERR
+			"No EEPROM found at 0x$address on bus $ARGV[0].\n";
+		exit 1;
+	}
+	elsif ($error == 2)
+	{
+		print STDERR
+			"EEPROM found at 0x$address on bus $ARGV[0], but is not an EDID EEPROM.\n";
+		exit 1;
+	}
+}
+# If no bus is given, try them all.
+else
+{
+	my $total = 0;
+
+	for (my $i = 0; $i < 16; $i++)
+	{
+		$total++ unless print_edid($i, $address);
+	}
+
+	unless ($total)
+	{
+		print STDERR
+			"No EDID EEPROM found.\n";
+		exit 1;
+	}
+}
diff --git a/i2c-tools-3.0.2/eeprom/decode-dimms b/i2c-tools-3.0.2/eeprom/decode-dimms
new file mode 100755
index 0000000..cf9cebf
--- /dev/null
+++ b/i2c-tools-3.0.2/eeprom/decode-dimms
@@ -0,0 +1,1417 @@
+#!/usr/bin/perl -w
+#
+# EEPROM data decoder for SDRAM DIMM modules
+#
+# Copyright 1998, 1999 Philip Edelbrock <phil@netroedge.com>
+# modified by Christian Zuckschwerdt <zany@triq.net>
+# modified by Burkart Lingner <burkart@bollchen.de>
+# Copyright (C) 2005-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.
+#
+#
+# The eeprom driver must be loaded (unless option -x is used). For kernels
+# older than 2.6.0, the eeprom driver can be found in the lm-sensors package.
+#
+# References:
+# PC SDRAM Serial Presence
+# Detect (SPD) Specification, Intel,
+# 1997,1999, Rev 1.2B
+#
+# Jedec Standards 4.1.x & 4.5.x
+# http://www.jedec.org
+#
+
+require 5.004;
+
+use strict;
+use POSIX qw(ceil);
+use Fcntl qw(:DEFAULT :seek);
+use vars qw($opt_html $opt_bodyonly $opt_igncheck $use_sysfs $use_hexdump
+	    @vendors %decode_callback $revision @dimm_list %hexdump_cache);
+
+use constant LITTLEENDIAN	=> "little-endian";
+use constant BIGENDIAN		=> "big-endian";
+
+$revision = '$Revision: 5388 $ ($Date: 2008-11-18 18:15:09 +0100 (mar. 18 nov. 2008) $)';
+$revision =~ s/\$\w+: (.*?) \$/$1/g;
+$revision =~ s/ \([^()]*\)//;
+
+@vendors = (
+["AMD", "AMI", "Fairchild", "Fujitsu",
+ "GTE", "Harris", "Hitachi", "Inmos",
+ "Intel", "I.T.T.", "Intersil", "Monolithic Memories",
+ "Mostek", "Freescale (former Motorola)", "National", "NEC",
+ "RCA", "Raytheon", "Conexant (Rockwell)", "Seeq",
+ "NXP (former Signetics, Philips Semi.)", "Synertek", "Texas Instruments", "Toshiba",
+ "Xicor", "Zilog", "Eurotechnique", "Mitsubishi",
+ "Lucent (AT&T)", "Exel", "Atmel", "SGS/Thomson",
+ "Lattice Semi.", "NCR", "Wafer Scale Integration", "IBM",
+ "Tristar", "Visic", "Intl. CMOS Technology", "SSSI",
+ "MicrochipTechnology", "Ricoh Ltd.", "VLSI", "Micron Technology",
+ "Hyundai Electronics", "OKI Semiconductor", "ACTEL", "Sharp",
+ "Catalyst", "Panasonic", "IDT", "Cypress",
+ "DEC", "LSI Logic", "Zarlink (former Plessey)", "UTMC",
+ "Thinking Machine", "Thomson CSF", "Integrated CMOS (Vertex)", "Honeywell",
+ "Tektronix", "Sun Microsystems", "SST", "ProMos/Mosel Vitelic",
+ "Infineon (former Siemens)", "Macronix", "Xerox", "Plus Logic",
+ "SunDisk", "Elan Circuit Tech.", "European Silicon Str.", "Apple Computer",
+ "Xilinx", "Compaq", "Protocol Engines", "SCI",
+ "Seiko Instruments", "Samsung", "I3 Design System", "Klic",
+ "Crosspoint Solutions", "Alliance Semiconductor", "Tandem", "Hewlett-Packard",
+ "Intg. Silicon Solutions", "Brooktree", "New Media", "MHS Electronic",
+ "Performance Semi.", "Winbond Electronic", "Kawasaki Steel", "Bright Micro",
+ "TECMAR", "Exar", "PCMCIA", "LG Semi (former Goldstar)",
+ "Northern Telecom", "Sanyo", "Array Microsystems", "Crystal Semiconductor",
+ "Analog Devices", "PMC-Sierra", "Asparix", "Convex Computer",
+ "Quality Semiconductor", "Nimbus Technology", "Transwitch", "Micronas (ITT Intermetall)",
+ "Cannon", "Altera", "NEXCOM", "QUALCOMM",
+ "Sony", "Cray Research", "AMS(Austria Micro)", "Vitesse",
+ "Aster Electronics", "Bay Networks (Synoptic)", "Zentrum or ZMD", "TRW",
+ "Thesys", "Solbourne Computer", "Allied-Signal", "Dialog",
+ "Media Vision", "Level One Communication"],
+["Cirrus Logic", "National Instruments", "ILC Data Device", "Alcatel Mietec",
+ "Micro Linear", "Univ. of NC", "JTAG Technologies", "BAE Systems",
+ "Nchip", "Galileo Tech", "Bestlink Systems", "Graychip",
+ "GENNUM", "VideoLogic", "Robert Bosch", "Chip Express",
+ "DATARAM", "United Microelec Corp.", "TCSI", "Smart Modular",
+ "Hughes Aircraft", "Lanstar Semiconductor", "Qlogic", "Kingston",
+ "Music Semi", "Ericsson Components", "SpaSE", "Eon Silicon Devices",
+ "Programmable Micro Corp", "DoD", "Integ. Memories Tech.", "Corollary Inc.",
+ "Dallas Semiconductor", "Omnivision", "EIV(Switzerland)", "Novatel Wireless",
+ "Zarlink (former Mitel)", "Clearpoint", "Cabletron", "STEC (former Silicon Technology)",
+ "Vanguard", "Hagiwara Sys-Com", "Vantis", "Celestica",
+ "Century", "Hal Computers", "Rohm Company Ltd.", "Juniper Networks",
+ "Libit Signal Processing", "Mushkin Enhanced Memory", "Tundra Semiconductor", "Adaptec Inc.",
+ "LightSpeed Semi.", "ZSP Corp.", "AMIC Technology", "Adobe Systems",
+ "Dynachip", "PNY Electronics", "Newport Digital", "MMC Networks",
+ "T Square", "Seiko Epson", "Broadcom", "Viking Components",
+ "V3 Semiconductor", "Flextronics (former Orbit)", "Suwa Electronics", "Transmeta",
+ "Micron CMS", "American Computer & Digital Components Inc", "Enhance 3000 Inc", "Tower Semiconductor",
+ "CPU Design", "Price Point", "Maxim Integrated Product", "Tellabs",
+ "Centaur Technology", "Unigen Corporation", "Transcend Information", "Memory Card Technology",
+ "CKD Corporation Ltd.", "Capital Instruments, Inc.", "Aica Kogyo, Ltd.", "Linvex Technology",
+ "MSC Vertriebs GmbH", "AKM Company, Ltd.", "Dynamem, Inc.", "NERA ASA",
+ "GSI Technology", "Dane-Elec (C Memory)", "Acorn Computers", "Lara Technology",
+ "Oak Technology, Inc.", "Itec Memory", "Tanisys Technology", "Truevision",
+ "Wintec Industries", "Super PC Memory", "MGV Memory", "Galvantech",
+ "Gadzoox Nteworks", "Multi Dimensional Cons.", "GateField", "Integrated Memory System",
+ "Triscend", "XaQti", "Goldenram", "Clear Logic",
+ "Cimaron Communications", "Nippon Steel Semi. Corp.", "Advantage Memory", "AMCC",
+ "LeCroy", "Yamaha Corporation", "Digital Microwave", "NetLogic Microsystems",
+ "MIMOS Semiconductor", "Advanced Fibre", "BF Goodrich Data.", "Epigram",
+ "Acbel Polytech Inc.", "Apacer Technology", "Admor Memory", "FOXCONN",
+ "Quadratics Superconductor", "3COM"],
+["Camintonn Corporation", "ISOA Incorporated", "Agate Semiconductor", "ADMtek Incorporated",
+ "HYPERTEC", "Adhoc Technologies", "MOSAID Technologies", "Ardent Technologies",
+ "Switchcore", "Cisco Systems, Inc.", "Allayer Technologies", "WorkX AG",
+ "Oasis Semiconductor", "Novanet Semiconductor", "E-M Solutions", "Power General",
+ "Advanced Hardware Arch.", "Inova Semiconductors GmbH", "Telocity", "Delkin Devices",
+ "Symagery Microsystems", "C-Port Corporation", "SiberCore Technologies", "Southland Microsystems",
+ "Malleable Technologies", "Kendin Communications", "Great Technology Microcomputer", "Sanmina Corporation",
+ "HADCO Corporation", "Corsair", "Actrans System Inc.", "ALPHA Technologies",
+ "Silicon Laboratories, Inc. (Cygnal)", "Artesyn Technologies", "Align Manufacturing", "Peregrine Semiconductor",
+ "Chameleon Systems", "Aplus Flash Technology", "MIPS Technologies", "Chrysalis ITS",
+ "ADTEC Corporation", "Kentron Technologies", "Win Technologies", "Tachyon Semiconductor (former ASIC Designs Inc.)",
+ "Extreme Packet Devices", "RF Micro Devices", "Siemens AG", "Sarnoff Corporation",
+ "Itautec Philco SA", "Radiata Inc.", "Benchmark Elect. (AVEX)", "Legend",
+ "SpecTek Incorporated", "Hi/fn", "Enikia Incorporated", "SwitchOn Networks",
+ "AANetcom Incorporated", "Micro Memory Bank", "ESS Technology", "Virata Corporation",
+ "Excess Bandwidth", "West Bay Semiconductor", "DSP Group", "Newport Communications",
+ "Chip2Chip Incorporated", "Phobos Corporation", "Intellitech Corporation", "Nordic VLSI ASA",
+ "Ishoni Networks", "Silicon Spice", "Alchemy Semiconductor", "Agilent Technologies",
+ "Centillium Communications", "W.L. Gore", "HanBit Electronics", "GlobeSpan",
+ "Element 14", "Pycon", "Saifun Semiconductors", "Sibyte, Incorporated",
+ "MetaLink Technologies", "Feiya Technology", "I & C Technology", "Shikatronics",
+ "Elektrobit", "Megic", "Com-Tier", "Malaysia Micro Solutions",
+ "Hyperchip", "Gemstone Communications", "Anadigm (former Anadyne)", "3ParData",
+ "Mellanox Technologies", "Tenx Technologies", "Helix AG", "Domosys",
+ "Skyup Technology", "HiNT Corporation", "Chiaro", "MDT Technologies GmbH (former MCI Computer GMBH)",
+ "Exbit Technology A/S", "Integrated Technology Express", "AVED Memory", "Legerity",
+ "Jasmine Networks", "Caspian Networks", "nCUBE", "Silicon Access Networks",
+ "FDK Corporation", "High Bandwidth Access", "MultiLink Technology", "BRECIS",
+ "World Wide Packets", "APW", "Chicory Systems", "Xstream Logic",
+ "Fast-Chip", "Zucotto Wireless", "Realchip", "Galaxy Power",
+ "eSilicon", "Morphics Technology", "Accelerant Networks", "Silicon Wave",
+ "SandCraft", "Elpida"],
+["Solectron", "Optosys Technologies", "Buffalo (former Melco)", "TriMedia Technologies",
+ "Cyan Technologies", "Global Locate", "Optillion", "Terago Communications",
+ "Ikanos Communications", "Princeton Technology", "Nanya Technology", "Elite Flash Storage",
+ "Mysticom", "LightSand Communications", "ATI Technologies", "Agere Systems",
+ "NeoMagic", "AuroraNetics", "Golden Empire", "Mushkin",
+ "Tioga Technologies", "Netlist", "TeraLogic", "Cicada Semiconductor",
+ "Centon Electronics", "Tyco Electronics", "Magis Works", "Zettacom",
+ "Cogency Semiconductor", "Chipcon AS", "Aspex Technology", "F5 Networks",
+ "Programmable Silicon Solutions", "ChipWrights", "Acorn Networks", "Quicklogic",
+ "Kingmax Semiconductor", "BOPS", "Flasys", "BitBlitz Communications",
+ "eMemory Technology", "Procket Networks", "Purple Ray", "Trebia Networks",
+ "Delta Electronics", "Onex Communications", "Ample Communications", "Memory Experts Intl",
+ "Astute Networks", "Azanda Network Devices", "Dibcom", "Tekmos",
+ "API NetWorks", "Bay Microsystems", "Firecron Ltd", "Resonext Communications",
+ "Tachys Technologies", "Equator Technology", "Concept Computer", "SILCOM",
+ "3Dlabs", "c't Magazine", "Sanera Systems", "Silicon Packets",
+ "Viasystems Group", "Simtek", "Semicon Devices Singapore", "Satron Handelsges",
+ "Improv Systems", "INDUSYS GmbH", "Corrent", "Infrant Technologies",
+ "Ritek Corp", "empowerTel Networks", "Hypertec", "Cavium Networks",
+ "PLX Technology", "Massana Design", "Intrinsity", "Valence Semiconductor",
+ "Terawave Communications", "IceFyre Semiconductor", "Primarion", "Picochip Designs Ltd",
+ "Silverback Systems", "Jade Star Technologies", "Pijnenburg Securealink",
+ "TakeMS International AG", "Cambridge Silicon Radio",
+ "Swissbit", "Nazomi Communications", "eWave System",
+ "Rockwell Collins", "Picocel Co., Ltd.", "Alphamosaic Ltd", "Sandburst",
+ "SiCon Video", "NanoAmp Solutions", "Ericsson Technology", "PrairieComm",
+ "Mitac International", "Layer N Networks", "MtekVision", "Allegro Networks",
+ "Marvell Semiconductors", "Netergy Microelectronic", "NVIDIA", "Internet Machines",
+ "Peak Electronics", "Litchfield Communication", "Accton Technology", "Teradiant Networks",
+ "Europe Technologies", "Cortina Systems", "RAM Components", "Raqia Networks",
+ "ClearSpeed", "Matsushita Battery", "Xelerated", "SimpleTech",
+ "Utron Technology", "Astec International", "AVM gmbH", "Redux Communications",
+ "Dot Hill Systems", "TeraChip"],
+["T-RAM Incorporated", "Innovics Wireless", "Teknovus", "KeyEye Communications",
+ "Runcom Technologies", "RedSwitch", "Dotcast", "Silicon Mountain Memory",
+ "Signia Technologies", "Pixim", "Galazar Networks", "White Electronic Designs",
+ "Patriot Scientific", "Neoaxiom Corporation", "3Y Power Technology", "Europe Technologies",
+ "Potentia Power Systems", "C-guys Incorporated", "Digital Communications Technology Incorporated", "Silicon-Based Technology",
+ "Fulcrum Microsystems", "Positivo Informatica Ltd", "XIOtech Corporation", "PortalPlayer",
+ "Zhiying Software", "Direct2Data", "Phonex Broadband", "Skyworks Solutions",
+ "Entropic Communications", "Pacific Force Technology", "Zensys A/S", "Legend Silicon Corp.",
+ "sci-worx GmbH", "SMSC (former Oasis Silicon Systems)", "Renesas Technology", "Raza Microelectronics",
+ "Phyworks", "MediaTek", "Non-cents Productions", "US Modular",
+ "Wintegra Ltd", "Mathstar", "StarCore", "Oplus Technologies",
+ "Mindspeed", "Just Young Computer", "Radia Communications", "OCZ",
+ "Emuzed", "LOGIC Devices", "Inphi Corporation", "Quake Technologies",
+ "Vixel", "SolusTek", "Kongsberg Maritime", "Faraday Technology",
+ "Altium Ltd.", "Insyte", "ARM Ltd.", "DigiVision",
+ "Vativ Technologies", "Endicott Interconnect Technologies", "Pericom", "Bandspeed",
+ "LeWiz Communications", "CPU Technology", "Ramaxel Technology", "DSP Group",
+ "Axis Communications", "Legacy Electronics", "Chrontel", "Powerchip Semiconductor",
+ "MobilEye Technologies", "Excel Semiconductor", "A-DATA Technology", "VirtualDigm",
+ "G Skill Intl", "Quanta Computer", "Yield Microelectronics", "Afa Technologies",
+ "KINGBOX Technology Co. Ltd.", "Ceva", "iStor Networks", "Advance Modules",
+ "Microsoft", "Open-Silicon", "Goal Semiconductor", "ARC International",
+ "Simmtec", "Metanoia", "Key Stream", "Lowrance Electronics",
+ "Adimos", "SiGe Semiconductor", "Fodus Communications", "Credence Systems Corp.",
+ "Genesis Microchip Inc.", "Vihana, Inc.", "WIS Technologies", "GateChange Technologies",
+ "High Density Devices AS", "Synopsys", "Gigaram", "Enigma Semiconductor Inc.",
+ "Century Micro Inc.", "Icera Semiconductor", "Mediaworks Integrated Systems", "O'Neil Product Development",
+ "Supreme Top Technology Ltd.", "MicroDisplay Corporation", "Team Group Inc.", "Sinett Corporation",
+ "Toshiba Corporation", "Tensilica", "SiRF Technology", "Bacoc Inc.",
+ "SMaL Camera Technologies", "Thomson SC", "Airgo Networks", "Wisair Ltd.",
+ "SigmaTel", "Arkados", "Compete IT gmbH Co. KG", "Eudar Technology Inc.",
+ "Focus Enhancements", "Xyratex"],
+["Specular Networks", "Patriot Memory", "U-Chip Technology Corp.", "Silicon Optix",
+ "Greenfield Networks", "CompuRAM GmbH", "Stargen, Inc.", "NetCell Corporation",
+ "Excalibrus Technologies Ltd", "SCM Microsystems", "Xsigo Systems, Inc.", "CHIPS & Systems Inc",
+ "Tier 1 Multichip Solutions", "CWRL Labs", "Teradici", "Gigaram, Inc.",
+ "g2 Microsystems", "PowerFlash Semiconductor", "P.A. Semi, Inc.", "NovaTech Solutions, S.A.",
+ "c2 Microsystems, Inc.", "Level5 Networks", "COS Memory AG", "Innovasic Semiconductor",
+ "02IC Co. Ltd", "Tabula, Inc.", "Crucial Technology", "Chelsio Communications",
+ "Solarflare Communications", "Xambala Inc.", "EADS Astrium", "ATO Semicon Co. Ltd.",
+ "Imaging Works, Inc.", "Astute Networks, Inc.", "Tzero", "Emulex",
+ "Power-One", "Pulse~LINK Inc.", "Hon Hai Precision Industry", "White Rock Networks Inc.",
+ "Telegent Systems USA, Inc.", "Atrua Technologies, Inc.", "Acbel Polytech Inc.",
+ "eRide Inc.","ULi Electronics Inc.", "Magnum Semiconductor Inc.", "neoOne Technology, Inc.",
+ "Connex Technology, Inc.", "Stream Processors, Inc.", "Focus Enhancements", "Telecis Wireless, Inc.",
+ "uNav Microelectronics", "Tarari, Inc.", "Ambric, Inc.", "Newport Media, Inc.", "VMTS",
+ "Enuclia Semiconductor, Inc.", "Virtium Technology Inc.", "Solid State System Co., Ltd.", "Kian Tech LLC",
+ "Artimi", "Power Quotient International", "Avago Technologies", "ADTechnology", "Sigma Designs",
+ "SiCortex, Inc.", "Ventura Technology Group", "eASIC", "M.H.S. SAS", "Micro Star International",
+ "Rapport Inc.", "Makway International", "Broad Reach Engineering Co.",
+ "Semiconductor Mfg Intl Corp", "SiConnect", "FCI USA Inc.", "Validity Sensors",
+ "Coney Technology Co. Ltd.", "Spans Logic", "Neterion Inc.", "Qimonda",
+ "New Japan Radio Co. Ltd.", "Velogix", "Montalvo Systems", "iVivity Inc.", "Walton Chaintech",
+ "AENEON", "Lorom Industrial Co. Ltd.", "Radiospire Networks", "Sensio Technologies, Inc.",
+ "Nethra Imaging", "Hexon Technology Pte Ltd", "CompuStocx (CSX)", "Methode Electronics, Inc.",
+ "Connect One Ltd.", "Opulan Technologies", "Septentrio NV", "Goldenmars Technology Inc.",
+ "Kreton Corporation", "Cochlear Ltd.", "Altair Semiconductor", "NetEffect, Inc.",
+ "Spansion, Inc.", "Taiwan Semiconductor Mfg", "Emphany Systems Inc.",
+ "ApaceWave Technologies", "Mobilygen Corporation", "Tego", "Cswitch Corporation",
+ "Haier (Beijing) IC Design Co.", "MetaRAM", "Axel Electronics Co. Ltd.", "Tilera Corporation",
+ "Aquantia", "Vivace Semiconductor", "Redpine Signals", "Octalica", "InterDigital Communications",
+ "Avant Technology", "Asrock, Inc.", "Availink", "Quartics, Inc.", "Element CXI",
+ "Innovaciones Microelectronicas", "VeriSilicon Microelectronics", "W5 Networks"],
+["MOVEKING", "Mavrix Technology, Inc.", "CellGuide Ltd.", "Faraday Technology",
+ "Diablo Technologies, Inc.", "Jennic", "Octasic", "Molex Incorporated", "3Leaf Networks",
+ "Bright Micron Technology", "Netxen", "NextWave Broadband Inc.", "DisplayLink", "ZMOS Technology",
+ "Tec-Hill", "Multigig, Inc.", "Amimon", "Euphonic Technologies, Inc.", "BRN Phoenix",
+ "InSilica", "Ember Corporation", "Avexir Technologies Corporation", "Echelon Corporation",
+ "Edgewater Computer Systems", "XMOS Semiconductor Ltd.", "GENUSION, Inc.", "Memory Corp NV",
+ "SiliconBlue Technologies", "Rambus Inc."]);
+
+$use_sysfs = -d '/sys/bus';
+
+# We consider that no data was written to this area of the SPD EEPROM if
+# all bytes read 0x00 or all bytes read 0xff
+sub spd_written(@)
+{
+	my $all_00 = 1;
+	my $all_ff = 1;
+
+	foreach my $b (@_) {
+		$all_00 = 0 unless $b == 0x00;
+		$all_ff = 0 unless $b == 0xff;
+		return 1 unless $all_00 or $all_ff;
+	}
+
+	return 0;
+}
+
+sub parity($)
+{
+	my $n = shift;
+	my $parity = 0;
+
+	while ($n) {
+		$parity++ if ($n & 1);
+		$n >>= 1;
+	}
+
+	return ($parity & 1);
+}
+
+sub manufacturer(@)
+{
+	my @bytes = @_;
+	my $ai = 0;
+	my $first;
+
+	return ("Undefined", []) unless spd_written(@bytes);
+
+	while (defined($first = shift(@bytes)) && $first == 0x7F) {
+		$ai++;
+	}
+
+	return ("Invalid", []) unless defined $first;
+	return ("Invalid", [$first, @bytes]) if parity($first) != 1;
+	return ("Unknown", \@bytes) unless (($first & 0x7F) - 1 <= $vendors[$ai]);
+
+	return ($vendors[$ai][($first & 0x7F) - 1], \@bytes);
+}
+
+sub manufacturer_data(@)
+{
+	my $hex = "";
+	my $asc = "";
+
+	return unless spd_written(@_);
+
+	foreach my $byte (@_) {
+		$hex .= sprintf("\%02X ", $byte);
+		$asc .= ($byte >= 32 && $byte < 127) ? chr($byte) : '?';
+	}
+
+	return "$hex(\"$asc\")";
+}
+
+sub part_number(@)
+{
+	my $asc = "";
+	my $byte;
+
+	while (defined ($byte = shift) && $byte >= 32 && $byte < 127) {
+		$asc .= chr($byte);
+	}
+
+	return ($asc eq "") ? "Undefined" : $asc;
+}
+
+sub cas_latencies(@)
+{
+	return "None" unless @_;
+	return join ', ', map("${_}T", sort { $b <=> $a } @_);
+}
+
+sub printl($$) # print a line w/ label and value
+{
+	my ($label, $value) = @_;
+	if ($opt_html) {
+		$label =~ s/</\&lt;/sg;
+		$label =~ s/>/\&gt;/sg;
+		$label =~ s/\n/<br>\n/sg;
+		$value =~ s/</\&lt;/sg;
+		$value =~ s/>/\&gt;/sg;
+		$value =~ s/\n/<br>\n/sg;
+		print "<tr><td valign=top>$label</td><td>$value</td></tr>\n";
+	} else {
+		my @values = split /\n/, $value;
+		printf "%-47s %s\n", $label, shift @values;
+		printf "%-47s %s\n", "", $_ foreach (@values);
+	}
+}
+
+sub printl2($$) # print a line w/ label and value (outside a table)
+{
+	my ($label, $value) = @_;
+	if ($opt_html) {
+		$label =~ s/</\&lt;/sg;
+		$label =~ s/>/\&gt;/sg;
+		$label =~ s/\n/<br>\n/sg;
+		$value =~ s/</\&lt;/sg;
+		$value =~ s/>/\&gt;/sg;
+		$value =~ s/\n/<br>\n/sg;
+	}
+	print "$label: $value\n";
+}
+
+sub prints($) # print seperator w/ given text
+{
+	my ($label) = @_;
+	if ($opt_html) {
+		$label =~ s/</\&lt;/sg;
+		$label =~ s/>/\&gt;/sg;
+		$label =~ s/\n/<br>\n/sg;
+		print "<tr><td align=center colspan=2><b>$label</b></td></tr>\n";
+	} else {
+		print "\n---=== $label ===---\n";
+	}
+}
+
+sub printh($$) # print header w/ given text
+{
+	my ($header, $sub) = @_;
+	if ($opt_html) {
+		$header =~ s/</\&lt;/sg;
+		$header =~ s/>/\&gt;/sg;
+		$header =~ s/\n/<br>\n/sg;
+		$sub =~ s/</\&lt;/sg;
+		$sub =~ s/>/\&gt;/sg;
+		$sub =~ s/\n/<br>\n/sg;
+		print "<h1>$header</h1>\n";
+		print "<p>$sub</p>\n";
+	} else {
+		print "\n$header\n$sub\n";
+	}
+}
+
+sub printc($) # print comment
+{
+	my ($comment) = @_;
+	if ($opt_html) {
+		$comment =~ s/</\&lt;/sg;
+		$comment =~ s/>/\&gt;/sg;
+		$comment =~ s/\n/<br>\n/sg;
+		print "<!-- $comment -->\n";
+	} else {
+		print "# $comment\n";
+	}
+}
+
+sub tns($) # print a time in ns
+{
+	return sprintf("%3.2f ns", $_[0]);
+}
+
+# Parameter: bytes 0-63
+sub decode_sdr_sdram($)
+{
+	my $bytes = shift;
+	my ($l, $temp);
+
+# SPD revision
+	printl "SPD Revision", $bytes->[62];
+
+#size computation
+
+	prints "Memory Characteristics";
+
+	my $k = 0;
+	my $ii = 0;
+
+	$ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17;
+	if (($bytes->[5] <= 8) && ($bytes->[17] <= 8)) {
+		 $k = $bytes->[5] * $bytes->[17];
+	}
+
+	if ($ii > 0 && $ii <= 12 && $k > 0) {
+		printl "Size", ((1 << $ii) * $k) . " MB";
+	} else {
+		printl "INVALID SIZE", $bytes->[3] . "," . $bytes->[4] . "," .
+				       $bytes->[5] . "," . $bytes->[17];
+	}
+
+	my @cas;
+	for ($ii = 0; $ii < 7; $ii++) {
+		push(@cas, $ii + 1) if ($bytes->[18] & (1 << $ii));
+	}
+
+	my $trcd;
+	my $trp;
+	my $tras;
+	my $ctime = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
+
+	$trcd = $bytes->[29];
+	$trp = $bytes->[27];;
+	$tras = $bytes->[30];
+
+	printl "tCL-tRCD-tRP-tRAS",
+		$cas[$#cas] . "-" .
+		ceil($trcd/$ctime) . "-" .
+		ceil($trp/$ctime) . "-" .
+		ceil($tras/$ctime);
+
+	$l = "Number of Row Address Bits";
+	if ($bytes->[3] == 0) { printl $l, "Undefined!"; }
+	elsif ($bytes->[3] == 1) { printl $l, "1/16"; }
+	elsif ($bytes->[3] == 2) { printl $l, "2/17"; }
+	elsif ($bytes->[3] == 3) { printl $l, "3/18"; }
+	else { printl $l, $bytes->[3]; }
+
+	$l = "Number of Col Address Bits";
+	if ($bytes->[4] == 0) { printl $l, "Undefined!"; }
+	elsif ($bytes->[4] == 1) { printl $l, "1/16"; }
+	elsif ($bytes->[4] == 2) { printl $l, "2/17"; }
+	elsif ($bytes->[4] == 3) { printl $l, "3/18"; }
+	else { printl $l, $bytes->[4]; }
+
+	$l = "Number of Module Rows";
+	if ($bytes->[5] == 0 ) { printl $l, "Undefined!"; }
+	else { printl $l, $bytes->[5]; }
+
+	$l = "Data Width";
+	if ($bytes->[7] > 1) {
+		printl $l, "Undefined!"
+	} else {
+		$temp = ($bytes->[7] * 256) + $bytes->[6];
+		printl $l, $temp;
+	}
+
+	$l = "Module Interface Signal Levels";
+	if ($bytes->[8] == 0) { printl $l, "5.0 Volt/TTL"; }
+	elsif ($bytes->[8] == 1) { printl $l, "LVTTL"; }
+	elsif ($bytes->[8] == 2) { printl $l, "HSTL 1.5"; }
+	elsif ($bytes->[8] == 3) { printl $l, "SSTL 3.3"; }
+	elsif ($bytes->[8] == 4) { printl $l, "SSTL 2.5"; }
+	elsif ($bytes->[8] == 255) { printl $l, "New Table"; }
+	else { printl $l, "Undefined!"; }
+
+	$l = "Module Configuration Type";
+	if ($bytes->[11] == 0) { printl $l, "No Parity"; }
+	elsif ($bytes->[11] == 1) { printl $l, "Parity"; }
+	elsif ($bytes->[11] == 2) { printl $l, "ECC"; }
+	else { printl $l, "Undefined!"; }
+
+	$l = "Refresh Type";
+	if ($bytes->[12] > 126) { printl $l, "Self Refreshing"; }
+	else { printl $l, "Not Self Refreshing"; }
+
+	$l = "Refresh Rate";
+	$temp = $bytes->[12] & 0x7f;
+	if ($temp == 0) { printl $l, "Normal (15.625 us)"; }
+	elsif ($temp == 1) { printl $l, "Reduced (3.9 us)"; }
+	elsif ($temp == 2) { printl $l, "Reduced (7.8 us)"; }
+	elsif ($temp == 3) { printl $l, "Extended (31.3 us)"; }
+	elsif ($temp == 4) { printl $l, "Extended (62.5 us)"; }
+	elsif ($temp == 5) { printl $l, "Extended (125 us)"; }
+	else { printl $l, "Undefined!"; }
+
+	$l = "Primary SDRAM Component Bank Config";
+	if ($bytes->[13] > 126) { printl $l, "Bank2 = 2 x Bank1"; }
+	else { printl $l, "No Bank2 OR Bank2 = Bank1 width"; }
+
+	$l = "Primary SDRAM Component Widths";
+	$temp = $bytes->[13] & 0x7f;
+	if ($temp == 0) { printl $l, "Undefined!\n"; }
+	else { printl $l, $temp; }
+
+	$l = "Error Checking SDRAM Component Bank Config";
+	if ($bytes->[14] > 126) { printl $l, "Bank2 = 2 x Bank1"; }
+	else { printl $l, "No Bank2 OR Bank2 = Bank1 width"; }
+
+	$l = "Error Checking SDRAM Component Widths";
+	$temp = $bytes->[14] & 0x7f;
+	if ($temp == 0) { printl $l, "Undefined!"; }
+	else { printl $l, $temp; }
+
+	$l = "Min Clock Delay for Back to Back Random Access";
+	if ($bytes->[15] == 0) { printl $l, "Undefined!"; }
+	else { printl $l, $bytes->[15]; }
+
+	$l = "Supported Burst Lengths";
+	my @array;
+	for ($ii = 0; $ii < 4; $ii++) {
+		push(@array, 1 << $ii) if ($bytes->[16] & (1 << $ii));
+	}
+	push(@array, "Page") if ($bytes->[16] & 128);
+	if (@array) { $temp = join ', ', @array; }
+	else { $temp = "None"; }
+	printl $l, $temp;
+
+	$l = "Number of Device Banks";
+	if ($bytes->[17] == 0) { printl $l, "Undefined/Reserved!"; }
+	else { printl $l, $bytes->[17]; }
+
+	$l = "Supported CAS Latencies";
+	printl $l, cas_latencies(@cas);
+
+	$l = "Supported CS Latencies";
+	@array = ();
+	for ($ii = 0; $ii < 7; $ii++) {
+		push(@array, $ii) if ($bytes->[19] & (1 << $ii));
+	}
+	if (@array) { $temp = join ', ', @array; }
+	else { $temp = "None"; }
+	printl $l, $temp;
+
+	$l = "Supported WE Latencies";
+	@array = ();
+	for ($ii = 0; $ii < 7; $ii++) {
+		push(@array, $ii) if ($bytes->[20] & (1 << $ii));
+	}
+	if (@array) { $temp = join ', ', @array; }
+	else { $temp = "None"; }
+	printl $l, $temp;
+
+	if (@cas >= 1) {
+		$l = "Cycle Time at CAS ".$cas[$#cas];
+		printl $l, "$ctime ns";
+
+		$l = "Access Time at CAS ".$cas[$#cas];
+		$temp = ($bytes->[10] >> 4) + ($bytes->[10] & 0xf) * 0.1;
+		printl $l, "$temp ns";
+	}
+
+	if (@cas >= 2 && spd_written(@$bytes[23..24])) {
+		$l = "Cycle Time at CAS ".$cas[$#cas-1];
+		$temp = $bytes->[23] >> 4;
+		if ($temp == 0) { printl $l, "Undefined!"; }
+		else {
+			if ($temp < 4 ) { $temp += 15; }
+			printl $l, $temp + (($bytes->[23] & 0xf) * 0.1) . " ns";
+		}
+
+		$l = "Access Time at CAS ".$cas[$#cas-1];
+		$temp = $bytes->[24] >> 4;
+		if ($temp == 0) { printl $l, "Undefined!"; }
+		else {
+			if ($temp < 4 ) { $temp += 15; }
+			printl $l, $temp + (($bytes->[24] & 0xf) * 0.1) . " ns";
+		}
+	}
+
+	if (@cas >= 3 && spd_written(@$bytes[25..26])) {
+		$l = "Cycle Time at CAS ".$cas[$#cas-2];
+		$temp = $bytes->[25] >> 2;
+		if ($temp == 0) { printl $l, "Undefined!"; }
+		else { printl $l, $temp + ($bytes->[25] & 0x3) * 0.25 . " ns"; }
+
+		$l = "Access Time at CAS ".$cas[$#cas-2];
+		$temp = $bytes->[26] >> 2;
+		if ($temp == 0) { printl $l, "Undefined!"; }
+		else { printl $l, $temp + ($bytes->[26] & 0x3) * 0.25 . " ns"; }
+	}
+
+	$l = "SDRAM Module Attributes";
+	$temp = "";
+	if ($bytes->[21] & 1) { $temp .= "Buffered Address/Control Inputs\n"; }
+	if ($bytes->[21] & 2) { $temp .= "Registered Address/Control Inputs\n"; }
+	if ($bytes->[21] & 4) { $temp .= "On card PLL (clock)\n"; }
+	if ($bytes->[21] & 8) { $temp .= "Buffered DQMB Inputs\n"; }
+	if ($bytes->[21] & 16) { $temp .= "Registered DQMB Inputs\n"; }
+	if ($bytes->[21] & 32) { $temp .= "Differential Clock Input\n"; }
+	if ($bytes->[21] & 64) { $temp .= "Redundant Row Address\n"; }
+	if ($bytes->[21] & 128) { $temp .= "Undefined (bit 7)\n"; }
+	if ($bytes->[21] == 0) { $temp .= "(None Reported)\n"; }
+	printl $l, $temp;
+
+	$l = "SDRAM Device Attributes (General)";
+	$temp = "";
+	if ($bytes->[22] & 1) { $temp .= "Supports Early RAS# Recharge\n"; }
+	if ($bytes->[22] & 2) { $temp .= "Supports Auto-Precharge\n"; }
+	if ($bytes->[22] & 4) { $temp .= "Supports Precharge All\n"; }
+	if ($bytes->[22] & 8) { $temp .= "Supports Write1/Read Burst\n"; }
+	if ($bytes->[22] & 16) { $temp .= "Lower VCC Tolerance: 5%\n"; }
+	else { $temp .= "Lower VCC Tolerance: 10%\n"; }
+	if ($bytes->[22] & 32) { $temp .= "Upper VCC Tolerance: 5%\n"; }
+	else { $temp .= "Upper VCC Tolerance: 10%\n"; }
+	if ($bytes->[22] & 64) { $temp .= "Undefined (bit 6)\n"; }
+	if ($bytes->[22] & 128) { $temp .= "Undefined (bit 7)\n"; }
+	printl $l, $temp;
+
+	$l = "Minimum Row Precharge Time";
+	if ($bytes->[27] == 0) { printl $l, "Undefined!"; }
+	else { printl $l, "$bytes->[27] ns"; }
+
+	$l = "Row Active to Row Active Min";
+	if ($bytes->[28] == 0) { printl $l, "Undefined!"; }
+	else { printl $l, "$bytes->[28] ns"; }
+
+	$l = "RAS to CAS Delay";
+	if ($bytes->[29] == 0) { printl $l, "Undefined!"; }
+	else { printl $l, "$bytes->[29] ns"; }
+
+	$l = "Min RAS Pulse Width";
+	if ($bytes->[30] == 0) { printl $l, "Undefined!"; }
+	else { printl $l, "$bytes->[30] ns"; }
+
+	$l = "Row Densities";
+	$temp = "";
+	if ($bytes->[31] & 1) { $temp .= "4 MByte\n"; }
+	if ($bytes->[31] & 2) { $temp .= "8 MByte\n"; }
+	if ($bytes->[31] & 4) { $temp .= "16 MByte\n"; }
+	if ($bytes->[31] & 8) { $temp .= "32 MByte\n"; }
+	if ($bytes->[31] & 16) { $temp .= "64 MByte\n"; }
+	if ($bytes->[31] & 32) { $temp .= "128 MByte\n"; }
+	if ($bytes->[31] & 64) { $temp .= "256 MByte\n"; }
+	if ($bytes->[31] & 128) { $temp .= "512 MByte\n"; }
+	if ($bytes->[31] == 0) { $temp .= "(Undefined! -- None Reported!)\n"; }
+	printl $l, $temp;
+
+	if (($bytes->[32] & 0xf) <= 9) {
+		$l = "Command and Address Signal Setup Time";
+		$temp = (($bytes->[32] & 0x7f) >> 4) + ($bytes->[32] & 0xf) * 0.1;
+		printl $l, (($bytes->[32] >> 7) ? -$temp : $temp) . " ns";
+	}
+
+	if (($bytes->[33] & 0xf) <= 9) {
+		$l = "Command and Address Signal Hold Time";
+		$temp = (($bytes->[33] & 0x7f) >> 4) + ($bytes->[33] & 0xf) * 0.1;
+		printl $l, (($bytes->[33] >> 7) ? -$temp : $temp) . " ns";
+	}
+
+	if (($bytes->[34] & 0xf) <= 9) {
+		$l = "Data Signal Setup Time";
+		$temp = (($bytes->[34] & 0x7f) >> 4) + ($bytes->[34] & 0xf) * 0.1;
+		printl $l, (($bytes->[34] >> 7) ? -$temp : $temp) . " ns";
+	}
+
+	if (($bytes->[35] & 0xf) <= 9) {
+		$l = "Data Signal Hold Time";
+		$temp = (($bytes->[35] & 0x7f) >> 4) + ($bytes->[35] & 0xf) * 0.1;
+		printl $l, (($bytes->[35] >> 7) ? -$temp : $temp) . " ns";
+	}
+}
+
+# Parameter: bytes 0-63
+sub decode_ddr_sdram($)
+{
+	my $bytes = shift;
+	my ($l, $temp);
+
+# SPD revision
+	if ($bytes->[62] != 0xff) {
+		printl "SPD Revision", ($bytes->[62] >> 4) . "." .
+				       ($bytes->[62] & 0xf);
+	}
+
+# speed
+	prints "Memory Characteristics";
+
+	$l = "Maximum module speed";
+	$temp = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
+	my $ddrclk = 2 * (1000 / $temp);
+	my $tbits = ($bytes->[7] * 256) + $bytes->[6];
+	if (($bytes->[11] == 2) || ($bytes->[11] == 1)) { $tbits = $tbits - 8; }
+	my $pcclk = int ($ddrclk * $tbits / 8);
+	$pcclk += 100 if ($pcclk % 100) >= 50; # Round properly
+	$pcclk = $pcclk - ($pcclk % 100);
+	$ddrclk = int ($ddrclk);
+	printl $l, "${ddrclk}MHz (PC${pcclk})";
+
+#size computation
+	my $k = 0;
+	my $ii = 0;
+
+	$ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17;
+	if (($bytes->[5] <= 8) && ($bytes->[17] <= 8)) {
+		 $k = $bytes->[5] * $bytes->[17];
+	}
+
+	if ($ii > 0 && $ii <= 12 && $k > 0) {
+		printl "Size", ((1 << $ii) * $k) . " MB";
+	} else {
+		printl "INVALID SIZE", $bytes->[3] . ", " . $bytes->[4] . ", " .
+				       $bytes->[5] . ", " . $bytes->[17];
+	}
+
+	my $highestCAS = 0;
+	my %cas;
+	for ($ii = 0; $ii < 7; $ii++) {
+		if ($bytes->[18] & (1 << $ii)) {
+			$highestCAS = 1+$ii*0.5;
+			$cas{$highestCAS}++;
+		}
+	}
+
+	my $trcd;
+	my $trp;
+	my $tras;
+	my $ctime = ($bytes->[9] >> 4) + ($bytes->[9] & 0xf) * 0.1;
+
+	$trcd = ($bytes->[29] >> 2) + (($bytes->[29] & 3) * 0.25);
+	$trp = ($bytes->[27] >> 2) + (($bytes->[27] & 3) * 0.25);
+	$tras = $bytes->[30];
+
+	printl "tCL-tRCD-tRP-tRAS",
+		$highestCAS . "-" .
+		ceil($trcd/$ctime) . "-" .
+		ceil($trp/$ctime) . "-" .
+		ceil($tras/$ctime);
+
+# latencies
+	printl "Supported CAS Latencies", cas_latencies(keys %cas);
+
+	my @array;
+	for ($ii = 0; $ii < 7; $ii++) {
+		push(@array, $ii) if ($bytes->[19] & (1 << $ii));
+	}
+	if (@array) { $temp = join ', ', @array; }
+	else { $temp = "None"; }
+	printl "Supported CS Latencies", $temp;
+
+	@array = ();
+	for ($ii = 0; $ii < 7; $ii++) {
+		push(@array, $ii) if ($bytes->[20] & (1 << $ii));
+	}
+	if (@array) { $temp = join ', ', @array; }
+	else { $temp = "None"; }
+	printl "Supported WE Latencies", $temp;
+
+# timings
+	if (exists $cas{$highestCAS}) {
+		printl "Minimum Cycle Time at CAS $highestCAS",
+		       "$ctime ns";
+
+		printl "Maximum Access Time at CAS $highestCAS",
+		       (($bytes->[10] >> 4) * 0.1 + ($bytes->[10] & 0xf) * 0.01) . " ns";
+	}
+
+	if (exists $cas{$highestCAS-0.5} && spd_written(@$bytes[23..24])) {
+		printl "Minimum Cycle Time at CAS ".($highestCAS-0.5),
+		       (($bytes->[23] >> 4) + ($bytes->[23] & 0xf) * 0.1) . " ns";
+
+		printl "Maximum Access Time at CAS ".($highestCAS-0.5),
+		       (($bytes->[24] >> 4) * 0.1 + ($bytes->[24] & 0xf) * 0.01) . " ns";
+	}
+
+	if (exists $cas{$highestCAS-1} && spd_written(@$bytes[25..26])) {
+		printl "Minimum Cycle Time at CAS ".($highestCAS-1),
+		       (($bytes->[25] >> 4) + ($bytes->[25] & 0xf) * 0.1) . " ns";
+
+		printl "Maximum Access Time at CAS ".($highestCAS-1),
+		       (($bytes->[26] >> 4) * 0.1 + ($bytes->[26] & 0xf) * 0.01) . " ns";
+	}
+
+# module attributes
+	if ($bytes->[47] & 0x03) {
+		if (($bytes->[47] & 0x03) == 0x01) { $temp = "1.125\" to 1.25\""; }
+		elsif (($bytes->[47] & 0x03) == 0x02) { $temp = "1.7\""; }
+		elsif (($bytes->[47] & 0x03) == 0x03) { $temp = "Other"; }
+		printl "Module Height", $temp;
+	}
+}
+
+sub ddr2_sdram_ctime($)
+{
+	my $byte = shift;
+	my $ctime;
+
+	$ctime = $byte >> 4;
+	if (($byte & 0xf) <= 9) { $ctime += ($byte & 0xf) * 0.1; }
+	elsif (($byte & 0xf) == 10) { $ctime += 0.25; }
+	elsif (($byte & 0xf) == 11) { $ctime += 0.33; }
+	elsif (($byte & 0xf) == 12) { $ctime += 0.66; }
+	elsif (($byte & 0xf) == 13) { $ctime += 0.75; }
+
+	return $ctime;
+}
+
+sub ddr2_sdram_atime($)
+{
+	my $byte = shift;
+	my $atime;
+
+	$atime = ($byte >> 4) * 0.1 + ($byte & 0xf) * 0.01;
+
+	return $atime;
+}
+
+# Base, high-bit, 3-bit fraction code
+sub ddr2_sdram_rtime($$$)
+{
+	my ($rtime, $msb, $ext) = @_;
+	my @table = (0, .25, .33, .50, .66, .75);
+
+	return $rtime + $msb * 256 + $table[$ext];
+}
+
+sub ddr2_module_types($)
+{
+	my $byte = shift;
+	my @types = qw(RDIMM UDIMM SO-DIMM Micro-DIMM Mini-RDIMM Mini-UDIMM);
+	my @widths = (133.35, 133.25, 67.6, 45.5, 82.0, 82.0);
+	my @suptypes;
+	local $_;
+
+	foreach (0..5) {
+		push @suptypes, "$types[$_] ($widths[$_] mm)"
+			if ($byte & (1 << $_));
+	}
+
+	return @suptypes;
+}
+
+sub ddr2_refresh_rate($)
+{
+	my $byte = shift;
+	my @refresh = qw(Normal Reduced Reduced Extended Extended Extended);
+	my @refresht = (15.625, 3.9, 7.8, 31.3, 62.5, 125);
+
+	return "$refresh[$byte & 0x7f] ($refresht[$byte & 0x7f] us)".
+	       ($byte & 0x80 ? " - Self Refresh" : "");
+}
+
+# Parameter: bytes 0-63
+sub decode_ddr2_sdram($)
+{
+	my $bytes = shift;
+	my ($l, $temp);
+	my $ctime;
+
+# SPD revision
+	if ($bytes->[62] != 0xff) {
+		printl "SPD Revision", ($bytes->[62] >> 4) . "." .
+				       ($bytes->[62] & 0xf);
+	}
+
+# speed
+	prints "Memory Characteristics";
+
+	$l = "Maximum module speed";
+	$ctime = ddr2_sdram_ctime($bytes->[9]);
+	my $ddrclk = 2 * (1000 / $ctime);
+	my $tbits = ($bytes->[7] * 256) + $bytes->[6];
+	if ($bytes->[11] & 0x03) { $tbits = $tbits - 8; }
+	my $pcclk = int ($ddrclk * $tbits / 8);
+	# Round down to comply with Jedec
+	$pcclk = $pcclk - ($pcclk % 100);
+	$ddrclk = int ($ddrclk);
+	printl $l, "${ddrclk}MHz (PC2-${pcclk})";
+
+#size computation
+	my $k = 0;
+	my $ii = 0;
+
+	$ii = ($bytes->[3] & 0x0f) + ($bytes->[4] & 0x0f) - 17;
+	$k = (($bytes->[5] & 0x7) + 1) * $bytes->[17];
+
+	if($ii > 0 && $ii <= 12 && $k > 0) {
+		printl "Size", ((1 << $ii) * $k) . " MB";
+	} else {
+		printl "INVALID SIZE", $bytes->[3] . "," . $bytes->[4] . "," .
+				       $bytes->[5] . "," . $bytes->[17];
+	}
+
+	printl "Banks x Rows x Columns x Bits",
+	       join(' x ', $bytes->[17], $bytes->[3], $bytes->[4], $bytes->[6]);
+	printl "Ranks", ($bytes->[5] & 7) + 1;
+
+	printl "SDRAM Device Width", $bytes->[13]." bits";
+
+	my @heights = ('< 25.4', '25.4', '25.4 - 30.0', '30.0', '30.5', '> 30.5');
+	printl "Module Height", $heights[$bytes->[5] >> 5]." mm";
+
+	my @suptypes = ddr2_module_types($bytes->[20]);
+	printl "Module Type".(@suptypes > 1 ? 's' : ''), join(', ', @suptypes);
+
+	printl "DRAM Package", $bytes->[5] & 0x10 ? "Stack" : "Planar";
+
+	my @volts = ("TTL (5V Tolerant)", "LVTTL", "HSTL 1.5V",
+		     "SSTL 3.3V", "SSTL 2.5V", "SSTL 1.8V", "TBD");
+	printl "Voltage Interface Level", $volts[$bytes->[8]];
+
+	printl "Refresh Rate", ddr2_refresh_rate($bytes->[12]);
+
+	my @burst;
+	push @burst, 4 if ($bytes->[16] & 4);
+	push @burst, 8 if ($bytes->[16] & 8);
+	$burst[0] = 'None' if !@burst;
+	printl "Supported Burst Lengths", join(', ', @burst);
+
+	my $highestCAS = 0;
+	my %cas;
+	for ($ii = 2; $ii < 7; $ii++) {
+		if ($bytes->[18] & (1 << $ii)) {
+			$highestCAS = $ii;
+			$cas{$highestCAS}++;
+		}
+	}
+
+	my $trcd;
+	my $trp;
+	my $tras;
+
+	$trcd = ($bytes->[29] >> 2) + (($bytes->[29] & 3) * 0.25);
+	$trp = ($bytes->[27] >> 2) + (($bytes->[27] & 3) * 0.25);
+	$tras = $bytes->[30];
+
+	printl "tCL-tRCD-tRP-tRAS",
+		$highestCAS . "-" .
+		ceil($trcd/$ctime) . "-" .
+		ceil($trp/$ctime) . "-" .
+		ceil($tras/$ctime);
+
+# latencies
+	printl "Supported CAS Latencies (tCL)", cas_latencies(keys %cas);
+
+# timings
+	if (exists $cas{$highestCAS}) {
+		printl "Minimum Cycle Time at CAS $highestCAS (tCK min)",
+		       tns($ctime);
+		printl "Maximum Access Time at CAS $highestCAS (tAC)",
+		       tns(ddr2_sdram_atime($bytes->[10]));
+	}
+
+	if (exists $cas{$highestCAS-1} && spd_written(@$bytes[23..24])) {
+		printl "Minimum Cycle Time at CAS ".($highestCAS-1),
+		       tns(ddr2_sdram_ctime($bytes->[23]));
+		printl "Maximum Access Time at CAS ".($highestCAS-1),
+		       tns(ddr2_sdram_atime($bytes->[24]));
+	}
+
+	if (exists $cas{$highestCAS-2} && spd_written(@$bytes[25..26])) {
+		printl "Minimum Cycle Time at CAS ".($highestCAS-2),
+		       tns(ddr2_sdram_ctime($bytes->[25]));
+		printl "Maximum Access Time at CAS ".($highestCAS-2),
+		       tns(ddr2_sdram_atime($bytes->[26]));
+	}
+	printl "Maximum Cycle Time (tCK max)",
+	       tns(ddr2_sdram_ctime($bytes->[43]));
+
+# more timing information
+	prints("Timing Parameters");
+	printl "Address/Command Setup Time Before Clock (tIS)",
+	       tns(ddr2_sdram_atime($bytes->[32]));
+	printl "Address/Command Hold Time After Clock (tIH)",
+	       tns(ddr2_sdram_atime($bytes->[33]));
+	printl "Data Input Setup Time Before Strobe (tDS)",
+	       tns(ddr2_sdram_atime($bytes->[34]));
+	printl "Data Input Hold Time After Strobe (tDH)",
+	       tns(ddr2_sdram_atime($bytes->[35]));
+	printl "Minimum Row Precharge Delay (tRP)", tns($trp);
+	printl "Minimum Row Active to Row Active Delay (tRRD)",
+	       tns($bytes->[28]/4);
+	printl "Minimum RAS# to CAS# Delay (tRCD)", tns($trcd);
+	printl "Minimum RAS# Pulse Width (tRAS)", tns($tras);
+	printl "Write Recovery Time (tWR)", tns($bytes->[36]/4);
+	printl "Minimum Write to Read CMD Delay (tWTR)", tns($bytes->[37]/4);
+	printl "Minimum Read to Pre-charge CMD Delay (tRTP)", tns($bytes->[38]/4);
+	printl "Minimum Active to Auto-refresh Delay (tRC)",
+	       tns(ddr2_sdram_rtime($bytes->[41], 0, ($bytes->[40] >> 4) & 7));
+	printl "Minimum Recovery Delay (tRFC)",
+	       tns(ddr2_sdram_rtime($bytes->[42], $bytes->[40] & 1,
+				    ($bytes->[40] >> 1) & 7));
+	printl "Maximum DQS to DQ Skew (tDQSQ)", tns($bytes->[44]/100);
+	printl "Maximum Read Data Hold Skew (tQHS)", tns($bytes->[45]/100);
+	printl "PLL Relock Time", $bytes->[46] . " us" if ($bytes->[46]);
+}
+
+# Parameter: bytes 0-63
+sub decode_direct_rambus($)
+{
+	my $bytes = shift;
+
+#size computation
+	prints "Memory Characteristics";
+
+	my $ii;
+
+	$ii = ($bytes->[4] & 0x0f) + ($bytes->[4] >> 4) + ($bytes->[5] & 0x07) - 13;
+
+	if ($ii > 0 && $ii < 16) {
+		printl "Size", (1 << $ii) . " MB";
+	} else {
+		printl "INVALID SIZE", sprintf("0x%02x, 0x%02x",
+					       $bytes->[4], $bytes->[5]);
+	}
+}
+
+# Parameter: bytes 0-63
+sub decode_rambus($)
+{
+	my $bytes = shift;
+
+#size computation
+	prints "Memory Characteristics";
+
+	my $ii;
+
+	$ii = ($bytes->[3] & 0x0f) + ($bytes->[3] >> 4) + ($bytes->[5] & 0x07) - 13;
+
+	if ($ii > 0 && $ii < 16) {
+		printl "Size", (1 << $ii) . " MB";
+	} else {
+		printl "INVALID SIZE", sprintf("0x%02x, 0x%02x",
+					       $bytes->[3], $bytes->[5]);
+	}
+}
+
+%decode_callback = (
+	"SDR SDRAM"	=> \&decode_sdr_sdram,
+	"DDR SDRAM"	=> \&decode_ddr_sdram,
+	"DDR2 SDRAM"	=> \&decode_ddr2_sdram,
+	"Direct Rambus"	=> \&decode_direct_rambus,
+	"Rambus"	=> \&decode_rambus,
+);
+
+# Parameter: bytes 64-127
+sub decode_intel_spec_freq($)
+{
+	my $bytes = shift;
+	my ($l, $temp);
+
+	prints "Intel Specification";
+
+	$l = "Frequency";
+	if ($bytes->[62] == 0x66) { $temp = "66MHz\n"; }
+	elsif ($bytes->[62] == 100) { $temp = "100MHz or 133MHz\n"; }
+	elsif ($bytes->[62] == 133) { $temp = "133MHz\n"; }
+	else { $temp = "Undefined!\n"; }
+	printl $l, $temp;
+
+	$l = "Details for 100MHz Support";
+	$temp = "";
+	if ($bytes->[63] & 1) { $temp .= "Intel Concurrent Auto-precharge\n"; }
+	if ($bytes->[63] & 2) { $temp .= "CAS Latency = 2\n"; }
+	if ($bytes->[63] & 4) { $temp .= "CAS Latency = 3\n"; }
+	if ($bytes->[63] & 8) { $temp .= "Junction Temp A (100 degrees C)\n"; }
+	else { $temp .= "Junction Temp B (90 degrees C)\n"; }
+	if ($bytes->[63] & 16) { $temp .= "CLK 3 Connected\n"; }
+	if ($bytes->[63] & 32) { $temp .= "CLK 2 Connected\n"; }
+	if ($bytes->[63] & 64) { $temp .= "CLK 1 Connected\n"; }
+	if ($bytes->[63] & 128) { $temp .= "CLK 0 Connected\n"; }
+	if (($bytes->[63] & 192) == 192) { $temp .= "Double-sided DIMM\n"; }
+	elsif (($bytes->[63] & 192) != 0) { $temp .= "Single-sided DIMM\n"; }
+	printl $l, $temp;
+}
+
+# Read various hex dump style formats: hexdump, hexdump -C, i2cdump, eeprog
+# note that normal 'hexdump' format on a little-endian system byte-swaps
+# words, using hexdump -C is better.
+sub read_hexdump($)
+{
+	my $addr = 0;
+	my $repstart = 0;
+	my @bytes;
+	my $header = 1;
+	my $word = 0;
+
+	# Look in the cache first
+	return @{$hexdump_cache{$_[0]}} if exists $hexdump_cache{$_[0]};
+
+	open F, '<', $_[0] or die "Unable to open: $_[0]";
+	while (<F>) {
+		chomp;
+		if (/^\*$/) {
+			$repstart = $addr;
+			next;
+		}
+		/^(?:0000 )?([a-f\d]{2,8}):?\s+((:?[a-f\d]{4}\s*){8}|(:?[a-f\d]{2}\s*){16})/i ||
+		/^(?:0000 )?([a-f\d]{2,8}):?\s*$/i;
+		next if (!defined $1 && $header);		# skip leading unparsed lines
+
+		defined $1 or die "Unable to parse input";
+		$header = 0;
+
+		$addr = hex $1;
+		if ($repstart) {
+			@bytes[$repstart .. ($addr-1)] =
+				(@bytes[($repstart-16)..($repstart-1)]) x (($addr-$repstart)/16);
+			$repstart = 0;
+		}
+		last unless defined $2;
+		foreach (split(/\s+/, $2)) {
+			if (/^(..)(..)$/) {
+			        $word |= 1;
+				if ($use_hexdump eq LITTLEENDIAN) {
+					$bytes[$addr++] = hex($2);
+					$bytes[$addr++] = hex($1);
+				} else {
+					$bytes[$addr++] = hex($1);
+					$bytes[$addr++] = hex($2);
+				}
+			} else {
+				$bytes[$addr++] = hex($_);
+			}
+		}
+	}
+	close F;
+	$header and die "Unable to parse any data from hexdump '$_[0]'";
+	$word and printc "Using $use_hexdump 16-bit hex dump";
+
+	# Cache the data for later use
+	$hexdump_cache{$_[0]} = \@bytes;
+	return @bytes;
+}
+
+sub readspd64($$) # reads 64 bytes from SPD-EEPROM
+{
+	my ($offset, $dimm_i) = @_;
+	my @bytes;
+	if ($use_hexdump) {
+		@bytes = read_hexdump($dimm_i);
+		return @bytes[$offset..($offset+63)];
+	} elsif ($use_sysfs) {
+		# Kernel 2.6 with sysfs
+		sysopen(HANDLE, "/sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom", O_RDONLY)
+			or die "Cannot open /sys/bus/i2c/drivers/eeprom/$dimm_i/eeprom";
+		binmode HANDLE;
+		sysseek(HANDLE, $offset, SEEK_SET);
+		sysread(HANDLE, my $eeprom, 64);
+		close HANDLE;
+		@bytes = unpack("C64", $eeprom);
+	} else {
+		# Kernel 2.4 with procfs
+		for my $i (0 .. 3) {
+			my $hexoff = sprintf('%02x', $offset + $i * 16);
+			push @bytes, split(" ", `cat /proc/sys/dev/sensors/$dimm_i/$hexoff`);
+		}
+	}
+	return @bytes;
+}
+
+# Parse command-line
+foreach (@ARGV) {
+	if ($_ eq '-h' || $_ eq '--help') {
+		print "Usage: $0 [-c] [-f [-b]] [-x|-X file [files..]]\n",
+			"       $0 -h\n\n",
+			"  -f, --format            Print nice html output\n",
+			"  -b, --bodyonly          Don't print html header\n",
+			"                          (useful for postprocessing the output)\n",
+			"  -c, --checksum          Decode completely even if checksum fails\n",
+			"  -x,                     Read data from hexdump files\n",
+			"  -X,                     Same as -x except treat multibyte hex\n",
+			"                          data as little endian\n",
+			"  -h, --help              Display this usage summary\n";
+		print <<"EOF";
+
+Hexdumps can be the output from hexdump, hexdump -C, i2cdump, eeprog and
+likely many other progams producing hex dumps of one kind or another.  Note
+that the default output of "hexdump" will be byte-swapped on little-endian
+systems and you must use -X instead of -x, otherwise the dump will not be
+parsed correctly.  It is better to use "hexdump -C", which is not ambiguous.
+EOF
+		exit;
+	}
+
+	if ($_ eq '-f' || $_ eq '--format') {
+		$opt_html = 1;
+		next;
+	}
+	if ($_ eq '-b' || $_ eq '--bodyonly') {
+		$opt_bodyonly = 1;
+		next;
+	}
+	if ($_ eq '-c' || $_ eq '--checksum') {
+		$opt_igncheck = 1;
+		next;
+	}
+	if ($_ eq '-x') {
+		$use_hexdump = BIGENDIAN;
+		next;
+	}
+	if ($_ eq '-X') {
+		$use_hexdump = LITTLEENDIAN;
+		next;
+	}
+
+	if (m/^-/) {
+		print STDERR "Unrecognized option $_\n";
+		exit;
+	}
+
+	push @dimm_list, $_ if $use_hexdump;
+}
+
+if ($opt_html && !$opt_bodyonly) {
+	print "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+	      "<html><head>\n",
+		  "\t<meta HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">\n",
+		  "\t<title>PC DIMM Serial Presence Detect Tester/Decoder Output</title>\n",
+		  "</head><body>\n";
+}
+
+printc "decode-dimms version $revision";
+printh 'Memory Serial Presence Detect Decoder',
+'By Philip Edelbrock, Christian Zuckschwerdt, Burkart Lingner,
+Jean Delvare, Trent Piepho and others';
+
+
+my $dimm_count = 0;
+my $dir;
+if (!$use_hexdump) {
+	if ($use_sysfs) { $dir = '/sys/bus/i2c/drivers/eeprom'; }
+	else { $dir = '/proc/sys/dev/sensors'; }
+	if (-d $dir) {
+		@dimm_list = split(/\s+/, `ls $dir`);
+	} elsif (! -d '/sys/module/eeprom') {
+		print "No EEPROM found, are you sure the eeprom module is loaded?\n";
+		exit;
+	}
+}
+
+for my $i ( 0 .. $#dimm_list ) {
+	$_ = $dimm_list[$i];
+	if (($use_sysfs && /^\d+-\d+$/)
+	 || (!$use_sysfs && /^eeprom-/)
+	 || $use_hexdump) {
+		my @bytes = readspd64(0, $dimm_list[$i]);
+		my $dimm_checksum = 0;
+		$dimm_checksum += $bytes[$_] foreach (0 .. 62);
+		$dimm_checksum &= 0xff;
+
+		next unless $bytes[63] == $dimm_checksum || $opt_igncheck;
+		$dimm_count++;
+
+		print "<b><u>" if $opt_html;
+		printl2 "\n\nDecoding EEPROM",
+		        $use_hexdump ? $dimm_list[$i] : ($use_sysfs ?
+			"/sys/bus/i2c/drivers/eeprom/$dimm_list[$i]" :
+			"/proc/sys/dev/sensors/$dimm_list[$i]");
+		print "</u></b>" if $opt_html;
+		print "<table border=1>\n" if $opt_html;
+		if (!$use_hexdump) {
+			if (($use_sysfs && /^[^-]+-([^-]+)$/)
+			 || (!$use_sysfs && /^[^-]+-[^-]+-[^-]+-([^-]+)$/)) {
+				my $dimm_num = $1 - 49;
+				printl "Guessing DIMM is in", "bank $dimm_num";
+			}
+		}
+
+# Decode first 3 bytes (0-2)
+		prints "SPD EEPROM Information";
+
+		my $l = "EEPROM Checksum of bytes 0-62";
+		printl $l, ($bytes[63] == $dimm_checksum ?
+			sprintf("OK (0x%.2X)", $bytes[63]):
+			sprintf("Bad\n(found 0x%.2X, calculated 0x%.2X)\n",
+				$bytes[63], $dimm_checksum));
+
+		# Simple heuristic to detect Rambus
+		my $is_rambus = $bytes[0] < 4;
+		my $temp;
+		if ($is_rambus) {
+			if ($bytes[0] == 1) { $temp = "0.7"; }
+			elsif ($bytes[0] == 2) { $temp = "1.0"; }
+			elsif ($bytes[0] == 0 || $bytes[0] == 255) { $temp = "Invalid"; }
+			else { $temp = "Reserved"; }
+			printl "SPD Revision", $temp;
+		} else {
+			printl "# of bytes written to SDRAM EEPROM",
+			       $bytes[0];
+		}
+
+		$l = "Total number of bytes in EEPROM";
+		if ($bytes[1] <= 14) {
+			printl $l, 2**$bytes[1];
+		} elsif ($bytes[1] == 0) {
+			printl $l, "RFU";
+		} else { printl $l, "ERROR!"; }
+
+		$l = "Fundamental Memory type";
+		my $type = "Unknown";
+		if ($is_rambus) {
+			if ($bytes[2] == 1) { $type = "Direct Rambus"; }
+			elsif ($bytes[2] == 17) { $type = "Rambus"; }
+		} else {
+			if ($bytes[2] == 1) { $type = "FPM DRAM"; }
+			elsif ($bytes[2] == 2) { $type = "EDO"; }
+			elsif ($bytes[2] == 3) { $type = "Pipelined Nibble"; }
+			elsif ($bytes[2] == 4) { $type = "SDR SDRAM"; }
+			elsif ($bytes[2] == 5) { $type = "Multiplexed ROM"; }
+			elsif ($bytes[2] == 6) { $type = "DDR SGRAM"; }
+			elsif ($bytes[2] == 7) { $type = "DDR SDRAM"; }
+			elsif ($bytes[2] == 8) { $type = "DDR2 SDRAM"; }
+		}
+		printl $l, $type;
+
+# Decode next 61 bytes (3-63, depend on memory type)
+		$decode_callback{$type}->(\@bytes)
+			if exists $decode_callback{$type};
+
+# Decode next 35 bytes (64-98, common to all memory types)
+		prints "Manufacturing Information";
+
+		@bytes = readspd64(64, $dimm_list[$i]);
+
+		$l = "Manufacturer";
+		# $extra is a reference to an array containing up to
+		# 7 extra bytes from the Manufacturer field. Sometimes
+		# these bytes are filled with interesting data.
+		($temp, my $extra) = manufacturer(@bytes[0..7]);
+		printl $l, $temp;
+		$l = "Custom Manufacturer Data";
+		$temp = manufacturer_data(@{$extra});
+		printl $l, $temp if defined $temp;
+
+		if (spd_written($bytes[8])) {
+			# Try the location code as ASCII first, as earlier specifications
+			# suggested this. As newer specifications don't mention it anymore,
+			# we still fall back to binary.
+			$l = "Manufacturing Location Code";
+			$temp = (chr($bytes[8]) =~ m/^[\w\d]$/) ? chr($bytes[8])
+			      : sprintf("0x%.2X", $bytes[8]);
+			printl $l, $temp;
+		}
+
+		$l = "Part Number";
+		$temp = part_number(@bytes[9..26]);
+		printl $l, $temp;
+
+		if (spd_written(@bytes[27..28])) {
+			$l = "Revision Code";
+			$temp = sprintf("0x%02X%02X\n", @bytes[27..28]);
+			printl $l, $temp;
+		}
+
+		if (spd_written(@bytes[29..30])) {
+			$l = "Manufacturing Date";
+			# In theory the year and week are in BCD format, but
+			# this is not always true in practice :(
+			if (($bytes[29] & 0xf0) <= 0x90
+			 && ($bytes[29] & 0x0f) <= 0x09
+			 && ($bytes[30] & 0xf0) <= 0x90
+			 && ($bytes[30] & 0x0f) <= 0x09) {
+				# Note that this heuristic will break in year 2080
+				$temp = sprintf("%d%02X-W%02X\n",
+						$bytes[29] >= 0x80 ? 19 : 20,
+						@bytes[29..30]);
+			} else {
+				$temp = sprintf("0x%02X%02X\n",
+						@bytes[29..30]);
+			}
+			printl $l, $temp;
+		}
+
+		if (spd_written(@bytes[31..34])) {
+			$l = "Assembly Serial Number";
+			$temp = sprintf("0x%02X%02X%02X%02X\n",
+					@bytes[31..34]);
+			printl $l, $temp;
+		}
+
+# Next 27 bytes (99-125) are manufacturer specific, can't decode
+
+# Last 2 bytes (126-127) are reserved, Intel used them as an extension
+		if ($type eq "SDR SDRAM") {
+			decode_intel_spec_freq(\@bytes);
+		}
+
+		print "</table>\n" if $opt_html;
+	}
+}
+printl2 "\n\nNumber of SDRAM DIMMs detected and decoded", $dimm_count;
+
+print "</body></html>\n" if ($opt_html && !$opt_bodyonly);
diff --git a/i2c-tools-3.0.2/eeprom/decode-edid b/i2c-tools-3.0.2/eeprom/decode-edid
new file mode 100755
index 0000000..15ba1a4
--- /dev/null
+++ b/i2c-tools-3.0.2/eeprom/decode-edid
@@ -0,0 +1,225 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2003-2006 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.
+#
+# Version 0.1  2003-07-17  Jean Delvare <khali@linux-fr.org>
+# Version 0.2  2003-07-22  Jean Delvare <khali@linux-fr.org>
+#  Use print instead of syswrite.
+# Version 0.3  2003-08-24  Jean Delvare <khali@linux-fr.org>
+#  Fix data block length (128 bytes instead of 256).
+# Version 1.0  2004-02-08  Jean Delvare <khali@linux-fr.org>
+#  Added support for Linux 2.5/2.6 (i.e. sysfs).
+# Version 1.1  2006-09-01  Jean Delvare <khali@linux-fr.org>
+#  Append /usr/sbin or /usr/local/sbin to $PATH if needed.
+#
+# EEPROM data decoding for EDID. EDID (Extended Display Identification
+# Data) is a VESA standard which allows storing (on manufacturer's side)
+# and retrieving (on user's side) of configuration information about
+# displays, such as manufacturer, serial number, physical dimensions and
+# allowed horizontal and vertical refresh rates.
+#
+# Using the eeprom kernel driver, you have two possibilities to
+# make use of these data:
+#  1* The ddcmon script.
+#  2* This script.
+# Both solutions will return a different kind of information. The first
+# method will report user-interesting information, such as the model number
+# or the year of manufacturing. The second method will report video-card-
+# interesting information, such as video modes and refresh rates.
+#
+# Note that this script does almost nothing by itself. It simply converts
+# what it finds in /proc to binary data to feed the parse-edid program.
+# The parse-edid program was written by John Fremlin and is available at
+# the following address:
+#   http://john.fremlin.de/programs/linux/read-edid/
+
+use strict;
+use Fcntl qw(:DEFAULT :seek);
+use vars qw($bus $address);
+use constant PROCFS => 1;
+use constant SYSFS  => 2;
+
+# parse-edid will typically be installed in /usr/sbin or /usr/local/sbin
+# even though regular users can run it
+$ENV{PATH} .= ':/usr/local/sbin'
+	if $ENV{PATH} !~ m,(^|:)/usr/local/sbin/?(:|$),
+	&& -x '/usr/local/sbin/parse-edid';
+$ENV{PATH} .= ':/usr/sbin'
+	if $ENV{PATH} !~ m,(^|:)/usr/sbin/?(:|$),
+	&& -x '/usr/sbin/parse-edid';
+
+sub edid_valid_procfs
+{
+	my ($bus, $addr) = @_;
+
+	open EEDATA, "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/00";
+	my $line = <EEDATA>;
+	close EEDATA;
+	return 1
+		if $line =~ m/^0 255 255 255 255 255 255 0 /;
+	return 0;
+}
+
+# Only used for sysfs
+sub rawread
+{
+	my ($filename, $length, $offset) = @_;
+	my $bytes = '';
+	
+	sysopen(FH, $filename, O_RDONLY)
+		or die "Can't open $filename";
+	if ($offset)
+	{
+		sysseek(FH, $offset, SEEK_SET)
+			or die "Can't seek in $filename";
+	}
+
+	$offset = 0;
+	while ($length)
+	{
+		my $r = sysread(FH, $bytes, $length, $offset);
+		die "Can't read $filename"
+			unless defined($r);
+		die "Unexpected EOF in $filename"
+			unless $r;
+		$offset += $r;
+		$length -= $r;
+	}
+	close(FH);
+
+	return $bytes;
+}
+
+sub edid_valid_sysfs
+{
+	my ($bus, $addr) = @_;
+	my $bytes = rawread("/sys/bus/i2c/devices/$bus-00$addr/eeprom", 8, 0);
+
+	return 1
+		if $bytes eq "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00";
+	return 0;
+}
+
+sub bus_detect
+{
+	my $max = shift;
+
+	for (my $i=0; $i<$max; $i++)
+	{
+		if (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-50/00")
+		{
+			if (edid_valid_procfs($i, '50'))
+			{
+				print STDERR
+					"decode-edid: using bus $i (autodetected)\n";
+				return $i;
+			}
+		}
+		elsif (-r "/sys/bus/i2c/devices/$i-0050/eeprom")
+		{
+			if (edid_valid_sysfs($i, '50'))
+			{
+				print STDERR
+					"decode-edid: using bus $i (autodetected)\n";
+				return $i;
+			}
+		}	
+	}
+	
+	return; # default
+}
+
+sub edid_decode
+{
+	my ($bus, $addr, $mode) = @_;
+
+	# Make sure it is an EDID EEPROM.
+
+	unless (($mode == PROCFS && edid_valid_procfs ($bus, $addr))
+	     || ($mode == SYSFS  && edid_valid_sysfs  ($bus, $addr)))
+	{
+		print STDERR
+			"decode-edid: not an EDID EEPROM at $bus-$addr\n";
+		return;
+	}
+
+	$SIG{__WARN__} = sub { };
+	open PIPE, "| parse-edid"
+		or die "Can't open parse-edid. Please install read-edid.\n";
+	delete $SIG{__WARN__};
+	binmode PIPE;
+	
+	if ($mode == PROCFS)
+	{
+		for (my $i=0; $i<=0x70; $i+=0x10)
+		{
+			my $file = sprintf '%02x', $i;
+			my $output = '';
+			open EEDATA, "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/$file"
+				or die "Can't read /proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/$file";
+			while(<EEDATA>)
+			{
+				foreach my $item (split)
+				{
+					$output .= pack "C", $item;
+				}
+			}
+			close EEDATA;
+			print PIPE $output;
+		}
+	}
+	elsif ($mode == SYSFS)
+	{
+		print PIPE rawread("/sys/bus/i2c/devices/$bus-00$address/eeprom", 128, 0);
+	}
+
+	close PIPE;
+}
+
+# Get the address. Default to 0x50 if not given.
+$address = $ARGV[1] || 0x50;
+# Convert to decimal, whatever the value.
+$address = oct $address if $address =~ m/^0/;
+# Convert to an hexadecimal string.
+$address = sprintf '%02x', $address;
+
+# Get the bus. Try to autodetect if not given.
+$bus = $ARGV[0] if defined $ARGV[0];
+$bus = bus_detect(8) unless defined $bus;
+
+if(defined $bus)
+{
+	print STDERR
+		"decode-edid: decode-edid version 1.1\n";
+	if (-r "/proc/sys/dev/sensors/eeprom-i2c-$bus-$address")
+	{
+		edid_decode ($bus, $address, PROCFS);
+		exit 0;
+	}
+	elsif (-r "/sys/bus/i2c/devices/$bus-00$address")
+	{
+		edid_decode ($bus, $address, SYSFS);
+		exit 0;
+	}
+}
+
+print STDERR
+	"EDID EEPROM not found.  Please make sure that the eeprom module is loaded.\n";
+print STDERR
+	"Maybe your EDID EEPROM is on another bus.  Try \"decode-edid ".($bus+1)."\".\n"
+	if defined $bus;
diff --git a/i2c-tools-3.0.2/eeprom/decode-vaio b/i2c-tools-3.0.2/eeprom/decode-vaio
new file mode 100755
index 0000000..2631170
--- /dev/null
+++ b/i2c-tools-3.0.2/eeprom/decode-vaio
@@ -0,0 +1,237 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2002-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.
+#
+# EEPROM data decoding for Sony Vaio laptops. 
+#
+# The eeprom driver must be loaded. For kernels older than 2.6.0, the
+# eeprom driver can be found in the lm-sensors package.
+#
+# Please note that this is a guess-only work.  Sony support refused to help
+# me, so if someone can provide information, please contact me.
+# My knowledge is summarized on this page:
+# http://khali.linux-fr.org/vaio/eeprom.html
+#
+# It seems that if present, the EEPROM is always at 0x57.
+#
+# Models tested so far:
+#   PCG-F403     : No EEPROM
+#   PCG-F707     : No EEPROM
+#   PCG-GR114EK  : OK
+#   PCG-GR114SK  : OK
+#   PCG-GR214EP  : OK
+#   PCG-GRT955MP : OK
+#   PCG-GRX316G  : OK
+#   PCG-GRX570   : OK
+#   PCG-GRX600K  : OK
+#   PCG-U1       : OK
+#   PCG-Z600LEK  : No EEPROM
+#   PCG-Z600NE   : No EEPROM
+#   VGN-S260     : OK
+#   VGN-S4M/S    : OK
+#   VGN-TZ11MN/N : OK
+#
+# Thanks to Werner Heuser, Carsten Blume, Christian Gennerat, Joe Wreschnig,
+# Xavier Roche, Sebastien Lefevre, Lars Heer, Steve Dobson, Kent Hunt,
+# Timo Hoenig and others for their precious help.
+
+
+use strict;
+use Fcntl qw(:DEFAULT :seek);
+use vars qw($sysfs $found);
+
+use constant VERSION	=> "1.6";
+use constant ONLYROOT	=> "Readable only by root";
+
+sub print_item
+{
+	my ($label,$value) = @_;
+	
+	printf("\%16s : \%s\n",$label,$value);
+}
+
+# Abstract reads so that other functions don't have to care wether
+# we need to use procfs or sysfs
+sub read_eeprom_bytes
+{
+	my ($bus, $addr, $offset, $length) = @_;
+	my $filename;
+	
+	if ($sysfs)
+	{
+		$filename = "/sys/bus/i2c/devices/$bus-00$addr/eeprom";
+		sysopen(FH, $filename, O_RDONLY)
+			or die "Can't open $filename";
+		sysseek(FH, $offset, SEEK_SET)
+			or die "Can't seek in $filename";
+
+		my ($r, $bytes);
+		$bytes = '';
+		$offset = 0;
+		while($length)
+		{
+			$r = sysread(FH, $bytes, $length, $offset);
+			die "Can't read $filename"
+				unless defined($r);
+			die "Unexpected EOF in $filename"
+				unless $r;
+			$offset += $r;
+			$length -= $r;
+		}
+		close(FH);
+		
+		return $bytes;
+	}
+	else
+	{
+		my $base = $offset & 0xf0;
+		$offset -= $base;
+		my $values = '';
+		my $remains = $length + $offset;
+		
+		# Get all lines in a single string
+		while ($remains > 0)
+		{
+			$filename = "/proc/sys/dev/sensors/eeprom-i2c-$bus-$addr/"
+			          . sprintf('%02x', $base);
+			open(FH, $filename)
+				or die "Can't open $filename";
+			$values .= <FH>;
+			close(FH);
+			$remains -= 16;
+			$base += 16;
+		}
+		
+		# Store the useful part in an array
+		my @bytes = split(/[ \n]/, $values);
+		@bytes = @bytes[$offset..$offset+$length-1];
+
+		# Back to a binary string
+		return pack('C*', @bytes);
+	}
+}
+
+sub decode_string
+{
+	my ($bus, $addr, $offset, $length) = @_;
+
+	my $string = read_eeprom_bytes($bus, $addr, $offset, $length);
+	$string =~ s/\x00.*$//;
+	
+	return($string);
+}
+
+sub decode_hexa
+{
+	my ($bus, $addr, $offset, $length) = @_;
+
+	my @bytes = unpack('C*', read_eeprom_bytes($bus, $addr, $offset, $length));
+	my $string='';
+
+	for(my $i=0;$i<$length;$i++)
+	{
+		$string.=sprintf('%02X', shift(@bytes));
+	}
+
+	return($string);
+}
+
+sub decode_uuid
+{
+	my ($bus,$addr,$base) = @_;
+
+	my @bytes = unpack('C16', read_eeprom_bytes($bus, $addr, $base, 16));
+	my $string='';
+
+	for(my $i=0;$i<16;$i++)
+	{
+		$string.=sprintf('%02x',shift(@bytes));
+		if(($i==3)||($i==5)||($i==7)||($i==9))
+		{
+			$string.='-';
+		}
+	}
+
+	if ($string eq '00000000-0000-0000-0000-000000000000')
+	{
+		return(ONLYROOT);
+	}
+	else
+	{
+		return($string);
+	}
+}
+
+sub vaio_decode
+{
+	my ($bus,$addr) = @_;
+	
+	my $name = decode_string($bus, $addr, 128, 32);
+	# Simple heuristic to skip false positives
+	return 0 unless $name =~ m/^[A-Z-]{4}/;
+
+	print_item('Machine Name', $name);
+	my $serial = decode_string($bus, $addr, 192, 32);
+	print_item('Serial Number', $serial ? $serial : ONLYROOT);
+	print_item('UUID', decode_uuid($bus, $addr, 16));
+	my $revision = decode_string($bus, $addr, 160, 10);
+	print_item(length($revision) > 2 ? 'Service Tag' : 'Revision',
+		   $revision);
+	print_item('Asset Tag', decode_string($bus, $addr, 170, 4).
+				decode_hexa($bus, $addr, 174, 12));
+	print_item('OEM Data', decode_string($bus, $addr, 32, 16));
+	print_item('Timestamp', decode_string($bus, $addr, 224, 18));
+	return 1;
+}
+
+BEGIN
+{
+	print("# Sony Vaio EEPROM Decoder version ".VERSION." by Jean Delvare\n\n");
+}
+
+END
+{
+	print("\n");
+}
+
+for (my $i = 0, $found=0; $i <= 4 && !$found; $i++)
+{
+	if (-r "/sys/bus/i2c/devices/$i-0057/eeprom")
+	{
+		$sysfs = 1;
+		$found += vaio_decode($i, '57');
+	}
+	elsif (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57")
+	{
+		if (-r "/proc/sys/dev/sensors/eeprom-i2c-$i-57/data0-15")
+		{
+			print("Deprecated old interface found.  Please upgrade to lm_sensors 2.6.3 or greater.");
+			exit;
+		}
+		else
+		{
+			$sysfs = 0;
+			$found += vaio_decode($i, '57');
+		}
+	}
+}
+
+if (!$found)
+{
+	print("Vaio EEPROM not found.  Please make sure that the eeprom module is loaded.\n");
+}
diff --git a/i2c-tools-3.0.2/eeprom/decode-xeon b/i2c-tools-3.0.2/eeprom/decode-xeon
new file mode 100755
index 0000000..8a400b9
--- /dev/null
+++ b/i2c-tools-3.0.2/eeprom/decode-xeon
@@ -0,0 +1,197 @@
+#!/usr/bin/perl
+#
+# Copyright 1998, 1999 Philip Edelbrock <phil@netroedge.com>
+# and Mark Studebaker <mdsxyz123@yahoo.com>
+#
+# Version 0.1
+#
+#
+# ID ROM data decoding for Xeon processors. 
+# Each Xeon processor contains two memories:
+#	- A scratch EEPROM at an even location 0x50, 52, 54, or 56;
+#	- An ID ROM at an odd location 0x51, 53, 55, or 57.
+# This program decodes the ID ROM's only.
+# The scratch EEPROMs have no prescribed format.
+# If the output of this program makes no sense for a particular device,
+# it is probably decoding a DIMM Serial Presence Detect (SPD) EEPROM.
+# See decode-dimms to decode those devices.
+#
+#
+# The eeprom driver must be loaded. For kernels older than 2.6.0, the
+# eeprom driver can be found in the lm-sensors package.
+#
+# To do:
+#	Calculate and check checksums for each section
+#	Decode flags in byte 0x7B (cartridge feature flags)
+#
+# References: 
+# "Pentium II Xeon Processor at 400 and 450 MHz" Data Sheet
+# Intel 
+#
+#
+#
+
+print "Xeon Processor Information ROM Decoder\n";
+print "Written by Philip Edelbrock and Mark Studebaker.  Copyright 1998, 1999.\n";
+print "Version 2.6.3\n\n";
+
+$dimm_count=0;
+$_=`ls /proc/sys/dev/sensors/`;
+@dimm_list=split();
+
+for $i ( 0 .. $#dimm_list ) {
+	$_=$dimm_list[$i];
+	if ((/^eeprom-/) && (/-51$/ || /-53$/ || /-55$/ || /-57$/)) {
+		$dimm_count=$dimm_count + 1;
+		
+		print "\nDecoding Xeon ROM: /proc/sys/dev/sensors/$dimm_list[$i]\n";
+		if (/^[^-]+-[^-]+-[^-]+-([^-]+)$/) {
+			$dimm_num=($1 - 49) / 2;
+			print "Guessing Xeon is number $dimm_num\n";
+		}
+# Decode first 16 bytes
+		print "\t\t----=== Xeon ROM Header Data ===----\n";
+
+		$_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/00`;
+		@bytes=split(" ");
+		
+		printf("\tData Format Revision: \t\t\t\t0x%.4X\n", $bytes[0]);
+
+		print "\tTotal number of bytes in EEPROM:\t\t";
+		print ($bytes[1] << 4) + $bytes[2];
+		print "\n";
+
+		printf("\tProcessor Data Address:\t\t\t\t0x%.2X\n", $bytes[3]);
+		printf("\tProcessor Core Data Address:\t\t\t0x%.2X\n", $bytes[4]);
+		printf("\tL2 Cache Data Address:\t\t\t\t0x%.2X\n", $bytes[5]);
+		printf("\tSEC Cartridge Data Address:\t\t\t0x%.2X\n", $bytes[6]);
+		printf("\tPart Number Data Address:\t\t\t0x%.2X\n", $bytes[7]);
+		printf("\tThermal Reference Data Address:\t\t\t0x%.2X\n", $bytes[8]);
+		printf("\tFeature Data Address:\t\t\t\t0x%.2X\n", $bytes[9]);
+		printf("\tOther Data Address:\t\t\t\t0x%.2X\n", $bytes[10]);
+		
+		print "\t\t----=== Xeon ROM Processor Data ===----\n";
+		
+# Decode next 16 bytes
+		$_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/10`;
+		@bbytes=split(" ");
+	      	print "\tS-spec/QDF Number:\t\t\t\t\"";
+		print pack("cccccc",$bytes[14],$bytes[15],$bbytes[0],
+    				    $bbytes[1],$bbytes[2],$bbytes[3]);
+		print "\"\n";
+		$tmp =  $bbytes[4] & 0xC0 >> 6;
+		printf("\tSample / Production:\t\t\t\t0x%.2X", $tmp);
+		if($tmp) {
+			print " (Production)\n";
+		} else {
+			print " (Sample)\n";
+		}
+
+		print "\t\t----=== Xeon ROM Core Data ===----\n";
+		
+		printf("\tProcessor Core Type:\t\t\t\t0x%.2X\n",
+			($bbytes[6] & 0xC0) >> 6);
+		printf("\tProcessor Core Family:\t\t\t\t0x%.2X\n",
+			($bbytes[6] & 0x3C) >> 2);
+		printf("\tProcessor Core Model:\t\t\t\t0x%.2X\n",
+			(($bbytes[6] & 0x03) << 2) + (($bbytes[7] & 0xC0) >> 6));
+		printf("\tProcessor Core Stepping:\t\t\t0x%.2X\n",
+			($bbytes[7] & 0x30) >> 4);
+		print "\tMaximum Core Frequency (Mhz):\t\t\t";
+		print ($bbytes[13] << 4) + $bbytes[14];
+		print "\n";
+		
+# Decode next 16 bytes (32-47)
+		$_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/20`;
+		@bytes=split(" ");
+		print "\tCore Voltage ID (mV):\t\t\t\t";
+		print ($bbytes[15] << 4) + $bytes[0];
+		print "\n";
+		print "\tCore Voltage Tolerance, High (mV):\t\t";
+		print $bytes[1];
+		print "\n";
+		print "\tCore Voltage Tolerance, Low (mV):\t\t";
+		print $bytes[2];
+		print "\n";
+
+		print "\t\t----=== Xeon ROM L2 Cache Data ===----\n";
+		
+		print "\tL2 Cache Size (KB):\t\t\t\t";
+		print ($bytes[9] << 4) + $bytes[10];
+		print "\n";
+		printf("\tNumber of SRAM Components:\t\t\t%d\n",
+			($bytes[11] & 0xF0) >> 4);
+		print "\tL2 Cache Voltage ID (mV):\t\t\t";
+		print ($bytes[12] << 4) + $bytes[13];
+		print "\n";
+		print "\tL2 Cache Voltage Tolerance, High (mV):\t\t";
+		print $bytes[14];
+		print "\n";
+		print "\tL2 Cache Voltage Tolerance, Low (mV):\t\t";
+		print $bytes[15];
+		print "\n";
+
+# Decode next 16 bytes (48-63)
+		$_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/30`;
+		@bytes=split(" ");
+
+		printf("\tCache/Tag Stepping ID:\t\t\t\t0x%.2X\n",
+			($bytes[0] & 0xF0) >> 4);
+
+		print "\t\t----=== Xeon ROM Cartridge Data ===----\n";
+
+	      	print "\tCartridge Revision:\t\t\t\t\"";
+		print pack("cccc",$bytes[2],$bytes[3],$bytes[4],$bytes[5]);
+		print "\"\n";
+		printf("\tSubstrate Rev. Software ID:\t\t\t0x%.2X\n",
+			($bbytes[6] & 0xC0) >> 6);
+
+		print "\t\t----=== Xeon ROM Part Number Data ===----\n";
+
+	      	print "\tProcessor Part Number:\t\t\t\t\"";
+		print pack("ccccccc",$bytes[8],$bytes[9],$bytes[10],
+  			    $bytes[11],$bytes[12],$bytes[13],$bytes[14]);
+		print "\"\n";
+		$byte15=$byte[15];
+
+# Decode next 16 bytes (64-79)
+		$_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/40`;
+		@bytes=split(" ");
+
+	      	print "\tProcessor BOM ID:\t\t\t\t\"";
+		print pack("cccccccccccccc",$byte15,$bytes[0],$bytes[1],
+			$bytes[2],$bytes[3],$bytes[4],$bytes[5],$bytes[6],
+			$bytes[7],$bytes[8],$bytes[9],$bytes[10],$bytes[11],
+			$bytes[12]);
+		print "\"\n";
+
+# Decode next 16 bytes (80-95)
+		$_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/50`;
+		@bbytes=split(" ");
+		printf("\tProcessor Electronic Signature: \t\t0x%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X\n",
+			$bytes[13],$bytes[14],$bytes[15],$bbytes[0],
+			$bbytes[1],$bbytes[2],$bbytes[3],$bbytes[4]);
+
+# Decode next 16 bytes (96-111)
+# Not used...   
+
+# Decode next 16 bytes (112-127)
+		$_=`cat /proc/sys/dev/sensors/$dimm_list[$i]/70`;
+		@bytes=split(" ");
+		
+		print "\t\t----=== Xeon Thermal Reference Data ===----\n";
+
+		printf("\tThermal Reference Byte: \t\t\t0x%.2X\n", $bytes[0]);
+
+		print "\t\t----=== Xeon ROM Feature Data ===----\n";
+
+		printf("\tProcessor Core Feature Flags: \t\t\t0x%.2X%.2X%.2X%.2X\n",
+			$bytes[4],$bytes[5],$bytes[6],$bytes[7]);
+		printf("\tCartridge Feature Flags: \t\t\t0x%.2X%.2X%.2X%.2X\n",
+			$bytes[8],$bytes[9],$bytes[10],$bytes[11]);
+		printf("\tNumber of Devices in TAP Chain:\t\t\t%d\n",
+			($bytes[12] & 0xF0) >> 4);
+		
+	}
+}
+print "\n\nNumber of Xeon ROMs detected and decoded: $dimm_count\n";
diff --git a/i2c-tools-3.0.2/eepromer/24cXX.c b/i2c-tools-3.0.2/eepromer/24cXX.c
new file mode 100644
index 0000000..134e5a1
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/24cXX.c
@@ -0,0 +1,182 @@
+/***************************************************************************
+    copyright            : (C) by 2002-2003 Stefano Barbato
+    email                : stefano@codesink.org
+
+    $Id: 24cXX.c 4230 2006-11-10 09:22:12Z khali $
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include "24cXX.h"
+
+static int i2c_write_1b(struct eeprom *e, __u8 buf)
+{
+	int r;
+	// we must simulate a plain I2C byte write with SMBus functions
+	r = i2c_smbus_write_byte(e->fd, buf);
+	if(r < 0)
+		fprintf(stderr, "Error i2c_write_1b: %s\n", strerror(errno));
+	usleep(10);
+	return r;
+}
+
+static int i2c_write_2b(struct eeprom *e, __u8 buf[2])
+{
+	int r;
+	// we must simulate a plain I2C byte write with SMBus functions
+	r = i2c_smbus_write_byte_data(e->fd, buf[0], buf[1]);
+	if(r < 0)
+		fprintf(stderr, "Error i2c_write_2b: %s\n", strerror(errno));
+	usleep(10);
+	return r;
+}
+
+static int i2c_write_3b(struct eeprom *e, __u8 buf[3])
+{
+	int r;
+	// we must simulate a plain I2C byte write with SMBus functions
+	// the __u16 data field will be byte swapped by the SMBus protocol
+	r = i2c_smbus_write_word_data(e->fd, buf[0], buf[2] << 8 | buf[1]);
+	if(r < 0)
+		fprintf(stderr, "Error i2c_write_3b: %s\n", strerror(errno));
+	usleep(10);
+	return r;
+}
+
+
+#define CHECK_I2C_FUNC( var, label ) \
+	do { 	if(0 == (var & label)) { \
+		fprintf(stderr, "\nError: " \
+			#label " function is required. Program halted.\n\n"); \
+		exit(1); } \
+	} while(0);
+
+int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom* e)
+{
+	int fd, r;
+	unsigned long funcs;
+	e->fd = e->addr = 0;
+	e->dev = 0;
+	
+	fd = open(dev_fqn, O_RDWR);
+	if(fd <= 0)
+		return -1;
+
+	// get funcs list
+	if((r = ioctl(fd, I2C_FUNCS, &funcs) < 0))
+		return r;
+
+	
+	// check for req funcs
+	CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE );
+	CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE );
+	CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE_DATA );
+	CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE_DATA );
+	CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_WORD_DATA );
+	CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_WORD_DATA );
+
+	// set working device
+	if( ( r = ioctl(fd, I2C_SLAVE, addr)) < 0)
+		return r;
+	e->fd = fd;
+	e->addr = addr;
+	e->dev = dev_fqn;
+	e->type = type;
+	return 0;
+}
+
+int eeprom_close(struct eeprom *e)
+{
+	close(e->fd);
+	e->fd = -1;
+	e->dev = 0;
+	e->type = EEPROM_TYPE_UNKNOWN;
+	return 0;
+}
+
+#if 0
+int eeprom_24c32_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
+{
+	__u8 buf[3] = { (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
+	return i2c_write_3b(e, buf);
+}
+
+
+int eeprom_24c32_read_current_byte(struct eeprom* e)
+{
+	ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
+	return i2c_smbus_read_byte(e->fd);
+}
+
+int eeprom_24c32_read_byte(struct eeprom* e, __u16 mem_addr)
+{
+	int r;
+	ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
+	__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
+	r = i2c_write_2b(e, buf);
+	if (r < 0)
+		return r;
+	r = i2c_smbus_read_byte(e->fd);
+	return r;
+}
+#endif
+
+
+int eeprom_read_current_byte(struct eeprom* e)
+{
+	ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
+	return i2c_smbus_read_byte(e->fd);
+}
+
+int eeprom_read_byte(struct eeprom* e, __u16 mem_addr)
+{
+	int r;
+	ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
+	if(e->type == EEPROM_TYPE_8BIT_ADDR)
+	{
+		__u8 buf =  mem_addr & 0x0ff;
+		r = i2c_write_1b(e, buf);
+	} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
+		__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
+		r = i2c_write_2b(e, buf);
+	} else {
+		fprintf(stderr, "ERR: unknown eeprom type\n");
+		return -1;
+	}
+	if (r < 0)
+		return r;
+	r = i2c_smbus_read_byte(e->fd);
+	return r;
+}
+
+int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
+{
+	if(e->type == EEPROM_TYPE_8BIT_ADDR) {
+		__u8 buf[2] = { mem_addr & 0x00ff, data };
+		return i2c_write_2b(e, buf);
+	} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
+		__u8 buf[3] = 
+			{ (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
+		return i2c_write_3b(e, buf);
+	} else {
+		fprintf(stderr, "ERR: unknown eeprom type\n");
+		return -1;
+	}
+}
+
diff --git a/i2c-tools-3.0.2/eepromer/24cXX.h b/i2c-tools-3.0.2/eepromer/24cXX.h
new file mode 100644
index 0000000..3b3b3a2
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/24cXX.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+    copyright            : (C) by 2002-2003 Stefano Barbato
+    email                : stefano@codesink.org
+
+    $Id: 24cXX.h 4495 2007-06-27 12:57:50Z khali $
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+#ifndef _24CXX_H_
+#define _24CXX_H_
+#include <linux/i2c-dev.h>
+
+#define EEPROM_TYPE_UNKNOWN	0
+#define EEPROM_TYPE_8BIT_ADDR	1
+#define EEPROM_TYPE_16BIT_ADDR 	2
+
+struct eeprom
+{
+	char *dev; 	// device file i.e. /dev/i2c-N
+	int addr;	// i2c address
+	int fd;		// file descriptor
+	int type; 	// eeprom type
+};
+
+/*
+ * opens the eeprom device at [dev_fqn] (i.e. /dev/i2c-N) whose address is
+ * [addr] and set the eeprom_24c32 [e]
+ */
+int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom*);
+/*
+ * closees the eeprom device [e] 
+ */
+int eeprom_close(struct eeprom *e);
+/*
+ * read and returns the eeprom byte at memory address [mem_addr] 
+ * Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address) 
+ */
+int eeprom_read_byte(struct eeprom* e, __u16 mem_addr);
+/*
+ * read the current byte
+ * Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address) 
+ */
+int eeprom_read_current_byte(struct eeprom *e);
+/*
+ * writes [data] at memory address [mem_addr] 
+ * Note: eeprom must have been selected by ioctl(fd,I2C_SLAVE,address) 
+ */
+int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data);
+
+#endif
+
diff --git a/i2c-tools-3.0.2/eepromer/Makefile b/i2c-tools-3.0.2/eepromer/Makefile
new file mode 100644
index 0000000..4893f97
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/Makefile
@@ -0,0 +1,14 @@
+#eepromer  Makefile
+
+CFLAGS = -O2 -I../include -Wall
+
+all:  eepromer eeprom eeprog
+
+eepromer:  eepromer.o
+
+eeprom:  eeprom.o
+
+eeprog: eeprog.o 24cXX.o
+
+clean:
+	rm -rf *~ *.o eepromer eeprom eeprog
diff --git a/i2c-tools-3.0.2/eepromer/README b/i2c-tools-3.0.2/eepromer/README
new file mode 100644
index 0000000..ff89c73
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/README
@@ -0,0 +1,31 @@
+These programs are used to read and write eeproms.
+
+Use eeprom for small eeproms with one-byte addresses:
+	24C01, 24C01A, 24C02, 24C04, 24C08, and 24C16
+	It works only on true i2c bus adapters.
+	See README.eeprom for details.
+
+Use eepromer for large eeproms with two-byte addresses:
+	24C32, 24C64, 24C128, 24C256, and 24C512
+	It works only on true i2c bus adapters.
+	See README.eepromer for details.
+
+Use eeprog for either small or large eeproms.
+	Use the -16 switch for large eeproms.
+	It works on both i2c and smbus bus adapters.
+	See README.eeprog for details.
+
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!                                                                           !
+!!! These programs should only be used on external busses such as i2c-pport   !
+!!! unless you REALLY know what you are doing.                                !
+!!!                                                                           !
+!!! Your computer probably contains eeproms for saving data vital to its      !
+!!! operation. If you are not careful you might overwrite this data with      !
+!!! this program and your computer may no longer boot!                        !
+!!!                                                                           !
+!!! An example are the EEPROMS on your SDRAM DIMMs, your computer may no      !
+!!! longer detect the RAM module rendering it essentially USELESS!            !
+!!!                                                                           !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/i2c-tools-3.0.2/eepromer/README.eeprog b/i2c-tools-3.0.2/eepromer/README.eeprog
new file mode 100644
index 0000000..6cccd00
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/README.eeprog
@@ -0,0 +1,12 @@
+Important! See the README file for important warnings.
+
+eeprog reads and writes 24Cxx EEPROMs connected to I2C serial bus.
+
+It uses the SMBus protocol used by most of the recent chipsets. Don't forget to load 
+your i2c chipset and the i2c-dev drivers.
+
+Use -16 switch for EEPROM larger then 24C16 (16 bit addressing mode). 
+
+Again, it's really important that you read the README file.
+
+Type "make" to compile.
diff --git a/i2c-tools-3.0.2/eepromer/README.eeprom b/i2c-tools-3.0.2/eepromer/README.eeprom
new file mode 100644
index 0000000..6f1e5ed
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/README.eeprom
@@ -0,0 +1,85 @@
+You can use this program to read/write to i2c-eeproms
+like the popular 24C16, 24C08, 24C04,.. In contrast to eeprommer
+which supports 24C256-type eeproms 24C16ss use 1-byte addresses!
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!                                                                           !
+!!! This program should only be used on external busses such as i2c-pport.    !
+!!!                                                                           !
+!!! Your computer may contain i2c-eeproms for saving data vital to its       !
+!!! operation. If you are not careful you might overwrite this data with      !
+!!! this program and your computer may no longer boot!                        !
+!!!                                                                           !
+!!! An example are the EEPROMS on your SDRAM DIMMs, your computer may no      !
+!!! longer detect the RAM module rendering it essentially USELESS!            !
+!!!                                                                           !
+!!! IBM Thinkpads are said to store their configuration data in a eeprom,     !
+!!! if you manage to overwrite this eeprom you will have to send your         !
+!!! computer to the manufacturer for a costly repair!                         !
+!!!                                                                           !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Warning !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+It has several options:
+
+	-d devicenode
+
+		set this to the device-node of the i2c-bus
+		you want to use like /dev/i2c-0.
+		Use /dev/i2c-1 for the second bus, i2c-2 for the third...
+
+		The default /dev/i2c-0 should work most of the time.
+
+	-a address
+
+		set this to the device-address of your
+		eeprom. For a 24C16 the address is hardcoded to
+		0x50, which is -you guessed it- the default.
+
+		For a 24C08 and smaller types you can choose which
+		addresses they occupy by forcing the address-pins
+		of the chip to High or Low so here the address may differ.
+
+	-p number_of_pages
+
+		set this to the number of pages you want to read
+		from or write to the eeprom. The 24C16 maps it's
+		pages to consecutive addresses on the i2c-bus so
+		we will try to read 256 bytes from every i2c
+		address between 'address' (inclusive) and
+		'address + number_of_pages' (exclusive)...
+
+		A 24C16 has 8 pages so that's the default for this
+		parameter.
+
+	-f filename
+
+		read data from this file (when writing to eeprom) or
+		write data to this file (when reading from eeprom).
+
+		When reading a file that's smaller than the
+		eeprom's storage size we will pad the eeprom
+		with zeroes.
+
+		If no file is given we will just read the
+		eeprom (while in read-mode) and test it's presence
+		this way. In write-mode we will just write zeroes
+		to the eeprom.
+
+	-w	When '-w' is present we will *write* to the eeprom.
+		If you do not specify '-w' we will read the contents
+		of the eeprom.
+
+	-y	This flag will suppress the warning when you write to the
+		eeprom. You will not be required to enter 'yes' so be careful
+		when using this switch!
+
+
+I wrote that program to clear a 24C16 eeprom that sit's in my crappy
+satellite receiver because sometimes its Z80 processor likes to
+write garbage to it and then crash....
+
+No further testing besides writing a long series of "The quick brown
+fox jumps over the lazy dog!" and reading it back has been done so
+of course this comes without any warranty.
+
+	Chris <chris@hedonism.cx>
diff --git a/i2c-tools-3.0.2/eepromer/README.eepromer b/i2c-tools-3.0.2/eepromer/README.eepromer
new file mode 100644
index 0000000..444103f
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/README.eepromer
@@ -0,0 +1,27 @@
+Simple program for storing data to I2C EEPROM.
+
+!!!!!!!!!!!!!!!!!!!!!!!!Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+The EEPROM must be a large EEPROM which uses a 2-byte address
+field (24C32 or larger). It will NOT WORK on small EEPROMs
+(24C01 - 24C16) such as those used on SDRAM DIMMs.
+
+Tested only on 24C256.
+
+!!!!!!!!!!!!!!!!!!!!!!!!Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+This program is intended for use on eeproms using external busses such as 
+i2c-pport.
+Do not use this on your SDRAM DIMM EEPROMS, it won't work!!!!!!!!!
+Doing so will render your SDRAM USELESS  and leave your system UNBOOTABLE!!!
+
+!!!!!!!!!!!!!!!!!!!!!!!!Warning!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+Options:
+	-r  read
+	-w  write
+	-e  erase
+	-p  print "super block of EEPROM" (date and size stored data)
+
+Daniel Smolik
+marvin@sitour.cz
diff --git a/i2c-tools-3.0.2/eepromer/eeprog.c b/i2c-tools-3.0.2/eepromer/eeprog.c
new file mode 100644
index 0000000..d7ccc7f
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/eeprog.c
@@ -0,0 +1,283 @@
+/***************************************************************************
+    copyright            : (C) by 2002-2003 Stefano Barbato
+    email                : stefano@codesink.org
+
+    $Id: eeprog.c 5122 2008-02-18 09:22:21Z khali $
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+#include <stdio.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "24cXX.h"
+
+#define VERSION 	"0.7.5"
+
+#define ENV_DEV		"EEPROG_DEV"
+#define ENV_I2C_ADDR	"EEPROG_I2C_ADDR"
+
+int g_quiet;
+
+#define usage_if(a) do { do_usage_if( a , __LINE__); } while(0);
+void do_usage_if(int b, int line)
+{
+	static const char *eeprog_usage =
+"eeprog " VERSION ", a 24Cxx EEPROM reader/writer\n"
+"Copyright (c) 2003 by Stefano Barbato - All rights reserved.\n"
+"Usage: eeprog [-fqxdh] [-16|-8] [ -r addr[:count] | -w addr ]  /dev/i2c-N  i2c-address\n" 
+"\n"
+"  Address modes:\n"
+"	-8		Use 8bit address mode for 24c0x...24C16 [default]\n"
+"	-16		Use 16bit address mode for 24c32...24C256\n"
+"  Actions:\n"
+"	-r addr[:count]	Read [count] (1 if omitted) bytes from [addr]\n" 
+"			and print them to the standard output\n" 
+"	-w addr		Write input (stdin) at address [addr] of the EEPROM\n"
+"	-h		Print this help\n"
+"  Options:\n"
+"	-x		Set hex output mode\n" 
+"	-d		Dummy mode, display what *would* have been done\n" 
+"	-f		Disable warnings and don't ask confirmation\n"
+"	-q		Quiet mode\n"
+"\n"
+"The following environment variables could be set instead of the command\n"
+"line arguments:\n"
+"	EEPROG_DEV		device name(/dev/i2c-N)\n"
+"	EEPROG_I2C_ADDR		i2c-address\n"
+"\n"
+"	Examples\n"
+"	1- read 64 bytes from the EEPROM at address 0x54 on bus 0 starting\n"
+"	   at address 123 (decimal)\n"
+"		eeprog /dev/i2c-0 0x54 -r 123:64\n"
+"	2- prints the hex codes of the first 32 bytes read from bus 1\n"
+"	   at address 0x22\n"
+"		eeprog /dev/i2c-1 0x51 -x -r 0x22:0x20\n"
+"	3- write the current timestamp at address 0x200 of the EEPROM on\n"
+"	   bus 0 at address 0x33\n"
+"		date | eeprog /dev/i2c-0 0x33 -w 0x200\n";
+
+	if(!b)
+		return;
+	fprintf(stderr, "%s\n[line %d]\n", eeprog_usage, line);
+	exit(1);
+}
+
+
+#define die_if(a, msg) do { do_die_if( a , msg, __LINE__); } while(0);
+void do_die_if(int b, char* msg, int line)
+{
+	if(!b)
+		return;
+	fprintf(stderr, "Error at line %d: %s\n", line, msg);
+	//fprintf(stderr, "	sysmsg: %s\n", strerror(errno));
+	exit(1);
+}
+
+#define print_info(args...) do { if(!g_quiet) fprintf(stderr, args); } while(0);
+
+void parse_arg(char *arg, int* paddr, int *psize)
+{
+	char *end;
+	*paddr = strtoul(arg, &end, 0);
+	if(*end == ':')
+		*psize = strtoul(++end, 0, 0);
+}
+
+int confirm_action()
+{
+	fprintf(stderr, 
+	"\n"
+	"____________________________WARNING____________________________\n"
+	"Erroneously writing to a system EEPROM (like DIMM SPD modules)\n"
+	"can break your system.  It will NOT boot anymore so you'll not\n"
+	"be able to fix it.\n"
+	"\n"
+	"Reading from 8bit EEPROMs (like that in your DIMM) without using\n"
+	"the -8 switch can also UNEXPECTEDLY write to them, so be sure to\n"
+	"use the -8 command param when required.\n"
+	"\n"
+	"Use -f to disable this warning message\n"
+	"\n"
+	"Press ENTER to continue or hit CTRL-C to exit\n"
+	"\n"
+	);
+	getchar();
+	return 1; 
+}
+
+
+int read_from_eeprom(struct eeprom *e, int addr, int size, int hex)
+{
+
+	int ch, i;
+	// hex print out
+	die_if((ch = eeprom_read_byte(e, addr)) < 0, "read error");
+	i = 1;
+	if(hex)
+		printf("\n %.4x|  %.2x ", addr, ch);
+	else
+		putchar(ch);
+	while(--size)
+	{
+		die_if((ch = eeprom_read_current_byte(e)) < 0, "read error");
+		if(hex)
+		{
+			addr++;
+			if( (i % 16) == 0 ) 
+				printf("\n %.4x|  ", addr);
+			else if( (i % 8) == 0 ) 
+				printf("  ");
+			i++;
+			printf("%.2x ", ch);
+		} else {
+			putchar(ch);
+		}
+	}
+	if(hex)
+		printf("\n\n");
+	fflush(stdout);
+	return 0;
+}
+
+int write_to_eeprom(struct eeprom *e, int addr)
+{
+	int c;
+	while((c = getchar()) != EOF)
+	{
+		print_info(".");
+		fflush(stdout);
+		die_if(eeprom_write_byte(e, addr++, c), "write error");
+	}
+	print_info("\n\n");
+	return 0;
+}
+
+int main(int argc, char** argv)
+{
+	struct eeprom e;
+	int ret, op, i2c_addr, memaddr, size, want_hex, dummy, force, sixteen;
+	char *device, *arg = 0, *i2c_addr_s;
+	struct stat st;
+	int eeprom_type = 0;
+
+	op = want_hex = dummy = force = sixteen = 0;
+	g_quiet = 0;
+
+	while((ret = getopt(argc, argv, "1:8fr:qhw:xd")) != -1)
+	{
+		switch(ret)
+		{
+		case '1':
+			usage_if(*optarg != '6' || strlen(optarg) != 1);
+			die_if(eeprom_type, "EEPROM type switch (-8 or -16) used twice");
+			eeprom_type = EEPROM_TYPE_16BIT_ADDR;	
+			break;
+		case 'x':
+			want_hex++;
+			break;
+		case 'd':
+			dummy++;
+			break;
+		case '8':
+			die_if(eeprom_type, "EEPROM type switch (-8 or -16) used twice");
+			eeprom_type = EEPROM_TYPE_8BIT_ADDR;
+			break;
+		case 'f':
+			force++;
+			break;
+		case 'q':
+			g_quiet++;
+			break;
+		case 'h':
+			usage_if(1);
+			break;
+		default:
+			die_if(op != 0, "Both read and write requested"); 
+			arg = optarg;
+			op = ret;
+		}
+	}
+	if(!eeprom_type)
+		eeprom_type = EEPROM_TYPE_8BIT_ADDR; // default
+
+	usage_if(op == 0); // no switches 
+	// set device and i2c_addr reading from cmdline or env
+	device = i2c_addr_s = 0;
+	switch(argc - optind)
+	{
+	case 0:
+		device = getenv(ENV_DEV);
+		i2c_addr_s = getenv(ENV_I2C_ADDR);
+		break;
+	case 1:
+		if(stat(argv[optind], &st) != -1)
+		{
+			device = argv[optind];
+			i2c_addr_s = getenv(ENV_I2C_ADDR);
+		} else {
+			device = getenv(ENV_DEV);
+			i2c_addr_s = argv[optind];
+		}
+		break;
+	case 2:
+		device = argv[optind++];
+		i2c_addr_s = argv[optind];
+		break;
+	default:
+		usage_if(1);
+	}
+	usage_if(!device || !i2c_addr_s);
+	i2c_addr = strtoul(i2c_addr_s, 0, 0);
+
+	print_info("eeprog %s, a 24Cxx EEPROM reader/writer\n", VERSION);
+	print_info("Copyright (c) 2003 by Stefano Barbato - All rights reserved.\n");
+	print_info("  Bus: %s, Address: 0x%x, Mode: %dbit\n", 
+			device, i2c_addr, 
+			(eeprom_type == EEPROM_TYPE_8BIT_ADDR ? 8 : 16) );
+	if(dummy)
+	{
+		fprintf(stderr, "Dummy mode selected, nothing done.\n");
+		return 0;
+	}
+	die_if(eeprom_open(device, i2c_addr, eeprom_type, &e) < 0, 
+			"unable to open eeprom device file (check that the file exists and that it's readable)");
+	switch(op)
+	{
+	case 'r':
+		if(force == 0)
+			confirm_action();
+		size = 1; // default
+		parse_arg(arg, &memaddr, &size);
+		print_info("  Reading %d bytes from 0x%x\n", size, memaddr);
+		read_from_eeprom(&e, memaddr, size, want_hex);
+		break;
+	case 'w':
+		if(force == 0)
+			confirm_action();
+		parse_arg(arg, &memaddr, &size);
+		print_info("  Writing stdin starting at address 0x%x\n", 
+			memaddr);
+		write_to_eeprom(&e, memaddr);
+		break;
+	default:
+		usage_if(1);
+		exit(1);
+	}
+	eeprom_close(&e);
+
+	return 0;
+}
+
diff --git a/i2c-tools-3.0.2/eepromer/eeprom.c b/i2c-tools-3.0.2/eepromer/eeprom.c
new file mode 100644
index 0000000..c0625f8
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/eeprom.c
@@ -0,0 +1,297 @@
+/*
+This program is hereby placed into the public domain.
+Of course the program is provided without warranty of any kind.
+*/
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <linux/i2c-dev.h>
+
+/*
+  this program can read 24C16 (and probably smaller ones, too)
+  I wrote it as a quick and dirty hack because my satellite receiver
+  hung again... so I had to reprogram the eeprom where is stores it's
+  settings.
+ */
+
+#define DEFAULT_I2C_BUS      "/dev/i2c-0"
+#define DEFAULT_EEPROM_ADDR  0x50         /* the 24C16 sits on i2c address 0x50 */
+#define DEFAULT_NUM_PAGES    8            /* we default to a 24C16 eeprom which has 8 pages */
+#define BYTES_PER_PAGE       256          /* one eeprom page is 256 byte */
+#define MAX_BYTES            8            /* max number of bytes to write in one chunk */
+       /* ... note: 24C02 and 24C01 only allow 8 bytes to be written in one chunk.   *
+        *  if you are going to write 24C04,8,16 you can change this to 16            */
+
+/* write len bytes (stored in buf) to eeprom at address addr, page-offset offset */
+/* if len=0 (buf may be NULL in this case) you can reposition the eeprom's read-pointer */
+/* return 0 on success, -1 on failure */
+int eeprom_write(int fd,
+		 unsigned int addr,
+		 unsigned int offset,
+		 unsigned char *buf,
+		 unsigned char len
+){
+	struct i2c_rdwr_ioctl_data msg_rdwr;
+	struct i2c_msg             i2cmsg;
+	int i;
+	char _buf[MAX_BYTES + 1];
+
+	if(len>MAX_BYTES){
+	    fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n");
+	    return -1;
+	}
+
+	if(len+offset >256){
+	    fprintf(stderr,"Sorry, len(%d)+offset(%d) > 256 (page boundary)\n",
+			len,offset);
+	    return -1;
+	}
+
+	_buf[0]=offset;    /* _buf[0] is the offset into the eeprom page! */
+	for(i=0;i<len;i++) /* copy buf[0..n] -> _buf[1..n+1] */
+	    _buf[1+i]=buf[i];
+
+	msg_rdwr.msgs = &i2cmsg;
+	msg_rdwr.nmsgs = 1;
+
+	i2cmsg.addr  = addr;
+	i2cmsg.flags = 0;
+	i2cmsg.len   = 1+len;
+	i2cmsg.buf   = _buf;
+
+	if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){
+	    perror("ioctl()");
+	    fprintf(stderr,"ioctl returned %d\n",i);
+	    return -1;
+	}
+
+	if(len>0)
+	    fprintf(stderr,"Wrote %d bytes to eeprom at 0x%02x, offset %08x\n",
+		    len,addr,offset);
+	else
+	    fprintf(stderr,"Positioned pointer in eeprom at 0x%02x to offset %08x\n",
+		    addr,offset);
+
+	return 0;
+}
+
+/* read len bytes stored in eeprom at address addr, offset offset in array buf */
+/* return -1 on error, 0 on success */
+int eeprom_read(int fd,
+		 unsigned int addr,
+		 unsigned int offset,
+		 unsigned char *buf,
+		 unsigned char len
+){
+	struct i2c_rdwr_ioctl_data msg_rdwr;
+	struct i2c_msg             i2cmsg;
+	int i;
+
+	if(len>MAX_BYTES){
+	    fprintf(stderr,"I can only write MAX_BYTES bytes at a time!\n");
+	    return -1;
+	}
+
+	if(eeprom_write(fd,addr,offset,NULL,0)<0)
+	    return -1;
+
+	msg_rdwr.msgs = &i2cmsg;
+	msg_rdwr.nmsgs = 1;
+
+	i2cmsg.addr  = addr;
+	i2cmsg.flags = I2C_M_RD;
+	i2cmsg.len   = len;
+	i2cmsg.buf   = buf;
+
+	if((i=ioctl(fd,I2C_RDWR,&msg_rdwr))<0){
+	    perror("ioctl()");
+	    fprintf(stderr,"ioctl returned %d\n",i);
+	    return -1;
+	}
+
+	fprintf(stderr,"Read %d bytes from eeprom at 0x%02x, offset %08x\n",
+		len,addr,offset);
+
+	return 0;
+}
+
+
+
+int main(int argc, char **argv){
+    int i,j;
+
+    /* filedescriptor and name of device */
+    int d; 
+    char *dn=DEFAULT_I2C_BUS;
+
+    /* filedescriptor and name of data file */
+    int f=-1;
+    char *fn=NULL;
+
+    unsigned int addr=DEFAULT_EEPROM_ADDR;
+    int rwmode=0;
+    int pages=DEFAULT_NUM_PAGES;
+
+    int force=0; /* suppress warning on write! */
+    
+    while((i=getopt(argc,argv,"d:a:p:wyf:h"))>=0){
+	switch(i){
+	case 'h':
+	    fprintf(stderr,"%s [-d dev] [-a adr] [-p pgs] [-w] [-y] [-f file]\n",argv[0]);
+	    fprintf(stderr,"\tdev: device, e.g. /dev/i2c-0    (def)\n");
+	    fprintf(stderr,"\tadr: base address of eeprom, eg 0xA0 (def)\n");
+	    fprintf(stderr,"\tpgs: number of pages to read, eg 8 (def)\n");
+	    fprintf(stderr,"\t-w : write to eeprom (default is reading!)\n");
+	    fprintf(stderr,"\t-y : suppress warning when writing (default is to warn!)\n");
+	    fprintf(stderr,"\t-f file: copy eeprom contents to/from file\n");
+	    fprintf(stderr,"\t         (default for read is test only; for write is all zeros)\n");
+	    fprintf(stderr,"Note on pages/addresses:\n");
+	    fprintf(stderr,"\teeproms with more than 256 byte appear as if they\n");
+	    fprintf(stderr,"\twere several eeproms with consecutive addresses on the bus\n");
+	    fprintf(stderr,"\tso we might as well address several seperate eeproms with\n");
+	    fprintf(stderr,"\tincreasing addresses....\n\n");
+	    exit(1);
+	    break;
+	case 'd':
+	    dn=optarg;
+	    break;
+	case 'a':
+	    if(sscanf(optarg,"0x%x",&addr)!=1){
+		fprintf(stderr,"Cannot parse '%s' as addrs., example: 0xa0\n",
+			optarg);
+		exit(1);
+	    }
+	    break;
+	case 'p':
+	    if(sscanf(optarg,"%d",&pages)!=1){
+		fprintf(stderr,"Cannot parse '%s' as number of pages, example: 8\n",
+			optarg);
+		exit(1);
+	    }
+	    break;
+	case 'w':
+	    rwmode++;
+	    break;
+	case 'f':
+	    fn=optarg;
+	    break;
+	case 'y':
+	    force++;
+	    break;
+	}
+
+    }
+   
+    fprintf(stderr,"base-address of eeproms       : 0x%02x\n",addr);
+    fprintf(stderr,"number of pages to read       : %d (0x%02x .. 0x%02x)\n",
+		    pages,addr,addr+pages-1);
+
+    if(fn){
+	if(!rwmode) /* if we are reading, *WRITE* to file */
+	    f=open(fn,O_WRONLY|O_CREAT,0666);
+	else /* if we are writing to eeprom, *READ* from file */
+	    f=open(fn,O_RDONLY);
+	if(f<0){
+	    fprintf(stderr,"Could not open data-file %s for reading or writing\n",fn);
+	    perror(fn);
+	    exit(1);
+	}
+	fprintf(stderr,"file opened for %7s       : %s\n",rwmode?"reading":"writing",fn);
+	fprintf(stderr,"            on filedescriptor : %d\n",f);
+    }
+
+    if((d=open(dn,O_RDWR))<0){
+	fprintf(stderr,"Could not open i2c at %s\n",dn);
+	perror(dn);
+	exit(1);
+    }
+
+    fprintf(stderr,"i2c-devicenode is             : %s\n",dn);
+    fprintf(stderr,"            on filedescriptor : %d\n\n",d);
+
+    /***
+     *** I'm not the one to blame of you screw your computer!
+     ***/
+    if(rwmode && ! force){
+	unsigned char warnbuf[4];
+	fprintf(stderr,"**WARNING**\n");
+	fprintf(stderr," - \tYou have chosen to WRITE to this eeprom.\n");
+	fprintf(stderr,"\tMake sure that this tiny chip is *NOT* vital to the\n");
+	fprintf(stderr,"\toperation of your computer as you can easily corrupt\n");
+	fprintf(stderr,"\tthe configuration memory of your SDRAM-memory-module,\n");
+	fprintf(stderr,"\tyour IBM ThinkPad or whatnot...! Fixing these errors can be\n");
+	fprintf(stderr,"\ta time-consuming and very costly process!\n\n");
+	fprintf(stderr,"Things to consider:\n");
+	fprintf(stderr," - \tYou can have more than one i2c-bus, check in /proc/bus/i2c\n");
+	fprintf(stderr,"\tand specify the correct one with -d\n");
+	fprintf(stderr,"\tright now you have chosen to use '%s'\n",dn);
+	fprintf(stderr," - \tA eeprom can occupy several i2c-addresses (one per page)\n");
+	fprintf(stderr,"\tso please make sure that there is no vital eeprom in your computer\n");
+	fprintf(stderr,"\tsitting at addresses between 0x%02x and 0x%02x\n",addr,addr+pages-1);
+
+	fprintf(stderr,"Enter 'yes' to continue:");
+	fflush(stderr);
+	if(!fgets(warnbuf,sizeof(warnbuf),stdin)){
+	    fprintf(stderr,"\nCould not read confirmation from stdin!\n");
+	    exit(1);
+	}
+	if(strncmp(warnbuf,"yes",3)){
+	    fprintf(stderr,"\n** ABORTING WRITE! **, you did not answer 'yes'\n");
+	    exit(1);
+	}
+    }
+
+    for(i=0;i<pages;i++){
+	unsigned char buf[BYTES_PER_PAGE];
+
+	if(rwmode){
+
+	    if(f>=0){
+		j=read(f,buf,sizeof(buf));
+		if(j<0){
+		    fprintf(stderr,"Cannot read from file '%s'\n",fn);
+		    perror(fn);
+		    exit(1);
+		}
+		if(j!=sizeof(buf)){
+		    fprintf(stderr,"File '%s' is too small, padding eeprom with zeroes\n",fn);
+		    while(j<sizeof(buf))
+			buf[j++]=0;
+		}
+	    } else {
+		for(j=0;j<sizeof(buf);j++)
+		    buf[j]=0;
+	    }
+            for(j=0;j<(BYTES_PER_PAGE/MAX_BYTES);j++)
+		if(eeprom_write(d,addr+i,j*MAX_BYTES,buf+(j*MAX_BYTES),MAX_BYTES)<0)
+		    exit(1);
+	} else {
+            for(j=0;j<(BYTES_PER_PAGE/MAX_BYTES);j++)
+		if(eeprom_read(d,addr+i,j*MAX_BYTES,buf+(j*MAX_BYTES),MAX_BYTES)<0)
+		    exit(1);
+	}
+
+
+	if(!rwmode && f>=0){
+	    j=write(f,buf,sizeof(buf));
+	    if(j!=sizeof(buf)){
+		fprintf(stderr,"Cannot write to file '%s'\n",fn);
+		perror(fn);
+		exit(1);
+	    }
+	}
+
+    }
+
+    if(f>=0)
+	close(f);
+
+    close(d);
+
+    exit(0);
+
+}
diff --git a/i2c-tools-3.0.2/eepromer/eepromer.c b/i2c-tools-3.0.2/eepromer/eepromer.c
new file mode 100644
index 0000000..3cb62e7
--- /dev/null
+++ b/i2c-tools-3.0.2/eepromer/eepromer.c
@@ -0,0 +1,718 @@
+#include <errno.h>                                                              
+#include <string.h>                                                             
+#include <stdio.h>                                                              
+#include <stdlib.h>                                                             
+#include <unistd.h>                                                             
+#include <fcntl.h>                                                              
+#include <time.h>
+#include <linux/i2c-dev.h>
+
+
+#define MAX_BLK_SIZE 64
+#define EEPROM_SIZE 32768
+#define READ 1
+#define WRITE 0
+#define ERASE 2
+#define PHEADER 3
+#define VER       "eepromer v 0.4 (c) Daniel Smolik 2001\n"
+#define HEAD_SIZE   sizeof(struct mini_inode)
+#define START_ADDR   0
+#define FORCE        1
+/*
+To disable startup warning #undef WARNINC
+
+
+*/
+
+#define  WARNINC     
+ 
+
+int block_write(int file,int dev_addr,int eeprom_addr,unsigned char *buf,int lenght);int block_write(int file,int dev_addr,int eeprom_addr,unsigned char *buf,int lenght);
+int block_read(int file,int dev_addr,int eeprom_addr,unsigned char *buf);
+
+/* block_read read block 64 bytes length and returns actual length of data*/
+void help(void);
+int init(char *device,int addr);
+int content_write(int file, int addr);
+int content_read(int file, int addr);
+int inode_write(int file, int dev_addr, int lenght);
+int inode_read(int file, int dev_addr, void *p_inode);
+void pheader(int file, int addr);
+void  erase(int file,int addr,int eeprom_size);	
+void made_address(int addr,unsigned char *buf);
+void warn(void);
+void bar(void);
+
+
+static int stav=0;
+
+
+
+static	struct  mini_inode {
+	
+			time_t  timestamp;
+			int		data_len;
+			char    data[56];
+	
+	} m_ind,*p_ind;
+
+
+
+void help(void)                                                                 
+{                                                                               
+  FILE *fptr;                                                                   
+  char s[100];                                                                  
+    
+	fprintf(stderr,"Syntax: eepromer [-r|-w|-e|-p]  -f /dev/i2c-X  ADDRESS \n\n");   
+	fprintf(stderr,"  ADDRESS is address of i2c device eg. 0x51\n");
+
+	if((fptr = fopen("/proc/bus/i2c", "r"))) {                                    
+	fprintf(stderr,"  Installed I2C busses:\n");                                
+	while(fgets(s, 100, fptr))                                                  
+		fprintf(stderr, "    %s", s);                                             
+	fclose(fptr);                                                               
+	}
+}	 
+
+
+
+
+
+int main(int argc, char *argv[]){
+
+	int i, file, addr;
+	int  action; //in this variable will be (-r,-w,-e)
+	char device[45];
+	int force;
+
+	p_ind=&m_ind;
+	force=0;
+
+
+
+	
+	for(i=1; i < argc;i++){
+	
+		
+		if(!strcmp("-r",argv[i])) {
+			 action=READ;
+			 break;
+		}	 
+		if(!strcmp("-e",argv[i])) {
+			 action=ERASE;
+			 break;
+		}	 
+		if(!strcmp("-w",argv[i])) { 
+			action=WRITE;
+			break;
+		}
+		if(!strcmp("-p",argv[i])) { 
+			action=PHEADER;
+			break;
+		}	
+		if(!strcmp("-force",argv[i])) { 
+			force=FORCE;
+			break;
+		}	
+		if(!strcmp("-v",argv[i])) { 
+			fprintf(stderr,VER);
+			exit(0);
+			break;
+		}	
+		else {
+		
+			fprintf(stderr,"Error: No action specified !\n");
+			help();
+			exit(1);
+		}
+
+	}	
+
+
+#ifdef  WARNINC
+	
+	if(force!=FORCE) warn();
+	
+#endif
+	
+
+	if(argc < 5) {
+		fprintf(stderr,"Error: No i2c address specified !\n");
+		help();
+		exit(1);
+	
+	}
+
+	
+	for(i=1; i < argc;i++){
+	
+		
+		if(!strcmp("-f",argv[i])) {
+			 strcpy(device,argv[i+1]);	 
+			 break;
+		}	 
+
+	}	
+
+	if(!strlen(device)) {
+
+			fprintf(stderr,"Error: No device specified !\n");
+			help();
+			exit(1);
+	}
+
+
+	if(! (addr=strtol(argv[4],NULL,16))) {
+	
+		fprintf(stderr,"Error: Bad device address !\n");
+		help();
+		exit(1);
+	}
+
+	if(! (file=init(device,addr))){
+	
+		fprintf(stderr,"Error: Init failed !\n");
+		exit(1);
+	}	
+
+
+	switch(action){
+	
+		case READ:  
+						content_read(file,addr);
+						break;
+		
+		case WRITE: 
+						content_write(file,addr);
+						break;
+		
+		case ERASE: 	erase(file,addr,EEPROM_SIZE);
+						break;
+		case PHEADER: 	pheader(file,addr);
+						break;			
+					
+		default:
+			fprintf(stderr,"Internal error!\n");
+			exit(1); break;
+	
+	}
+
+
+	close(file);
+	exit(0);
+
+}
+
+
+
+/****************************************************************************/
+/*            Low level function	                                        */	
+/*																			*/
+/****************************************************************************/
+
+
+
+
+
+int block_write(int file,int dev_addr,int eeprom_addr,unsigned char *buf,int lenght){
+
+		unsigned char buff[2];
+		struct i2c_msg msg[2];
+		
+		struct i2c_ioctl_rdwr_data {
+	
+	 		struct i2c_msg *msgs;  /* ptr to array of simple messages */              
+	    	int nmsgs;             /* number of messages to exchange */ 
+		} msgst;
+	
+
+
+		if ( lenght > (MAX_BLK_SIZE) ) {
+		
+			fprintf(stderr,                                                             
+	                  "Error: Block too large:\n"); 
+		
+		}
+
+
+		//bar();
+
+		made_address(eeprom_addr,buff);
+		
+			
+		msg[0].addr = dev_addr;
+		msg[0].flags = 0;
+		msg[0].len = 2;
+		msg[0].buf = buff;
+	
+	
+		msg[1].addr = dev_addr;
+		msg[1].flags = I2C_M_NOSTART;
+		msg[1].len = lenght;
+		msg[1].buf = buf;
+
+
+		msgst.msgs = msg;	
+		msgst.nmsgs = 2;
+	
+		
+		if (ioctl(file,I2C_RDWR,&msgst) < 0){
+
+				fprintf(stderr,                                                             
+	                  "Error: Transaction failed: %s\n",      
+	                              strerror(errno)); 
+
+			return 1;
+	                                                                                
+		}
+
+       return 0;
+	
+}
+
+
+
+
+int block_read(int file,int dev_addr,int eeprom_addr,unsigned char *buf){
+
+	int ln;
+	char buff[2]; //={0x0,0x0};
+	
+	struct i2c_msg msg[2];
+		
+	struct i2c_ioctl_rdwr_data {
+	
+	 		struct i2c_msg *msgs;  /* ptr to array of simple messages */              
+	    	int nmsgs;             /* number of messages to exchange */ 
+	} msgst;
+
+
+	
+	made_address(eeprom_addr,buff);
+	ln=0;
+	//bar();	
+	
+	msg[0].addr = dev_addr;
+	msg[0].flags = 0;
+	msg[0].len = 2;
+	msg[0].buf = buff;
+	
+	
+	msg[1].addr = dev_addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = MAX_BLK_SIZE;
+	msg[1].buf = buf;
+
+	
+	
+
+	msgst.msgs = msg;	
+	msgst.nmsgs = 2;
+	
+	
+	
+
+	if ((ln = ioctl(file, I2C_RDWR, &msgst)) < 0) {
+
+			fprintf(stderr,                                                             
+	                  "Error: Read error:%d\n",ln);
+	   return ln;                     
+	}
+	
+	return ln;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void made_address(int addr,unsigned char *buf){
+
+		int k;
+		
+		//addr = addr & 0xFFFF; /*odstranim nepoterbne bity*/
+
+		k=addr;
+		buf[1]=(unsigned char) (k & 0xFF); //vyrobim druhy byte adresy
+		k=addr & 0xFF00 ;
+		buf[0]= ((unsigned char) (k >> 8)) & 0x7F;
+	
+		
+	return;
+}
+
+
+int init(char *device,int addr) { 
+
+	int file;	
+	unsigned long funcs;
+
+	if ((file = open(device,O_RDWR)) < 0) {
+	
+  	 	fprintf(stderr,"Error: Could not open file %s\n",                
+		                    device);             
+	
+		return 0;
+	}
+
+
+	/* check adapter functionality */                                             
+	if (ioctl(file,I2C_FUNCS,&funcs) < 0) {                                       
+	      fprintf(stderr,                                                             
+	                  "Error: Could not get the adapter functionality matrix: %s\n",      
+	                              strerror(errno));                                                   
+		 close(file);		
+	     return 0;                                                                    
+	}             
+
+	/* The I2C address */                                        
+	if (ioctl(file,I2C_SLAVE,addr) < 0) {                                         
+	      /* ERROR HANDLING; you can check errno to see what went wrong */            
+		fprintf(stderr,                                                             
+	                  "Error: Cannot communicate with slave: %s\n",      
+	                              strerror(errno));                                                   
+
+		close(file);	      
+		return 0;                                                                    
+	}       
+
+	return file;
+}
+
+
+int content_write(int file, int addr){
+
+	unsigned char buf[MAX_BLK_SIZE];
+	unsigned char pom; 
+	int i, j, k, delka, addr_cnt;
+	
+	delka=0;
+	addr_cnt=HEAD_SIZE;
+	k=0;
+
+	for(j=0;j<=MAX_BLK_SIZE;j++)buf[j]=0;
+
+
+
+	i=0;
+
+	for(;;) {
+	
+		delka=fread(&pom,1,1,stdin);
+
+		if( delka > 0 ){
+			buf[i]=pom;
+		}
+
+		if(i==(MAX_BLK_SIZE-1) || (delka < 1)) {
+			
+				
+						
+	 		if(block_write(file,addr,addr_cnt,buf,delka<1?i:(i+1)) !=0) {
+	 
+	 			fprintf(stderr,"Block write failed\n");      
+	 			return 1;
+	 
+	 		}
+	 		//printf("i:%d\n",i);
+			addr_cnt=addr_cnt + i + (delka==1?1:0); //+i
+			
+			for(j=0;j<=MAX_BLK_SIZE;j++)buf[j]=0;
+
+			i=0;
+			if(delka<1) {
+			
+				//pisu EOF
+				
+				
+	 			if(inode_write(file,addr,(addr_cnt-HEAD_SIZE)) !=0) {
+					 
+	 				fprintf(stderr,"Inode write failed\n");      
+	 				return 1;
+	 			
+	 			}
+				break;
+			}			
+			
+			
+		} else  i++;
+
+	}
+
+	return 0;
+	
+}
+
+
+int content_read(int file, int addr){
+
+	unsigned char buf[MAX_BLK_SIZE];
+	int i, j, k, delka;
+	
+	delka=0;
+	k=0;
+	
+	
+	inode_read(file,addr,p_ind );
+
+
+	for(i=HEAD_SIZE;i<= (HEAD_SIZE + p_ind->data_len);i=i+MAX_BLK_SIZE ) {
+	
+	
+	 		if(block_read(file,addr,i,buf) !=0) {
+	 
+	 			fprintf(stderr,"Block read failed\n");      
+	 			return 1;
+	 
+	 		}
+		
+			if( (HEAD_SIZE + p_ind->data_len - i) < MAX_BLK_SIZE ) {
+				k= HEAD_SIZE + p_ind->data_len - i;
+			}else {
+				k=MAX_BLK_SIZE;
+			}
+			
+					
+			for(j=0;j<k ;j++){
+
+					putc(buf[j],stdout);
+				
+			}
+			
+		
+	}
+
+	return 0;
+	
+}
+
+
+
+void erase(int file, int addr,int eeprom_size){
+
+	unsigned char buf[MAX_BLK_SIZE];
+	int i, j, k, delka;
+	
+	delka=0;
+	k=0;
+
+	for(j=0;j<=MAX_BLK_SIZE;j++)buf[j]=0;
+
+
+
+
+
+	for(i=0;i<eeprom_size;i=i+MAX_BLK_SIZE) {
+	
+
+	 		if(block_write(file,addr,i,buf,MAX_BLK_SIZE) !=0) {
+	 
+	 			fprintf(stderr,"Block write failed\n");      
+	 			return;
+	 
+	 		}
+
+	}
+
+	return;
+	
+}
+
+
+
+void bar(void){
+
+
+	if( stav > 70 ) stav=0;
+	
+	
+		switch(stav) {
+
+		
+			case 10: fwrite("\\",1,1,stderr);
+						fflush(stderr); 
+						rewind(stderr);
+						break;
+			case 20: fwrite("|",1,1,stderr); 
+						fflush(stderr);
+						rewind(stderr); 
+						break;
+			case 30: fwrite("/",1,1,stderr); 
+						fflush(stderr); 
+						rewind(stderr);
+						break;
+			case 40: fwrite("-",1,1,stderr);
+						fflush(stderr); 
+						rewind(stderr);
+						break;
+			case 50: fwrite("\\",1,1,stderr);
+						fflush(stderr); 
+						rewind(stderr);
+						break;
+			case 60: fwrite("|",1,1,stderr);
+						fflush(stderr); 
+						rewind(stderr);
+						break;
+			case 70: fwrite("/",1,1,stderr);
+						fflush(stderr); 
+						rewind(stderr);
+						break;
+		}
+	stav++;
+
+}
+
+
+
+
+
+int  inode_write(int file,int dev_addr,int lenght){
+
+		unsigned char buff[2];
+		struct i2c_msg msg[2];
+		
+		struct i2c_ioctl_rdwr_data {
+	
+	 		struct i2c_msg *msgs;  /* ptr to array of simple messages */              
+	    	int nmsgs;             /* number of messages to exchange */ 
+		} msgst;
+	
+		
+		m_ind.timestamp=time(NULL);
+		m_ind.data_len=lenght;
+
+
+
+
+
+		//bar();
+
+		made_address(START_ADDR,buff);
+		
+			
+		msg[0].addr = dev_addr;
+		msg[0].flags = 0;
+		msg[0].len = 2;
+		msg[0].buf = buff;
+	
+	
+		msg[1].addr = dev_addr;
+		msg[1].flags = I2C_M_NOSTART;
+		msg[1].len = sizeof(struct mini_inode);
+		msg[1].buf = (char *) &m_ind;
+
+	
+
+		msgst.msgs = msg;	
+		msgst.nmsgs = 2;
+	
+		
+		if (ioctl(file,I2C_RDWR,&msgst) < 0){
+
+				fprintf(stderr,                                                             
+	                  "Error: Transaction failed: %s\n",      
+	                              strerror(errno)); 
+
+			return 1;
+	                                                                                
+		}
+
+       return 0;
+	
+}
+
+
+
+int inode_read(int file,int dev_addr,void *p_inode ){
+
+	
+	#define  POK  32
+	int ln;
+	char buff[2]; //={0x0,0x0};
+	
+	struct i2c_msg msg[2];
+		
+	struct i2c_ioctl_rdwr_data {
+	
+	 		struct i2c_msg *msgs;  /* ptr to array of simple messages */              
+	    	int nmsgs;             /* number of messages to exchange */ 
+	} msgst;
+	
+	made_address(START_ADDR,buff);
+	
+	ln=0;
+	//bar();	
+	
+	msg[0].addr = dev_addr;
+	msg[0].flags = 0;
+	msg[0].len = 2;
+	msg[0].buf = buff;
+	
+	
+	msg[1].addr = dev_addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = sizeof(struct mini_inode);
+	msg[1].buf = p_inode;
+
+	
+	
+
+	msgst.msgs = msg;	
+	msgst.nmsgs = 2;
+	
+
+	if ((ln = ioctl(file, I2C_RDWR, &msgst)) < 0) {
+
+			fprintf(stderr,                                                             
+	                  "Error: Read error:%d\n",ln);
+	   return ln;                     
+	}
+
+
+	
+	return ln;
+
+}
+
+
+void pheader(int file,int dev_addr){
+
+	struct tm *p_tm;
+	char time_buf[15],*p_buf;
+
+	p_buf=time_buf;
+	inode_read(file,dev_addr,p_ind );
+	p_tm=localtime(&p_ind->timestamp);
+	strftime(p_buf,sizeof(time_buf),"%Y%m%d%H%M%S",p_tm);
+	printf("LEN=%d,TIME=%s\n",p_ind->data_len,p_buf);
+	return;
+}
+
+
+
+
+#ifdef WARNINC
+void warn(void)
+{
+
+	fprintf(stderr,"\n\n!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!\n");
+	fprintf(stderr,"This program is intended for use on eeproms\nusing external busses such as i2c-pport.\n");
+	fprintf(stderr,"Do not use this on your SDRAM DIMM EEPROMS\nunless you REALLY REALLY know what you are\ndoing!!! Doing so will render your SDRAM\nUSELESS and leave your system UNBOOTABLE!!!\n"); 
+	fprintf(stderr,"To disable this warning use -force\n");
+	fprintf(stderr,"\n\nPress  ENTER  to continue or hit Control-C NOW !!!!\n\n\n");                                 
+
+	getchar();
+}
+#endif
diff --git a/i2c-tools-3.0.2/include/Module.mk b/i2c-tools-3.0.2/include/Module.mk
new file mode 100644
index 0000000..7312a98
--- /dev/null
+++ b/i2c-tools-3.0.2/include/Module.mk
@@ -0,0 +1,26 @@
+# Linux I2C header files
+#
+# Copyright (C) 2007  Jean Delvare <khali@linux-fr.org>
+#
+# Licensed under the GNU General Public License.
+
+INCLUDE_DIR	:= include
+
+INCLUDE_TARGETS	:= linux/i2c-dev.h
+
+#
+# Commands
+#
+
+install-include: $(addprefix $(INCLUDE_DIR)/,$(INCLUDE_TARGETS))
+	$(INSTALL_DIR) $(DESTDIR)$(incdir)/linux
+	for file in $(INCLUDE_TARGETS) ; do \
+	$(INSTALL_DATA) $(INCLUDE_DIR)/$$file $(DESTDIR)$(incdir)/$$file ; done
+
+uninstall-include:
+	for file in $(INCLUDE_TARGETS) ; do \
+	$(RM) $(DESTDIR)$(incdir)/$$file ; done
+
+install: install-include
+
+uninstall: uninstall-include
diff --git a/i2c-tools-3.0.2/include/linux/i2c-dev.h b/i2c-tools-3.0.2/include/linux/i2c-dev.h
new file mode 100644
index 0000000..2caeaac
--- /dev/null
+++ b/i2c-tools-3.0.2/include/linux/i2c-dev.h
@@ -0,0 +1,334 @@
+/*
+    i2c-dev.h - i2c-bus driver, char device interface
+
+    Copyright (C) 1995-97 Simon G. Vogl
+    Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+
+    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.
+*/
+
+/* $Id: i2c-dev.h 5361 2008-10-19 09:47:02Z khali $ */
+
+#ifndef LIB_I2CDEV_H
+#define LIB_I2CDEV_H
+
+#include <linux/types.h>
+#include <sys/ioctl.h>
+
+
+/* -- i2c.h -- */
+
+
+/*
+ * I2C Message - used for pure i2c transaction, also from /dev interface
+ */
+struct i2c_msg {
+	__u16 addr;	/* slave address			*/
+	unsigned short flags;		
+#define I2C_M_TEN	0x10	/* we have a ten bit chip address	*/
+#define I2C_M_RD	0x01
+#define I2C_M_NOSTART	0x4000
+#define I2C_M_REV_DIR_ADDR	0x2000
+#define I2C_M_IGNORE_NAK	0x1000
+#define I2C_M_NO_RD_ACK		0x0800
+	short len;		/* msg length				*/
+	char *buf;		/* pointer to msg data			*/
+};
+
+/* To determine what functionality is present */
+
+#define I2C_FUNC_I2C			0x00000001
+#define I2C_FUNC_10BIT_ADDR		0x00000002
+#define I2C_FUNC_PROTOCOL_MANGLING	0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
+#define I2C_FUNC_SMBUS_PEC		0x00000008
+#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL	0x00008000 /* SMBus 2.0 */
+#define I2C_FUNC_SMBUS_QUICK		0x00010000 
+#define I2C_FUNC_SMBUS_READ_BYTE	0x00020000 
+#define I2C_FUNC_SMBUS_WRITE_BYTE	0x00040000 
+#define I2C_FUNC_SMBUS_READ_BYTE_DATA	0x00080000 
+#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA	0x00100000 
+#define I2C_FUNC_SMBUS_READ_WORD_DATA	0x00200000 
+#define I2C_FUNC_SMBUS_WRITE_WORD_DATA	0x00400000 
+#define I2C_FUNC_SMBUS_PROC_CALL	0x00800000 
+#define I2C_FUNC_SMBUS_READ_BLOCK_DATA	0x01000000 
+#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 
+#define I2C_FUNC_SMBUS_READ_I2C_BLOCK	0x04000000 /* I2C-like block xfer  */
+#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK	0x08000000 /* w/ 1-byte reg. addr. */
+
+#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
+                             I2C_FUNC_SMBUS_WRITE_BYTE)
+#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \
+                                  I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
+#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \
+                                  I2C_FUNC_SMBUS_WRITE_WORD_DATA)
+#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \
+                                   I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
+#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \
+                                  I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
+
+/* Old name, for compatibility */
+#define I2C_FUNC_SMBUS_HWPEC_CALC	I2C_FUNC_SMBUS_PEC
+
+/* 
+ * Data for SMBus Messages 
+ */
+#define I2C_SMBUS_BLOCK_MAX	32	/* As specified in SMBus standard */	
+#define I2C_SMBUS_I2C_BLOCK_MAX	32	/* Not specified but we use same structure */
+union i2c_smbus_data {
+	__u8 byte;
+	__u16 word;
+	__u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
+	                                            /* and one more for PEC */
+};
+
+/* smbus_access read or write markers */
+#define I2C_SMBUS_READ	1
+#define I2C_SMBUS_WRITE	0
+
+/* SMBus transaction types (size parameter in the above functions) 
+   Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
+#define I2C_SMBUS_QUICK		    0
+#define I2C_SMBUS_BYTE		    1
+#define I2C_SMBUS_BYTE_DATA	    2 
+#define I2C_SMBUS_WORD_DATA	    3
+#define I2C_SMBUS_PROC_CALL	    4
+#define I2C_SMBUS_BLOCK_DATA	    5
+#define I2C_SMBUS_I2C_BLOCK_BROKEN  6
+#define I2C_SMBUS_BLOCK_PROC_CALL   7		/* SMBus 2.0 */
+#define I2C_SMBUS_I2C_BLOCK_DATA    8
+
+
+/* ----- commands for the ioctl like i2c_command call:
+ * note that additional calls are defined in the algorithm and hw 
+ *	dependent layers - these can be listed here, or see the 
+ *	corresponding header files.
+ */
+				/* -> bit-adapter specific ioctls	*/
+#define I2C_RETRIES	0x0701	/* number of times a device address      */
+				/* should be polled when not            */
+                                /* acknowledging 			*/
+#define I2C_TIMEOUT	0x0702	/* set timeout - call with int 		*/
+
+
+/* this is for i2c-dev.c	*/
+#define I2C_SLAVE	0x0703	/* Change slave address			*/
+				/* Attn.: Slave address is 7 or 10 bits */
+#define I2C_SLAVE_FORCE	0x0706	/* Change slave address			*/
+				/* Attn.: Slave address is 7 or 10 bits */
+				/* This changes the address, even if it */
+				/* is already taken!			*/
+#define I2C_TENBIT	0x0704	/* 0 for 7 bit addrs, != 0 for 10 bit	*/
+
+#define I2C_FUNCS	0x0705	/* Get the adapter functionality */
+#define I2C_RDWR	0x0707	/* Combined R/W transfer (one stop only)*/
+#define I2C_PEC		0x0708	/* != 0 for SMBus PEC                   */
+
+#define I2C_SMBUS	0x0720	/* SMBus-level access */
+
+/* -- i2c.h -- */
+
+
+/* Note: 10-bit addresses are NOT supported! */
+
+/* This is the structure as used in the I2C_SMBUS ioctl call */
+struct i2c_smbus_ioctl_data {
+	char read_write;
+	__u8 command;
+	int size;
+	union i2c_smbus_data *data;
+};
+
+/* This is the structure as used in the I2C_RDWR ioctl call */
+struct i2c_rdwr_ioctl_data {
+	struct i2c_msg *msgs;	/* pointers to i2c_msgs */
+	int nmsgs;		/* number of i2c_msgs */
+};
+
+
+static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 
+                                     int size, union i2c_smbus_data *data)
+{
+	struct i2c_smbus_ioctl_data args;
+
+	args.read_write = read_write;
+	args.command = command;
+	args.size = size;
+	args.data = data;
+	return ioctl(file,I2C_SMBUS,&args);
+}
+
+
+static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
+{
+	return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
+}
+	
+static inline __s32 i2c_smbus_read_byte(int file)
+{
+	union i2c_smbus_data data;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
+		return -1;
+	else
+		return 0x0FF & data.byte;
+}
+
+static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
+{
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
+	                        I2C_SMBUS_BYTE,NULL);
+}
+
+static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
+{
+	union i2c_smbus_data data;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     I2C_SMBUS_BYTE_DATA,&data))
+		return -1;
+	else
+		return 0x0FF & data.byte;
+}
+
+static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, 
+                                              __u8 value)
+{
+	union i2c_smbus_data data;
+	data.byte = value;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_BYTE_DATA, &data);
+}
+
+static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
+{
+	union i2c_smbus_data data;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     I2C_SMBUS_WORD_DATA,&data))
+		return -1;
+	else
+		return 0x0FFFF & data.word;
+}
+
+static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, 
+                                              __u16 value)
+{
+	union i2c_smbus_data data;
+	data.word = value;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_WORD_DATA, &data);
+}
+
+static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
+{
+	union i2c_smbus_data data;
+	data.word = value;
+	if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                     I2C_SMBUS_PROC_CALL,&data))
+		return -1;
+	else
+		return 0x0FFFF & data.word;
+}
+
+
+/* Returns the number of read bytes */
+static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, 
+                                              __u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     I2C_SMBUS_BLOCK_DATA,&data))
+		return -1;
+	else {
+		for (i = 1; i <= data.block[0]; i++)
+			values[i-1] = data.block[i];
+		return data.block[0];
+	}
+}
+
+static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, 
+                                               __u8 length, __u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (length > 32)
+		length = 32;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_BLOCK_DATA, &data);
+}
+
+/* Returns the number of read bytes */
+/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
+   ask for less than 32 bytes, your code will only work with kernels
+   2.6.23 and later. */
+static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command,
+                                                  __u8 length, __u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+
+	if (length > 32)
+		length = 32;
+	data.block[0] = length;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
+	                      I2C_SMBUS_I2C_BLOCK_DATA,&data))
+		return -1;
+	else {
+		for (i = 1; i <= data.block[0]; i++)
+			values[i-1] = data.block[i];
+		return data.block[0];
+	}
+}
+
+static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
+                                               __u8 length, __u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (length > 32)
+		length = 32;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
+}
+
+/* Returns the number of read bytes */
+static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,
+                                                 __u8 length, __u8 *values)
+{
+	union i2c_smbus_data data;
+	int i;
+	if (length > 32)
+		length = 32;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                     I2C_SMBUS_BLOCK_PROC_CALL,&data))
+		return -1;
+	else {
+		for (i = 1; i <= data.block[0]; i++)
+			values[i-1] = data.block[i];
+		return data.block[0];
+	}
+}
+
+
+#endif /* LIB_I2CDEV_H */
diff --git a/i2c-tools-3.0.2/py-smbus/README b/i2c-tools-3.0.2/py-smbus/README
new file mode 100644
index 0000000..b97801d
--- /dev/null
+++ b/i2c-tools-3.0.2/py-smbus/README
@@ -0,0 +1,28 @@
+
+README: py-smbus
+
+Prerequisites:
+Be sure to build and install the lm-sensors userspace first.  This package
+requires one of the header files from that.
+
+To build:
+	$ python setup.py build
+
+To install (will also build if necessary):
+	$ python setup.py install
+
+For general build/install help:
+	$ python setup.py --help-commands
+
+Frequently Answered Question:
+
+Q: It's throwing exceptions, nothing works, what's wrong?
+
+  A1: You need write permissions to the i2c-dev devices.  Try running as root.
+
+  A2: Addresses in Linux/I2C are the most-sig 7 bits, right-justified.  E.g.
+	if your device uses address 0xc0 to write and 0xc1 to read, then use
+	address 0x60 with this module.
+
+  A3: Some other kernel driver has claimed that I2C address.  Unload it first.
+
diff --git a/i2c-tools-3.0.2/py-smbus/setup.py b/i2c-tools-3.0.2/py-smbus/setup.py
new file mode 100644
index 0000000..d85c808
--- /dev/null
+++ b/i2c-tools-3.0.2/py-smbus/setup.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+from distutils.core import setup, Extension
+
+setup(	name="smbus",
+	version="1.1",
+	description="Python bindings for Linux SMBus access through i2c-dev",
+	author="Mark M. Hoffman",
+	author_email="mhoffman@lightlink.com",
+	maintainer="Mark M. Hoffman",
+	maintainer_email="lm-sensors@lm-sensors.org",
+	license="GPLv2",
+	url="http://lm-sensors.org/",
+	ext_modules=[Extension("smbus", ["smbusmodule.c"])])
diff --git a/i2c-tools-3.0.2/py-smbus/smbusmodule.c b/i2c-tools-3.0.2/py-smbus/smbusmodule.c
new file mode 100644
index 0000000..afc54a4
--- /dev/null
+++ b/i2c-tools-3.0.2/py-smbus/smbusmodule.c
@@ -0,0 +1,697 @@
+/*
+ * smbusmodule.c - Python bindings for Linux SMBus access through i2c-dev
+ * Copyright (C) 2005-2007 Mark M. Hoffman <mhoffman@lightlink.com>
+ *
+ * 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; version 2 of the License.
+ * 
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <Python.h>
+#include "structmember.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <linux/i2c-dev.h>
+
+/*
+** These are required to build this module against Linux older than 2.6.23.
+*/
+#ifndef I2C_SMBUS_I2C_BLOCK_BROKEN
+#undef I2C_SMBUS_I2C_BLOCK_DATA
+#define I2C_SMBUS_I2C_BLOCK_BROKEN	6
+#define I2C_SMBUS_I2C_BLOCK_DATA	8
+#endif
+
+PyDoc_STRVAR(SMBus_module_doc,
+	"This module defines an object type that allows SMBus transactions\n"
+	"on Linux hosts.  The host kernel must have I2C support, I2C device\n"
+	"interface support, and a bus adapter driver.  All of these can be\n"
+	"either built-in to the kernel, or loaded from modules.\n"
+	"\n"
+	"Because the I2C device interface is opened R/W, users of this\n"
+	"module usually must have root permissions.\n");
+
+typedef struct {
+	PyObject_HEAD
+
+	int fd;		/* open file descriptor: /dev/i2c-?, or -1 */
+	int addr;	/* current client SMBus address */
+	int pec;	/* !0 => Packet Error Codes enabled */
+} SMBus;
+
+static PyObject *
+SMBus_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+	SMBus *self;
+
+	if ((self = (SMBus *)type->tp_alloc(type, 0)) == NULL)
+		return NULL;
+
+	self->fd = -1;
+	self->addr = -1;
+	self->pec = 0;
+
+	return (PyObject *)self;
+}
+
+PyDoc_STRVAR(SMBus_close_doc,
+	"close()\n\n"
+	"Disconnects the object from the bus.\n");
+
+static PyObject *
+SMBus_close(SMBus *self)
+{
+	if ((self->fd != -1) && (close(self->fd) == -1)) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	self->fd = -1;
+	self->addr = -1;
+	self->pec = 0;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static void
+SMBus_dealloc(SMBus *self)
+{
+	PyObject *ref = SMBus_close(self);
+	Py_XDECREF(ref);
+
+	self->ob_type->tp_free((PyObject *)self);
+}
+
+#define MAXPATH 16
+
+PyDoc_STRVAR(SMBus_open_doc,
+	"open(bus)\n\n"
+	"Connects the object to the specified SMBus.\n");
+
+static PyObject *
+SMBus_open(SMBus *self, PyObject *args, PyObject *kwds)
+{
+	int bus;
+	char path[MAXPATH];
+
+	static char *kwlist[] = {"bus", NULL};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:open", kwlist, &bus))
+		return NULL;
+
+	if (snprintf(path, MAXPATH, "/dev/i2c-%d", bus) >= MAXPATH) {
+		PyErr_SetString(PyExc_OverflowError,
+			"Bus number is invalid.");
+		return NULL;
+	}
+
+	if ((self->fd = open(path, O_RDWR, 0)) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static int
+SMBus_init(SMBus *self, PyObject *args, PyObject *kwds)
+{
+	int bus = -1;
+
+	static char *kwlist[] = {"bus", NULL};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:__init__",
+			kwlist, &bus))
+		return -1;
+
+	if (bus >= 0) {
+		SMBus_open(self, args, kwds);
+		if (PyErr_Occurred())
+			return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * private helper function, 0 => success, !0 => error
+ */
+static int
+SMBus_set_addr(SMBus *self, int addr)
+{
+	int ret = 0;
+
+	if (self->addr != addr) {
+		ret = ioctl(self->fd, I2C_SLAVE, addr);
+		self->addr = addr;
+	}
+
+	return ret;
+}
+
+#define SMBus_SET_ADDR(self, addr) do { \
+	if (SMBus_set_addr(self, addr)) { \
+		PyErr_SetFromErrno(PyExc_IOError); \
+		return NULL; \
+	} \
+} while(0)
+
+PyDoc_STRVAR(SMBus_write_quick_doc,
+	"write_quick(addr)\n\n"
+	"Perform SMBus Quick transaction.\n");
+
+static PyObject *
+SMBus_write_quick(SMBus *self, PyObject *args)
+{
+	int addr;
+	__s32 result;
+
+	if (!PyArg_ParseTuple(args, "i:write_quick", &addr))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	if ((result = i2c_smbus_write_quick(self->fd, I2C_SMBUS_WRITE))) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyDoc_STRVAR(SMBus_read_byte_doc,
+	"read_byte(addr) -> result\n\n"
+	"Perform SMBus Read Byte transaction.\n");
+
+static PyObject *
+SMBus_read_byte(SMBus *self, PyObject *args)
+{
+	int addr;
+	__s32 result;
+
+	if (!PyArg_ParseTuple(args, "i:read_byte", &addr))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	if ((result = i2c_smbus_read_byte(self->fd)) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	return Py_BuildValue("l", (long)result);
+}
+
+PyDoc_STRVAR(SMBus_write_byte_doc,
+	"write_byte(addr, val)\n\n"
+	"Perform SMBus Write Byte transaction.\n");
+
+static PyObject *
+SMBus_write_byte(SMBus *self, PyObject *args)
+{
+	int addr, val;
+	__s32 result;
+
+	if (!PyArg_ParseTuple(args, "ii:write_byte", &addr, &val))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	if ((result = i2c_smbus_write_byte(self->fd, (__u8)val)) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyDoc_STRVAR(SMBus_read_byte_data_doc,
+	"read_byte_data(addr, cmd) -> result\n\n"
+	"Perform SMBus Read Byte Data transaction.\n");
+
+static PyObject *
+SMBus_read_byte_data(SMBus *self, PyObject *args)
+{
+	int addr, cmd;
+	__s32 result;
+
+	if (!PyArg_ParseTuple(args, "ii:read_byte_data", &addr, &cmd))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	if ((result = i2c_smbus_read_byte_data(self->fd, (__u8)cmd)) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	return Py_BuildValue("l", (long)result);
+}
+
+PyDoc_STRVAR(SMBus_write_byte_data_doc,
+	"write_byte_data(addr, cmd, val)\n\n"
+	"Perform SMBus Write Byte Data transaction.\n");
+
+static PyObject *
+SMBus_write_byte_data(SMBus *self, PyObject *args)
+{
+	int addr, cmd, val;
+	__s32 result;
+
+	if (!PyArg_ParseTuple(args, "iii:write_byte_data", &addr, &cmd, &val))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	if ((result = i2c_smbus_write_byte_data(self->fd,
+				(__u8)cmd, (__u8)val)) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyDoc_STRVAR(SMBus_read_word_data_doc,
+	"read_word_data(addr, cmd) -> result\n\n"
+	"Perform SMBus Read Word Data transaction.\n");
+
+static PyObject *
+SMBus_read_word_data(SMBus *self, PyObject *args)
+{
+	int addr, cmd;
+	__s32 result;
+
+	if (!PyArg_ParseTuple(args, "ii:read_word_data", &addr, &cmd))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	if ((result = i2c_smbus_read_word_data(self->fd, (__u8)cmd)) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	return Py_BuildValue("l", (long)result);
+}
+
+PyDoc_STRVAR(SMBus_write_word_data_doc,
+	"write_word_data(addr, cmd, val)\n\n"
+	"Perform SMBus Write Word Data transaction.\n");
+
+static PyObject *
+SMBus_write_word_data(SMBus *self, PyObject *args)
+{
+	int addr, cmd, val;
+	__s32 result;
+
+	if (!PyArg_ParseTuple(args, "iii:write_word_data", &addr, &cmd, &val))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	if ((result = i2c_smbus_write_word_data(self->fd,
+				(__u8)cmd, (__u16)val)) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyDoc_STRVAR(SMBus_process_call_doc,
+	"process_call(addr, cmd, val)\n\n"
+	"Perform SMBus Process Call transaction.\n");
+
+static PyObject *
+SMBus_process_call(SMBus *self, PyObject *args)
+{
+	int addr, cmd, val;
+	__s32 result;
+
+	if (!PyArg_ParseTuple(args, "iii:process_call", &addr, &cmd, &val))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	if ((result = i2c_smbus_process_call(self->fd,
+				(__u8)cmd, (__u16)val)) == -1) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+/*
+ * private helper function; returns a new list of integers
+ */
+static PyObject *
+SMBus_buf_to_list(__u8 const *buf, int len)
+{
+	PyObject *list = PyList_New(len);
+	int ii;
+
+	if (list == NULL)
+		return NULL;
+
+	for (ii = 0; ii < len; ii++) {
+		PyObject *val = Py_BuildValue("l", (long)buf[ii]);
+		PyList_SET_ITEM(list, ii, val);
+	}
+	return list;
+}
+
+PyDoc_STRVAR(SMBus_read_block_data_doc,
+	"read_block_data(addr, cmd) -> results\n\n"
+	"Perform SMBus Read Block Data transaction.\n");
+
+static PyObject *
+SMBus_read_block_data(SMBus *self, PyObject *args)
+{
+	int addr, cmd;
+	union i2c_smbus_data data;
+
+	if (!PyArg_ParseTuple(args, "ii:read_block_data", &addr, &cmd))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	/* save a bit of code by calling the access function directly */
+	if (i2c_smbus_access(self->fd, I2C_SMBUS_READ, (__u8)cmd,
+				I2C_SMBUS_BLOCK_DATA, &data)) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	/* first byte of the block contains (remaining) data length */
+	return SMBus_buf_to_list(&data.block[1], data.block[0]);
+}
+
+/*
+ * private helper function: convert an integer list to union i2c_smbus_data
+ */
+static int
+SMBus_list_to_data(PyObject *list, union i2c_smbus_data *data)
+{
+	static char *msg = "Third argument must be a list of at least one, "
+				"but not more than 32 integers";
+	int ii, len;
+
+	if (!PyList_Check(list)) {
+		PyErr_SetString(PyExc_TypeError, msg);
+		return 0; /* fail */
+	}
+
+	if ((len = PyList_GET_SIZE(list)) > 32) {
+		PyErr_SetString(PyExc_OverflowError, msg);
+		return 0; /* fail */
+	}
+
+	/* first byte is the length */
+	data->block[0] = (__u8)len;
+
+	for (ii = 0; ii < len; ii++) {
+		PyObject *val = PyList_GET_ITEM(list, ii);
+		if (!PyInt_Check(val)) {
+			PyErr_SetString(PyExc_TypeError, msg);
+			return 0; /* fail */
+		}
+		data->block[ii+1] = (__u8)PyInt_AS_LONG(val);
+	}
+
+	return 1; /* success */
+}
+
+PyDoc_STRVAR(SMBus_write_block_data_doc,
+	"write_block_data(addr, cmd, [vals])\n\n"
+	"Perform SMBus Write Block Data transaction.\n");
+
+static PyObject *
+SMBus_write_block_data(SMBus *self, PyObject *args)
+{
+	int addr, cmd;
+	union i2c_smbus_data data;
+
+	if (!PyArg_ParseTuple(args, "iiO&:write_block_data", &addr, &cmd,
+				SMBus_list_to_data, &data))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	/* save a bit of code by calling the access function directly */
+	if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd,
+				I2C_SMBUS_BLOCK_DATA, &data)) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyDoc_STRVAR(SMBus_block_process_call_doc,
+	"block_process_call(addr, cmd, [vals]) -> results\n\n"
+	"Perform SMBus Block Process Call transaction.\n");
+
+static PyObject *
+SMBus_block_process_call(SMBus *self, PyObject *args)
+{
+	int addr, cmd;
+	union i2c_smbus_data data;
+
+	if (!PyArg_ParseTuple(args, "iiO&:block_process_call", &addr, &cmd,
+			SMBus_list_to_data, &data))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	/* save a bit of code by calling the access function directly */
+	if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd,
+				I2C_SMBUS_BLOCK_PROC_CALL, &data)) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	/* first byte of the block contains (remaining) data length */
+	return SMBus_buf_to_list(&data.block[1], data.block[0]);
+}
+
+PyDoc_STRVAR(SMBus_read_i2c_block_data_doc,
+	"read_i2c_block_data(addr, cmd, len=32) -> results\n\n"
+	"Perform I2C Block Read transaction.\n");
+
+static PyObject *
+SMBus_read_i2c_block_data(SMBus *self, PyObject *args)
+{
+	int addr, cmd, len=32;
+	union i2c_smbus_data data;
+
+	if (!PyArg_ParseTuple(args, "ii|i:read_i2c_block_data", &addr, &cmd,
+			&len))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	data.block[0] = len;
+	/* save a bit of code by calling the access function directly */
+	if (i2c_smbus_access(self->fd, I2C_SMBUS_READ, (__u8)cmd,
+				len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN:
+				I2C_SMBUS_I2C_BLOCK_DATA, &data)) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	/* first byte of the block contains (remaining) data length */
+	return SMBus_buf_to_list(&data.block[1], data.block[0]);
+}
+
+PyDoc_STRVAR(SMBus_write_i2c_block_data_doc,
+	"write_i2c_block_data(addr, cmd, [vals])\n\n"
+	"Perform I2C Block Write transaction.\n");
+
+static PyObject *
+SMBus_write_i2c_block_data(SMBus *self, PyObject *args)
+{
+	int addr, cmd;
+	union i2c_smbus_data data;
+
+	if (!PyArg_ParseTuple(args, "iiO&:write_i2c_block_data", &addr, &cmd,
+			SMBus_list_to_data, &data))
+		return NULL;
+
+	SMBus_SET_ADDR(self, addr);
+
+	/* save a bit of code by calling the access function directly */
+	if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd,
+				I2C_SMBUS_I2C_BLOCK_BROKEN, &data)) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyDoc_STRVAR(SMBus_type_doc,
+	"SMBus([bus]) -> SMBus\n\n"
+	"Return a new SMBus object that is (optionally) connected to the\n"
+	"specified I2C device interface.\n");
+
+static PyMethodDef SMBus_methods[] = {
+	{"open", (PyCFunction)SMBus_open, METH_VARARGS | METH_KEYWORDS,
+		SMBus_open_doc},
+	{"close", (PyCFunction)SMBus_close, METH_NOARGS,
+		SMBus_close_doc},
+	{"write_quick", (PyCFunction)SMBus_write_quick, METH_VARARGS,
+		SMBus_write_quick_doc},
+	{"read_byte", (PyCFunction)SMBus_read_byte, METH_VARARGS,
+		SMBus_read_byte_doc},
+	{"write_byte", (PyCFunction)SMBus_write_byte, METH_VARARGS,
+		SMBus_write_byte_doc},
+	{"read_byte_data", (PyCFunction)SMBus_read_byte_data, METH_VARARGS,
+		SMBus_read_byte_data_doc},
+	{"write_byte_data", (PyCFunction)SMBus_write_byte_data, METH_VARARGS,
+		SMBus_write_byte_data_doc},
+	{"read_word_data", (PyCFunction)SMBus_read_word_data, METH_VARARGS,
+		SMBus_read_word_data_doc},
+	{"write_word_data", (PyCFunction)SMBus_write_word_data, METH_VARARGS,
+		SMBus_write_word_data_doc},
+	{"process_call", (PyCFunction)SMBus_process_call, METH_VARARGS,
+		SMBus_process_call_doc},
+	{"read_block_data", (PyCFunction)SMBus_read_block_data, METH_VARARGS,
+		SMBus_read_block_data_doc},
+	{"write_block_data", (PyCFunction)SMBus_write_block_data, METH_VARARGS,
+		SMBus_write_block_data_doc},
+	{"block_process_call", (PyCFunction)SMBus_block_process_call,
+		METH_VARARGS, SMBus_block_process_call_doc},
+	{"read_i2c_block_data", (PyCFunction)SMBus_read_i2c_block_data,
+		METH_VARARGS, SMBus_read_i2c_block_data_doc},
+	{"write_i2c_block_data", (PyCFunction)SMBus_write_i2c_block_data,
+		METH_VARARGS, SMBus_write_i2c_block_data_doc},
+	{NULL},
+};
+
+static PyObject *
+SMBus_get_pec(SMBus *self, void *closure)
+{
+	PyObject *result = self->pec ? Py_True : Py_False;
+	Py_INCREF(result);
+	return result;
+}
+
+static int
+SMBus_set_pec(SMBus *self, PyObject *val, void *closure)
+{
+	int pec;
+
+	pec = PyObject_IsTrue(val);
+
+	if (val == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+			"Cannot delete attribute");
+		return -1;
+	}
+	else if (pec == -1) {
+		PyErr_SetString(PyExc_TypeError, 
+			"The pec attribute must be a boolean.");
+		return -1;
+	}
+
+	if (self->pec != pec) {
+		if (ioctl(self->fd, I2C_PEC, pec)) {
+			PyErr_SetFromErrno(PyExc_IOError);
+			return -1;
+		}
+		self->pec = pec;
+	}
+
+	return 0;
+}
+
+static PyGetSetDef SMBus_getset[] = {
+	{"pec", (getter)SMBus_get_pec, (setter)SMBus_set_pec,
+			"True if Packet Error Codes (PEC) are enabled"},
+	{NULL},
+};
+
+static PyTypeObject SMBus_type = {
+	PyObject_HEAD_INIT(NULL)
+	0,				/* ob_size */
+	"SMBus",			/* tp_name */
+	sizeof(SMBus),			/* tp_basicsize */
+	0,				/* tp_itemsize */
+	(destructor)SMBus_dealloc,	/* tp_dealloc */
+	0,				/* tp_print */
+	0,				/* tp_getattr */
+	0,				/* tp_setattr */
+	0,				/* tp_compare */
+	0,				/* tp_repr */
+	0,				/* tp_as_number */
+	0,				/* tp_as_sequence */
+	0,				/* tp_as_mapping */
+	0,				/* tp_hash */
+	0,				/* tp_call */
+	0,				/* tp_str */
+	0,				/* tp_getattro */
+	0,				/* tp_setattro */
+	0,				/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,		/* tp_flags */
+	SMBus_type_doc,			/* tp_doc */
+	0,				/* tp_traverse */
+	0,				/* tp_clear */
+	0,				/* tp_richcompare */
+	0,				/* tp_weaklistoffset */
+	0,				/* tp_iter */
+	0,				/* tp_iternext */
+	SMBus_methods,			/* tp_methods */
+	0,				/* tp_members */
+	SMBus_getset,			/* tp_getset */
+	0,				/* tp_base */
+	0,				/* tp_dict */
+	0,				/* tp_descr_get */
+	0,				/* tp_descr_set */
+	0,				/* tp_dictoffset */
+	(initproc)SMBus_init,		/* tp_init */
+	0,				/* tp_alloc */
+	SMBus_new,			/* tp_new */
+};
+
+static PyMethodDef SMBus_module_methods[] = {
+	{NULL}
+};
+
+#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+initsmbus(void) 
+{
+	PyObject* m;
+
+	if (PyType_Ready(&SMBus_type) < 0)
+		return;
+
+	m = Py_InitModule3("smbus", SMBus_module_methods, SMBus_module_doc);
+
+	Py_INCREF(&SMBus_type);
+	PyModule_AddObject(m, "SMBus", (PyObject *)&SMBus_type);
+}
+
diff --git a/i2c-tools-3.0.2/stub/Module.mk b/i2c-tools-3.0.2/stub/Module.mk
new file mode 100644
index 0000000..8ebcfcb
--- /dev/null
+++ b/i2c-tools-3.0.2/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/i2c-tools-3.0.2/stub/i2c-stub-from-dump b/i2c-tools-3.0.2/stub/i2c-stub-from-dump
new file mode 100755
index 0000000..f91da1c
--- /dev/null
+++ b/i2c-tools-3.0.2/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/i2c-tools-3.0.2/stub/i2c-stub-from-dump.8 b/i2c-tools-3.0.2/stub/i2c-stub-from-dump.8
new file mode 100644
index 0000000..b594839
--- /dev/null
+++ b/i2c-tools-3.0.2/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
diff --git a/i2c-tools-3.0.2/tools/Module.mk b/i2c-tools-3.0.2/tools/Module.mk
new file mode 100644
index 0000000..699a3b9
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/Module.mk
@@ -0,0 +1,84 @@
+# I2C tools for Linux
+#
+# Copyright (C) 2007  Jean Delvare <khali@linux-fr.org>
+#
+# Licensed under the GNU General Public License.
+
+TOOLS_DIR	:= tools
+
+TOOLS_CFLAGS	:= -Wstrict-prototypes -Wshadow -Wpointer-arith -Wcast-qual \
+		   -Wcast-align -Wwrite-strings -Wnested-externs -Winline \
+		   -W -Wundef -Wmissing-prototypes -Iinclude
+
+TOOLS_TARGETS	:= i2cdetect i2cdump i2cset i2cget
+
+#
+# Programs
+#
+
+$(TOOLS_DIR)/i2cdetect: $(TOOLS_DIR)/i2cdetect.o $(TOOLS_DIR)/i2cbusses.o
+	$(CC) $(LDFLAGS) -o $@ $^
+
+$(TOOLS_DIR)/i2cdump: $(TOOLS_DIR)/i2cdump.o $(TOOLS_DIR)/i2cbusses.o $(TOOLS_DIR)/util.o
+	$(CC) $(LDFLAGS) -o $@ $^
+
+$(TOOLS_DIR)/i2cset: $(TOOLS_DIR)/i2cset.o $(TOOLS_DIR)/i2cbusses.o $(TOOLS_DIR)/util.o
+	$(CC) $(LDFLAGS) -o $@ $^
+
+$(TOOLS_DIR)/i2cget: $(TOOLS_DIR)/i2cget.o $(TOOLS_DIR)/i2cbusses.o $(TOOLS_DIR)/util.o
+	$(CC) $(LDFLAGS) -o $@ $^
+
+#
+# Objects
+#
+
+$(TOOLS_DIR)/i2cdetect.o: $(TOOLS_DIR)/i2cdetect.c $(TOOLS_DIR)/i2cbusses.h
+	$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
+
+$(TOOLS_DIR)/i2cdump.o: $(TOOLS_DIR)/i2cdump.c $(TOOLS_DIR)/i2cbusses.h $(TOOLS_DIR)/util.h
+	$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
+
+$(TOOLS_DIR)/i2cset.o: $(TOOLS_DIR)/i2cset.c $(TOOLS_DIR)/i2cbusses.h $(TOOLS_DIR)/util.h
+	$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
+
+$(TOOLS_DIR)/i2cget.o: $(TOOLS_DIR)/i2cget.c $(TOOLS_DIR)/i2cbusses.h $(TOOLS_DIR)/util.h
+	$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
+
+$(TOOLS_DIR)/i2cbusses.o: $(TOOLS_DIR)/i2cbusses.c $(TOOLS_DIR)/i2cbusses.h
+	$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
+
+$(TOOLS_DIR)/util.o: $(TOOLS_DIR)/util.c $(TOOLS_DIR)/util.h
+	$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
+
+#
+# Commands
+#
+
+all-tools: $(addprefix $(TOOLS_DIR)/,$(TOOLS_TARGETS))
+
+strip-tools: $(addprefix $(TOOLS_DIR)/,$(TOOLS_TARGETS))
+	strip $(addprefix $(TOOLS_DIR)/,$(TOOLS_TARGETS))
+
+clean-tools:
+	$(RM) $(addprefix $(TOOLS_DIR)/,*.o $(TOOLS_TARGETS))
+
+install-tools: $(addprefix $(TOOLS_DIR)/,$(TOOLS_TARGETS))
+	$(INSTALL_DIR) $(DESTDIR)$(sbindir) $(DESTDIR)$(man8dir)
+	for program in $(TOOLS_TARGETS) ; do \
+	$(INSTALL_PROGRAM) $(TOOLS_DIR)/$$program $(DESTDIR)$(sbindir) ; \
+	$(INSTALL_DATA) $(TOOLS_DIR)/$$program.8 $(DESTDIR)$(man8dir) ; done
+
+uninstall-tools:
+	for program in $(TOOLS_TARGETS) ; do \
+	$(RM) $(DESTDIR)$(sbindir)/$$program ; \
+	$(RM) $(DESTDIR)$(man8dir)/$$program.8 ; done
+
+all: all-tools
+
+strip: strip-tools
+
+clean: clean-tools
+
+install: install-tools
+
+uninstall: uninstall-tools
diff --git a/i2c-tools-3.0.2/tools/i2cbusses.c b/i2c-tools-3.0.2/tools/i2cbusses.c
new file mode 100644
index 0000000..693c191
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cbusses.c
@@ -0,0 +1,414 @@
+/*
+    i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels.
+               Part of user-space programs to access for I2C
+               devices.
+    Copyright (c) 1999-2003  Frodo Looijaard <frodol@dds.nl> and
+                             Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Copyright (C) 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.
+*/
+
+/* For strdup */
+#define _BSD_SOURCE 1
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>	/* for NAME_MAX */
+#include <string.h>
+#include <strings.h>	/* for strcasecmp() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "i2cbusses.h"
+#include <linux/i2c-dev.h>
+
+enum adt { adt_dummy, adt_isa, adt_i2c, adt_smbus, adt_unknown };
+
+struct adap_type {
+	const char *funcs;
+	const char* algo;
+};
+
+static struct adap_type adap_types[5] = {
+	{ .funcs	= "dummy",
+	  .algo		= "Dummy bus", },
+	{ .funcs	= "isa",
+	  .algo		= "ISA bus", },
+	{ .funcs	= "i2c",
+	  .algo		= "I2C adapter", },
+	{ .funcs	= "smbus",
+	  .algo		= "SMBus adapter", },
+	{ .funcs	= "unknown",
+	  .algo		= "N/A", },
+};
+
+static enum adt i2c_get_funcs(int i2cbus)
+{
+	unsigned long funcs;
+	int file;
+	char filename[20];
+	enum adt ret;
+
+	file = open_i2c_dev(i2cbus, filename, 1);
+	if (file < 0)
+		return adt_unknown;
+
+	if (ioctl(file, I2C_FUNCS, &funcs) < 0)
+		ret = adt_unknown;
+	else if (funcs & I2C_FUNC_I2C)
+		ret = adt_i2c;
+	else if (funcs & (I2C_FUNC_SMBUS_BYTE |
+			  I2C_FUNC_SMBUS_BYTE_DATA |
+			  I2C_FUNC_SMBUS_WORD_DATA))
+		ret = adt_smbus;
+	else
+		ret = adt_dummy;
+
+	close(file);
+	return ret;
+}
+
+/* Remove trailing spaces from a string
+   Return the new string length including the trailing NUL */
+static int rtrim(char *s)
+{
+	int i;
+
+	for (i = strlen(s) - 1; i >= 0 && (s[i] == ' ' || s[i] == '\n'); i--)
+		s[i] = '\0';
+	return i + 2;
+}
+
+void free_adapters(struct i2c_adap *adapters)
+{
+	int i;
+
+	for (i = 0; adapters[i].name; i++)
+		free(adapters[i].name);
+	free(adapters);
+}
+
+/* We allocate space for the adapters in bunches. The last item is a
+   terminator, so here we start with room for 7 adapters, which should
+   be enough in most cases. If not, we allocate more later as needed. */
+#define BUNCH	8
+
+/* n must match the size of adapters at calling time */
+static struct i2c_adap *more_adapters(struct i2c_adap *adapters, int n)
+{
+	struct i2c_adap *new_adapters;
+
+	new_adapters = realloc(adapters, (n + BUNCH) * sizeof(struct i2c_adap));
+	if (!new_adapters) {
+		free_adapters(adapters);
+		return NULL;
+	}
+	memset(new_adapters + n, 0, BUNCH * sizeof(struct i2c_adap));
+
+	return new_adapters;
+}
+
+struct i2c_adap *gather_i2c_busses(void)
+{
+	char s[120];
+	struct dirent *de, *dde;
+	DIR *dir, *ddir;
+	FILE *f;
+	char fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX];
+	int foundsysfs = 0;
+	int count=0;
+	struct i2c_adap *adapters;
+
+	adapters = calloc(BUNCH, sizeof(struct i2c_adap));
+	if (!adapters)
+		return NULL;
+
+	/* look in /proc/bus/i2c */
+	if ((f = fopen("/proc/bus/i2c", "r"))) {
+		while (fgets(s, 120, f)) {
+			char *algo, *name, *type, *all;
+			int len_algo, len_name, len_type;
+			int i2cbus;
+
+			algo = strrchr(s, '\t');
+			*(algo++) = '\0';
+			len_algo = rtrim(algo);
+
+			name = strrchr(s, '\t');
+			*(name++) = '\0';
+			len_name = rtrim(name);
+
+			type = strrchr(s, '\t');
+			*(type++) = '\0';
+			len_type = rtrim(type);
+
+			sscanf(s, "i2c-%d", &i2cbus);
+
+			if ((count + 1) % BUNCH == 0) {
+				/* We need more space */
+				adapters = more_adapters(adapters, count + 1);
+				if (!adapters)
+					return NULL;
+			}
+
+			all = malloc(len_name + len_type + len_algo);
+			if (all == NULL) {
+				free_adapters(adapters);
+				return NULL;
+			}
+			adapters[count].nr = i2cbus;
+			adapters[count].name = strcpy(all, name);
+			adapters[count].funcs = strcpy(all + len_name, type);
+			adapters[count].algo = strcpy(all + len_name + len_type,
+						      algo);
+			count++;
+		}
+		fclose(f);
+		goto done;
+	}
+
+	/* look in sysfs */
+	/* First figure out where sysfs was mounted */
+	if ((f = fopen("/proc/mounts", "r")) == NULL) {
+		goto done;
+	}
+	while (fgets(n, NAME_MAX, f)) {
+		sscanf(n, "%*[^ ] %[^ ] %[^ ] %*s\n", sysfs, fstype);
+		if (strcasecmp(fstype, "sysfs") == 0) {
+			foundsysfs++;
+			break;
+		}
+	}
+	fclose(f);
+	if (! foundsysfs) {
+		goto done;
+	}
+
+	/* Bus numbers in i2c-adapter don't necessarily match those in
+	   i2c-dev and what we really care about are the i2c-dev numbers.
+	   Unfortunately the names are harder to get in i2c-dev */
+	strcat(sysfs, "/class/i2c-dev");
+	if(!(dir = opendir(sysfs)))
+		goto done;
+	/* go through the busses */
+	while ((de = readdir(dir)) != NULL) {
+		if (!strcmp(de->d_name, "."))
+			continue;
+		if (!strcmp(de->d_name, ".."))
+			continue;
+
+		/* this should work for kernels 2.6.5 or higher and */
+		/* is preferred because is unambiguous */
+		sprintf(n, "%s/%s/name", sysfs, de->d_name);
+		f = fopen(n, "r");
+		/* this seems to work for ISA */
+		if(f == NULL) {
+			sprintf(n, "%s/%s/device/name", sysfs, de->d_name);
+			f = fopen(n, "r");
+		}
+		/* non-ISA is much harder */
+		/* and this won't find the correct bus name if a driver
+		   has more than one bus */
+		if(f == NULL) {
+			sprintf(n, "%s/%s/device", sysfs, de->d_name);
+			if(!(ddir = opendir(n)))
+				continue;
+			while ((dde = readdir(ddir)) != NULL) {
+				if (!strcmp(dde->d_name, "."))
+					continue;
+				if (!strcmp(dde->d_name, ".."))
+					continue;
+				if ((!strncmp(dde->d_name, "i2c-", 4))) {
+					sprintf(n, "%s/%s/device/%s/name",
+						sysfs, de->d_name, dde->d_name);
+					if((f = fopen(n, "r")))
+						goto found;
+				}
+			}
+		}
+
+found:
+		if (f != NULL) {
+			int i2cbus;
+			enum adt type;
+			char *px;
+
+			px = fgets(s, 120, f);
+			fclose(f);
+			if (!px) {
+				fprintf(stderr, "%s: read error\n", n);
+				continue;
+			}
+			if ((px = strchr(s, '\n')) != NULL)
+				*px = 0;
+			if (!sscanf(de->d_name, "i2c-%d", &i2cbus))
+				continue;
+			if (!strncmp(s, "ISA ", 4)) {
+				type = adt_isa;
+			} else {
+				/* Attempt to probe for adapter capabilities */
+				type = i2c_get_funcs(i2cbus);
+			}
+
+			if ((count + 1) % BUNCH == 0) {
+				/* We need more space */
+				adapters = more_adapters(adapters, count + 1);
+				if (!adapters)
+					return NULL;
+			}
+
+			adapters[count].nr = i2cbus;
+			adapters[count].name = strdup(s);
+			if (adapters[count].name == NULL) {
+				free_adapters(adapters);
+				return NULL;
+			}
+			adapters[count].funcs = adap_types[type].funcs;
+			adapters[count].algo = adap_types[type].algo;
+			count++;
+		}
+	}
+	closedir(dir);
+
+done:
+	return adapters;
+}
+
+static int lookup_i2c_bus_by_name(const char *bus_name)
+{
+	struct i2c_adap *adapters;
+	int i, i2cbus = -1;
+
+	adapters = gather_i2c_busses();
+	if (adapters == NULL) {
+		fprintf(stderr, "Error: Out of memory!\n");
+		return -3;
+	}
+
+	/* Walk the list of i2c busses, looking for the one with the
+	   right name */
+	for (i = 0; adapters[i].name; i++) {
+		if (strcmp(adapters[i].name, bus_name) == 0) {
+			if (i2cbus >= 0) {
+				fprintf(stderr,
+					"Error: I2C bus name is not unique!\n");
+				i2cbus = -4;
+				goto done;
+			}
+			i2cbus = adapters[i].nr;
+		}
+	}
+
+	if (i2cbus == -1)
+		fprintf(stderr, "Error: I2C bus name doesn't match any "
+			"bus present!\n");
+
+done:
+	free_adapters(adapters);
+	return i2cbus;
+}
+
+/*
+ * Parse an I2CBUS command line argument and return the corresponding
+ * bus number, or a negative value if the bus is invalid.
+ */
+int lookup_i2c_bus(const char *i2cbus_arg)
+{
+	long i2cbus;
+	char *end;
+
+	i2cbus = strtol(i2cbus_arg, &end, 0);
+	if (*end || !*i2cbus_arg) {
+		/* Not a number, maybe a name? */
+		return lookup_i2c_bus_by_name(i2cbus_arg);
+	}
+	if (i2cbus < 0 || i2cbus > 0xff) {
+		fprintf(stderr, "Error: I2C bus out of range (0-255)!\n");
+		return -2;
+	}
+
+	return i2cbus;
+}
+
+/*
+ * Parse a CHIP-ADDRESS command line argument and return the corresponding
+ * chip address, or a negative value if the address is invalid.
+ */
+int parse_i2c_address(const char *address_arg)
+{
+	long address;
+	char *end;
+
+	address = strtol(address_arg, &end, 0);
+	if (*end || !*address_arg) {
+		fprintf(stderr, "Error: Chip address is not a number!\n");
+		return -1;
+	}
+	if (address < 0x03 || address > 0x77) {
+		fprintf(stderr, "Error: Chip address out of range "
+			"(0x03-0x77)!\n");
+		return -2;
+	}
+
+	return address;
+}
+
+int open_i2c_dev(const int i2cbus, char *filename, const int quiet)
+{
+	int file;
+
+	sprintf(filename, "/dev/i2c/%d", i2cbus);
+	file = open(filename, O_RDWR);
+
+	if (file < 0 && errno == ENOENT) {
+		sprintf(filename, "/dev/i2c-%d", i2cbus);
+		file = open(filename, O_RDWR);
+	}
+
+	if (file < 0 && !quiet) {
+		if (errno == ENOENT) {
+			fprintf(stderr, "Error: Could not open file "
+				"`/dev/i2c-%d' or `/dev/i2c/%d': %s\n",
+				i2cbus, i2cbus, strerror(ENOENT));
+		} else {
+			fprintf(stderr, "Error: Could not open file "
+				"`%s': %s\n", filename, strerror(errno));
+			if (errno == EACCES)
+				fprintf(stderr, "Run as root?\n");
+		}
+	}
+
+	return file;
+}
+
+int set_slave_addr(int file, int address, int force)
+{
+	/* With force, let the user read from/write to the registers
+	   even when a driver is also running */
+	if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) {
+		fprintf(stderr,
+			"Error: Could not set address to 0x%02x: %s\n",
+			address, strerror(errno));
+		return -errno;
+	}
+
+	return 0;
+}
diff --git a/i2c-tools-3.0.2/tools/i2cbusses.h b/i2c-tools-3.0.2/tools/i2cbusses.h
new file mode 100644
index 0000000..b089887
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cbusses.h
@@ -0,0 +1,42 @@
+/*
+    i2cbusses.h - Part of the i2c-tools package
+
+    Copyright (C) 2004-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.
+*/
+
+#ifndef _I2CBUSSES_H
+#define _I2CBUSSES_H
+
+struct i2c_adap {
+	int nr;
+	char *name;
+	const char *funcs;
+	const char *algo;
+};
+
+struct i2c_adap *gather_i2c_busses(void);
+void free_adapters(struct i2c_adap *adapters);
+
+int lookup_i2c_bus(const char *i2cbus_arg);
+int parse_i2c_address(const char *address_arg);
+int open_i2c_dev(const int i2cbus, char *filename, const int quiet);
+int set_slave_addr(int file, int address, int force);
+
+#define MISSING_FUNC_FMT	"Error: Adapter does not have %s capability\n"
+
+#endif
diff --git a/i2c-tools-3.0.2/tools/i2cdetect.8 b/i2c-tools-3.0.2/tools/i2cdetect.8
new file mode 100644
index 0000000..47cad04
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cdetect.8
@@ -0,0 +1,87 @@
+.TH I2CDETECT 8 "April 2008"
+.SH NAME
+i2cdetect \- detect I2C chips
+
+.SH SYNOPSIS
+.B i2cdetect
+.RI [ -y ]
+.RI [ -a ]
+.RI [ -q | -r ]
+.I i2cbus
+.RI [ "first last" ]
+.br
+.B i2cdetect
+.I -F
+.I i2cbus
+.br
+.B i2cdetect
+.I -V
+.br
+.B i2cdetect
+.I -l
+
+.SH DESCRIPTION
+i2cdetect is a userspace program to scan an I2C bus for devices. It
+outputs a table with the list of detected devices on the specified bus.
+\fIi2cbus\fR indicates the number or name of the I2C bus to be scanned, and
+should correspond to one of the busses listed by \fIi2cdetect -l\fR.
+The optional parameters \fIfirst\fR and \fIlast\fR restrict the scanning
+range (default: from 0x03 to 0x77).
+.PP
+i2cdetect can also be used to query the functionalities of an I2C bus
+(see option \fB-F\fP.)
+
+.SH WARNING
+This program can confuse your I2C bus, cause data loss and worse!
+
+.SH INTERPRETING THE OUTPUT
+Each cell in the output table will contain one of the following symbols:
+.IP \(bu "\w'\(bu'u+1n"
+"--". The address was probed but no chip answered.
+.IP \(bu
+"UU". Probing was skipped, because this address is currently in use by
+a driver. This strongly suggests that there is a chip at this address.
+.IP \(bu
+An address number in hexadecimal, e.g. "2d" or "4e". A chip
+was found at this address.
+
+.SH OPTIONS
+.TP
+.B "\-y"
+Disable interactive mode. By default, i2cdetect will wait for a confirmation
+from the user before messing with the I2C bus. When this flag is used, it
+will perform the operation directly. This is mainly meant to be used in
+scripts.
+.TP
+.B "\-a"
+Force scanning of non-regular addresses. Not recommended.
+.TP
+.B "\-q"
+Use SMBus "quick write" commands for probing (by default, the command
+used is the one believed to be the safest for each address). 
+Not recommended. This is known to corrupt the Atmel AT24RF08 EEPROM
+found on many IBM Thinkpad laptops.
+.TP
+.B "\-r"
+Use SMBus "read byte" commands for probing (by default, the command
+used is the one believed to be the safest for each address). 
+Not recommended. This is known to lock SMBus on various write-only
+chips (most notably clock chips at address 0x69).
+.TP
+.B "\-F"
+Display the list of functionalities implemented by the adapter and exit.
+.TP
+.B "\-V"
+Display the version and exit.
+.TP
+.B "\-l"
+Output a list of installed busses.
+
+.SH SEE ALSO
+i2cdump(8), sensors-detect(8)
+
+.SH AUTHOR
+Frodo Looijaard, Mark D. Studebaker and Jean Delvare
+
+This manual page was originally written by Aurelien Jarno
+<aurel32@debian.org>, for the Debian GNU/Linux system.
diff --git a/i2c-tools-3.0.2/tools/i2cdetect.c b/i2c-tools-3.0.2/tools/i2cdetect.c
new file mode 100644
index 0000000..4750db5
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cdetect.c
@@ -0,0 +1,357 @@
+/*
+    i2cdetect.c - a user-space program to scan for I2C devices
+    Copyright (C) 1999-2004  Frodo Looijaard <frodol@dds.nl>,
+                             Mark D. Studebaker <mdsxyz123@yahoo.com> and
+                             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.
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/i2c-dev.h>
+#include "i2cbusses.h"
+#include "../version.h"
+
+#define MODE_AUTO	0
+#define MODE_QUICK	1
+#define MODE_READ	2
+#define MODE_FUNC	3
+
+static void help(void)
+{
+	fprintf(stderr,
+		"Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]\n"
+		"       i2cdetect -F I2CBUS\n"
+		"       i2cdetect -l\n"
+		"  I2CBUS is an integer or an I2C bus name\n"
+		"  If provided, FIRST and LAST limit the probing range.\n");
+}
+
+static int scan_i2c_bus(int file, int mode, int first, int last)
+{
+	int i, j;
+	int res;
+
+	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
+
+	for (i = 0; i < 128; i += 16) {
+		printf("%02x: ", i);
+		for(j = 0; j < 16; j++) {
+			fflush(stdout);
+
+			/* Skip unwanted addresses */
+			if (i+j < first || i+j > last) {
+				printf("   ");
+				continue;
+			}
+
+			/* Set slave address */
+			if (ioctl(file, I2C_SLAVE, i+j) < 0) {
+				if (errno == EBUSY) {
+					printf("UU ");
+					continue;
+				} else {
+					fprintf(stderr, "Error: Could not set "
+						"address to 0x%02x: %s\n", i+j,
+						strerror(errno));
+					return -1;
+				}
+			}
+
+			/* Probe this address */
+			switch (mode) {
+			case MODE_QUICK:
+				/* This is known to corrupt the Atmel AT24RF08
+				   EEPROM */
+				res = i2c_smbus_write_quick(file,
+				      I2C_SMBUS_WRITE);
+				break;
+			case MODE_READ:
+				/* This is known to lock SMBus on various
+				   write-only chips (mainly clock chips) */
+				res = i2c_smbus_read_byte(file);
+				break;
+			default:
+				if ((i+j >= 0x30 && i+j <= 0x37)
+				 || (i+j >= 0x50 && i+j <= 0x5F))
+					res = i2c_smbus_read_byte(file);
+				else
+					res = i2c_smbus_write_quick(file,
+					      I2C_SMBUS_WRITE);
+			}
+
+			if (res < 0)
+				printf("-- ");
+			else
+				printf("%02x ", i+j);
+		}
+		printf("\n");
+	}
+
+	return 0;
+}
+
+struct func
+{
+	long value;
+	const char* name;
+};
+
+static const struct func all_func[] = {
+	{ .value = I2C_FUNC_I2C,
+	  .name = "I2C" },
+	{ .value = I2C_FUNC_SMBUS_QUICK,
+	  .name = "SMBus Quick Command" },
+	{ .value = I2C_FUNC_SMBUS_WRITE_BYTE,
+	  .name = "SMBus Send Byte" },
+	{ .value = I2C_FUNC_SMBUS_READ_BYTE,
+	  .name = "SMBus Receive Byte" },
+	{ .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
+	  .name = "SMBus Write Byte" },
+	{ .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
+	  .name = "SMBus Read Byte" },
+	{ .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
+	  .name = "SMBus Write Word" },
+	{ .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
+	  .name = "SMBus Read Word" },
+	{ .value = I2C_FUNC_SMBUS_PROC_CALL,
+	  .name = "SMBus Process Call" },
+	{ .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
+	  .name = "SMBus Block Write" },
+	{ .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
+	  .name = "SMBus Block Read" },
+	{ .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
+	  .name = "SMBus Block Process Call" },
+	{ .value = I2C_FUNC_SMBUS_PEC,
+	  .name = "SMBus PEC" },
+	{ .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
+	  .name = "I2C Block Write" },
+	{ .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
+	  .name = "I2C Block Read" },
+	{ .value = 0, .name = "" }
+};
+
+static void print_functionality(unsigned long funcs)
+{
+	int i;
+
+	for (i = 0; all_func[i].value; i++) {
+		printf("%-32s %s\n", all_func[i].name,
+		       (funcs & all_func[i].value) ? "yes" : "no");
+	}
+}
+
+/*
+ * Print the installed i2c busses. The format is those of Linux 2.4's
+ * /proc/bus/i2c for historical compatibility reasons.
+ */
+static void print_i2c_busses(void)
+{
+	struct i2c_adap *adapters;
+	int count;
+
+	adapters = gather_i2c_busses();
+	if (adapters == NULL) {
+		fprintf(stderr, "Error: Out of memory!\n");
+		return;
+	}
+
+	for (count = 0; adapters[count].name; count++) {
+		printf("i2c-%d\t%-10s\t%-32s\t%s\n",
+			adapters[count].nr, adapters[count].funcs,
+			adapters[count].name, adapters[count].algo);
+	}
+
+	free_adapters(adapters);
+}
+
+int main(int argc, char *argv[])
+{
+	char *end;
+	int i2cbus, file, res;
+	char filename[20];
+	unsigned long funcs;
+	int mode = MODE_AUTO;
+	int first = 0x03, last = 0x77;
+	int flags = 0;
+	int yes = 0, version = 0, list = 0;
+
+	/* handle (optional) flags first */
+	while (1+flags < argc && argv[1+flags][0] == '-') {
+		switch (argv[1+flags][1]) {
+		case 'V': version = 1; break;
+		case 'y': yes = 1; break;
+		case 'l': list = 1; break;
+		case 'F':
+			if (mode != MODE_AUTO && mode != MODE_FUNC) {
+				fprintf(stderr, "Error: Different modes "
+					"specified!\n");
+				exit(1);
+			}
+			mode = MODE_FUNC;
+			break;
+		case 'r':
+			if (mode == MODE_QUICK) {
+				fprintf(stderr, "Error: Different modes "
+					"specified!\n");
+				exit(1);
+			}
+			mode = MODE_READ;
+			break;
+		case 'q':
+			if (mode == MODE_READ) {
+				fprintf(stderr, "Error: Different modes "
+					"specified!\n");
+				exit(1);
+			}
+			mode = MODE_QUICK;
+			break;
+		case 'a':
+			first = 0x00;
+			last = 0x7F;
+			break;
+		default:
+			fprintf(stderr, "Error: Unsupported option "
+				"\"%s\"!\n", argv[1+flags]);
+			help();
+			exit(1);
+		}
+		flags++;
+	}
+
+	if (version) {
+		fprintf(stderr, "i2cdetect version %s\n", VERSION);
+		exit(0);
+	}
+
+	if (list) {
+		print_i2c_busses();
+		exit(0);
+	}
+
+	if (argc < flags + 2) {
+		fprintf(stderr, "Error: No i2c-bus specified!\n");
+		help();
+		exit(1);
+	}
+	i2cbus = lookup_i2c_bus(argv[flags+1]);
+	if (i2cbus < 0) {
+		help();
+		exit(1);
+	}
+
+	/* read address range if present */
+	if (argc == flags + 4 && mode != MODE_FUNC) {
+		int tmp;
+
+		tmp = strtol(argv[flags+2], &end, 0);
+		if (*end) {
+			fprintf(stderr, "Error: FIRST argment not a "
+				"number!\n");
+			help();
+			exit(1);
+		}
+		if (tmp < first || tmp > last) {
+			fprintf(stderr, "Error: FIRST argument out of range "
+				"(0x%02x-0x%02x)!\n", first, last);
+			help();
+			exit(1);
+		}
+		first = tmp;
+
+		tmp = strtol(argv[flags+3], &end, 0);
+		if (*end) {
+			fprintf(stderr, "Error: LAST argment not a "
+				"number!\n");
+			help();
+			exit(1);
+		}
+		if (tmp < first || tmp > last) {
+			fprintf(stderr, "Error: LAST argument out of range "
+				"(0x%02x-0x%02x)!\n", first, last);
+			help();
+			exit(1);
+		}
+		last = tmp;
+	} else if (argc != flags + 2) {
+		help();
+		exit(1);
+	}
+
+	file = open_i2c_dev(i2cbus, filename, 0);
+	if (file < 0) {
+		exit(1);
+	}
+
+	if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
+		fprintf(stderr, "Error: Could not get the adapter "
+			"functionality matrix: %s\n", strerror(errno));
+		close(file);
+		exit(1);
+	}
+
+	/* Special case, we only list the implemented functionalities */
+	if (mode == MODE_FUNC) {
+		close(file);
+		printf("Functionalities implemented by %s:\n", filename);
+		print_functionality(funcs);
+		exit(0);
+	}
+
+	if (mode != MODE_READ && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
+		fprintf(stderr, "Error: Can't use SMBus Quick Write command "
+			"on this bus (ISA bus?)\n");
+		close(file);
+		exit(1);
+	}
+	if (mode != MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
+		fprintf(stderr, "Error: Can't use SMBus Read Byte command "
+			"on this bus (ISA bus?)\n");
+		close(file);
+		exit(1);
+	}
+
+	if (!yes) {
+		char s[2];
+
+		fprintf(stderr, "WARNING! This program can confuse your I2C "
+			"bus, cause data loss and worse!\n");
+
+		fprintf(stderr, "I will probe file %s%s.\n", filename,
+			mode==MODE_QUICK?" using quick write commands":
+			mode==MODE_READ?" using read byte commands":"");
+		fprintf(stderr, "I will probe address range 0x%02x-0x%02x.\n",
+			first, last);
+
+		fprintf(stderr, "Continue? [Y/n] ");
+		fflush(stderr);
+		if (!fgets(s, 2, stdin)
+		 || (s[0] != '\n' && s[0] != 'y' && s[0] != 'Y')) {
+			fprintf(stderr, "Aborting on user request.\n");
+			exit(0);
+		}
+	}
+
+	res = scan_i2c_bus(file, mode, first, last);
+
+	close(file);
+
+	exit(res?1:0);
+}
diff --git a/i2c-tools-3.0.2/tools/i2cdump.8 b/i2c-tools-3.0.2/tools/i2cdump.8
new file mode 100644
index 0000000..7a02a47
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cdump.8
@@ -0,0 +1,84 @@
+.TH I2CDUMP 8 "May 2008"
+.SH NAME
+i2cdump \- examine I2C registers
+
+.SH SYNOPSIS
+.B i2cdump
+.RB [ -f ]
+.RB [ "-r first-last" ]
+.RB [ -y ]
+.I i2cbus
+.I address
+.RI [ "mode " [ "bank " [ bankreg ]]]
+.br
+.B i2cdump
+.B -V
+
+.SH DESCRIPTION
+i2cdump is a small helper program to examine registers
+visible through the I2C bus.
+
+.SH OPTIONS
+.TP
+.B -V
+Display the version and exit.
+.TP
+.B -f
+Force access to the device even if it is already busy. By default, i2cdump
+will refuse to access a device which is already under the control of a
+kernel driver. Using this flag is dangerous, it can seriously confuse the
+kernel driver in question. It can also cause i2cdump to return invalid
+results. So use at your own risk and only if you know what you're doing.
+.TP
+.B -r first-last
+Limit the range of registers being accessed. This option is only available
+with modes \fBb\fP, \fBw\fP, \fBc\fP and \fBW\fP. For mode \fBW\fP,
+\fBfirst\fR must be even and \fBlast\fR must be odd.
+.TP
+.B -y
+Disable interactive mode. By default, i2cdump will wait for a confirmation
+from the user before messing with the I2C bus. When this flag is used, it
+will perform the operation directly. This is mainly meant to be used in
+scripts.
+.PP
+At least two options must be provided to i2cdump. \fIi2cbus\fR indicates the
+number or name of the I2C bus to be scanned. This number should correspond to one
+of the busses listed by \fIi2cdetect -l\fR. \fIaddress\fR indicates the
+address to be scanned on that bus, and is an integer between 0x03 and 0x77.
+.PP
+The \fImode\fR parameter, if specified, is one of the letters \fBb\fP, \fBw\fP,
+\fBs\fP, or \fBi\fP, corresponding to a read size of a single byte, a 16-bit
+word, an SMBus block, an I2C block, respectively. The \fBc\fP mode is a
+little different, it reads all bytes consecutively, and is useful for chips that
+have an address auto-increment feature, such as EEPROMs. The \fBW\fP mode is
+also special, it is similar to \fBw\fP except that a read command will only
+be issued on even register addresses; this is again mainly useful for EEPROMs.
+.PP
+A \fBp\fP can also be appended to the \fImode\fR parameter (except for
+\fBi\fP and \fBW\fP) to enable PEC. If the \fImode\fR parameter is omitted,
+i2cdump defaults to byte access without PEC.
+.PP
+The \fIbank\fR and \fIbankreg\fR parameters are useful on the W83781D and
+similar chips (at the time of writing, all Winbond and Asus chips).
+\fIbank\fR is an integer between 0 and 7, and \fIbankreg\fR is an integer
+between 0x00 and 0xFF (default value: 0x4E). The W83781D data sheet has more
+information on bank selection.
+
+.SH WARNING
+i2cdump can be dangerous if used improperly. Most notably, the \fBc\fP mode
+starts with WRITING a byte to the chip. On most chips it will be stored in the
+address pointer register, which is OK, but some chips with a single register
+or no (visible) register at all will most likely see this as a real WRITE,
+resulting in possible misbehavior or corruption. Do not use i2cdump
+on random addresses. Anyway, it is of little use unless you have good
+knowledge of the chip you're working with and an idea of what you are looking
+for.
+
+.SH SEE ALSO
+i2cset(8), i2cdetect(8), isadump(8)
+
+.SH AUTHOR
+Frodo Looijaard, Mark D. Studebaker and Jean Delvare
+
+This manual page was originally written by David Z Maze <dmaze@debian.org> for
+the Debian GNU/Linux system.
diff --git a/i2c-tools-3.0.2/tools/i2cdump.c b/i2c-tools-3.0.2/tools/i2cdump.c
new file mode 100644
index 0000000..84b4bca
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cdump.c
@@ -0,0 +1,487 @@
+/*
+    i2cdump.c - a user-space program to dump I2C registers
+    Copyright (C) 2002-2003  Frodo Looijaard <frodol@dds.nl>, and
+                             Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Copyright (C) 2004-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.
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/i2c-dev.h>
+#include "i2cbusses.h"
+#include "util.h"
+#include "../version.h"
+
+static void help(void)
+{
+	fprintf(stderr,
+		"Usage: i2cdump [-f] [-y] [-r first-last] I2CBUS ADDRESS [MODE [BANK [BANKREG]]]\n"
+		"  I2CBUS is an integer or an I2C bus name\n"
+		"  ADDRESS is an integer (0x03 - 0x77)\n"
+		"  MODE is one of:\n"
+		"    b (byte, default)\n"
+		"    w (word)\n"
+		"    W (word on even register addresses)\n"
+		"    s (SMBus block)\n"
+		"    i (I2C block)\n"
+		"    c (consecutive byte)\n"
+		"    Append p for SMBus PEC\n");
+}
+
+static int check_funcs(int file, int size, int pec)
+{
+	unsigned long funcs;
+
+	/* check adapter functionality */
+	if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
+		fprintf(stderr, "Error: Could not get the adapter "
+			"functionality matrix: %s\n", strerror(errno));
+		return -1;
+	}
+
+	switch(size) {
+	case I2C_SMBUS_BYTE:
+		if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus receive byte");
+			return -1;
+		}
+		if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
+			return -1;
+		}
+		break;
+
+	case I2C_SMBUS_BYTE_DATA:
+		if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus read byte");
+			return -1;
+		}
+		break;
+
+	case I2C_SMBUS_WORD_DATA:
+		if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus read word");
+			return -1;
+		}
+		break;
+
+	case I2C_SMBUS_BLOCK_DATA:
+		if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus block read");
+			return -1;
+		}
+		break;
+
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "I2C block read");
+			return -1;
+		}
+		break;
+	}
+
+	if (pec
+	 && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
+		fprintf(stderr, "Warning: Adapter does "
+			"not seem to support PEC\n");
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	char *end;
+	int i, j, res, i2cbus, address, size, file;
+	int bank = 0, bankreg = 0x4E, old_bank = 0;
+	char filename[20];
+	int block[256], s_length = 0;
+	int pec = 0, even = 0;
+	int flags = 0;
+	int force = 0, yes = 0, version = 0;
+	const char *range = NULL;
+	int first = 0x00, last = 0xff;
+
+	/* handle (optional) flags first */
+	while (1+flags < argc && argv[1+flags][0] == '-') {
+		switch (argv[1+flags][1]) {
+		case 'V': version = 1; break;
+		case 'f': force = 1; break;
+		case 'r': range = argv[1+(++flags)]; break;
+		case 'y': yes = 1; break;
+		default:
+			fprintf(stderr, "Error: Unsupported option "
+				"\"%s\"!\n", argv[1+flags]);
+			help();
+			exit(1);
+		}
+		flags++;
+	}
+
+	if (version) {
+		fprintf(stderr, "i2cdump version %s\n", VERSION);
+		exit(0);
+	}
+
+	if (argc < flags + 2) {
+		fprintf(stderr, "Error: No i2c-bus specified!\n");
+		help();
+		exit(1);
+	}
+	i2cbus = lookup_i2c_bus(argv[flags+1]);
+	if (i2cbus < 0) {
+		help();
+		exit(1);
+	}
+
+	if (argc < flags + 3) {
+		fprintf(stderr, "Error: No address specified!\n");
+		help();
+		exit(1);
+	}
+	address = parse_i2c_address(argv[flags+2]);
+	if (address < 0) {
+		help();
+		exit(1);
+	}
+
+	if (argc < flags + 4) {
+		fprintf(stderr, "No size specified (using byte-data access)\n");
+		size = I2C_SMBUS_BYTE_DATA;
+	} else if (!strncmp(argv[flags+3], "b", 1)) {
+		size = I2C_SMBUS_BYTE_DATA;
+		pec = argv[flags+3][1] == 'p';
+	} else if (!strncmp(argv[flags+3], "w", 1)) {
+		size = I2C_SMBUS_WORD_DATA;
+		pec = argv[flags+3][1] == 'p';
+	} else if (!strncmp(argv[flags+3], "W", 1)) {
+		size = I2C_SMBUS_WORD_DATA;
+		even = 1;
+	} else if (!strncmp(argv[flags+3], "s", 1)) {
+		size = I2C_SMBUS_BLOCK_DATA;
+		pec = argv[flags+3][1] == 'p';
+	} else if (!strncmp(argv[flags+3], "c", 1)) {
+		size = I2C_SMBUS_BYTE;
+		pec = argv[flags+3][1] == 'p';
+	} else if (!strcmp(argv[flags+3], "i"))
+		size = I2C_SMBUS_I2C_BLOCK_DATA;
+	else {
+		fprintf(stderr, "Error: Invalid mode!\n");
+		help();
+		exit(1);
+	}
+
+	if (argc > flags + 4) {
+		bank = strtol(argv[flags+4], &end, 0);
+		if (*end || size == I2C_SMBUS_I2C_BLOCK_DATA) {
+			fprintf(stderr, "Error: Invalid bank number!\n");
+			help();
+			exit(1);
+		}
+		if ((size == I2C_SMBUS_BYTE_DATA || size == I2C_SMBUS_WORD_DATA)
+		 && (bank < 0 || bank > 15)) {
+			fprintf(stderr, "Error: bank out of range!\n");
+			help();
+			exit(1);
+		}
+		if (size == I2C_SMBUS_BLOCK_DATA
+		 && (bank < 0 || bank > 0xff)) {
+			fprintf(stderr, "Error: block command out of range!\n");
+			help();
+			exit(1);
+		}
+
+		if (argc > flags + 5) {
+			bankreg = strtol(argv[flags+5], &end, 0);
+			if (*end || size == I2C_SMBUS_BLOCK_DATA) {
+				fprintf(stderr, "Error: Invalid bank register "
+					"number!\n");
+				help();
+				exit(1);
+			}
+			if (bankreg < 0 || bankreg > 0xff) {
+				fprintf(stderr, "Error: bank out of range "
+					"(0-0xff)!\n");
+				help();
+				exit(1);
+			}
+		}
+	}
+
+	/* Parse optional range string */
+	if (range) {
+		char *dash;
+
+		first = strtol(range, &dash, 0);
+		if (dash == range || *dash != '-'
+		 || first < 0 || first > 0xff) {
+			fprintf(stderr, "Error: Invalid range parameter!\n");
+			exit(1);
+		}
+		last = strtol(++dash, &end, 0);
+		if (end == dash || *end != '\0'
+		 || last < first || last > 0xff) {
+			fprintf(stderr, "Error: Invalid range parameter!\n");
+			exit(1);
+		}
+
+		/* Check mode constraints */
+		switch (size) {
+		case I2C_SMBUS_BYTE:
+		case I2C_SMBUS_BYTE_DATA:
+			break;
+		case I2C_SMBUS_WORD_DATA:
+			if (!even || (!(first%2) && last%2))
+				break;
+			/* Fall through */
+		default:
+			fprintf(stderr,
+				"Error: Range parameter not compatible with selected mode!\n");
+			exit(1);
+		}
+	}
+
+	file = open_i2c_dev(i2cbus, filename, 0);
+	if (file < 0
+	 || check_funcs(file, size, pec)
+	 || set_slave_addr(file, address, force))
+		exit(1);
+
+	if (pec) {
+		if (ioctl(file, I2C_PEC, 1) < 0) {
+			fprintf(stderr, "Error: Could not set PEC: %s\n",
+				strerror(errno));
+			exit(1);
+		}
+	}
+
+	if (!yes) {
+		fprintf(stderr, "WARNING! This program can confuse your I2C "
+			"bus, cause data loss and worse!\n");
+
+		fprintf(stderr, "I will probe file %s, address 0x%x, mode "
+			"%s\n", filename, address,
+			size == I2C_SMBUS_BLOCK_DATA ? "smbus block" :
+			size == I2C_SMBUS_I2C_BLOCK_DATA ? "i2c block" :
+			size == I2C_SMBUS_BYTE ? "byte consecutive read" :
+			size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
+		if (pec)
+			fprintf(stderr, "PEC checking enabled.\n");
+		if (even)
+			fprintf(stderr, "Only probing even register "
+				"addresses.\n");
+		if (bank) {
+			if (size == I2C_SMBUS_BLOCK_DATA)
+				fprintf(stderr, "Using command 0x%02x.\n",
+					bank);
+			else
+				fprintf(stderr, "Probing bank %d using bank "
+					"register 0x%02x.\n", bank, bankreg);
+		}
+		if (range) {
+			fprintf(stderr,
+				"Probe range limited to 0x%02x-0x%02x.\n",
+				first, last);
+		}
+
+		fprintf(stderr, "Continue? [Y/n] ");
+		fflush(stderr);
+		if (!user_ack(1)) {
+			fprintf(stderr, "Aborting on user request.\n");
+			exit(0);
+		}
+	}
+
+	/* See Winbond w83781d data sheet for bank details */
+	if (bank && size != I2C_SMBUS_BLOCK_DATA) {
+		res = i2c_smbus_read_byte_data(file, bankreg);
+		if (res >= 0) {
+			old_bank = res;
+			res = i2c_smbus_write_byte_data(file, bankreg,
+				bank | (old_bank & 0xf0));
+		}
+		if (res < 0) {
+			fprintf(stderr, "Error: Bank switching failed\n");
+			exit(1);
+		}
+	}
+
+	/* handle all but word data */
+	if (size != I2C_SMBUS_WORD_DATA || even) {
+		/* do the block transaction */
+		if (size == I2C_SMBUS_BLOCK_DATA
+		 || size == I2C_SMBUS_I2C_BLOCK_DATA) {
+			unsigned char cblock[288];
+
+			if (size == I2C_SMBUS_BLOCK_DATA) {
+				res = i2c_smbus_read_block_data(file, bank,
+				      cblock);
+				/* Remember returned block length for a nicer
+				   display later */
+				s_length = res;
+			} else {
+				for (res = 0; res < 256; res += i) {
+					i = i2c_smbus_read_i2c_block_data(file,
+						res, 32, cblock + res);
+					if (i <= 0) {
+						res = i;
+						break;
+					}
+				}
+			}
+			if (res <= 0) {
+				fprintf(stderr, "Error: Block read failed, "
+					"return code %d\n", res);
+				exit(1);
+			}
+			if (res >= 256)
+				res = 256;
+			for (i = 0; i < res; i++)
+				block[i] = cblock[i];
+			if (size != I2C_SMBUS_BLOCK_DATA)
+				for (i = res; i < 256; i++)
+					block[i] = -1;
+		}
+
+		if (size == I2C_SMBUS_BYTE) {
+			res = i2c_smbus_write_byte(file, first);
+			if(res != 0) {
+				fprintf(stderr, "Error: Write start address "
+					"failed, return code %d\n", res);
+				exit(1);
+			}
+		}
+
+		printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f"
+		       "    0123456789abcdef\n");
+		for (i = 0; i < 256; i+=16) {
+			if (size == I2C_SMBUS_BLOCK_DATA && i >= s_length)
+				break;
+			if (i/16 < first/16)
+				continue;
+			if (i/16 > last/16)
+				break;
+
+			printf("%02x: ", i);
+			for (j = 0; j < 16; j++) {
+				fflush(stdout);
+				/* Skip unwanted registers */
+				if (i+j < first || i+j > last) {
+					printf("   ");
+					if (size == I2C_SMBUS_WORD_DATA) {
+						printf("   ");
+						j++;
+					}
+					continue;
+				}
+
+				if (size == I2C_SMBUS_BYTE_DATA) {
+					block[i+j] = res =
+					  i2c_smbus_read_byte_data(file, i+j);
+				} else if (size == I2C_SMBUS_WORD_DATA) {
+					res = i2c_smbus_read_word_data(file,
+								       i+j);
+					if (res < 0) {
+						block[i+j] = res;
+						block[i+j+1] = res;
+					} else {
+						block[i+j] = res & 0xff;
+						block[i+j+1] = res >> 8;
+					}
+				} else if (size == I2C_SMBUS_BYTE) {
+					block[i+j] = res =
+					  i2c_smbus_read_byte(file);
+				} else
+					res = block[i+j];
+
+				if (size == I2C_SMBUS_BLOCK_DATA
+				 && i+j >= s_length) {
+					printf("   ");
+				} else if (res < 0) {
+					printf("XX ");
+					if (size == I2C_SMBUS_WORD_DATA)
+						printf("XX ");
+				} else {
+					printf("%02x ", block[i+j]);
+					if (size == I2C_SMBUS_WORD_DATA)
+						printf("%02x ", block[i+j+1]);
+				}
+				if (size == I2C_SMBUS_WORD_DATA)
+					j++;
+			}
+			printf("   ");
+
+			for (j = 0; j < 16; j++) {
+				if (size == I2C_SMBUS_BLOCK_DATA
+				 && i+j >= s_length)
+					break;
+				/* Skip unwanted registers */
+				if (i+j < first || i+j > last) {
+					printf(" ");
+					continue;
+				}
+
+				res = block[i+j];
+				if (res < 0)
+					printf("X");
+				else
+				if ((res & 0xff) == 0x00
+				 || (res & 0xff) == 0xff)
+					printf(".");
+				else
+				if ((res & 0xff) < 32
+				 || (res & 0xff) >= 127)
+					printf("?");
+				else
+					printf("%c", res & 0xff);
+			}
+			printf("\n");
+		}
+	} else {
+		printf("     0,8  1,9  2,a  3,b  4,c  5,d  6,e  7,f\n");
+		for (i = 0; i < 256; i+=8) {
+			if (i/8 < first/8)
+				continue;
+			if (i/8 > last/8)
+				break;
+
+			printf("%02x: ", i);
+			for (j = 0; j < 8; j++) {
+				/* Skip unwanted registers */
+				if (i+j < first || i+j > last) {
+					printf("     ");
+					continue;
+				}
+
+				res = i2c_smbus_read_word_data(file, i+j);
+				if (res < 0)
+					printf("XXXX ");
+				else
+					printf("%04x ", res & 0xffff);
+			}
+			printf("\n");
+		}
+	}
+	if (bank && size != I2C_SMBUS_BLOCK_DATA) {
+		i2c_smbus_write_byte_data(file, bankreg, old_bank);
+	}
+	exit(0);
+}
diff --git a/i2c-tools-3.0.2/tools/i2cget.8 b/i2c-tools-3.0.2/tools/i2cget.8
new file mode 100644
index 0000000..8786603
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cget.8
@@ -0,0 +1,68 @@
+.TH I2CGET 8 "May 2008"
+.SH "NAME"
+i2cget \- read from I2C/SMBus chip registers
+
+.SH SYNOPSIS
+.B i2cget
+.RB [ -f ]
+.RB [ -y ]
+.I i2cbus
+.I chip-address
+.RI [ "data-address " [ mode ]]
+.br
+.B i2cget
+.B -V
+
+.SH DESCRIPTION
+i2cget is a small helper program to read registers visible through the I2C
+bus (or SMBus).
+
+.SH OPTIONS
+.TP
+.B -V
+Display the version and exit.
+.TP
+.B -f
+Force access to the device even if it is already busy. By default, i2cget
+will refuse to access a device which is already under the control of a
+kernel driver. Using this flag is dangerous, it can seriously confuse the
+kernel driver in question. It can also cause i2cget to return an invalid
+value. So use at your own risk and only if you know what you're doing.
+.TP
+.B -y
+Disable interactive mode. By default, i2cget will wait for a confirmation
+from the user before messing with the I2C bus. When this flag is used, it
+will perform the operation directly. This is mainly meant to be used in
+scripts. Use with caution.
+.PP
+There are two required options to i2cget. \fIi2cbus\fR indicates the number
+or name of the I2C bus to be scanned.  This number should correspond to one of
+the busses listed by \fIi2cdetect -l\fR. \fIchip-address\fR specifies the
+address of the chip on that bus, and is an integer between 0x03 and 0x77.
+.PP
+\fIdata-address\fR specifies the address on that chip to read from, and is
+an integer between 0x00 and 0xFF. If omitted, the currently active register
+will be read (if that makes sense for the considered chip).
+.PP
+The \fImode\fR parameter, if specified, is one of the letters \fBb\fP,
+\fBw\fP or \fBc\fP, corresponding to a read byte data, a read word data or a
+write byte/read byte transaction, respectively. A \fBp\fP can also be appended
+to the \fImode\fR parameter to enable PEC. If the \fImode\fR parameter is omitted,
+i2cget defaults to a read byte data transaction, unless \fIdata-address\fR is
+also omitted, in which case the default (and only valid) transaction is a
+single read byte.
+
+.SH WARNING
+i2cget can be extremely dangerous if used improperly. I2C and SMBus are designed
+in such a way that an SMBus read transaction can be seen as a write transaction by
+certain chips. This is particularly true if setting \fImode\fR to \fBcp\fP (write byte/read
+byte with PEC). Be extremely careful using this program.
+
+.SH SEE ALSO
+i2cdump(8), i2cset(8)
+
+.SH AUTHOR
+Jean Delvare
+
+This manual page was strongly inspired from those written by David Z Maze
+for i2cset.
diff --git a/i2c-tools-3.0.2/tools/i2cget.c b/i2c-tools-3.0.2/tools/i2cget.c
new file mode 100644
index 0000000..32a68e5
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cget.c
@@ -0,0 +1,256 @@
+/*
+    i2cget.c - A user-space program to read an I2C register.
+    Copyright (C) 2005-2008  Jean Delvare <khali@linux-fr.org>
+
+    Based on i2cset.c:
+    Copyright (C) 2001-2003  Frodo Looijaard <frodol@dds.nl>, and
+                             Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Copyright (C) 2004-2005  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.
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/i2c-dev.h>
+#include "i2cbusses.h"
+#include "util.h"
+#include "../version.h"
+
+static void help(void) __attribute__ ((noreturn));
+
+static void help(void)
+{
+	fprintf(stderr,
+		"Usage: i2cget [-f] [-y] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]\n"
+		"  I2CBUS is an integer or an I2C bus name\n"
+		"  ADDRESS is an integer (0x03 - 0x77)\n"
+		"  MODE is one of:\n"
+		"    b (read byte data, default)\n"
+		"    w (read word data)\n"
+		"    c (write byte/read byte)\n"
+		"    Append p for SMBus PEC\n");
+	exit(1);
+}
+
+static int check_funcs(int file, int size, int daddress, int pec)
+{
+	unsigned long funcs;
+
+	/* check adapter functionality */
+	if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
+		fprintf(stderr, "Error: Could not get the adapter "
+			"functionality matrix: %s\n", strerror(errno));
+		return -1;
+	}
+
+	switch (size) {
+	case I2C_SMBUS_BYTE:
+		if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus receive byte");
+			return -1;
+		}
+		if (daddress >= 0
+		 && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
+			return -1;
+		}
+		break;
+
+	case I2C_SMBUS_BYTE_DATA:
+		if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus read byte");
+			return -1;
+		}
+		break;
+
+	case I2C_SMBUS_WORD_DATA:
+		if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus read word");
+			return -1;
+		}
+		break;
+	}
+
+	if (pec
+	 && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
+		fprintf(stderr, "Warning: Adapter does "
+			"not seem to support PEC\n");
+	}
+
+	return 0;
+}
+
+static int confirm(const char *filename, int address, int size, int daddress,
+		   int pec)
+{
+	int dont = 0;
+
+	fprintf(stderr, "WARNING! This program can confuse your I2C "
+		"bus, cause data loss and worse!\n");
+
+	/* Don't let the user break his/her EEPROMs */
+	if (address >= 0x50 && address <= 0x57 && pec) {
+		fprintf(stderr, "STOP! EEPROMs are I2C devices, not "
+			"SMBus devices. Using PEC\non I2C devices may "
+			"result in unexpected results, such as\n"
+			"trashing the contents of EEPROMs. We can't "
+			"let you do that, sorry.\n");
+		return 0;
+	}
+
+	if (size == I2C_SMBUS_BYTE && daddress >= 0 && pec) {
+		fprintf(stderr, "WARNING! All I2C chips and some SMBus chips "
+			"will interpret a write\nbyte command with PEC as a"
+			"write byte data command, effectively writing a\n"
+			"value into a register!\n");
+		dont++;
+	}
+
+	fprintf(stderr, "I will read from device file %s, chip "
+		"address 0x%02x, ", filename, address);
+	if (daddress < 0)
+		fprintf(stderr, "current data\naddress");
+	else
+		fprintf(stderr, "data address\n0x%02x", daddress);
+	fprintf(stderr, ", using %s.\n",
+		size == I2C_SMBUS_BYTE ? (daddress < 0 ?
+		"read byte" : "write byte/read byte") :
+		size == I2C_SMBUS_BYTE_DATA ? "read byte data" :
+		"read word data");
+	if (pec)
+		fprintf(stderr, "PEC checking enabled.\n");
+
+	fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n");
+	fflush(stderr);
+	if (!user_ack(!dont)) {
+		fprintf(stderr, "Aborting on user request.\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	char *end;
+	int res, i2cbus, address, size, file;
+	int daddress;
+	char filename[20];
+	int pec = 0;
+	int flags = 0;
+	int force = 0, yes = 0, version = 0;
+
+	/* handle (optional) flags first */
+	while (1+flags < argc && argv[1+flags][0] == '-') {
+		switch (argv[1+flags][1]) {
+		case 'V': version = 1; break;
+		case 'f': force = 1; break;
+		case 'y': yes = 1; break;
+		default:
+			fprintf(stderr, "Error: Unsupported option "
+				"\"%s\"!\n", argv[1+flags]);
+			help();
+			exit(1);
+		}
+		flags++;
+	}
+
+	if (version) {
+		fprintf(stderr, "i2cget version %s\n", VERSION);
+		exit(0);
+	}
+
+	if (argc < flags + 3)
+		help();
+
+	i2cbus = lookup_i2c_bus(argv[flags+1]);
+	if (i2cbus < 0)
+		help();
+
+	address = parse_i2c_address(argv[flags+2]);
+	if (address < 0)
+		help();
+
+	if (argc > flags + 3) {
+		size = I2C_SMBUS_BYTE_DATA;
+		daddress = strtol(argv[flags+3], &end, 0);
+		if (*end || daddress < 0 || daddress > 0xff) {
+			fprintf(stderr, "Error: Data address invalid!\n");
+			help();
+		}
+	} else {
+		size = I2C_SMBUS_BYTE;
+		daddress = -1;
+	}
+
+	if (argc > flags + 4) {
+		switch (argv[flags+4][0]) {
+		case 'b': size = I2C_SMBUS_BYTE_DATA; break;
+		case 'w': size = I2C_SMBUS_WORD_DATA; break;
+		case 'c': size = I2C_SMBUS_BYTE; break;
+		default:
+			fprintf(stderr, "Error: Invalid mode!\n");
+			help();
+		}
+		pec = argv[flags+4][1] == 'p';
+	}
+
+	file = open_i2c_dev(i2cbus, filename, 0);
+	if (file < 0
+	 || check_funcs(file, size, daddress, pec)
+	 || set_slave_addr(file, address, force))
+		exit(1);
+
+	if (!yes && !confirm(filename, address, size, daddress, pec))
+		exit(0);
+
+	if (pec && ioctl(file, I2C_PEC, 1) < 0) {
+		fprintf(stderr, "Error: Could not set PEC: %s\n",
+			strerror(errno));
+		close(file);
+		exit(1);
+	}
+
+	switch (size) {
+	case I2C_SMBUS_BYTE:
+		if (daddress >= 0) {
+			res = i2c_smbus_write_byte(file, daddress);
+			if (res < 0)
+				fprintf(stderr, "Warning - write failed\n");
+		}
+		res = i2c_smbus_read_byte(file);
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		res = i2c_smbus_read_word_data(file, daddress);
+		break;
+	default: /* I2C_SMBUS_BYTE_DATA */
+		res = i2c_smbus_read_byte_data(file, daddress);
+	}
+	close(file);
+
+	if (res < 0) {
+		fprintf(stderr, "Error: Read failed\n");
+		exit(2);
+	}
+
+	printf("0x%0*x\n", size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
+
+	exit(0);
+}
diff --git a/i2c-tools-3.0.2/tools/i2cset.8 b/i2c-tools-3.0.2/tools/i2cset.8
new file mode 100644
index 0000000..2b4ce3a
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cset.8
@@ -0,0 +1,91 @@
+.TH I2CSET 8 "November 2008"
+.SH "NAME"
+i2cset \- set I2C registers
+
+.SH SYNOPSIS
+.B i2cset
+.RB [ -f ]
+.RB [ -y ]
+.RB [ "-m mask" ]
+.RB [ -r ]
+.I i2cbus
+.I chip-address
+.I data-address
+.RI [ "value " [ "mode" ]]
+.br
+.B i2cset
+.B -V
+
+.SH DESCRIPTION
+i2cset is a small helper program to set registers visible through the I2C
+bus.
+
+.SH OPTIONS
+.TP
+.B -V
+Display the version and exit.
+.TP
+.B -f
+Force access to the device even if it is already busy. By default, i2cset
+will refuse to access a device which is already under the control of a
+kernel driver. Using this flag is dangerous, it can seriously confuse the
+kernel driver in question. It can also cause i2cset to silently write to
+the wrong register. So use at your own risk and only if you know what
+you're doing.
+.TP
+.B -y
+Disable interactive mode. By default, i2cset will wait for a confirmation
+from the user before messing with the I2C bus. When this flag is used, it
+will perform the operation directly. This is mainly meant to be used in
+scripts.
+.TP
+.B -m mask
+The \fImask\fR parameter, if specified, describes which bits of \fIvalue\fR
+will be actually written to \fIdata-address\fR. Bits set to 1 in the mask
+are taken from \fIvalue\fR, while bits set to 0 will be read from
+\fIdata-address\fR and thus preserved by the operation. Please note that
+this parameter assumes that the read and write operations for the specified
+mode are symmetrical for the device you are accessing. This may or may not
+be the case, as neither I2C nor SMBus guarantees this.
+.TP
+.B -r
+Read back the value right after writing it, and compare the result with the
+value written. This used to be the default behavior. The same limitations
+apply as those of option \fB-m\fR.
+.PP
+There are three required options to i2cset. \fIi2cbus\fR indicates the number
+or name of the I2C bus to be scanned.  This number should correspond to one of
+the busses listed by \fIi2cdetect -l\fR. \fIchip-address\fR specifies the
+address of the chip on that bus, and is an integer between 0x03 and 0x77.
+\fIdata-address\fR specifies the address on that chip to write to, and is an
+integer between 0x00 and 0xFF.
+.PP
+The \fIvalue\fR parameter, if specified, is the value to write to that
+location on the chip. If this parameter is omited, then a short write is
+issued. For most chips, it simply sets an internal pointer to the target
+location, but doesn't actually write to that location. For a few chips
+though, in particular simple ones with a single register, this short write
+is an actual write.
+.PP
+The \fImode\fR parameter, if specified, is one of the letters \fBb\fP or
+\fBw\fP, corresponding to a write size of a single byte or a 16-bit word,
+respectively. A \fBp\fP can also be appended to the \fImode\fR parameter to
+enable PEC. If the \fImode\fR parameter is omitted, i2cset defaults to byte
+mode without PEC. The \fIvalue\fR provided must be within range for the
+specified data type (0x00-0xFF for bytes, 0x0000-0xFFFF for words).
+
+.SH WARNING
+i2cset can be extremely dangerous if used improperly. It can confuse your
+I2C bus, cause data loss, or have more serious side effects. Writing to
+a serial EEPROM on a memory DIMM (chip addresses between 0x50 and 0x57) may
+DESTROY your memory, leaving your system unbootable!  Be extremely careful
+using this program.
+
+.SH SEE ALSO
+i2cdump(8), isaset(8)
+
+.SH AUTHOR
+Frodo Looijaard, Mark D. Studebaker and Jean Delvare
+
+This manual page was originally written by David Z Maze <dmaze@debian.org> for
+the Debian GNU/Linux system.
diff --git a/i2c-tools-3.0.2/tools/i2cset.c b/i2c-tools-3.0.2/tools/i2cset.c
new file mode 100644
index 0000000..296abe1
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/i2cset.c
@@ -0,0 +1,344 @@
+/*
+    i2cset.c - A user-space program to write an I2C register.
+    Copyright (C) 2001-2003  Frodo Looijaard <frodol@dds.nl>, and
+                             Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Copyright (C) 2004-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.
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/i2c-dev.h>
+#include "i2cbusses.h"
+#include "util.h"
+#include "../version.h"
+
+static void help(void) __attribute__ ((noreturn));
+
+static void help(void)
+{
+	fprintf(stderr,
+	        "Usage: i2cset [-f] [-y] [-m MASK] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE [MODE]]\n"
+		"  I2CBUS is an integer or an I2C bus name\n"
+		"  ADDRESS is an integer (0x03 - 0x77)\n"
+		"  MODE is one of:\n"
+		"    b (byte, default)\n"
+		"    w (word)\n"
+		"    Append p for SMBus PEC\n");
+	exit(1);
+}
+
+static int check_funcs(int file, int size, int pec)
+{
+	unsigned long funcs;
+
+	/* check adapter functionality */
+	if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
+		fprintf(stderr, "Error: Could not get the adapter "
+			"functionality matrix: %s\n", strerror(errno));
+		return -1;
+	}
+
+	switch (size) {
+	case I2C_SMBUS_BYTE:
+		if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
+			return -1;
+		}
+		break;
+
+	case I2C_SMBUS_BYTE_DATA:
+		if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus write byte");
+			return -1;
+		}
+		break;
+
+	case I2C_SMBUS_WORD_DATA:
+		if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
+			fprintf(stderr, MISSING_FUNC_FMT, "SMBus write word");
+			return -1;
+		}
+		break;
+	}
+
+	if (pec
+	 && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
+		fprintf(stderr, "Warning: Adapter does "
+			"not seem to support PEC\n");
+	}
+
+	return 0;
+}
+
+static int confirm(const char *filename, int address, int size, int daddress,
+		   int value, int vmask, int pec)
+{
+	int dont = 0;
+
+	fprintf(stderr, "WARNING! This program can confuse your I2C "
+		"bus, cause data loss and worse!\n");
+
+	if (address >= 0x50 && address <= 0x57) {
+		fprintf(stderr, "DANGEROUS! Writing to a serial "
+			"EEPROM on a memory DIMM\nmay render your "
+			"memory USELESS and make your system "
+			"UNBOOTABLE!\n");
+		dont++;
+	}
+
+	fprintf(stderr, "I will write to device file %s, chip address "
+		"0x%02x, data address\n0x%02x, ", filename, address, daddress);
+	if (size == I2C_SMBUS_BYTE)
+		fprintf(stderr, "no data.\n");
+	else
+		fprintf(stderr, "data 0x%02x%s, mode %s.\n", value,
+			vmask ? " (masked)" : "",
+			size == I2C_SMBUS_BYTE_DATA ? "byte" : "word");
+	if (pec)
+		fprintf(stderr, "PEC checking enabled.\n");
+
+	fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n");
+	fflush(stderr);
+	if (!user_ack(!dont)) {
+		fprintf(stderr, "Aborting on user request.\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	char *end;
+	const char *maskp = NULL;
+	int res, i2cbus, address, size, file;
+	int value, daddress, vmask = 0;
+	char filename[20];
+	int pec = 0;
+	int flags = 0;
+	int force = 0, yes = 0, version = 0, readback = 0;
+
+	/* handle (optional) flags first */
+	while (1+flags < argc && argv[1+flags][0] == '-') {
+		switch (argv[1+flags][1]) {
+		case 'V': version = 1; break;
+		case 'f': force = 1; break;
+		case 'y': yes = 1; break;
+		case 'm':
+			if (2+flags < argc)
+				maskp = argv[2+flags];
+			flags++;
+			break;
+		case 'r': readback = 1; break;
+		default:
+			fprintf(stderr, "Error: Unsupported option "
+				"\"%s\"!\n", argv[1+flags]);
+			help();
+			exit(1);
+		}
+		flags++;
+	}
+
+	if (version) {
+		fprintf(stderr, "i2cset version %s\n", VERSION);
+		exit(0);
+	}
+
+	if (argc < flags + 4)
+		help();
+
+	i2cbus = lookup_i2c_bus(argv[flags+1]);
+	if (i2cbus < 0)
+		help();
+
+	address = parse_i2c_address(argv[flags+2]);
+	if (address < 0)
+		help();
+
+	daddress = strtol(argv[flags+3], &end, 0);
+	if (*end || daddress < 0 || daddress > 0xff) {
+		fprintf(stderr, "Error: Data address invalid!\n");
+		help();
+	}
+
+	if (argc > flags + 4) {
+		size = I2C_SMBUS_BYTE_DATA;
+		value = strtol(argv[flags+4], &end, 0);
+		if (*end || value < 0) {
+			fprintf(stderr, "Error: Data value invalid!\n");
+			help();
+		}
+	} else {
+		size = I2C_SMBUS_BYTE;
+		value = -1;
+	}
+
+	if (argc > flags + 5) {
+		switch (argv[flags+5][0]) {
+		case 'b': size = I2C_SMBUS_BYTE_DATA; break;
+		case 'w': size = I2C_SMBUS_WORD_DATA; break;
+		default:
+			fprintf(stderr, "Error: Invalid mode!\n");
+			help();
+		}
+		pec = argv[flags+5][1] == 'p';
+	}
+
+	/* Old method to provide the value mask, deprecated and no longer
+	   documented but still supported for compatibility */
+	if (argc > flags + 6) {
+		if (maskp) {
+			fprintf(stderr, "Error: Data value mask provided twice!\n");
+			help();
+		}
+		fprintf(stderr, "Warning: Using deprecated way to set the data value mask!\n");
+		fprintf(stderr, "         Please switch to using -m.\n");
+		maskp = argv[flags+6];
+	}
+
+	if (maskp) {
+		vmask = strtol(maskp, &end, 0);
+		if (*end || vmask == 0) {
+			fprintf(stderr, "Error: Data value mask invalid!\n");
+			help();
+		}
+	}
+
+	if ((size == I2C_SMBUS_BYTE_DATA && value > 0xff)
+	 || (size == I2C_SMBUS_WORD_DATA && value > 0xffff)) {
+		fprintf(stderr, "Error: Data value out of range!\n");
+		help();
+	}
+
+	file = open_i2c_dev(i2cbus, filename, 0);
+	if (file < 0
+	 || check_funcs(file, size, pec)
+	 || set_slave_addr(file, address, force))
+		exit(1);
+
+	if (!yes && !confirm(filename, address, size, daddress,
+			     value, vmask, pec))
+		exit(0);
+
+	if (vmask) {
+		int oldvalue;
+
+		switch (size) {
+		case I2C_SMBUS_BYTE:
+			oldvalue = i2c_smbus_read_byte(file);
+			break;
+		case I2C_SMBUS_WORD_DATA:
+			oldvalue = i2c_smbus_read_word_data(file, daddress);
+			break;
+		default:
+			oldvalue = i2c_smbus_read_byte_data(file, daddress);
+		}
+
+		if (oldvalue < 0) {
+			fprintf(stderr, "Error: Failed to read old value\n");
+			exit(1);
+		}
+
+		value = (value & vmask) | (oldvalue & ~vmask);
+
+		if (!yes) {
+			fprintf(stderr, "Old value 0x%0*x, write mask "
+				"0x%0*x: Will write 0x%0*x to register "
+				"0x%02x\n",
+				size == I2C_SMBUS_WORD_DATA ? 4 : 2, oldvalue,
+				size == I2C_SMBUS_WORD_DATA ? 4 : 2, vmask,
+				size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
+				daddress);
+
+			fprintf(stderr, "Continue? [Y/n] ");
+			fflush(stderr);
+			if (!user_ack(1)) {
+				fprintf(stderr, "Aborting on user request.\n");
+				exit(0);
+			}
+		}
+	}
+
+	if (pec && ioctl(file, I2C_PEC, 1) < 0) {
+		fprintf(stderr, "Error: Could not set PEC: %s\n",
+			strerror(errno));
+		close(file);
+		exit(1);
+	}
+
+	switch (size) {
+	case I2C_SMBUS_BYTE:
+		res = i2c_smbus_write_byte(file, daddress);
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		res = i2c_smbus_write_word_data(file, daddress, value);
+		break;
+	default: /* I2C_SMBUS_BYTE_DATA */
+		res = i2c_smbus_write_byte_data(file, daddress, value);
+	}
+	if (res < 0) {
+		fprintf(stderr, "Error: Write failed\n");
+		close(file);
+		exit(1);
+	}
+
+	if (pec) {
+		if (ioctl(file, I2C_PEC, 0) < 0) {
+			fprintf(stderr, "Error: Could not clear PEC: %s\n",
+				strerror(errno));
+			close(file);
+			exit(1);
+		}
+	}
+
+	if (!readback) { /* We're done */
+		close(file);
+		exit(0);
+	}
+
+	switch (size) {
+	case I2C_SMBUS_BYTE:
+		res = i2c_smbus_read_byte(file);
+		value = daddress;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		res = i2c_smbus_read_word_data(file, daddress);
+		break;
+	default: /* I2C_SMBUS_BYTE_DATA */
+		res = i2c_smbus_read_byte_data(file, daddress);
+	}
+	close(file);
+
+	if (res < 0) {
+		printf("Warning - readback failed\n");
+	} else
+	if (res != value) {
+		printf("Warning - data mismatch - wrote "
+		       "0x%0*x, read back 0x%0*x\n",
+		       size == I2C_SMBUS_WORD_DATA ? 4 : 2, value,
+		       size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
+	} else {
+		printf("Value 0x%0*x written, readback matched\n",
+		       size == I2C_SMBUS_WORD_DATA ? 4 : 2, value);
+	}
+
+	exit(0);
+}
diff --git a/i2c-tools-3.0.2/tools/util.c b/i2c-tools-3.0.2/tools/util.c
new file mode 100644
index 0000000..029719e
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/util.c
@@ -0,0 +1,48 @@
+/*
+    util.c - helper functions
+    Copyright (C) 2006 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.
+*/
+
+#include <stdio.h>
+#include "util.h"
+
+/* Return 1 if we should continue, 0 if we should abort */
+int user_ack(int def)
+{
+	char s[2];
+	int ret;
+
+	if (!fgets(s, 2, stdin))
+		return 0; /* Nack by default */
+
+	switch (s[0]) {
+	case 'y':
+	case 'Y':
+		ret = 1;
+		break;
+	case 'n':
+	case 'N':
+		ret = 0;
+		break;
+	default:
+		ret = def;
+	}
+
+	/* Flush extra characters */
+	while (s[0] != '\n') {
+		int c = fgetc(stdin);
+		if (c == EOF) {
+			ret = 0;
+			break;
+		}
+		s[0] = c;
+	}
+
+	return ret;
+}
+
diff --git a/i2c-tools-3.0.2/tools/util.h b/i2c-tools-3.0.2/tools/util.h
new file mode 100644
index 0000000..a179b19
--- /dev/null
+++ b/i2c-tools-3.0.2/tools/util.h
@@ -0,0 +1,16 @@
+/*
+    util - helper functions
+    Copyright (C) 2006 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.
+*/
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+extern int user_ack(int def);
+
+#endif /* _UTIL_H */
diff --git a/i2c-tools-3.0.2/version.h b/i2c-tools-3.0.2/version.h
new file mode 100644
index 0000000..48057bc
--- /dev/null
+++ b/i2c-tools-3.0.2/version.h
@@ -0,0 +1 @@
+#define VERSION "3.0.2"
diff --git a/i2c-tools.tar.bz2 b/i2c-tools.tar.bz2
new file mode 100644
index 0000000..2135abb
--- /dev/null
+++ b/i2c-tools.tar.bz2
Binary files differ
diff --git a/i2c-tools.url b/i2c-tools.url
new file mode 100644
index 0000000..61c877e
--- /dev/null
+++ b/i2c-tools.url
@@ -0,0 +1 @@
+http://dl.lm-sensors.org/i2c-tools/releases/i2c-tools-3.0.2.tar.bz2
diff --git a/i2c-tools.version b/i2c-tools.version
new file mode 100644
index 0000000..b502146
--- /dev/null
+++ b/i2c-tools.version
@@ -0,0 +1 @@
+3.0.2