Anonymous avatar Anonymous committed 13482e7

Added the i2c bus protocol

Comments (0)

Files changed (43)

libs/i2c-tools-3.1.0/CHANGES

+i2c-tools CHANGES
+-----------------
+
+3.1.0 (2011-12-04)
+  decode-dimms: Decode module configuration type of DDR SDRAM
+                Decode refresh rate of DDR SDRAM
+                Add support for the at24 kernel driver
+  i2c-dev.h: Make value arrays const for block write functions
+  i2cset: Add support for SMBus and I2C block writes
+          Removed obsolete method to specify value mask
+          More stringent parameter validation
+
+3.0.3 (2010-12-12)
+  Makefile: Let the environment set CC and CFLAGS
+            Integrate py-smbus into the build system
+  README: Point users to the linux-i2c mailing list
+  decode-dimms: Handle CRC of FB-DIMM and DDR3 SDRAM memory modules
+                Add support for DDR3 SDRAM
+                Fix decoding of SDR SDRAM bytes 12-14
+                Add side-by-side formatting option
+                Add merged cells formatting option
+                Try harder to decode the manufacturing date
+                Handle read errors on sysfs
+                Decode voltage interface level of DDR SDRAM
+  decode-xeon: Delete
+  eepromer: Fix array initialization overrun
+  i2cdetect: Drop legacy reference to ISA bus
+  i2cset: Add support for short writes with PEC
+  i2c-stub-from-dump: Use udev settle to speed up initialization
+                      Unload i2c-stub automatically if needed
+                      Add support for multiple dumps
+  tools: Properly handle /dev/i2c not being a directory
+         Increase limit on I2C bus number
+
+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

libs/i2c-tools-3.1.0/COPYING

+		    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.

libs/i2c-tools-3.1.0/Makefile

+# I2C tools for Linux
+#
+# Copyright (C) 2007  Jean Delvare <khali@linux-fr.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+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	?= -O2
+# When debugging, use the following instead
+#CFLAGS	:= -O -g
+CFLAGS	+= -Wall
+
+KERNELVERSION	:= $(shell uname -r)
+
+.PHONY: all strip clean install uninstall
+
+all:
+
+EXTRA	:=
+#EXTRA	+= py-smbus
+SRCDIRS	:= include eeprom stub tools $(EXTRA)
+include $(SRCDIRS:%=%/Module.mk)

libs/i2c-tools-3.1.0/README

+I2C TOOLS FOR LINUX
+===================
+
+This package contains an heterogeneous set of I2C tools for the Linux kernel.
+These tools were originally part of the lm-sensors project but were finally
+split into their own package for convenience. They compile, run and have been
+tested on GNU/Linux.
+
+
+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.
+
+If you wish to include sub-directories that are not enabled by default, then
+just set them via the EXTRA make variable. For example, to build py-smbus,
+do:
+  $ make EXTRA="py-smbus"
+
+
+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.
+
+
+QUESTIONS AND BUG REPORTS
+-------------------------
+
+Please post your questions and bug reports to the linux-i2c mailing list:
+  linux-i2c@vger.kernel.org
+For additional information about this list, see:
+  http://vger.kernel.org/vger-lists.html#linux-i2c

libs/i2c-tools-3.1.0/eeprom/Module.mk

+# EEPROM decoding scripts for the Linux eeprom driver
+#
+# 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.
+
+EEPROM_DIR	:= eeprom
+
+EEPROM_TARGETS	:= decode-dimms decode-vaio ddcmon decode-edid
+
+#
+# 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

libs/i2c-tools-3.1.0/eeprom/README

+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.

libs/i2c-tools-3.1.0/eeprom/ddcmon

+#!/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;
+	}
+}

libs/i2c-tools-3.1.0/eeprom/decode-dimms

