summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornima <nima@abc39116-655e-4be6-ad55-d661dc543056>2008-06-30 12:08:58 +0000
committernima <nima@abc39116-655e-4be6-ad55-d661dc543056>2008-06-30 12:08:58 +0000
commite7d6d472c21aa80c28be01c0d6dcbfd250d57a25 (patch)
tree04d9d76a9a48f183f4cdf1c922a8e33555e77da1
downloadpython-dmidecode-e7d6d472c21aa80c28be01c0d6dcbfd250d57a25.tar.gz
python-dmidecode-e7d6d472c21aa80c28be01c0d6dcbfd250d57a25.tar.xz
python-dmidecode-e7d6d472c21aa80c28be01c0d6dcbfd250d57a25.zip
First commit to SVN.
git-svn-id: svn://svn.autonomy.net.au/python-dmidecode@1 abc39116-655e-4be6-ad55-d661dc543056
-rw-r--r--AUTHORS59
-rw-r--r--CHANGELOG993
-rw-r--r--LICENSE340
-rw-r--r--Makefile148
-rw-r--r--README146
-rw-r--r--biosdecode.c666
-rw-r--r--catsprintf.c20
-rw-r--r--catsprintf.h10
-rw-r--r--config.h25
-rw-r--r--dmidecode.c4140
-rw-r--r--dmidecode.h40
-rw-r--r--dmidecodemodule.c170
-rw-r--r--dmioem.c128
-rw-r--r--dmioem.h25
-rw-r--r--dmiopt.c308
-rw-r--r--dmiopt.h46
-rw-r--r--global.h7
-rw-r--r--ownership.c212
-rw-r--r--setup.py5
-rw-r--r--test.c127
-rw-r--r--types.h62
-rw-r--r--util.c165
-rw-r--r--util.h8
-rw-r--r--version.h1
-rw-r--r--vpddecode.c202
-rw-r--r--vpdopt.c159
-rw-r--r--vpdopt.h45
27 files changed, 8257 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..fed2534
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,59 @@
+DEVELOPER AND MAINTAINER
+Jean Delvare <khali@linux-fr.org>
+
+ORIGINAL AUTHOR
+Alan Cox <alan@redhat.com>
+
+CODE CONTRIBUTORS (IN CHRONOLOGICAL ORDER)
+Matt Domsch <Matt_Domsch@dell.com>
+Arjan van de Ven <arjanv@redhat.com>
+Mark D. Studebaker <mds@paradyne.com>
+Larry Lile <llile@dreamworks.com>
+Dave Johnson <ddj@cascv.brown.edu>
+Petter Reinholdtsen <pere@hungry.com>
+Roberto Nibali <ratz@tac.ch>
+John Cagle <jcagle@kernel.org>
+Jens Elkner <elkner@linofee.org>
+
+MANY THANKS TO (IN CHRONOLOGICAL ORDER)
+Werner Heuser
+Alexandre Duret-Lutz
+Xavier Roche
+Pamela Huntley
+Gael Stephan
+Sebastian Henschel
+Richard Sharpe
+David Wilson
+Glen Foster
+Chad Smith
+Joshua Goldenhar
+Luc Van de Velde
+Mario Lang
+Hugues Lepesant
+Sergey Leonovich
+Mike Cooper
+Marc Rieffel
+Jeff Moyer
+Josef Moellers
+Zing Zing Shishak
+Rafael Avila de Espindola
+Roger Koot
+Martin Pool
+Doug Brenner
+Alex Williamson
+Durval Menezes
+Raphael Raimbault
+Raul Nunez de Arenas Coronado
+Francois Revol
+Dominik Klein
+Erwan Velu
+Don Howard
+Frans Pop
+Tomek Mateja
+Myke Olson
+Torsten Seemann
+Garry Belka
+Klaus Muth
+Antoine Fuselier
+Matthew Garrett
+Landry Breuil
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..eb420c6
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,993 @@
+2007-02-26 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix an array overrun while decoding the system
+ event log status (DMI type 15).
+ * biosdecode.c: Use printf instead of fwrite.
+ * dmidecode.8: Some OEM-specific types can be decoded now.
+ * biosdecode.8: List the FJKEYINF entry point type.
+ * vpddecode.8: The product name is no longer displayed.
+ * version.h: Set version to 2.9.
+
+2007-02-16 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Do not print the BIOS base address and runtime size
+ if the base address is 0. This happens on IA-64 because there's
+ no BIOS.
+ * Makefile, README: Do not build biosdecode, ownership and
+ vpddecode on IA-64, as IA-64 systems have no BIOS. This was
+ quite tricky to keep both GNU make and BSD make happy, but it
+ seems that I finally succeeded.
+
+2007-02-13 Jean Delvare <khali@linux-fr.org>
+
+ Update to support SMBIOS specification version 2.5, second round.
+
+ * dmidecode.c: Decode new processor characteristics (multi-core,
+ multi-thread, 64-bit) (DMI type 4).
+ * dmidecode.c: Decode slot ID of AGP 8x and PCI Express slots (DMI
+ type 9).
+
+ * dmidecode.c: Fix the mask of 3 bitfield tests. This will let
+ the memory type of some systems be properly reported as SDRAM.
+ * dmidecode.c: Fix the AMD processors signature decoding.
+ * README: Minor edits.
+
+2007-02-12 Jens Elkner <elkner@linofee.org>
+
+ Update to support SMBIOS specification version 2.5, first round.
+
+ * dmidecode.c: Add chassis types "CompactPCI" and "AdvancedTCA"
+ (DMI type 3).
+ * dmidecode.c: Add processor types "Turion 64",
+ "Dual-Core Opteron", "Athlon 64 X2", "Celeron D", "Pentium D"
+ and "Pentium EE" (DMI type 4).
+ * dmidecode.c: Add processor upgrade types "Socket mPGA604",
+ "Socket LGA771" and "Socket LGA775" (DMI type 4).
+ * dmidecode.c: Add connector type "SAS/SATA Plug Receptacle" and
+ port types "SATA" and "SAS" (DMI type 8).
+ * dmidecode.c: Add on-board device types "PATA Controller",
+ "SATA Controller" and "SAS Controller" (DMI type 10).
+ * dmidecode.c: Add memory device form factor "FB-DIMM" and memory
+ device type "DDR2 FB-DIMM" (DMI type 17).
+
+2007-02-12 Jean Delvare <khali@linux-fr.org>
+
+ * dmioem.c: Share the code between HP-specific types 209 and 221.
+ Both types are really the same, only the title is different.
+ * dmioem.c: Make the HP-specific types 209 and 221 output a bit
+ more verbose.
+ * dmidecode.c: Let --type decode OEM-specific entries when
+ possible.
+ * dmidecode.c: Include decoded OEM-specific entries in quiet mode
+ output (--quiet).
+ * dmidecode.c: Do not complain about truncated entries in quiet
+ mode.
+ * dmioem.c: Decode HP-specific type 204 entries in a safer way:
+ check the length before decoding, and don't assume that all
+ strings are provided in the same order as they are used.
+
+ Update to support Intel AP-485 (CPUID) revision 31 (was 28).
+
+ * dmidecode.c: New CPUID flag IA64.
+ * dmidecode.c: Fix the decoding of Intel extended family.
+
+2007-02-11 Jean Delvare <khali@linux-fr.org>
+
+ * dmioem.c, dmioem.h: New.
+ * Makefile, dmidecode.c, dmidecode.h, dmioem.c, dmioem.h: Move the
+ decoding of OEM-specific entries to a separate source file.
+ * dmidecode.c: DMI type 38 is tested by now.
+ * dmioem.c: The PCI function is typically represented as a single
+ digit.
+ * Makefile, dmiopt.c, vpdopt.c, util.h: Define an ARRAY_SIZE macro
+ which computes the size of a static array, and use it where
+ relevant.
+
+2007-02-11 John Cagle <jcagle@kernel.org>
+
+ * dmidecode.c: Add support for 3 HP-specific entries: system/rack
+ locator (type 204), NIC MAC information (type 209) and NIC iSCSI
+ MAC information (type 221).
+
+2007-01-14 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Fix a rare warning.
+ * biosdecode.c: Add support for the FJKEYINF entry point, which
+ contains data related to the "application panel" on Fujitsu
+ laptops.
+
+2006-05-23 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix a recently introduced compilation error with
+ non-C99 compilers.
+ * dmidecode.c: Check for short entries (less than 4 bytes), stop
+ with an error when one is encountered.
+
+2006-05-13 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c, README: Drop the product name lookup table. It
+ was reported to be unreliable too many times, and was also
+ difficult to maintain.
+
+2006-05-10 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Don't cast from u8* to dmi_header*, else
+ architectures which do not support unaligned memory accesses
+ may break. Instead, copy the members individually. That's a
+ bit slower, but that's also safer and we only need to do it
+ once per DMI entry, so it's not time critical. So far, we
+ were using a trick to later work around the unaligned memory
+ access, but the compiler would still warn about the risk,
+ which is always confusing.
+ * config.h, types.h, README: Automatically enable the unaligned
+ memory access workaround on ia64.
+ * types.h: Inline U64. It makes sense per se and also lets us
+ get rid of a warning about U64 being unused.
+ * dmidecode.c: Detect EFI at run-time rather than compilation-
+ time. Based on an original patch from Matthew Garrett. This
+ will make x86 binaries work for both PC systems with BIOS and
+ Macintosh systems with EFI. Also prevent a possible, though
+ unlikely, NULL-pointer dereference in the EFI code.
+
+2006-02-25 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix typo reported by David Wilson (DMI case 3).
+
+2006-02-04 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Update lookup table from revision 2006-01-31 of IBM
+ reference document (add product ID "7B").
+ * version.h: Set version to 2.8.
+
+2006-01-21 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: The mysterious last character of xSeries records
+ may be a BIOS revision. Display it as such when present and
+ non zero, and ask users to report.
+ * vpddecode.c: Adjust an error message.
+ * dmidecode.8: Update the sample entry to match the new output
+ format.
+ * README: Improve the IA-64 specific section and the vpddecode
+ tool description.
+ * vpdopt.h: Add missing system header file include.
+
+2006-01-20 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Assume a constant length of 12 characters for the
+ "Default Flash Image File Name" entry. The 13th character never
+ contained anything useful, so it probably has a different
+ meaning (unknown for now).
+
+2005-12-24 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Scan for VPD records on 4-byte boundaries instead
+ of 16-byte boundaries. This is needed for some eServer xSeries
+ 206. Still emit a warning if a VPD record is found not on a
+ 16-byte boundary.
+
+2005-10-26 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "NR". Reported by Klaus Muth.
+ * vpddecode.c: Update lookup table from revision 2005-10-06 of IBM
+ reference document (add product IDs "77" and "78").
+
+2005-10-05 Jean Delvare <khali@linux-fr.org>
+
+ Update to support IPMI specification version 2.0 (was 1.5).
+
+ * dmidecode.c: Support IPMI interface type SSIF. Original patch
+ by Garry Belka.
+
+2005-10-04 Jean Delvare <khali@linux-fr.org>
+
+ * vpdopt.c: Display the list of all valid string keywords when
+ --string is used without an argument.
+ * vpddecode.8: Document the new -s, --string option.
+ * dmidecode.8: List the four new string keywords.
+ * vpddecode.c: Keep quiet when --string is used, even when no VPD
+ record is found.
+
+2005-10-03 Jean Delvare <khali@linux-fr.org>
+
+ * biosdecode.c: Fix a potential (but highly improbable) buffer
+ overrun in the VPD record decoding.
+ * biosdecode.c: Change the xSeries checksumming method to
+ accomodate a strange xSeries 440 VPD record, as was done in
+ vpddecode.c some weeks ago. Do not display the default flash
+ image file name anymore, it's not so useful and the field length
+ is now uncertain.
+ * vpdopt.c, vpdopt.h: New.
+ * Makefile, vpddecode.c, vpdopt.c, vpdopt.h: Move the command line
+ handling of vpddecode to a separate source file.
+ * vpddecode.c, vpdopt.c, vpdopt.h: Add option -s, --string. It
+ prints one selected VPD string instead of the regular output.
+
+2005-09-24 Jean Delvare <khali@linux-fr.org>
+
+ * dmiopt.c: Fix incorrect header include. The strcasecmp function
+ is defined in <strings.h>, not <string.h>. Reported by Petter
+ Reinholdtsen.
+
+2005-09-14 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.h: New.
+ * dmidecode.c, dmidecode.h, Makefile: Export four specific
+ decoding functions, make them suitable for external call.
+ * dmidecode.c, dmiopt.c, dmiopt.h, Makefile: Make it possible
+ for --string to print decoded binary data rather than only
+ DMI strings. Add four such string keywords.
+ * dmidecode.c, dmiopt.c, dmiopt.h: Modify the opt structure
+ to handle the string option more efficiently.
+
+2005-09-13 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Slightly change the xSeries checksumming method to
+ accomodate a strange xSeries 440 VPD record. Also tweak the
+ decoding of the "Default Flash Image File Name" entry. Thanks
+ to Torsten Seemann for providing a test VPD record.
+
+2005-09-05 Jean Delvare <khali@linux-fr.org>
+
+ * Makefile: Use -Wundef.
+
+2005-08-31 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Drop trailing dot from handle description line.
+
+2005-08-29 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Reword a comment about CPUID.
+ * dmidecode.c: Claim to support revision 28 of Intel AP-485
+ (CPUID). No relevant change since revision 27.
+
+2005-08-25 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "VI". Reported by Torsten Seemann.
+ * vpddecode.c: Update lookup table from revision 2005-06-24 of IBM
+ reference document (add product IDs "1U", "1X", "70", "74", "75"
+ and "76", update product ID "1Y").
+ * dmiopt.c: Complain about unknown options again.
+ * biosdecode.c, ownership.c, vpddecode.c: getopt_long() will never
+ return ':'.
+
+2005-08-04 Jean Delvare <khali@linux-fr.org>
+
+ * README: Manual pages document the command line interface.
+ A discussion list exists for developers. Mmap is used on
+ most systems, not just Linux.
+ * version.h: Set version to 2.7.
+
+2005-08-02 Jean Delvare <khali@linux-fr.org>
+
+ * dmiopt.c, dmidecode.8: Options --dump and --quiet are mutually
+ exclusive.
+
+2005-06-23 Jean Delvare <khali@linux-fr.org>
+
+ * dmiopt.c, dmidecode.8: Options --dump and --string are mutually
+ exclusive.
+
+2005-06-22 Jean Delvare <khali@linux-fr.org>
+
+ * dmiopt.c: Display the list of all valid type or string keywords
+ when --type or --string, respectively, is used without an
+ argument or with an invalid one.
+ * dmidecode.8: Document the new -s, --string option. Update the
+ -t, --type option documentation.
+ * dmiopt.c, dmidecode.8: Add string keyword "bios-release-date",
+ the Linux kernel uses it.
+ * dmidecode.c, dmidecode.8: Fix typo ("Controler" becomes
+ "Controller").
+
+2005-06-21 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c, dmiopt.c, dmiopt.h: Add option -s, --string. It
+ prints one selected DMI string instead of the regular output.
+
+2005-06-18 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Hide handle references and entries of unknown
+ type when --quiet is used.
+ * dmidecode.8: Document the new -q, --quiet option.
+ * dmidecode.c: Stop decoding at end of table entry when --quiet
+ is used. Also don't warn about incorrect table length or entries
+ count when --quiet is used.
+
+2005-06-17 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c, dmiopt.c, dmiopt.h: Add option -q, --quiet. It
+ makes the output less verbose.
+ * dmidecode.c: Suppress one level of indentation in the output,
+ insert blank lines between records. This will hopefully make
+ the output easier to read.
+ * dmidecode.c: Hide table address and size when --type is used.
+
+2005-06-16 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.8: Document the new -t, --type option.
+
+2005-06-15 Jean Delvare <khali@linux-fr.org>
+
+ * dmiopt.c, dmiopt.h: New.
+ * Makefile, dmidecode.c, dmiopt.c, dmiopt.h: Move the command line
+ handling of dmidecode to a separate source file.
+ * dmiopt.c: Define keywords to be used with --type (instead of
+ numeric values).
+
+2005-06-14 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Centralize the main exit point. This allows fixing
+ a minor, recently introduced memory leak which was happening on
+ error conditions.
+
+2005-06-13 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Add option -t, --type. It limits the output to
+ the given type(s) of DMI entries.
+
+2005-05-25 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product IDs "KE", "NT" and "ZR". Reported by
+ Bernd Krumboeck.
+
+2005-05-15 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.8, vpddecode.8: Document the new -u, --dump option.
+
+ Update to support SMBIOS specification version 2.4 (was 2.4
+ preliminary). There is actually no difference between 2.4
+ preliminary and 2.4 final.
+
+ * dmidecode.c: Update the "System Management BIOS Reference
+ Specification" version.
+
+2005-04-26 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "M1". Reported by Myke Olson.
+ * vpddecode.c: Add option -u, --dump. It disables decoding of the
+ VPD records, a raw dump is displayed instead. This option is
+ mainly intended for debugging.
+
+2005-04-03 Jean Delvare <khali@linux-fr.org>
+
+ * Makefile: Use variables for install and rm commands, so that these
+ can be overriden by the caller.
+
+2005-03-25 Jean Delvare <khali@linux-fr.org>
+
+ * Makefile: Install some documentation files (README, CHANGELOG,
+ AUTHORS).
+
+ Update to support SMBIOS specification version 2.4 preliminary
+ [11/18/2004] (was 2.3.4).
+
+ * dmidecode.c: Add BIOS characteristics (DMI type 0).
+ * dmidecode.c: Display BIOS and firmware revisions where available
+ (DMI type 0).
+ * dmidecode.c: Display system SKU number and family where available
+ (DMI type 1).
+ * dmidecode.c: Add system slot types and widths (DMI type 9).
+ * dmidecode.c: Add memory device type "DDR2" (DMI type 17).
+
+2005-03-20 Jean Delvare <khali@linux-fr.org>
+
+ * Makefile: Install manual pages under $(prefix)/share/man by
+ default, instead of $(prefix)/man, so as to comply with the FHS.
+
+2005-03-08 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Update lookup table from revision 2005-03-08 of IBM
+ reference document (add product ID "1V", update product ID "1R").
+ Thanks to Ingo van Lil for reporting about product ID "1V".
+
+2005-03-06 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Add option -u, --dump. It disables decoding of the
+ entries, raw dumps are displayed instead. This option is mainly
+ intended for debugging.
+ * Makefile: Use -Winline.
+ * dmidecode.c: Make ASCII filtering of strings faster.
+
+2005-02-28 Jean Delvare <khali@linux-fr.org>
+
+ * version.h: Set version to 2.6.
+ * Makefile: ownership.o depends on version.h.
+
+2005-02-24 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "2C". Reported by Tomek Mateja.
+
+2005-02-17 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product IDs "OP" and "PN". Reported by Scott
+ Denham.
+ * vpddecode.c: Fix typo in one product name (560E improperly
+ spelled 650E).
+ * vpddecode.c: Add product IDs "IW" and "IY", as added recently
+ on IBM's reference web page. Update reference.
+ * config.h: Use mmap on all but BeOS, instead of only Linux.
+
+2005-02-12 Jean Delvare <khali@linux-fr.org>
+
+ * util.c: Fix incorrect length in munmap call.
+ * Makefile: Use -Wmissing-prototypes.
+ * dmidecode.c: Fix maximum battery error value.
+
+2005-02-11 Jean Delvare <khali@linux-fr.org>
+
+ * Makefile: Discard -pedantic, we don't really need this.
+ * util.c: Display an error message on memory shortage. Suggested
+ by Don Howard.
+
+ Fix a bug causing dmidecode to crash on some systems with more than
+ 2 GB of memory. This is a signedness issue, which existed up to
+ version 2.2, was fixed in 2.3 but reintroduced in a different form
+ in 2.5 as part of a code clean up and refactoring.
+ https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=112355
+ Thanks to Petter Reinholdtsen for reporting. Thanks to Don Howard
+ for additional insight.
+
+ * dmidecode.c, util.c, util.h: Use size_t instead of off_t when
+ handling memory addresses.
+
+2005-02-10 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Add option -h, --help, display a usage summary.
+ * biosdecode.c, ownership.c, vpddecode.c: Copy command-line handling
+ from dmidecode.c.
+ * biosdecode.8, dmidecode.8, ownership.8, vpddecode.8: Document
+ the new command-line interface.
+
+2005-02-06 Jean Delvare <khali@linux-fr.org>
+
+ * Makefile: Everything depends on config.h.
+ * dmidecode.c: Add basic command-line handling. This was suggested
+ a long time ago by Erwan Velu.
+
+2005-02-01 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product IDs "AP", "KP" and "RD". Reported by
+ David Rosala.
+
+2005-01-17 Jean Delvare <khali@linux-fr.org>
+
+ * README: Add a note about Cygwin. Thanks to Dominik Klein for
+ reporting success.
+
+2004-12-10 Jean Delvare <khali@linux-fr.org>
+
+ Increase portability and configurability to in order to support BeOS.
+
+ * config.h: New.
+ * config.h: Define a default memory device.
+ * biosdecode.c, dmidecode.c, ownership.c, vpddecide.c: Include
+ config.h and use the defined default memory device.
+ * Makefile, config.h, util.c, README: Move USE_MMAP to config.h,
+ use mmap on Linux only.
+
+2004-11-22 Jean Delvare <khali@linux-fr.org>
+
+ * biosdecode.c: Avoid size_t in printf. Should remove a warning on
+ ia64. Thanks to Petter Reinholdtsen for reporting.
+ * util.c: Use sysconf(_SC_PAGESIZE) instead of getpagesize() where
+ available. This may remove a warning on ia64 as a side effect.
+ Thanks to Petter Reinholdtsen for reporting.
+
+2004-11-21 Jean Delvare <khali@linux-fr.org>
+
+ * util.c, util.h: Function myread has no more user outside of util.c.
+ * biosdecode.c: Speed improvements.
+
+2004-11-20 Jean Delvare <khali@linux-fr.org>
+
+ * biosdecode.c, ownership.c, vpddecode.c: Make use of the mem_chunk
+ function.
+ * vpddecode.c: Simplify the mem loop code a bit.
+
+2004-11-12 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Hide bank connection type for uninstalled memory
+ modules.
+ * dmidecode.c: Reference comment fix.
+ * dmidecode.c: Hide watchdog timer details when no watchdog is
+ present. Change label for no watchdog.
+ * README: Match case change for PREFIX (now prefix) in the Makefile
+ file. Reported by Raul Nunez de Arenas Coronado.
+
+2004-11-12 Jean Delvare <khali@linux-fr.org>
+
+ Update to support DMTF Master MIF version 040707 (was 030621).
+
+ * dmidecode.c: One additional processor type (Sempron).
+ * dmidecode.c: One additional processor type (Efficeon TM8800).
+ * dmidecode.c: One additional processor upgrade type (Socket 939).
+ * dmidecode.c: Add the AMD Sempron to the list of x86-class
+ processors.
+
+ Update to support Intel AP-485 (CPUID) revision 27 (was 25).
+
+ * dmidecode.c: Rename SBF flag to PBE.
+
+2004-11-11 Jean Delvare <khali@linux-fr.org>
+
+ * util.c: More helpful error messages.
+ * util.c: Use MAP_SHARED instead of MAP_PRIVATE in mmap.
+ * version.h: Set version to 2.5.
+
+2004-11-10 Jean Delvare <khali@linux-fr.org>
+
+ * README: Update dmidecode presentation (copied from the web page).
+ Move the list of supported systems from the documentation section
+ to the installation section.
+
+2004-11-09 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Update product ID "1R". Reported by Marco Wertejuk.
+
+2004-10-24 Jean Delvare <khali@linux-fr.org>
+
+ * util.c: Workaround missing MAP_FAILED definition, needed on
+ old systems. Original patch from Durval Menezes.
+
+2004-10-14 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Search for EFI systab at /sys/firmware/efi/systab.
+ Original patch from Alex Williamson.
+ * dmidecode.c: Remove warning about legacy_decode not being used
+ when USE_EFI is defined.
+ * dmidecode.c: Detect missing SMBIOS entry point in efi/systab.
+ * dmidecode.c: Fix fatal typo in USE_EFI-specific code.
+
+2004-10-01 Roberto Nibali <ratz@tac.ch>
+
+ * Makefile: Be LDFLAGS aware.
+
+2004-07-24 Jean Delvare <khali@linux-fr.org>
+
+ * util.c: Add missing header include.
+
+2004-06-11 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product IDs "GE" and "T2". Reported by Doug Brenner.
+
+2004-05-02 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Move legacy DMI entry point decoding to a separate
+ function.
+ * dmidecode.c: Use a 64 kB buffer for searching entry points,
+ instead of repeated 16-byte reads.
+ * util.c, util.h: New mem_chunk function. It returns a buffer
+ containing a copy of a given chunk of the physical memory.
+ * dmidecode.c: Make use of the new mem_chunk function.
+
+2004-04-30 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "JP". Reported by Bernd Krumboeck.
+
+2004-04-22 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c, biosdecode.c, ownership.c, types.h: Refactor WORD-like
+ macros into types.h.
+
+2004-04-21 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c, biosdecode.c: Fix my contact information.
+ * dmidecode.c: Update copyright year.
+
+2004-04-20 Jean Delvare <khali@linux-fr.org>
+
+ * README: Correct Chad Smith's name. Reported by Martin Pool.
+
+2004-04-15 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "PL". Reported by Mark Syms.
+
+2004-04-14 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "PD". Reported by Roger Koot.
+
+2004-04-11 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c, Makefile, README: Drop TABLE_LITTLEENDIAN.
+ * README: Update manual pages information.
+
+2004-04-02 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "NV". Reported by Shawn Starr.
+
+2004-03-27 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "24". Reported by Paul Sturm.
+ * dmidecode.c: Fix two missing comas in string enumerations. Thanks to
+ Joshua Goldenhar for reporting the first one.
+
+2004-03-24 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "PJ". Reported by Roger Koot.
+ * vpddecode.c: Rename two Netvista systems to use their real name
+ instead of machine type.
+
+2004-03-20 Petter Reinholdtsen <pere@hungry.com>
+
+ * Makefile: Make it easier to select where to install the binaries
+ and manual pages, and to use different paths when building and
+ installing.
+
+2004-03-19 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "2A". Reported by Rafael Avila
+ de Espindola.
+ * version.h: Set version to 2.4.
+
+2004-03-07 Jean Delvare <khali@linux-fr.org>
+
+ * biosdecode.c, vpddecode.c: Add a third checksumming method for
+ VPD records.
+ * vpddecode.c: Add product ID "PI", update "20". Reported by
+ Zing Zing Shishak.
+
+2004-03-05 Jean Delvare <khali@linux-fr.org>
+
+ * README: Update.
+
+2004-02-25 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Support CPUID document revision 25 (no change).
+ * dmidecode.c: Shorten the EOF error message.
+
+2004-02-23 Jean Delvare <khali@linux-fr.org>
+
+ * man/biosdecode.8, man/dmidecode.8, man/ownership.8,
+ man/vpddecode.8: New.
+ * Makefile: Handle new manual pages.
+
+2003-12-28 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "PT". Reported by Ramiro Barreiro.
+
+2003-12-17 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "RE". Reported by Josef Moellers.
+ * vpddecode.c, biosdecode.c: Handle longer VPD records as seen on
+ xSeries. These have a different checksumming method.
+
+2003-12-03 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "TT". Reported by Hugues Lepesant.
+ * vpddecode.c, biosdecode.c: Fix typo ("Bios" becomes "BIOS").
+ * dmidecode.c: Add another exception to the CPUID-supporting CPU list
+ ("Pentium III MMX").
+ * dmidecode.c: Number devices in multi-device on board device
+ information structures (DMI case 10).
+
+2003-11-13 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Automatically detect architectures on which to use EFI
+ (ia64 for now). Suggested by Jeff Moyer.
+
+2003-11-11 Jean Delvare <khali@linux-fr.org>
+
+ * vpddecode.c: Add product ID "KX". Reported by Klaus Ade Johnstad,
+ confirmed by Pamela Huntley.
+ * dmidecode.c: Display CPUID values as decimal, not hexa. This is
+ a reversal of the 2003-07-18 change to be consistent with
+ /proc/cpuinfo under Linux.
+ * dmidecode.c: Fix processor ID decoding for older 80486. Not very
+ important since such systems are unlikely to support SMBIOS.
+ * dmidecode.c: Modify CPU signature display for AMD processors.
+ * vpddecode.c, biosdecode.c: Fix incorrect VPD checksumming.
+
+2003-10-24 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Add another exception to the CPUID-supporting CPU list.
+
+2003-10-19 Jean Delvare <khali@linux-fr.org>
+
+ * README: Clarify why mmap is used. Fix typo.
+ * Makefile: Add deleting core to the clean target.
+ * version.h: Set version to 2.3.
+
+2003-10-17 Jean Delvare <khali@linux-fr.org>
+
+ * biosdecode.c: Use (void) instead of __attribute__ ((usused)) to
+ declare that a function parameter isn't used. According to Alexandre
+ Duret-Lutz, this is the portable way do to it. Fix typo in comment.
+ * dmidecode.c: Fix typo.
+
+2003-10-16 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Remove useless comparison in dmi_system_boot_status.
+ Thanks to Alexandre Duret-Lutz for pointing this out.
+ * biosdecode.c: Add a missing length check in acpi_decode. Found
+ using Valgrind.
+ * biosdecode.c: Fix buffer overrun in main. Found using Valgrind.
+
+2003-10-14 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Update DMTF reference addresses.
+ * dmidecode.c: List two more processors (Athlon64 and Pentium M)
+ as x86-class (i.e. supporting CPUID).
+
+2003-10-11 Jean Delvare <khali@linux-fr.org>
+
+ Update to support DMTF Master MIF version 030621 (was 021205).
+
+ * dmidecode.c: Handle unknown processor voltage.
+ * dmidecode.c: Fix typo in event log method.
+ * dmidecode.c: One additional processor type (Pentium M).
+ * dmidecode.c: Add the AMD Opteron to the list of x86-class
+ processors. Thanks to Mike Cooper for providing information.
+ * vpddecode.c: New program for decoding a machine's VPD structure
+ (only found in IBM machines).
+ * Makefile: Update accordingly.
+ * Makefile: Fix dependencies for ownership. Add strip target. Various
+ cleanups (reordering, comments, optimization and debug flags).
+ * README: Update to reflect the addition of the strip target and the
+ vpddecode program. Some additional changes and fixes.
+
+2003-10-10 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Change mmap options to prevent dmidecode from being
+ killed by the Linux kernel in some rare cases. Reported by
+ Mike Cooper.
+ * dmidecode.c: Various code cleanups and optimizations.
+
+2003-10-09 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix a bug that prevented dmidecode to reach DMI tables
+ beyond the 2GB memory limit. Reported by Mike Cooper.
+ * ownership.c: Add one reference. Code cleanups.
+ * CHANGELOG: Fix typo.
+
+2003-10-08 Jean Delvare <khali@linux-fr.org>
+
+ * biosdecode.c: Fix potentially wrong checksum on Sony-specific entry.
+ * biosdecode.c: Unimportant changes (comment, typo...) in
+ Compaq-specific section.
+ * biosdecode.c: Add support for VPD (vital product data, IBM-specific).
+ * CHANGELOG: Various updates.
+
+2003-10-07 Jean Delvare <khali@linux-fr.org>
+
+ * ownership.c: Fix a harmless warning on x86_64. Reported by Mike
+ Cooper.
+
+2003-09-19 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Explicitly say when no SMBIOS nor DMI entry point
+ was found. Implicitly suggested by Sergey Leonovich.
+
+2003-09-11 Jean Delvare <khali@linux-fr.org>
+
+ * Makefile: Don't use $^ since it isn't supported by BSD make.
+ Reported by Hugues Lepesant.
+
+2003-09-05 Jean Delvare <khali@linux-fr.org>
+
+ * Makefile: Fix missing ownership dependency for install target.
+ Reported by Mario Lang.
+
+2003-08-08 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Update the README file (mainly the now solved laptop
+ and IA-64 issues, and add a section for biosdecode and ownership).
+ * version.h: Set version to 2.2.
+
+2003-07-18 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Display CPUID values as hexa, not decimal.
+ * dmidecode.c: Shift the I2C slave address by one bit to the right
+ (DMI case 38).
+
+2003-06-27 Jean Delvare <khali@linux-fr.org>
+
+ * biosdecode.c: Better display of Compaq-specific entries (thank to
+ some documentation).
+
+2003-06-25 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Remove fp_last (not useful anymore). Reworded the "table
+ is unreachable" message to mention the -DUSE_MMAP solution.
+
+2003-06-19 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Add support for IA-64.
+ * Makefile: Add new option CFLAGS modifier lines for IA-64.
+
+2003-06-17 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c, biosdecode.c: Move common "util" functions to util.c.
+ * util.c, util.h: New.
+ * types.h: New.
+ * Makefile: Update accordingly.
+ * biosdecode.c: Add detection of Compaq-specific entries.
+ * ownership.c: New program for finding a machine's ownership tag
+ (only found in Compaq machines). Requested by Luc Van de Velde.
+ * Makefile: Update again.
+
+2003-06-10 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix typo in IPMI register spacing table.
+ * version.h: Set version to 2.1.
+
+2003-06-04 Jean Delvare <khali@linux-fr.org>
+
+ * Makefile: Restore optional CFLAGS modifier lines.
+ * README: New.
+
+2003-05-30 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Cleaner handling of unreachable table.
+
+2003-05-27 Jean Delvare <khali@linux-fr.org>
+
+ Update to support Intel AP-485 specification (CPUID) revision 023
+ (was 021).
+
+ * dmidecode.c: Add SBF flag to processor ID (DMI case 4). Add comment
+ about new flags returned in ECX.
+
+2003-05-26 Jean Delvare <khali@linux-fr.org>
+
+ Update to support SMBIOS specification version 2.3.4 (was 2.3.3).
+
+ * dmidecode.c: Add processor and processor upgrade names (DMI case 4).
+ * dmidecode.c: Add slot names (DMI case 9).
+
+2003-05-22 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix typo reported by David Wilson (DMI case 6).
+
+2003-03-08 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Decode more fields according to the IPMI specification
+ (DMI case 38).
+
+2003-03-07 Jean Delvare <khali@linux-fr.org>
+
+ Fixed IPMI device information (DMI case 38). Thanks to Richard Sharpe
+ for pointing the bugs out.
+
+ * dmidecode.c: Fix IPMI interface type being shifted by one.
+ * dmidecode.c: Fix NV storage device being improperly displayed.
+ * dmidecode.c: Reword IPMI specification revision into specification
+ version, as suggested in the IPMI specification itself.
+ * dmidecode.c: Add a reference to the IPMI specification.
+ * dmidecode.c: Show I2C address as hexadecimal.
+ * dmidecode.c: Base address is a QWORD, not DWORD.
+ * dmidecode.c: Decode some extra fields according to the IPMI
+ specification.
+
+2003-03-06 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c, biosdecode.c: Move all changelog entries to CHANGELOG.
+ * CHANGELOG: New. Format inspired by Heroes' ChangeLog file.
+ * dmidecode.c, biosdecode.c, Makefile: Update copyright years.
+ * dmidecode.c, biosdecode.c, Makefile: Move version definition to
+ version.h. Update dependencies accordingly.
+ * version.h: New.
+
+2002-10-21 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Change supported log type descriptors display.
+ * dmidecode.c: Code optimization in event log status.
+ * dmidecode.c: Remove extra newline in voltage probe accuracy.
+ * dmidecode.c: Display "OEM-specific" if type is 128 or more.
+ * dmidecode.c: Do not display Strings on dump if there are no strings.
+ * dmidecode.c: Add ASCII-filtering to dmi_string.
+ * dmidecode.c: Convert all dates to ISO 8601.
+
+2002-10-18 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Complete rewrite.
+ * dmidecode.c: Now complies with SMBIOS specification 2.3.3.
+ * dmidecode.c: Move all non-DMI stuff to biosdecode.c.
+ * biosdecode.c: New.
+
+2002-10-15 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix bad index in DMI case 27 (cooling device).
+
+2002-10-14 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix typo in dmi_memory_array_location.
+ * dmidecode.c: Replace Kbyte by kB in DMI case 16.
+ * dmidecode.c: Add DDR entry in dmi_memory_device_type.
+ * dmidecode.c: Fix extra s in SYSID.
+
+2002-10-12 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix maximum cache size and installed size being
+ inverted.
+ * dmidecode.c: Fix typos in port types.
+
+2002-10-10 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Remove extra semicolon at the end of
+ dmi_memory_array_use.
+ * dmidecode.c: Fix compilation warnings.
+ * dmidecode.c: Add missing backslash in DMI case 37.
+ * dmidecode.c: Fix BIOS ROM size (DMI case 0).
+
+2002-10-05 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: More ACPI decoded.
+ * dmidecode.c: More PNP decoded.
+ * dmidecode.c: More SYSID decoded.
+ * dmidecode.c: PCI Interrupt Routing decoded.
+ * dmidecode.c: BIOS32 Service Directory decoded.
+ * dmidecode.c: Sony system detection (unconfirmed).
+ * dmidecode.c: Checksums verified whenever possible.
+ * dmidecode.c: Better checks on file read and close.
+ * dmidecode.c: Define VERSION and display version at beginning.
+ * dmidecode.c: More secure decoding (won't run off the table in any
+ case).
+ * dmidecode.c: Do not try to decode more structures than announced.
+ * dmidecode.c: Fix an off-by-one error that caused the last address
+ being scanned to be 0x100000, not 0xFFFF0 as it should.
+
+2002-09-28 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Fix missing coma in dmi_bus_name.
+ * dmidecode.c: Remove unwanted bitmaskings in dmi_mgmt_dev_type,
+ dmi_mgmt_addr_type, dmi_fan_type, dmi_volt_loc, dmi_temp_loc and
+ dmi_status.
+ * dmidecode.c: Fix DMI table read bug ("dmi: read: Success").
+ * dmidecode.c: Make the code pass -W again.
+ * dmidecode.c: Fix return value of dmi_card_size.
+
+2002-09-20 Dave Johnson <ddj@cascv.brown.edu>
+
+ * dmidecode.c: Fix comparisons in dmi_bus_name.
+ * dmidecode.c: Fix comparison in dmi_processor_type.
+ * dmidecode.c: Fix bitmasking in dmi_onboard_type.
+ * dmidecode.c: Fix return value of dmi_temp_loc.
+
+2002-09-17 Larry Lile <llile@dreamworks.com>
+
+ * dmidecode.c: Type 16 & 17 structures displayed per SMBIOS 2.3.1 spec.
+
+2002-08-23 Alan Cox <alan@redhat.com>
+
+ * dmidecode.c: Make the code pass -Wall -pedantic by fixing a few
+ harmless sign of pointer mismatches.
+ * dmidecode.c: Correct main() prototype.
+ * dmidecode.c: Check for compilers with wrong type sizes.
+
+2002-08-09 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Better DMI struct count/size error display.
+ * dmidecode.c: More careful memory access in dmi_table.
+ * dmidecode.c: DMI case 13 (Language) decoded.
+ * dmidecode.c: C++ style comments removed. Commented out code removed.
+ * dmidecode.c: DMI 0.0 case handled.
+ * dmideocde.c: Fix return value of dmi_port_type and
+ dmi_port_connector_type.
+
+2002-08-06 Jean Delvare <khali@linux-fr.org>
+
+ * dmidecode.c: Reposition file pointer after DMI table display.
+ * dmidecode.c: Disable first RSD PTR checksum (was not correct anyway).
+ * dmidecode.c: Show actual DMI struct count and occupied size.
+ * dmidecode.c: Check for NULL after malloc.
+ * dmidecode.c: Use SEEK_* constants instead of numeric values.
+ * dmidecode.c: Code optimization (and warning fix) in DMI cases 10 and
+ 14.
+ * dmidecode.c: Add else's to avoid unneeded cascaded if's in main loop.
+ * dmidecode.c: Code optimization in DMI information display.
+ * dmidecode.c: Fix all compilation warnings.
+
+2002-08-03 Mark D. Studebaker <mds@paradyne.com>
+
+ * dmidecode.c: Better indent in dump_raw_data.
+ * dmidecode.c: Fix return value of dmi_bus_name.
+ * dmidecode.c: Additional sensor fields decoded.
+ * dmidecode.c: Fix compilation warnings.
+
+2001-12-13 Arjan van de Ven <arjanv@redhat.com>
+
+ * dmidecode.c: Fix memory bank type (DMI case 6).
+
+2001-07-02 Matt Domsch <Matt_Domsch@dell.com>
+
+ * dmidecode.c: Additional structures displayed per SMBIOS 2.3.1 spec.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..29d4238
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,148 @@
+#
+# DMI Decode
+# BIOS Decode
+#
+# (C) 2000-2002 Alan Cox <alan@redhat.com>
+# (C) 2002-2007 Jean Delvare <khali@linux-fr.org>
+#
+# Licensed under the GNU Public License.
+#
+
+CC = gcc
+CFLAGS = -W -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual \
+ -Wcast-align -Wwrite-strings -Wmissing-prototypes -Winline -Wundef
+#CFLAGS += -DBIGENDIAN
+#CFLAGS += -DALIGNMENT_WORKAROUND
+
+# When debugging, disable -O2 and enable -g.
+CFLAGS += -O2
+#CFLAGS += -g
+
+# Pass linker flags here
+LDFLAGS =
+
+DESTDIR =
+prefix = /usr/local
+sbindir = $(prefix)/sbin
+mandir = $(prefix)/share/man
+man8dir = $(mandir)/man8
+docdir = $(prefix)/share/doc/dmidecode
+
+INSTALL := install
+INSTALL_DATA := $(INSTALL) -m 644
+INSTALL_DIR := $(INSTALL) -m 755 -d
+INSTALL_PROGRAM := $(INSTALL) -m 755
+RM := rm -f
+
+PROGRAMS := go
+PROGRAMS += $(shell test `uname -m 2>/dev/null` != ia64 && echo biosdecode ownership vpddecode)
+# BSD make doesn't understand the $(shell) syntax above, it wants the !=
+# syntax below. GNU make ignores the line below so in the end both BSD
+# make and GNU make are happy.
+PROGRAMS != echo dmidecode ; test `uname -m 2>/dev/null` != ia64 && echo biosdecode ownership vpddecode
+
+
+
+all : $(PROGRAMS)
+ python setup.py clean
+ python setup.py build
+ sudo python setup.py install
+ ldd /usr/lib/python2.4/site-packages/dmidecode.so
+ python -c 'import dmidecode'
+
+#. NiMA...
+go: test.c catsprintf.o libdmidecode.so dmidecode.o dmiopt.o dmioem.o util.o
+ gcc -o go test.c -L. -I/usr/include/python2.4 -ldmidecode catsprintf.o dmidecode.o dmiopt.o dmioem.o util.o
+libdmidecode.so: dmidecode.o
+ gcc -shared $< -o $@
+catsprintf.o: catsprintf.c catsprintf.h
+ $(CC) $(CFLAGS) -c $< -o $@
+#. ...NiMA
+
+#
+# Programs
+#
+
+#dmidecode : dmidecode.o dmiopt.o dmioem.o util.o
+# $(CC) $(LDFLAGS) dmidecode.o dmiopt.o dmioem.o util.o -o $@
+
+biosdecode : biosdecode.o util.o
+ $(CC) $(LDFLAGS) biosdecode.o util.o -o $@
+
+ownership : ownership.o util.o
+ $(CC) $(LDFLAGS) ownership.o util.o -o $@
+
+vpddecode : vpddecode.o vpdopt.o util.o
+ $(CC) $(LDFLAGS) vpddecode.o vpdopt.o util.o -o $@
+
+#
+# Objects
+#
+
+dmidecode.o : dmidecode.c version.h types.h util.h config.h dmidecode.h \
+ dmiopt.h dmioem.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+dmiopt.o : dmiopt.c config.h types.h util.h dmidecode.h dmiopt.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+dmioem.o : dmioem.c types.h dmidecode.h dmioem.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+biosdecode.o : biosdecode.c version.h types.h util.h config.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+ownership.o : ownership.c version.h types.h util.h config.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+vpddecode.o : vpddecode.c version.h types.h util.h config.h vpdopt.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+vpdopt.o : vpdopt.c config.h util.h vpdopt.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+util.o : util.c types.h util.h config.h
+ $(CC) $(CFLAGS) -c $< -o $@
+
+#
+# Commands
+#
+
+strip : $(PROGRAMS)
+ strip $(PROGRAMS)
+
+install : install-bin install-man install-doc
+
+uninstall : uninstall-bin uninstall-man uninstall-doc
+
+install-bin : $(PROGRAMS)
+ $(INSTALL_DIR) $(DESTDIR)$(sbindir)
+ for program in $(PROGRAMS) ; do \
+ $(INSTALL_PROGRAM) $$program $(DESTDIR)$(sbindir) ; done
+
+uninstall-bin :
+ for program in $(PROGRAMS) ; do \
+ $(RM) $(DESTDIR)$(sbindir)/$$program ; done
+
+install-man :
+ $(INSTALL_DIR) $(DESTDIR)$(man8dir)
+ for program in $(PROGRAMS) ; do \
+ $(INSTALL_DATA) man/$$program.8 $(DESTDIR)$(man8dir) ; done
+
+uninstall-man :
+ for program in $(PROGRAMS) ; do \
+ $(RM) $(DESTDIR)$(man8dir)/$$program.8
+
+install-doc :
+ $(INSTALL_DIR) $(DESTDIR)$(docdir)
+ $(INSTALL_DATA) README $(DESTDIR)$(docdir)
+ $(INSTALL_DATA) CHANGELOG $(DESTDIR)$(docdir)
+ $(INSTALL_DATA) AUTHORS $(DESTDIR)$(docdir)
+
+uninstall-doc :
+ $(RM) -r $(DESTDIR)$(docdir)
+
+clean :
+ python setup.py clean
+ $(RM) *.so *.o $(PROGRAMS) core
+ rm -rf build
diff --git a/README b/README
new file mode 100644
index 0000000..521fab9
--- /dev/null
+++ b/README
@@ -0,0 +1,146 @@
+** INTRODUCTION **
+
+Dmidecode reports information about your system's hardware as described in
+your system BIOS according to the SMBIOS/DMI standard. This information
+typically includes system manufacturer, model name, serial number, BIOS
+version, asset tag as well as a lot of other details of varying level of
+interest and reliability depending on the manufacturer. This will often
+include usage status for the CPU sockets, expansion slots (e.g. AGP, PCI,
+ISA) and memory module slots, and the list of I/O ports (e.g. serial,
+parallel, USB).
+
+Part of the dmidecode code can be found in the Linux kernel, where DMI data
+is used to enable or disable specific portions of code depending on the
+specific hardware. Thus, one use of dmidecode is for kernel developers to
+detect system "signatures" and add them to the kernel source code when
+needed.
+
+Beware that DMI data have proven to be too unreliable to be blindly trusted.
+Dmidecode does not scan your hardware, it only reports what the BIOS told it
+to.
+
+
+** INSTALLATION **
+
+The home web page for dmidecode is hosted on Savannah:
+ http://www.nongnu.org/dmidecode/
+You will find the latest version (including CVS) there, as well as fresh news
+and other interesting material, such as a list of related projects and
+articles.
+
+This program was first written for Linux, and has since been reported to work
+on FreeBSD, NetBSD, OpenBSD, BeOS and Cygwin as well.
+
+There's no configure script, so simply run "make" to build dmidecode, and
+"make install" to install it. 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.
+
+Two parameters can be set in the Makefile file to make dmidecode work on
+non-i386 systems. They should be used if your system uses the big endian
+byte ordering (Motorola) or doesn't support unaligned memory accesses,
+respectively. For example, compiling for a SPARC processor would require
+both. Compiling for an IA64 processor requires the memory alignment
+workaround, and it is enabled automatically.
+
+
+** DOCUMENTATION **
+
+Each tool has a manual page, found in the "man" subdirectory. Manual pages
+are installed by "make install". See these manual pages for command line
+interface details and tool specific information.
+
+For an history of the changes made to dmidecode, see the CHANGELOG file.
+
+If you need help, your best chances are to visit the web page (see the
+INSTALLATION section above) or to get in touch with the developers directly.
+Have a look at the AUTHORS file and contact one of the maintainers.
+
+If you want to help with the development of dmidecode, please consider
+joining the dmidecode-devel discussion list:
+ http://lists.nongnu.org/mailman/listinfo/dmidecode-devel
+
+
+** COMMON PROBLEMS **
+
+MODEL SPECIFIC ISSUES
+
+Dmidecode used not to work on IBM T-series laptops nor on Fujitsu-Siemens
+S-series laptops under Linux. This was due to the fact that the DMI table
+is at a memory location we couldn't seem to reach through /dev/mem. Although
+I believe this reveals a problem in the Linux kernel, which should be fixed,
+a workaround was found by Chad Smith, and we are using it for now. See the
+IA-64 subsection below for more details. I posted about this problem on the
+LKML but never received any answer. Since then, the list of affected systems
+was extended to IBM X-series laptops and xSeries x445 servers.
+
+IA-64
+
+Dmidecode used to have problems on IA-64 systems. The first reason for
+this is that dmidecode accesses the DMI table through /dev/mem, and reading
+this file on an IA-64 system sometimes leads to a crash. A second reason is
+that the method for locating the above-mentioned table differs on IA-64
+(compared to x86), so dmidecode was likely to miss the table entry point.
+This complex issue was reported by Glen Foster and Chad Smith from HP. We
+have since been working on a solution, and dmidecode now supports IA-64
+systems. Chad Smith noticed that, for some obscure reason, accessing the
+/dev/mem file using mmap() instead of read() would work. Then, he wrote a
+patch to export the DMI table address from the internal EFI table to /proc,
+so dmidecode doesn't have to scan /dev/mem for it anymore. This patch was
+since integrated into the main ia64 patch. Finally, I added the required
+code to make it all work. So, in order to have dmidecode work on your IA-64
+system, you need two things:
+ - dmidecode version 2.2 or later;
+ - an ia64 patched 2.4 kernel, using linux-2.4.21-ia64-030702.diff or any
+ later version, or a 2.6 kernel.
+Chad Smith tested dmidecode successfully on two different IA-64 systems, and
+success has been reported by other users too. Non-Linux systems are not
+supported.
+
+MMAP
+
+Note that mmap() is now used by default wherever possible, since this seems
+to solve a number of problems. This default behavior can be changed in
+config.h. Just to make sure this is clear, mmap() is not used for performance
+reasons but to increase the number of systems on which dmidecode can be
+successfully run. See the IA-64 subsection above for details.
+
+CYGWIN
+
+Dmidecode was reported to work under Cygwin. It seems that /dev/mem doesn't
+work properly before version 1.5.10 though, so you will need to use at least
+this version.
+
+
+** MISCELLANEOUS TOOLS **
+
+Three other tools come along with dmidecode: biosdecode, ownership and
+vpddecode. These tools are only useful on systems with a BIOS, so they
+are not built on IA-64 by default.
+
+BIOSDECODE
+
+This one prints all BIOS related information it can find in /dev/mem.
+It used to be part of dmidecode itself, but as dmidecode was growing,
+we felt that the non-DMI part had to be moved to a separate tool.
+
+OWNERSHIP
+
+This tool was written on a request by Luc Van de Velde for use with Novell
+tools in his company. It retrieves the "ownership tag" that can be set on
+most Compaq computers. Since it uses the same mechanisms dmidecode and
+biosdecode use, and could be of some use for other people as well, we
+decided to make it part of the project.
+
+VPDDECODE
+
+This tool prints the contents of the "vital product data" structure as
+found in most IBM and Lenovo computers. It used to have a lookup table
+for the machine name, but it was unreliable and hard to maintain so it
+was ultimately dropped. It has a command line interface.
diff --git a/biosdecode.c b/biosdecode.c
new file mode 100644
index 0000000..354234e
--- /dev/null
+++ b/biosdecode.c
@@ -0,0 +1,666 @@
+/*
+ * BIOS Decode
+ *
+ * (C) 2000-2002 Alan Cox <alan@redhat.com>
+ * (C) 2002-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open unpatent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ * References:
+ * - DMTF "System Management BIOS Reference Specification"
+ * Version 2.3.4
+ * http://www.dmtf.org/standards/smbios
+ * - Intel "Preboot Execution Environment (PXE) Specification"
+ * Version 2.1
+ * http://www.intel.com/labs/manage/wfm/wfmspecs.htm
+ * - ACPI "Advanced Configuration and Power Interface Specification"
+ * Revision 2.0
+ * http://www.acpi.info/spec20.htm
+ * - Phoenix "BIOS32 Service Directory"
+ * Revision 0.4
+ * http://www.phoenix.com/en/support/white+papers-specs/
+ * - Microsoft "Plug and Play BIOS Specification"
+ * Version 1.0A
+ * http://www.microsoft.com/hwdev/tech/PnP/
+ * - Microsoft "PCI IRQ Routing Table Specification"
+ * Version 1.0
+ * http://www.microsoft.com/hwdev/archive/BUSBIOS/pciirq.asp
+ * - Compaq "Technical Reference Guide for Compaq Deskpro 4000 and 6000"
+ * First Edition
+ * http://h18000.www1.hp.com/support/techpubs/technical_reference_guides/113a1097.html
+ * - IBM "Using the BIOS Build ID to identify Thinkpad systems"
+ * Revision 2005-09-19
+ * http://www-307.ibm.com/pc/support/site.wss/MIGR-45120.html
+ * - Fujitsu application panel technical details
+ * As of July 23rd, 2004
+ * http://apanel.sourceforge.net/tech.php
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+
+/* Options are global */
+struct opt
+{
+ const char* devmem;
+ unsigned int flags;
+};
+static struct opt opt;
+
+#define FLAG_VERSION (1<<0)
+#define FLAG_HELP (1<<1)
+
+struct bios_entry {
+ const char *anchor;
+ size_t anchor_len; /* computed */
+ off_t low_address;
+ off_t high_address;
+ size_t (*length)(const u8 *);
+ int (*decode)(const u8*, size_t);
+};
+
+
+/*
+ * SMBIOS
+ */
+
+static size_t smbios_length(const u8 *p)
+{
+ return(p[0x05]==0x1E?0x1F:p[0x05]);
+}
+
+static int smbios_decode(const u8 *p, size_t len)
+{
+ if(len<0x1F || !checksum(p, p[0x05])
+ || memcmp("_DMI_", p+0x10, 5)!=0
+ || !checksum(p+0x10, 0x0F))
+ return 0;
+
+ printf("SMBIOS %u.%u present.\n",
+ p[0x06], p[0x07]);
+ printf("\tStructure Table Length: %u bytes\n",
+ WORD(p+0x16));
+ printf("\tStructure Table Address: 0x%08X\n",
+ DWORD(p+0x18));
+ printf("\tNumber Of Structures: %u\n",
+ WORD(p+0x1C));
+ printf("\tMaximum Structure Size: %u bytes\n",
+ WORD(p+0x08));
+
+ return 1;
+}
+
+static size_t dmi_length(const u8 *p)
+{
+ (void) p;
+
+ return(0x0F);
+}
+
+static int dmi_decode(const u8 *p, size_t len)
+{
+ if(len<0x0F || !checksum(p, len))
+ return 0;
+
+ printf("Legacy DMI %u.%u present.\n",
+ p[0x0E]>>4, p[0x0E]&0x0F);
+ printf("\tStructure Table Length: %u bytes\n",
+ WORD(p+0x06));
+ printf("\tStructure Table Address: 0x%08X\n",
+ DWORD(p+0x08));
+ printf("\tNumber Of Structures: %u\n",
+ WORD(p+0x0C));
+
+ return 1;
+}
+
+/*
+ * SYSID
+ */
+
+static size_t sysid_length(const u8 *p)
+{
+ return WORD(p+0x08);
+}
+
+static int sysid_decode(const u8 *p, size_t len)
+{
+ if(len<0x11 || !checksum(p, WORD(p+0x08)))
+ return 0;
+
+ printf("SYSID present.\n");
+ printf("\tRevision: %u\n",
+ p[0x10]);
+ printf("\tStructure Table Address: 0x%08X\n",
+ DWORD(p+0x0A));
+ printf("\tNumber Of Structures: %u\n",
+ WORD(p+0x0E));
+
+ return 1;
+}
+
+/*
+ * PnP
+ */
+
+static size_t pnp_length(const u8 *p)
+{
+ return(p[0x05]);
+}
+
+static const char *pnp_event_notification(u8 code)
+{
+ static const char *notification[]={
+ "Not Supported", /* 0x0 */
+ "Polling",
+ "Asynchronous",
+ "Unknown" /* 0x3 */
+ };
+
+ return notification[code];
+}
+
+static int pnp_decode(const u8 *p, size_t len)
+{
+ if(len<0x21 || !checksum(p, p[0x05]))
+ return 0;
+
+ printf("PNP BIOS %u.%u present.\n",
+ p[0x04]>>4, p[0x04]&0x0F);
+ printf("\tEvent Notification: %s\n",
+ pnp_event_notification(WORD(p+0x06)&0x03));
+ if((WORD(p+0x06)&0x03)==0x01)
+ printf("\tEvent Notification Flag Address: 0x%08X\n",
+ DWORD(p+0x09));
+ printf("\tReal Mode 16-bit Code Address: %04X:%04X\n",
+ WORD(p+0x0F), WORD(p+0x0D));
+ printf("\tReal Mode 16-bit Data Address: %04X:0000\n",
+ WORD(p+0x1B));
+ printf("\t16-bit Protected Mode Code Address: 0x%08X\n",
+ DWORD(p+0x13)+WORD(p+0x11));
+ printf("\t16-bit Protected Mode Data Address: 0x%08X\n",
+ DWORD(p+0x1D));
+ if(DWORD(p+0x17)!=0)
+ printf("\tOEM Device Identifier: %c%c%c%02X%02X\n",
+ 0x40+((p[0x17]>>2)&0x1F),
+ 0x40+((p[0x17]&0x03)<<3)+((p[0x18]>>5)&0x07),
+ 0x40+(p[0x18]&0x1F), p[0x19], p[0x20]);
+
+ return 1;
+}
+
+/*
+ * ACPI
+ */
+
+static size_t acpi_length(const u8 *p)
+{
+ return(p[15]==2?36:20);
+}
+
+static const char *acpi_revision(u8 code)
+{
+ switch(code)
+ {
+ case 0:
+ return " 1.0";
+ case 2:
+ return " 2.0";
+ default:
+ return "";
+ }
+}
+
+static int acpi_decode(const u8 *p, size_t len)
+{
+ if(len<20 || !checksum(p, 20))
+ return 0;
+
+ printf("ACPI%s present.\n",
+ acpi_revision(p[15]));
+ printf("\tOEM Identifier: %c%c%c%c%c%c\n",
+ p[9], p[10], p[11], p[12], p[13], p[14]);
+ printf("\tRSD Table 32-bit Address: 0x%08X\n",
+ DWORD(p+16));
+
+ if(len<36)
+ return 1;
+
+ if(DWORD(p+20)>len || !checksum(p, DWORD(p+20)))
+ return 0;
+
+ if(DWORD(p+20)<32) return 1;
+
+ printf("\tXSD Table 64-bit Address: 0x%08X%08X\n",
+ QWORD(p+24).h, QWORD(p+24).l);
+
+ return 1;
+}
+
+/*
+ * Sony
+ */
+
+static size_t sony_length(const u8 *p)
+{
+ return(p[0x05]);
+}
+
+static int sony_decode(const u8 *p, size_t len)
+{
+ if(!checksum(p, len))
+ return 0;
+
+ printf("Sony system detected.\n");
+
+ return 1;
+}
+
+/*
+ * BIOS32
+ */
+
+static size_t bios32_length(const u8 *p)
+{
+ return p[0x09]<<4;
+}
+
+static int bios32_decode(const u8 *p, size_t len)
+{
+ if(len<0x0A || !checksum(p, p[0x09]<<4))
+ return 0;
+
+ printf("BIOS32 Service Directory present.\n");
+ printf("\tRevision: %u\n",
+ p[0x08]);
+ printf("\tCalling Interface Address: 0x%08X\n",
+ DWORD(p+0x04));
+
+ return 1;
+}
+
+/*
+ * PIR
+ */
+
+static void pir_irqs(u16 code)
+{
+ if(code==0)
+ printf(" None");
+ else
+ {
+ u8 i;
+
+ for(i=0; i<16; i++)
+ if(code&(1<<i))
+ printf(" %u", i);
+ }
+}
+
+static void pir_slot_number(u8 code)
+{
+ if(code==0)
+ printf(" on-board");
+ else
+ printf(" slot number %u", code);
+}
+
+static size_t pir_length(const u8 *p)
+{
+ return WORD(p+6);
+}
+
+static int pir_decode(const u8 *p, size_t len)
+{
+ int i;
+
+ if(len<32 || !checksum(p, WORD(p+6)))
+ return 0;
+
+ printf("PCI Interrupt Routing %u.%u present.\n",
+ p[5], p[4]);
+ printf("\tRouter ID: %02x:%02x.%1x\n",
+ p[8], p[9]>>3, p[9]&0x07);
+ printf("\tExclusive IRQs:");
+ pir_irqs(WORD(p+10));
+ printf("\n");
+ if(DWORD(p+12)!=0)
+ printf("\tCompatible Router: %04x:%04x\n",
+ WORD(p+12), WORD(p+14));
+ if(DWORD(p+16)!=0)
+ printf("\tMiniport Data: 0x%08X\n",
+ DWORD(p+16));
+
+ for(i=1; i<=(WORD(p+6)-32)/16; i++)
+ {
+ printf("\tSlot Entry %u: ID %02x:%02x,",
+ i, p[(i+1)*16], p[(i+1)*16+1]>>3);
+ pir_slot_number(p[(i+1)*16+14]);
+ printf("\n");
+/* printf("\tSlot Entry %u\n", i);
+ printf("\t\tID: %02x:%02x\n",
+ p[(i+1)*16], p[(i+1)*16+1]>>3);
+ printf("\t\tLink Value for INTA#: %u\n",
+ p[(i+1)*16+2]);
+ printf("\t\tIRQ Bitmap for INTA#:");
+ pir_irqs(WORD(p+(i+1)*16+3));
+ printf("\n");
+ printf("\t\tLink Value for INTB#: %u\n",
+ p[(i+1)*16+5]);
+ printf("\t\tIRQ Bitmap for INTB#:");
+ pir_irqs(WORD(p+(i+1)*16+6));
+ printf("\n");
+ printf("\t\tLink Value for INTC#: %u\n",
+ p[(i+1)*16+8]);
+ printf("\t\tIRQ Bitmap for INTC#:");
+ pir_irqs(WORD(p+(i+1)*16+9));
+ printf("\n");
+ printf("\t\tLink Value for INTD#: %u\n",
+ p[(i+1)*16+11]);
+ printf("\t\tIRQ Bitmap for INTD#:");
+ pir_irqs(WORD(p+(i+1)*16+12));
+ printf("\n");
+ printf("\t\tSlot Number:");
+ pir_slot_number(p[(i+1)*16+14]);
+ printf("\n");*/
+ }
+
+ return 1;
+}
+
+/*
+ * Compaq-specific entries
+ */
+
+static size_t compaq_length(const u8 *p)
+{
+ return (p[4]*10+5);
+}
+
+static int compaq_decode(const u8 *p, size_t len)
+{
+ unsigned int i;
+ (void) len;
+
+ printf("Compaq-specific entries present.\n");
+
+ /* integrity checking (lack of checksum) */
+ for(i=0; i<p[4]; i++)
+ {
+ /*
+ * We do not check for truncated entries, because the length
+ * was computed from the number of records in compaq_length
+ * right above, so it can't be wrong.
+ */
+ if(p[5+i*10]!='$' || !(p[6+i*10]>='A' && p[6+i*10]<='Z')
+ || !(p[7+i*10]>='A' && p[7+i*10]<='Z')
+ || !(p[8+i*10]>='A' && p[8+i*10]<='Z'))
+ {
+ printf("\t Abnormal entry! Please report. [%02X %02X "
+ "%02X %02X]\n", p[5+i*10], p[6+i*10],
+ p[7+i*10], p[8+i*10]);
+ return 0;
+ }
+ }
+
+ for(i=0; i<p[4]; i++)
+ {
+ printf("\tEntry %u: %c%c%c%c at 0x%08X (%u bytes)\n",
+ i+1, p[5+i*10], p[6+i*10], p[7+i*10], p[8+i*10],
+ DWORD(p+9+i*10), WORD(p+13+i*10));
+ }
+
+ return 1;
+}
+
+/*
+ * VPD (vital product data, IBM-specific)
+ */
+
+static void vpd_print_entry(const char *name, const u8 *p, size_t len)
+{
+ size_t i;
+
+ printf("\t%s: ", name);
+ for(i=0; i<len; i++)
+ if(p[i]>=32 && p[i]<127)
+ printf("%c", p[i]);
+ printf("\n");
+}
+
+static size_t vpd_length(const u8 *p)
+{
+ return (p[5]);
+}
+
+static int vpd_decode(const u8 *p, size_t len)
+{
+ if(len<0x30)
+ return 0;
+
+ /* XSeries have longer records. */
+ if(!(len>=0x45 && checksum(p, len))
+ /* Some Netvista seem to work with this. */
+ && !checksum(p, 0x30)
+ /* The Thinkpad checksum does *not* include the first 13 bytes. */
+ && !checksum(p+0x0D, 0x30-0x0D))
+ return 0;
+
+ printf("VPD present.\n");
+
+ vpd_print_entry("BIOS Build ID", p+0x0D, 9);
+ vpd_print_entry("Box Serial Number", p+0x16, 7);
+ vpd_print_entry("Motherboard Serial Number", p+0x1D, 11);
+ vpd_print_entry("Machine Type/Model", p+0x28, 7);
+
+ if(len<0x45)
+ return 1;
+
+ vpd_print_entry("BIOS Release Date", p+0x30, 8);
+
+ return 1;
+}
+
+/*
+ * Fujitsu application panel
+ */
+
+static size_t fjkeyinf_length(const u8 *p)
+{
+ (void) p;
+ /*
+ * We don't know at this point, it's somewhere between 12 and 32.
+ * So we return the max, it shouldn't hurt.
+ */
+ return 32;
+}
+
+static int fjkeyinf_decode(const u8 *p, size_t len)
+{
+ (void) len;
+ int i;
+
+ printf("Fujitsu application panel present.\n");
+
+ for (i = 0; i < 6; i++)
+ {
+ if (*(p+8+i*4)==0)
+ return 1;
+ printf("\tDevice %d: type %u, chip %u", i+1,
+ *(p+8+i*4), *(p+8+i*4+2));
+ if (*(p+8+i*4+1)) /* Access method */
+ printf(", SMBus address 0x%x", *(p+8+i*4+3) >> 1);
+ printf("\n");
+ }
+
+ return 1;
+}
+
+/*
+ * Main
+ */
+
+static struct bios_entry bios_entries[]={
+ { "_SM_", 0, 0xF0000, 0xFFFFF, smbios_length, smbios_decode },
+ { "_DMI_", 0, 0xF0000, 0xFFFFF, dmi_length, dmi_decode },
+ { "_SYSID_", 0, 0xE0000, 0xFFFFF, sysid_length, sysid_decode },
+ { "$PnP", 0, 0xF0000, 0xFFFFF, pnp_length, pnp_decode },
+ { "RSD PTR ", 0, 0xE0000, 0xFFFFF, acpi_length, acpi_decode },
+ { "$SNY", 0, 0xE0000, 0xFFFFF, sony_length, sony_decode },
+ { "_32_", 0, 0xE0000, 0xFFFFF, bios32_length, bios32_decode },
+ { "$PIR", 0, 0xF0000, 0xFFFFF, pir_length, pir_decode },
+ { "32OS", 0, 0xE0000, 0xFFFFF, compaq_length, compaq_decode },
+ { "\252\125VPD", 0, 0xF0000, 0xFFFFF, vpd_length, vpd_decode },
+ { "FJKEYINF", 0, 0xF0000, 0xFFFFF, fjkeyinf_length, fjkeyinf_decode },
+ { NULL, 0, 0, 0, NULL, NULL }
+};
+
+/* Believe it or not, this is significantly faster than memcmp and strncmp */
+static inline int anchor_match(const struct bios_entry *entry, const char *p)
+{
+ size_t i;
+
+ for(i=0; i<entry->anchor_len; i++)
+ if(entry->anchor[i]!=p[i])
+ return 0;
+
+ return 1;
+}
+
+/* Return -1 on error, 0 on success */
+static int parse_command_line(int argc, char * const argv[])
+{
+ int option;
+ const char *optstring = "d:hV";
+ struct option longopts[]={
+ { "dev-mem", required_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { 0, 0, 0, 0 }
+ };
+
+ while((option=getopt_long(argc, argv, optstring, longopts, NULL))!=-1)
+ switch(option)
+ {
+ case 'd':
+ opt.devmem=optarg;
+ break;
+ case 'h':
+ opt.flags|=FLAG_HELP;
+ break;
+ case 'V':
+ opt.flags|=FLAG_VERSION;
+ break;
+ case '?':
+ return -1;
+ }
+
+ return 0;
+}
+
+static void print_help(void)
+{
+ static const char *help=
+ "Usage: biosdecode [OPTIONS]\n"
+ "Options are:\n"
+ " -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
+ " -h, --help Display this help text and exit\n"
+ " -V, --version Display the version and exit\n";
+
+ printf("%s", help);
+}
+
+int main(int argc, char * const argv[])
+{
+ u8 *buf;
+ off_t fp;
+ int i;
+
+ if(sizeof(u8)!=1 || sizeof(u16)!=2 || sizeof(u32)!=4)
+ {
+ fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+ exit(255);
+ }
+
+ /* Set default option values */
+ opt.devmem=DEFAULT_MEM_DEV;
+ opt.flags=0;
+
+ if(parse_command_line(argc, argv)<0)
+ exit(2);
+
+ if(opt.flags & FLAG_HELP)
+ {
+ print_help();
+ return 0;
+ }
+
+ if(opt.flags & FLAG_VERSION)
+ {
+ printf("%s\n", VERSION);
+ return 0;
+ }
+
+ printf("# biosdecode %s\n", VERSION);
+
+ if((buf=mem_chunk(0xE0000, 0x20000, opt.devmem))==NULL)
+ exit(1);
+
+ /* Compute anchor lengths once and for all */
+ for(i=0; bios_entries[i].anchor!=NULL; i++)
+ bios_entries[i].anchor_len = strlen(bios_entries[i].anchor);
+
+ for(fp=0xE0000; fp<=0xFFFF0; fp+=16)
+ {
+ u8 *p=buf+fp-0xE0000;
+
+ for(i=0; bios_entries[i].anchor!=NULL; i++)
+ {
+ if(anchor_match(&bios_entries[i], (char *)p)
+ && fp>=bios_entries[i].low_address
+ && fp<bios_entries[i].high_address)
+ {
+ off_t len=bios_entries[i].length(p);
+
+ if(fp+len-1<=bios_entries[i].high_address)
+ {
+ if(bios_entries[i].decode(p, len))
+ {
+ fp+=(((len-1)>>4)<<4);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ free(buf);
+
+ return 0;
+}
diff --git a/catsprintf.c b/catsprintf.c
new file mode 100644
index 0000000..e0914c4
--- /dev/null
+++ b/catsprintf.c
@@ -0,0 +1,20 @@
+#include "catsprintf.h"
+
+int catsprintf(char *buf, const char *format, ...) {
+ static int i = 0;
+
+ va_list arg; /*will point to each unnamed argument in turn*/
+ va_start(arg, format); /* point to first element after fmt*/
+
+
+ char b[8192];
+ int c = vsprintf (b, format, arg);
+ i += strlen(b);
+ //printf("%d %s (%d)\n", i, b, strlen(b));
+
+ strcat(buf, b);
+
+ va_end(arg); /*cleanup*/
+
+ return c;
+}
diff --git a/catsprintf.h b/catsprintf.h
new file mode 100644
index 0000000..992cb2e
--- /dev/null
+++ b/catsprintf.h
@@ -0,0 +1,10 @@
+#ifndef CAT
+#define CAT 1
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+int catsprintf(char *buf, const char *format, ...);
+/* sed -i -e 's/\<printf(/catsprintf(buffer, /g' dmidecode.c */
+
+#endif
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..c1d7d03
--- /dev/null
+++ b/config.h
@@ -0,0 +1,25 @@
+/*
+ * Configuration
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Default memory device file */
+#ifdef __BEOS__
+#define DEFAULT_MEM_DEV "/dev/misc/mem"
+#else
+#define DEFAULT_MEM_DEV "/dev/mem"
+#endif
+
+/* Use mmap or not */
+#ifndef __BEOS__
+#define USE_MMAP
+#endif
+
+/* Use memory alignment workaround or not */
+#ifdef __ia64__
+#define ALIGNMENT_WORKAROUND
+#endif
+
+#endif
diff --git a/dmidecode.c b/dmidecode.c
new file mode 100644
index 0000000..966b0d5
--- /dev/null
+++ b/dmidecode.c
@@ -0,0 +1,4140 @@
+/*
+ * DMI Decode
+ *
+ * (C) 2000-2002 Alan Cox <alan@redhat.com>
+ * (C) 2002-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open unpatent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ * Unless specified otherwise, all references are aimed at the "System
+ * Management BIOS Reference Specification, Version 2.5" document,
+ * available from http://www.dmtf.org/standards/smbios/.
+ *
+ * Note to contributors:
+ * Please reference every value you add or modify, especially if the
+ * information does not come from the above mentioned specification.
+ *
+ * Additional references:
+ * - Intel AP-485 revision 31
+ * "Intel Processor Identification and the CPUID Instruction"
+ * http://developer.intel.com/design/xeon/applnots/241618.htm
+ * - DMTF Master MIF version 040707
+ * "DMTF approved standard groups"
+ * http://www.dmtf.org/standards/dmi
+ * - IPMI 2.0 revision 1.0
+ * "Intelligent Platform Management Interface Specification"
+ * http://developer.intel.com/design/servers/ipmi/spec.htm
+ * - AMD publication #25481 revision 2.18
+ * "CPUID Specification"
+ * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "dmidecode.h"
+#include "dmiopt.h"
+#include "dmioem.h"
+
+#include "global.h"
+#include "catsprintf.h"
+
+static const char *out_of_spec = "<OUT OF SPEC>";
+static const char *bad_index = "<BAD INDEX>";
+
+/*
+ * Type-independant Stuff
+ */
+
+const char *dmi_string(struct dmi_header *dm, u8 s)
+{
+ char *bp=(char *)dm->data;
+ size_t i, len;
+
+ if(s==0)
+ return "Not Specified";
+
+ bp+=dm->length;
+ while(s>1 && *bp)
+ {
+ bp+=strlen(bp);
+ bp++;
+ s--;
+ }
+
+ if(!*bp)
+ return bad_index;
+
+ /* ASCII filtering */
+ len=strlen(bp);
+ for(i=0; i<len; i++)
+ if(bp[i]<32 || bp[i]==127)
+ bp[i]='.';
+
+ return bp;
+}
+
+static const char *dmi_smbios_structure_type(u8 code)
+{
+ static const char *type[]={
+ "BIOS", /* 0 */
+ "System",
+ "Base Board",
+ "Chassis",
+ "Processor",
+ "Memory Controller",
+ "Memory Module",
+ "Cache",
+ "Port Connector",
+ "System Slots",
+ "On Board Devices",
+ "OEM Strings",
+ "System Configuration Options",
+ "BIOS Language",
+ "Group Associations",
+ "System Event Log",
+ "Physical Memory Array",
+ "Memory Device",
+ "32-bit Memory Error",
+ "Memory Array Mapped Address",
+ "Memory Device Mapped Address",
+ "Built-in Pointing Device",
+ "Portable Battery",
+ "System Reset",
+ "Hardware Security",
+ "System Power Controls",
+ "Voltage Probe",
+ "Cooling Device",
+ "Temperature Probe",
+ "Electrical Current Probe",
+ "Out-of-band Remote Access",
+ "Boot Integrity Services",
+ "System Boot",
+ "64-bit Memory Error",
+ "Management Device",
+ "Management Device Component",
+ "Management Device Threshold Data",
+ "Memory Channel",
+ "IPMI Device",
+ "Power Supply" /* 39 */
+ };
+
+ if(code<=39)
+ return(type[code]);
+ return out_of_spec;
+}
+
+static int dmi_bcd_range(u8 value, u8 low, u8 high)
+{
+ if(value>0x99 || (value&0x0F)>0x09)
+ return 0;
+ if(value<low || value>high)
+ return 0;
+ return 1;
+}
+
+void dmi_dump(struct dmi_header *h, const char *prefix)
+{
+ int row, i;
+ const char *s;
+
+ catsprintf(buffer, "%sHeader and Data:\n", prefix);
+ for(row=0; row<((h->length-1)>>4)+1; row++)
+ {
+ catsprintf(buffer, "%s\t", prefix);
+ for(i=0; i<16 && i<h->length-(row<<4); i++)
+ catsprintf(buffer, "%s%02X", i?" ":"", (h->data)[(row<<4)+i]);
+ catsprintf(buffer, "\n");
+ }
+
+ if((h->data)[h->length] || (h->data)[h->length+1])
+ {
+ catsprintf(buffer, "%sStrings:\n", prefix);
+ i=1;
+ while((s=dmi_string(h, i++))!=bad_index)
+ {
+ if(opt.flags & FLAG_DUMP)
+ {
+ int j, l = strlen(s)+1;
+ for(row=0; row<((l-1)>>4)+1; row++)
+ {
+ catsprintf(buffer, "%s\t", prefix);
+ for(j=0; j<16 && j<l-(row<<4); j++)
+ catsprintf(buffer, "%s%02X", j?" ":"",
+ s[(row<<4)+j]);
+ catsprintf(buffer, "\n");
+ }
+ catsprintf(buffer, "%s\t\"%s\"\n", prefix, s);
+ }
+ else
+ catsprintf(buffer, "%s\t%s\n", prefix, s);
+ }
+ }
+}
+
+/*
+ * 3.3.1 BIOS Information (Type 0)
+ */
+
+static void dmi_bios_runtime_size(u32 code)
+{
+ if(code&0x000003FF)
+ catsprintf(buffer, " %u bytes", code);
+ else
+ catsprintf(buffer, " %u kB", code>>10);
+}
+
+static void dmi_bios_characteristics(u64 code, const char *prefix)
+{
+ /* 3.3.1.1 */
+ static const char *characteristics[]={
+ "BIOS characteristics not supported", /* 3 */
+ "ISA is supported",
+ "MCA is supported",
+ "EISA is supported",
+ "PCI is supported",
+ "PC Card (PCMCIA) is supported",
+ "PNP is supported",
+ "APM is supported",
+ "BIOS is upgradeable",
+ "BIOS shadowing is allowed",
+ "VLB is supported",
+ "ESCD support is available",
+ "Boot from CD is supported",
+ "Selectable boot is supported",
+ "BIOS ROM is socketed",
+ "Boot from PC Card (PCMCIA) is supported",
+ "EDD is supported",
+ "Japanese floppy for NEC 9800 1.2 MB is supported (int 13h)",
+ "Japanese floppy for Toshiba 1.2 MB is supported (int 13h)",
+ "5.25\"/360 KB floppy services are supported (int 13h)",
+ "5.25\"/1.2 MB floppy services are supported (int 13h)",
+ "3.5\"/720 KB floppy services are supported (int 13h)",
+ "3.5\"/2.88 MB floppy services are supported (int 13h)",
+ "Print screen service is supported (int 5h)",
+ "8042 keyboard services are supported (int 9h)",
+ "Serial services are supported (int 14h)",
+ "Printer services are supported (int 17h)",
+ "CGA/mono video services are supported (int 10h)",
+ "NEC PC-98" /* 31 */
+ };
+ int i;
+
+ /*
+ * This isn't very clear what this bit is supposed to mean
+ */
+ if(code.l&(1<<3))
+ {
+ catsprintf(buffer, "%s%s\n",
+ prefix, characteristics[0]);
+ return;
+ }
+
+ for(i=4; i<=31; i++)
+ if(code.l&(1<<i))
+ catsprintf(buffer, "%s%s\n",
+ prefix, characteristics[i-3]);
+}
+
+static void dmi_bios_characteristics_x1(u8 code, const char *prefix)
+{
+ /* 3.3.1.2.1 */
+ static const char *characteristics[]={
+ "ACPI is supported", /* 0 */
+ "USB legacy is supported",
+ "AGP is supported",
+ "I2O boot is supported",
+ "LS-120 boot is supported",
+ "ATAPI Zip drive boot is supported",
+ "IEEE 1394 boot is supported",
+ "Smart battery is supported" /* 7 */
+ };
+ int i;
+
+ for(i=0; i<=7; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, "%s%s\n",
+ prefix, characteristics[i]);
+}
+
+static void dmi_bios_characteristics_x2(u8 code, const char *prefix)
+{
+ /* 3.3.1.2.2 */
+ static const char *characteristics[]={
+ "BIOS boot specification is supported", /* 0 */
+ "Function key-initiated network boot is supported",
+ "Targeted content distribution is supported" /* 2 */
+ };
+ int i;
+
+ for(i=0; i<=2; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, "%s%s\n",
+ prefix, characteristics[i]);
+}
+
+/*
+ * 3.3.2 System Information (Type 1)
+ */
+
+void dmi_system_uuid(u8 *p)
+{
+ int only0xFF=1, only0x00=1;
+ int i;
+
+ for(i=0; i<16 && (only0x00 || only0xFF); i++)
+ {
+ if(p[i]!=0x00) only0x00=0;
+ if(p[i]!=0xFF) only0xFF=0;
+ }
+
+ if(only0xFF)
+ {
+ catsprintf(buffer, "Not Present");
+ return;
+ }
+ if(only0x00)
+ {
+ catsprintf(buffer, "Not Settable");
+ return;
+ }
+
+ catsprintf(buffer, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
+ p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+}
+
+static const char *dmi_system_wake_up_type(u8 code)
+{
+ /* 3.3.2.1 */
+ static const char *type[]={
+ "Reserved", /* 0x00 */
+ "Other",
+ "Unknown",
+ "APM Timer",
+ "Modem Ring",
+ "LAN Remote",
+ "Power Switch",
+ "PCI PME#",
+ "AC Power Restored" /* 0x08 */
+ };
+
+ if(code<=0x08)
+ return type[code];
+ return out_of_spec;
+}
+
+/*
+ * 3.3.3 Base Board Information (Type 2)
+ */
+
+static void dmi_base_board_features(u8 code, const char *prefix)
+{
+ /* 3.3.3.1 */
+ static const char *features[]={
+ "Board is a hosting board", /* 0 */
+ "Board requires at least one daughter board",
+ "Board is removable",
+ "Board is replaceable",
+ "Board is hot swappable" /* 4 */
+ };
+
+ if((code&0x1F)==0)
+ catsprintf(buffer, " None\n");
+ else
+ {
+ int i;
+
+ catsprintf(buffer, "\n");
+ for(i=0; i<=4; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, "%s%s\n",
+ prefix, features[i]);
+ }
+}
+
+static const char *dmi_base_board_type(u8 code)
+{
+ /* 3.3.3.2 */
+ static const char *type[]={
+ "Unknown", /* 0x01 */
+ "Other",
+ "Server Blade",
+ "Connectivity Switch",
+ "System Management Module",
+ "Processor Module",
+ "I/O Module",
+ "Memory Module",
+ "Daughter Board",
+ "Motherboard",
+ "Processor+Memory Module",
+ "Processor+I/O Module",
+ "Interconnect Board" /* 0x0D */
+ };
+
+ if(code>=0x01 && code<=0x0D)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_base_board_handles(u8 count, u8 *p, const char *prefix)
+{
+ int i;
+
+ catsprintf(buffer, "%sContained Object Handles: %u\n",
+ prefix, count);
+ for(i=0; i<count; i++)
+ catsprintf(buffer, "%s\t0x%04X\n",
+ prefix, WORD(p+sizeof(u16)*i));
+}
+
+/*
+ * 3.3.4 Chassis Information (Type 3)
+ */
+
+const char *dmi_chassis_type(u8 code)
+{
+ /* 3.3.4.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Desktop",
+ "Low Profile Desktop",
+ "Pizza Box",
+ "Mini Tower",
+ "Tower",
+ "Portable",
+ "Laptop",
+ "Notebook",
+ "Hand Held",
+ "Docking Station",
+ "All In One",
+ "Sub Notebook",
+ "Space-saving",
+ "Lunch Box",
+ "Main Server Chassis", /* master.mif says System */
+ "Expansion Chassis",
+ "Sub Chassis",
+ "Bus Expansion Chassis",
+ "Peripheral Chassis",
+ "RAID Chassis",
+ "Rack Mount Chassis",
+ "Sealed-case PC",
+ "Multi-system",
+ "CompactPCI",
+ "AdvancedTCA" /* 0x1B */
+ };
+
+ if(code>=0x01 && code<=0x1B)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_chassis_lock(u8 code)
+{
+ static const char *lock[]={
+ "Not Present", /* 0x00 */
+ "Present" /* 0x01 */
+ };
+
+ return lock[code];
+}
+
+static const char *dmi_chassis_state(u8 code)
+{
+ /* 3.3.4.2 */
+ static const char *state[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Safe", /* master.mif says OK */
+ "Warning",
+ "Critical",
+ "Non-recoverable" /* 0x06 */
+ };
+
+ if(code>=0x01 && code<=0x06)
+ return(state[code-0x01]);
+ return out_of_spec;
+}
+
+static const char *dmi_chassis_security_status(u8 code)
+{
+ /* 3.3.4.3 */
+ static const char *status[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "None",
+ "External Interface Locked Out",
+ "External Interface Enabled" /* 0x05 */
+ };
+
+ if(code>=0x01 && code<=0x05)
+ return(status[code-0x01]);
+ return out_of_spec;
+}
+
+static void dmi_chassis_height(u8 code)
+{
+ if(code==0x00)
+ catsprintf(buffer, " Unspecified");
+ else
+ catsprintf(buffer, " %u U", code);
+}
+
+static void dmi_chassis_power_cords(u8 code)
+{
+ if(code==0x00)
+ catsprintf(buffer, " Unspecified");
+ else
+ catsprintf(buffer, " %u", code);
+}
+
+static void dmi_chassis_elements(u8 count, u8 len, u8 *p, const char *prefix)
+{
+ int i;
+
+ catsprintf(buffer, "%sContained Elements: %u\n",
+ prefix, count);
+ for(i=0; i<count; i++)
+ {
+ if(len>=0x03)
+ {
+ catsprintf(buffer, "%s\t%s (",
+ prefix, p[i*len]&0x80?
+ dmi_smbios_structure_type(p[i*len]&0x7F):
+ dmi_base_board_type(p[i*len]&0x7F));
+ if(p[1+i*len]==p[2+i*len])
+ catsprintf(buffer, "%u", p[1+i*len]);
+ else
+ catsprintf(buffer, "%u-%u", p[1+i*len], p[2+i*len]);
+ catsprintf(buffer, ")\n");
+ }
+ }
+}
+
+/*
+ * 3.3.5 Processor Information (Type 4)
+ */
+
+static const char *dmi_processor_type(u8 code)
+{
+ /* 3.3.5.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Central Processor",
+ "Math Processor",
+ "DSP Processor",
+ "Video Processor" /* 0x06 */
+ };
+
+ if(code>=0x01 && code<=0x06)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+const char *dmi_processor_family(u8 code)
+{
+ /* 3.3.5.2 */
+ static const char *family[256]={
+ NULL, /* 0x00 */
+ "Other",
+ "Unknown",
+ "8086",
+ "80286",
+ "80386",
+ "80486",
+ "8087",
+ "80287",
+ "80387",
+ "80487",
+ "Pentium",
+ "Pentium Pro",
+ "Pentium II",
+ "Pentium MMX",
+ "Celeron",
+ "Pentium II Xeon",
+ "Pentium III",
+ "M1",
+ "M2",
+ NULL, /* 0x14 */
+ NULL,
+ NULL,
+ NULL, /* 0x17 */
+ "Duron",
+ "K5",
+ "K6",
+ "K6-2",
+ "K6-3",
+ "Athlon",
+ "AMD2900",
+ "K6-2+",
+ "Power PC",
+ "Power PC 601",
+ "Power PC 603",
+ "Power PC 603+",
+ "Power PC 604",
+ "Power PC 620",
+ "Power PC x704",
+ "Power PC 750",
+ NULL, /* 0x28 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,/* 0x2F */
+ "Alpha",
+ "Alpha 21064",
+ "Alpha 21066",
+ "Alpha 21164",
+ "Alpha 21164PC",
+ "Alpha 21164a",
+ "Alpha 21264",
+ "Alpha 21364",
+ NULL, /* 0x38 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x3F */
+ "MIPS",
+ "MIPS R4000",
+ "MIPS R4200",
+ "MIPS R4400",
+ "MIPS R4600",
+ "MIPS R10000",
+ NULL, /* 0x46 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x4F */
+ "SPARC",
+ "SuperSPARC",
+ "MicroSPARC II",
+ "MicroSPARC IIep",
+ "UltraSPARC",
+ "UltraSPARC II",
+ "UltraSPARC IIi",
+ "UltraSPARC III",
+ "UltraSPARC IIIi",
+ NULL, /* 0x59 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x5F */
+ "68040",
+ "68xxx",
+ "68000",
+ "68010",
+ "68020",
+ "68030",
+ NULL, /* 0x66 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x6F */
+ "Hobbit",
+ NULL, /* 0x71 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x77 */
+ "Crusoe TM5000",
+ "Crusoe TM3000",
+ "Efficeon TM8000",
+ NULL, /* 0x7B */
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x7F */
+ "Weitek",
+ NULL, /* 0x81 */
+ "Itanium",
+ "Athlon 64",
+ "Opteron",
+ "Sempron",
+ "Turion 64",
+ "Dual-Core Opteron",
+ "Athlon 64 X2",
+ NULL, /* 0x89 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x8F */
+ "PA-RISC",
+ "PA-RISC 8500",
+ "PA-RISC 8000",
+ "PA-RISC 7300LC",
+ "PA-RISC 7200",
+ "PA-RISC 7100LC",
+ "PA-RISC 7100",
+ NULL, /* 0x97 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x9F */
+ "V30",
+ NULL, /* 0xA1 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0xAF */
+ "Pentium III Xeon",
+ "Pentium III Speedstep",
+ "Pentium 4",
+ "Xeon",
+ "AS400",
+ "Xeon MP",
+ "Athlon XP",
+ "Athlon MP",
+ "Itanium 2",
+ "Pentium M",
+ "Celeron D",
+ "Pentium D",
+ "Pentium EE",
+ NULL, /* 0xBD */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0xC7 */
+ "IBM390",
+ "G4",
+ "G5",
+ NULL, /* 0xCB */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0xF9 */
+ "i860",
+ "i960",
+ NULL, /* 0xFC */
+ NULL,
+ NULL,
+ NULL /* 0xFF */
+ /* master.mif has values beyond that, but they can't be used for DMI */
+ };
+
+ if(family[code]!=NULL)
+ return family[code];
+ return out_of_spec;
+}
+
+static void dmi_processor_id(u8 type, u8 *p, const char *version, const char *prefix)
+{
+ /* Intel AP-485 revision 31, table 3-4 */
+ static const char *flags[32]={
+ "FPU (Floating-point unit on-chip)", /* 0 */
+ "VME (Virtual mode extension)",
+ "DE (Debugging extension)",
+ "PSE (Page size extension)",
+ "TSC (Time stamp counter)",
+ "MSR (Model specific registers)",
+ "PAE (Physical address extension)",
+ "MCE (Machine check exception)",
+ "CX8 (CMPXCHG8 instruction supported)",
+ "APIC (On-chip APIC hardware supported)",
+ NULL, /* 10 */
+ "SEP (Fast system call)",
+ "MTRR (Memory type range registers)",
+ "PGE (Page global enable)",
+ "MCA (Machine check architecture)",
+ "CMOV (Conditional move instruction supported)",
+ "PAT (Page attribute table)",
+ "PSE-36 (36-bit page size extension)",
+ "PSN (Processor serial number present and enabled)",
+ "CLFSH (CLFLUSH instruction supported)",
+ NULL, /* 20 */
+ "DS (Debug store)",
+ "ACPI (ACPI supported)",
+ "MMX (MMX technology supported)",
+ "FXSR (Fast floating-point save and restore)",
+ "SSE (Streaming SIMD extensions)",
+ "SSE2 (Streaming SIMD extensions 2)",
+ "SS (Self-snoop)",
+ "HTT (Hyper-threading technology)",
+ "TM (Thermal monitor supported)",
+ "IA64 (IA64 capabilities)",
+ "PBE (Pending break enabled)" /* 31 */
+ };
+ /*
+ * Extra flags are now returned in the ECX register when one calls
+ * the CPUID instruction. Their meaning is explained in table 3-5, but
+ * DMI doesn't support this yet.
+ */
+ u32 eax, edx;
+ int sig=0;
+
+ /*
+ * This might help learn about new processors supporting the
+ * CPUID instruction or another form of identification.
+ */
+ catsprintf(buffer, "%sID: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ prefix, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+
+ if(type==0x05) /* 80386 */
+ {
+ u16 dx=WORD(p);
+ /*
+ * 80386 have a different signature.
+ */
+ catsprintf(buffer, "%sSignature: Type %u, Family %u, Major Stepping %u, Minor Stepping %u\n",
+ prefix, dx>>12, (dx>>8)&0xF, (dx>>4)&0xF, dx&0xF);
+ return;
+ }
+ if(type==0x06) /* 80486 */
+ {
+ u16 dx=WORD(p);
+ /*
+ * Not all 80486 CPU support the CPUID instruction, we have to find
+ * wether the one we have here does or not. Note that this trick
+ * works only because we know that 80486 must be little-endian.
+ */
+ if((dx&0x0F00)==0x0400
+ && ((dx&0x00F0)==0x0040 || (dx&0x00F0)>=0x0070)
+ && ((dx&0x000F)>=0x0003))
+ sig=1;
+ else
+ {
+ catsprintf(buffer, "%sSignature: Type %u, Family %u, Model %u, Stepping %u\n",
+ prefix, (dx>>12)&0x3, (dx>>8)&0xF, (dx>>4)&0xF, dx&0xF);
+ return;
+ }
+ }
+ else if((type>=0x0B && type<=0x13) /* Intel, Cyrix */
+ || (type>=0xB0 && type<=0xB3) /* Intel */
+ || type==0xB5 /* Intel */
+ || (type>=0xB9 && type<=0xBC)) /* Intel */
+ sig=1;
+ else if((type>=0x18 && type<=0x1D) /* AMD */
+ || type==0x1F /* AMD */
+ || (type>=0xB6 && type<=0xB7) /* AMD */
+ || (type>=0x83 && type<=0x88)) /* AMD */
+ sig=2;
+ else if(type==0x01 || type==0x02)
+ {
+ /*
+ * Some X86-class CPU have family "Other" or "Unknown". In this case,
+ * we use the version string to determine if they are known to
+ * support the CPUID instruction.
+ */
+ if(strncmp(version, "Pentium III MMX", 15)==0)
+ sig=1;
+ else if(strncmp(version, "AMD Athlon(TM)", 14)==0
+ || strncmp(version, "AMD Opteron(tm)", 15)==0)
+ sig=2;
+ else
+ return;
+ }
+ else /* not X86-class */
+ return;
+
+ eax=DWORD(p);
+ edx=DWORD(p+4);
+ switch(sig)
+ {
+ case 1: /* Intel */
+ catsprintf(buffer, "%sSignature: Type %u, Family %u, Model %u, Stepping %u\n",
+ prefix, (eax>>12)&0x3, ((eax>>20)&0xFF)+((eax>>8)&0x0F),
+ ((eax>>12)&0xF0)+((eax>>4)&0x0F), eax&0xF);
+ break;
+ case 2: /* AMD */
+ catsprintf(buffer, "%sSignature: Family %u, Model %u, Stepping %u\n",
+ prefix,
+ ((eax>>8)&0xF)+(((eax>>8)&0xF)==0xF?(eax>>20)&0xFF:0),
+ ((eax>>4)&0xF)|(((eax>>8)&0xF)==0xF?(eax>>12)&0xF0:0),
+ eax&0xF);
+ break;
+ }
+
+ edx=DWORD(p+4);
+ catsprintf(buffer, "%sFlags:", prefix);
+ if((edx&0xFFEFFBFF)==0)
+ catsprintf(buffer, " None\n");
+ else
+ {
+ int i;
+
+ catsprintf(buffer, "\n");
+ for(i=0; i<=31; i++)
+ if(flags[i]!=NULL && edx&(1<<i))
+ catsprintf(buffer, "%s\t%s\n", prefix, flags[i]);
+ }
+}
+
+static void dmi_processor_voltage(u8 code)
+{
+ /* 3.3.5.4 */
+ static const char *voltage[]={
+ "5.0 V", /* 0 */
+ "3.3 V",
+ "2.9 V" /* 2 */
+ };
+ int i;
+
+ if(code&0x80)
+ catsprintf(buffer, " %.1f V", (float)(code&0x7f)/10);
+ else
+ {
+ for(i=0; i<=2; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, " %s", voltage[i]);
+ if(code==0x00)
+ catsprintf(buffer, " Unknown");
+ }
+}
+
+void dmi_processor_frequency(u8 *p)
+{
+ u16 code = WORD(p);
+
+ if(code)
+ catsprintf(buffer, "%u MHz", code);
+ else
+ catsprintf(buffer, "Unknown");
+}
+
+static const char *dmi_processor_status(u8 code)
+{
+ static const char *status[]={
+ "Unknown", /* 0x00 */
+ "Enabled",
+ "Disabled By User",
+ "Disabled By BIOS",
+ "Idle", /* 0x04 */
+ "Other" /* 0x07 */
+ };
+
+ if(code<=0x04)
+ return status[code];
+ if(code==0x07)
+ return status[0x05];
+ return out_of_spec;
+}
+
+static const char *dmi_processor_upgrade(u8 code)
+{
+ /* 3.3.5.5 */
+ static const char *upgrade[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Daughter Board",
+ "ZIF Socket",
+ "Replaceable Piggy Back",
+ "None",
+ "LIF Socket",
+ "Slot 1",
+ "Slot 2",
+ "370-pin Socket",
+ "Slot A",
+ "Slot M",
+ "Socket 423",
+ "Socket A (Socket 462)",
+ "Socket 478",
+ "Socket 754",
+ "Socket 940",
+ "Socket 939",
+ "Socket mPGA604",
+ "Socket LGA771",
+ "Socket LGA775" /* 0x15 */
+ };
+
+ if(code>=0x01 && code<=0x15)
+ return upgrade[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_processor_cache(u16 code, const char *level, u16 ver)
+{
+ if(code==0xFFFF)
+ {
+ if(ver>=0x0203)
+ catsprintf(buffer, " Not Provided");
+ else
+ catsprintf(buffer, " No %s Cache", level);
+ }
+ else
+ catsprintf(buffer, " 0x%04X", code);
+}
+
+static void dmi_processor_characteristics(u16 code, const char *prefix)
+{
+ /* 3.3.5.9 */
+ static const char *characteristics[]={
+ "64-bit capable" /* 2 */
+ };
+
+ if((code&0x0004)==0)
+ catsprintf(buffer, " None\n");
+ else
+ {
+ int i;
+
+ catsprintf(buffer, "\n");
+ for(i=2; i<=2; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, "%s%s\n", prefix, characteristics[i-2]);
+ }
+}
+
+/*
+ * 3.3.6 Memory Controller Information (Type 5)
+ */
+
+static const char *dmi_memory_controller_ed_method(u8 code)
+{
+ /* 3.3.6.1 */
+ static const char *method[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "None",
+ "8-bit Parity",
+ "32-bit ECC",
+ "64-bit ECC",
+ "128-bit ECC",
+ "CRC" /* 0x08 */
+ };
+
+ if(code>=0x01 && code<=0x08)
+ return(method[code-0x01]);
+ return out_of_spec;
+}
+
+static void dmi_memory_controller_ec_capabilities(u8 code, const char *prefix)
+{
+ /* 3.3.6.2 */
+ static const char *capabilities[]={
+ "Other", /* 0 */
+ "Unknown",
+ "None",
+ "Single-bit Error Correcting",
+ "Double-bit Error Correcting",
+ "Error Scrubbing" /* 5 */
+ };
+
+ if((code&0x3F)==0)
+ catsprintf(buffer, " None\n");
+ else
+ {
+ int i;
+
+ catsprintf(buffer, "\n");
+ for(i=0; i<=5; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, "%s%s\n", prefix, capabilities[i]);
+ }
+}
+
+static const char* dmi_memory_controller_interleave(u8 code)
+{
+ /* 3.3.6.3 */
+ static const char *interleave[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "One-way Interleave",
+ "Two-way Interleave",
+ "Four-way Interleave",
+ "Eight-way Interleave",
+ "Sixteen-way Interleave" /* 0x07 */
+ };
+
+ if(code>=0x01 && code<=0x07)
+ return(interleave[code-0x01]);
+ return(out_of_spec);
+}
+
+static void dmi_memory_controller_speeds(u16 code, const char *prefix)
+{
+ /* 3.3.6.4 */
+ const char *speeds[]={
+ "Other", /* 0 */
+ "Unknown",
+ "70 ns",
+ "60 ns",
+ "50 ns" /* 4 */
+ };
+
+ if((code&0x001F)==0)
+ catsprintf(buffer, " None\n");
+ else
+ {
+ int i;
+
+ catsprintf(buffer, "\n");
+ for(i=0; i<=4; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, "%s%s\n", prefix, speeds[i]);
+ }
+}
+
+static void dmi_memory_controller_slots(u8 count, u8 *p, const char *prefix)
+{
+ int i;
+
+ catsprintf(buffer, "%sAssociated Memory Slots: %u\n",
+ prefix, count);
+ for(i=0; i<count; i++)
+ catsprintf(buffer, "%s\t0x%04X\n",
+ prefix, WORD(p+sizeof(u16)*i));
+}
+
+/*
+ * 3.3.7 Memory Module Information (Type 6)
+ */
+
+static void dmi_memory_module_types(u16 code, const char *sep)
+{
+ /* 3.3.7.1 */
+ static const char *types[]={
+ "Other", /* 0 */
+ "Unknown",
+ "Standard",
+ "FPM",
+ "EDO",
+ "Parity",
+ "ECC",
+ "SIMM",
+ "DIMM",
+ "Burst EDO",
+ "SDRAM" /* 10 */
+ };
+
+ if((code&0x07FF)==0)
+ catsprintf(buffer, " None");
+ else
+ {
+ int i;
+
+ for(i=0; i<=10; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, "%s%s", sep, types[i]);
+ }
+}
+
+static void dmi_memory_module_connections(u8 code)
+{
+ if(code==0xFF)
+ catsprintf(buffer, " None");
+ else
+ {
+ if((code&0xF0)!=0xF0)
+ catsprintf(buffer, " %u", code>>4);
+ if((code&0x0F)!=0x0F)
+ catsprintf(buffer, " %u", code&0x0F);
+ }
+}
+
+static void dmi_memory_module_speed(u8 code)
+{
+ if(code==0)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u ns", code);
+}
+
+static void dmi_memory_module_size(u8 code)
+{
+ /* 3.3.7.2 */
+ switch(code&0x7F)
+ {
+ case 0x7D:
+ catsprintf(buffer, " Not Determinable");
+ break;
+ case 0x7E:
+ catsprintf(buffer, " Disabled");
+ break;
+ case 0x7F:
+ catsprintf(buffer, " Not Installed");
+ return;
+ default:
+ catsprintf(buffer, " %u MB", 1<<(code&0x7F));
+ }
+
+ if(code&0x80)
+ catsprintf(buffer, " (Double-bank Connection)");
+ else
+ catsprintf(buffer, " (Single-bank Connection)");
+}
+
+static void dmi_memory_module_error(u8 code, const char *prefix)
+{
+ if(code&(1<<2))
+ catsprintf(buffer, " See Event Log\n");
+ else
+ { if((code&0x03)==0)
+ catsprintf(buffer, " OK\n");
+ if(code&(1<<0))
+ catsprintf(buffer, "%sUncorrectable Errors\n", prefix);
+ if(code&(1<<1))
+ catsprintf(buffer, "%sCorrectable Errors\n", prefix);
+ }
+}
+
+/*
+ * 3.3.8 Cache Information (Type 7)
+ */
+
+static const char *dmi_cache_mode(u8 code)
+{
+ static const char *mode[]={
+ "Write Through", /* 0x00 */
+ "Write Back",
+ "Varies With Memory Address",
+ "Unknown" /* 0x03 */
+ };
+
+ return mode[code];
+}
+
+static const char *dmi_cache_location(u8 code)
+{
+ static const char *location[4]={
+ "Internal", /* 0x00 */
+ "External",
+ NULL, /* 0x02 */
+ "Unknown" /* 0x03 */
+ };
+
+ if(location[code]!=NULL)
+ return location[code];
+ return out_of_spec;
+}
+
+static void dmi_cache_size(u16 code)
+{
+ if(code&0x8000)
+ catsprintf(buffer, " %u KB", (code&0x7FFF)<<6);
+ else
+ catsprintf(buffer, " %u KB", code);
+}
+
+static void dmi_cache_types(u16 code, const char *sep)
+{
+ /* 3.3.8.2 */
+ static const char *types[]={
+ "Other", /* 0 */
+ "Unknown",
+ "Non-burst",
+ "Burst",
+ "Pipeline Burst",
+ "Synchronous",
+ "Asynchronous" /* 6 */
+ };
+
+ if((code&0x007F)==0)
+ catsprintf(buffer, " None");
+ else
+ {
+ int i;
+
+ for(i=0; i<=6; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, "%s%s", sep, types[i]);
+ }
+}
+
+static const char *dmi_cache_ec_type(u8 code)
+{
+ /* 3.3.8.3 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "None",
+ "Parity",
+ "Single-bit ECC",
+ "Multi-bit ECC" /* 0x06 */
+ };
+
+ if(code>=0x01 && code<=0x06)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_cache_type(u8 code)
+{
+ /* 3.3.8.4 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Instruction",
+ "Data",
+ "Unified" /* 0x05 */
+ };
+
+ if(code>=0x01 && code<=0x05)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_cache_associativity(u8 code)
+{
+ /* 3.3.8.5 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Direct Mapped",
+ "2-way Set-associative",
+ "4-way Set-associative",
+ "Fully Associative",
+ "8-way Set-associative",
+ "16-way Set-associative" /* 0x08 */
+ };
+
+ if(code>=0x01 && code<=0x08)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+/*
+ * 3.3.9 Port Connector Information (Type 8)
+ */
+
+static const char *dmi_port_connector_type(u8 code)
+{
+ /* 3.3.9.2 */
+ static const char *type[]={
+ "None", /* 0x00 */
+ "Centronics",
+ "Mini Centronics",
+ "Proprietary",
+ "DB-25 male",
+ "DB-25 female",
+ "DB-15 male",
+ "DB-15 female",
+ "DB-9 male",
+ "DB-9 female",
+ "RJ-11",
+ "RJ-45",
+ "50 Pin MiniSCSI",
+ "Mini DIN",
+ "Micro DIN",
+ "PS/2",
+ "Infrared",
+ "HP-HIL",
+ "Access Bus (USB)",
+ "SSA SCSI",
+ "Circular DIN-8 male",
+ "Circular DIN-8 female",
+ "On Board IDE",
+ "On Board Floppy",
+ "9 Pin Dual Inline (pin 10 cut)",
+ "25 Pin Dual Inline (pin 26 cut)",
+ "50 Pin Dual Inline",
+ "68 Pin Dual Inline",
+ "On Board Sound Input From CD-ROM",
+ "Mini Centronics Type-14",
+ "Mini Centronics Type-26",
+ "Mini Jack (headphones)",
+ "BNC",
+ "IEEE 1394",
+ "SAS/SATA Plug Receptacle" /* 0x22 */
+ };
+ static const char *type_0xA0[]={
+ "PC-98", /* 0xA0 */
+ "PC-98 Hireso",
+ "PC-H98",
+ "PC-98 Note",
+ "PC-98 Full" /* 0xA4 */
+ };
+
+ if(code<=0x22)
+ return type[code];
+ if(code>=0xA0 && code<=0xA4)
+ return type_0xA0[code-0xA0];
+ if(code==0xFF)
+ return "Other";
+ return out_of_spec;
+}
+
+static const char *dmi_port_type(u8 code)
+{
+ /* 3.3.9.3 */
+ static const char *type[]={
+ "None", /* 0x00 */
+ "Parallel Port XT/AT Compatible",
+ "Parallel Port PS/2",
+ "Parallel Port ECP",
+ "Parallel Port EPP",
+ "Parallel Port ECP/EPP",
+ "Serial Port XT/AT Compatible",
+ "Serial Port 16450 Compatible",
+ "Serial Port 16550 Compatible",
+ "Serial Port 16550A Compatible",
+ "SCSI Port",
+ "MIDI Port",
+ "Joystick Port",
+ "Keyboard Port",
+ "Mouse Port",
+ "SSA SCSI",
+ "USB",
+ "Firewire (IEEE P1394)",
+ "PCMCIA Type I",
+ "PCMCIA Type II",
+ "PCMCIA Type III",
+ "Cardbus",
+ "Access Bus Port",
+ "SCSI II",
+ "SCSI Wide",
+ "PC-98",
+ "PC-98 Hireso",
+ "PC-H98",
+ "Video Port",
+ "Audio Port",
+ "Modem Port",
+ "Network Port",
+ "SATA",
+ "SAS" /* 0x21 */
+ };
+ static const char *type_0xA0[]={
+ "8251 Compatible", /* 0xA0 */
+ "8251 FIFO Compatible" /* 0xA1 */
+ };
+
+ if(code<=0x21)
+ return type[code];
+ if(code>=0xA0 && code<=0xA1)
+ return type_0xA0[code-0xA0];
+ if(code==0xFF)
+ return "Other";
+ return out_of_spec;
+}
+
+/*
+ * 3.3.10 System Slots (Type 9)
+ */
+
+static const char *dmi_slot_type(u8 code)
+{
+ /* 3.3.10.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "ISA",
+ "MCA",
+ "EISA",
+ "PCI",
+ "PC Card (PCMCIA)",
+ "VLB",
+ "Proprietary",
+ "Processor Card",
+ "Proprietary Memory Card",
+ "I/O Riser Card",
+ "NuBus",
+ "PCI-66",
+ "AGP",
+ "AGP 2x",
+ "AGP 4x",
+ "PCI-X",
+ "AGP 8x" /* 0x13 */
+ };
+ static const char *type_0xA0[]={
+ "PC-98/C20", /* 0xA0 */
+ "PC-98/C24",
+ "PC-98/E",
+ "PC-98/Local Bus",
+ "PC-98/Card",
+ "PCI Express" /* 0xA5 */
+ };
+
+ if(code>=0x01 && code<=0x13)
+ return type[code-0x01];
+ if(code>=0xA0 && code<=0xA5)
+ return type_0xA0[code-0xA0];
+ return out_of_spec;
+}
+
+static const char *dmi_slot_bus_width(u8 code)
+{
+ /* 3.3.10.2 */
+ static const char *width[]={
+ "", /* 0x01, "Other" */
+ "", /* "Unknown" */
+ "8-bit ",
+ "16-bit ",
+ "32-bit ",
+ "64-bit ",
+ "128-bit ",
+ "x1 ",
+ "x2 ",
+ "x4 ",
+ "x8 ",
+ "x12 ",
+ "x16 ",
+ "x32 " /* 0x0E */
+ };
+
+ if(code>=0x01 && code<=0x0E)
+ return width[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_slot_current_usage(u8 code)
+{
+ /* 3.3.10.3 */
+ static const char *usage[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Available",
+ "In Use" /* 0x04 */
+ };
+
+ if(code>=0x01 && code<=0x04)
+ return usage[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_slot_length(u8 code)
+{
+ /* 3.3.1O.4 */
+ static const char *length[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Short",
+ "Long" /* 0x04 */
+ };
+
+ if(code>=0x01 && code<=0x04)
+ return length[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_slot_id(u8 code1, u8 code2, u8 type, const char *prefix)
+{
+ /* 3.3.10.5 */
+ switch(type)
+ {
+ case 0x04: /* MCA */
+ catsprintf(buffer, "%sID: %u\n", prefix, code1);
+ break;
+ case 0x05: /* EISA */
+ catsprintf(buffer, "%sID: %u\n", prefix, code1);
+ break;
+ case 0x06: /* PCI */
+ case 0x0E: /* PCI */
+ case 0x0F: /* AGP */
+ case 0x10: /* AGP */
+ case 0x11: /* AGP */
+ case 0x12: /* PCI-X */
+ case 0x13: /* AGP */
+ case 0xA5: /* PCI Express */
+ catsprintf(buffer, "%sID: %u\n", prefix, code1);
+ break;
+ case 0x07: /* PCMCIA */
+ catsprintf(buffer, "%sID: Adapter %u, Socket %u\n", prefix, code1, code2);
+ break;
+ }
+}
+
+static void dmi_slot_characteristics(u8 code1, u8 code2, const char *prefix)
+{
+ /* 3.3.10.6 */
+ static const char *characteristics1[]={
+ "5.0 V is provided", /* 1 */
+ "3.3 V is provided",
+ "Opening is shared",
+ "PC Card-16 is supported",
+ "Cardbus is supported",
+ "Zoom Video is supported",
+ "Modem ring resume is supported" /* 7 */
+ };
+ /* 3.3.10.7 */
+ static const char *characteristics2[]={
+ "PME signal is supported", /* 0 */
+ "Hot-plug devices are supported",
+ "SMBus signal is supported" /* 2 */
+ };
+
+ if(code1&(1<<0))
+ catsprintf(buffer, " Unknown\n");
+ else if((code1&0xFE)==0 && (code2&0x07)==0)
+ catsprintf(buffer, " None\n");
+ else
+ {
+ int i;
+
+ catsprintf(buffer, "\n");
+ for(i=1; i<=7; i++)
+ if(code1&(1<<i))
+ catsprintf(buffer, "%s%s\n", prefix, characteristics1[i-1]);
+ for(i=0; i<=2; i++)
+ if(code2&(1<<i))
+ catsprintf(buffer, "%s%s\n", prefix, characteristics2[i]);
+ }
+}
+
+/*
+ * 3.3.11 On Board Devices Information (Type 10)
+ */
+
+static const char *dmi_on_board_devices_type(u8 code)
+{
+ /* 3.3.11.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Video",
+ "SCSI Controller",
+ "Ethernet",
+ "Token Ring",
+ "Sound",
+ "PATA Controller",
+ "SATA Controller",
+ "SAS Controller" /* 0x0A */
+ };
+
+ if(code>=0x01 && code<=0x0A)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_on_board_devices(struct dmi_header *h, const char *prefix)
+{
+ u8 *p=h->data+4;
+ u8 count=(h->length-0x04)/2;
+ int i;
+
+ for(i=0; i<count; i++)
+ {
+ if(count==1)
+ catsprintf(buffer, "%sOn Board Device Information\n",
+ prefix);
+ else
+ catsprintf(buffer, "%sOn Board Device %d Information\n",
+ prefix, i+1);
+ catsprintf(buffer, "%s\tType: %s\n",
+ prefix, dmi_on_board_devices_type(p[2*i]&0x7F));
+ catsprintf(buffer, "%s\tStatus: %s\n",
+ prefix, p[2*i]&0x80?"Enabled":"Disabled");
+ catsprintf(buffer, "%s\tDescription: %s\n",
+ prefix, dmi_string(h, p[2*i+1]));
+ }
+}
+
+/*
+ * 3.3.12 OEM Strings (Type 11)
+ */
+
+static void dmi_oem_strings(struct dmi_header *h, const char *prefix)
+{
+ u8 *p=h->data+4;
+ u8 count=p[0x00];
+ int i;
+
+ for(i=1; i<=count; i++)
+ catsprintf(buffer, "%sString %d: %s\n",
+ prefix, i, dmi_string(h, i));
+}
+
+/*
+ * 3.3.13 System Configuration Options (Type 12)
+ */
+
+static void dmi_system_configuration_options(struct dmi_header *h, const char *prefix)
+{
+ u8 *p=h->data+4;
+ u8 count=p[0x00];
+ int i;
+
+ for(i=1; i<=count; i++)
+ catsprintf(buffer, "%sOption %d: %s\n",
+ prefix, i, dmi_string(h, i));
+}
+
+/*
+ * 3.3.14 BIOS Language Information (Type 13)
+ */
+
+static void dmi_bios_languages(struct dmi_header *h, const char *prefix)
+{
+ u8 *p=h->data+4;
+ u8 count=p[0x00];
+ int i;
+
+ for(i=1; i<=count; i++)
+ catsprintf(buffer, "%s%s\n",
+ prefix, dmi_string(h, i));
+}
+
+/*
+ * 3.3.15 Group Associations (Type 14)
+ */
+
+static void dmi_group_associations_items(u8 count, u8 *p, const char *prefix)
+{
+ int i;
+
+ for(i=0; i<count; i++)
+ {
+ catsprintf(buffer, "%s0x%04X (%s)\n",
+ prefix, WORD(p+3*i+1),
+ dmi_smbios_structure_type(p[3*i]));
+ }
+}
+
+/*
+ * 3.3.16 System Event Log (Type 15)
+ */
+
+static const char *dmi_event_log_method(u8 code)
+{
+ static const char *method[]={
+ "Indexed I/O, one 8-bit index port, one 8-bit data port", /* 0x00 */
+ "Indexed I/O, two 8-bit index ports, one 8-bit data port",
+ "Indexed I/O, one 16-bit index port, one 8-bit data port",
+ "Memory-mapped physical 32-bit address",
+ "General-purpose non-volatile data functions" /* 0x04 */
+ };
+
+ if(code<=0x04)
+ return method[code];
+ if(code>=0x80)
+ return "OEM-specific";
+ return out_of_spec;
+}
+
+static void dmi_event_log_status(u8 code)
+{
+ static const char *valid[]={
+ "Invalid", /* 0 */
+ "Valid" /* 1 */
+ };
+ static const char *full[]={
+ "Not Full", /* 0 */
+ "Full" /* 1 */
+ };
+
+ catsprintf(buffer, " %s, %s",
+ valid[(code>>0)&1], full[(code>>1)&1]);
+}
+
+static void dmi_event_log_address(u8 method, u8 *p)
+{
+ /* 3.3.16.3 */
+ switch(method)
+ {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ catsprintf(buffer, " Index 0x%04X, Data 0x%04X", WORD(p), WORD(p+2));
+ break;
+ case 0x03:
+ catsprintf(buffer, " 0x%08X", DWORD(p));
+ break;
+ case 0x04:
+ catsprintf(buffer, " 0x%04X", WORD(p));
+ break;
+ default:
+ catsprintf(buffer, " Unknown");
+ }
+}
+
+static const char *dmi_event_log_header_type(u8 code)
+{
+ static const char *type[]={
+ "No Header", /* 0x00 */
+ "Type 1" /* 0x01 */
+ };
+
+ if(code<=0x01)
+ return type[code];
+ if(code>=0x80)
+ return "OEM-specific";
+ return out_of_spec;
+}
+
+static const char *dmi_event_log_descriptor_type(u8 code)
+{
+ /* 3.3.16.6.1 */
+ static const char *type[]={
+ NULL, /* 0x00 */
+ "Single-bit ECC memory error",
+ "Multi-bit ECC memory error",
+ "Parity memory error",
+ "Bus timeout",
+ "I/O channel block",
+ "Software NMI",
+ "POST memory resize",
+ "POST error",
+ "PCI parity error",
+ "PCI system error",
+ "CPU failure",
+ "EISA failsafe timer timeout",
+ "Correctable memory log disabled",
+ "Logging disabled",
+ NULL, /* 0x0F */
+ "System limit exceeded",
+ "Asynchronous hardware timer expired",
+ "System configuration information",
+ "Hard disk information",
+ "System reconfigured",
+ "Uncorrectable CPU-complex error",
+ "Log area reset/cleared",
+ "System boot" /* 0x17 */
+ };
+
+ if(code<=0x17 && type[code]!=NULL)
+ return type[code];
+ if(code>=0x80 && code<=0xFE)
+ return "OEM-specific";
+ if(code==0xFF)
+ return "End of log";
+ return out_of_spec;
+}
+
+static const char *dmi_event_log_descriptor_format(u8 code)
+{
+ /* 3.3.16.6.2 */
+ static const char *format[]={
+ "None", /* 0x00 */
+ "Handle",
+ "Multiple-event",
+ "Multiple-event handle",
+ "POST results bitmap",
+ "System management",
+ "Multiple-event system management" /* 0x06 */
+ };
+
+ if(code<=0x06)
+ return format[code];
+ if(code>=0x80)
+ return "OEM-specific";
+ return out_of_spec;
+}
+
+static void dmi_event_log_descriptors(u8 count, u8 len, u8 *p, const char *prefix)
+{
+ /* 3.3.16.1 */
+ int i;
+
+ for(i=0; i<count; i++)
+ {
+ if(len>=0x02)
+ {
+ catsprintf(buffer, "%sDescriptor %u: %s\n",
+ prefix, i+1, dmi_event_log_descriptor_type(p[i*len]));
+ catsprintf(buffer, "%sData Format %u: %s\n",
+ prefix, i+1, dmi_event_log_descriptor_format(p[i*len+1]));
+ }
+ }
+}
+
+/*
+ * 3.3.17 Physical Memory Array (Type 16)
+ */
+
+static const char *dmi_memory_array_location(u8 code)
+{
+ /* 3.3.17.1 */
+ static const char *location[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "System Board Or Motherboard",
+ "ISA Add-on Card",
+ "EISA Add-on Card",
+ "PCI Add-on Card",
+ "MCA Add-on Card",
+ "PCMCIA Add-on Card",
+ "Proprietary Add-on Card",
+ "NuBus" /* 0x0A, master.mif says 16 */
+ };
+ static const char *location_0xA0[]={
+ "PC-98/C20 Add-on Card", /* 0xA0 */
+ "PC-98/C24 Add-on Card",
+ "PC-98/E Add-on Card",
+ "PC-98/Local Bus Add-on Card",
+ "PC-98/Card Slot Add-on Card" /* 0xA4, from master.mif */
+ };
+
+ if(code>=0x01 && code<=0x0A)
+ return location[code-0x01];
+ if(code>=0xA0 && code<=0xA4)
+ return location_0xA0[code-0xA0];
+ return out_of_spec;
+}
+
+static const char *dmi_memory_array_use(u8 code)
+{
+ /* 3.3.17.2 */
+ static const char *use[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "System Memory",
+ "Video Memory",
+ "Flash Memory",
+ "Non-volatile RAM",
+ "Cache Memory" /* 0x07 */
+ };
+
+ if(code>=0x01 && code<=0x07)
+ return use[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_memory_array_ec_type(u8 code)
+{
+ /* 3.3.17.3 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "None",
+ "Parity",
+ "Single-bit ECC",
+ "Multi-bit ECC",
+ "CRC" /* 0x07 */
+ };
+
+ if(code>=0x01 && code<=0x07)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_memory_array_capacity(u32 code)
+{
+ if(code==0x8000000)
+ catsprintf(buffer, " Unknown");
+ else
+ {
+ if((code&0x000FFFFF)==0)
+ catsprintf(buffer, " %u GB", code>>20);
+ else if((code&0x000003FF)==0)
+ catsprintf(buffer, " %u MB", code>>10);
+ else
+ catsprintf(buffer, " %u kB", code);
+ }
+}
+
+static void dmi_memory_array_error_handle(u16 code)
+{
+ if(code==0xFFFE)
+ catsprintf(buffer, " Not Provided");
+ else if(code==0xFFFF)
+ catsprintf(buffer, " No Error");
+ else
+ catsprintf(buffer, " 0x%04X", code);
+}
+
+/*
+ * 3.3.18 Memory Device (Type 17)
+ */
+
+static void dmi_memory_device_width(u16 code)
+{
+ /*
+ * If no memory module is present, width may be 0
+ */
+ if(code==0xFFFF || code==0)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u bits", code);
+}
+
+static void dmi_memory_device_size(u16 code)
+{
+ if(code==0)
+ catsprintf(buffer, " No Module Installed");
+ else if(code==0xFFFF)
+ catsprintf(buffer, " Unknown");
+ else
+ {
+ if(code&0x8000)
+ catsprintf(buffer, " %u kB", code&0x7FFF);
+ else
+ catsprintf(buffer, " %u MB", code);
+ }
+}
+
+static const char *dmi_memory_device_form_factor(u8 code)
+{
+ /* 3.3.18.1 */
+ static const char *form_factor[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "SIMM",
+ "SIP",
+ "Chip",
+ "DIP",
+ "ZIP",
+ "Proprietary Card",
+ "DIMM",
+ "TSOP",
+ "Row Of Chips",
+ "RIMM",
+ "SODIMM",
+ "SRIMM",
+ "FB-DIMM" /* 0x0F */
+ };
+
+ if(code>=0x01 && code<=0x0F)
+ return form_factor[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_memory_device_set(u8 code)
+{
+ if(code==0)
+ catsprintf(buffer, " None");
+ else if(code==0xFF)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u", code);
+}
+
+static const char *dmi_memory_device_type(u8 code)
+{
+ /* 3.3.18.2 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "DRAM",
+ "EDRAM",
+ "VRAM",
+ "SRAM",
+ "RAM",
+ "ROM",
+ "Flash",
+ "EEPROM",
+ "FEPROM",
+ "EPROM",
+ "CDRAM",
+ "3DRAM",
+ "SDRAM",
+ "SGRAM",
+ "RDRAM",
+ "DDR",
+ "DDR2",
+ "DDR2 FB-DIMM" /* 0x14 */
+ };
+
+ if(code>=0x01 && code<=0x14)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_memory_device_type_detail(u16 code)
+{
+ /* 3.3.18.3 */
+ static const char *detail[]={
+ "Other", /* 1 */
+ "Unknown",
+ "Fast-paged",
+ "Static Column",
+ "Pseudo-static",
+ "RAMBus",
+ "Synchronous",
+ "CMOS",
+ "EDO",
+ "Window DRAM",
+ "Cache DRAM",
+ "Non-Volatile" /* 12 */
+ };
+
+ if((code&0x1FFE)==0)
+ catsprintf(buffer, " None");
+ else
+ {
+ int i;
+
+ for(i=1; i<=12; i++)
+ if(code&(1<<i))
+ catsprintf(buffer, " %s", detail[i-1]);
+ }
+}
+
+static void dmi_memory_device_speed(u16 code)
+{
+ if(code==0)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u MHz (%.1f ns)", code, (float)1000/code);
+}
+
+/*
+ * 3.3.19 32-bit Memory Error Information (Type 18)
+ */
+
+static const char *dmi_memory_error_type(u8 code)
+{
+ /* 3.3.19.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "OK",
+ "Bad Read",
+ "Parity Error",
+ "Single-bit Error",
+ "Double-bit Error",
+ "Multi-bit Error",
+ "Nibble Error",
+ "Checksum Error",
+ "CRC Error",
+ "Corrected Single-bit Error",
+ "Corrected Error",
+ "Uncorrectable Error" /* 0x0E */
+ };
+
+ if(code>=0x01 && code<=0x0E)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_memory_error_granularity(u8 code)
+{
+ /* 3.3.19.2 */
+ static const char *granularity[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Device Level",
+ "Memory Partition Level" /* 0x04 */
+ };
+
+ if(code>=0x01 && code<=0x04)
+ return granularity[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_memory_error_operation(u8 code)
+{
+ /* 3.3.19.3 */
+ static const char *operation[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Read",
+ "Write",
+ "Partial Write" /* 0x05 */
+ };
+
+ if(code>=0x01 && code<=0x05)
+ return operation[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_memory_error_syndrome(u32 code)
+{
+ if(code==0x00000000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " 0x%08X", code);
+}
+
+static void dmi_32bit_memory_error_address(u32 code)
+{
+ if(code==0x80000000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " 0x%08X", code);
+}
+
+/*
+ * 3.3.20 Memory Array Mapped Address (Type 19)
+ */
+
+static void dmi_mapped_address_size(u32 code)
+{
+ if(code==0)
+ catsprintf(buffer, " Invalid");
+ else if((code&0x000FFFFF)==0)
+ catsprintf(buffer, " %u GB", code>>20);
+ else if((code&0x000003FF)==0)
+ catsprintf(buffer, " %u MB", code>>10);
+ else
+ catsprintf(buffer, " %u kB", code);
+}
+
+/*
+ * 3.3.21 Memory Device Mapped Address (Type 20)
+ */
+
+static void dmi_mapped_address_row_position(u8 code)
+{
+ if(code==0)
+ catsprintf(buffer, " %s", out_of_spec);
+ else if(code==0xFF)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u", code);
+}
+
+static void dmi_mapped_address_interleave_position(u8 code, const char *prefix)
+{
+ if(code!=0)
+ {
+ catsprintf(buffer, "%sInterleave Position:", prefix);
+ if(code==0xFF)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u", code);
+ catsprintf(buffer, "\n");
+ }
+}
+
+static void dmi_mapped_address_interleaved_data_depth(u8 code, const char *prefix)
+{
+ if(code!=0)
+ {
+ catsprintf(buffer, "%sInterleaved Data Depth:", prefix);
+ if(code==0xFF)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u", code);
+ catsprintf(buffer, "\n");
+ }
+}
+
+/*
+ * 3.3.22 Built-in Pointing Device (Type 21)
+ */
+
+static const char *dmi_pointing_device_type(u8 code)
+{
+ /* 3.3.22.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Mouse",
+ "Track Ball",
+ "Track Point",
+ "Glide Point",
+ "Touch Pad",
+ "Touch Screen",
+ "Optical Sensor" /* 0x09 */
+ };
+
+ if(code>=0x01 && code<=0x09)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_pointing_device_interface(u8 code)
+{
+ /* 3.3.22.2 */
+ static const char *interface[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Serial",
+ "PS/2",
+ "Infrared",
+ "HIP-HIL",
+ "Bus Mouse",
+ "ADB (Apple Desktop Bus)" /* 0x08 */
+ };
+ static const char *interface_0xA0[]={
+ "Bus Mouse DB-9", /* 0xA0 */
+ "Bus Mouse Micro DIN",
+ "USB" /* 0xA2 */
+ };
+
+ if(code>=0x01 && code<=0x08)
+ return interface[code-0x01];
+ if(code>=0xA0 && code<=0xA2)
+ return interface_0xA0[code-0xA0];
+ return out_of_spec;
+}
+
+/*
+ * 3.3.23 Portable Battery (Type 22)
+ */
+
+static const char *dmi_battery_chemistry(u8 code)
+{
+ /* 3.3.23.1 */
+ static const char *chemistry[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Lead Acid",
+ "Nickel Cadmium",
+ "Nickel Metal Hydride",
+ "Lithium Ion",
+ "Zinc Air",
+ "Lithium Polymer" /* 0x08 */
+ };
+
+ if(code>=0x01 && code<=0x08)
+ return chemistry[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_battery_capacity(u16 code, u8 multiplier)
+{
+ if(code==0)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u mWh", code*multiplier);
+}
+
+static void dmi_battery_voltage(u16 code)
+{
+ if(code==0)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u mV", code);
+}
+
+static void dmi_battery_maximum_error(u8 code)
+{
+ if(code==0xFF)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u%%", code);
+}
+
+/*
+ * 3.3.24 System Reset (Type 23)
+ */
+
+static const char *dmi_system_reset_boot_option(u8 code)
+{
+ static const char *option[]={
+ "Operating System", /* 0x1 */
+ "System Utilities",
+ "Do Not Reboot" /* 0x3 */
+ };
+
+ if(code>=0x1)
+ return option[code-0x1];
+ return out_of_spec;
+}
+
+static void dmi_system_reset_count(u16 code)
+{
+ if(code==0xFFFF)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u", code);
+}
+
+static void dmi_system_reset_timer(u16 code)
+{
+ if(code==0xFFFF)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %u min", code);
+}
+
+/*
+ * 3.3.25 Hardware Security (Type 24)
+ */
+
+static const char *dmi_hardware_security_status(u8 code)
+{
+ static const char *status[]={
+ "Disabled", /* 0x00 */
+ "Enabled",
+ "Not Implemented",
+ "Unknown" /* 0x03 */
+ };
+
+ return status[code];
+}
+
+/*
+ * 3.3.26 System Power Controls (Type 25)
+ */
+
+static void dmi_power_controls_power_on(u8 *p)
+{
+ /* 3.3.26.1 */
+ if(dmi_bcd_range(p[0], 0x01, 0x12))
+ catsprintf(buffer, " %02X", p[0]);
+ else
+ catsprintf(buffer, " *");
+ if(dmi_bcd_range(p[1], 0x01, 0x31))
+ catsprintf(buffer, "-%02X", p[1]);
+ else
+ catsprintf(buffer, "-*");
+ if(dmi_bcd_range(p[2], 0x00, 0x23))
+ catsprintf(buffer, " %02X", p[2]);
+ else
+ catsprintf(buffer, " *");
+ if(dmi_bcd_range(p[3], 0x00, 0x59))
+ catsprintf(buffer, ":%02X", p[3]);
+ else
+ catsprintf(buffer, ":*");
+ if(dmi_bcd_range(p[4], 0x00, 0x59))
+ catsprintf(buffer, ":%02X", p[4]);
+ else
+ catsprintf(buffer, ":*");
+}
+
+/*
+ * 3.3.27 Voltage Probe (Type 26)
+ */
+
+static const char *dmi_voltage_probe_location(u8 code)
+{
+ /* 3.3.27.1 */
+ static const char *location[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Processor",
+ "Disk",
+ "Peripheral Bay",
+ "System Management Module",
+ "Motherboard",
+ "Memory Module",
+ "Processor Module",
+ "Power Unit",
+ "Add-in Card" /* 0x0B */
+ };
+
+ if(code>=0x01 && code<=0x0B)
+ return location[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_probe_status(u8 code)
+{
+ /* 3.3.27.1 */
+ static const char *status[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "OK",
+ "Non-critical",
+ "Critical",
+ "Non-recoverable" /* 0x06 */
+ };
+
+ if(code>=0x01 && code<=0x06)
+ return status[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_voltage_probe_value(u16 code)
+{
+ if(code==0x8000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %.3f V", (float)(i16)code/1000);
+}
+
+static void dmi_voltage_probe_resolution(u16 code)
+{
+ if(code==0x8000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %.1f mV", (float)code/10);
+}
+
+static void dmi_probe_accuracy(u16 code)
+{
+ if(code==0x8000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %.2f%%", (float)code/100);
+}
+
+/*
+ * 3.3.28 Cooling Device (Type 27)
+ */
+
+static const char *dmi_cooling_device_type(u8 code)
+{
+ /* 3.3.28.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Fan",
+ "Centrifugal Blower",
+ "Chip Fan",
+ "Cabinet Fan",
+ "Power Supply Fan",
+ "Heat Pipe",
+ "Integrated Refrigeration" /* 0x09 */
+ };
+ static const char *type_0x10[]={
+ "Active Cooling", /* 0x10, master.mif says 32 */
+ "Passive Cooling" /* 0x11, master.mif says 33 */
+ };
+
+ if(code>=0x01 && code<=0x09)
+ return type[code-0x01];
+ if(code>=0x10 && code<=0x11)
+ return type_0x10[code-0x10];
+ return out_of_spec;
+}
+
+static void dmi_cooling_device_speed(u16 code)
+{
+ if(code==0x8000)
+ catsprintf(buffer, " Unknown Or Non-rotating");
+ else
+ catsprintf(buffer, " %u rpm", code);
+}
+
+/*
+ * 3.3.29 Temperature Probe (Type 28)
+ */
+
+static const char *dmi_temperature_probe_location(u8 code)
+{
+ /* 3.3.29.1 */
+ static const char *location[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Processor",
+ "Disk",
+ "Peripheral Bay",
+ "System Management Module", /* master.mif says SMB Master */
+ "Motherboard",
+ "Memory Module",
+ "Processor Module",
+ "Power Unit",
+ "Add-in Card",
+ "Front Panel Board",
+ "Back Panel Board",
+ "Power System Board",
+ "Drive Back Plane" /* 0x0F */
+ };
+
+ if(code>=0x01 && code<=0x0F)
+ return location[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_temperature_probe_value(u16 code)
+{
+ if(code==0x8000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %.1f deg C", (float)(i16)code/10);
+}
+
+static void dmi_temperature_probe_resolution(u16 code)
+{
+ if(code==0x8000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %.3f deg C", (float)code/1000);
+}
+
+/*
+ * 3.3.30 Electrical Current Probe (Type 29)
+ */
+
+static void dmi_current_probe_value(u16 code)
+{
+ if(code==0x8000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %.3f A", (float)(i16)code/1000);
+}
+
+static void dmi_current_probe_resolution(u16 code)
+{
+ if(code==0x8000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %.1f mA", (float)code/10);
+}
+
+/*
+ * 3.3.33 System Boot Information (Type 32)
+ */
+
+static const char *dmi_system_boot_status(u8 code)
+{
+ static const char *status[]={
+ "No errors detected", /* 0 */
+ "No bootable media",
+ "Operating system failed to load",
+ "Firmware-detected hardware failure",
+ "Operating system-detected hardware failure",
+ "User-requested boot",
+ "System security violation",
+ "Previously-requested image",
+ "System watchdog timer expired" /* 8 */
+ };
+
+ if(code<=8)
+ return status[code];
+ if(code>=128 && code<=191)
+ return "OEM-specific";
+ if(code>=192)
+ return "Product-specific";
+ return out_of_spec;
+}
+
+/*
+ * 3.3.34 64-bit Memory Error Information (Type 33)
+ */
+
+static void dmi_64bit_memory_error_address(u64 code)
+{
+ if(code.h==0x80000000 && code.l==0x00000000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " 0x%08X%08X", code.h, code.l);
+}
+
+/*
+ * 3.3.35 Management Device (Type 34)
+ */
+
+static const char *dmi_management_device_type(u8 code)
+{
+ /* 3.3.35.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "LM75",
+ "LM78",
+ "LM79",
+ "LM80",
+ "LM81",
+ "ADM9240",
+ "DS1780",
+ "MAX1617",
+ "GL518SM",
+ "W83781D",
+ "HT82H791" /* 0x0D */
+ };
+
+ if(code>=0x01 && code<=0x0D)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_management_device_address_type(u8 code)
+{
+ /* 3.3.35.2 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "I/O Port",
+ "Memory",
+ "SMBus" /* 0x05 */
+ };
+
+ if(code>=0x01 && code<=0x05)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+/*
+ * 3.3.38 Memory Channel (Type 37)
+ */
+
+static const char *dmi_memory_channel_type(u8 code)
+{
+ /* 3.3.38.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "RamBus",
+ "SyncLink" /* 0x04 */
+ };
+
+ if(code>=0x01 && code<=0x04)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static void dmi_memory_channel_devices(u8 count, u8 *p, const char *prefix)
+{
+ int i;
+
+ for(i=1; i<=count; i++)
+ {
+ catsprintf(buffer, "%sDevice %u Load: %u\n",
+ prefix, i, p[3*i]);
+ if(!(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "%sDevice %u Handle: 0x%04X\n",
+ prefix, i, WORD(p+3*i+1));
+ }
+}
+
+/*
+ * 3.3.39 IPMI Device Information (Type 38)
+ */
+
+static const char *dmi_ipmi_interface_type(u8 code)
+{
+ /* 3.3.39.1 and IPMI 2.0, appendix C1, table C1-2 */
+ static const char *type[]={
+ "Unknown", /* 0x00 */
+ "KCS (Keyboard Control Style)",
+ "SMIC (Server Management Interface Chip)",
+ "BT (Block Transfer)",
+ "SSIF (SMBus System Interface)" /* 0x04 */
+ };
+
+ if(code<=0x04)
+ return type[code];
+ return out_of_spec;
+}
+
+static void dmi_ipmi_base_address(u8 type, u8 *p, u8 lsb)
+{
+ if(type==0x04) /* SSIF */
+ {
+ catsprintf(buffer, "0x%02X (SMBus)", (*p)>>1);
+ }
+ else
+ {
+ u64 address=QWORD(p);
+ catsprintf(buffer, "0x%08X%08X (%s)", address.h, (address.l&~1)|lsb,
+ address.l&1?"I/O":"Memory-mapped");
+ }
+}
+
+static const char *dmi_ipmi_register_spacing(u8 code)
+{
+ /* IPMI 2.0, appendix C1, table C1-1 */
+ static const char *spacing[]={
+ "Successive Byte Boundaries", /* 0x00 */
+ "32-bit Boundaries",
+ "16-byte Boundaries" /* 0x02 */
+ };
+
+ if(code<=0x02)
+ return spacing[code];
+ return out_of_spec;
+}
+
+/*
+ * 3.3.40 System Power Supply (Type 39)
+ */
+
+static void dmi_power_supply_power(u16 code)
+{
+ if(code==0x8000)
+ catsprintf(buffer, " Unknown");
+ else
+ catsprintf(buffer, " %.3f W", (float)code/1000);
+}
+
+static const char *dmi_power_supply_type(u8 code)
+{
+ /* 3.3.40.1 */
+ static const char *type[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Linear",
+ "Switching",
+ "Battery",
+ "UPS",
+ "Converter",
+ "Regulator" /* 0x08 */
+ };
+
+ if(code>=0x01 && code<=0x08)
+ return type[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_power_supply_status(u8 code)
+{
+ /* 3.3.40.1 */
+ static const char *status[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "OK",
+ "Non-critical",
+ "Critical" /* 0x05 */
+ };
+
+ if(code>=0x01 && code<=0x05)
+ return status[code-0x01];
+ return out_of_spec;
+}
+
+static const char *dmi_power_supply_range_switching(u8 code)
+{
+ /* 3.3.40.1 */
+ static const char *switching[]={
+ "Other", /* 0x01 */
+ "Unknown",
+ "Manual",
+ "Auto-switch",
+ "Wide Range",
+ "N/A" /* 0x06 */
+ };
+
+ if(code>=0x01 && code<=0x06)
+ return switching[code-0x01];
+ return out_of_spec;
+}
+
+/*
+ * Main
+ */
+
+void dmi_decode(struct dmi_header *h, u16 ver)
+{
+ u8 *data=h->data;
+
+ /*
+ * Note: DMI types 37 and 39 are untested
+ */
+ switch(h->type)
+ {
+ case 0: /* 3.3.1 BIOS Information */
+ catsprintf(buffer, "BIOS Information\n");
+ if(h->length<0x12) break;
+ catsprintf(buffer, "\tVendor: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tVersion: %s\n",
+ dmi_string(h, data[0x05]));
+ catsprintf(buffer, "\tRelease Date: %s\n",
+ dmi_string(h, data[0x08]));
+ /*
+ * On IA-64, the BIOS base address will read 0 because
+ * there is no BIOS. Skip the base address and the
+ * runtime size in this case.
+ */
+ if(WORD(data+0x06)!=0)
+ {
+ catsprintf(buffer, "\tAddress: 0x%04X0\n",
+ WORD(data+0x06));
+ catsprintf(buffer, "\tRuntime Size:");
+ dmi_bios_runtime_size((0x10000-WORD(data+0x06))<<4);
+ catsprintf(buffer, "\n");
+ }
+ catsprintf(buffer, "\tROM Size: %u kB\n",
+ (data[0x09]+1)<<6);
+ catsprintf(buffer, "\tCharacteristics:\n");
+ dmi_bios_characteristics(QWORD(data+0x0A), "\t\t");
+ if(h->length<0x13) break;
+ dmi_bios_characteristics_x1(data[0x12], "\t\t");
+ if(h->length<0x14) break;
+ dmi_bios_characteristics_x2(data[0x13], "\t\t");
+ if(h->length<0x18) break;
+ if(data[0x14]!=0xFF && data[0x15]!=0xFF)
+ catsprintf(buffer, "\tBIOS Revision: %u.%u\n",
+ data[0x14], data[0x15]);
+ if(data[0x16]!=0xFF && data[0x17]!=0xFF)
+ catsprintf(buffer, "\tFirmware Revision: %u.%u\n",
+ data[0x16], data[0x17]);
+ break;
+
+ case 1: /* 3.3.2 System Information */
+ catsprintf(buffer, "System Information\n");
+ if(h->length<0x08) break;
+ catsprintf(buffer, "\tManufacturer: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tProduct Name: %s\n",
+ dmi_string(h, data[0x05]));
+ catsprintf(buffer, "\tVersion: %s\n",
+ dmi_string(h, data[0x06]));
+ catsprintf(buffer, "\tSerial Number: %s\n",
+ dmi_string(h, data[0x07]));
+ if(h->length<0x19) break;
+ catsprintf(buffer, "\tUUID: ");
+ dmi_system_uuid(data+0x08);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tWake-up Type: %s\n",
+ dmi_system_wake_up_type(data[0x18]));
+ if(h->length<0x1B) break;
+ catsprintf(buffer, "\tSKU Number: %s\n",
+ dmi_string(h, data[0x19]));
+ catsprintf(buffer, "\tFamily: %s\n",
+ dmi_string(h, data[0x1A]));
+ break;
+
+ case 2: /* 3.3.3 Base Board Information */
+ catsprintf(buffer, "Base Board Information\n");
+ if(h->length<0x08) break;
+ catsprintf(buffer, "\tManufacturer: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tProduct Name: %s\n",
+ dmi_string(h, data[0x05]));
+ catsprintf(buffer, "\tVersion: %s\n",
+ dmi_string(h, data[0x06]));
+ catsprintf(buffer, "\tSerial Number: %s\n",
+ dmi_string(h, data[0x07]));
+ if(h->length<0x0F) break;
+ catsprintf(buffer, "\tAsset Tag: %s\n",
+ dmi_string(h, data[0x08]));
+ catsprintf(buffer, "\tFeatures:");
+ dmi_base_board_features(data[0x09], "\t\t");
+ catsprintf(buffer, "\tLocation In Chassis: %s\n",
+ dmi_string(h, data[0x0A]));
+ if(!(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "\tChassis Handle: 0x%04X\n",
+ WORD(data+0x0B));
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_base_board_type(data[0x0D]));
+ if(h->length<0x0F+data[0x0E]*sizeof(u16)) break;
+ if(!(opt.flags & FLAG_QUIET))
+ dmi_base_board_handles(data[0x0E], data+0x0F, "\t");
+ break;
+
+ case 3: /* 3.3.4 Chassis Information */
+ catsprintf(buffer, "Chassis Information\n");
+ if(h->length<0x09) break;
+ catsprintf(buffer, "\tManufacturer: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_chassis_type(data[0x05]&0x7F));
+ catsprintf(buffer, "\tLock: %s\n",
+ dmi_chassis_lock(data[0x05]>>7));
+ catsprintf(buffer, "\tVersion: %s\n",
+ dmi_string(h, data[0x06]));
+ catsprintf(buffer, "\tSerial Number: %s\n",
+ dmi_string(h, data[0x07]));
+ catsprintf(buffer, "\tAsset Tag: %s\n",
+ dmi_string(h, data[0x08]));
+ if(h->length<0x0D) break;
+ catsprintf(buffer, "\tBoot-up State: %s\n",
+ dmi_chassis_state(data[0x09]));
+ catsprintf(buffer, "\tPower Supply State: %s\n",
+ dmi_chassis_state(data[0x0A]));
+ catsprintf(buffer, "\tThermal State: %s\n",
+ dmi_chassis_state(data[0x0B]));
+ catsprintf(buffer, "\tSecurity Status: %s\n",
+ dmi_chassis_security_status(data[0x0C]));
+ if(h->length<0x11) break;
+ catsprintf(buffer, "\tOEM Information: 0x%08X\n",
+ DWORD(data+0x0D));
+ if(h->length<0x15) break;
+ catsprintf(buffer, "\tHeight:");
+ dmi_chassis_height(data[0x11]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tNumber Of Power Cords:");
+ dmi_chassis_power_cords(data[0x12]);
+ catsprintf(buffer, "\n");
+ if(h->length<0x15+data[0x13]*data[0x14]) break;
+ dmi_chassis_elements(data[0x13], data[0x14], data+0x15, "\t");
+ break;
+
+ case 4: /* 3.3.5 Processor Information */
+ catsprintf(buffer, "Processor Information\n");
+ if(h->length<0x1A) break;
+ catsprintf(buffer, "\tSocket Designation: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_processor_type(data[0x05]));
+ catsprintf(buffer, "\tFamily: %s\n",
+ dmi_processor_family(data[0x06]));
+ catsprintf(buffer, "\tManufacturer: %s\n",
+ dmi_string(h, data[0x07]));
+ dmi_processor_id(data[0x06], data+8, dmi_string(h, data[0x10]), "\t");
+ catsprintf(buffer, "\tVersion: %s\n",
+ dmi_string(h, data[0x10]));
+ catsprintf(buffer, "\tVoltage:");
+ dmi_processor_voltage(data[0x11]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tExternal Clock: ");
+ dmi_processor_frequency(data+0x12);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tMax Speed: ");
+ dmi_processor_frequency(data+0x14);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tCurrent Speed: ");
+ dmi_processor_frequency(data+0x16);
+ catsprintf(buffer, "\n");
+ if(data[0x18]&(1<<6))
+ catsprintf(buffer, "\tStatus: Populated, %s\n",
+ dmi_processor_status(data[0x18]&0x07));
+ else
+ catsprintf(buffer, "\tStatus: Unpopulated\n");
+ catsprintf(buffer, "\tUpgrade: %s\n",
+ dmi_processor_upgrade(data[0x19]));
+ if(h->length<0x20) break;
+ if(!(opt.flags & FLAG_QUIET))
+ {
+ catsprintf(buffer, "\tL1 Cache Handle:");
+ dmi_processor_cache(WORD(data+0x1A), "L1", ver);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tL2 Cache Handle:");
+ dmi_processor_cache(WORD(data+0x1C), "L2", ver);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tL3 Cache Handle:");
+ dmi_processor_cache(WORD(data+0x1E), "L3", ver);
+ catsprintf(buffer, "\n");
+ }
+ if(h->length<0x23) break;
+ catsprintf(buffer, "\tSerial Number: %s\n",
+ dmi_string(h, data[0x20]));
+ catsprintf(buffer, "\tAsset Tag: %s\n",
+ dmi_string(h, data[0x21]));
+ catsprintf(buffer, "\tPart Number: %s\n",
+ dmi_string(h, data[0x22]));
+ if(h->length<0x28) break;
+ if(data[0x23]!=0)
+ catsprintf(buffer, "\tCore Count: %u\n", data[0x23]);
+ if(data[0x24]!=0)
+ catsprintf(buffer, "\tCore Enabled: %u\n", data[0x24]);
+ if(data[0x25]!=0)
+ catsprintf(buffer, "\tThread Count: %u\n", data[0x25]);
+ catsprintf(buffer, "\tCharacteristics:");
+ dmi_processor_characteristics(WORD(data+0x26), "\t\t");
+ break;
+
+ case 5: /* 3.3.6 Memory Controller Information */
+ catsprintf(buffer, "Memory Controller Information\n");
+ if(h->length<0x0F) break;
+ catsprintf(buffer, "\tError Detecting Method: %s\n",
+ dmi_memory_controller_ed_method(data[0x04]));
+ catsprintf(buffer, "\tError Correcting Capabilities:");
+ dmi_memory_controller_ec_capabilities(data[0x05], "\t\t");
+ catsprintf(buffer, "\tSupported Interleave: %s\n",
+ dmi_memory_controller_interleave(data[0x06]));
+ catsprintf(buffer, "\tCurrent Interleave: %s\n",
+ dmi_memory_controller_interleave(data[0x07]));
+ catsprintf(buffer, "\tMaximum Memory Module Size: %u MB\n",
+ 1<<data[0x08]);
+ catsprintf(buffer, "\tMaximum Total Memory Size: %u MB\n",
+ data[0x0E]*(1<<data[0x08]));
+ catsprintf(buffer, "\tSupported Speeds:");
+ dmi_memory_controller_speeds(WORD(data+0x09), "\t\t");
+ catsprintf(buffer, "\tSupported Memory Types:");
+ dmi_memory_module_types(WORD(data+0x0B), "\n\t\t");
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tMemory Module Voltage:");
+ dmi_processor_voltage(data[0x0D]);
+ catsprintf(buffer, "\n");
+ if(h->length<0x0F+data[0x0E]*sizeof(u16)) break;
+ dmi_memory_controller_slots(data[0x0E], data+0x0F, "\t");
+ if(h->length<0x10+data[0x0E]*sizeof(u16)) break;
+ catsprintf(buffer, "\tEnabled Error Correcting Capabilities:");
+ dmi_memory_controller_ec_capabilities(data[0x0F+data[0x0E]*sizeof(u16)], "\t\t");
+ break;
+
+ case 6: /* 3.3.7 Memory Module Information */
+ catsprintf(buffer, "Memory Module Information\n");
+ if(h->length<0x0C) break;
+ catsprintf(buffer, "\tSocket Designation: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tBank Connections:");
+ dmi_memory_module_connections(data[0x05]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tCurrent Speed:");
+ dmi_memory_module_speed(data[0x06]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tType:");
+ dmi_memory_module_types(WORD(data+0x07), " ");
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tInstalled Size:");
+ dmi_memory_module_size(data[0x09]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tEnabled Size:");
+ dmi_memory_module_size(data[0x0A]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tError Status:");
+ dmi_memory_module_error(data[0x0B], "\t\t");
+ break;
+
+ case 7: /* 3.3.8 Cache Information */
+ catsprintf(buffer, "Cache Information\n");
+ if(h->length<0x0F) break;
+ catsprintf(buffer, "\tSocket Designation: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tConfiguration: %s, %s, Level %u\n",
+ WORD(data+0x05)&0x0080?"Enabled":"Disabled",
+ WORD(data+0x05)&0x0008?"Socketed":"Not Socketed",
+ (WORD(data+0x05)&0x0007)+1);
+ catsprintf(buffer, "\tOperational Mode: %s\n",
+ dmi_cache_mode((WORD(data+0x05)>>8)&0x0003));
+ catsprintf(buffer, "\tLocation: %s\n",
+ dmi_cache_location((WORD(data+0x05)>>5)&0x0003));
+ catsprintf(buffer, "\tInstalled Size:");
+ dmi_cache_size(WORD(data+0x09));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tMaximum Size:");
+ dmi_cache_size(WORD(data+0x07));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tSupported SRAM Types:");
+ dmi_cache_types(WORD(data+0x0B), "\n\t\t");
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tInstalled SRAM Type:");
+ dmi_cache_types(WORD(data+0x0D), " ");
+ catsprintf(buffer, "\n");
+ if(h->length<0x13) break;
+ catsprintf(buffer, "\tSpeed:");
+ dmi_memory_module_speed(data[0x0F]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tError Correction Type: %s\n",
+ dmi_cache_ec_type(data[0x10]));
+ catsprintf(buffer, "\tSystem Type: %s\n",
+ dmi_cache_type(data[0x11]));
+ catsprintf(buffer, "\tAssociativity: %s\n",
+ dmi_cache_associativity(data[0x12]));
+ break;
+
+ case 8: /* 3.3.9 Port Connector Information */
+ catsprintf(buffer, "Port Connector Information\n");
+ if(h->length<0x09) break;
+ catsprintf(buffer, "\tInternal Reference Designator: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tInternal Connector Type: %s\n",
+ dmi_port_connector_type(data[0x05]));
+ catsprintf(buffer, "\tExternal Reference Designator: %s\n",
+ dmi_string(h, data[0x06]));
+ catsprintf(buffer, "\tExternal Connector Type: %s\n",
+ dmi_port_connector_type(data[0x07]));
+ catsprintf(buffer, "\tPort Type: %s\n",
+ dmi_port_type(data[0x08]));
+ break;
+
+ case 9: /* 3.3.10 System Slots */
+ catsprintf(buffer, "System Slot Information\n");
+ if(h->length<0x0C) break;
+ catsprintf(buffer, "\tDesignation: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tType: %s%s\n",
+ dmi_slot_bus_width(data[0x06]),
+ dmi_slot_type(data[0x05]));
+ catsprintf(buffer, "\tCurrent Usage: %s\n",
+ dmi_slot_current_usage(data[0x07]));
+ catsprintf(buffer, "\tLength: %s\n",
+ dmi_slot_length(data[0x08]));
+ dmi_slot_id(data[0x09], data[0x0A], data[0x05], "\t");
+ catsprintf(buffer, "\tCharacteristics:");
+ if(h->length<0x0D)
+ dmi_slot_characteristics(data[0x0B], 0x00, "\t\t");
+ else
+ dmi_slot_characteristics(data[0x0B], data[0x0C], "\t\t");
+ break;
+
+ case 10: /* 3.3.11 On Board Devices Information */
+ dmi_on_board_devices(h, "");
+ break;
+
+ case 11: /* 3.3.12 OEM Strings */
+ catsprintf(buffer, "OEM Strings\n");
+ if(h->length<0x05) break;
+ dmi_oem_strings(h, "\t");
+ break;
+
+ case 12: /* 3.3.13 System Configuration Options */
+ catsprintf(buffer, "System Configuration Options\n");
+ if(h->length<0x05) break;
+ dmi_system_configuration_options(h, "\t");
+ break;
+
+ case 13: /* 3.3.14 BIOS Language Information */
+ catsprintf(buffer, "BIOS Language Information\n");
+ if(h->length<0x16) break;
+ catsprintf(buffer, "\tInstallable Languages: %u\n", data[0x04]);
+ dmi_bios_languages(h, "\t\t");
+ catsprintf(buffer, "\tCurrently Installed Language: %s\n",
+ dmi_string(h, data[0x15]));
+ break;
+
+ case 14: /* 3.3.15 Group Associations */
+ catsprintf(buffer, "Group Associations\n");
+ if(h->length<0x05) break;
+ catsprintf(buffer, "\tName: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tItems: %u\n",
+ (h->length-0x05)/3);
+ dmi_group_associations_items((h->length-0x05)/3, data+0x05, "\t\t");
+ break;
+
+ case 15: /* 3.3.16 System Event Log */
+ catsprintf(buffer, "System Event Log\n");
+ if(h->length<0x14) break;
+ catsprintf(buffer, "\tArea Length: %u bytes\n",
+ WORD(data+0x04));
+ catsprintf(buffer, "\tHeader Start Offset: 0x%04X\n",
+ WORD(data+0x06));
+ if(WORD(data+0x08)-WORD(data+0x06))
+ catsprintf(buffer, "\tHeader Length: %u byte%s\n",
+ WORD(data+0x08)-WORD(data+0x06),
+ WORD(data+0x08)-WORD(data+0x06)>1?"s":"");
+ catsprintf(buffer, "\tData Start Offset: 0x%04X\n",
+ WORD(data+0x08));
+ catsprintf(buffer, "\tAccess Method: %s\n",
+ dmi_event_log_method(data[0x0A]));
+ catsprintf(buffer, "\tAccess Address:");
+ dmi_event_log_address(data[0x0A], data+0x10);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tStatus:");
+ dmi_event_log_status(data[0x0B]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tChange Token: 0x%08X\n",
+ DWORD(data+0x0C));
+ if(h->length<0x17) break;
+ catsprintf(buffer, "\tHeader Format: %s\n",
+ dmi_event_log_header_type(data[0x14]));
+ catsprintf(buffer, "\tSupported Log Type Descriptors: %u\n",
+ data[0x15]);
+ if(h->length<0x17+data[0x15]*data[0x16]) break;
+ dmi_event_log_descriptors(data[0x15], data[0x16], data+0x17, "\t");
+ break;
+
+ case 16: /* 3.3.17 Physical Memory Array */
+ catsprintf(buffer, "Physical Memory Array\n");
+ if(h->length<0x0F) break;
+ catsprintf(buffer, "\tLocation: %s\n",
+ dmi_memory_array_location(data[0x04]));
+ catsprintf(buffer, "\tUse: %s\n",
+ dmi_memory_array_use(data[0x05]));
+ catsprintf(buffer, "\tError Correction Type: %s\n",
+ dmi_memory_array_ec_type(data[0x06]));
+ catsprintf(buffer, "\tMaximum Capacity:");
+ dmi_memory_array_capacity(DWORD(data+0x07));
+ catsprintf(buffer, "\n");
+ if(!(opt.flags & FLAG_QUIET))
+ {
+ catsprintf(buffer, "\tError Information Handle:");
+ dmi_memory_array_error_handle(WORD(data+0x0B));
+ catsprintf(buffer, "\n");
+ }
+ catsprintf(buffer, "\tNumber Of Devices: %u\n",
+ WORD(data+0x0D));
+ break;
+
+ case 17: /* 3.3.18 Memory Device */
+ catsprintf(buffer, "Memory Device\n");
+ if(h->length<0x15) break;
+ if(!(opt.flags & FLAG_QUIET))
+ {
+ catsprintf(buffer, "\tArray Handle: 0x%04X\n",
+ WORD(data+0x04));
+ catsprintf(buffer, "\tError Information Handle:");
+ dmi_memory_array_error_handle(WORD(data+0x06));
+ catsprintf(buffer, "\n");
+ }
+ catsprintf(buffer, "\tTotal Width:");
+ dmi_memory_device_width(WORD(data+0x08));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tData Width:");
+ dmi_memory_device_width(WORD(data+0x0A));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tSize:");
+ dmi_memory_device_size(WORD(data+0x0C));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tForm Factor: %s\n",
+ dmi_memory_device_form_factor(data[0x0E]));
+ catsprintf(buffer, "\tSet:");
+ dmi_memory_device_set(data[0x0F]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tLocator: %s\n",
+ dmi_string(h, data[0x10]));
+ catsprintf(buffer, "\tBank Locator: %s\n",
+ dmi_string(h, data[0x11]));
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_memory_device_type(data[0x12]));
+ catsprintf(buffer, "\tType Detail:");
+ dmi_memory_device_type_detail(WORD(data+0x13));
+ catsprintf(buffer, "\n");
+ if(h->length<0x17) break;
+ catsprintf(buffer, "\tSpeed:");
+ dmi_memory_device_speed(WORD(data+0x15));
+ catsprintf(buffer, "\n");
+ if(h->length<0x1B) break;
+ catsprintf(buffer, "\tManufacturer: %s\n",
+ dmi_string(h, data[0x17]));
+ catsprintf(buffer, "\tSerial Number: %s\n",
+ dmi_string(h, data[0x18]));
+ catsprintf(buffer, "\tAsset Tag: %s\n",
+ dmi_string(h, data[0x19]));
+ catsprintf(buffer, "\tPart Number: %s\n",
+ dmi_string(h, data[0x1A]));
+ break;
+
+ case 18: /* 3.3.19 32-bit Memory Error Information */
+ catsprintf(buffer, "32-bit Memory Error Information\n");
+ if(h->length<0x17) break;
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_memory_error_type(data[0x04]));
+ catsprintf(buffer, "\tGranularity: %s\n",
+ dmi_memory_error_granularity(data[0x05]));
+ catsprintf(buffer, "\tOperation: %s\n",
+ dmi_memory_error_operation(data[0x06]));
+ catsprintf(buffer, "\tVendor Syndrome:");
+ dmi_memory_error_syndrome(DWORD(data+0x07));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tMemory Array Address:");
+ dmi_32bit_memory_error_address(DWORD(data+0x0B));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tDevice Address:");
+ dmi_32bit_memory_error_address(DWORD(data+0x0F));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tResolution:");
+ dmi_32bit_memory_error_address(DWORD(data+0x13));
+ catsprintf(buffer, "\n");
+ break;
+
+ case 19: /* 3.3.20 Memory Array Mapped Address */
+ catsprintf(buffer, "Memory Array Mapped Address\n");
+ if(h->length<0x0F) break;
+ catsprintf(buffer, "\tStarting Address: 0x%08X%03X\n",
+ DWORD(data+0x04)>>2, (DWORD(data+0x04)&0x3)<<10);
+ catsprintf(buffer, "\tEnding Address: 0x%08X%03X\n",
+ DWORD(data+0x08)>>2, ((DWORD(data+0x08)&0x3)<<10)+0x3FF);
+ catsprintf(buffer, "\tRange Size:");
+ dmi_mapped_address_size(DWORD(data+0x08)-DWORD(data+0x04)+1);
+ catsprintf(buffer, "\n");
+ if(!(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "\tPhysical Array Handle: 0x%04X\n",
+ WORD(data+0x0C));
+ catsprintf(buffer, "\tPartition Width: %u\n",
+ data[0x0F]);
+ break;
+
+ case 20: /* 3.3.21 Memory Device Mapped Address */
+ catsprintf(buffer, "Memory Device Mapped Address\n");
+ if(h->length<0x13) break;
+ catsprintf(buffer, "\tStarting Address: 0x%08X%03X\n",
+ DWORD(data+0x04)>>2, (DWORD(data+0x04)&0x3)<<10);
+ catsprintf(buffer, "\tEnding Address: 0x%08X%03X\n",
+ DWORD(data+0x08)>>2, ((DWORD(data+0x08)&0x3)<<10)+0x3FF);
+ catsprintf(buffer, "\tRange Size:");
+ dmi_mapped_address_size(DWORD(data+0x08)-DWORD(data+0x04)+1);
+ catsprintf(buffer, "\n");
+ if(!(opt.flags & FLAG_QUIET))
+ {
+ catsprintf(buffer, "\tPhysical Device Handle: 0x%04X\n",
+ WORD(data+0x0C));
+ catsprintf(buffer, "\tMemory Array Mapped Address Handle: 0x%04X\n",
+ WORD(data+0x0E));
+ }
+ catsprintf(buffer, "\tPartition Row Position:");
+ dmi_mapped_address_row_position(data[0x10]);
+ catsprintf(buffer, "\n");
+ dmi_mapped_address_interleave_position(data[0x11], "\t");
+ dmi_mapped_address_interleaved_data_depth(data[0x12], "\t");
+ break;
+
+ case 21: /* 3.3.22 Built-in Pointing Device */
+ catsprintf(buffer, "Built-in Pointing Device\n");
+ if(h->length<0x07) break;
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_pointing_device_type(data[0x04]));
+ catsprintf(buffer, "\tInterface: %s\n",
+ dmi_pointing_device_interface(data[0x05]));
+ catsprintf(buffer, "\tButtons: %u\n",
+ data[0x06]);
+ break;
+
+ case 22: /* 3.3.23 Portable Battery */
+ catsprintf(buffer, "Portable Battery\n");
+ if(h->length<0x10) break;
+ catsprintf(buffer, "\tLocation: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tManufacturer: %s\n",
+ dmi_string(h, data[0x05]));
+ if(data[0x06] || h->length<0x1A)
+ catsprintf(buffer, "\tManufacture Date: %s\n",
+ dmi_string(h, data[0x06]));
+ if(data[0x07] || h->length<0x1A)
+ catsprintf(buffer, "\tSerial Number: %s\n",
+ dmi_string(h, data[0x07]));
+ catsprintf(buffer, "\tName: %s\n",
+ dmi_string(h, data[0x08]));
+ if(data[0x09]!=0x02 || h->length<0x1A)
+ catsprintf(buffer, "\tChemistry: %s\n",
+ dmi_battery_chemistry(data[0x09]));
+ catsprintf(buffer, "\tDesign Capacity:");
+ if(h->length<0x1A)
+ dmi_battery_capacity(WORD(data+0x0A), 1);
+ else
+ dmi_battery_capacity(WORD(data+0x0A), data[0x15]);
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tDesign Voltage:");
+ dmi_battery_voltage(WORD(data+0x0C));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tSBDS Version: %s\n",
+ dmi_string(h, data[0x0E]));
+ catsprintf(buffer, "\tMaximum Error:");
+ dmi_battery_maximum_error(data[0x0F]);
+ catsprintf(buffer, "\n");
+ if(h->length<0x1A) break;
+ if(data[0x07]==0)
+ catsprintf(buffer, "\tSBDS Serial Number: %04X\n",
+ WORD(data+0x10));
+ if(data[0x06]==0)
+ catsprintf(buffer, "\tSBDS Manufacture Date: %u-%02u-%02u\n",
+ 1980+(WORD(data+0x12)>>9), (WORD(data+0x12)>>5)&0x0F,
+ WORD(data+0x12)&0x1F);
+ if(data[0x09]==0x02)
+ catsprintf(buffer, "\tSBDS Chemistry: %s\n",
+ dmi_string(h, data[0x14]));
+ catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n",
+ DWORD(data+0x16));
+ break;
+
+ case 23: /* 3.3.24 System Reset */
+ catsprintf(buffer, "System Reset\n");
+ if(h->length<0x0D) break;
+ catsprintf(buffer, "\tStatus: %s\n",
+ data[0x04]&(1<<0)?"Enabled":"Disabled");
+ catsprintf(buffer, "\tWatchdog Timer: %s\n",
+ data[0x04]&(1<<5)?"Present":"Not Present");
+ if(!(data[0x04]&(1<<5)))
+ break;
+ catsprintf(buffer, "\tBoot Option: %s\n",
+ dmi_system_reset_boot_option((data[0x04]>>1)&0x3));
+ catsprintf(buffer, "\tBoot Option On Limit: %s\n",
+ dmi_system_reset_boot_option((data[0x04]>>3)&0x3));
+ catsprintf(buffer, "\tReset Count:");
+ dmi_system_reset_count(WORD(data+0x05));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tReset Limit:");
+ dmi_system_reset_count(WORD(data+0x07));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tTimer Interval:");
+ dmi_system_reset_timer(WORD(data+0x09));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tTimeout:");
+ dmi_system_reset_timer(WORD(data+0x0B));
+ catsprintf(buffer, "\n");
+ break;
+
+ case 24: /* 3.3.25 Hardware Security */
+ catsprintf(buffer, "Hardware Security\n");
+ if(h->length<0x05) break;
+ catsprintf(buffer, "\tPower-On Password Status: %s\n",
+ dmi_hardware_security_status(data[0x04]>>6));
+ catsprintf(buffer, "\tKeyboard Password Status: %s\n",
+ dmi_hardware_security_status((data[0x04]>>4)&0x3));
+ catsprintf(buffer, "\tAdministrator Password Status: %s\n",
+ dmi_hardware_security_status((data[0x04]>>2)&0x3));
+ catsprintf(buffer, "\tFront Panel Reset Status: %s\n",
+ dmi_hardware_security_status(data[0x04]&0x3));
+ break;
+
+ case 25: /* 3.3.26 System Power Controls */
+ catsprintf(buffer, "\tSystem Power Controls\n");
+ if(h->length<0x09) break;
+ catsprintf(buffer, "\tNext Scheduled Power-on:");
+ dmi_power_controls_power_on(data+0x04);
+ catsprintf(buffer, "\n");
+ break;
+
+ case 26: /* 3.3.27 Voltage Probe */
+ catsprintf(buffer, "Voltage Probe\n");
+ if(h->length<0x14) break;
+ catsprintf(buffer, "\tDescription: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tLocation: %s\n",
+ dmi_voltage_probe_location(data[0x05]&0x1f));
+ catsprintf(buffer, "\tStatus: %s\n",
+ dmi_probe_status(data[0x05]>>5));
+ catsprintf(buffer, "\tMaximum Value:");
+ dmi_voltage_probe_value(WORD(data+0x06));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tMinimum Value:");
+ dmi_voltage_probe_value(WORD(data+0x08));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tResolution:");
+ dmi_voltage_probe_resolution(WORD(data+0x0A));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tTolerance:");
+ dmi_voltage_probe_value(WORD(data+0x0C));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tAccuracy:");
+ dmi_probe_accuracy(WORD(data+0x0E));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n",
+ DWORD(data+0x10));
+ if(h->length<0x16) break;
+ catsprintf(buffer, "\tNominal Value:");
+ dmi_voltage_probe_value(WORD(data+0x14));
+ catsprintf(buffer, "\n");
+ break;
+
+ case 27: /* 3.3.28 Cooling Device */
+ catsprintf(buffer, "Cooling Device\n");
+ if(h->length<0x0C) break;
+ if(!(opt.flags & FLAG_QUIET) && WORD(data+0x04)!=0xFFFF)
+ catsprintf(buffer, "\tTemperature Probe Handle: 0x%04X\n",
+ WORD(data+0x04));
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_cooling_device_type(data[0x06]&0x1f));
+ catsprintf(buffer, "\tStatus: %s\n",
+ dmi_probe_status(data[0x06]>>5));
+ if(data[0x07]!=0x00)
+ catsprintf(buffer, "\tCooling Unit Group: %u\n",
+ data[0x07]);
+ catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n",
+ DWORD(data+0x08));
+ if(h->length<0x0E) break;
+ catsprintf(buffer, "\tNominal Speed:");
+ dmi_cooling_device_speed(WORD(data+0x0C));
+ catsprintf(buffer, "\n");
+ break;
+
+ case 28: /* 3.3.29 Temperature Probe */
+ catsprintf(buffer, "Temperature Probe\n");
+ if(h->length<0x14) break;
+ catsprintf(buffer, "\tDescription: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tLocation: %s\n",
+ dmi_temperature_probe_location(data[0x05]&0x1F));
+ catsprintf(buffer, "\tStatus: %s\n",
+ dmi_probe_status(data[0x05]>>5));
+ catsprintf(buffer, "\tMaximum Value:");
+ dmi_temperature_probe_value(WORD(data+0x06));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tMinimum Value");
+ dmi_temperature_probe_value(WORD(data+0x08));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tResolution:");
+ dmi_temperature_probe_resolution(WORD(data+0x0A));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tTolerance:");
+ dmi_temperature_probe_value(WORD(data+0x0C));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tAccuracy:");
+ dmi_probe_accuracy(WORD(data+0x0E));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n",
+ DWORD(data+0x10));
+ if(h->length<0x16) break;
+ catsprintf(buffer, "\tNominal Value:");
+ dmi_temperature_probe_value(WORD(data+0x14));
+ catsprintf(buffer, "\n");
+ break;
+
+ case 29: /* 3.3.30 Electrical Current Probe */
+ catsprintf(buffer, "Electrical Current Probe\n");
+ if(h->length<0x14) break;
+ catsprintf(buffer, "\tDescription: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tLocation: %s\n",
+ dmi_voltage_probe_location(data[5]&0x1F));
+ catsprintf(buffer, "\tStatus: %s\n",
+ dmi_probe_status(data[0x05]>>5));
+ catsprintf(buffer, "\tMaximum Value:");
+ dmi_current_probe_value(WORD(data+0x06));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tMinimum Value:");
+ dmi_current_probe_value(WORD(data+0x08));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tResolution:");
+ dmi_current_probe_resolution(WORD(data+0x0A));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tTolerance:");
+ dmi_current_probe_value(WORD(data+0x0C));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tAccuracy:");
+ dmi_probe_accuracy(WORD(data+0x0E));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tOEM-specific Information: 0x%08X\n",
+ DWORD(data+0x10));
+ if(h->length<0x16) break;
+ catsprintf(buffer, "\tNominal Value:");
+ dmi_current_probe_value(WORD(data+0x14));
+ catsprintf(buffer, "\n");
+ break;
+
+ case 30: /* 3.3.31 Out-of-band Remote Access */
+ catsprintf(buffer, "Out-of-band Remote Access\n");
+ if(h->length<0x06) break;
+ catsprintf(buffer, "\tManufacturer Name: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tInbound Connection: %s\n",
+ data[0x05]&(1<<0)?"Enabled":"Disabled");
+ catsprintf(buffer, "\tOutbound Connection: %s\n",
+ data[0x05]&(1<<1)?"Enabled":"Disabled");
+ break;
+
+ case 31: /* 3.3.32 Boot Integrity Services Entry Point */
+ catsprintf(buffer, "Boot Integrity Services Entry Point\n");
+ break;
+
+ case 32: /* 3.3.33 System Boot Information */
+ catsprintf(buffer, "System Boot Information\n");
+ if(h->length<0x0B) break;
+ catsprintf(buffer, "\tStatus: %s\n",
+ dmi_system_boot_status(data[0x0A]));
+ break;
+
+ case 33: /* 3.3.34 64-bit Memory Error Information */
+ if(h->length<0x1F) break;
+ catsprintf(buffer, "64-bit Memory Error Information\n");
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_memory_error_type(data[0x04]));
+ catsprintf(buffer, "\tGranularity: %s\n",
+ dmi_memory_error_granularity(data[0x05]));
+ catsprintf(buffer, "\tOperation: %s\n",
+ dmi_memory_error_operation(data[0x06]));
+ catsprintf(buffer, "\tVendor Syndrome:");
+ dmi_memory_error_syndrome(DWORD(data+0x07));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tMemory Array Address:");
+ dmi_64bit_memory_error_address(QWORD(data+0x0B));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tDevice Address:");
+ dmi_64bit_memory_error_address(QWORD(data+0x13));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tResolution:");
+ dmi_32bit_memory_error_address(DWORD(data+0x1B));
+ catsprintf(buffer, "\n");
+ break;
+
+ case 34: /* 3.3.35 Management Device */
+ catsprintf(buffer, "Management Device\n");
+ if(h->length<0x0B) break;
+ catsprintf(buffer, "\tDescription: %s\n",
+ dmi_string(h, data[0x04]));
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_management_device_type(data[0x05]));
+ catsprintf(buffer, "\tAddress: 0x%08X\n",
+ DWORD(data+0x06));
+ catsprintf(buffer, "\tAddress Type: %s\n",
+ dmi_management_device_address_type(data[0x0A]));
+ break;
+
+ case 35: /* 3.3.36 Management Device Component */
+ catsprintf(buffer, "Management Device Component\n");
+ if(h->length<0x0B) break;
+ catsprintf(buffer, "\tDescription: %s\n",
+ dmi_string(h, data[0x04]));
+ if(!(opt.flags & FLAG_QUIET))
+ {
+ catsprintf(buffer, "\tManagement Device Handle: 0x%04X\n",
+ WORD(data+0x05));
+ catsprintf(buffer, "\tComponent Handle: 0x%04X\n",
+ WORD(data+0x07));
+ if(WORD(data+0x09)!=0xFFFF)
+ catsprintf(buffer, "\tThreshold Handle: 0x%04X\n",
+ WORD(data+0x09));
+ }
+ break;
+
+ case 36: /* 3.3.37 Management Device Threshold Data */
+ catsprintf(buffer, "Management Device Threshold Data\n");
+ if(h->length<0x10) break;
+ if(WORD(data+0x04)!=0x8000)
+ catsprintf(buffer, "\tLower Non-critical Threshold: %d\n",
+ (i16)WORD(data+0x04));
+ if(WORD(data+0x06)!=0x8000)
+ catsprintf(buffer, "\tUpper Non-critical Threshold: %d\n",
+ (i16)WORD(data+0x06));
+ if(WORD(data+0x08)!=0x8000)
+ catsprintf(buffer, "\tLower Critical Threshold: %d\n",
+ (i16)WORD(data+0x08));
+ if(WORD(data+0x0A)!=0x8000)
+ catsprintf(buffer, "\tUpper Critical Threshold: %d\n",
+ (i16)WORD(data+0x0A));
+ if(WORD(data+0x0C)!=0x8000)
+ catsprintf(buffer, "\tLower Non-recoverable Threshold: %d\n",
+ (i16)WORD(data+0x0C));
+ if(WORD(data+0x0E)!=0x8000)
+ catsprintf(buffer, "\tUpper Non-recoverable Threshold: %d\n",
+ (i16)WORD(data+0x0E));
+ break;
+
+ case 37: /* 3.3.38 Memory Channel */
+ catsprintf(buffer, "Memory Channel\n");
+ if(h->length<0x07) break;
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_memory_channel_type(data[0x04]));
+ catsprintf(buffer, "\tMaximal Load: %u\n",
+ data[0x05]);
+ catsprintf(buffer, "\tDevices: %u\n",
+ data[0x06]);
+ if(h->length<0x07+3*data[0x06]) break;
+ dmi_memory_channel_devices(data[0x06], data+0x07, "\t");
+ break;
+
+ case 38: /* 3.3.39 IPMI Device Information */
+ /*
+ * We use the word "Version" instead of "Revision", conforming to
+ * the IPMI specification.
+ */
+ catsprintf(buffer, "IPMI Device Information\n");
+ if(h->length<0x10) break;
+ catsprintf(buffer, "\tInterface Type: %s\n",
+ dmi_ipmi_interface_type(data[0x04]));
+ catsprintf(buffer, "\tSpecification Version: %u.%u\n",
+ data[0x05]>>4, data[0x05]&0x0F);
+ catsprintf(buffer, "\tI2C Slave Address: 0x%02x\n",
+ data[0x06]>>1);
+ if(data[0x07]!=0xFF)
+ catsprintf(buffer, "\tNV Storage Device Address: %u\n",
+ data[0x07]);
+ else
+ catsprintf(buffer, "\tNV Storage Device: Not Present\n");
+ catsprintf(buffer, "\tBase Address: ");
+ dmi_ipmi_base_address(data[0x04], data+0x08,
+ h->length<0x12?0:(data[0x10]>>5)&1);
+ catsprintf(buffer, "\n");
+ if(h->length<0x12) break;
+ if(data[0x04]!=0x04)
+ {
+ catsprintf(buffer, "\tRegister Spacing: %s\n",
+ dmi_ipmi_register_spacing(data[0x10]>>6));
+ if(data[0x10]&(1<<3))
+ {
+ catsprintf(buffer, "\tInterrupt Polarity: %s\n",
+ data[0x10]&(1<<1)?"Active High":"Active Low");
+ catsprintf(buffer, "\tInterrupt Trigger Mode: %s\n",
+ data[0x10]&(1<<0)?"Level":"Edge");
+ }
+ }
+ if(data[0x11]!=0x00)
+ {
+ catsprintf(buffer, "\tInterrupt Number: %x\n",
+ data[0x11]);
+ }
+ break;
+
+ case 39: /* 3.3.40 System Power Supply */
+ catsprintf(buffer, "System Power Supply\n");
+ if(h->length<0x10) break;
+ if(data[0x04]!=0x00)
+ catsprintf(buffer, "\tPower Unit Group: %u\n",
+ data[0x04]);
+ catsprintf(buffer, "\tLocation: %s\n",
+ dmi_string(h, data[0x05]));
+ catsprintf(buffer, "\tName: %s\n",
+ dmi_string(h, data[0x06]));
+ catsprintf(buffer, "\tManufacturer: %s\n",
+ dmi_string(h, data[0x07]));
+ catsprintf(buffer, "\tSerial Number: %s\n",
+ dmi_string(h, data[0x08]));
+ catsprintf(buffer, "\tAsset Tag: %s\n",
+ dmi_string(h, data[0x09]));
+ catsprintf(buffer, "\tModel Part Number: %s\n",
+ dmi_string(h, data[0x0A]));
+ catsprintf(buffer, "\tRevision: %s\n",
+ dmi_string(h, data[0x0B]));
+ catsprintf(buffer, "\tMax Power Capacity:");
+ dmi_power_supply_power(WORD(data+0x0C));
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tStatus:");
+ if(WORD(data+0x0E)&(1<<1))
+ catsprintf(buffer, " Present, %s",
+ dmi_power_supply_status((WORD(data+0x0E)>>7)&0x07));
+ else
+ catsprintf(buffer, " Not Present");
+ catsprintf(buffer, "\n");
+ catsprintf(buffer, "\tType: %s\n",
+ dmi_power_supply_type((WORD(data+0x0E)>>10)&0x0F));
+ catsprintf(buffer, "\tInput Voltage Range Switching: %s\n",
+ dmi_power_supply_range_switching((WORD(data+0x0E)>>3)&0x0F));
+ catsprintf(buffer, "\tPlugged: %s\n",
+ WORD(data+0x0E)&(1<<2)?"No":"Yes");
+ catsprintf(buffer, "\tHot Replaceable: %s\n",
+ WORD(data+0x0E)&(1<<0)?"Yes":"No");
+ if(h->length<0x16) break;
+ if(!(opt.flags & FLAG_QUIET))
+ {
+ if(WORD(data+0x10)!=0xFFFF)
+ catsprintf(buffer, "\tInput Voltage Probe Handle: 0x%04X\n",
+ WORD(data+0x10));
+ if(WORD(data+0x12)!=0xFFFF)
+ catsprintf(buffer, "\tCooling Device Handle: 0x%04X\n",
+ WORD(data+0x12));
+ if(WORD(data+0x14)!=0xFFFF)
+ catsprintf(buffer, "\tInput Current Probe Handle: 0x%04X\n",
+ WORD(data+0x14));
+ }
+ break;
+
+ case 126: /* 3.3.41 Inactive */
+ catsprintf(buffer, "Inactive\n");
+ break;
+
+ case 127: /* 3.3.42 End Of Table */
+ catsprintf(buffer, "End Of Table\n");
+ break;
+
+ default:
+ if(dmi_decode_oem(h))
+ break;
+ if(opt.flags & FLAG_QUIET)
+ return;
+ catsprintf(buffer, "%s Type\n",
+ h->type>=128?"OEM-specific":"Unknown");
+ dmi_dump(h, "\t");
+ }
+ catsprintf(buffer, "\n");
+}
+
+void to_dmi_header(struct dmi_header *h, u8 *data)
+{
+ h->type=data[0];
+ h->length=data[1];
+ h->handle=WORD(data+2);
+ h->data=data;
+}
+
+static void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem)
+{
+ u8 *buf;
+ u8 *data;
+ int i=0;
+
+ if(!(opt.flags & FLAG_QUIET))
+ {
+ if(opt.type==NULL)
+ catsprintf(buffer, "%u structures occupying %u bytes.\n"
+ "Table at 0x%08X.\n",
+ num, len, base);
+ catsprintf(buffer, "\n");
+ }
+
+ if((buf=mem_chunk(base, len, devmem))==NULL)
+ {
+#ifndef USE_MMAP
+ catsprintf(buffer, "Table is unreachable, sorry. Try compiling dmidecode with -DUSE_MMAP.\n");
+#endif
+ return;
+ }
+
+ data=buf;
+ while(i<num && data+4<=buf+len) /* 4 is the length of an SMBIOS structure header */
+ {
+ u8 *next;
+ struct dmi_header h;
+ int display;
+
+ to_dmi_header(&h, data);
+ display=((opt.type==NULL || opt.type[h.type])
+ && !((opt.flags & FLAG_QUIET) && (h.type>39 && h.type<=127))
+ && !opt.string);
+
+ /*
+ * If a short entry is found (less than 4 bytes), not only it
+ * is invalid, but we cannot reliably locate the next entry.
+ * Better stop at this point, and let the user know his/her
+ * table is broken.
+ */
+ if(h.length<4)
+ {
+ catsprintf(buffer, "Invalid entry length (%u). DMI table is "
+ "broken! Stop.\n\n", (unsigned int)h.length);
+ opt.flags |= FLAG_QUIET;
+ break;
+ }
+
+ /* In quiet mode, stop decoding at end of table marker */
+ if((opt.flags & FLAG_QUIET) && h.type==127)
+ break;
+
+ if(display && !(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "Handle 0x%04X, DMI type %d, %d bytes\n",
+ h.handle, h.type, h.length);
+
+ /* assign vendor for vendor-specific decodes later */
+ if(h.type==0 && h.length>=5)
+ dmi_set_vendor(dmi_string(&h, data[0x04]));
+
+ /* look for the next handle */
+ next=data+h.length;
+ while(next-buf+1<len && (next[0]!=0 || next[1]!=0))
+ next++;
+ next+=2;
+ if(display)
+ {
+ if(next-buf<=len)
+ {
+ if(opt.flags & FLAG_DUMP)
+ {
+ dmi_dump(&h, "\t");
+ catsprintf(buffer, "\n");
+ }
+ else
+ dmi_decode(&h, ver);
+ }
+ else if(!(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "\t<TRUNCATED>\n\n");
+ }
+ else if(opt.string!=NULL
+ && opt.string->type==h.type
+ && opt.string->offset<h.length)
+ {
+ if (opt.string->lookup!=NULL)
+ catsprintf(buffer, "%s\n", opt.string->lookup(data[opt.string->offset]));
+ else if (opt.string->print!=NULL) {
+ opt.string->print(data+opt.string->offset);
+ catsprintf(buffer, "\n");
+ }
+ else
+ catsprintf(buffer, "%s\n", dmi_string(&h, data[opt.string->offset]));
+ }
+
+ data=next;
+ i++;
+ }
+
+ if(!(opt.flags & FLAG_QUIET))
+ {
+ if(i!=num)
+ catsprintf(buffer, "Wrong DMI structures count: %d announced, "
+ "only %d decoded.\n", num, i);
+ if(data-buf!=len)
+ catsprintf(buffer, "Wrong DMI structures length: %d bytes "
+ "announced, structures occupy %d bytes.\n",
+ len, (unsigned int)(data-buf));
+ }
+
+ free(buf);
+}
+
+int smbios_decode(u8 *buf, const char *devmem)
+{
+ if(checksum(buf, buf[0x05])
+ && memcmp(buf+0x10, "_DMI_", 5)==0
+ && checksum(buf+0x10, 0x0F))
+ {
+ if(!(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "SMBIOS %u.%u present.\n",
+ buf[0x06], buf[0x07]);
+ dmi_table(DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C),
+ (buf[0x06]<<8)+buf[0x07], devmem);
+ return 1;
+ }
+
+ return 0;
+}
+
+int legacy_decode(u8 *buf, const char *devmem)
+{
+ if(checksum(buf, 0x0F))
+ {
+ if(!(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "Legacy DMI %u.%u present.\n",
+ buf[0x0E]>>4, buf[0x0E]&0x0F);
+ dmi_table(DWORD(buf+0x08), WORD(buf+0x06), WORD(buf+0x0C),
+ ((buf[0x0E]&0xF0)<<4)+(buf[0x0E]&0x0F), devmem);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Probe for EFI interface
+ */
+#define EFI_NOT_FOUND (-1)
+#define EFI_NO_SMBIOS (-2)
+int address_from_efi(size_t *address)
+{
+ FILE *efi_systab;
+ const char *filename;
+ char linebuf[64];
+ int ret;
+
+ *address=0; /* Prevent compiler warning */
+
+ /*
+ * Linux up to 2.6.6: /proc/efi/systab
+ * Linux 2.6.7 and up: /sys/firmware/efi/systab
+ */
+ if((efi_systab=fopen(filename="/sys/firmware/efi/systab", "r"))==NULL
+ && (efi_systab=fopen(filename="/proc/efi/systab", "r"))==NULL)
+ {
+ /* No EFI interface, fallback to memory scan */
+ return EFI_NOT_FOUND;
+ }
+ ret=EFI_NO_SMBIOS;
+ while((fgets(linebuf, sizeof(linebuf)-1, efi_systab))!=NULL)
+ {
+ char *addrp=strchr(linebuf, '=');
+ *(addrp++)='\0';
+ if(strcmp(linebuf, "SMBIOS")==0)
+ {
+ *address=strtoul(addrp, NULL, 0);
+ if(!(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "# SMBIOS entry point at 0x%08lx\n",
+ (unsigned long)*address);
+ ret=0;
+ break;
+ }
+ }
+ if(fclose(efi_systab)!=0)
+ perror(filename);
+
+ if(ret==EFI_NO_SMBIOS)
+ fprintf(stderr, "%s: SMBIOS entry point missing\n", filename);
+ return ret;
+}
+
+#ifdef SO
+int main(int argc, char * const argv[])
+{
+ int ret=0; /* Returned value */
+ int found=0;
+ size_t fp;
+ int efi;
+ u8 *buf;
+
+ if(sizeof(u8)!=1 || sizeof(u16)!=2 || sizeof(u32)!=4 || '\0'!=0)
+ {
+ fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+ exit(255);
+ }
+
+ /* Set default option values */
+ opt.devmem=DEFAULT_MEM_DEV;
+ opt.flags=0;
+
+ if(parse_command_line(argc, argv)<0)
+ {
+ ret=2;
+ goto exit_free;
+ }
+
+ if(opt.flags & FLAG_HELP)
+ {
+ print_help();
+ goto exit_free;
+ }
+
+ if(opt.flags & FLAG_VERSION)
+ {
+ catsprintf(buffer, "%s\n", VERSION);
+ goto exit_free;
+ }
+
+ if(!(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "# dmidecode %s\n", VERSION);
+
+ /* First try EFI (ia64, Intel-based Mac) */
+ efi=address_from_efi(&fp);
+ switch(efi)
+ {
+ case EFI_NOT_FOUND:
+ goto memory_scan;
+ case EFI_NO_SMBIOS:
+ ret=1;
+ goto exit_free;
+ }
+
+ if((buf=mem_chunk(fp, 0x20, opt.devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ if(smbios_decode(buf, opt.devmem))
+ found++;
+ goto done;
+
+memory_scan:
+ /* Fallback to memory scan (x86, x86_64) */
+ if((buf=mem_chunk(0xF0000, 0x10000, opt.devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ for(fp=0; fp<=0xFFF0; fp+=16)
+ {
+ if(memcmp(buf+fp, "_SM_", 4)==0 && fp<=0xFFE0)
+ {
+ if(smbios_decode(buf+fp, opt.devmem))
+ found++;
+ fp+=16;
+ }
+ else if(memcmp(buf+fp, "_DMI_", 5)==0)
+ {
+ if (legacy_decode(buf+fp, opt.devmem))
+ found++;
+ }
+ }
+
+done:
+ free(buf);
+
+ if(!found && !(opt.flags & FLAG_QUIET))
+ catsprintf(buffer, "# No SMBIOS nor DMI entry point found, sorry.\n");
+
+exit_free:
+ free(opt.type);
+
+ return ret;
+}
+#endif
diff --git a/dmidecode.h b/dmidecode.h
new file mode 100644
index 0000000..62779ca
--- /dev/null
+++ b/dmidecode.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2005-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+struct dmi_header
+{
+ u8 type;
+ u8 length;
+ u16 handle;
+ u8 *data;
+};
+
+void dmi_dump(struct dmi_header *h, const char *prefix);
+void dmi_decode(struct dmi_header *h, u16 ver);
+int address_from_efi(size_t *address);
+void to_dmi_header(struct dmi_header *h, u8 *data);
+int smbios_decode(u8 *buf, const char *devmem);
+int legacy_decode(u8 *buf, const char *devmem);
+
+const char *dmi_string(struct dmi_header *dm, u8 s);
+void dmi_system_uuid(u8 *p);
+const char *dmi_chassis_type(u8 code);
+const char *dmi_processor_family(u8 code);
+void dmi_processor_frequency(u8 *p);
diff --git a/dmidecodemodule.c b/dmidecodemodule.c
new file mode 100644
index 0000000..7590063
--- /dev/null
+++ b/dmidecodemodule.c
@@ -0,0 +1,170 @@
+#include <Python.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "dmidecode.h"
+#include "dmiopt.h"
+#include "dmioem.h"
+
+#define EFI_NOT_FOUND (-1)
+#define EFI_NO_SMBIOS (-2)
+
+#include "catsprintf.h"
+#include "global.h"
+
+//http://docs.python.org/api/sequence.html#l2h-338
+// NeuralNuts: you usually use PySquence_Fast() combined with
+// PySquence_Fast_GET_ITEM, but since you know you have a tuple,
+// PySequence_ITEM or PyTuple_GET_ITEM will be fine.
+//
+//
+extern void dmi_dump(struct dmi_header *h, const char *prefix);
+extern void dmi_decode(struct dmi_header *h, u16 ver);
+extern int address_from_efi(size_t *address);
+extern void to_dmi_header(struct dmi_header *h, u8 *data);
+extern void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem);
+extern int smbios_decode(u8 *buf, const char *devmem);
+extern int legacy_decode(u8 *buf, const char *devmem);
+extern void *mem_chunk(size_t base, size_t len, const char *devmem);
+
+static PyObject* dmidecode_get(PyObject *self, PyObject *args) {
+ PyObject *list = PyList_New(0);
+
+ //const char *command;
+ //if(!PyArg_ParseTuple(args, "s", &command))
+ // return NULL;
+
+ //for(i=0; i<len(args); i++)
+ // PyList_Append(list, Py_BuildValue("s", args[i]));
+ PyList_Append(list, PyInt_FromLong(3));
+ PyList_Append(list, PyInt_FromLong(4));
+ //PyList_Append(list, Py_BuildValue("s", command));
+ PyList_Append(list, Py_BuildValue("i", PySequence_Size(args)));
+
+ int i;
+ int argc = PySequence_Size(args);
+ char *argv[argc];
+ for(i=0; i<argc; i++) {
+ argv[i] = PyString_AS_STRING(PySequence_ITEM(args, i));
+ printf(">> %s <<\n", argv[i]);
+ PyList_Append(list, PySequence_ITEM(args, i));
+ }
+ bzero(buffer, 50000);
+ //submain(buffer, argc, argv);
+
+ return list;
+}
+
+PyMethodDef DMIDataMethods[] = {
+ { "dmidecode", dmidecode_get, METH_VARARGS, "Get hardware data as a list" },
+ { NULL, NULL, 0, NULL }
+};
+
+
+PyMODINIT_FUNC initdmidecode(void) {
+ (void) Py_InitModule("dmidecode", DMIDataMethods);
+}
+
+
+int submain(char* buffer, int argc, char * const argv[])
+{
+ int ret=0; /* Returned value */
+ int found=0;
+ size_t fp;
+ int efi;
+ u8 *buf;
+
+ if(sizeof(u8)!=1 || sizeof(u16)!=2 || sizeof(u32)!=4 || '\0'!=0)
+ {
+ fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+ exit(255);
+ }
+
+ /* Set default option values */
+ opt.devmem=DEFAULT_MEM_DEV;
+ opt.flags=0;
+
+ if(parse_command_line(argc, argv)<0)
+ {
+ ret=2;
+ goto exit_free;
+ }
+
+ if(opt.flags & FLAG_HELP)
+ {
+ print_help();
+ goto exit_free;
+ }
+
+ if(opt.flags & FLAG_VERSION)
+ {
+ printf("%s\n", VERSION);
+ goto exit_free;
+ }
+
+ if(!(opt.flags & FLAG_QUIET))
+ printf("# dmidecode %s\n", VERSION);
+
+ /* First try EFI (ia64, Intel-based Mac) */
+ efi=address_from_efi(&fp);
+ switch(efi)
+ {
+ case EFI_NOT_FOUND:
+ goto memory_scan;
+ case EFI_NO_SMBIOS:
+ ret=1;
+ goto exit_free;
+ }
+
+ if((buf=mem_chunk(fp, 0x20, opt.devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ if(smbios_decode(buf, opt.devmem))
+ found++;
+ goto done;
+
+memory_scan:
+ /* Fallback to memory scan (x86, x86_64) */
+ if((buf=mem_chunk(0xF0000, 0x10000, opt.devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ for(fp=0; fp<=0xFFF0; fp+=16)
+ {
+ if(memcmp(buf+fp, "_SM_", 4)==0 && fp<=0xFFE0)
+ {
+ if(smbios_decode(buf+fp, opt.devmem))
+ found++;
+ fp+=16;
+ }
+ else if(memcmp(buf+fp, "_DMI_", 5)==0)
+ {
+ if (legacy_decode(buf+fp, opt.devmem))
+ found++;
+ }
+ }
+
+done:
+ free(buf);
+
+ if(!found && !(opt.flags & FLAG_QUIET))
+ printf("# No SMBIOS nor DMI entry point found, sorry.\n");
+
+exit_free:
+ free(opt.type);
+
+ printf("%s\n", buffer);
+ return ret;
+}
diff --git a/dmioem.c b/dmioem.c
new file mode 100644
index 0000000..a2fd2a2
--- /dev/null
+++ b/dmioem.c
@@ -0,0 +1,128 @@
+/*
+ * Decoding of OEM-specific entries
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "types.h"
+#include "dmidecode.h"
+#include "dmioem.h"
+
+/*
+ * Globals for vendor-specific decodes
+ */
+
+enum DMI_VENDORS { VENDOR_UNKNOWN, VENDOR_HP };
+
+static enum DMI_VENDORS dmi_vendor=VENDOR_UNKNOWN;
+
+/*
+ * Remember the system vendor for later use. We only actually store the
+ * value if we know how to decode at least one specific entry type for
+ * that vendor.
+ */
+void dmi_set_vendor(const char *s)
+{
+ if(strcmp(s, "HP")==0)
+ dmi_vendor=VENDOR_HP;
+}
+
+/*
+ * HP-specific data structures are decoded here.
+ *
+ * Code contributed by John Cagle.
+ */
+
+static int dmi_decode_hp(struct dmi_header *h)
+{
+ u8 *data=h->data;
+ int nic, ptr;
+
+ switch(h->type)
+ {
+ case 204:
+ /*
+ * Vendor Specific: HP ProLiant System/Rack Locator
+ */
+ printf("HP ProLiant System/Rack Locator\n");
+ if(h->length<0x0B) break;
+ printf("\tRack Name: %s\n", dmi_string(h, data[0x04]));
+ printf("\tEnclosure Name: %s\n", dmi_string(h, data[0x05]));
+ printf("\tEnclosure Model: %s\n", dmi_string(h, data[0x06]));
+ printf("\tEnclosure Serial: %s\n", dmi_string(h, data[0x0A]));
+ printf("\tEnclosure Bays: %d\n", data[0x08]);
+ printf("\tServer Bay: %s\n", dmi_string(h, data[0x07]));
+ printf("\tBays Filled: %d\n", data[0x09]);
+ break;
+
+ case 209:
+ case 221:
+ /*
+ * Vendor Specific: HP ProLiant NIC MAC Information
+ *
+ * This prints the BIOS NIC number,
+ * PCI bus/device/function, and MAC address
+ */
+ printf(h->type==221?
+ "HP BIOS iSCSI NIC PCI and MAC Information\n":
+ "HP BIOS NIC PCI and MAC Information\n");
+ nic=1;
+ ptr=4;
+ while(h->length>=ptr+8)
+ {
+ if(data[ptr]==0x00 && data[ptr+1]==0x00)
+ printf("\tNIC %d: Disabled\n", nic);
+ else if(data[ptr]==0xFF && data[ptr+1]==0xFF)
+ printf("\tNIC %d: Not Installed\n", nic);
+ else
+ {
+ printf("\tNIC %d: PCI device %02x:%02x.%x, "
+ "MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
+ nic, data[ptr+1], data[ptr]>>3, data[ptr]&7,
+ data[ptr+2], data[ptr+3],
+ data[ptr+4], data[ptr+5],
+ data[ptr+6], data[ptr+7]);
+ }
+ nic++;
+ ptr+=8;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Dispatch vendor-specific entries decoding
+ * Return 1 if decoding was successful, 0 otherwise
+ */
+int dmi_decode_oem(struct dmi_header *h)
+{
+ switch(dmi_vendor)
+ {
+ case VENDOR_HP:
+ return dmi_decode_hp(h);
+ default:
+ return 0;
+ }
+}
diff --git a/dmioem.h b/dmioem.h
new file mode 100644
index 0000000..00483f2
--- /dev/null
+++ b/dmioem.h
@@ -0,0 +1,25 @@
+/*
+ * Decoding of OEM-specific entries
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+struct dmi_header;
+
+void dmi_set_vendor(const char *s);
+int dmi_decode_oem(struct dmi_header *h);
diff --git a/dmiopt.c b/dmiopt.c
new file mode 100644
index 0000000..d571108
--- /dev/null
+++ b/dmiopt.c
@@ -0,0 +1,308 @@
+/*
+ * Command line handling of dmidecode
+ * This file is part of the dmidecode project.
+ *
+ * (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "dmidecode.h"
+#include "dmiopt.h"
+
+
+/* Options are global */
+struct opt opt;
+
+
+/*
+ * Handling of option --type
+ */
+
+struct type_keyword
+{
+ const char *keyword;
+ const u8 *type;
+};
+
+static const u8 opt_type_bios[]={ 0, 13, 255 };
+static const u8 opt_type_system[]={ 1, 12, 15, 23, 32, 255 };
+static const u8 opt_type_baseboard[]={ 2, 10, 255 };
+static const u8 opt_type_chassis[]={ 3, 255 };
+static const u8 opt_type_processor[]={ 4, 255 };
+static const u8 opt_type_memory[]={ 5, 6, 16, 17, 255 };
+static const u8 opt_type_cache[]={ 7, 255 };
+static const u8 opt_type_connector[]={ 8, 255 };
+static const u8 opt_type_slot[]={ 9, 255 };
+
+static const struct type_keyword opt_type_keyword[]={
+ { "bios", opt_type_bios },
+ { "system", opt_type_system },
+ { "baseboard", opt_type_baseboard },
+ { "chassis", opt_type_chassis },
+ { "processor", opt_type_processor },
+ { "memory", opt_type_memory },
+ { "cache", opt_type_cache },
+ { "connector", opt_type_connector },
+ { "slot", opt_type_slot },
+};
+
+static void print_opt_type_list(void)
+{
+ unsigned int i;
+
+ fprintf(stderr, "Valid type keywords are:\n");
+ for(i=0; i<ARRAY_SIZE(opt_type_keyword); i++)
+ {
+ fprintf(stderr, " %s\n", opt_type_keyword[i].keyword);
+ }
+}
+
+static u8 *parse_opt_type(u8 *p, const char *arg)
+{
+ unsigned int i;
+
+ /* Allocate memory on first call only */
+ if(p==NULL)
+ {
+ p=(u8 *)calloc(256, sizeof(u8));
+ if(p==NULL)
+ {
+ perror("calloc");
+ return NULL;
+ }
+ }
+
+ /* First try as a keyword */
+ for(i=0; i<ARRAY_SIZE(opt_type_keyword); i++)
+ {
+ if(!strcasecmp(arg, opt_type_keyword[i].keyword))
+ {
+ int j=0;
+ while(opt_type_keyword[i].type[j]!=255)
+ p[opt_type_keyword[i].type[j++]]=1;
+ goto found;
+ }
+ }
+
+ /* Else try as a number */
+ while(*arg!='\0')
+ {
+ unsigned long val;
+ char *next;
+
+ val=strtoul(arg, &next, 0);
+ if(next==arg)
+ {
+ fprintf(stderr, "Invalid type keyword: %s\n", arg);
+ print_opt_type_list();
+ goto exit_free;
+ }
+ if(val>0xff)
+ {
+ fprintf(stderr, "Invalid type number: %lu\n", val);
+ goto exit_free;
+ }
+
+ p[val]=1;
+ arg=next;
+ while(*arg==',' || *arg==' ')
+ arg++;
+ }
+
+found:
+ return p;
+
+exit_free:
+ free(p);
+ return NULL;
+}
+
+
+/*
+ * Handling of option --string
+ */
+
+/* This lookup table could admittedly be reworked for improved performance.
+ Due to the low count of items in there at the moment, it did not seem
+ worth the additional code complexity though. */
+static const struct string_keyword opt_string_keyword[]={
+ { "bios-vendor", 0, 0x04, NULL, NULL },
+ { "bios-version", 0, 0x05, NULL, NULL },
+ { "bios-release-date", 0, 0x08, NULL, NULL },
+ { "system-manufacturer", 1, 0x04, NULL, NULL },
+ { "system-product-name", 1, 0x05, NULL, NULL },
+ { "system-version", 1, 0x06, NULL, NULL },
+ { "system-serial-number", 1, 0x07, NULL, NULL },
+ { "system-uuid", 1, 0x08, NULL, dmi_system_uuid },
+ { "baseboard-manufacturer", 2, 0x04, NULL, NULL },
+ { "baseboard-product-name", 2, 0x05, NULL, NULL },
+ { "baseboard-version", 2, 0x06, NULL, NULL },
+ { "baseboard-serial-number", 2, 0x07, NULL, NULL },
+ { "baseboard-asset-tag", 2, 0x08, NULL, NULL },
+ { "chassis-manufacturer", 3, 0x04, NULL, NULL },
+ { "chassis-type", 3, 0x05, dmi_chassis_type, NULL },
+ { "chassis-version", 3, 0x06, NULL, NULL },
+ { "chassis-serial-number", 3, 0x07, NULL, NULL },
+ { "chassis-asset-tag", 3, 0x08, NULL, NULL },
+ { "processor-family", 4, 0x06, dmi_processor_family, NULL },
+ { "processor-manufacturer", 4, 0x07, NULL, NULL },
+ { "processor-version", 4, 0x10, NULL, NULL },
+ { "processor-frequency", 4, 0x16, NULL, dmi_processor_frequency },
+};
+
+static void print_opt_string_list(void)
+{
+ unsigned int i;
+
+ fprintf(stderr, "Valid string keywords are:\n");
+ for(i=0; i<ARRAY_SIZE(opt_string_keyword); i++)
+ {
+ fprintf(stderr, " %s\n", opt_string_keyword[i].keyword);
+ }
+}
+
+static int parse_opt_string(const char *arg)
+{
+ unsigned int i;
+
+ if(opt.string)
+ {
+ fprintf(stderr, "Only one string can be specified\n");
+ return -1;
+ }
+
+ for(i=0; i<ARRAY_SIZE(opt_string_keyword); i++)
+ {
+ if(!strcasecmp(arg, opt_string_keyword[i].keyword))
+ {
+ opt.string=&opt_string_keyword[i];
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "Invalid string keyword: %s\n", arg);
+ print_opt_string_list();
+ return -1;
+}
+
+
+/*
+ * Command line options handling
+ */
+
+/* Return -1 on error, 0 on success */
+int parse_command_line(int argc, char * const argv[])
+{
+ int option;
+ const char *optstring = "d:hqs:t:uV";
+ struct option longopts[]={
+ { "dev-mem", required_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "quiet", no_argument, NULL, 'q' },
+ { "string", required_argument, NULL, 's' },
+ { "type", required_argument, NULL, 't' },
+ { "dump", no_argument, NULL, 'u' },
+ { "version", no_argument, NULL, 'V' },
+ { 0, 0, 0, 0 }
+ };
+
+ while((option=getopt_long(argc, argv, optstring, longopts, NULL))!=-1)
+ switch(option)
+ {
+ case 'd':
+ opt.devmem=optarg;
+ break;
+ case 'h':
+ opt.flags|=FLAG_HELP;
+ break;
+ case 'q':
+ opt.flags|=FLAG_QUIET;
+ break;
+ case 's':
+ if(parse_opt_string(optarg)<0)
+ return -1;
+ opt.flags|=FLAG_QUIET;
+ break;
+ case 't':
+ opt.type=parse_opt_type(opt.type, optarg);
+ if(opt.type==NULL)
+ return -1;
+ break;
+ case 'u':
+ opt.flags|=FLAG_DUMP;
+ break;
+ case 'V':
+ opt.flags|=FLAG_VERSION;
+ break;
+ case '?':
+ switch(optopt)
+ {
+ case 's':
+ fprintf(stderr, "String keyword expected\n");
+ print_opt_string_list();
+ break;
+ case 't':
+ fprintf(stderr, "Type number or keyword expected\n");
+ print_opt_type_list();
+ break;
+ }
+ return -1;
+ }
+
+ if(opt.type!=NULL && opt.string!=NULL)
+ {
+ fprintf(stderr, "Options --string and --type are mutually exclusive\n");
+ return -1;
+ }
+
+ if((opt.flags & FLAG_DUMP) && opt.string!=NULL)
+ {
+ fprintf(stderr, "Options --string and --dump are mutually exclusive\n");
+ return -1;
+ }
+
+ if((opt.flags & FLAG_DUMP) && (opt.flags & FLAG_QUIET))
+ {
+ fprintf(stderr, "Options --quiet and --dump are mutually exclusive\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void print_help(void)
+{
+ static const char *help=
+ "Usage: dmidecode [OPTIONS]\n"
+ "Options are:\n"
+ " -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
+ " -h, --help Display this help text and exit\n"
+ " -q, --quiet Less verbose output\n"
+ " -s, --string KEYWORD Only display the value of the given DMI string\n"
+ " -t, --type TYPE Only display the entries of given type\n"
+ " -u, --dump Do not decode the entries\n"
+ " -V, --version Display the version and exit\n";
+
+ printf("%s", help);
+}
diff --git a/dmiopt.h b/dmiopt.h
new file mode 100644
index 0000000..fe8e193
--- /dev/null
+++ b/dmiopt.h
@@ -0,0 +1,46 @@
+/*
+ * Command line handling of dmidecode
+ * This file is part of the dmidecode project.
+ *
+ * (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+struct string_keyword
+{
+ const char *keyword;
+ u8 type;
+ u8 offset;
+ const char *(*lookup)(u8);
+ void (*print)(u8 *);
+};
+
+struct opt
+{
+ const char* devmem;
+ unsigned int flags;
+ u8 *type;
+ const struct string_keyword *string;
+};
+extern struct opt opt;
+
+#define FLAG_VERSION (1<<0)
+#define FLAG_HELP (1<<1)
+#define FLAG_DUMP (1<<2)
+#define FLAG_QUIET (1<<3)
+
+int parse_command_line(int argc, char * const argv[]);
+void print_help(void);
diff --git a/global.h b/global.h
new file mode 100644
index 0000000..a1a911a
--- /dev/null
+++ b/global.h
@@ -0,0 +1,7 @@
+#ifndef GLOB
+#define GLOB 1
+
+struct opt opt;
+char buffer[50000];
+
+#endif
diff --git a/ownership.c b/ownership.c
new file mode 100644
index 0000000..29b9850
--- /dev/null
+++ b/ownership.c
@@ -0,0 +1,212 @@
+/*
+ * Compaq Ownership Tag
+ *
+ * (C) 2003-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open unpatent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ * References:
+ * - Compaq "Technical Reference Guide for Compaq Deskpro 4000 and 6000"
+ * First Edition
+ * http://h18000.www1.hp.com/support/techpubs/technical_reference_guides/113a1097.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+
+/* Options are global */
+struct opt
+{
+ const char* devmem;
+ unsigned int flags;
+};
+static struct opt opt;
+
+#define FLAG_VERSION (1<<0)
+#define FLAG_HELP (1<<1)
+
+static void ownership(u32 base, const char *pname, const char *devmem)
+{
+ u8 *buf;
+ int i;
+
+ /* read the ownership tag */
+ if((buf=mem_chunk(base, 0x51, devmem))==NULL)
+ {
+ perror(pname);
+ return;
+ }
+
+ /* chop the trailing garbage */
+ i=0x4f;
+ while(i>=0 && (buf[i]==0x20 || buf[i]==0x00))
+ i--;
+ buf[i+1]='\0';
+
+ /* filter and print */
+ if(i>=0)
+ {
+ for(; i>=0; i--)
+ {
+ if(buf[i]<32 || (buf[i]>=127 && buf[i]<160))
+ buf[i]='?';
+ }
+ printf("%s\n", (char *)buf);
+ }
+
+ free(buf);
+}
+
+static u32 decode(const u8 *p)
+{
+ int i;
+
+ /* integrity checking (lack of checksum) */
+ for(i=0; i<p[4]; i++)
+ {
+ if(p[5+i*10]!='$' || !(p[6+i*10]>='A' && p[6+i*10]<='Z')
+ || !(p[7+i*10]>='A' && p[7+i*10]<='Z')
+ || !(p[8+i*10]>='A' && p[8+i*10]<='Z'))
+ {
+ printf("\t Abnormal Entry! Please report. [%02x %02x %02x %02x]\n",
+ p[5+i*10], p[6+i*10], p[7+i*10], p[8+i*10]);
+ return 0;
+ }
+ }
+
+ /* search for the right entry */
+ for(i=0; i<p[4]; i++)
+ if(memcmp(p+5+i*10, "$ERB", 4)==0)
+ return DWORD(p+9+i*10);
+
+ return 0;
+}
+
+/* Return -1 on error, 0 on success */
+static int parse_command_line(int argc, char * const argv[])
+{
+ int option;
+ const char *optstring = "d:hV";
+ struct option longopts[]={
+ { "dev-mem", required_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { 0, 0, 0, 0 }
+ };
+
+ while((option=getopt_long(argc, argv, optstring, longopts, NULL))!=-1)
+ switch(option)
+ {
+ case 'd':
+ opt.devmem=optarg;
+ break;
+ case 'h':
+ opt.flags|=FLAG_HELP;
+ break;
+ case 'V':
+ opt.flags|=FLAG_VERSION;
+ break;
+ case '?':
+ return -1;
+ }
+
+ return 0;
+}
+
+static void print_help(void)
+{
+ static const char *help=
+ "Usage: ownership [OPTIONS]\n"
+ "Options are:\n"
+ " -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
+ " -h, --help Display this help text and exit\n"
+ " -V, --version Display the version and exit\n";
+
+ printf("%s", help);
+}
+
+int main(int argc, char * const argv[])
+{
+ u8 *buf;
+ off_t fp;
+ int ok=0;
+
+ if(sizeof(u8)!=1 || sizeof(u32)!=4)
+ {
+ fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+ exit(255);
+ }
+
+ /* Set default option values */
+ opt.devmem=DEFAULT_MEM_DEV;
+ opt.flags=0;
+
+ if(parse_command_line(argc, argv)<0)
+ exit(2);
+
+ if(opt.flags & FLAG_HELP)
+ {
+ print_help();
+ return 0;
+ }
+
+ if(opt.flags & FLAG_VERSION)
+ {
+ printf("%s\n", VERSION);
+ return 0;
+ }
+
+ if((buf=mem_chunk(0xE0000, 0x20000, opt.devmem))==NULL)
+ exit(1);
+
+ for(fp=0; !ok && fp<=0x1FFF0; fp+=16)
+ {
+ u8 *p=buf+fp;
+
+ if(memcmp((char *)p, "32OS", 4)==0)
+ {
+ off_t len=p[4]*10+5;
+
+ if(fp+len-1<=0x1FFFF)
+ {
+ u32 base;
+
+ if((base=decode(p)))
+ {
+ ok=1;
+ ownership(base, argv[0], opt.devmem);
+ }
+ }
+ }
+ }
+
+ free(buf);
+
+ return 0;
+}
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..ca193c0
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,5 @@
+from distutils.core import setup, Extension
+
+setup(name = "DMIDecode",
+ version = "1.0",
+ ext_modules = [Extension("dmidecode", ["dmidecodemodule.c"])])
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..1b86b2f
--- /dev/null
+++ b/test.c
@@ -0,0 +1,127 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "dmidecode.h"
+#include "dmiopt.h"
+#include "dmioem.h"
+
+#define EFI_NOT_FOUND (-1)
+#define EFI_NO_SMBIOS (-2)
+
+#include <Python.h>
+#include "catsprintf.h"
+#include "global.h"
+
+extern void dmi_dump(struct dmi_header *h, const char *prefix);
+extern void dmi_decode(struct dmi_header *h, u16 ver);
+extern int address_from_efi(size_t *address);
+extern void to_dmi_header(struct dmi_header *h, u8 *data);
+extern void dmi_table(u32 base, u16 len, u16 num, u16 ver, const char *devmem);
+extern int smbios_decode(u8 *buf, const char *devmem);
+extern int legacy_decode(u8 *buf, const char *devmem);
+
+
+
+int main(int argc, char * const argv[])
+{
+ bzero(buffer, 50000);
+
+ int ret=0; /* Returned value */
+ int found=0;
+ size_t fp;
+ int efi;
+ u8 *buf;
+
+ if(sizeof(u8)!=1 || sizeof(u16)!=2 || sizeof(u32)!=4 || '\0'!=0)
+ {
+ fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+ exit(255);
+ }
+
+ /* Set default option values */
+ opt.devmem=DEFAULT_MEM_DEV;
+ opt.flags=0;
+
+ if(parse_command_line(argc, argv)<0)
+ {
+ ret=2;
+ goto exit_free;
+ }
+
+ if(opt.flags & FLAG_HELP)
+ {
+ print_help();
+ goto exit_free;
+ }
+
+ if(opt.flags & FLAG_VERSION)
+ {
+ printf("%s\n", VERSION);
+ goto exit_free;
+ }
+
+ if(!(opt.flags & FLAG_QUIET))
+ printf("# dmidecode %s\n", VERSION);
+
+ /* First try EFI (ia64, Intel-based Mac) */
+ efi=address_from_efi(&fp);
+ switch(efi)
+ {
+ case EFI_NOT_FOUND:
+ goto memory_scan;
+ case EFI_NO_SMBIOS:
+ ret=1;
+ goto exit_free;
+ }
+
+ if((buf=mem_chunk(fp, 0x20, opt.devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ if(smbios_decode(buf, opt.devmem))
+ found++;
+ goto done;
+
+memory_scan:
+ /* Fallback to memory scan (x86, x86_64) */
+ if((buf=mem_chunk(0xF0000, 0x10000, opt.devmem))==NULL)
+ {
+ ret=1;
+ goto exit_free;
+ }
+
+ for(fp=0; fp<=0xFFF0; fp+=16)
+ {
+ if(memcmp(buf+fp, "_SM_", 4)==0 && fp<=0xFFE0)
+ {
+ if(smbios_decode(buf+fp, opt.devmem))
+ found++;
+ fp+=16;
+ }
+ else if(memcmp(buf+fp, "_DMI_", 5)==0)
+ {
+ if (legacy_decode(buf+fp, opt.devmem))
+ found++;
+ }
+ }
+
+done:
+ free(buf);
+
+ if(!found && !(opt.flags & FLAG_QUIET))
+ printf("# No SMBIOS nor DMI entry point found, sorry.\n");
+
+exit_free:
+ free(opt.type);
+
+ printf("%s\n", buffer);
+ return ret;
+}
diff --git a/types.h b/types.h
new file mode 100644
index 0000000..b124ecf
--- /dev/null
+++ b/types.h
@@ -0,0 +1,62 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+#include "config.h"
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef signed short i16;
+typedef unsigned int u32;
+
+/*
+ * You may use the following defines to adjust the type definitions
+ * depending on the architecture:
+ * - Define BIGENDIAN on big-endian systems. Untested, as all target
+ * systems to date are little-endian.
+ * - Define ALIGNMENT_WORKAROUND if your system doesn't support
+ * non-aligned memory access. In this case, we use a slower, but safer,
+ * memory access method. This should be done automatically in config.h
+ * for architectures which need it.
+ */
+
+#ifdef BIGENDIAN
+typedef struct {
+ u32 h;
+ u32 l;
+} u64;
+#else
+typedef struct {
+ u32 l;
+ u32 h;
+} u64;
+#endif
+
+#ifdef ALIGNMENT_WORKAROUND
+static inline u64 U64(u32 low, u32 high)
+{
+ u64 self;
+
+ self.l=low;
+ self.h=high;
+
+ return self;
+}
+#endif
+
+#ifdef ALIGNMENT_WORKAROUND
+# ifdef BIGENDIAN
+# define WORD(x) (u16)((x)[1]+((x)[0]<<8))
+# define DWORD(x) (u32)((x)[3]+((x)[2]<<8)+((x)[1]<<16)+((x)[0]<<24))
+# define QWORD(x) (U64(DWORD(x+4), DWORD(x)))
+# else /* BIGENDIAN */
+# define WORD(x) (u16)((x)[0]+((x)[1]<<8))
+# define DWORD(x) (u32)((x)[0]+((x)[1]<<8)+((x)[2]<<16)+((x)[3]<<24))
+# define QWORD(x) (U64(DWORD(x), DWORD(x+4)))
+# endif /* BIGENDIAN */
+#else /* ALIGNMENT_WORKAROUND */
+#define WORD(x) (u16)(*(const u16 *)(x))
+#define DWORD(x) (u32)(*(const u32 *)(x))
+#define QWORD(x) (*(const u64 *)(x))
+#endif /* ALIGNMENT_WORKAROUND */
+
+#endif
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..9eda714
--- /dev/null
+++ b/util.c
@@ -0,0 +1,165 @@
+/*
+ * Common "util" functions
+ * This file is part of the dmidecode project.
+ *
+ * (C) 2002-2005 Jean Delvare <khali@linux-fr>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open unpatent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+
+#ifdef USE_MMAP
+#include <sys/mman.h>
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif /* !MAP_FAILED */
+#endif /* USE MMAP */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "types.h"
+#include "util.h"
+
+#ifndef USE_MMAP
+static int myread(int fd, u8 *buf, size_t count, const char *prefix)
+{
+ ssize_t r=1;
+ size_t r2=0;
+
+ while(r2!=count && r!=0)
+ {
+ r=read(fd, buf+r2, count-r2);
+ if(r==-1)
+ {
+ if(errno!=EINTR)
+ {
+ close(fd);
+ perror(prefix);
+ return -1;
+ }
+ }
+ else
+ r2+=r;
+ }
+
+ if(r2!=count)
+ {
+ close(fd);
+ fprintf(stderr, "%s: Unexpected end of file\n", prefix);
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+int checksum(const u8 *buf, size_t len)
+{
+ u8 sum=0;
+ size_t a;
+
+ for(a=0; a<len; a++)
+ sum+=buf[a];
+ return (sum==0);
+}
+
+/*
+ * Copy a physical memory chunk into a memory buffer.
+ * This function allocates memory.
+ */
+void *mem_chunk(size_t base, size_t len, const char *devmem)
+{
+ void *p;
+ int fd;
+#ifdef USE_MMAP
+ size_t mmoffset;
+ void *mmp;
+#endif
+
+ if((fd=open(devmem, O_RDONLY))==-1)
+ {
+ perror(devmem);
+ return NULL;
+ }
+
+ if((p=malloc(len))==NULL)
+ {
+ perror("malloc");
+ return NULL;
+ }
+
+#ifdef USE_MMAP
+#ifdef _SC_PAGESIZE
+ mmoffset=base%sysconf(_SC_PAGESIZE);
+#else
+ mmoffset=base%getpagesize();
+#endif /* _SC_PAGESIZE */
+ /*
+ * Please note that we don't use mmap() for performance reasons here,
+ * but to workaround problems many people encountered when trying
+ * to read from /dev/mem using regular read() calls.
+ */
+ mmp=mmap(0, mmoffset+len, PROT_READ, MAP_SHARED, fd, base-mmoffset);
+ if(mmp==MAP_FAILED)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("mmap");
+ free(p);
+ return NULL;
+ }
+
+ memcpy(p, (u8 *)mmp+mmoffset, len);
+
+ if(munmap(mmp, mmoffset+len)==-1)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("munmap");
+ }
+#else /* USE_MMAP */
+ if(lseek(fd, base, SEEK_SET)==-1)
+ {
+ fprintf(stderr, "%s: ", devmem);
+ perror("lseek");
+ free(p);
+ return NULL;
+ }
+
+ if(myread(fd, p, len, devmem)==-1)
+ {
+ free(p);
+ return NULL;
+ }
+#endif /* USE_MMAP */
+
+ if(close(fd)==-1)
+ perror(devmem);
+
+ return p;
+}
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..b546f64
--- /dev/null
+++ b/util.h
@@ -0,0 +1,8 @@
+#include <sys/types.h>
+
+#include "types.h"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+int checksum(const u8 *buf, size_t len);
+void *mem_chunk(size_t base, size_t len, const char *devmem);
diff --git a/version.h b/version.h
new file mode 100644
index 0000000..050cf7a
--- /dev/null
+++ b/version.h
@@ -0,0 +1 @@
+#define VERSION "2.9"
diff --git a/vpddecode.c b/vpddecode.c
new file mode 100644
index 0000000..4e00263
--- /dev/null
+++ b/vpddecode.c
@@ -0,0 +1,202 @@
+/*
+ * IBM Vital Product Data decoder
+ *
+ * (C) 2003-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open unpatent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ * References:
+ * - IBM "Using the BIOS Build ID to identify Thinkpad systems"
+ * Revision 2006-01-31
+ * http://www-307.ibm.com/pc/support/site.wss/MIGR-45120.html
+ *
+ * Notes:
+ * - Main part of the code is taken directly from biosdecode, with an
+ * additional command line interface and a few experimental features.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "version.h"
+#include "config.h"
+#include "types.h"
+#include "util.h"
+#include "vpdopt.h"
+
+static void print_entry(const char *name, const u8 *p, size_t len)
+{
+ size_t i;
+
+ if(name!=NULL)
+ printf("%s: ", name);
+ for(i=0; i<len; i++)
+ {
+ /* ASCII filtering */
+ if(p[i]>=32 && p[i]<127)
+ printf("%c", p[i]);
+ else if(p[i]!=0)
+ printf(".");
+ }
+ printf("\n");
+}
+
+static void dump(const u8 *p, u8 len)
+{
+ int done, i, min;
+
+ for(done=0; done<len; done+=16)
+ {
+ printf("%02X:", done);
+ min=(len-done<16)?len-done:16;
+
+ /* As hexadecimal first */
+ for(i=0; i<min; i++)
+ printf(" %02X", p[done+i]);
+ for(; i<16; i++) /* Complete line if needed */
+ printf(" ");
+ printf(" ");
+
+ /* And now as text, with ASCII filtering */
+ for(i=0; i<min; i++)
+ printf("%c", (p[done+i]>=32 && p[done+i]<127)?
+ p[done+i]:'.');
+ printf("\n");
+ }
+}
+
+static int decode(const u8 *p)
+{
+ if(p[5]<0x30)
+ return 0;
+
+ /* XSeries have longer records, exact length seems to vary. */
+ if(!(p[5]>=0x45 && checksum(p, p[5]))
+ /* Some Netvista seem to work with this. */
+ && !(checksum(p, 0x30))
+ /* The Thinkpad/Thinkcentre checksum does *not* include the first
+ 13 bytes. */
+ && !(checksum(p+0x0D, 0x30-0x0D)))
+ {
+ /* A few systems have a bad checksum (xSeries 325, 330, 335
+ and 345 with early BIOS) but the record is otherwise
+ valid. */
+ if(!(opt.flags & FLAG_QUIET))
+ printf("Bad checksum! Please report.\n");
+ }
+
+ if(opt.string!=NULL)
+ {
+ if(opt.string->offset+opt.string->len<p[5])
+ print_entry(NULL, p+opt.string->offset,
+ opt.string->len);
+ return 1;
+ }
+
+ print_entry("BIOS Build ID", p+0x0D, 9);
+ print_entry("Box Serial Number", p+0x16, 7);
+ print_entry("Motherboard Serial Number", p+0x1D, 11);
+ print_entry("Machine Type/Model", p+0x28, 7);
+
+ if(p[5]<0x44)
+ return 1;
+
+ print_entry("BIOS Release Date", p+0x30, 8);
+ print_entry("Default Flash Image File Name", p+0x38, 12);
+
+ if(p[5]>=0x46 && p[0x44]!=0x00)
+ {
+ printf("%s: %u (Please report!)\n", "BIOS Revision",
+ p[0x44]);
+ }
+
+ return 1;
+}
+
+int main(int argc, char * const argv[])
+{
+ u8 *buf;
+ int found=0;
+ unsigned int fp;
+
+ if(sizeof(u8)!=1)
+ {
+ fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
+ exit(255);
+ }
+
+ /* Set default option values */
+ opt.devmem=DEFAULT_MEM_DEV;
+ opt.flags=0;
+
+ if(parse_command_line(argc, argv)<0)
+ exit(2);
+
+ if(opt.flags & FLAG_HELP)
+ {
+ print_help();
+ return 0;
+ }
+
+ if(opt.flags & FLAG_VERSION)
+ {
+ printf("%s\n", VERSION);
+ return 0;
+ }
+
+ if(!(opt.flags & FLAG_QUIET))
+ printf("# vpddecode %s\n", VERSION);
+
+ if((buf=mem_chunk(0xF0000, 0x10000, opt.devmem))==NULL)
+ exit(1);
+
+ for(fp=0; fp<=0xFFF0; fp+=4)
+ {
+ u8 *p=buf+fp;
+
+ if(memcmp((char *)p, "\252\125VPD", 5)==0
+ && fp+p[5]-1<=0xFFFF)
+ {
+ if(fp%16 && !(opt.flags & FLAG_QUIET))
+ printf("Unaligned address (%#x), please report!\n",
+ 0xf0000+fp);
+ if(opt.flags & FLAG_DUMP)
+ {
+ dump(p, p[5]);
+ found++;
+ }
+ else
+ {
+ if(decode(p))
+ found++;
+ }
+ }
+ }
+
+ free(buf);
+
+ if(!found && !(opt.flags && FLAG_QUIET))
+ printf("# No VPD structure found, sorry.\n");
+
+ return 0;
+}
diff --git a/vpdopt.c b/vpdopt.c
new file mode 100644
index 0000000..c895202
--- /dev/null
+++ b/vpdopt.c
@@ -0,0 +1,159 @@
+/*
+ * Command line handling of vpddecode
+ * This file is part of the dmidecode project.
+ *
+ * (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "config.h"
+#include "util.h"
+#include "vpdopt.h"
+
+#include "global.h"
+
+
+/* Options are global */
+//struct opt opt;
+
+
+/*
+ * Handling of option --string
+ */
+
+/* This lookup table could admittedly be reworked for improved performance.
+ Due to the low count of items in there at the moment, it did not seem
+ worth the additional code complexity though. */
+static const struct string_keyword opt_string_keyword[]={
+ { "bios-build-id", 0x0D, 9 },
+ { "box-serial-number", 0x16, 7 },
+ { "motherboard-serial-number", 0x1D, 11 },
+ { "machine-type-model", 0x28, 7 },
+ { "bios-release-date", 0x30, 8 },
+};
+
+static void print_opt_string_list(void)
+{
+ unsigned int i;
+
+ fprintf(stderr, "Valid string keywords are:\n");
+ for(i=0; i<ARRAY_SIZE(opt_string_keyword); i++)
+ {
+ fprintf(stderr, " %s\n", opt_string_keyword[i].keyword);
+ }
+}
+
+static int parse_opt_string(const char *arg)
+{
+ unsigned int i;
+
+ if(opt.string)
+ {
+ fprintf(stderr, "Only one string can be specified\n");
+ return -1;
+ }
+
+ for(i=0; i<ARRAY_SIZE(opt_string_keyword); i++)
+ {
+ if(!strcasecmp(arg, opt_string_keyword[i].keyword))
+ {
+ opt.string=&opt_string_keyword[i];
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "Invalid string keyword: %s\n", arg);
+ print_opt_string_list();
+ return -1;
+}
+
+
+/*
+ * Command line options handling
+ */
+
+/* Return -1 on error, 0 on success */
+int parse_command_line(int argc, char * const argv[])
+{
+ int option;
+ const char *optstring = "d:hs:uV";
+ struct option longopts[]={
+ { "dev-mem", required_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "string", required_argument, NULL, 's' },
+ { "dump", no_argument, NULL, 'u' },
+ { "version", no_argument, NULL, 'V' },
+ { 0, 0, 0, 0 }
+ };
+
+ while((option=getopt_long(argc, argv, optstring, longopts, NULL))!=-1)
+ switch(option)
+ {
+ case 'd':
+ opt.devmem=optarg;
+ break;
+ case 'h':
+ opt.flags|=FLAG_HELP;
+ break;
+ case 's':
+ if(parse_opt_string(optarg)<0)
+ return -1;
+ opt.flags|=FLAG_QUIET;
+ break;
+ case 'u':
+ opt.flags|=FLAG_DUMP;
+ break;
+ case 'V':
+ opt.flags|=FLAG_VERSION;
+ break;
+ case '?':
+ switch(optopt)
+ {
+ case 's':
+ fprintf(stderr, "String keyword expected\n");
+ print_opt_string_list();
+ break;
+ }
+ return -1;
+ }
+
+ if((opt.flags & FLAG_DUMP) && opt.string!=NULL)
+ {
+ fprintf(stderr, "Options --string and --dump are mutually exclusive\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void print_help(void)
+{
+ static const char *help=
+ "Usage: vpddecode [OPTIONS]\n"
+ "Options are:\n"
+ " -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
+ " -h, --help Display this help text and exit\n"
+ " -s, --string KEYWORD Only display the value of the given VPD string\n"
+ " -u, --dump Do not decode the VPD records\n"
+ " -V, --version Display the version and exit\n";
+
+ printf("%s", help);
+}
diff --git a/vpdopt.h b/vpdopt.h
new file mode 100644
index 0000000..378766f
--- /dev/null
+++ b/vpdopt.h
@@ -0,0 +1,45 @@
+/*
+ * Command line handling of vpddecode
+ * This file is part of the dmidecode project.
+ *
+ * (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <sys/types.h>
+
+struct string_keyword
+{
+ const char *keyword;
+ off_t offset;
+ size_t len;
+};
+
+struct opt
+{
+ const char* devmem;
+ unsigned int flags;
+ const struct string_keyword *string;
+};
+extern struct opt opt;
+
+#define FLAG_VERSION (1<<0)
+#define FLAG_HELP (1<<1)
+#define FLAG_DUMP (1<<2)
+#define FLAG_QUIET (1<<3)
+
+int parse_command_line(int argc, char * const argv[]);
+void print_help(void);