+#!/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-2011  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_side_by_side $opt_merge
+	    $opt_igncheck $use_sysfs $use_hexdump $sbs_col_width
+	    @vendors %decode_callback $revision @dimm $current %hexdump_cache);
+
+use constant LITTLEENDIAN	=> "little-endian";
+use constant BIGENDIAN		=> "big-endian";
+
+$revision = '$Revision: 5929 $ ($Date: 2011-02-16 14:58:38 +0100 (mer. 16 févr. 2011) $)';
+$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);
+}
+
+# New encoding format (as of DDR3) for manufacturer just has a count of
+# leading 0x7F rather than all the individual bytes.  The count bytes includes
+# parity!
+sub manufacturer_ddr3($$)
+{
+	my ($count, $code) = @_;
+	return "Invalid" if parity($count) != 1;
+	return "Invalid" if parity($code) != 1;
+	return (($code & 0x7F) - 1 > $vendors[$count & 0x7F]) ? "Unknown" :
+		$vendors[$count & 0x7F][($code & 0x7F) - 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;
+	if (parity($ai) == 0) {
+		$ai |= 0x80;
+	}
+	return (manufacturer_ddr3($ai, $first), \@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 } @_);
+}
+
+# Real printing functions
+
+sub html_encode($)
+{
+	my $text = shift;
+	$text =~ s/</\&lt;/sg;
+	$text =~ s/>/\&gt;/sg;
+	$text =~ s/\n/<br>\n/sg;
+	return $text;
+}
+
+sub same_values(@)
+{
+	my $value = shift;
+	while (@_) {
+		return 0 unless $value eq shift;
+	}
+	return 1;
+}
+
+sub real_printl($$) # print a line w/ label and values
+{
+	my ($label, @values) = @_;
+	local $_;
+	my $same_values = same_values(@values);
+
+	# If all values are N/A, don't bother printing
+	return if $values[0] eq "N/A" and $same_values;
+
+	if ($opt_html) {
+		$label = html_encode($label);
+		@values = map { html_encode($_) } @values;
+		print "<tr><td valign=top>$label</td>";
+		if ($opt_merge && $same_values) {
+			print "<td colspan=".(scalar @values).">$values[0]</td>";
+		} else {
+			print "<td>$_</td>" foreach @values;
+		}
+		print "</tr>\n";
+	} else {
+		if ($opt_merge && $same_values) {
+			splice(@values, 1);
+		}
+
+		my $format = "%-47s".((" %-".$sbs_col_width."s") x (scalar @values - 1))." %s\n";
+		my $maxl = 0; # Keep track of the max number of lines
+
+		# It's a bit tricky because each value may span over more than
+		# one line. We can easily extract the values per column, but
+		# we need them per line at printing time. So we have to
+		# prepare a 2D array with all the individual string fragments.
+		my ($col, @lines);
+		for ($col = 0; $col < @values; $col++) {
+			my @cells = split /\n/, $values[$col];
+			$maxl = @cells if @cells > $maxl;
+			for (my $l = 0; $l < @cells; $l++) {
+				$lines[$l]->[$col] = $cells[$l];
+			}
+		}
+
+		# Also make sure there are no holes in the array
+		for (my $l = 0; $l < $maxl; $l++) {
+			for ($col = 0; $col < @values; $col++) {
+				$lines[$l]->[$col] = ""
+					if not defined $lines[$l]->[$col];
+			}
+		}
+
+		printf $format, $label, @{shift @lines};
+		printf $format, "", @{$_} foreach (@lines);
+	}
+}
+
+sub printl2($$) # print a line w/ label and value (outside a table)
+{
+	my ($label, $value) = @_;
+	if ($opt_html) {
+		$label = html_encode($label);
+		$value = html_encode($value);
+	}
+	print "$label: $value\n";
+}
+
+sub real_prints($) # print separator w/ given text
+{
+	my ($label, $ncol) = @_;
+	$ncol = 1 unless $ncol;
+	if ($opt_html) {
+		$label = html_encode($label);
+		print "<tr><td align=center colspan=".(1+$ncol)."><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 = html_encode($header);
+		$sub = html_encode($sub);
+		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 = html_encode($comment);
+		print "<!-- $comment -->\n";
+	} else {
+		print "# $comment\n";
+	}
+}
+
+# Fake printing functions
+# These don't actually print anything, instead they store the desired
+# output for later processing.
+
+sub printl($$) # print a line w/ label and value
+{
+	my @output = (\&real_printl, @_);
+	push @{$dimm[$current]->{output}}, \@output;
+}
+
+sub printl_cond($$$) # same as printl but conditional
+{
+	my ($cond, $label, $value) = @_;
+	return unless $cond || $opt_side_by_side;
+	printl($label, $cond ? $value : "N/A");
+}
+
+sub prints($) # print separator w/ given text
+{
+	my @output = (\&real_prints, @_);
+	push @{$dimm[$current]->{output}}, \@output;
+}
+
+# Helper functions
+
+sub tns($) # print a time in ns
+{
+	return sprintf("%3.2f ns", $_[0]);
+}
+
+sub tns3($) # print a time in ns, with 3 decimal digits
+{
+	return sprintf("%.3f ns", $_[0]);
+}
+
+sub value_or_undefined
+{
+	my ($value, $unit) = @_;
+	return "Undefined!" unless $value;
+	$value .= " $unit" if defined $unit;
+	return $value;
+}
+
+# Common to SDR, DDR and DDR2 SDRAM
+sub sdram_voltage_interface_level($)
+{
+	my @levels = (
+		"TTL (5V tolerant)",		#  0
+		"LVTTL (not 5V tolerant)",	#  1
+		"HSTL 1.5V",			#  2
+		"SSTL 3.3V",			#  3
+		"SSTL 2.5V",			#  4
+		"SSTL 1.8V",			#  5
+	);
+	
+	return ($_[0] < @levels) ? $levels[$_[0]] : "Undefined!";
+}
+
+# Common to SDR and DDR SDRAM
+sub sdram_module_configuration_type($)
+{
+	my @types = (
+		"No Parity",			# 0
+		"Parity",			# 1
+		"ECC",				# 2
+	);
+
+	return ($_[0] < @types) ? $types[$_[0]] : "Undefined!";
+}
+
+# Parameter: EEPROM bytes 0-127 (using 3-62)
+sub decode_sdr_sdram($)
+{
+	my $bytes = shift;
+	my $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("Size", "INVALID: " . $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));
+
+	if ($bytes->[3] == 0) { $temp = "Undefined!"; }
+	elsif ($bytes->[3] == 1) { $temp = "1/16"; }
+	elsif ($bytes->[3] == 2) { $temp = "2/17"; }
+	elsif ($bytes->[3] == 3) { $temp = "3/18"; }
+	else { $temp = $bytes->[3]; }
+	printl("Number of Row Address Bits", $temp);
+
+	if ($bytes->[4] == 0) { $temp = "Undefined!"; }
+	elsif ($bytes->[4] == 1) { $temp = "1/16"; }
+	elsif ($bytes->[4] == 2) { $temp = "2/17"; }
+	elsif ($bytes->[4] == 3) { $temp = "3/18"; }
+	else { $temp = $bytes->[4]; }
+	printl("Number of Col Address Bits", $temp);
+
+	printl("Number of Module Rows", value_or_undefined($bytes->[5]));
+
+	if ($bytes->[7] > 1) { $temp = "Undefined!"; }
+	else { $temp = ($bytes->[7] * 256) + $bytes->[6]; }
+	printl("Data Width", $temp);
+
+	printl("Voltage Interface Level",
+	       sdram_voltage_interface_level($bytes->[8]));
+
+	printl("Module Configuration Type",
+	       sdram_module_configuration_type($bytes->[11]));
+
+	printl("Refresh Rate", ddr2_refresh_rate($bytes->[12]));
+
+	if ($bytes->[13] & 0x80) { $temp = "Bank2 = 2 x Bank1"; }
+	else { $temp = "No Bank2 OR Bank2 = Bank1 width"; }
+	printl("Primary SDRAM Component Bank Config", $temp);
+	printl("Primary SDRAM Component Widths",
+	       value_or_undefined($bytes->[13] & 0x7f));
+
+	if ($bytes->[14] & 0x80) { $temp = "Bank2 = 2 x Bank1"; }
+	else { $temp = "No Bank2 OR Bank2 = Bank1 width"; }
+	printl("Error Checking SDRAM Component Bank Config", $temp);
+	printl("Error Checking SDRAM Component Widths",
+	       value_or_undefined($bytes->[14] & 0x7f));
+
+	printl("Min Clock Delay for Back to Back Random Access",
+	       value_or_undefined($bytes->[15]));
+
+	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("Supported Burst Lengths", $temp);
+
+	printl("Number of Device Banks",
+	       value_or_undefined($bytes->[17]));
+
+	printl("Supported CAS Latencies", cas_latencies(@cas));
+
+	@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);
+
+	my ($cycle_time, $access_time);
+
+	if (@cas >= 1) {
+		$cycle_time = "$ctime ns at CAS ".$cas[$#cas];
+
+		$temp = ($bytes->[10] >> 4) + ($bytes->[10] & 0xf) * 0.1;
+		$access_time = "$temp ns at CAS ".$cas[$#cas];
+	}
+
+	if (@cas >= 2 && spd_written(@$bytes[23..24])) {
+		$temp = $bytes->[23] >> 4;
+		if ($temp == 0) { $temp = "Undefined!"; }
+		else {
+			$temp += 15 if $temp < 4;
+			$temp += ($bytes->[23] & 0xf) * 0.1;
+			$temp .= " ns";
+		}
+		$cycle_time .= "\n$temp ns at CAS ".$cas[$#cas-1];
+
+		$temp = $bytes->[24] >> 4;
+		if ($temp == 0) { $temp = "Undefined!"; }
+		else {
+			$temp += 15 if $temp < 4;
+			$temp += ($bytes->[24] & 0xf) * 0.1;
+			$temp .= " ns";
+		}
+		$access_time .= "\n$temp ns at CAS ".$cas[$#cas-1];
+	}
+
+	if (@cas >= 3 && spd_written(@$bytes[25..26])) {
+		$temp = $bytes->[25] >> 2;
+		if ($temp == 0) { $temp = "Undefined!"; }
+		else {
+			$temp += ($bytes->[25] & 0x3) * 0.25;
+			$temp .= " ns";
+		}
+		$cycle_time .= "\n$temp ns at CAS ".$cas[$#cas-2];
+
+		$temp = $bytes->[26] >> 2;
+		if ($temp == 0) { $temp = "Undefined!"; }
+		else {
+			$temp += ($bytes->[26] & 0x3) * 0.25;
+			$temp .= " ns";
+		}
+		$access_time .= "\n$temp ns at CAS ".$cas[$#cas-2];
+	}
+
+	printl_cond(defined $cycle_time, "Cycle Time", $cycle_time);
+	printl_cond(defined $access_time, "Access Time", $access_time);
+
+	$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("SDRAM Module Attributes", $temp);
+
+	$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("SDRAM Device Attributes (General)", $temp);
+
+	printl("Minimum Row Precharge Time",
+	       value_or_undefined($bytes->[27], "ns"));
+
+	printl("Row Active to Row Active Min",
+	       value_or_undefined($bytes->[28], "ns"));
+
+	printl("RAS to CAS Delay",
+	       value_or_undefined($bytes->[29], "ns"));
+
+	printl("Min RAS Pulse Width",
+	       value_or_undefined($bytes->[30], "ns"));
+
+	$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("Row Densities", $temp);
+
+	$temp = (($bytes->[32] & 0x7f) >> 4) + ($bytes->[32] & 0xf) * 0.1;
+	printl_cond(($bytes->[32] & 0xf) <= 9,
+		    "Command and Address Signal Setup Time",
+		    (($bytes->[32] >> 7) ? -$temp : $temp) . " ns");
+
+	$temp = (($bytes->[33] & 0x7f) >> 4) + ($bytes->[33] & 0xf) * 0.1;
+	printl_cond(($bytes->[33] & 0xf) <= 9,
+		    "Command and Address Signal Hold Time",
+		    (($bytes->[33] >> 7) ? -$temp : $temp) . " ns");
+
+	$temp = (($bytes->[34] & 0x7f) >> 4) + ($bytes->[34] & 0xf) * 0.1;
+	printl_cond(($bytes->[34] & 0xf) <= 9, "Data Signal Setup Time",
+		    (($bytes->[34] >> 7) ? -$temp : $temp) . " ns");
+
+	$temp = (($bytes->[35] & 0x7f) >> 4) + ($bytes->[35] & 0xf) * 0.1;
+	printl_cond(($bytes->[35] & 0xf) <= 9, "Data Signal Hold Time",
+		    (($bytes->[35] >> 7) ? -$temp : $temp) . " ns");
+}
+
+# Parameter: EEPROM bytes 0-127 (using 3-62)
+sub decode_ddr_sdram($)
+{
+	my $bytes = shift;
+	my $temp;
+
+# SPD revision
+	printl_cond($bytes->[62] != 0xff, "SPD Revision",
+		    ($bytes->[62] >> 4) . "." . ($bytes->[62] & 0xf));
+
+# speed
+	prints("Memory Characteristics");
+
+	$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("Maximum module speed", "${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("Size", "INVALID: " . $bytes->[3] . ", " . $bytes->[4] . ", " .
+			       $bytes->[5] . ", " . $bytes->[17]);
+	}
+
+	printl("Voltage Interface Level",
+	       sdram_voltage_interface_level($bytes->[8]));
+
+	printl("Module Configuration Type",
+	       sdram_module_configuration_type($bytes->[11]));
+
+	printl("Refresh Rate", ddr2_refresh_rate($bytes->[12]));
+
+	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
+	my ($cycle_time, $access_time);
+
+	if (exists $cas{$highestCAS}) {
+		$cycle_time = "$ctime ns at CAS $highestCAS";
+		$access_time = (($bytes->[10] >> 4) * 0.1 + ($bytes->[10] & 0xf) * 0.01)
+			     . " ns at CAS $highestCAS";
+	}
+
+	if (exists $cas{$highestCAS-0.5} && spd_written(@$bytes[23..24])) {
+		$cycle_time .= "\n".(($bytes->[23] >> 4) + ($bytes->[23] & 0xf) * 0.1)
+			     . " ns at CAS ".($highestCAS-0.5);
+		$access_time .= "\n".(($bytes->[24] >> 4) * 0.1 + ($bytes->[24] & 0xf) * 0.01)
+			      . " ns at CAS ".($highestCAS-0.5);
+	}
+
+	if (exists $cas{$highestCAS-1} && spd_written(@$bytes[25..26])) {
+		$cycle_time .= "\n".(($bytes->[25] >> 4) + ($bytes->[25] & 0xf) * 0.1)
+			     . " ns at CAS ".($highestCAS-1);
+		$access_time .= "\n".(($bytes->[26] >> 4) * 0.1 + ($bytes->[26] & 0xf) * 0.01)
+			      . " ns at CAS ".($highestCAS-1);
+	}
+
+	printl_cond(defined $cycle_time, "Minimum Cycle Time", $cycle_time);