Index: /lm-sensors/tags/V3-0-0-RC2/doc/lm_sensors-FAQ.texi
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/lm_sensors-FAQ.texi	(revision 4865)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/lm_sensors-FAQ.texi	(revision 4865)
@@ -0,0 +1,1616 @@
+\input texinfo.tex    @c -*-texinfo-*-
+
+@c %**start of header
+@setfilename lm_sensors-FAQ.info
+@include version.texi
+@settitle Sensors FAQ for lm_sensors version @value{VERSION}
+@comment %**end of header
+
+@titlepage
+@center @titlefont{This is the FAQ for the @command{lm_sensors} program, @value{VERSION}}
+@sp 3
+@center Copyright (C) 1998 - 2005
+@sp 1
+@center Frodo Looijaard,
+@center Philip Edelbrock,
+@center Mark D. Studebaker,
+@center and
+@center Jean Delvare
+@end titlepage
+
+@ifhtml
+Copyright (C) 1998 - 2005@*
+Frodo Looijaard,@*
+Philip Edelbrock,@*
+Mark D. Studebaker@*
+and@*
+Jean Delvare@*
+@end ifhtml
+
+@dircategory Utilities
+@direntry
+* lm_sensors-FAQ: (lm_sensors-FAQ)           The lm_sensors FAQ
+@end direntry
+
+@summarycontents
+@contents
+
+@ifnottex
+@node Top
+@top lm_sensors
+
+The lm_sensors package includes a collection of modules for general SMBus
+access and hardware monitoring.  NOTE: this requires special support which
+is not in standard 2.2-vintage kernels.
+
+@end ifnottex
+
+@menu
+* Overview::                PC and Sensor Overview
+* Basics::                  Sensor and Bus Basics
+* Installation::            Installation and Management
+* Problems::                Problems
+* Help::                    How to Ask for Help
+* Contribute::              How to Contribute
+* Document Revisions::      Revision History of This Document
+@end menu
+
+
+@node Overview, Basics, Top, Top
+@chapter PC and Sensor Overview
+
+@menu
+* Section 1.1::             What sensors are available on my PC? 
+* Section 1.2::             What can a sensor chip like the "LM78" do?
+* Section 1.3::             Where do I find out more about any of these chips?
+@end menu
+
+@node Section 1.1, Section 1.2, , Overview
+@section What sensors are available on my PC?
+
+Most PC's built since late 1997 now come with a
+hardware health monitoring chip. This chip may be accessed via the
+ISA bus or the SMBus, depending on the motherboard.
+
+Some motherboard chipsets, notably the Via 686 and the SiS 5595,
+contain hardware monitor functions.
+
+This FAQ frequently refers to the "LM78". This chip has been
+obsoleted by National Semiconductor. Most motherboards today contain
+a chip with similar functions.
+
+
+@node Section 1.2, Section 1.3, Section 1.1, Overview
+@section What can a sensor chip like the "LM78" do?
+
+The LM78 is a chip made by National Semiconductor which can monitor 7
+voltages (5 positive, 2 negative) from 0 to 4.08V.  The inputs are usually in
+series with voltage dividers which lower the +/- 12V and +/- 5V supplies to
+measurable range.  Therefore, the readings for such inputs need to be
+re-scaled appropriately by software.
+
+The LM78 also has 3 fan speed monitoring inputs, an internal
+temperature sensor, a chassis intrusion sensor, and a couple maskable interrupt
+inputs.  The LM78 can also relay the processor's (P6 or Pent II) VID lines
+which are hardwired and used to indicate to the power regulator (usually on
+the mainboard close to the processor socket/slot) what voltage to supply to
+the processor.
+
+The LM78 can be interfaced to a system via the ISA bus and/or the
+SMBus.
+
+Most other sensor chips have comparable functionality. Each supported
+chip is documented in the @file{doc/chips} directory.
+
+
+@node Section 1.3,  , Section 1.2, Overview
+@section Where do I find out more about any of these chips?
+
+Most semiconductor companies have comprehensive documentation,
+including complete datasheets, on their websites. Analog Devices,
+Dallas Semiconductor, Maxim, and National Semiconductor have the widest selection
+of sensor chips. Their websites are:
+
+@itemize @bullet
+  @item @uref{http://www.analog.com}
+  @item @uref{http://www.dalsemi.com}
+  @item @uref{http://www.maxim-ic.com}
+  @item @uref{http://www.national.com}
+@end itemize
+
+Please see the file @uref{http://www.lm-sensors.org/wiki/UsefulLinks}
+for links to other companies' websites.
+
+
+
+@node Basics, Installation, Overview, Top
+@chapter Sensor and Bus Basics
+
+@menu
+* Section 2.1::             What sensors are available on my PC? 
+* Section 2.2::             What can a sensor chip like the "LM78" do?
+* Section 2.3::             Where do I find out more about any of these chips?
+* Section 2.4::             What sensors are available on my PC? 
+* Section 2.5::             What can a sensor chip like the "LM78" do?
+* Section 2.6::             Where do I find out more about any of these chips?
+@end menu
+
+
+@node Section 2.1, Section 2.2, , Basics
+@section How are these sensors read?
+
+Sensor chips reside on either the ISA bus, the SMBus, or both.
+See the file @file{doc/chips/SUMMARY} in our package for a list.
+
+To communicate with chips on the ISA bus, the software uses
+simple I/O reads and writes.
+
+To communicate with chips on the SMBus, the software must
+use an SMBus interface device, explained below.
+
+
+@node Section 2.2, Section 2.3, Section 2.1, Basics
+@section What is the SMBus? And the I2C bus?
+
+The SMBus is the "System Management Bus".  More specifically, it is a
+2-wire, low-speed serial communication bus used for basic health monitoring
+and hardware management. It is a specific implementation of the more
+general I2C (pronunciation: I-squared-C) bus. In fact, both I2C devices
+and SMBus devices may be connected to the same (I2C) bus.
+
+The SMBus (or I2C bus) starts at the host controller, used for
+starting transactions on the SMBus.  From the host interface, the
+devices communicated with are the @dfn{slave} devices.  Each slave device has a
+unique 7-bit address which the host uses to refer to that device.
+
+For each supported SMBus host, there is a separate kernel module
+which implements the communication protocol with the host. Some SMBus hosts
+really operate on the SMBus level; these hosts can not cope with pure I2C
+devices. Other hosts are in fact I2C hosts: in this case, we implement
+the SMBus protocol in terms of I2C operations. But these hosts can also
+talk to pure I2C devices.
+
+
+@node Section 2.3, Section 2.4, Section 2.2, Basics
+@section I don't have an ISA bus!
+
+We promise, you do, even if you don't have any old ISA slots.
+The "ISA Bus" exists in your computer even if you don't have ISA slots;
+it is simply a memory-mapped area, 64KB in size (0x0000 - 0xFFFF)
+where many "legacy" functions, such as keyboard and interrupt controllers,
+are found. It isn't necessarily a separate physical bus.
+See the file @file{/proc/ioports} for a list of devices living on
+the "ISA Bus" in your system. If you don't like the term "ISA Bus"
+think "I/O Space".
+
+
+@node Section 2.4, Section 2.5, Section 2.3, Basics
+@section What sensors do processors have?
+
+Most new processors contain a thermal diode on the die itself.
+The electical properties of all diodes and transistors vary
+slightly with temperature. The thermal diode is exceptionally accurate
+because it is directly on the die. Newer temperature sensor chips,
+like the Analog Devices ADM1021 and clones, and the Winbond chips,
+have circuitry for measuring the the electrical properties of
+an external diode and converting this data to a temperature.
+Any sensor chip listed in @file{doc/chips/SUMMARY} in our package which
+has support for more than one temperature supports external temperature sensing.
+
+Older motherboards and processors without this feature generally use
+an LM75 placed close to the processor. This is much less accurate.
+
+The Pentium 2 'boxed' processor usually has an LM75 very close to the
+base of the box. It can be read through the SMBus to report the approximate
+temperature of the processor.  The processor also contains an internal
+temperature sensor (of low accuracy) used as a fail-safe to disable the
+processor in case it gets much too hot (usually around 130 degrees C).  And,
+the Pentium 2 also has a hard-wired signal (VID lines) on it's SEC (single
+edge connector) which indicates what power supply is required to operate the
+processor.
+
+The P6 (Pentium-Pro) may have an LM75 in or just under the socket.
+P6's also have VID lines.
+
+Pentiums and Pentium w/ MMX do not have VID lines, and sometimes have
+LM75's under the sockets (depends on the mainboard, and how 'modern' the
+mainboard is).
+
+The P2 Xeon was the first Intel processor to include the SMBus
+interface on the P2 Xeon SEC.
+
+
+@node Section 2.5, Section 2.6, Section 2.4, Basics
+@section How often are the sensor values updated?
+
+The LM78, and most other sensor chips like it, reads its sensors one
+by one. A complete scanning sweep will take about 1.5 seconds. The LM78 stops
+readings sensors if you try to access it, so if you access it very often
+(by reading sensor values; writing new limits is safe) it will not find the
+time to update its sensor values at all! Fortunately, the kernel module takes
+care not to do this, and only reads new values each 1.5 seconds. If you
+read the values again, you will get the 'old' values again.
+
+
+@node Section 2.6, , Section 2.5, Basics
+@section How are alarms triggered?
+
+It is possible to monitor each sensor and have an alarm go off if
+it crosses some pre-determined limits.  There are two sorts of interrupts
+which can be generated by sensor chips if this happens (it depends a bit on
+the actual chip if both are supported; the LM80, for example, has only
+IRQ interrupts): IRQ interrupts and SMI interrupts.  IRQ stands for
+Interrupt Request and are the interrupt lines you can find in @file{/proc/interrupts}.
+SMI stands for System Management Interrupt, and is a special interrupt which
+puts the processor in a secure environment independent of any other things
+running.  SMI is currently not supported by the Linux kernel.  IRQs are
+supported, of course.
+
+Even if no interrupt is generated, some bits in a status register
+will be set until the register is read the next time. If the alarm condition
+persists after that, the bits will be set on the next scanning sweep, etc.
+
+Most drivers in our package do not support interrupts at this time.
+
+
+
+@node Installation, Problems, Basics, Top
+@chapter Installation and Management
+
+@menu
+* Section 3.1::     Why so many modules, and how do I cope with them?
+* Section 3.2::     How do I know which chips I own?
+* Section 3.3::     Which modules should I insert?
+* Section 3.4::     Do I need the configuration file @file{/etc/sensors.conf}?
+* Section 3.5::     What about the @samp{No such file or directory} warnings
+* Section 3.6::     I get all kinds of weird compilation errors?
+* Section 3.7::     It still does not compile or patch!
+* Section 3.8::     @command{make install} fails on Mandrake kernels
+* Section 3.9::     I get unresolved symbols when I @command{modprobe} modules
+* Section 3.10::    I2C_DRIVERID_ADM1024 undefined (Red Hat especially)
+@end menu
+
+@node Section 3.1, Section 3.2, , Installation
+@section Why so many modules, and how do I cope with them?
+
+We tried to make this package as modular as possible. This makes it
+easy to add new drivers, and unused drivers will take no precious kernel
+space. On the other hand, it can be a bit confusing at first.
+
+Here are two simple guidelines:
+@itemize
+  @item Run @command{sensors-detect} and do what it tells you.
+  @item Always use @command{modprobe}, not @command{insmod}.
+@end itemize
+
+Further information is in @file{doc/modules}.
+
+
+@anchor{How do I know which chips I own}
+@node Section 3.2, Section 3.3, Section 3.1, Installation
+@section How do I know which chips I own?
+
+We have an excellent program that scans all your hardware.
+It is called @file{sensors-detect} and is installed in @file{/usr/local/sbin}
+by @command{make install}. Just execute this script, and it will tell you.
+
+Chip detection in the drivers is fairly good. That means that it is
+usually harmless to insert more chip drivers than you need. However, this
+can still lead to problems, so we do not recommend it.
+
+If sensors-detect didn't find any sensors, either you don't have
+any, or the ones you have, we don't support. (Look at your motherboard
+for candidates, then @pxref{Help})
+
+
+@anchor{Section 3.2.1}
+@subsection What chips are on motherboard XYZ?
+
+    @strong{!!!!!!!!! YES THIS IS THE MOST FREQUENT QUESTION WE GET !!!!!!!!!}
+
+We have no idea. Here is what you should do:
+@enumerate
+  @item Run sensors-detect.
+@end enumerate
+
+If that doesn't work:
+@enumerate 2
+@item Look at your motherboard.
+@item Check the manufacturer's website or ask their support
+@item Check the
+@uref{http://www.lm-sensors.org/wiki/UsefulLinks, "links"}
+page on @uref{http://www.lm-sensors.org, our website} some good cross-references.
+@end enumerate
+
+
+@anchor{Section 3.2.2}
+@subsection Do you support motherboard XYZ?
+
+We don't support boards, we support chips. @xref{Section 3.2.1, What chips are on motherboard XYZ}.
+
+
+@anchor{Section 3.2.3}
+@subsection Do you support chip XYZ?
+
+This we have good answers for.
+@itemize
+@item Sorted by Manufacturer:   @file{README}
+@item Sorted by Manufacturer:   @uref{http://www.lm-sensors.org/wiki/Devices}
+@item Sorted by Sensor Driver:  @file{doc/chips/SUMMARY}
+@end itemize
+
+
+@anchor{Section 3.2.4}
+@subsection Anybody working on a driver for chip XYZ?
+
+Newest Driver Status: @uref{http://www.lm-sensors.org/wiki/Devices}
+
+
+@node Section 3.3, Section 3.4, Section 3.2, Installation
+@section Which modules should I insert?
+
+@command{sensors-detect} will tell you. Take the @command{modprobe} lines it
+recommends and paste them into the appropriate @file{/etc/rc.d/xxxx} file
+to be executed at startup.
+
+You need one module for each sensor chip and bus adapter you own;
+if there are sensor chips on the ISA bus, you also need @file{i2c-isa.o}.
+for each type of chip you own. That's all. On my computer, I could use the
+following lines:
+@itemize
+@item @command{modprobe i2c-isa}
+@item @command{modprobe i2c-piix4}
+@item @command{modprobe lm78}
+@item @command{modprobe lm75}
+@item @command{modprobe i2c-dev}
+@item @command{sensors -s}
+@end itemize
+
+
+@node Section 3.4, Section 3.5, Section 3.3, Installation
+@section Do I need the configuration file @file{/etc/sensors.conf}?
+
+Yes, for any applications that use @file{libsensors,} including the
+@command{sensors} application included in our package.
+It tells libsensors how to translate the values the chip
+measures to real-world values. This is especially important for voltage
+inputs. The default configuration file should usually do the trick.
+It is automatically installed as @file{/etc/sensors.conf}, but it will not
+overwrite any existing file with that name.
+
+
+@anchor{Section 3.4.1}
+@subsection The labels for the voltage and temperature readings in @command{sensors} are incorrect!
+
+Every motherboard is different. You can customize the labels
+in the file @file{/etc/sensors.conf}. That's why it exists!
+The default labelling (in @file{lib/chips.c} and @file{/etc/sensors.conf}) is just
+a template.
+
+
+@anchor{Section 3.4.2}
+@subsection The min and max for the readings in @command{sensors} are incorrect!
+
+You can customize them in the file @file{/etc/sensors.conf}. See above.
+
+
+@anchor{Section 3.4.3}
+@subsection The min and max settings in @file{/etc/sensors.conf} didn't take effect!
+
+You forgot to run @command{sensors -s}. See above.
+
+
+@anchor{Section 3.4.4}
+@subsection One sensor isn't hooked up on my board!
+
+Use an @command{ignore} line in @file{/etc/sensors.conf} so it isn't
+displayed in @command{sensors}.
+
+
+@anchor{Section 3.4.5}
+@subsection I need help with @file{sensors.conf}!
+
+There is detailed help at the top of that file.
+
+
+@anchor{Section 3.4.6}
+@subsection Do you have a database of @file{sensors.conf} entries for specific boards?
+
+No. Good idea though. If you would like to set one up on your website
+send us mail and we will set up a link to it.
+
+
+@node Section 3.5, Section 3.6, Section 3.4, Installation
+@section What about the @samp{No such file or directory} warnings when I compile?
+
+Don't worry about them. The dependency files (which tell which
+files should be recompiled when certain files change) are created
+dynamically. They are not distributed with the package. The @command{make} program
+notices they are not there, and warns about that - and the first thing
+it will do is generate them. So all is well.
+
+
+@node Section 3.6, Section 3.7, Section 3.5, Installation
+@section I get all kinds of weird compilation errors?
+
+Check that the correct i2c header files are used. Depending on
+how you installed, they should be under either @file{/usr/local/include} or
+@file{/usr/src/linux*/include}. Try to edit the @file{Makefile} for the other setting.
+
+
+@anchor{Section 3.6.1}
+@subsection @samp{No rule to make target xxxx needed by xxxx} - how to fix?
+
+@itemize
+@item @xref{Section 3.6, I get all kinds of weird compilation errors}, also try @command{make clean} in @file{lm_sensors}.
+@item If that doesn't work, try @command{make clean} in @file{i2c}.
+@item If that doesn't work, try @command{make clean} in the kernel.
+@item Also make sure @file{/usr/include/linux} points to @file{/usr/src/linux/include/linux}.
+@end itemize
+
+
+@node Section 3.7, Section 3.8, Section 3.6, Installation
+@section It still does not compile or patch!
+
+Have you installed the matching version of the i2c package? Remember,
+compilation is not enough, you also need to install it for the header
+files to be found!
+
+If you want to patch the kernel, you will have to apply the i2c
+patches first!
+
+
+@node Section 3.8, Section 3.9, Section 3.7, Installation
+@section @command{make install} fails on Mandrake kernels
+
+Mandrake uses a non-standard @file{version.h} file which confuses our @file{Makefile}.
+Edit our @file{Makefile} on the @code{MODDIR :=} line to hard-code the module directory.
+
+
+@node Section 3.9, Section 3.10, Section 3.8, Installation
+@section I get unresolved symbols when I @command{modprobe} modules (Red Hat especially)
+
+Example:
+@example
+*** Unresolved symbols in /lib/modules/2.4.5/kernel/drivers/i2c/i2c-i810.o
+i2c_bit_add_bus_R8c3bc60e
+i2c_bit_del_bus_R92b18f49
+@end example
+
+You can also run @command{depmod -a -e} to see all unresolved symbols.
+
+
+These are module versioning problems. Generally you did not compile
+against the kernel you are running. Sometimes the Red Hat source you
+have is not for the kernel you are running.
+You must compile our package against the source for the kernel you
+are running with something like @command{make LINUX=/usr/src/linux-2.4.14}.
+
+
+Try the following to be sure:
+
+@itemize
+@item @command{nm --extern MODULE.o}
+Filter out the kernel symbols, like @code{kmalloc}, @code{printk} etc. and note the
+number code behind them, like @code{printk_R1b7d4074}. If there is no numeric
+code after them, note this too.
+@item @command{grep SYMBOL /proc/ksyms}
+Substitute SYMBOL by the basename of the symbols above, like @code{kmalloc},
+@code{printk} etc. Note the number code behind them, or the lack thereof.
+@item Compare both sets of symbols. Are they the same? If so, the problem
+lies somewhere else. Are they different? If so, you have a module
+versioning problem.
+@end itemize
+
+
+@node Section 3.10, , Section 3.9, Installation
+@section I2C_DRIVERID_ADM1024 undefined (Red Hat especially)
+
+In some versions of Redhat, an RPM is included to provide i2c support.
+However, this RPM does not place the header files in the kernel directory
+structure.  When you update kernels, they may persist.  To get rid of
+these obsolete header files, at a command prompt:
+
+@enumerate
+@item @command{rpm -qa | grep i2c}
+@item Look for @file{kernel-i2c,} or a similar rpm in the output
+@item <as root>
+@command{rpm -ev kernel-i2c} (or the name of the similar package)
+If this complains about dependencies, you can try adding
+@command{--nodeps}, but this *MAY* break something else.  Not likely,
+as you have upgraded kernels, and nothing should be using the
+old i2c stuff anymore anyway.  Just don't use it with abandon.
+@item Try (in the build directory of @file{lm_sensors)}
+@example
+@command{make clean}
+@command{make}
+@end example
+@item @emph{If} you still have problems, you may have to replace the include
+paths in the @file{.c/.h} files with absolute paths to the header files.
+More of a workaround than a real fix, but at least you can get it
+to work.
+@end enumerate
+
+
+@node Problems, Help, Installation, Top
+@chapter Problems
+
+@menu
+* Section 4.1::         My fans report exactly half/double their values?
+* Section 4.2::         Why do my two LM75's report "-48 degrees"?
+* Section 4.3::         Why do I have two Vcore readings?
+* Section 4.4::         How do those ALARMS work?
+* Section 4.5::         My voltage readings seem to drift a bit. What's wrong?
+* Section 4.6::         Some measurements are way out of range. What happened?
+* Section 4.7::         What are VID lines? Why is the VID reading wrong?
+* Section 4.8::         Sensor are only updated each second or so. Why?
+* Section 4.9::         It takes a second before reading sensor results. Why?
+* Section 4.10::        Can I be alerted when an ALARM occurs?
+* Section 4.11::        SMBus transactions on my PIIX4 simply don't work. Why?
+* Section 4.12::        My BIOS reports a higher CPU temperature than you!
+* Section 4.13::        I read strange values from the raw @file{/proc} files!
+* Section 4.14::        How do I set new limits?
+* Section 4.15::        Some sensors are doubly detected?
+* Section 4.16::        I ran sensors-detect, but now I get strange readings?!
+* Section 4.17::        Bad readings from particular chips
+* Section 4.18::        How do I configure two chips (LM87) differently?
+* Section 4.19::        Dmesg says @samp{Upgrade BIOS}! I don't want to!
+* Section 4.20::        Sensors says @samp{Can't access procfs/sysfs file}
+* Section 4.21::        Sensors says @samp{No sensors found!}
+* Section 4.22::        Sensors output is not correct!
+* Section 4.23::        What is at I2C address XXX?
+* Section 4.24::        Sensors-detect doesn't work at all
+* Section 4.25::        Sensors says @samp{Error: Line xxx: zzzzzzz}
+* Section 4.26::        Sensors only gives the name and adapter!
+* Section 4.27::        Sensors says @samp{ERROR: Can't get xxxxx data!}
+* Section 4.28::        Sensors doesn't find any sensors, just eeproms.
+* Section 4.29::        Inserting modules hangs my board
+* Section 4.30::        Inserting modules slows down my board
+* Section 4.31::        Problems on particular motherboards
+* Section 4.32::        Problems on 2.6 kernels
+@end menu
+
+
+@node Section 4.1, Section 4.2, , Problems
+@section My fans report exactly half/double their values compared to the BIOS?
+
+The problem with much of the sensor data is that it is impossible to
+properly interpret some of the readings without knowing what the hardware
+configuration is.  Some fans report one 'tick' each rotation, some report
+two 'ticks' each rotation. It is easy to resolve this through the
+configuration file @file{/etc/sensors.conf}:
+
+@example
+chip lm78-*             # Or whatever chip this relates to
+compute fan1 2*@@,@@/2    # This will double the fan1 reading
+                        # -- or --
+compute fan1 @@/2,2*@@    # This will halve the fan1 reading
+@end example
+
+See @file{doc/fan-divisors} in our package for further information.
+
+
+@anchor{Fans sometimes/always read 0!}
+@subsection Fans sometimes/always read 0!!
+
+You may not have a three-wire fan, which is required.
+
+You may need to increase the 'fan divisor'. See @file{doc/fan-divisors}
+in our package for further information.
+
+
+@anchor{I doubled the fan divisor and the fan still reads 7000}
+@subsection I doubled the fan divisor and the fan still reads 7000!
+
+Believe it or not, doubling the 'fan divisor' will not halve
+the fan reading. You have to add a compute line in @file{/etc/sensors.conf}.
+@xref{Section 4.1, My fans report exactly half/double their values compared to the BIOS},
+and see @file{doc/fan-divisors} in our package for further information.
+
+
+@node Section 4.2, Section 4.3, Section 4.1, Problems
+@section Why do my two LM75's report "-48 degrees"?
+
+For starters, those aren't LM75's.  Your mainboard actually has the
+Winbond W83781D which emulates two LM75's, but many systems which use the
+Winbond chip (such as the Asus P2B) don't have the thermo-resisters connected
+to the chip resulting in these strange -48 degree readings.
+
+In upcoming versions, you will be able to disable non-interesting
+readings.
+
+
+@node Section 4.3, Section 4.4, Section 4.2, Problems
+@section Why do I have two Vcore readings, I have only one processor!
+
+The LM78 has seven voltage sensors. The default way of
+connecting them is used in the configuration file. This includes a VCore2,
+even if you do not have one. You can easily edit the configuration file
+to give it another name, or make this reading disappear using
+an @command{ignore} line.
+
+Note that Vcore2 is often the same as Vcore on motherboards which
+only support one processor. Another possibility is that Vcore2 is not
+connected at all and will not have a valid reading at all.
+A third possibility, is that Vcore2 monitors something
+else, so you should not be too surprised if the values are completely
+different.
+
+
+@node Section 4.4, Section 4.5, Section 4.3, Problems
+@section How do those ALARMS work? The current value is within range but there is still an ALARM warning!
+
+The ALARM indications in @command{sensors} are those reported by the
+sensor chip itself. They are NOT calculated by @command{sensors}. @command{sensors}
+simply reads the ALARM bits and reports them.
+
+An ALARM will go off when a minimum or maximum limit is crossed.
+The ALARM is then latched - that is, it will stay there until the
+chip's registers are next accessed - which will be the next time
+you read these values, but not within (usually) 1.5 seconds since the last
+update.
+
+Reading the registers clears the ALARMS, unless the current
+value is still out of range.
+
+The purpose of this scheme is to tell you if there has been
+a problem and report it to the user. Voltage or temperature spikes
+get detected without having to read the sensor chip hundreds of times
+a second. The implemetation details depend a bit on the kind of chip.
+See the specific chip documentation in @file{doc/chips} and the
+chip datasheet for more information.
+
+
+@node Section 4.5, Section 4.6, Section 4.4, Problems
+@section My voltage readings seem to drift a bit. Is something wrong?
+
+No, probably not. If your motherboard heats up a bit, the sensed
+voltages will drift a bit. If your power supply is loaded (because a disk
+gets going, for example), the voltages may get a bit lower. Heavy
+processor activity, in particular, dramatically increases core voltage
+supply load which will often cause variation in the other supplies.
+As long as they stay within a sensible range (say 5% of the nominal value
+for CPU core voltages, and 10% for other voltages), there is no
+reason to worry.
+
+
+@node Section 4.6, Section 4.7, Section 4.5, Problems
+@section Some measurements are way out of range. What happened?
+
+Each module tries to set limits to sensible values on initialization,
+but a module does not know how a chip is actually connected. This is
+described in the configuration file, which is not read by kernel modules.
+So limits can be strange, if the chip is connected in a non-standard way.
+
+Readings can also be strange; there are several reasons for this.
+Temperature sensors, for example, can simply not be present, even though
+the chip supports them. Also, it can be that the input is used in a
+non-standard way. You can use the configuration file to describe how this
+measurement should be interpreted; see the comments the example file for
+more information.
+
+@anchor{-5V and -12V readings are way out of range!}
+@subsection -5V and -12V readings are way out of range!
+
+It's very frequent that negative voltage lines are not wired because
+motherboard manufacturers don't think they're worth monitoring
+(they are mostly unused these days). You can just add
+@command{ignore inN} lines to @file{/etc/sensors.conf} to hide them.
+
+Another possibility is that these lines are used to monitor different
+voltages. Only the motherboard manufacturer can tell for sure. Taking
+a look at what voltage values the BIOS displays may provide valuable
+hints though.
+
+
+@node Section 4.7, Section 4.8, Section 4.6, Problems
+@section What are VID lines? Why is the VID reading wrong?
+
+These describe the core voltage for your processor. They are
+supported for most processors, however they are not always
+correctly connected to the sensor chip, so the readings may be invalid.
+A reading of 0V, +3.5V or +2.05V is especially suspect.
+If this is the case, add a line @command{ignore vid} to @file{/etc/sensors.conf},
+and change the min and max settings for the Processor Core voltage
+(often in0_min and in0_max) in that file so that they don't depend on vid.
+
+The CPU nominal voltage is computed from VID lines according to a formula
+that depends on the CPU type. Since Linux 2.6.9, the right formula is
+selected automatically.
+See @file{doc/vid} for more information.
+
+
+@node Section 4.8, Section 4.9, Section 4.7, Problems
+@section I read sensor values several times a second, but they are only updated only each second or so. Why?
+
+If we would read the registers more often, it would not find the
+time to update them. So we only update our readings once each 1.5 seconds
+(the actual delay is chip-specific; for some chips, it may not be needed
+at all).
+
+
+@node Section 4.9, Section 4.10, Section 4.8, Problems
+@section It sometimes seems to take almost a second before I see the sensor reading results. Why?
+
+ISA bus access is fast, but SMBus access is really slow. If you have
+a lot of sensors, it just takes a lot of time to access them. Fortunately,
+this has almost no impact on the system as a whole, as another job can run
+while we are waiting for the transaction to finish.
+
+
+@node Section 4.10, Section 4.11, Section 4.9, Problems
+@section Can I be alerted when an ALARM occurs?
+
+No, you can't; and it may well be never supported.
+
+Almost no mainboard we have encountered have actually connected the
+IRQ-out pin of sensor chips. That means that we could enable IRQ reporting, but
+nothing would happen. Also, even if a motherboard has it connected, it is
+unclear what interrupt number would be triggered. And IRQ lines are a scarce
+facility, which means that almost nobody would be able to use it anyway.
+
+The SMI interrupt is only available on a few types of chips. It is
+really a very obscure way to handle interrupts, and supporting it under Linux
+might be quite hard to do.
+
+Your best bet would be to poll the alarm file with a user-land daemon
+which alerts you if an alarm is raised. I am not aware of any program which
+does the job, though you might want to examine one of the graphical monitor
+programs under X, see @uref{http://www.lm-sensors.org/wiki/UsefulLinks} for addresses.
+
+
+@node Section 4.11, Section 4.12, Section 4.10, Problems
+@section SMBus transactions on my PIIX4 simply don't work (timeouts happen).  Why?
+
+Some chips which mainboard makers connect to the SMBus are not SMBus
+devices.  An example is the 91xx clock generator chips.  When read, these
+devices can lock up the SMBus until the next hard reboot.  This is because
+they have a similar serial interface (like the I2C), but don't conform to
+Intel's SMBus standard.
+
+Why did they connect these devices to the SMBus if they aren't
+compatible?  Good question! :')  Actually, these devices may support being
+written to, but lock things up when they are read.
+
+
+@node Section 4.12, Section 4.13, Section 4.11, Problems
+@section My BIOS reports a much higher CPU temperature than your modules!
+
+We display the actual temperature of the sensor. This may not be the
+temperature you are interested in, though.  If a sensor should measure
+the CPU temperature, it must be in thermal contact with it.  In practice,
+it may be just somewhere nearby. Your BIOS may correct for this (by adding,
+for example, thirty degrees to the measured temperature).  The correction
+factor is regrettably different for each mainboard, so we can not do this
+in the module itself. You can do it through the configuration file, though:
+
+@example
+chip lm75-*-49                      # Or whatever chip this relates to
+label temp "Processor"
+compute temp @@*1.2+13,(@@-13)/1.2    # Or whatever formula
+@end example
+
+However, the offset you are introducing might not be necessary. If you
+tried to have Linux idle temperature and BIOS "idle" temperature match,
+you may be misguided.
+We have a Supermicro (370DLE) motherboard and we know
+that its BIOS has a closed, almost undelayed while(1) loop that
+keeps the CPU busy all the time. Linux reads 26 degrees idle, BIOS reads
+38 degrees. Linux at full load is in the 35-40 degrees range so this
+makes sense.
+
+@node Section 4.13, Section 4.14, Section 4.12, Problems
+@section I try to read the raw @file{/proc} files, but the values are strange?!?
+
+Remember, these values do not take the configuration file
+@file{compute} lines in account. This is especially obvious for voltage readings
+(usually called in? or vin?). Use a program linked to libsensors (like
+the provided @command{sensors} program) instead.
+
+
+@node Section 4.14, Section 4.15, Section 4.13, Problems
+@section How do I set new limits?
+
+Change the limit values in @file{/etc/sensors.conf} and then run
+@command{sensors -s}.
+
+
+@anchor{I set new limits and it didnt work}
+@subsection  I set new limits and it didn't work?
+
+You forgot to run @command{sensors -s}. Put it in a @file{/etc/rc.d/...} file
+after the modprobe lines to run at startup.
+
+
+@node Section 4.15, Section 4.16, Section 4.14, Problems
+@section Some sensors are doubly detected?
+
+Yes, this is still a problem. It is partially solved by alias detection
+and confidence values in sensors-detect, but it is really tough.
+
+Double detections can be caused by two things:
+sensors can be detected to both the ISA and the SMBus (and if you have
+loaded the approprate adapter drivers, it will be detected on both), and
+some chips simulate other chips (the Winbond W83781D simulates LM75 chips
+on the SMBus, for example). Remove the offending adapter or chip driver, or
+run sensors-detect and add the @command{ignore=} modprobe parameters it suggests.
+
+
+@node Section 4.16, Section 4.17, Section 4.15, Problems
+@section I ran sensors-detect, but now I get very strange readings?!?
+
+Your SMBus (PIIX4?) is probably crashed or hung. There are some mainboards
+which connect a clock chip to the SMBus. Unfortunately, this clock chip
+hangs the PIIX4 if it is read (it is an I2C device, but not SMBus compatible).
+We have found no way of solving this, except for rebooting your computer.
+Next time when you run sensors-detect, you may want to exclude addresses
+0x69 and/or 0x6a, by entering @kbd{s} when you are asked whether you want to
+scan the PIIX4.
+
+
+@node Section 4.17, Section 4.18, Section 4.16, Problems
+@section Bad readings from particular chips
+
+See below for some particularly troublesome chips.
+Also be sure and check @file{doc/chips/xxxxx} for the particular driver.
+
+
+@anchor{Bad readings from the AS99127F}
+@subsection Bad readings from the AS99127F!
+
+The Asus AS99127F is a modified version of the Winbond W83781D.
+Asus will not release a datasheet. The driver was developed by tedious
+experimentation. We've done the best we can. If you want to make adjustments
+to the readings please edit @file{/etc/sensors.conf.} Please don't ask us to
+fix the driver. Ask Asus to release a datasheet.
+
+
+@anchor{Bad readings from the VIA 686A}
+@subsection Bad readings from the VIA 686A!
+
+The Via 686A datasheet is incomplete.
+Via will not release details. The driver was developed by tedious
+experimentation. We've done the best we can. If you want to make adjustments
+to the readings please edit @file{/etc/sensors.conf.} Please don't ask us to
+fix the driver. Ask Via to release a better datasheet.
+Also, don't forget to @command{modprobe i2c-isa}.
+
+
+@anchor{Bad readings from the MTP008}
+@subsection Bad readings from the MTP008!
+
+The MTP008 has programmable temperature sensor types.
+If your sensor type does not match the default, you will have to change it.
+See @file{doc/chips/mtp008} for details.
+Also, MTP008 chips seem to randomly refuse to respond, for
+unknown reasons. You can see this as 'XX' entries in i2cdump.
+
+
+@anchor{Bad temperature readings from the SIS5595}
+@subsection Bad temperature readings from the SIS5595!
+
+This chip can use multiple thermistor types and there are also
+two different versions of the chip. We are trying to get the driver
+working better and develop formulas for different thermistors
+but we aren't there yet. Sorry.
+Also, many times the chip isn't really a sis5595 but it was
+misidentified. We are working on improving that too.
+
+
+@anchor{Bad readings from a w8378[12]d}
+@subsection Bad readings from a w8378[12]d!
+
+Do you own an ASUS motherboard?  Perhaps your chip is being
+misidentified.  Look on the motherboard for a 'Winbond' or Asus chip.
+Often the real device is an Asus as99127f. If so, the driver can be
+forced to recognize the as99127f with
+@command{force_as99127f=BUS,0x2d} where @code{BUS} is your i2c bus number.
+Cat /proc/bus/i2c to see a list of bus numbers.
+Read the w83781d module documentation (@file{doc/chips/w83781d})
+for more details.
+
+
+@anchor{Bus hangs on Ali 1543 on Asus P5A boards}
+@subsection Bus hangs on Ali 1543 on Asus P5A boards!
+
+The SMBus tends to hang on this board and it seems to get worse
+at higher temperatures. Use ISA accesses to reliably use the w83781d
+monitor chip on this board and use the @command{ignore=1,0x2d} or similar option
+to the w83781d module to prevent i2c accesses.
+
+
+@anchor{Bad readings from LM75}
+@subsection Bad readings from LM75!
+
+The LM75 detection is poor and other hardware is often misdetected
+as an LM75. Figure out what you really have @xref{Section 3.2.1, What chips are on motherboard XYZ}.
+
+
+@anchor{Bad readings from LM78}
+@subsection Bad readings from LM78!
+
+The LM78 is no longer manufactured by National Semiconductor.
+You probably don't have a real LM78 but something similar that we
+do not recogize or support. Figure out what you really have @xref{Section 3.2.1, What chips are on motherboard XYZ}.
+
+
+@anchor{Bad readings from LM80}
+@subsection Bad readings from LM80!
+
+The LM80 detection is poor and other hardware is often misdetected
+as an LM80. Figure out what you really have @xref{Section 3.2.1, What chips are on motherboard XYZ}.
+
+
+@node Section 4.18, Section 4.19, Section 4.17, Problems
+@section How do I configure two chips (LM87) differently?
+
+There is a SuperMicro board with two LM87's on it that are
+not hooked up in the same way, so they need different defaults.
+For example, both CPU temperatures go to one LM87.
+
+Make two different sections in @file{/etc/sensors.conf} as follows:
+@example
+chip "lm87-i2c-*-2c"
+    put configuration for the chip at 0x2c here
+chip "lm87-i2c-*-2d"
+    put configuration for the chip at 0x2d here
+@end example
+
+There is a commented example in @file{sensors.conf.eg} which should
+be helpful.
+
+
+@node Section 4.19, Section 4.20, Section 4.18, Problems
+@section Dmesg says @samp{Upgrade BIOS}! I don't want to!
+
+If the problem is a PCI device is not present in @command{lspci}, the solution
+is complex. For the ALI M7101 device, there is a solution which uses the
+2.4 kernel's @command{hotplug} facility. See @file{prog/hotplug} in our package.
+For other PCI devices, you can try to modify
+the m7101 solution in @file{prog/hotplug}.
+
+
+If dmesg says @samp{try force_addr}, see below. Other drivers generally do not
+support the force_addr parameter. Sorry. Check the documentation
+for your driver in @file{doc/[chips,busses]} and if we don't support it
+you can send us your request.
+
+
+@anchor{Dmesg says use force_addr=0xaddr! What address do I use}
+@subsection Dmesg says @samp{use force_addr=0xaddr}! What address do I use?
+
+If the problem is a PCI device whose base address is not set,
+you may be able to set the address with a force parameter. The via686a
+and sis5595 chip drivers, and some bus drivers, support the command line
+@command{modprobe via686a force_addr=0xADDRESS} where ADDRESS
+is the I/O address. You must select an address that is not in use.
+@command{cat @file{/proc/ioports}} to check (carefully) for conflicts. A high number like
+0xf000 is generally safe.
+
+
+@node Section 4.20, Section 4.21, Section 4.19, Problems
+@section Sensors says @samp{Can't access procfs/sysfs file}
+
+@itemize
+@item Linux 2.6
+@itemize 
+@item Did you @command{modprobe i2c_sensor}? Check @command{lsmod}.
+@item Do you have sysfs support in your kernel and @file{/sys} mounted (is @file{/sys} there and populated)?
+Create /sys with @command{mkdir /sys} if needed. Then add the following line to @file{/etc/fstab}:
+@example
+sys              /sys             sysfs       default          0   0@end example
+and @command{mount /sys}.
+@end itemize
+@item Linux 2.4
+@itemize
+@item Did you @command{modprobe i2c-proc}? Check @command{lsmod}.
+@item Do you have procfs support in your kernel and @file{/proc} mounted (is @file{/proc} there and populated)?
+Create /proc with @command{mkdir /proc} if needed. Then add the following line to @file{/etc/fstab}:
+@example
+proc             /proc            proc        defaults         0   0@end example
+and @command{mount /proc}.
+@end itemize
+@item If you did @command{sensors -s}, did you run it as root?
+@end itemize
+
+
+@node Section 4.21, Section 4.22, Section 4.20, Problems
+@section Sensors says @samp{No sensors found!}
+
+@itemize
+@item Did @command{sensors-detect} find sensors? (If not @pxref{Sensors-detect doesnt find any sensors})
+@item Did you do what @command{sensors-detect} said?
+@item Did you @command{modprobe} your sensor modules?
+@item Did you @command{modprobe} your I2C adapter modules?
+@item Did you @command{modprobe i2c-isa} if you have ISA sensor chips?
+@item Check @command{lsmod}.
+@end itemize
+
+
+@node Section 4.22, Section 4.23, Section 4.21, Problems
+@section Sensors output is not correct!
+
+    What specifically is the trouble?
+@itemize
+@item Labels: @xref{Section 3.4.1, The labels for the voltage and temperature readings in sensors are incorrect}.
+@item Min/max readings: @xref{Section 3.4.2, The min and max for the readings in sensors are incorrect}, and @xref{Section 3.4.3, The min and max settings didnt take effect}.
+@item AS99127F: @xref{Section 4.16, I ran sensors-detect but now I get very strange readings?}.
+@item Via 686A: @xref{Section 4.16, I ran sensors-detect but now I get very strange readings?}.
+@item Other specific chips: @xref{Section 4.16, I ran sensors-detect but now I get very strange readings?}.
+@item No output for a particular sensors chip: @xref{Section 5.3, What to do if it inserts but nothing happens}.
+@item No output at all: @xref{Section 4.21, Sensors says No sensors found}, @xref{Section 5.3, What to do if it inserts but nothing happens}.
+@item Completely bad output for a particular sensor chip: @xref{Section 5.4, What to do if I read only bogus information}.
+@item One particular sensor readings:
+@itemize
+@item Maybe it isn't hooked up? - tell 'sensors' to ignore it. @xref{Section 3.4.4, One sensor isnt hooked up on my board}.
+@item Maybe it is hooked up differently on your motherboard? - adjust @file{sensors.conf} calculation.
+@end itemize
+@end itemize
+
+@node Section 4.23, Section 4.24, Section 4.22, Problems
+@section What is at I2C address XXX?
+
+In general, we don't know. Start by running @command{sensors-detect}.
+If it doesn't recognize it, try running @command{i2cdump}. A partial list
+of manufacturers' IDs are at the bottom of @file{doc/chips/SUMMARY}.
+
+
+@anchor{What is at I2C address 0x69}
+@subsection What is at I2C address 0x69?
+
+A clock chip. Often, accessing these clock chips in the wrong
+way will instantly crash your computer. Sensors-detect carefully
+avoids these chips, and you should do too.  You have been warned.
+
+
+@anchor{What is at I2C addresses 0x50 - 0x57}
+@subsection What is at I2C addresses 0x50 - 0x57?
+
+EEPROMs on your SDRAM DIMMs. Load the eeprom module and use the script
+@command{decode-dimms.pl} (in the i2c-tools package)
+to get more information than you ever wanted.
+
+
+@anchor{What is at I2C addresses 0x30 - 0x37}
+@subsection What is at I2C addresses 0x30 - 0x37?
+
+These are often 'shadows' of your EEPROMs on your SDRAM DIMMs
+at addresses 0x50 - 0x57. They are the 'software write-protect'
+registers of the SDRAM Serial Presence Detect EEPROMs.
+If you try and
+do a @command{i2cdump} on them to read the location, you won't get anything,
+because they contain a single write-only register.
+This register can be used to permanently
+write-protect the contents of the eeprom.
+
+
+@node Section 4.24, Section 4.25, Section 4.23, Problems
+@section Sensors-detect doesn't work at all
+
+It could be many things. What was the problem? @xref{Section 4.31, Problems on particular motherboards}.
+
+
+@anchor{Sensors-detect says "Couldnt open /proc/bus/i2c?!?"}
+@subsection Sensors-detect says "Couldn't open /proc/bus/i2c?!?"
+
+You don't have i2c support in your kernel, or the i2c-core module
+was not loaded and you did not run sensors-detect as root.
+
+
+@anchor{Sensors-detect says "Cant open /dev/i2c[-/]0"}
+@subsection Sensors-detect says "Can't open /dev/i2c[-/]0"
+
+Your @file{/dev/i2c-0,} @file{/dev/i2c0}, or @file{/dev/i2c/0} files do not exist
+or you did not run @command{sensors-detect} as root.
+Use @command{MAKEDEV} or @command{mknod} to create the @file{/dev/i2c-x} files.
+Run @command{devfs} in the kernel to get the @file{/dev/i2c/x} files.
+
+
+@anchor{Sensors-detect doesnt find any sensors}
+@subsection Sensors-detect doesn't find any sensors!
+
+Either
+@enumerate
+@item The board doesn't have any sensors.
+@item We don't support the sensors on the board.
+@item The sensors it has are on an I2C bus connected to an I2C bus adapter that we don't support.
+@item You don't have the latest version of lm_sensors.
+@end enumerate
+
+But in any case you should figure out what is on the board:
+@enumerate
+@item Look at your motherboard.
+@item Check the manufacturer's website.
+@end enumerate
+
+When you know what chips you have, check the
+@uref{http://www.lm-sensors.org/wiki/Devices, Driver Status} web page to
+see if support has been added for your chip in a later release or in SVN.
+
+
+@node Section 4.25, Section 4.26, Section 4.24, Problems
+@section Sensors says @samp{Error: Line xxx: zzzzzzz}
+
+These are errors from the libsensors library in
+reading the @file{/etc/sensors.conf} configuration file. Go to that line
+number and fix it. If you have a parse error, perhaps you have
+to put the feature name in double quotes.
+
+
+@node Section 4.26, Section 4.27, Section 4.25, Problems
+@section Sensors only gives the name and adapter for my chip
+
+If @command{sensors} only says this, for example, and doesn't
+provide any actual data at all:
+
+@example
+it87-isa-0290
+Adapter: ISA adapter
+@end example
+
+Your chip is not currently supported by @command{sensors} and so all it
+does is print out that information. Get the latest release
+and be sure you are running the @command{sensors} program it installed
+and not some older @command{sensors}.
+
+
+@node Section 4.27, Section 4.28, Section 4.26, Problems
+@section Sensors says @samp{ERROR: Can't get xxxxx data!}
+
+@itemize
+@item (Linux 2.6) Make sure you are using one of the
+@uref{http://www.lm-sensors.org/wiki/Kernel2.6,
+recommended kernel/lm_sensors combination}.
+@item You have a @file{libsensors}/@command{sensors} mismatch.
+@command{sensors} is unable to
+get a data entry from @file{libsensors}. You probably have an
+old @file{libsensors} in your @file{/etc/ld.so.conf} path.
+Make sure you did (as root) a @command{make install} (Linux 2.4) or
+@command{make user_install} (Linux 2.6) followed by a @command{ldconfig}.
+Then check the output of @command{ldconfig -v | grep libsensors} to
+verify that there is only ONE @file{libsensors} entry and that it matches
+the @file{libsensors} that was built in the @file{lib/} directory in @file{lm_sensors2}.
+@end itemize
+
+
+@node Section 4.28, Section 4.29, Section 4.27, Problems
+@section Sensors doesn't find any sensors, just eeproms.
+
+@xref{Section 4.24, Sensors-detect doesnt work at all}, if @command{sensors-detect} failed to find any sensors.
+
+If @command{sensors-detect} did find sensors, did you insert your modules? For chips on the ISA
+bus, did you insert i2c-isa?
+
+@xref{Section 5.2, What to do if a module wont insert}, if the modules didn't insert,
+also @ref{Section 4.21, Sensors says No sensors found}.
+
+
+@node Section 4.29, Section 4.30, Section 4.28, Problems
+@section Inserting modules hangs my board
+
+There are several possible causes:
+@enumerate
+@item Bus driver problems. Insert the bus driver first, before you have inserted any chip drivers, to verify.
+@item Wrong chip driver. Verify that you have a chip supported by the chip driver, see @ref{Section 3.2.1, What chips are on motherboard XYZ}.
+@item The chip driver is reinitializing the chip, which undoes critical initialization done by the BIOS.  Try the parameter @command{init=0} for the w83781d driver; this is the only driver supporting this parameter.
+@item Some chips on the bus don't like to be probed at all.  After inserting the bus driver (but not the chip drivers), run @command{i2cdetect} on the bus, then @command{i2cdump} on each address responding to @command{i2cdetect}. This may find the culprit.  Do not @command{i2cdump address 0x69}, the clock chip.
+@item The chip driver is incorrectly finding a second chip on the bus and is accessing it. For example, with the Tyan 2688 with a w83781d at 0x29, use @command{modprobe ignore_range=0,0x00,0x28,0,0x2a,0x7f} to prevent access to other addresses. (@command{init=0} also req'd for the Tyan 2688).
+@end enumerate
+
+
+@node Section 4.30, Section 4.31, Section 4.29, Problems
+@section Inserting modules slows down my board
+
+Generally this is caused by an overtemperature alarm output from
+the sensor chip. This triggers hardware on the board which
+automatically slows down the CPU clock. Be sure that your
+temperature limits are above the temperature reading. Put
+the new limits in @file{/etc/sensors.conf} and run @command{sensors -s}.
+
+
+@node Section 4.31, Section 4.32, Section 4.30, Problems
+@section Problems on particular motherboards
+
+The following boards have unique problems and solutions.
+
+
+@anchor{Asus P4B}
+@subsection Asus P4B
+
+See @file{prog/hotplug/README.p4b} if your SMBus master is not found.
+
+
+@anchor{Tyan 2460 2462}
+@subsection Tyan 2460, 2462
+
+See support tickets 805, 765, 781, 812, 813, and 867 for information.
+
+
+@anchor{Tyan 2466}
+@subsection Tyan 2466
+
+See support tickets 941, 840, and 841 for information.
+
+
+@anchor{Tyan 2688}
+@subsection Tyan 2688
+
+For board hangs, see support ticket 721 for information.
+Also @ref{Section 4.29, Inserting modules hangs my board}.
+
+
+@node Section 4.32, , Section 4.31, Problems
+@section Problems on 2.6 kernels
+
+Not all drivers have been ported to 2.6. If your favorite driver is not
+in 2.6, the reason is that nobody has ported it, or the ported code did
+not get a proper review yet.
+If you would like to port the driver, see the file
+Documentation/i2c/porting-clients in the 2.6 kernel tree for help,
+then send us the ported driver when you are done.
+
+@subsection i2c-viapro and via686a
+Until kernel 2.6.11, there was a PCI resource conflict between
+i2c-viapro (the SMBus driver for VIA bridges) and via686a (the integrated
+sensors driver for VIA bridges). This caused the second loaded driver to 
+silently fail working. So do not load both i2c-viapro and via686a together 
+unless you have a recent kernel.
+
+@subsection Where are my EEPROMs?
+The 2.6.14-rc1 kernel introduced the hwmon class, which groups all
+hardware monitoring drivers in a logical way. The goal was to help
+libsensors grab the relevant sensors information in /sys. In particular:
+@itemize
+@item libsensors will no more need to know about the underlying bus types
+(I2C/SMBus, ISA or other);
+@item libsensors will no more list non-hardware monitoring chips.
+@end itemize
+This explains why EEPROMs are no more displayed by @command{sensors}:
+they are no hardware monitoring chips. The medium term plan is to drop
+eeprom support for all Linux 2.6 kernels, as it didn't fit well in
+the library code in the first place.
+
+Note that you can still obtain information about your EEPROMs by using
+the dedicated perl scripts in the i2c-tools package: @command{ddcmon},
+@command{decode-dimms.pl}, @command{decode-edid.pl} and
+@command{decode-vaio.pl}.
+
+
+@node Help, Contribute, Problems, Top
+@chapter How to Ask for Help
+
+@menu
+* Section 5.1::  What to send us when asking for help
+* Section 5.2::  What to do if a module won't insert?
+* Section 5.3::  What to do if it inserts, but nothing happens?
+* Section 5.4::  What to do if I read only bogus information?
+* Section 5.5::  What to do if you have other problems?
+* Section 5.6::  What if it just works like a charm?
+* Section 5.7::  How do I update a ticket?
+* Section 5.8::  How do I follow up on a ticket?
+* Section 5.9::  Why did you decide not to support undocumented chips?
+@end menu
+
+
+@node Section 5.1, Section 5.2, , Help
+@section What to send us when asking for help
+
+We are always willing to answer questions if things don't work out.
+Post your question to our @uref{http://lists.lm-sensors.org/mailman/listinfo/lm-sensors, discussion list},
+and not the individual authors,
+unless you have something private to say.
+
+Instead of using email, you can also use the web-based support
+area, at @uref{http://www.lm-sensors.org/wiki/FeedbackAndSupport}. You will be helped
+just as fast, and others may profit from the answer too. You will be
+emailed automatically when your question has been answered.
+
+Here's what you should send us:
+
+@itemize
+@item The dmesg or syslog output if applicable
+@item The output of (as root) @command{prog/detect/sensors-detect}
+@item The output of @command{lsmod}
+@item If a PCI chip problem:
+@itemize
+@item The output of @command{lspci -n}
+@end itemize
+@item If an I2C sensor chip problem:
+@itemize
+@item The output of (as root) @command{prog/detect/i2cdetect X}
+where X = the bus number (run @command{i2cdetect} with no arguments to list the busses)
+(please send this only if it's not all @samp{XX})
+@item The output of (as root) @command{prog/dump/i2cdump X 0xXX}
+where XX = the address of each chip you see in the output of @command{i2cdetect}. (run once for each chip)
+(please send this only if it's not all @samp{ff})
+@end itemize
+@item If an ISA sensor chip problem:
+@itemize
+@item The output of (as root) @command{prog/dump/isadump 0x295 0x296} (only if it's not all @samp{XX})
+@end itemize
+@item Part numbers of chips on your motherboard you think are the sensor chips (look at your motherboard)
+@item Motherboard type
+@item Sensors version
+@item Kernel version
+@end itemize
+
+
+@node Section 5.2, Section 5.3, Section 5.1, Help
+@section What to do if a module won't insert?
+
+Did you use @command{modprobe} instead of @command{insmod}??? Don't use insmod.
+
+Were there unresolved symbols? Did you run @command{depmod -a}? Run
+@command{depmod -a -e} to see where the symbol problem is.
+
+ALWAYS inspect the output of @command{dmesg}. That's where the error
+messages come out!!! Don't rely on the generic message from @command{modprobe}.
+If you still can't figure it out, send us the information
+listed above.
+
+
+@node Section 5.3, Section 5.4, Section 5.2, Help
+@section What to do if it inserts, but nothing happens?
+
+For an ISA sensor chip, did you also @command{modprobe i2c-isa}? It must be inserted.
+
+For an I2C sensor chip, did you also @command{modprobe i2c-xxx} where xxx is your
+I2C bus adapter? It must be inserted.
+
+Always inspect the output of @command{dmesg}. That's where the error
+messages come out. If you still can't figure it out, send us the information
+listed above.
+
+
+@node Section 5.4, Section 5.5, Section 5.3, Help
+@section What to do if I read only bogus information?
+
+It may be that this was a mis-detection: the chip may not be
+present. If you are convinced there is something wrong, verify that you
+indeed have the devices on your motherboard that you think you do.
+Look at the motherboard and make sure. If you are still stuck,
+please send us the usual information (@pxref{Help})
+
+
+@node Section 5.5, Section 5.6, Section 5.4, Help
+@section What to do if you have other problems?
+
+Again, send the output listed above.
+
+
+@node Section 5.6, Section 5.7, Section 5.5, Help
+@section What if it just works like a charm?
+
+Drop us a mail if you feel like it, mentioning the mainboard and
+detected chip type. That way, we have some positive feedback, too!
+
+
+@node Section 5.7, Section 5.8, Section 5.6, Help
+@section How do I update a ticket?
+
+You can't. Only developers can. Follow up by emailing us
+and reference your ticket number
+in the subject. Please don't enter a new ticket with
+follow-up information, email us instead. Thanks.
+
+
+@node Section 5.8, Section 5.9, Section 5.7, Help
+@section How do I follow up on a ticket?
+
+Follow up by emailing us
+and reference your ticket number in the subject.
+
+
+@node Section 5.9, , Section 5.8, Help
+@section Why did you decide not to support undocumented chips?
+
+There are several reasons why we are generally not interested in writing
+drivers for undocumented chips:
+
+@itemize
+@item Writing a driver without a datasheet is much harder, as you have to
+guess most things. Remember that, most of the time, we write drivers for fun
+and for free, so there is no reason we would write a driver in conditions
+that promise more pain than fun.
+@item If we hit a problem, we are certain never to get any support from the
+chip manufacturer. This means that we may spend days on code which will
+finally never work.
+@item There are several chips out there which are fully documented and lack
+a driver. This is natural for us to give these the priority when we
+finally have some spare time to spend on driver coding.
+@item Hardware monitoring chips are not toys. Misprogramming them can
+result in data loss or hardware breakage. This is obviously more likely
+to happen with undocumented chips. This is a responsability we do not
+want to endorse (the GPL is pretty clear than we are not legally
+liable, but still).
+@end itemize
+
+There are also several reasons why we do not want to support such drivers,
+even if they were written by other people:
+
+@itemize
+@item Problems are much more likely to happen with such drivers.
+This means increased needs of support. User support if very
+time-consuming and we are usually short of time.
+@item Support should be done by the driver author (as only him/her knows
+the driver and chip) but in the reality of facts, people will always ask
+us for help if the driver is part of our package. Redirecting all user
+requests to the driver's author manually is boring.
+@item The lack of datasheet usually results in an original driver which
+works relatively fine for its author, but will happen not to work
+completely for other users. This means that the driver will need many
+more additions and fixes than other drivers do, resulting in an increased
+maitainance workload, which we can hardly afford. Of course this too should
+be handled by the original driver author, but we never know whether he/she
+will actually do the work.
+@end itemize
+
+Lastly, there are other considerations, some of which are deliberately
+political:
+
+@itemize
+@item We do not want to trick hardware buyers into thinking that a chip is
+fully supported under Linux when in fact it is only partly supported by a
+driver which was written without a datasheet. Clearly stating that such
+chips are not supported makes it much easier for anyone who really needs
+fully working hardware monitoring under Linux to avoid motherboards with
+these partly supported chips.
+@item Drivers written without a datasheet are a pain for developers and
+users, but are a complete win for the manufacturers of these chips:
+they don't have to write the driver, they don't have to help us,
+they don't have to support the users, and they still sell their
+hardware. We do not want to encourage such a selfish behavior.
+@end itemize
+
+That being said, authors of such drivers can still submit their code to
+the Linux kernel folks for inclusion into Linux 2.6. Their driver may be
+accepted there, under conditions.
+
+If such a driver is ever accepted into the Linux 2.6 tree, and someone
+provides a patch to libsensors and/or sensors to add support for this
+driver, we will apply it. This generic code is unlikely to cause trouble.
+
+
+@node Contribute, Document Revisions, Help, Top
+@chapter How to Contribute
+
+@menu
+* Section 6.1::  How to write a driver
+* Section 6.2::  How to get SVN access
+* Section 6.3::  How to donate hardware to the project
+* Section 6.4::  How to join the project mailing list
+* Section 6.5::  How to access mailing list archives
+* Section 6.6::  How to submit a patch
+* Section 6.7::  How to REALLY help
+* Section 6.8::  How to get release announcements
+@end menu
+
+
+@node Section 6.1, Section 6.2, , Contribute
+@section How to write a driver
+
+See @file{doc/developers/new_drivers} in our package for instructions.
+
+
+@node Section 6.2, Section 6.3, Section 6.1, Contribute
+@section How to get SVN access
+
+For anonymous SVN read access, see the instructions on our
+@uref{http://www.lm-sensors.org/wiki/Download, download page}.
+
+For write access, please contact us.
+
+
+@node Section 6.3, Section 6.4, Section 6.2, Contribute
+@section How to donate hardware to the project
+
+@uref{http://www.lm-sensors.org/wiki/FeedbackAndSupport, Contact us}.
+
+
+@node Section 6.4, Section 6.5, Section 6.3, Contribute
+@section How to join the project mailing lists
+
+There are two lists you can subscribe to:
+
+@itemize
+@item A @uref{http://lists.lm-sensors.org/mailman/listinfo/lm-sensors, general discussion list},
+meant for both development and user support. You do not need to be subscribed to post.
+@item A @uref{http://lists.lm-sensors.org/mailman/listinfo/lm-sensors-commit, CVS commits list},
+for watching the changes made to the CVS repositories. This list is read-only.
+@end itemize
+
+
+@node Section 6.5, Section 6.6, Section 6.4, Contribute
+@section How to access mailing list archives
+
+The primary mailing list archive is at:
+@uref{http://lists.lm-sensors.org/pipermail/lm-sensors/}.
+It contains messages since October 28, 2001.
+
+There is another mailing list archive at:
+@uref{http://news.gmane.org/gmane.linux.drivers.sensors}.
+It contains messages since December 31, 2004.
+This archive may also be accessed via a news reader:
+@uref{nntp://news.gmane.org/gmane.linux.drivers.sensors}
+and RSS:
+@uref{http://rss.gmane.org/gmane.linux.drivers.sensors}.
+
+And last there is a legacy archive at:
+@uref{http://archives.andrew.net.au/lm-sensors}.
+It contains messages from October 28, 2001 through May 16, 2005.
+
+
+@node Section 6.6, Section 6.7, Section 6.5, Contribute
+@section How to submit a patch
+
+Check out the latest from CVS, then copy the directory to another
+directory, and make your changes. Generate the diff with
+@command{diff -u2 -r DIR1 DIR2}. Or you can generate the diff in CVS with
+@command{cvs diff -u2}. Send us the patch in an email and tell us what it does.
+
+@node Section 6.7, Section 6.8, Section 6.6, Contribute
+@section How to REALLY help
+
+Believe it or not, what we really need help with are:
+@itemize
+@item Answering email
+@item Answering support tickets
+@item Porting drivers to Linux 2.6
+@item Creating a sensors.conf database
+@item Reviewing patches
+@end itemize
+
+If you are willing to help, simply join our
+@uref{http://lists.lm-sensors.org/mailman/listinfo/lm-sensors, discussion list},
+and we'll help you help us.
+
+
+@node Section 6.8, , Section 6.7, Contribute
+@section How to get release announcements
+
+We don't have a separate release announcement mailing list;
+however, we put all our releases on freshmeat: @uref{http://freshmeat.net}
+and you can register on our freshmeat project page  @uref{http://freshmeat.net/projects/lm_sensors}
+to 'subscribe to new releases' and then freshmeat
+will email you announcement.
+
+
+@node Document Revisions, , Contribute, Top
+@appendix Revision History of This Document
+
+@itemize
+@item Rev 2.19 (JD) Removed 4.32 (Thinkpad-specific issues), 2007-09-24
+@item Rev 2.18 (JD) Removed version 1 specifics part, 2005-12-17
+@item Rev 2.17 (JD) Added 5.9 (why we don't support undocumented chips),
+	removed 6.9 (doesn't apply to the new mailing list), 2005-10-05
+@item Rev 2.16 (JD) Added 4.33.2, 2005-09-06
+@item Rev 2.15 (JD) Updates, including mailing-list change, 2005-05-21
+@item Rev 2.14 (MDS) Updated 4.12, 2004-11-26
+@item Rev 2.13 (JD) Added 4.6.1, updated 4.7, 2004-06-23
+@item Rev 2.12 (JD) Updated 4.27, 2004-04-11
+@item Rev 2.11 (JD) Various updates, 2004-01-18
+@item Rev 2.10 (MDS) Various updates, 2004-01-03
+@item Rev 2.9 (CP) Converted to Gnu texinfo format, 2002-09-10
+@item Rev 2.8 (MDS) Minor updates 2002-07-10, released with lm_sensors 2.6.4
+@item Rev 2.7 (MDS) Minor updates 2002-04-25
+@item Rev 2.6 (MDS) Minor updates 2002-01-15, released with lm_sensors 2.6.3
+@item Rev 2.5 (MDS) Minor updates 2001-11-11, released with lm_sensors 2.6.2
+@item Rev 2.4 (MDS) Minor updates 2001-07-22
+@item Rev 2.3 (MDS) General update, 2001-02-24, released with lm_sensors 2.6.0.
+@item Rev 2.2 (Frodo) Corrections for lm_sensors 2.4, 1999-09-20
+@item Rev 2.1 (Frodo) Corrections for lm_sensors 2.2, 1999-01-12
+@item Rev 2.0 (Frodo) Major revision for lm_sensors 2.1, 1998-12-29
+@item Rev 1.10 (Frodo) Modified 3.8, updated some other things, 1998-09-24
+@item Rev 1.9 (Frodo) Added 3.15, 1998-09-06
+@item Rev 1.8 (Frodo) Added 3.14, 1998-09-05
+@item Rev 1.7 (Phil) Added 3.13 and some other minor changes, 1998-09-01
+@item Rev 1.6 (Frodo) Added 4, 4.1, 4.2, 4.3, 4.4, 4.5, 1998-09-01
+@item Rev 1.5 (Frodo) Added 2.3, 2.4, 3.9, 3.10, 3.11, 1998-08-26
+@item Rev 1.4 (Frodo) Added some more Winbond information, and 3.5-3.8, 1998-08-17
+@item Rev 1.3 (Phil) Added info on the Winbond chip, 1998-08-16
+@item Rev 1.2 (Frodo) Adapation, 1998-08-10
+@item Rev 1.1 (Phil) Modifications, 1998-08-09
+@item Rev 1.0 (Phil) First version, 1998-08-03
+@end itemize
+
+@bye
Index: /lm-sensors/tags/V3-0-0-RC2/doc/vid
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/vid	(revision 4543)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/vid	(revision 4543)
@@ -0,0 +1,56 @@
+VID pin settings
+--------------------
+
+The VID (Voltage Identification) pins on sensor chips
+are used to read the CPU Core voltage setting.
+
+The VID setting can be controlled by jumpers on the board,
+or, in newer motherboards, by settings in the BIOS.
+On these newer boards, the BIOS programs some device's
+pins which in turn controls a DC-DC Converter to set its
+output to a certain voltage. These pins are also connected to
+the sensor chip so that the VID setting can be read back
+by applications.
+
+There are generally 5 VID pins. Recent motherboards may use 6 pins.
+The VID codes are defined by Intel in documents titled
+"VRM X.X DC-DC Converter Design Guidelines".
+(VRM = Voltage Regulator Module), or
+"Voltage Regulator-Down (VRD) 10.0 Design Guide".
+These documents are available at http://developer.intel.com.
+
+There are several different VRM document versions.
+The common versions are as follows:
+
+Document Version	Voltage Range	Increment	Processors
+----------------	-------------	---------	----------
+"2.4"			0.8 - 1.55	0.025V		AMD Opteron 24x
+
+8.2 (8.1, 8.3)		1.30 - 2.05V    0.05V		PII, PIII, Celeron
+			2.1 - 3.5V	0.10V
+
+8.4			1.30 - 2.05V    0.05V		PIII, Celeron
+							4 pins only
+
+8.5			1.050 - 1.825V	0.05V		PIII-S Tualatin
+
+9.0, (9.1)		1.100 - 1.850V	0.025V		P4, AMD Socket A
+
+10.0			0.8375 - 1.6000 0.0125V		Desktop Socket 478
+
+
+"2.4" is not an actual document version but simply a way to identify
+AMD Opteron 24x processors.
+Note that versions 8.1 - 8.4 are compatible.
+
+Since Linux 2.6.9, the correct VRM version is selected automatically
+based on the CPU brand and model. Thus you shouldn't have to care about
+it. If you are using a brand new CPU and even the latest kernel complains
+("Unknown VRM version of your CPU"), this means that the kernel must be
+taught about this new CPU model. Please report to us in this case.
+
+Remember, the VID pins on the sensor chips are inputs only.
+You cannot use them to manipulate the actual processor core voltage.
+
+------------------
+Copyright (c) 2002-2004 Mark D. Studebaker
Index: /lm-sensors/tags/V3-0-0-RC2/doc/fancontrol.txt
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/fancontrol.txt	(revision 4589)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/fancontrol.txt	(revision 4589)
@@ -0,0 +1,134 @@
+
+fancontrol - automated software based fan speed regulation
+
+
+Introduction
+
+fancontrol is a shellscript for use with lm_sensors. It reads its
+configuration from a file, then calculates fan speeds from temperatures and
+sets the corresponding pwm outputs to the computed values.  It is included in
+lm_sensors since 2.8.0, the latest version is always available through SVN or
+at http://www.hdev.de/fancontrol/ For easy configuration, there's a script
+named pwmconfig which lets you interactively write your configuration file for
+fancontrol. Alternatively you can write this file yourself using the
+information from the configuration section of this document.
+
+Please be careful when using the fan control features of your mainboard, in
+addition to the risk of burning your CPU, at higher temperatures there will be
+a higher wearout of your other hardware components, too. So if you plan to use
+these components in 50 years, _maybe_ you shouldn't use fancontrol/your
+hardware at all.  Also please keep in mind most fans aren't designed to be
+powered by a PWMed voltage, for more detailed information on this I recommend
+this appnote: http://www.maxim-ic.com/appnotes.cfm/appnote_number/707
+In practice it doesn't seem to be a major issue, the fans will get slightly
+warmer, just be sure to have a temperature alarm and/or shutdown call, in case
+some fan fails, because you probably won't hear it anymore ;)
+
+Configuration
+
+Since most of you are going to use the pwmconfig script, the config
+file syntax will be discussed last. First I'm going to describe the various
+variables available for changing fancontrol's behaviour:
+
+INTERVAL
+	This variable defines at which interval in seconds the main loop of
+	fancontrol will be executed
+
+FCTEMPS
+	Maps pwm outputs to temperature sensors so fancontrol knows which
+	temperature sensors should be used for calculation of new values for
+	the corresponding pwm outputs.
+
+FCFANS
+	FCFANS records the association between a pwm and a fan.
+	Then fancontrol can check the fan speed and restart it if it
+	stops unexpectedly.
+
+MINTEMP
+	The temperature below which the fan gets switched to minimum speed.
+
+MAXTEMP
+	The temperature over which the fan gets switched to maximum speed.
+
+MINSTART
+	Sets the minimum speed at which the fan begins spinning. You should
+	use a safe value to be sure it works, even when the fan gets old.
+
+MINSTOP
+	The minimum speed at which the fan still spins. Use a safe value here,
+	too.
+
+MINPWM
+	The PWM value to use when the temperature is below MINTEMP.
+	Typically, this will be either 0 if it is OK for the fan to plain
+	stop, or the same value as MINSTOP if you don't want the fan to
+	ever stop.
+	If this value isn't defined, it defaults to 0 (stopped fan).
+
+MAXPWM
+	The PWM value to use when the temperature is over MAXTEMP.
+	If this value isn't defined, it defaults to 255 (full speed).
+
+A graph might help you understand how the different values relate
+to each other:
+
+    PWM ^
+    255 +
+        |
+        |
+        |                             ,-------------- MAXPWM
+        |                           ,'.
+        |                         ,'  .
+        |                       ,'    .
+        |                     ,'      .
+        |                   ,'        .
+        |                 ,'          .
+        |       MINSTOP .'            .
+        |               |             .
+        |               |             .
+        |               |             .
+ MINPWM |---------------'             .
+        |               .             .
+        |               .             .
+        |               .             .
+      0 +---------------+-------------+---------------->
+                     MINTEMP       MAXTEMP            t (degree C)
+
+The configuration file format is a bit strange:
+
+VARIABLE=chip/pwmdev=value chip/pwmdev2=value2 [...]
+VARIABLE2=[...]
+
+Each variable has its own line. The variable name is followed by an equal sign
+and the device=value pairs. These consist of the relative path to the pwm
+output (from /proc/sys/dev/sensors, /sys/bus/i2c/devices or /sys/class/hwmon
+depending on the kernel version) for which the value is valid, equal sign
+followed by the value and are separated by a blank.
+
+Example:
+
+MINTEMP=w83627hf-isa-0290/pwm2=40 w83627hf-isa-0290/pwm1=54
+
+You have to play with the temperature values a bit to get happy. For initial
+setup I recommend using the pwmconfig script. Small changes can be made by
+editing the config file directly following the rules above.
+
+
+The algorithm
+
+fancontrol first reads its configuration, writes it to arrays and loops its
+main function.  This function gets the temperatures and fanspeeds from
+kernel driver files and calculates new speeds depending on temperature
+changes, but only if the temp is between MINTEMP and MAXTEMP. After that, the
+new values are written to the pwm outputs.  The pwm value increases
+linearly with rising temperature.
+
+
+Planned features
+
+rc-scripts for some gnu/linux-distributions
+smoother regulation (temp interpolation)
+gui for configuration
+
+If you have other wishes or want to contribute something, please let me know:
+marius.reiner${AT}hdev.de
Index: /lm-sensors/tags/V3-0-0-RC2/doc/fan-divisors
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/fan-divisors	(revision 4251)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/fan-divisors	(revision 4251)
@@ -0,0 +1,99 @@
+Fan reading problems and solutions
+----------------------------------
+
+If you aren't getting the expected readings on your fans,
+try the following:
+
+- Do you get a fan reading in the BIOS or using a different OS?
+  If not, you may not have a fan with a tachometer output.
+  Look and see. Fans with tachometer outputs have at least 3 wires.
+  Fans with only 2 wires cannot, in general, report their speed.
+
+- Try experimenting with the fan divisor settings:
+
+
+Fan Divisor Settings
+--------------------
+
+Fan Divisor	Minimum RPM	Maximum RPM
+-----------	-----------	-----------
+  1		5314		1350000
+  2		2657		 675000		default on most chips
+  4		1328		 337500
+  8		 664		 168750
+ 16		 332		  84375		not supported on most chips
+ 32		 166		  42187		""
+ 64		  83		  21093		""
+128		  41		  10546		""
+
+Pick a divisor so that the nominal RPM is about 50%
+above the minimum. This is a good compromise between
+margin and accuracy. Note that most chips only support
+fan divisors of 1, 2, 4, and 8.
+
+If you have a 0 RPM reading some or all of the time,
+increase the divisor until you get good readings.
+
+If you have a nominal reading less than 1.25 times the
+minimum, increase the divisor to give you margin
+so that you will not get spurious alarms.
+
+If you have a nominal reading more than 3 times the
+minimum, decrease the divisor to provide better
+accuracy.
+
+
+How to change fan divisors
+--------------------------
+
+Put an entry "set fanN_div X" in the appropriate section of
+/etc/sensors.conf and run 'sensors -s'
+(N is the number of the fan, and X is the divisor you want).
+
+
+Further details
+---------------
+
+Fan divisors are quite confusing.
+
+Sensor chips count fan speed by using the fan signal
+to gate an 8-bit counter driven by a 22.5 kHz clock.
+So the _higher_ the counter value, the _slower_ the fan,
+and vice versa.
+
+The term 'fan divisor' is a misnomer because it doesn't divide
+the fan signal, it divides the 22.5 kHz clock.
+Thus you _increase_ the divisor if you have a slow fan.
+
+The drivers account for the 'fan divisor' in their calculation
+of RPM. So changing the fan divisor will NOT change the
+nominal RPM reading, it will only affect the minimum and maximum
+readings and the accuracy of the readings.
+
+The actual formula is RPM = (60 * 22500) / (count * divisor)
+
+The readings are most accurate when the fan speed is low
+(i.e., close to the minimum possible RPM reading).
+As fan speed gets closer to the maximum possible RPM reading,
+the reading becomes quite inaccurate. Fortunately, most computer
+fans do not approach 1,000,000 RPM !
+
+
+Fan readings 2X too high
+------------------------
+
+This is rare, but can happen. This is typically caused by a fan which
+outputs 4 pulses by revolution, instead of the standard 2.
+
+As we learned above, you can _not_ fix this by changing
+the fan divisor. You must add entries into the appropriate
+section of /etc/sensors.conf:
+
+	compute fanN  @/2,  2*@
+
+(N is the number of the fan)
+
+
+
+------------------
+Copyright (c) 2000-2004 Mark D. Studebaker
Index: /lm-sensors/tags/V3-0-0-RC2/doc/chips/MODPARMS
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/chips/MODPARMS	(revision 1369)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/chips/MODPARMS	(revision 1369)
@@ -0,0 +1,129 @@
+Parameters for modprobe and insmod
+==================================
+==================================
+SUMMARY
+
+	[modprobe,insmod] module {parameter...}
+	Parameters:
+		force=bus,address{,bus,address}
+		force_addr=address{,address}
+		force_[chipname]=bus,address{,bus,address}
+		force_subclients=bus,caddr,saddr,saddr
+		ignore=bus,address{,bus,address}
+		ignore_range=bus,start,end{,bus,start,end}
+		probe=bus,address{,bus,address}
+		probe_range=bus,start,end{,bus,start,end}
+		init=[0,1] (default 1)
+
+	All arguments are in decimal unless prefixed by "0x".
+	No spaces are allowed.
+
+==================================
+OVERVIEW
+
+All chip drivers have a few modprobe module parameters in common.
+(Insmod can also be used, but we recommend modprobe so that
+other required modules are automatically loaded.) These
+parameters can be used when a module is inserted, to give some additional
+information about how it should function. In this case, they tell where
+the module should look for what chips. Usually, you don't need them, and
+if you do, you are often told by sensors-detect which ones you need.
+
+If a module doesn't load with no parameters, you may need to
+add parameters. Check 'dmesg' for clues to what went wrong.
+
+
+BUS NUMBERING
+-------------
+I2C/SMBus adapters are numbered in the order they are inserted. If you want
+to know what number an adapter has, please make sure module `i2c-proc' is 
+inserted, and look at file /proc/bus/i2c. The ISA bus always has the
+symbolic number 9191 (`I' is the ninth letter of the alphabet, `S' the
+nineteenth and `A' the first). Do not use the ISA Bus number from
+/proc/bus/i2c. If you want 'any I2C bus', use '-1' (or 65535).
+So to summarize:
+	-1	Any Bus
+	0-15	Specific I2C Bus
+	9191	ISA BUS
+
+
+ADDRESS NUMBERING
+-----------------
+Each adapter has a number of addresses on I2C/SMBus adapters and/or the
+ISA bus that are always scanned if no modprobe parameters are given. The
+parameters below override those addresses that are scanned by default.
+
+All modprobe parameters described below take lists of positive integers
+(unsigned, in the range of 0 to 65535) as their arguments.  Integers
+are separated by comma's, and may be given as ordinary decimal numbers,
+as octal numbers (by starting them with a `0') or as hexadecimal numbers
+(by starting them with a `0x'). More information can be found by
+entering `man modprobe' or `man insmod'.
+So to summarize:
+	0x00 - 0x7f	Valid I2C Addresses
+	0x0000 - 0xffff	Valid ISA Bus Addresses
+
+
+==================================
+PARAMETER DETAILS
+
+`force', `force_*', `ignore' and `probe' parameters take pairs of numbers.
+Each first (odd) number is a bus number, each second (even) number is
+an (I2C or ISA) address.
+
+`ignore_range' and `probe_range' parameters take triples of numbers.
+Each first number is a bus number, each second number is the start address
+of a range, and each third number is the end address of a range. Ranges
+are always inclusive.
+
+`probe' and `probe_range' parameters tell the module to scan additional 
+addresses for a specific bus. These are treated just as the ordinary
+addresses scanned. This is useful for some chips that can be anywhere;
+to keep loading time (and false detections) down, only the most common
+addresses are scanned by default.
+
+`ignore' and `ignore_range' parameters tell the module not to scan
+specific addresses. They overrule the default addresses and any 
+addresses specified by `probe' and `probe_range' statements.
+
+The `force' parameter tells the module a supported chip is found at
+a specific address. It overrules all previously mentioned parameters.
+Sometimes, a chip can be in a specific internal state that makes
+detection impossible. If you specify it with the `force' parameter,
+it is first put into a recognizable state. Also, some detection routines
+are skipped. If the module supports several chips, it will still try
+to determine what chip is found on that address. If it can't determine
+this, the address will still not be used.
+
+There is a `force_*' parameter for each type of chip supported by a
+module. This is the strongest statement possible - it says that a
+specific type of chip is found on a specific address, and the module
+will skip all detection and recognition routines. This can lead to
+very strange results...
+
+`force_addr' is a parameter used for PCI sensor adapters.
+It is used to program the base address of the sensor registers.
+This is required if the BIOS does not initialize the base address.
+
+`force_subclients' is used to force the i2c addresses for subclients of
+a certain chip. Typical usage is `force_subclients=0,0x2d,0x4a,0x4b'
+to force the subclients of chip 0x2d on bus 0 to i2c addresses
+0x4a and 0x4b.
+This parameter is currently supported only by the w83781d driver
+and is useful for certain Tyan boards.
+
+`init' is used to tell a driver to bypass initializing a chip.
+This may be necessary if the BIOS has initialized the chip a certain way
+and the driver should not overwrite that initialization.
+It is also useful if normal initialization crashes the system.
+The default is 1, so the only useful value is `init=0'.
+This parameter is currently supported only by the w83781d driver.
+
+==================================
+EXAMPLE
+
+  # ISA address 0x390 contains a LM79
+  # Scan all I2C addresses (from 0 to 0x7f) for all I2C adapters
+  # But skip address 0x2d on adapter 0, and address 0x20 on adapter 1
+
+  modprobe lm78 force_lm79=9191,0x390 ignore=0,0x2d,1,0x20 probe_range=-1,0,0x7f
Index: /lm-sensors/tags/V3-0-0-RC2/doc/chips/SUMMARY
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/chips/SUMMARY	(revision 4900)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/chips/SUMMARY	(revision 4900)
@@ -0,0 +1,300 @@
+SUMMARY OF SUPPORTED CHIPS
+==========================
+
+This is a summary of the sensor and non-sensor chips supported by this
+package. It lists the features of each supported chip. For further
+information on a particular driver, see the documentation in this
+directory.
+
+To determine what chips you have in your system, run 'sensors-detect'.
+
+If your sensor chip is not detected by sensors-detect, please contact us
+(see http://www.lm-sensors.org/wiki/AuthorsAndContributors). Only contact us
+if you know for sure that your system includes a sensor chip (for
+example if you have technical documentation mentioning it, or if the
+BIOS setup screen presents monitoring values, or if you can get
+hardware monitoring to work using a different OS). Do *not* contact us
+if you have no proof that your system includes sensors. Such systems
+tend to be rare these days, but do still exist. This is especially true
+of laptops. If there are no sensors, there's nothing we can do.
+
+If you contact us, please include the following in your mail:
+ - The output of (as root) 'sensors-detect'. Make sure you unloaded
+   every chip driver beforehand (check that the sensors-detect script
+   does not complain that it couldn't probe some I2C addresses on any
+   given bus).
+ - Dumps of the chips that might be hardware monitoring chips. To get
+   these, follow the following steps:
+   1* Run 'i2cdetect -l'. This will list all available I2C (or SMBus)
+      busses on your system.
+   2* For each bus listed, run (as root) 'i2cdetect N' where N is the
+      bus number.
+   3* For each bus, if there is anything in the ranges 0x20-0x2f or
+      0x48-0x4f, dump the contents of that chip with (as root)
+      'i2cdump N 0xXX', where N is the bus number and XX is the
+      responsive address. Chips in other address ranges are way less
+      likely to be hardware monitoring chips. In particular, do not
+      send dumps of addresses 0x08, 0x0c, 0x10, 0x30-0x37, 0x42, 0x44,
+      0x50-0x5f, 0x61 and 0x69. These are *not* hadware monitoring
+      chips.
+ - The part numbers of the chips on your motherboard you think are the
+   sensor chips.
+
+-----------------------------------------------------------------------------
+
+SUPPORTED SENSOR CHIPS
+----------------------
+
+			Included Sensors	Controls Busses
+			----------------------	-------  -----------
+Driver  Chips		#temp	#vin	#fanin	pwm/dac	I2C	ISA
+---------------------------------------------------------------------
+adm1021
+	adm1021		2	-	-	-	yes	no
+	adm1021a	2	-	-	-	yes	no
+	adm1023		2	-	-	-	yes	no
+	gl523sm		2	-	-	-	yes	no
+	lm84		2	-	-	-	yes	no
+	max1617		2	-	-	-	yes	no
+	max1617a	2	-	-	-	yes	no
+	tc1068		2	-	-	-	yes	no
+	tcm1617		2	-	-	-	yes	no
+	thmc10		2	-	-	-	yes	no
+	mc1066		2	-	-	-	yes	no
+	  (xeon - no detection - requires force_adm1021 parameter)
+	xeon		1	-	-	-	yes	no
+	  (the following chips are detected as a max1617)
+	ne1617		2	-	-	-	yes	no
+	ne1617a		2	-	-	-	yes	no
+
+adm1024
+	adm1024		3	6	-	1 dac	yes	no
+
+adm1025
+	adm1025		2	6	-	-	yes	no
+	ne1619		2	6	-	-	yes	no
+
+adm1026
+	adm1026		3	17	8	2 pwm+dac yes	no
+
+adm1031
+	adm1030		2	-	1	1 pwm	yes	no
+	adm1031		3	-	2	2 pwm	yes	no
+
+adm9240
+	adm9240		1	6	2	1 dac	yes	no
+	ds1780		1	6	2	1 dac	yes	no
+	lm81		1	6	2	1 dac	yes	no
+
+asb100
+	asb100		4	7	3	1	yes	no
+
+bmcsensors
+	bmcsensors	?	?	?	-	no	no
+
+ds1621
+	ds1621		1	-	-	-	yes	no
+	  (the following chip is detected as a ds1621)
+	ds1625		1	-	-	-	yes	no
+
+f71805f
+	f71805f		9	3	3	-	no	yes
+
+fscher
+	fscher		3	3	3	-	yes	no
+
+fscpos
+	fscpos		3	3	3	-	yes	no
+
+fscscy
+	fscscy		4	3	6	-	yes	no
+
+gl518sm
+	gl518sm (r00)	1	1-4	2	-	yes	no
+	gl518sm (r80)	1	4	2	-	yes	no
+
+gl520sm
+	gl520sm		1-2	4-5	2	-	yes	no
+
+it87
+	it8712		3	8	3	3 pwm	yes	yes
+	(the following are reported as an "it87")
+	it8705		3	8	3	3 pwm	yes	yes
+	sis950		3	8	3	3 pwm	yes	yes
+
+lm63
+	lm63		2	-	1	1 pwm	yes	no
+
+lm75
+	lm75		1	-	-	-	yes	no
+	  (the following chips are detected as an lm75)
+	ds75		1	-	-	-	yes	no
+	ds1775		1	-	-	-	yes	no
+	max6625		1	-	-	-	yes	no
+	max6626		1	-	-	-	yes	no
+	tcn75		1	-	-	-	yes	no
+
+lm78
+	lm78		1	7	3	-	yes	yes
+	lm78-j		1	7	3	-	yes	yes
+	lm79		1	7	3	-	yes	yes
+
+lm80
+	lm80		1	7	2	-	yes	no
+
+lm83
+	lm83		4	-	-	-	yes	no
+	lm82		2	-	-	-	yes	no
+
+lm85
+	lm85		3	5	4	3 pwm	yes	no
+	adm1027		3	5	4	3 pwm	yes	no
+	adt7463		3	5	4	3 pwm	yes	no
+	emc6d100	3	8	4	3 pwm	yes	no
+	(emc6d101 is reported as emc6d100)
+	emc6d101	3	8	4	3 pwm	yes	no
+	emc6d102	3	8	4	3 pwm	yes	no
+
+lm87
+	lm87		2-3	6-8	0-2	1 pwm	yes	no
+
+lm90
+	lm90		2	-	-	-	yes	no
+	lm99		2	-	-	-	yes	no
+	lm86		2	-	-	-	yes	no
+	adm1032		2	-	-	-	yes	no
+	max6657		2	-	-	-	yes	no
+	(lm89 is detected as an lm99)
+	lm89		2	-	-	-	yes	no
+	(max6658 and max6659 are detected as a max6657)
+	max6658		2	-	-	-	yes	no
+	max6659		2	-	-	-	yes	no
+	(adt7461 only works in ADM1032 compatibility mode)
+	adt7461		2	-	-	-	yes	no
+
+lm92
+	(all are reported as an "lm92")
+	lm92		1	-	-	-	yes	no
+	max6633		1	-	-	-	yes	no
+	max6634		1	-	-	-	yes	no
+	max6635		1	-	-	-	yes	no
+	(lm76 needs force parameter)
+	lm76		1	-	-	-	yes	no
+
+max1619
+	max1619		2	-	-	-	yes	no
+
+max6650
+	(all are reported as a "max6650")
+	max6650		-	-	1	1 pwm	yes	no
+	max6651		-	-	4	1 pwm	yes	no
+
+maxilife
+	maxilife-as	5	4	3	-	yes	no
+	maxilife-co	5	4	3	-	yes	no
+	maxilife-cg	5	4	3	-	yes	no
+
+mtp008
+	mtp008		3	7	3	3 pwm	yes	no
+
+pc87360
+	pc87360		-	-	2	2 pwm	no	yes (LPC)
+	pc87363		-	-	2	2 pwm	no	yes (LPC)
+	pc87364		-	-	3	3 pwm	no	yes (LPC)
+	pc87365		2	11	3	3 pwm	no	yes (LPC)
+	pc87366		3-4	11	3	3 pwm	no	yes (LPC)
+
+pcf8591
+	pcf8591		-	2-4	-	1 dac	yes	no
+
+sis5595
+	sis5595		0-1	4-5	2	-	no	yes
+
+smartbatt
+	smartbatt	1	1	-	-	yes	no
+
+smsc47m1
+	(all are reported as a "smsc47m1")
+	smsc47b27x	-	-	2	2	no	yes (LPC)
+	smsc47m10x	-	-	2	2	no	yes (LPC)
+	smsc47m112	-	-	2	2	no	yes (LPC)
+	smsc47m13x	-	-	2	2	no	yes (LPC)
+	smsc47m14x	-	-	2	2	no	yes (LPC)
+	smsc47m15x	-	-	2	2	no	yes (LPC)
+	smsc47m192	-	-	2	2	no	yes (LPC)
+	smsc47m997	-	-	2	2	no	yes (LPC)
+	(reported as a "smsc47m2")
+	smsc47m292	-	-	3	3	no	yes (LPC)
+
+thmc50
+	adm1022		3	2	-	1 dac	yes	no
+	thmc50		3	2	-	1 dac	yes	no
+
+via686a
+	via686a		3	5	2	-	no	yes
+	vt8231		3	5	2	-	no	yes
+
+vt1211
+	vt1211		2-7	1-6	2	2	no	yes (LPC)
+
+vt8231
+	vt8231		2-7	2-7	2	2	no	yes
+
+w83627hf
+	w83627hf	3	9	3	2 pwm	no	yes (LPC)
+	w83627thf	3	7	3	3 dac	no	yes (LPC)
+	w83637hf	3	7	2	3 pwm	no	yes (LPC)
+	w83687thf	3	7	3	3 pw/da	no	yes (LPC)
+	w83697hf	2	8	2	2 pwm	no	yes (LPC)
+
+w83781d
+	as99127f	3	7	3	-	yes	no
+	w83781d		3	7	3	-	yes	yes
+	w83782d		3	9	3	2-4 pwm	yes	yes
+	w83783s		1-2	5-6	3	2 pwm	yes	no
+	w83791d		3	10	5	5 pwm	yes	no
+	w83627hf	3	9	3	2 pwm	yes	yes (LPC)
+
+w83l785ts
+	w83l785ts	1	-	-	-	yes	no
+
+w83792d
+	w83792d		3	9	7	3 pwm	yes	no
+
+xeontemp
+	xeontemp	1	-	-	-	yes	no
+
+
+-----------------------------------------------------------------------------
+
+COMPANY ID LIST
+---------------
+
+Many SMBus chips have a company ID at location 0x3E or 0xFE.
+
+Here is a partial list.
+This may help identify a chip after doing a 'i2cdump [bus] [address]'.
+
+0x00	National (on LM84)
+0x01	National
+0x12C3	Asus (at 0x4F)
+0x1934	Fintek (at 0x5D-0x5E)
+0x23	Analog Devices
+0x41	Analog Devices (also at 0x16)
+0x49	TI
+0x4D	Maxim
+0x54	On Semi
+0x54	Microchip (at 0x7)
+0x5C	SMSC
+0x5D 	SMSC
+0x55	SMSC
+0x5CA3	Winbond (at 0x4F)
+0x61	Andigilog
+0x90	ITE (at 0x58)
+0xA1	Philips (at 0x05 too)
+0xA3	Winbond (at 0x4F)
+0xAC	Myson (at 0x58)
+0xC3	Asus (at 0x4F)
+0xDA	Dallas
+
+[A-Z]{3} at 0x00-0x02: Fujitsu-Siemens
Index: /lm-sensors/tags/V3-0-0-RC2/doc/svn
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/svn	(revision 4063)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/svn	(revision 4063)
@@ -0,0 +1,31 @@
+Subversion Repository 
+
+Anonymous access to our Subversion repository (SVN) is available. This means
+that users can have direct access to up-to-the-minute code.
+(http://subversion.tigris.org/)
+
+Driver development for 2.6 kernels is taking place directly in the kernel
+using GIT. Do not use the drivers from our SVN repository for 2.6 kernels, it
+will not work. The user-space tools will work though.
+
+We presume that you have Subversion installed on your machine. To check out a
+working copy of the code for this project use the following commands:
+
+svn checkout http://lm-sensors.org/svn/i2c/trunk i2c
+svn checkout http://lm-sensors.org/svn/lm-sensors/trunk lm-sensors
+
+To update the code, do a svn update from within the i2c or lm-sensors
+directories. Please read the README and INSTALL files of your working copy
+for how to build the code. Also read the related files in the 'doc' directory
+for info regarding the different bus and chip drivers. Lastly, you can use
+the regular svn commands on the files (like cvs log [filename]) to see the
+comments made by the developers as changes were made.
+
+If you're not familiar with the use of Subversion we recommend the excellent
+Subversion book which is a valuable resource.
+(http://svnbook.red-bean.com/)
+
+Commits to the repositories are notified on the lm-sensors-notify
+mailing-list. Feel free to subscribe if you want to be informed of the
+changes made to the i2c and lm-sensors repositories. 
+(http://lists.lm-sensors.org/mailman/listinfo/lm-sensors-notify)
Index: /lm-sensors/tags/V3-0-0-RC2/doc/FAQ
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/FAQ	(revision 4865)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/FAQ	(revision 4865)
@@ -0,0 +1,1577 @@
+Short Contents
+**************
+
+lm_sensors
+1 PC and Sensor Overview
+2 Sensor and Bus Basics
+3 Installation and Management
+4 Problems
+5 How to Ask for Help
+6 How to Contribute
+Appendix A Revision History of This Document
+
+
+Table of Contents
+*****************
+
+lm_sensors
+1 PC and Sensor Overview
+  1.1 What sensors are available on my PC?
+  1.2 What can a sensor chip like the "LM78" do?
+  1.3 Where do I find out more about any of these chips?
+2 Sensor and Bus Basics
+  2.1 How are these sensors read?
+  2.2 What is the SMBus? And the I2C bus?
+  2.3 I don't have an ISA bus!
+  2.4 What sensors do processors have?
+  2.5 How often are the sensor values updated?
+  2.6 How are alarms triggered?
+3 Installation and Management
+  3.1 Why so many modules, and how do I cope with them?
+  3.2 How do I know which chips I own?
+    3.2.1 What chips are on motherboard XYZ?
+    3.2.2 Do you support motherboard XYZ?
+    3.2.3 Do you support chip XYZ?
+    3.2.4 Anybody working on a driver for chip XYZ?
+  3.3 Which modules should I insert?
+  3.4 Do I need the configuration file `/etc/sensors.conf'?
+    3.4.1 The labels for the voltage and temperature readings in `sensors' are incorrect!
+    3.4.2 The min and max for the readings in `sensors' are incorrect!
+    3.4.3 The min and max settings in `/etc/sensors.conf' didn't take effect!
+    3.4.4 One sensor isn't hooked up on my board!
+    3.4.5 I need help with `sensors.conf'!
+    3.4.6 Do you have a database of `sensors.conf' entries for specific boards?
+  3.5 What about the `No such file or directory' warnings when I compile?
+  3.6 I get all kinds of weird compilation errors?
+    3.6.1 `No rule to make target xxxx needed by xxxx' - how to fix?
+  3.7 It still does not compile or patch!
+  3.8 `make install' fails on Mandrake kernels
+  3.9 I get unresolved symbols when I `modprobe' modules (Red Hat especially)
+  3.10 I2C_DRIVERID_ADM1024 undefined (Red Hat especially)
+4 Problems
+  4.1 My fans report exactly half/double their values compared to the BIOS?
+    4.1.1 Fans sometimes/always read 0!!
+    4.1.2 I doubled the fan divisor and the fan still reads 7000!
+  4.2 Why do my two LM75's report "-48 degrees"?
+  4.3 Why do I have two Vcore readings, I have only one processor!
+  4.4 How do those ALARMS work? The current value is within range but there is still an ALARM warning!
+  4.5 My voltage readings seem to drift a bit. Is something wrong?
+  4.6 Some measurements are way out of range. What happened?
+    4.6.1 -5V and -12V readings are way out of range!
+  4.7 What are VID lines? Why is the VID reading wrong?
+  4.8 I read sensor values several times a second, but they are only updated only each second or so. Why?
+  4.9 It sometimes seems to take almost a second before I see the sensor reading results. Why?
+  4.10 Can I be alerted when an ALARM occurs?
+  4.11 SMBus transactions on my PIIX4 simply don't work (timeouts happen).  Why?
+  4.12 My BIOS reports a much higher CPU temperature than your modules!
+  4.13 I try to read the raw `/proc' files, but the values are strange?!?
+  4.14 How do I set new limits?
+    4.14.1 I set new limits and it didn't work?
+  4.15 Some sensors are doubly detected?
+  4.16 I ran sensors-detect, but now I get very strange readings?!?
+  4.17 Bad readings from particular chips
+    4.17.1 Bad readings from the AS99127F!
+    4.17.2 Bad readings from the VIA 686A!
+    4.17.3 Bad readings from the MTP008!
+    4.17.4 Bad temperature readings from the SIS5595!
+    4.17.5 Bad readings from a w8378[12]d!
+    4.17.6 Bus hangs on Ali 1543 on Asus P5A boards!
+    4.17.7 Bad readings from LM75!
+    4.17.8 Bad readings from LM78!
+    4.17.9 Bad readings from LM80!
+  4.18 How do I configure two chips (LM87) differently?
+  4.19 Dmesg says `Upgrade BIOS'! I don't want to!
+    4.19.1 Dmesg says `use force_addr=0xaddr'! What address do I use?
+  4.20 Sensors says `Can't access procfs/sysfs file'
+  4.21 Sensors says `No sensors found!'
+  4.22 Sensors output is not correct!
+  4.23 What is at I2C address XXX?
+    4.23.1 What is at I2C address 0x69?
+    4.23.2 What is at I2C addresses 0x50 - 0x57?
+    4.23.3 What is at I2C addresses 0x30 - 0x37?
+  4.24 Sensors-detect doesn't work at all
+    4.24.1 Sensors-detect says "Couldn't open /proc/bus/i2c?!?"
+    4.24.2 Sensors-detect says "Can't open /dev/i2c[-/]0"
+    4.24.3 Sensors-detect doesn't find any sensors!
+  4.25 Sensors says `Error: Line xxx: zzzzzzz'
+  4.26 Sensors only gives the name and adapter for my chip
+  4.27 Sensors says `ERROR: Can't get xxxxx data!'
+  4.28 Sensors doesn't find any sensors, just eeproms.
+  4.29 Inserting modules hangs my board
+  4.30 Inserting modules slows down my board
+  4.31 Problems on particular motherboards
+    4.31.1 Asus P4B
+    4.31.2 Tyan 2460, 2462
+    4.31.3 Tyan 2466
+    4.31.4 Tyan 2688
+  4.32 Problems on 2.6 kernels
+    4.32.1 i2c-viapro and via686a
+    4.32.2 Where are my EEPROMs?
+5 How to Ask for Help
+  5.1 What to send us when asking for help
+  5.2 What to do if a module won't insert?
+  5.3 What to do if it inserts, but nothing happens?
+  5.4 What to do if I read only bogus information?
+  5.5 What to do if you have other problems?
+  5.6 What if it just works like a charm?
+  5.7 How do I update a ticket?
+  5.8 How do I follow up on a ticket?
+  5.9 Why did you decide not to support undocumented chips?
+6 How to Contribute
+  6.1 How to write a driver
+  6.2 How to get SVN access
+  6.3 How to donate hardware to the project
+  6.4 How to join the project mailing lists
+  6.5 How to access mailing list archives
+  6.6 How to submit a patch
+  6.7 How to REALLY help
+  6.8 How to get release announcements
+Appendix A Revision History of This Document
+
+
+lm_sensors
+**********
+
+The lm_sensors package includes a collection of modules for general
+SMBus access and hardware monitoring.  NOTE: this requires special
+support which is not in standard 2.2-vintage kernels.
+
+1 PC and Sensor Overview
+************************
+
+1.1 What sensors are available on my PC?
+========================================
+
+Most PC's built since late 1997 now come with a hardware health
+monitoring chip. This chip may be accessed via the ISA bus or the
+SMBus, depending on the motherboard.
+
+   Some motherboard chipsets, notably the Via 686 and the SiS 5595,
+contain hardware monitor functions.
+
+   This FAQ frequently refers to the "LM78". This chip has been
+obsoleted by National Semiconductor. Most motherboards today contain a
+chip with similar functions.
+
+1.2 What can a sensor chip like the "LM78" do?
+==============================================
+
+The LM78 is a chip made by National Semiconductor which can monitor 7
+voltages (5 positive, 2 negative) from 0 to 4.08V.  The inputs are
+usually in series with voltage dividers which lower the +/- 12V and +/-
+5V supplies to measurable range.  Therefore, the readings for such
+inputs need to be re-scaled appropriately by software.
+
+   The LM78 also has 3 fan speed monitoring inputs, an internal
+temperature sensor, a chassis intrusion sensor, and a couple maskable
+interrupt inputs.  The LM78 can also relay the processor's (P6 or Pent
+II) VID lines which are hardwired and used to indicate to the power
+regulator (usually on the mainboard close to the processor socket/slot)
+what voltage to supply to the processor.
+
+   The LM78 can be interfaced to a system via the ISA bus and/or the
+SMBus.
+
+   Most other sensor chips have comparable functionality. Each supported
+chip is documented in the `doc/chips' directory.
+
+1.3 Where do I find out more about any of these chips?
+======================================================
+
+Most semiconductor companies have comprehensive documentation,
+including complete datasheets, on their websites. Analog Devices,
+Dallas Semiconductor, Maxim, and National Semiconductor have the widest
+selection of sensor chips. Their websites are:
+
+   * `http://www.analog.com'
+
+   * `http://www.dalsemi.com'
+
+   * `http://www.maxim-ic.com'
+
+   * `http://www.national.com'
+
+   Please see the file `http://www.lm-sensors.org/wiki/UsefulLinks' for
+links to other companies' websites.
+
+2 Sensor and Bus Basics
+***********************
+
+2.1 How are these sensors read?
+===============================
+
+Sensor chips reside on either the ISA bus, the SMBus, or both.  See the
+file `doc/chips/SUMMARY' in our package for a list.
+
+   To communicate with chips on the ISA bus, the software uses simple
+I/O reads and writes.
+
+   To communicate with chips on the SMBus, the software must use an
+SMBus interface device, explained below.
+
+2.2 What is the SMBus? And the I2C bus?
+=======================================
+
+The SMBus is the "System Management Bus".  More specifically, it is a
+2-wire, low-speed serial communication bus used for basic health
+monitoring and hardware management. It is a specific implementation of
+the more general I2C (pronunciation: I-squared-C) bus. In fact, both
+I2C devices and SMBus devices may be connected to the same (I2C) bus.
+
+   The SMBus (or I2C bus) starts at the host controller, used for
+starting transactions on the SMBus.  From the host interface, the
+devices communicated with are the "slave" devices.  Each slave device
+has a unique 7-bit address which the host uses to refer to that device.
+
+   For each supported SMBus host, there is a separate kernel module
+which implements the communication protocol with the host. Some SMBus
+hosts really operate on the SMBus level; these hosts can not cope with
+pure I2C devices. Other hosts are in fact I2C hosts: in this case, we
+implement the SMBus protocol in terms of I2C operations. But these
+hosts can also talk to pure I2C devices.
+
+2.3 I don't have an ISA bus!
+============================
+
+We promise, you do, even if you don't have any old ISA slots.  The "ISA
+Bus" exists in your computer even if you don't have ISA slots; it is
+simply a memory-mapped area, 64KB in size (0x0000 - 0xFFFF) where many
+"legacy" functions, such as keyboard and interrupt controllers, are
+found. It isn't necessarily a separate physical bus.  See the file
+`/proc/ioports' for a list of devices living on the "ISA Bus" in your
+system. If you don't like the term "ISA Bus" think "I/O Space".
+
+2.4 What sensors do processors have?
+====================================
+
+Most new processors contain a thermal diode on the die itself.  The
+electical properties of all diodes and transistors vary slightly with
+temperature. The thermal diode is exceptionally accurate because it is
+directly on the die. Newer temperature sensor chips, like the Analog
+Devices ADM1021 and clones, and the Winbond chips, have circuitry for
+measuring the the electrical properties of an external diode and
+converting this data to a temperature.  Any sensor chip listed in
+`doc/chips/SUMMARY' in our package which has support for more than one
+temperature supports external temperature sensing.
+
+   Older motherboards and processors without this feature generally use
+an LM75 placed close to the processor. This is much less accurate.
+
+   The Pentium 2 'boxed' processor usually has an LM75 very close to the
+base of the box. It can be read through the SMBus to report the
+approximate temperature of the processor.  The processor also contains
+an internal temperature sensor (of low accuracy) used as a fail-safe to
+disable the processor in case it gets much too hot (usually around 130
+degrees C).  And, the Pentium 2 also has a hard-wired signal (VID
+lines) on it's SEC (single edge connector) which indicates what power
+supply is required to operate the processor.
+
+   The P6 (Pentium-Pro) may have an LM75 in or just under the socket.
+P6's also have VID lines.
+
+   Pentiums and Pentium w/ MMX do not have VID lines, and sometimes have
+LM75's under the sockets (depends on the mainboard, and how 'modern' the
+mainboard is).
+
+   The P2 Xeon was the first Intel processor to include the SMBus
+interface on the P2 Xeon SEC.
+
+2.5 How often are the sensor values updated?
+============================================
+
+The LM78, and most other sensor chips like it, reads its sensors one by
+one. A complete scanning sweep will take about 1.5 seconds. The LM78
+stops readings sensors if you try to access it, so if you access it
+very often (by reading sensor values; writing new limits is safe) it
+will not find the time to update its sensor values at all! Fortunately,
+the kernel module takes care not to do this, and only reads new values
+each 1.5 seconds. If you read the values again, you will get the 'old'
+values again.
+
+2.6 How are alarms triggered?
+=============================
+
+It is possible to monitor each sensor and have an alarm go off if it
+crosses some pre-determined limits.  There are two sorts of interrupts
+which can be generated by sensor chips if this happens (it depends a
+bit on the actual chip if both are supported; the LM80, for example,
+has only IRQ interrupts): IRQ interrupts and SMI interrupts.  IRQ
+stands for Interrupt Request and are the interrupt lines you can find
+in `/proc/interrupts'.  SMI stands for System Management Interrupt, and
+is a special interrupt which puts the processor in a secure environment
+independent of any other things running.  SMI is currently not
+supported by the Linux kernel.  IRQs are supported, of course.
+
+   Even if no interrupt is generated, some bits in a status register
+will be set until the register is read the next time. If the alarm
+condition persists after that, the bits will be set on the next
+scanning sweep, etc.
+
+   Most drivers in our package do not support interrupts at this time.
+
+3 Installation and Management
+*****************************
+
+3.1 Why so many modules, and how do I cope with them?
+=====================================================
+
+We tried to make this package as modular as possible. This makes it
+easy to add new drivers, and unused drivers will take no precious kernel
+space. On the other hand, it can be a bit confusing at first.
+
+   Here are two simple guidelines:
+   * Run `sensors-detect' and do what it tells you.
+
+   * Always use `modprobe', not `insmod'.
+
+   Further information is in `doc/modules'.
+
+3.2 How do I know which chips I own?
+====================================
+
+We have an excellent program that scans all your hardware.  It is
+called `sensors-detect' and is installed in `/usr/local/sbin' by `make
+install'. Just execute this script, and it will tell you.
+
+   Chip detection in the drivers is fairly good. That means that it is
+usually harmless to insert more chip drivers than you need. However,
+this can still lead to problems, so we do not recommend it.
+
+   If sensors-detect didn't find any sensors, either you don't have
+any, or the ones you have, we don't support. (Look at your motherboard
+for candidates, then *note Help::)
+
+3.2.1 What chips are on motherboard XYZ?
+----------------------------------------
+
+*!!!!!!!!! YES THIS IS THE MOST FREQUENT QUESTION WE GET !!!!!!!!!*
+
+   We have no idea. Here is what you should do:
+  1. Run sensors-detect.
+
+   If that doesn't work:
+  2. Look at your motherboard.
+
+  3. Check the manufacturer's website or ask their support
+
+  4. Check the "links" (http://www.lm-sensors.org/wiki/UsefulLinks)
+     page on our website (http://www.lm-sensors.org) some good
+     cross-references.
+
+3.2.2 Do you support motherboard XYZ?
+-------------------------------------
+
+We don't support boards, we support chips. *Note What chips are on
+motherboard XYZ: Section 3.2.1.
+
+3.2.3 Do you support chip XYZ?
+------------------------------
+
+This we have good answers for.
+   * Sorted by Manufacturer:   `README'
+
+   * Sorted by Manufacturer:   `http://www.lm-sensors.org/wiki/Devices'
+
+   * Sorted by Sensor Driver:  `doc/chips/SUMMARY'
+
+3.2.4 Anybody working on a driver for chip XYZ?
+-----------------------------------------------
+
+Newest Driver Status: `http://www.lm-sensors.org/wiki/Devices'
+
+3.3 Which modules should I insert?
+==================================
+
+`sensors-detect' will tell you. Take the `modprobe' lines it recommends
+and paste them into the appropriate `/etc/rc.d/xxxx' file to be
+executed at startup.
+
+   You need one module for each sensor chip and bus adapter you own; if
+there are sensor chips on the ISA bus, you also need `i2c-isa.o'.  for
+each type of chip you own. That's all. On my computer, I could use the
+following lines:
+   * `modprobe i2c-isa'
+
+   * `modprobe i2c-piix4'
+
+   * `modprobe lm78'
+
+   * `modprobe lm75'
+
+   * `modprobe i2c-dev'
+
+   * `sensors -s'
+
+3.4 Do I need the configuration file `/etc/sensors.conf'?
+=========================================================
+
+Yes, for any applications that use `libsensors,' including the
+`sensors' application included in our package.  It tells libsensors how
+to translate the values the chip measures to real-world values. This is
+especially important for voltage inputs. The default configuration file
+should usually do the trick.  It is automatically installed as
+`/etc/sensors.conf', but it will not overwrite any existing file with
+that name.
+
+3.4.1 The labels for the voltage and temperature readings in `sensors' are incorrect!
+-------------------------------------------------------------------------------------
+
+Every motherboard is different. You can customize the labels in the
+file `/etc/sensors.conf'. That's why it exists!  The default labelling
+(in `lib/chips.c' and `/etc/sensors.conf') is just a template.
+
+3.4.2 The min and max for the readings in `sensors' are incorrect!
+------------------------------------------------------------------
+
+You can customize them in the file `/etc/sensors.conf'. See above.
+
+3.4.3 The min and max settings in `/etc/sensors.conf' didn't take effect!
+-------------------------------------------------------------------------
+
+You forgot to run `sensors -s'. See above.
+
+3.4.4 One sensor isn't hooked up on my board!
+---------------------------------------------
+
+Use an `ignore' line in `/etc/sensors.conf' so it isn't displayed in
+`sensors'.
+
+3.4.5 I need help with `sensors.conf'!
+--------------------------------------
+
+There is detailed help at the top of that file.
+
+3.4.6 Do you have a database of `sensors.conf' entries for specific boards?
+---------------------------------------------------------------------------
+
+No. Good idea though. If you would like to set one up on your website
+send us mail and we will set up a link to it.
+
+3.5 What about the `No such file or directory' warnings when I compile?
+=======================================================================
+
+Don't worry about them. The dependency files (which tell which files
+should be recompiled when certain files change) are created
+dynamically. They are not distributed with the package. The `make'
+program notices they are not there, and warns about that - and the
+first thing it will do is generate them. So all is well.
+
+3.6 I get all kinds of weird compilation errors?
+================================================
+
+Check that the correct i2c header files are used. Depending on how you
+installed, they should be under either `/usr/local/include' or
+`/usr/src/linux*/include'. Try to edit the `Makefile' for the other
+setting.
+
+3.6.1 `No rule to make target xxxx needed by xxxx' - how to fix?
+----------------------------------------------------------------
+
+   * *Note I get all kinds of weird compilation errors: Section 3.6,
+     also try `make clean' in `lm_sensors'.
+
+   * If that doesn't work, try `make clean' in `i2c'.
+
+   * If that doesn't work, try `make clean' in the kernel.
+
+   * Also make sure `/usr/include/linux' points to
+     `/usr/src/linux/include/linux'.
+
+3.7 It still does not compile or patch!
+=======================================
+
+Have you installed the matching version of the i2c package? Remember,
+compilation is not enough, you also need to install it for the header
+files to be found!
+
+   If you want to patch the kernel, you will have to apply the i2c
+patches first!
+
+3.8 `make install' fails on Mandrake kernels
+============================================
+
+Mandrake uses a non-standard `version.h' file which confuses our
+`Makefile'.  Edit our `Makefile' on the `MODDIR :=' line to hard-code
+the module directory.
+
+3.9 I get unresolved symbols when I `modprobe' modules (Red Hat especially)
+===========================================================================
+
+Example:
+     *** Unresolved symbols in /lib/modules/2.4.5/kernel/drivers/i2c/i2c-i810.o
+     i2c_bit_add_bus_R8c3bc60e
+     i2c_bit_del_bus_R92b18f49
+
+   You can also run `depmod -a -e' to see all unresolved symbols.
+
+   These are module versioning problems. Generally you did not compile
+against the kernel you are running. Sometimes the Red Hat source you
+have is not for the kernel you are running.  You must compile our
+package against the source for the kernel you are running with
+something like `make LINUX=/usr/src/linux-2.4.14'.
+
+   Try the following to be sure:
+
+   * `nm --extern MODULE.o' Filter out the kernel symbols, like
+     `kmalloc', `printk' etc. and note the number code behind them,
+     like `printk_R1b7d4074'. If there is no numeric code after them,
+     note this too.
+
+   * `grep SYMBOL /proc/ksyms' Substitute SYMBOL by the basename of the
+     symbols above, like `kmalloc', `printk' etc. Note the number code
+     behind them, or the lack thereof.
+
+   * Compare both sets of symbols. Are they the same? If so, the problem
+     lies somewhere else. Are they different? If so, you have a module
+     versioning problem.
+
+3.10 I2C_DRIVERID_ADM1024 undefined (Red Hat especially)
+========================================================
+
+In some versions of Redhat, an RPM is included to provide i2c support.
+However, this RPM does not place the header files in the kernel
+directory structure.  When you update kernels, they may persist.  To
+get rid of these obsolete header files, at a command prompt:
+
+  1. `rpm -qa | grep i2c'
+
+  2. Look for `kernel-i2c,' or a similar rpm in the output
+
+  3. <as root> `rpm -ev kernel-i2c' (or the name of the similar package)
+     If this complains about dependencies, you can try adding
+     `--nodeps', but this *MAY* break something else.  Not likely, as
+     you have upgraded kernels, and nothing should be using the old i2c
+     stuff anymore anyway.  Just don't use it with abandon.
+
+  4. Try (in the build directory of `lm_sensors)'
+          `make clean'
+          `make'
+
+  5. _If_ you still have problems, you may have to replace the include
+     paths in the `.c/.h' files with absolute paths to the header files.
+     More of a workaround than a real fix, but at least you can get it
+     to work.
+
+4 Problems
+**********
+
+4.1 My fans report exactly half/double their values compared to the BIOS?
+=========================================================================
+
+The problem with much of the sensor data is that it is impossible to
+properly interpret some of the readings without knowing what the
+hardware configuration is.  Some fans report one 'tick' each rotation,
+some report two 'ticks' each rotation. It is easy to resolve this
+through the configuration file `/etc/sensors.conf':
+
+     chip lm78-*             # Or whatever chip this relates to
+     compute fan1 2*@,@/2    # This will double the fan1 reading
+                             # -- or --
+     compute fan1 @/2,2*@    # This will halve the fan1 reading
+
+   See `doc/fan-divisors' in our package for further information.
+
+4.1.1 Fans sometimes/always read 0!!
+------------------------------------
+
+You may not have a three-wire fan, which is required.
+
+   You may need to increase the 'fan divisor'. See `doc/fan-divisors'
+in our package for further information.
+
+4.1.2 I doubled the fan divisor and the fan still reads 7000!
+-------------------------------------------------------------
+
+Believe it or not, doubling the 'fan divisor' will not halve the fan
+reading. You have to add a compute line in `/etc/sensors.conf'.  *Note
+My fans report exactly half/double their values compared to the BIOS:
+Section 4.1, and see `doc/fan-divisors' in our package for further
+information.
+
+4.2 Why do my two LM75's report "-48 degrees"?
+==============================================
+
+For starters, those aren't LM75's.  Your mainboard actually has the
+Winbond W83781D which emulates two LM75's, but many systems which use
+the Winbond chip (such as the Asus P2B) don't have the thermo-resisters
+connected to the chip resulting in these strange -48 degree readings.
+
+   In upcoming versions, you will be able to disable non-interesting
+readings.
+
+4.3 Why do I have two Vcore readings, I have only one processor!
+================================================================
+
+The LM78 has seven voltage sensors. The default way of connecting them
+is used in the configuration file. This includes a VCore2, even if you
+do not have one. You can easily edit the configuration file to give it
+another name, or make this reading disappear using an `ignore' line.
+
+   Note that Vcore2 is often the same as Vcore on motherboards which
+only support one processor. Another possibility is that Vcore2 is not
+connected at all and will not have a valid reading at all.  A third
+possibility, is that Vcore2 monitors something else, so you should not
+be too surprised if the values are completely different.
+
+4.4 How do those ALARMS work? The current value is within range but there is still an ALARM warning!
+====================================================================================================
+
+The ALARM indications in `sensors' are those reported by the sensor
+chip itself. They are NOT calculated by `sensors'. `sensors' simply
+reads the ALARM bits and reports them.
+
+   An ALARM will go off when a minimum or maximum limit is crossed.
+The ALARM is then latched - that is, it will stay there until the
+chip's registers are next accessed - which will be the next time you
+read these values, but not within (usually) 1.5 seconds since the last
+update.
+
+   Reading the registers clears the ALARMS, unless the current value is
+still out of range.
+
+   The purpose of this scheme is to tell you if there has been a
+problem and report it to the user. Voltage or temperature spikes get
+detected without having to read the sensor chip hundreds of times a
+second. The implemetation details depend a bit on the kind of chip.
+See the specific chip documentation in `doc/chips' and the chip
+datasheet for more information.
+
+4.5 My voltage readings seem to drift a bit. Is something wrong?
+================================================================
+
+No, probably not. If your motherboard heats up a bit, the sensed
+voltages will drift a bit. If your power supply is loaded (because a
+disk gets going, for example), the voltages may get a bit lower. Heavy
+processor activity, in particular, dramatically increases core voltage
+supply load which will often cause variation in the other supplies.  As
+long as they stay within a sensible range (say 5% of the nominal value
+for CPU core voltages, and 10% for other voltages), there is no reason
+to worry.
+
+4.6 Some measurements are way out of range. What happened?
+==========================================================
+
+Each module tries to set limits to sensible values on initialization,
+but a module does not know how a chip is actually connected. This is
+described in the configuration file, which is not read by kernel
+modules.  So limits can be strange, if the chip is connected in a
+non-standard way.
+
+   Readings can also be strange; there are several reasons for this.
+Temperature sensors, for example, can simply not be present, even though
+the chip supports them. Also, it can be that the input is used in a
+non-standard way. You can use the configuration file to describe how
+this measurement should be interpreted; see the comments the example
+file for more information.
+
+4.6.1 -5V and -12V readings are way out of range!
+-------------------------------------------------
+
+It's very frequent that negative voltage lines are not wired because
+motherboard manufacturers don't think they're worth monitoring (they
+are mostly unused these days). You can just add `ignore inN' lines to
+`/etc/sensors.conf' to hide them.
+
+   Another possibility is that these lines are used to monitor different
+voltages. Only the motherboard manufacturer can tell for sure. Taking a
+look at what voltage values the BIOS displays may provide valuable
+hints though.
+
+4.7 What are VID lines? Why is the VID reading wrong?
+=====================================================
+
+These describe the core voltage for your processor. They are supported
+for most processors, however they are not always correctly connected to
+the sensor chip, so the readings may be invalid.  A reading of 0V,
++3.5V or +2.05V is especially suspect.  If this is the case, add a line
+`ignore vid' to `/etc/sensors.conf', and change the min and max
+settings for the Processor Core voltage (often in0_min and in0_max) in
+that file so that they don't depend on vid.
+
+   The CPU nominal voltage is computed from VID lines according to a
+formula that depends on the CPU type. Since Linux 2.6.9, the right
+formula is selected automatically.  See `doc/vid' for more information.
+
+4.8 I read sensor values several times a second, but they are only updated only each second or so. Why?
+=======================================================================================================
+
+If we would read the registers more often, it would not find the time
+to update them. So we only update our readings once each 1.5 seconds
+(the actual delay is chip-specific; for some chips, it may not be needed
+at all).
+
+4.9 It sometimes seems to take almost a second before I see the sensor reading results. Why?
+============================================================================================
+
+ISA bus access is fast, but SMBus access is really slow. If you have a
+lot of sensors, it just takes a lot of time to access them. Fortunately,
+this has almost no impact on the system as a whole, as another job can
+run while we are waiting for the transaction to finish.
+
+4.10 Can I be alerted when an ALARM occurs?
+===========================================
+
+No, you can't; and it may well be never supported.
+
+   Almost no mainboard we have encountered have actually connected the
+IRQ-out pin of sensor chips. That means that we could enable IRQ
+reporting, but nothing would happen. Also, even if a motherboard has it
+connected, it is unclear what interrupt number would be triggered. And
+IRQ lines are a scarce facility, which means that almost nobody would
+be able to use it anyway.
+
+   The SMI interrupt is only available on a few types of chips. It is
+really a very obscure way to handle interrupts, and supporting it under
+Linux might be quite hard to do.
+
+   Your best bet would be to poll the alarm file with a user-land daemon
+which alerts you if an alarm is raised. I am not aware of any program
+which does the job, though you might want to examine one of the
+graphical monitor programs under X, see
+`http://www.lm-sensors.org/wiki/UsefulLinks' for addresses.
+
+4.11 SMBus transactions on my PIIX4 simply don't work (timeouts happen).  Why?
+==============================================================================
+
+Some chips which mainboard makers connect to the SMBus are not SMBus
+devices.  An example is the 91xx clock generator chips.  When read,
+these devices can lock up the SMBus until the next hard reboot.  This
+is because they have a similar serial interface (like the I2C), but
+don't conform to Intel's SMBus standard.
+
+   Why did they connect these devices to the SMBus if they aren't
+compatible?  Good question! :')  Actually, these devices may support
+being written to, but lock things up when they are read.
+
+4.12 My BIOS reports a much higher CPU temperature than your modules!
+=====================================================================
+
+We display the actual temperature of the sensor. This may not be the
+temperature you are interested in, though.  If a sensor should measure
+the CPU temperature, it must be in thermal contact with it.  In
+practice, it may be just somewhere nearby. Your BIOS may correct for
+this (by adding, for example, thirty degrees to the measured
+temperature).  The correction factor is regrettably different for each
+mainboard, so we can not do this in the module itself. You can do it
+through the configuration file, though:
+
+     chip lm75-*-49                      # Or whatever chip this relates to
+     label temp "Processor"
+     compute temp @*1.2+13,(@-13)/1.2    # Or whatever formula
+
+   However, the offset you are introducing might not be necessary. If
+you tried to have Linux idle temperature and BIOS "idle" temperature
+match, you may be misguided.  We have a Supermicro (370DLE) motherboard
+and we know that its BIOS has a closed, almost undelayed while(1) loop
+that keeps the CPU busy all the time. Linux reads 26 degrees idle, BIOS
+reads 38 degrees. Linux at full load is in the 35-40 degrees range so
+this makes sense.
+
+4.13 I try to read the raw `/proc' files, but the values are strange?!?
+=======================================================================
+
+Remember, these values do not take the configuration file `compute'
+lines in account. This is especially obvious for voltage readings
+(usually called in? or vin?). Use a program linked to libsensors (like
+the provided `sensors' program) instead.
+
+4.14 How do I set new limits?
+=============================
+
+Change the limit values in `/etc/sensors.conf' and then run `sensors
+-s'.
+
+4.14.1 I set new limits and it didn't work?
+-------------------------------------------
+
+You forgot to run `sensors -s'. Put it in a `/etc/rc.d/...' file after
+the modprobe lines to run at startup.
+
+4.15 Some sensors are doubly detected?
+======================================
+
+Yes, this is still a problem. It is partially solved by alias detection
+and confidence values in sensors-detect, but it is really tough.
+
+   Double detections can be caused by two things: sensors can be
+detected to both the ISA and the SMBus (and if you have loaded the
+approprate adapter drivers, it will be detected on both), and some
+chips simulate other chips (the Winbond W83781D simulates LM75 chips on
+the SMBus, for example). Remove the offending adapter or chip driver, or
+run sensors-detect and add the `ignore=' modprobe parameters it
+suggests.
+
+4.16 I ran sensors-detect, but now I get very strange readings?!?
+=================================================================
+
+Your SMBus (PIIX4?) is probably crashed or hung. There are some
+mainboards which connect a clock chip to the SMBus. Unfortunately, this
+clock chip hangs the PIIX4 if it is read (it is an I2C device, but not
+SMBus compatible).  We have found no way of solving this, except for
+rebooting your computer.  Next time when you run sensors-detect, you
+may want to exclude addresses 0x69 and/or 0x6a, by entering `s' when
+you are asked whether you want to scan the PIIX4.
+
+4.17 Bad readings from particular chips
+=======================================
+
+See below for some particularly troublesome chips.  Also be sure and
+check `doc/chips/xxxxx' for the particular driver.
+
+4.17.1 Bad readings from the AS99127F!
+--------------------------------------
+
+The Asus AS99127F is a modified version of the Winbond W83781D.  Asus
+will not release a datasheet. The driver was developed by tedious
+experimentation. We've done the best we can. If you want to make
+adjustments to the readings please edit `/etc/sensors.conf.' Please
+don't ask us to fix the driver. Ask Asus to release a datasheet.
+
+4.17.2 Bad readings from the VIA 686A!
+--------------------------------------
+
+The Via 686A datasheet is incomplete.  Via will not release details.
+The driver was developed by tedious experimentation. We've done the
+best we can. If you want to make adjustments to the readings please
+edit `/etc/sensors.conf.' Please don't ask us to fix the driver. Ask
+Via to release a better datasheet.  Also, don't forget to `modprobe
+i2c-isa'.
+
+4.17.3 Bad readings from the MTP008!
+------------------------------------
+
+The MTP008 has programmable temperature sensor types.  If your sensor
+type does not match the default, you will have to change it.  See
+`doc/chips/mtp008' for details.  Also, MTP008 chips seem to randomly
+refuse to respond, for unknown reasons. You can see this as 'XX'
+entries in i2cdump.
+
+4.17.4 Bad temperature readings from the SIS5595!
+-------------------------------------------------
+
+This chip can use multiple thermistor types and there are also two
+different versions of the chip. We are trying to get the driver working
+better and develop formulas for different thermistors but we aren't
+there yet. Sorry.  Also, many times the chip isn't really a sis5595 but
+it was misidentified. We are working on improving that too.
+
+4.17.5 Bad readings from a w8378[12]d!
+--------------------------------------
+
+Do you own an ASUS motherboard?  Perhaps your chip is being
+misidentified.  Look on the motherboard for a 'Winbond' or Asus chip.
+Often the real device is an Asus as99127f. If so, the driver can be
+forced to recognize the as99127f with `force_as99127f=BUS,0x2d' where
+`BUS' is your i2c bus number.  Cat /proc/bus/i2c to see a list of bus
+numbers.  Read the w83781d module documentation (`doc/chips/w83781d')
+for more details.
+
+4.17.6 Bus hangs on Ali 1543 on Asus P5A boards!
+------------------------------------------------
+
+The SMBus tends to hang on this board and it seems to get worse at
+higher temperatures. Use ISA accesses to reliably use the w83781d
+monitor chip on this board and use the `ignore=1,0x2d' or similar option
+to the w83781d module to prevent i2c accesses.
+
+4.17.7 Bad readings from LM75!
+------------------------------
+
+The LM75 detection is poor and other hardware is often misdetected as
+an LM75. Figure out what you really have *Note What chips are on
+motherboard XYZ: Section 3.2.1.
+
+4.17.8 Bad readings from LM78!
+------------------------------
+
+The LM78 is no longer manufactured by National Semiconductor.  You
+probably don't have a real LM78 but something similar that we do not
+recogize or support. Figure out what you really have *Note What chips
+are on motherboard XYZ: Section 3.2.1.
+
+4.17.9 Bad readings from LM80!
+------------------------------
+
+The LM80 detection is poor and other hardware is often misdetected as
+an LM80. Figure out what you really have *Note What chips are on
+motherboard XYZ: Section 3.2.1.
+
+4.18 How do I configure two chips (LM87) differently?
+=====================================================
+
+There is a SuperMicro board with two LM87's on it that are not hooked
+up in the same way, so they need different defaults.  For example, both
+CPU temperatures go to one LM87.
+
+   Make two different sections in `/etc/sensors.conf' as follows:
+     chip "lm87-i2c-*-2c"
+         put configuration for the chip at 0x2c here
+     chip "lm87-i2c-*-2d"
+         put configuration for the chip at 0x2d here
+
+   There is a commented example in `sensors.conf.eg' which should be
+helpful.
+
+4.19 Dmesg says `Upgrade BIOS'! I don't want to!
+================================================
+
+If the problem is a PCI device is not present in `lspci', the solution
+is complex. For the ALI M7101 device, there is a solution which uses the
+2.4 kernel's `hotplug' facility. See `prog/hotplug' in our package.
+For other PCI devices, you can try to modify the m7101 solution in
+`prog/hotplug'.
+
+   If dmesg says `try force_addr', see below. Other drivers generally
+do not support the force_addr parameter. Sorry. Check the documentation
+for your driver in `doc/[chips,busses]' and if we don't support it you
+can send us your request.
+
+4.19.1 Dmesg says `use force_addr=0xaddr'! What address do I use?
+-----------------------------------------------------------------
+
+If the problem is a PCI device whose base address is not set, you may
+be able to set the address with a force parameter. The via686a and
+sis5595 chip drivers, and some bus drivers, support the command line
+`modprobe via686a force_addr=0xADDRESS' where ADDRESS is the I/O
+address. You must select an address that is not in use.  `cat
+`/proc/ioports'' to check (carefully) for conflicts. A high number like
+0xf000 is generally safe.
+
+4.20 Sensors says `Can't access procfs/sysfs file'
+==================================================
+
+   * Linux 2.6
+        * Did you `modprobe i2c_sensor'? Check `lsmod'.
+
+        * Do you have sysfs support in your kernel and `/sys' mounted
+          (is `/sys' there and populated)?  Create /sys with `mkdir
+          /sys' if needed. Then add the following line to `/etc/fstab':
+               sys              /sys             sysfs       default          0   0
+          and `mount /sys'.
+
+   * Linux 2.4
+        * Did you `modprobe i2c-proc'? Check `lsmod'.
+
+        * Do you have procfs support in your kernel and `/proc' mounted
+          (is `/proc' there and populated)?  Create /proc with `mkdir
+          /proc' if needed. Then add the following line to `/etc/fstab':
+               proc             /proc            proc        defaults         0   0
+          and `mount /proc'.
+
+   * If you did `sensors -s', did you run it as root?
+
+4.21 Sensors says `No sensors found!'
+=====================================
+
+   * Did `sensors-detect' find sensors? (If not *note Sensors-detect
+     doesnt find any sensors::)
+
+   * Did you do what `sensors-detect' said?
+
+   * Did you `modprobe' your sensor modules?
+
+   * Did you `modprobe' your I2C adapter modules?
+
+   * Did you `modprobe i2c-isa' if you have ISA sensor chips?
+
+   * Check `lsmod'.
+
+4.22 Sensors output is not correct!
+===================================
+
+What specifically is the trouble?
+   * Labels: *Note The labels for the voltage and temperature readings
+     in sensors are incorrect: Section 3.4.1.
+
+   * Min/max readings: *Note The min and max for the readings in
+     sensors are incorrect: Section 3.4.2, and *Note The min and max
+     settings didnt take effect: Section 3.4.3.
+
+   * AS99127F: *Note I ran sensors-detect but now I get very strange
+     readings?: Section 4.16.
+
+   * Via 686A: *Note I ran sensors-detect but now I get very strange
+     readings?: Section 4.16.
+
+   * Other specific chips: *Note I ran sensors-detect but now I get
+     very strange readings?: Section 4.16.
+
+   * No output for a particular sensors chip: *Note What to do if it
+     inserts but nothing happens: Section 5.3.
+
+   * No output at all: *Note Sensors says No sensors found: Section
+     4.21, *Note What to do if it inserts but nothing happens: Section
+     5.3.
+
+   * Completely bad output for a particular sensor chip: *Note What to
+     do if I read only bogus information: Section 5.4.
+
+   * One particular sensor readings:
+        * Maybe it isn't hooked up? - tell 'sensors' to ignore it.
+          *Note One sensor isnt hooked up on my board: Section 3.4.4.
+
+        * Maybe it is hooked up differently on your motherboard? -
+          adjust `sensors.conf' calculation.
+
+4.23 What is at I2C address XXX?
+================================
+
+In general, we don't know. Start by running `sensors-detect'.  If it
+doesn't recognize it, try running `i2cdump'. A partial list of
+manufacturers' IDs are at the bottom of `doc/chips/SUMMARY'.
+
+4.23.1 What is at I2C address 0x69?
+-----------------------------------
+
+A clock chip. Often, accessing these clock chips in the wrong way will
+instantly crash your computer. Sensors-detect carefully avoids these
+chips, and you should do too.  You have been warned.
+
+4.23.2 What is at I2C addresses 0x50 - 0x57?
+--------------------------------------------
+
+EEPROMs on your SDRAM DIMMs. Load the eeprom module and use the script
+`decode-dimms.pl' (in the i2c-tools package) to get more information
+than you ever wanted.
+
+4.23.3 What is at I2C addresses 0x30 - 0x37?
+--------------------------------------------
+
+These are often 'shadows' of your EEPROMs on your SDRAM DIMMs at
+addresses 0x50 - 0x57. They are the 'software write-protect' registers
+of the SDRAM Serial Presence Detect EEPROMs.  If you try and do a
+`i2cdump' on them to read the location, you won't get anything, because
+they contain a single write-only register.  This register can be used
+to permanently write-protect the contents of the eeprom.
+
+4.24 Sensors-detect doesn't work at all
+=======================================
+
+It could be many things. What was the problem? *Note Problems on
+particular motherboards: Section 4.31.
+
+4.24.1 Sensors-detect says "Couldn't open /proc/bus/i2c?!?"
+-----------------------------------------------------------
+
+You don't have i2c support in your kernel, or the i2c-core module was
+not loaded and you did not run sensors-detect as root.
+
+4.24.2 Sensors-detect says "Can't open /dev/i2c[-/]0"
+-----------------------------------------------------
+
+Your `/dev/i2c-0,' `/dev/i2c0', or `/dev/i2c/0' files do not exist or
+you did not run `sensors-detect' as root.  Use `MAKEDEV' or `mknod' to
+create the `/dev/i2c-x' files.  Run `devfs' in the kernel to get the
+`/dev/i2c/x' files.
+
+4.24.3 Sensors-detect doesn't find any sensors!
+-----------------------------------------------
+
+Either
+  1. The board doesn't have any sensors.
+
+  2. We don't support the sensors on the board.
+
+  3. The sensors it has are on an I2C bus connected to an I2C bus
+     adapter that we don't support.
+
+  4. You don't have the latest version of lm_sensors.
+
+   But in any case you should figure out what is on the board:
+  1. Look at your motherboard.
+
+  2. Check the manufacturer's website.
+
+   When you know what chips you have, check the Driver Status
+(http://www.lm-sensors.org/wiki/Devices) web page to see if support has
+been added for your chip in a later release or in SVN.
+
+4.25 Sensors says `Error: Line xxx: zzzzzzz'
+============================================
+
+These are errors from the libsensors library in reading the
+`/etc/sensors.conf' configuration file. Go to that line number and fix
+it. If you have a parse error, perhaps you have to put the feature name
+in double quotes.
+
+4.26 Sensors only gives the name and adapter for my chip
+========================================================
+
+If `sensors' only says this, for example, and doesn't provide any
+actual data at all:
+
+     it87-isa-0290
+     Adapter: ISA adapter
+
+   Your chip is not currently supported by `sensors' and so all it does
+is print out that information. Get the latest release and be sure you
+are running the `sensors' program it installed and not some older
+`sensors'.
+
+4.27 Sensors says `ERROR: Can't get xxxxx data!'
+================================================
+
+   * (Linux 2.6) Make sure you are using one of the recommended
+     kernel/lm_sensors combination
+     (http://www.lm-sensors.org/wiki/Kernel2.6).
+
+   * You have a `libsensors'/`sensors' mismatch.  `sensors' is unable to
+     get a data entry from `libsensors'. You probably have an old
+     `libsensors' in your `/etc/ld.so.conf' path.  Make sure you did
+     (as root) a `make install' (Linux 2.4) or `make user_install'
+     (Linux 2.6) followed by a `ldconfig'.  Then check the output of
+     `ldconfig -v | grep libsensors' to verify that there is only ONE
+     `libsensors' entry and that it matches the `libsensors' that was
+     built in the `lib/' directory in `lm_sensors2'.
+
+4.28 Sensors doesn't find any sensors, just eeproms.
+====================================================
+
+*Note Sensors-detect doesnt work at all: Section 4.24, if
+`sensors-detect' failed to find any sensors.
+
+   If `sensors-detect' did find sensors, did you insert your modules?
+For chips on the ISA bus, did you insert i2c-isa?
+
+   *Note What to do if a module wont insert: Section 5.2, if the
+modules didn't insert, also *Note Sensors says No sensors found:
+Section 4.21.
+
+4.29 Inserting modules hangs my board
+=====================================
+
+There are several possible causes:
+  1. Bus driver problems. Insert the bus driver first, before you have
+     inserted any chip drivers, to verify.
+
+  2. Wrong chip driver. Verify that you have a chip supported by the
+     chip driver, see *Note What chips are on motherboard XYZ: Section
+     3.2.1.
+
+  3. The chip driver is reinitializing the chip, which undoes critical
+     initialization done by the BIOS.  Try the parameter `init=0' for
+     the w83781d driver; this is the only driver supporting this
+     parameter.
+
+  4. Some chips on the bus don't like to be probed at all.  After
+     inserting the bus driver (but not the chip drivers), run
+     `i2cdetect' on the bus, then `i2cdump' on each address responding
+     to `i2cdetect'. This may find the culprit.  Do not `i2cdump
+     address 0x69', the clock chip.
+
+  5. The chip driver is incorrectly finding a second chip on the bus
+     and is accessing it. For example, with the Tyan 2688 with a
+     w83781d at 0x29, use `modprobe
+     ignore_range=0,0x00,0x28,0,0x2a,0x7f' to prevent access to other
+     addresses. (`init=0' also req'd for the Tyan 2688).
+
+4.30 Inserting modules slows down my board
+==========================================
+
+Generally this is caused by an overtemperature alarm output from the
+sensor chip. This triggers hardware on the board which automatically
+slows down the CPU clock. Be sure that your temperature limits are
+above the temperature reading. Put the new limits in
+`/etc/sensors.conf' and run `sensors -s'.
+
+4.31 Problems on particular motherboards
+========================================
+
+The following boards have unique problems and solutions.
+
+4.31.1 Asus P4B
+---------------
+
+See `prog/hotplug/README.p4b' if your SMBus master is not found.
+
+4.31.2 Tyan 2460, 2462
+----------------------
+
+See support tickets 805, 765, 781, 812, 813, and 867 for information.
+
+4.31.3 Tyan 2466
+----------------
+
+See support tickets 941, 840, and 841 for information.
+
+4.31.4 Tyan 2688
+----------------
+
+For board hangs, see support ticket 721 for information.  Also *Note
+Inserting modules hangs my board: Section 4.29.
+
+4.32 Problems on 2.6 kernels
+============================
+
+Not all drivers have been ported to 2.6. If your favorite driver is not
+in 2.6, the reason is that nobody has ported it, or the ported code did
+not get a proper review yet.  If you would like to port the driver, see
+the file Documentation/i2c/porting-clients in the 2.6 kernel tree for
+help, then send us the ported driver when you are done.
+
+4.32.1 i2c-viapro and via686a
+-----------------------------
+
+Until kernel 2.6.11, there was a PCI resource conflict between
+i2c-viapro (the SMBus driver for VIA bridges) and via686a (the
+integrated sensors driver for VIA bridges). This caused the second
+loaded driver to silently fail working. So do not load both i2c-viapro
+and via686a together unless you have a recent kernel.
+
+4.32.2 Where are my EEPROMs?
+----------------------------
+
+The 2.6.14-rc1 kernel introduced the hwmon class, which groups all
+hardware monitoring drivers in a logical way. The goal was to help
+libsensors grab the relevant sensors information in /sys. In particular:
+   * libsensors will no more need to know about the underlying bus types
+     (I2C/SMBus, ISA or other);
+
+   * libsensors will no more list non-hardware monitoring chips.
+   This explains why EEPROMs are no more displayed by `sensors': they
+are no hardware monitoring chips. The medium term plan is to drop
+eeprom support for all Linux 2.6 kernels, as it didn't fit well in the
+library code in the first place.
+
+   Note that you can still obtain information about your EEPROMs by
+using the dedicated perl scripts in the i2c-tools package: `ddcmon',
+`decode-dimms.pl', `decode-edid.pl' and `decode-vaio.pl'.
+
+5 How to Ask for Help
+*********************
+
+5.1 What to send us when asking for help
+========================================
+
+We are always willing to answer questions if things don't work out.
+Post your question to our discussion list
+(http://lists.lm-sensors.org/mailman/listinfo/lm-sensors), and not the
+individual authors, unless you have something private to say.
+
+   Instead of using email, you can also use the web-based support area,
+at `http://www.lm-sensors.org/wiki/FeedbackAndSupport'. You will be
+helped just as fast, and others may profit from the answer too. You
+will be emailed automatically when your question has been answered.
+
+   Here's what you should send us:
+
+   * The dmesg or syslog output if applicable
+
+   * The output of (as root) `prog/detect/sensors-detect'
+
+   * The output of `lsmod'
+
+   * If a PCI chip problem:
+        * The output of `lspci -n'
+
+   * If an I2C sensor chip problem:
+        * The output of (as root) `prog/detect/i2cdetect X' where X =
+          the bus number (run `i2cdetect' with no arguments to list the
+          busses) (please send this only if it's not all `XX')
+
+        * The output of (as root) `prog/dump/i2cdump X 0xXX' where XX =
+          the address of each chip you see in the output of
+          `i2cdetect'. (run once for each chip) (please send this only
+          if it's not all `ff')
+
+   * If an ISA sensor chip problem:
+        * The output of (as root) `prog/dump/isadump 0x295 0x296' (only
+          if it's not all `XX')
+
+   * Part numbers of chips on your motherboard you think are the sensor
+     chips (look at your motherboard)
+
+   * Motherboard type
+
+   * Sensors version
+
+   * Kernel version
+
+5.2 What to do if a module won't insert?
+========================================
+
+Did you use `modprobe' instead of `insmod'??? Don't use insmod.
+
+   Were there unresolved symbols? Did you run `depmod -a'? Run `depmod
+-a -e' to see where the symbol problem is.
+
+   ALWAYS inspect the output of `dmesg'. That's where the error
+messages come out!!! Don't rely on the generic message from `modprobe'.
+If you still can't figure it out, send us the information listed above.
+
+5.3 What to do if it inserts, but nothing happens?
+==================================================
+
+For an ISA sensor chip, did you also `modprobe i2c-isa'? It must be
+inserted.
+
+   For an I2C sensor chip, did you also `modprobe i2c-xxx' where xxx is
+your I2C bus adapter? It must be inserted.
+
+   Always inspect the output of `dmesg'. That's where the error
+messages come out. If you still can't figure it out, send us the
+information listed above.
+
+5.4 What to do if I read only bogus information?
+================================================
+
+It may be that this was a mis-detection: the chip may not be present.
+If you are convinced there is something wrong, verify that you indeed
+have the devices on your motherboard that you think you do.  Look at
+the motherboard and make sure. If you are still stuck, please send us
+the usual information (*note Help::)
+
+5.5 What to do if you have other problems?
+==========================================
+
+Again, send the output listed above.
+
+5.6 What if it just works like a charm?
+=======================================
+
+Drop us a mail if you feel like it, mentioning the mainboard and
+detected chip type. That way, we have some positive feedback, too!
+
+5.7 How do I update a ticket?
+=============================
+
+You can't. Only developers can. Follow up by emailing us and reference
+your ticket number in the subject. Please don't enter a new ticket with
+follow-up information, email us instead. Thanks.
+
+5.8 How do I follow up on a ticket?
+===================================
+
+Follow up by emailing us and reference your ticket number in the
+subject.
+
+5.9 Why did you decide not to support undocumented chips?
+=========================================================
+
+There are several reasons why we are generally not interested in writing
+drivers for undocumented chips:
+
+   * Writing a driver without a datasheet is much harder, as you have to
+     guess most things. Remember that, most of the time, we write
+     drivers for fun and for free, so there is no reason we would write
+     a driver in conditions that promise more pain than fun.
+
+   * If we hit a problem, we are certain never to get any support from
+     the chip manufacturer. This means that we may spend days on code
+     which will finally never work.
+
+   * There are several chips out there which are fully documented and
+     lack a driver. This is natural for us to give these the priority
+     when we finally have some spare time to spend on driver coding.
+
+   * Hardware monitoring chips are not toys. Misprogramming them can
+     result in data loss or hardware breakage. This is obviously more
+     likely to happen with undocumented chips. This is a responsability
+     we do not want to endorse (the GPL is pretty clear than we are not
+     legally liable, but still).
+
+   There are also several reasons why we do not want to support such
+drivers, even if they were written by other people:
+
+   * Problems are much more likely to happen with such drivers.  This
+     means increased needs of support. User support if very
+     time-consuming and we are usually short of time.
+
+   * Support should be done by the driver author (as only him/her knows
+     the driver and chip) but in the reality of facts, people will
+     always ask us for help if the driver is part of our package.
+     Redirecting all user requests to the driver's author manually is
+     boring.
+
+   * The lack of datasheet usually results in an original driver which
+     works relatively fine for its author, but will happen not to work
+     completely for other users. This means that the driver will need
+     many more additions and fixes than other drivers do, resulting in
+     an increased maitainance workload, which we can hardly afford. Of
+     course this too should be handled by the original driver author,
+     but we never know whether he/she will actually do the work.
+
+   Lastly, there are other considerations, some of which are
+deliberately political:
+
+   * We do not want to trick hardware buyers into thinking that a chip
+     is fully supported under Linux when in fact it is only partly
+     supported by a driver which was written without a datasheet.
+     Clearly stating that such chips are not supported makes it much
+     easier for anyone who really needs fully working hardware
+     monitoring under Linux to avoid motherboards with these partly
+     supported chips.
+
+   * Drivers written without a datasheet are a pain for developers and
+     users, but are a complete win for the manufacturers of these chips:
+     they don't have to write the driver, they don't have to help us,
+     they don't have to support the users, and they still sell their
+     hardware. We do not want to encourage such a selfish behavior.
+
+   That being said, authors of such drivers can still submit their code
+to the Linux kernel folks for inclusion into Linux 2.6. Their driver
+may be accepted there, under conditions.
+
+   If such a driver is ever accepted into the Linux 2.6 tree, and
+someone provides a patch to libsensors and/or sensors to add support
+for this driver, we will apply it. This generic code is unlikely to
+cause trouble.
+
+6 How to Contribute
+*******************
+
+6.1 How to write a driver
+=========================
+
+See `doc/developers/new_drivers' in our package for instructions.
+
+6.2 How to get SVN access
+=========================
+
+For anonymous SVN read access, see the instructions on our download
+page (http://www.lm-sensors.org/wiki/Download).
+
+   For write access, please contact us.
+
+6.3 How to donate hardware to the project
+=========================================
+
+Contact us (http://www.lm-sensors.org/wiki/FeedbackAndSupport).
+
+6.4 How to join the project mailing lists
+=========================================
+
+There are two lists you can subscribe to:
+
+   * A general discussion list
+     (http://lists.lm-sensors.org/mailman/listinfo/lm-sensors), meant
+     for both development and user support. You do not need to be
+     subscribed to post.
+
+   * A CVS commits list
+     (http://lists.lm-sensors.org/mailman/listinfo/lm-sensors-commit),
+     for watching the changes made to the CVS repositories. This list
+     is read-only.
+
+6.5 How to access mailing list archives
+=======================================
+
+The primary mailing list archive is at:
+`http://lists.lm-sensors.org/pipermail/lm-sensors/'.  It contains
+messages since October 28, 2001.
+
+   There is another mailing list archive at:
+`http://news.gmane.org/gmane.linux.drivers.sensors'.  It contains
+messages since December 31, 2004.  This archive may also be accessed
+via a news reader: `nntp://news.gmane.org/gmane.linux.drivers.sensors'
+and RSS: `http://rss.gmane.org/gmane.linux.drivers.sensors'.
+
+   And last there is a legacy archive at:
+`http://archives.andrew.net.au/lm-sensors'.  It contains messages from
+October 28, 2001 through May 16, 2005.
+
+6.6 How to submit a patch
+=========================
+
+Check out the latest from CVS, then copy the directory to another
+directory, and make your changes. Generate the diff with `diff -u2 -r
+DIR1 DIR2'. Or you can generate the diff in CVS with `cvs diff -u2'.
+Send us the patch in an email and tell us what it does.
+
+6.7 How to REALLY help
+======================
+
+Believe it or not, what we really need help with are:
+   * Answering email
+
+   * Answering support tickets
+
+   * Porting drivers to Linux 2.6
+
+   * Creating a sensors.conf database
+
+   * Reviewing patches
+
+   If you are willing to help, simply join our discussion list
+(http://lists.lm-sensors.org/mailman/listinfo/lm-sensors), and we'll
+help you help us.
+
+6.8 How to get release announcements
+====================================
+
+We don't have a separate release announcement mailing list; however, we
+put all our releases on freshmeat: `http://freshmeat.net' and you can
+register on our freshmeat project page
+`http://freshmeat.net/projects/lm_sensors' to 'subscribe to new
+releases' and then freshmeat will email you announcement.
+
+Appendix A Revision History of This Document
+********************************************
+
+   * Rev 2.18 (JD) Removed version 1 specifics part, 2005-12-17
+
+   * Rev 2.17 (JD) Added 5.9 (why we don't support undocumented chips),
+     removed 6.9 (doesn't apply to the new mailing list), 2005-10-05
+
+   * Rev 2.16 (JD) Added 4.33.2, 2005-09-06
+
+   * Rev 2.15 (JD) Updates, including mailing-list change, 2005-05-21
+
+   * Rev 2.14 (MDS) Updated 4.12, 2004-11-26
+
+   * Rev 2.13 (JD) Added 4.6.1, updated 4.7, 2004-06-23
+
+   * Rev 2.12 (JD) Updated 4.27, 2004-04-11
+
+   * Rev 2.11 (JD) Various updates, 2004-01-18
+
+   * Rev 2.10 (MDS) Various updates, 2004-01-03
+
+   * Rev 2.9 (CP) Converted to Gnu texinfo format, 2002-09-10
+
+   * Rev 2.8 (MDS) Minor updates 2002-07-10, released with lm_sensors
+     2.6.4
+
+   * Rev 2.7 (MDS) Minor updates 2002-04-25
+
+   * Rev 2.6 (MDS) Minor updates 2002-01-15, released with lm_sensors
+     2.6.3
+
+   * Rev 2.5 (MDS) Minor updates 2001-11-11, released with lm_sensors
+     2.6.2
+
+   * Rev 2.4 (MDS) Minor updates 2001-07-22
+
+   * Rev 2.3 (MDS) General update, 2001-02-24, released with lm_sensors
+     2.6.0.
+
+   * Rev 2.2 (Frodo) Corrections for lm_sensors 2.4, 1999-09-20
+
+   * Rev 2.1 (Frodo) Corrections for lm_sensors 2.2, 1999-01-12
+
+   * Rev 2.0 (Frodo) Major revision for lm_sensors 2.1, 1998-12-29
+
+   * Rev 1.10 (Frodo) Modified 3.8, updated some other things,
+     1998-09-24
+
+   * Rev 1.9 (Frodo) Added 3.15, 1998-09-06
+
+   * Rev 1.8 (Frodo) Added 3.14, 1998-09-05
+
+   * Rev 1.7 (Phil) Added 3.13 and some other minor changes, 1998-09-01
+
+   * Rev 1.6 (Frodo) Added 4, 4.1, 4.2, 4.3, 4.4, 4.5, 1998-09-01
+
+   * Rev 1.5 (Frodo) Added 2.3, 2.4, 3.9, 3.10, 3.11, 1998-08-26
+
+   * Rev 1.4 (Frodo) Added some more Winbond information, and 3.5-3.8,
+     1998-08-17
+
+   * Rev 1.3 (Phil) Added info on the Winbond chip, 1998-08-16
+
+   * Rev 1.2 (Frodo) Adapation, 1998-08-10
+
+   * Rev 1.1 (Phil) Modifications, 1998-08-09
+
+   * Rev 1.0 (Phil) First version, 1998-08-03
+
Index: /lm-sensors/tags/V3-0-0-RC2/doc/temperature-sensors
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/temperature-sensors	(revision 1103)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/temperature-sensors	(revision 1103)
@@ -0,0 +1,107 @@
+Thermistors and Transistors as Temperature Sensors
+--------------------------------------------------
+Temperature measuring chips that use external sensors
+generally are designed to use either thermistors or
+transistors. Check the driver documentation in doc/chips
+or the actual data sheets to determine which.
+
+Exceptions are the Winbond W83782D and W83783S which can use either.
+These chips default to termistors but can be configured to use
+Pentium II / Celeron diodes or 3904 transistors.
+
+Thermistors are about 10 times more sensitive than
+diodes or transistors at room temperature.
+
+
+Thermistors
+-----------
+(summarized from http://www.thermometrics.com/htmldocs/ntcapp.htm  -
+ most thermistor companies don't have much on their web sites but
+ Thermometrics has a comprehensive guide)
+
+NTC (negative temperature coefficient) thermistors decrease their
+resistance with an increase in temperature.
+They commonly have a parameter B (beta), units are K (kelvin).
+B is the "material constant" of the thermistor and
+is a measure of the change of resistance with respect to temperature.
+It is the slope of the line graphing (ln R) vs. (1/T).
+
+B values for three common termistor materials are
+approximately 3400K, 3900K, and 4300K.
+
+The other measure of thermistors is the temperature coefficient 'a' (alpha).
+This is the percentage change in resistance for a given change
+in temperature. This varies with temperature.
+
+T = temp in Kelvin (C + 273)
+
+A = (dR/dT) / R
+
+A = - B / T**2
+
+So by the last equation, a thermistor with a Beta of 3900 will change
+resistance about 4.4% for 1 degree change at 25C (298K).
+For a beta of 3435 as recommended in the
+Winbond W83782D data sheet the change is 3.8%.
+
+For thermistors, resistance (= voltage for a constant current)
+is exponentially related to temperature.
+
+PTC (positive temperature coefficient) thermistors increase
+in resistance with an increase in temperature. They are not
+commonly used for accurate temperature sensing.
+
+
+Transistors / Diodes
+--------------------
+To use a transistor as a sensor, hook the base of an NPN transistor
+(such as the 3904) to the collector.
+
+This is from Richard Dorf, "Electrical Engineering Handbook".
+
+For a diode, the voltage Vd = Vt ln(Id/Is).
+Vt = kT/q where k = Boltzman's constant 1.38 e-23;
+                q = elementary charge 1.6 e-19;
+                T = temp in kelvin.
+		Is is reverse saturation current.
+
+(more math and greek letters I don't understand completely)
+
+dVd/dT works out to, at room temperature, about 2.1 mV/degree
+or a temperature coefficient of about 0.32%/degree.
+
+For diodes, voltage is linear with temperature.
+
+
+
+Winbond W83782D and W83783S
+---------------------------
+These chips default to thermistors with Beta = 3435.
+Each sensor on the chip can be individually set to be 
+a diode, transistor, or thermistor.
+If the temperature reading changes much less than expected,
+the sensor type probably needs to be changed to a diode.
+See doc/chips/w83781d for details.
+
+
+Summary
+-------
+Thermistors are about 10 times more sensitive than
+diodes or transistors at room temperature.
+
+Thermistors change resistance exponentially with respect to temperature.
+Diodes and transistors change voltage linearly with respect to temperature.
+
+Sensors built into chips (including Pentium II / Celeron processors)
+are always diodes/transistors because that's what's on a chip
+already - transistors.
+
+External, discrete sensors can be either diodes/transistors or
+thermistors. Generally, sensor chips are designed to be connected
+to one or the other and cannot be configured. The Winbond
+W83782D/W83783S chips are exceptions, they can be
+configured for either.
+
+
+------------------
+Copyright (c) 1999, 2001 Mark D. Studebaker <mdsxyz123@yahoo.com>
Index: /lm-sensors/tags/V3-0-0-RC2/doc/developers/makefiles
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/developers/makefiles	(revision 4931)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/developers/makefiles	(revision 4931)
@@ -0,0 +1,54 @@
+The Makefiles in this package are rather advanced. They are partially based
+on the article "Recursive Make considered Harmful", written by Peter Miller:
+  http://miller.emu.id.au/pmiller/books/rmch/
+
+There is one big Makefile in the root of this package. It includes many
+other files; one for each directory in which source code is found. These
+included files are called 'Module.mk'.
+
+There are several interesting targets defined through this Makefile:
+  * all
+    Create everything in all directories.
+  * install
+    Install everything from all directories.
+  * uninstall
+    Uninstall everything.
+  * clean
+    Remove anything which can be regenerated from all directories. A call
+    of 'make clean' (without any other targets) will ignore any .d files;
+    this is useful when they are out of date (and prevent the calling of
+    any other target).
+
+The best way to understand the Module.mk subfiles is to examine one of them,
+for example lib/Module.mk. They are not too difficult to understand.
+
+There are several variables which can be set in the main Makefile. You can
+also specify them on the command-line; this overrules any definitions 
+within the Makefile. For example: 'make all WARN=1' will enable all warnings.
+Examine main Makefile to see which ones are available. The most important
+ones for developers:
+  * WARN
+    Set to 1 to enable many compiler warnings.
+  * DEBUG
+    Set to 1 to enable any debugging code. Note that debugging code should
+    only output more information, and never make the code mis-behave.
+
+Several files are generated by Makefiles:
+  * .rd
+    Dependency files for executables. Automatically generated.
+  * .ao
+    Dependency files for static libraries. Automatically generated.
+  * .lo
+    Dependency files for shared libraries. Automatically generated.
+  * .ro
+    Object files for executables. They will be linked together to create
+    the executable.
+  * .ao
+    Object files for static libraries
+  * .lo
+    Object files for shared libraries
+The reason for using different extensions is to make the Makefile much
+simpler.
+
+There are lots of comments within the main Makefile. Please read them if
+you want to know more.
Index: /lm-sensors/tags/V3-0-0-RC2/doc/developers/sysfs-interface
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/developers/sysfs-interface	(revision 4868)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/developers/sysfs-interface	(revision 4868)
@@ -0,0 +1,10 @@
+sysfs access
+------------
+
+In the 2.6 kernel, sensor chip drivers create subdirectories in
+the sysfs filesystem (usually /sys) which can be accessed
+directly by applications, or preferably through libsensors.
+
+Naming and content standards for the entries in these subdirectories
+is documented in the file Documentation/hwmon/sysfs-interface in the
+2.6 kernel source tree.
Index: /lm-sensors/tags/V3-0-0-RC2/doc/developers/applications
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/developers/applications	(revision 4498)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/developers/applications	(revision 4498)
@@ -0,0 +1,126 @@
+How to write applications which use our drivers
+-----------------------------------------------
+
+You have several choices in accessing sensor devices using the
+drivers in our package. This document will briefly
+describe these methods, their advantages and disadvantages,
+and provide examples.
+
+From lowest-level to the highest-level, the access methods are:
+
+	1) Character device access to the i2c bus driver
+	   via /dev/i2c-x
+	2) I2C bus access functions as defined in <linux/i2c-dev.h>
+	3) sysfs access to the chip device driver
+	4) libsensors library
+	5) sensors program
+
+
+Details:
+
+1. Direct /dev access using ioctls
+----------------------------------
+   Character device access to the i2c bus driver via ioctls on a /dev
+   device. This device could be i2cx, i2c-x, or i2c/x, where x is an
+   integer. The ioctls are defined in doc/dev-interface in the
+   i2c package or Documentation/i2c/dev-interface in the linux kernel
+   sources.
+
+   This method does not use a chip device driver at all.
+   However it does require the i2c-dev module.
+   The driver must set an individual chip address on the bus via
+   an ioctl, so it must use locking if multiple devices on the
+   bus are being accessed. No access is provided for non-i2c
+   busses such as ISA.
+
+   For good examples, see i2cdetect.c (in the i2c-tools package) and
+   prog/detect/sensors-detect.
+
+
+2. Direct /dev access using inline functions
+--------------------------------------------
+   I2C bus access inline functions as defined in <linux/i2c-dev.h>,
+   and in doc/dev-interface in the i2c package or
+   Documentation/i2c/dev-interface in the linux kernel sources.
+   Note that these used to be defined in <linux/i2c-dev.h> in the kernel
+   source tree. However, userspace applications are not supposed to	
+   include kernel headers, so the inline functions were removed from
+   the kernel file in recent kernels. Use the header file from the
+   i2c-tools package instead.
+
+   This method does not use a chip device driver at all.
+   However it does require the i2c-dev module.
+   The driver must set an individual chip address on the bus via
+   an ioctl, so it must use locking if multiple devices on the
+   bus are being accessed. No access is provided for non-i2c
+   busses such as ISA.
+
+   For good examples, see i2cdetect.c, i2cdump.c, and i2cset.c (all in the
+   i2c-tools package).
+
+
+3. sysfs access
+---------------
+   Chip drivers using the i2c-sensor module create subdirectories in
+   the sysfs filesystem (usually /sys) which can be accessed
+   directly by applications.
+   Naming and content standards for the entries in these subdirectories
+   is documented in the file Documentation/i2c/sysfs-interface in the
+   2.6 kernel source tree. Note that these standards may not be
+   strictly followed.
+
+   If a new driver adheres to these standards then an application may
+   be able to support new devices on-the-fly.
+
+   sysfs access provides a method to read and write sensor values
+   for any driver, including ISA chip drivers.
+
+   This method may also works well for shell and perl scripts
+   written to access a specific device. Note that sysfs is
+   standard in 2.6 kernels.
+
+   Note that most drivers provide only raw sensor readings via /sys;
+   many readings must be scaled or adjusted, and these adjustments
+   must often be changed by the user. An application using /sys must
+   generally provide adjustment facilities and the requirements
+   of the adjustments can be quite complex. If you need adjustment
+   facilities, consider the libsensors library, below.
+
+   For an examples of a program using /sys accesses, see gkrellm.
+   See also lib/proc.c and i2cbusses.c (in the i2c-tools package) for
+   examples. The sysfsutils package may also be helpful.
+   Also search freshmeat for sensors and sysfs applications.
+
+
+4. libsensors library
+---------------------
+   The libsensors library provides standardized access to all chip drivers.
+   It also provides a translation layer with settings in /etc/sensors.conf
+   so that your application sees adjusted (scaled) values using settings
+   provided by the user. Other facilities are sensor renaming, limit setting,
+   and ignoring individual sensors.
+   The libsensors library supports both 2.4 and 2.6 kernels.
+
+   Unfortunately there is little documentation for libsensors. See the
+   'sensors' application in prog/sensors for an example. The source
+   for libsensors is in the lib/ directory. Another example
+   is in prog/sensord. Also search freshmeat for sensors applications.
+
+   One other limitation of libsensors is that it is relatively
+   cumbersome to add support for new devices.
+
+   Note that libsensors falls under the GPL, not the LGPL.
+   In more human language, that means it is FORBIDDEN to link any application
+   to the library, even to the shared version, if the application itself
+   does not fall under the GPL. This may or may not be changed in the future.
+   Contact us if you wish to discuss your application.
+
+   For an examples of a program using libsensors accesses, see
+   prog/sensors/sensors. Also search freshmeat for sensors applications.
+
+5. sensors program
+------------------
+   The 'sensors' program is a text-based application that uses libsensors.
+   The output is fairly standardized; therefore this output could be
+   used by other applications.
+   One simple method is 'sensors|grep ALARM'.
Index: /lm-sensors/tags/V3-0-0-RC2/doc/developers/release_checklist
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/developers/release_checklist	(revision 4889)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/developers/release_checklist	(revision 4889)
@@ -0,0 +1,35 @@
+CHECKLIST FOR NEW RELEASES
+==========================
+
+Release steps:
+- Check out lm-sensors
+- Update if necessary, the version number of libsensors
+  (edit lib/Module.mk and change LIBMAINVER and/or LIBMINORVER)
+  Remember: update main number when interface changes, minor if new
+  functionality is added, and patch if only bugs are fixed.
+  `svn diff -r Vx-y-z lib' is your friend.
+- Update the CHANGES file (add the release date)
+- Update lm_sensors.lsm (Version, Entered-date and Primary-site) and send
+  it to the LSM by mailing it to lsm@qqx.org with the subject `add' (no
+  quotes).
+- Update version.h
+- Commit
+- Tag the release using SVN:
+  svn copy http://lm-sensors.org/svn/lm-sensors/branches/lm-sensors-3.0.0 \
+      http://lm-sensors.org/svn/lm-sensors/tags/V3-x-x \
+      -m "3.x.x release"
+- Remove 'SVN' related files/directories (e.g. rm -fR `find . -name .svn`)
+- Rename the base directory to lm_sensors-3.x.x
+- Tar it up and post it (sign it)
+- Make sure the file permissions on both the archive and the signature
+  are correct (664)
+
+After release, remember to:
+- Copy to mirrors
+- Announce on Freshmeat
+- Put back ???? for dates
+- Prep CHANGES files for next release
+- Mark the corresponding release milestone as complete using trac-admin
+  e.g. 'trac-admin /srv/lm-sensors.org/trac milestone completed 2.10.2 2006-12-31'
+- Create a new release milestone using trac-admin
+  e.g. 'trac-admin /srv/lm-sensors.org/trac milestone add 2.10.2 2006-12-31'
Index: /lm-sensors/tags/V3-0-0-RC2/doc/developers/lm_sensors.lsm
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/developers/lm_sensors.lsm	(revision 4882)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/developers/lm_sensors.lsm	(revision 4882)
@@ -0,0 +1,18 @@
+Begin4
+Title: lm_sensors
+Version: 3.0.0-rc1
+Entered-date: 2007-09-25
+Description: Hardware health monitoring package for Linux. It consists of 
+             a library to allow applications to read sensors data more
+             easily, and of an example program to pretty print this data.
+             Also included is a fan speed control script.
+             http://www.lm-sensors.org/
+Keywords: sensors health hardware-monitoring fan-speed
+Author: khali@linux-fr.org (Jean Delvare)
+Maintained-by: khali@linux-fr.org (Jean Delvare)
+Primary-site: http://dl.lm-sensors.org /lm-sensors/releases/
+              lm_sensors-3.0.0-rc1.tar.gz
+              lm_sensors-3.0.0-rc1.tar.gz.asc
+Alternate-site: ftp.netroedge.com /pub/lm-sensors/
+Copying-policy: GPL
+End
Index: /lm-sensors/tags/V3-0-0-RC2/doc/progs
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/progs	(revision 4931)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/progs	(revision 4931)
@@ -0,0 +1,70 @@
+This is a list of additional programs, that may or may not be installed by
+`make install', and that can be found in the `prog' directory of
+this package.
+
+These programs are generally small utilities used for debugging,
+and installation of the lm_sensors package, and for demonstrating
+the use of the drivers and libraries in this package.
+For more elaborate programs (for example, GUI sensor displays),
+see http://www.lm-sensors.org/wiki/UsefulLinks.
+
+
+* prog/daemon/healthd.sh (written in bash, not installed)
+  An example of a very simple hardware health monitoring daemon.
+
+* prog/detect/sensors-detect (written in Perl, installed by 'make install')
+  This program tries to detect the available SMBus adapters and the chips
+  connected to them, as well as Super-I/O and misc chips. It also generates
+  modprobe lines and module options. This program is interactive.
+
+* prog/dump/isadump (written in C, installed by 'make install')
+  This program dumps the registers of ISA or Super-I/O chips.
+  Usual syntax:
+     isadump 0x295 0x296
+     isadump -k 0x55 0x2e 0x2f
+
+* prog/hotplug/unhide_ICH_SMBus (shell script, not installed)
+  It unhides the ICH Intel SMBus for 2.6 kernels
+
+* prog/init/lm_sensors.init (shell script, not installed)
+  A SysV init script to be installed in /etc/rc.d/init.d/
+  It inserts the bus and chip modules.
+
+* prog/init/sensord.init (shell script, not installed)
+  A SysV init script to be installed in /etc/rc.d/init.d/
+  It inserts the bus and chip modules and starts the sensord daemon.
+
+* prog/maxilife/sysinfo.sh (written in shell, not installed)
+  Write system information to the HP Maxilife LCD display using writelcd.sh.
+
+* prog/maxilife/writelcd.sh (written in shell, not installed)
+  Write a string to the HP Maxilife LCD display.
+
+* prog/pwm/pwmconfig (shell script, installed by 'make install')
+  Formerly pwmtest, tests the pwm (pulse width modulation) outputs of sensors
+  for their effect on the fans and helps to setup the configfile for fancontrol.
+
+* prog/pwm/fancontrol (shell script, installed by 'make install')
+  Controls fanspeeds responding to changes on temperature sensors.
+  Configuration through pwmconfig.
+
+* prog/rrd/sens_update_rrd (written in bash, not installed)
+  This script gathers sensors data and adds it to a round robin database
+  (RRD). RRD is then used to display the graphed data in web pages.
+  See prog/rrd/README for more information.
+
+* prog/sensord/sensord (written in C, installed by `make install-prog-sensord')
+  This daemon can be used to periodically log sensor readings from
+  the sensors hardware to syslog, and to alert (using syslog level ALERT)
+  when a sensor alarm is signalled; for example, if a fan fails, a temperature
+  limit is exceeded, etc.
+
+* prog/sensors/sensors (written in C, installed by `make install')
+  This pretty-prints the information provided by the modules. It is a normal
+  console application, using stdout. It is essential, because
+  unlike the raw /proc/sys/dev/sensors/*/* files, it takes your configuration
+  file into account.
+
+* prog/tellerstats/gather.sh, tellerstats.sh (written in bash, not installed)
+  These scripts gather sensors data and graph the data for web pages.
+  See prog/tellerstats/README for more information.
Index: /lm-sensors/tags/V3-0-0-RC2/doc/lm_sensors-FAQ.html
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/lm_sensors-FAQ.html	(revision 4865)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/lm_sensors-FAQ.html	(revision 4865)
@@ -0,0 +1,2351 @@
+<html lang="en">
+<head>
+<title>Sensors FAQ for lm_sensors version 2.18</title>
+<meta http-equiv="Content-Type" content="text/html">
+<meta name="description" content="Sensors FAQ for lm_sensors version 2.18">
+<meta name="generator" content="makeinfo 4.8">
+<link title="Top" rel="top" href="#Top">
+<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage">
+<meta http-equiv="Content-Style-Type" content="text/css">
+<style type="text/css"><!--
+  pre.display { font-family:inherit }
+  pre.format  { font-family:inherit }
+  pre.smalldisplay { font-family:inherit; font-size:smaller }
+  pre.smallformat  { font-family:inherit; font-size:smaller }
+  pre.smallexample { font-size:smaller }
+  pre.smalllisp    { font-size:smaller }
+  span.sc    { font-variant:small-caps }
+  span.roman { font-family:serif; font-weight:normal; } 
+  span.sansserif { font-family:sans-serif; font-weight:normal; } 
+--></style>
+</head>
+<body>
+<h1 class="settitle">Sensors FAQ for lm_sensors version 2.18</h1>
+Copyright (C) 1998 - 2005<br>
+Frodo Looijaard,<br>
+Philip Edelbrock,<br>
+Mark D. Studebaker<br>
+and<br>
+Jean Delvare<br>
+
+   <div class="shortcontents">
+<h2>Short Contents</h2>
+<ul>
+<li><a href="#toc_Top">lm_sensors</a></li>
+<li><a href="#toc_Overview">1 PC and Sensor Overview</a></li>
+<li><a href="#toc_Basics">2 Sensor and Bus Basics</a></li>
+<li><a href="#toc_Installation">3 Installation and Management</a></li>
+<li><a href="#toc_Problems">4 Problems</a></li>
+<li><a href="#toc_Help">5 How to Ask for Help</a></li>
+<li><a href="#toc_Contribute">6 How to Contribute</a></li>
+<li><a href="#toc_Document-Revisions">Appendix A Revision History of This Document</a></li>
+</ul>
+</div>
+
+   <div class="contents">
+<h2>Table of Contents</h2>
+<ul>
+<li><a name="toc_Top" href="#Top">lm_sensors</a>
+<li><a name="toc_Overview" href="#Overview">1 PC and Sensor Overview</a>
+<ul>
+<li><a href="#Section-1_002e1">1.1 What sensors are available on my PC?</a>
+<li><a href="#Section-1_002e2">1.2 What can a sensor chip like the "LM78" do?</a>
+<li><a href="#Section-1_002e3">1.3 Where do I find out more about any of these chips?</a>
+</li></ul>
+<li><a name="toc_Basics" href="#Basics">2 Sensor and Bus Basics</a>
+<ul>
+<li><a href="#Section-2_002e1">2.1 How are these sensors read?</a>
+<li><a href="#Section-2_002e2">2.2 What is the SMBus? And the I2C bus?</a>
+<li><a href="#Section-2_002e3">2.3 I don't have an ISA bus!</a>
+<li><a href="#Section-2_002e4">2.4 What sensors do processors have?</a>
+<li><a href="#Section-2_002e5">2.5 How often are the sensor values updated?</a>
+<li><a href="#Section-2_002e6">2.6 How are alarms triggered?</a>
+</li></ul>
+<li><a name="toc_Installation" href="#Installation">3 Installation and Management</a>
+<ul>
+<li><a href="#Section-3_002e1">3.1 Why so many modules, and how do I cope with them?</a>
+<li><a href="#Section-3_002e2">3.2 How do I know which chips I own?</a>
+<ul>
+<li><a href="#Section-3_002e2">3.2.1 What chips are on motherboard XYZ?</a>
+<li><a href="#Section-3_002e2">3.2.2 Do you support motherboard XYZ?</a>
+<li><a href="#Section-3_002e2">3.2.3 Do you support chip XYZ?</a>
+<li><a href="#Section-3_002e2">3.2.4 Anybody working on a driver for chip XYZ?</a>
+</li></ul>
+<li><a href="#Section-3_002e3">3.3 Which modules should I insert?</a>
+<li><a href="#Section-3_002e4">3.4 Do I need the configuration file <samp><span class="file">/etc/sensors.conf</span></samp>?</a>
+<ul>
+<li><a href="#Section-3_002e4">3.4.1 The labels for the voltage and temperature readings in <samp><span class="command">sensors</span></samp> are incorrect!</a>
+<li><a href="#Section-3_002e4">3.4.2 The min and max for the readings in <samp><span class="command">sensors</span></samp> are incorrect!</a>
+<li><a href="#Section-3_002e4">3.4.3 The min and max settings in <samp><span class="file">/etc/sensors.conf</span></samp> didn't take effect!</a>
+<li><a href="#Section-3_002e4">3.4.4 One sensor isn't hooked up on my board!</a>
+<li><a href="#Section-3_002e4">3.4.5 I need help with <samp><span class="file">sensors.conf</span></samp>!</a>
+<li><a href="#Section-3_002e4">3.4.6 Do you have a database of <samp><span class="file">sensors.conf</span></samp> entries for specific boards?</a>
+</li></ul>
+<li><a href="#Section-3_002e5">3.5 What about the `<samp><span class="samp">No such file or directory</span></samp>' warnings when I compile?</a>
+<li><a href="#Section-3_002e6">3.6 I get all kinds of weird compilation errors?</a>
+<ul>
+<li><a href="#Section-3_002e6">3.6.1 `<samp><span class="samp">No rule to make target xxxx needed by xxxx</span></samp>' - how to fix?</a>
+</li></ul>
+<li><a href="#Section-3_002e7">3.7 It still does not compile or patch!</a>
+<li><a href="#Section-3_002e8">3.8 <samp><span class="command">make install</span></samp> fails on Mandrake kernels</a>
+<li><a href="#Section-3_002e9">3.9 I get unresolved symbols when I <samp><span class="command">modprobe</span></samp> modules (Red Hat especially)</a>
+<li><a href="#Section-3_002e10">3.10 I2C_DRIVERID_ADM1024 undefined (Red Hat especially)</a>
+</li></ul>
+<li><a name="toc_Problems" href="#Problems">4 Problems</a>
+<ul>
+<li><a href="#Section-4_002e1">4.1 My fans report exactly half/double their values compared to the BIOS?</a>
+<ul>
+<li><a href="#Section-4_002e1">4.1.1 Fans sometimes/always read 0!!</a>
+<li><a href="#Section-4_002e1">4.1.2 I doubled the fan divisor and the fan still reads 7000!</a>
+</li></ul>
+<li><a href="#Section-4_002e2">4.2 Why do my two LM75's report "-48 degrees"?</a>
+<li><a href="#Section-4_002e3">4.3 Why do I have two Vcore readings, I have only one processor!</a>
+<li><a href="#Section-4_002e4">4.4 How do those ALARMS work? The current value is within range but there is still an ALARM warning!</a>
+<li><a href="#Section-4_002e5">4.5 My voltage readings seem to drift a bit. Is something wrong?</a>
+<li><a href="#Section-4_002e6">4.6 Some measurements are way out of range. What happened?</a>
+<ul>
+<li><a href="#Section-4_002e6">4.6.1 -5V and -12V readings are way out of range!</a>
+</li></ul>
+<li><a href="#Section-4_002e7">4.7 What are VID lines? Why is the VID reading wrong?</a>
+<li><a href="#Section-4_002e8">4.8 I read sensor values several times a second, but they are only updated only each second or so. Why?</a>
+<li><a href="#Section-4_002e9">4.9 It sometimes seems to take almost a second before I see the sensor reading results. Why?</a>
+<li><a href="#Section-4_002e10">4.10 Can I be alerted when an ALARM occurs?</a>
+<li><a href="#Section-4_002e11">4.11 SMBus transactions on my PIIX4 simply don't work (timeouts happen).  Why?</a>
+<li><a href="#Section-4_002e12">4.12 My BIOS reports a much higher CPU temperature than your modules!</a>
+<li><a href="#Section-4_002e13">4.13 I try to read the raw <samp><span class="file">/proc</span></samp> files, but the values are strange?!?</a>
+<li><a href="#Section-4_002e14">4.14 How do I set new limits?</a>
+<ul>
+<li><a href="#Section-4_002e14">4.14.1 I set new limits and it didn't work?</a>
+</li></ul>
+<li><a href="#Section-4_002e15">4.15 Some sensors are doubly detected?</a>
+<li><a href="#Section-4_002e16">4.16 I ran sensors-detect, but now I get very strange readings?!?</a>
+<li><a href="#Section-4_002e17">4.17 Bad readings from particular chips</a>
+<ul>
+<li><a href="#Section-4_002e17">4.17.1 Bad readings from the AS99127F!</a>
+<li><a href="#Section-4_002e17">4.17.2 Bad readings from the VIA 686A!</a>
+<li><a href="#Section-4_002e17">4.17.3 Bad readings from the MTP008!</a>
+<li><a href="#Section-4_002e17">4.17.4 Bad temperature readings from the SIS5595!</a>
+<li><a href="#Section-4_002e17">4.17.5 Bad readings from a w8378[12]d!</a>
+<li><a href="#Section-4_002e17">4.17.6 Bus hangs on Ali 1543 on Asus P5A boards!</a>
+<li><a href="#Section-4_002e17">4.17.7 Bad readings from LM75!</a>
+<li><a href="#Section-4_002e17">4.17.8 Bad readings from LM78!</a>
+<li><a href="#Section-4_002e17">4.17.9 Bad readings from LM80!</a>
+</li></ul>
+<li><a href="#Section-4_002e18">4.18 How do I configure two chips (LM87) differently?</a>
+<li><a href="#Section-4_002e19">4.19 Dmesg says `<samp><span class="samp">Upgrade BIOS</span></samp>'! I don't want to!</a>
+<ul>
+<li><a href="#Section-4_002e19">4.19.1 Dmesg says `<samp><span class="samp">use force_addr=0xaddr</span></samp>'! What address do I use?</a>
+</li></ul>
+<li><a href="#Section-4_002e20">4.20 Sensors says `<samp><span class="samp">Can't access procfs/sysfs file</span></samp>'</a>
+<li><a href="#Section-4_002e21">4.21 Sensors says `<samp><span class="samp">No sensors found!</span></samp>'</a>
+<li><a href="#Section-4_002e22">4.22 Sensors output is not correct!</a>
+<li><a href="#Section-4_002e23">4.23 What is at I2C address XXX?</a>
+<ul>
+<li><a href="#Section-4_002e23">4.23.1 What is at I2C address 0x69?</a>
+<li><a href="#Section-4_002e23">4.23.2 What is at I2C addresses 0x50 - 0x57?</a>
+<li><a href="#Section-4_002e23">4.23.3 What is at I2C addresses 0x30 - 0x37?</a>
+</li></ul>
+<li><a href="#Section-4_002e24">4.24 Sensors-detect doesn't work at all</a>
+<ul>
+<li><a href="#Section-4_002e24">4.24.1 Sensors-detect says "Couldn't open /proc/bus/i2c?!?"</a>
+<li><a href="#Section-4_002e24">4.24.2 Sensors-detect says "Can't open /dev/i2c[-/]0"</a>
+<li><a href="#Section-4_002e24">4.24.3 Sensors-detect doesn't find any sensors!</a>
+</li></ul>
+<li><a href="#Section-4_002e25">4.25 Sensors says `<samp><span class="samp">Error: Line xxx: zzzzzzz</span></samp>'</a>
+<li><a href="#Section-4_002e26">4.26 Sensors only gives the name and adapter for my chip</a>
+<li><a href="#Section-4_002e27">4.27 Sensors says `<samp><span class="samp">ERROR: Can't get xxxxx data!</span></samp>'</a>
+<li><a href="#Section-4_002e28">4.28 Sensors doesn't find any sensors, just eeproms.</a>
+<li><a href="#Section-4_002e29">4.29 Inserting modules hangs my board</a>
+<li><a href="#Section-4_002e30">4.30 Inserting modules slows down my board</a>
+<li><a href="#Section-4_002e31">4.31 Problems on particular motherboards</a>
+<ul>
+<li><a href="#Section-4_002e31">4.31.1 Asus P4B</a>
+<li><a href="#Section-4_002e31">4.31.2 Tyan 2460, 2462</a>
+<li><a href="#Section-4_002e31">4.31.3 Tyan 2466</a>
+<li><a href="#Section-4_002e31">4.31.4 Tyan 2688</a>
+</li></ul>
+<li><a href="#Section-4_002e32">4.32 Problems on 2.6 kernels</a>
+<ul>
+<li><a href="#Section-4_002e32">4.32.1 i2c-viapro and via686a</a>
+<li><a href="#Section-4_002e32">4.32.2 Where are my EEPROMs?</a>
+</li></ul>
+</li></ul>
+<li><a name="toc_Help" href="#Help">5 How to Ask for Help</a>
+<ul>
+<li><a href="#Section-5_002e1">5.1 What to send us when asking for help</a>
+<li><a href="#Section-5_002e2">5.2 What to do if a module won't insert?</a>
+<li><a href="#Section-5_002e3">5.3 What to do if it inserts, but nothing happens?</a>
+<li><a href="#Section-5_002e4">5.4 What to do if I read only bogus information?</a>
+<li><a href="#Section-5_002e5">5.5 What to do if you have other problems?</a>
+<li><a href="#Section-5_002e6">5.6 What if it just works like a charm?</a>
+<li><a href="#Section-5_002e7">5.7 How do I update a ticket?</a>
+<li><a href="#Section-5_002e8">5.8 How do I follow up on a ticket?</a>
+<li><a href="#Section-5_002e9">5.9 Why did you decide not to support undocumented chips?</a>
+</li></ul>
+<li><a name="toc_Contribute" href="#Contribute">6 How to Contribute</a>
+<ul>
+<li><a href="#Section-6_002e1">6.1 How to write a driver</a>
+<li><a href="#Section-6_002e2">6.2 How to get SVN access</a>
+<li><a href="#Section-6_002e3">6.3 How to donate hardware to the project</a>
+<li><a href="#Section-6_002e4">6.4 How to join the project mailing lists</a>
+<li><a href="#Section-6_002e5">6.5 How to access mailing list archives</a>
+<li><a href="#Section-6_002e6">6.6 How to submit a patch</a>
+<li><a href="#Section-6_002e7">6.7 How to REALLY help</a>
+<li><a href="#Section-6_002e8">6.8 How to get release announcements</a>
+</li></ul>
+<li><a name="toc_Document-Revisions" href="#Document-Revisions">Appendix A Revision History of This Document</a>
+</li></ul>
+</div>
+
+<div class="node">
+<p><hr>
+<a name="Top"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Overview">Overview</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#dir">(dir)</a>
+
+</div>
+
+<h2 class="unnumbered">lm_sensors</h2>
+
+<p>The lm_sensors package includes a collection of modules for general SMBus
+access and hardware monitoring.  NOTE: this requires special support which
+is not in standard 2.2-vintage kernels.
+
+<ul class="menu">
+<li><a accesskey="1" href="#Overview">Overview</a>:                 PC and Sensor Overview
+<li><a accesskey="2" href="#Basics">Basics</a>:                   Sensor and Bus Basics
+<li><a accesskey="3" href="#Installation">Installation</a>:             Installation and Management
+<li><a accesskey="4" href="#Problems">Problems</a>:                 Problems
+<li><a accesskey="5" href="#Help">Help</a>:                     How to Ask for Help
+<li><a accesskey="6" href="#Contribute">Contribute</a>:               How to Contribute
+<li><a accesskey="7" href="#Document-Revisions">Document Revisions</a>:       Revision History of This Document
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Overview"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Basics">Basics</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Top">Top</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
+
+</div>
+
+<h2 class="chapter">1 PC and Sensor Overview</h2>
+
+<ul class="menu">
+<li><a accesskey="1" href="#Section-1_002e1">Section 1.1</a>:              What sensors are available on my PC? 
+<li><a accesskey="2" href="#Section-1_002e2">Section 1.2</a>:              What can a sensor chip like the "LM78" do? 
+<li><a accesskey="3" href="#Section-1_002e3">Section 1.3</a>:              Where do I find out more about any of these chips? 
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-1.1"></a>
+<a name="Section-1_002e1"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-1_002e2">Section 1.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Overview">Overview</a>
+
+</div>
+
+<h3 class="section">1.1 What sensors are available on my PC?</h3>
+
+<p>Most PC's built since late 1997 now come with a
+hardware health monitoring chip. This chip may be accessed via the
+ISA bus or the SMBus, depending on the motherboard.
+
+   <p>Some motherboard chipsets, notably the Via 686 and the SiS 5595,
+contain hardware monitor functions.
+
+   <p>This FAQ frequently refers to the "LM78". This chip has been
+obsoleted by National Semiconductor. Most motherboards today contain
+a chip with similar functions.
+
+<div class="node">
+<p><hr>
+<a name="Section-1.2"></a>
+<a name="Section-1_002e2"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-1_002e3">Section 1.3</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-1_002e1">Section 1.1</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Overview">Overview</a>
+
+</div>
+
+<h3 class="section">1.2 What can a sensor chip like the "LM78" do?</h3>
+
+<p>The LM78 is a chip made by National Semiconductor which can monitor 7
+voltages (5 positive, 2 negative) from 0 to 4.08V.  The inputs are usually in
+series with voltage dividers which lower the +/- 12V and +/- 5V supplies to
+measurable range.  Therefore, the readings for such inputs need to be
+re-scaled appropriately by software.
+
+   <p>The LM78 also has 3 fan speed monitoring inputs, an internal
+temperature sensor, a chassis intrusion sensor, and a couple maskable interrupt
+inputs.  The LM78 can also relay the processor's (P6 or Pent II) VID lines
+which are hardwired and used to indicate to the power regulator (usually on
+the mainboard close to the processor socket/slot) what voltage to supply to
+the processor.
+
+   <p>The LM78 can be interfaced to a system via the ISA bus and/or the
+SMBus.
+
+   <p>Most other sensor chips have comparable functionality. Each supported
+chip is documented in the <samp><span class="file">doc/chips</span></samp> directory.
+
+<div class="node">
+<p><hr>
+<a name="Section-1.3"></a>
+<a name="Section-1_002e3"></a>
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-1_002e2">Section 1.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Overview">Overview</a>
+
+</div>
+
+<h3 class="section">1.3 Where do I find out more about any of these chips?</h3>
+
+<p>Most semiconductor companies have comprehensive documentation,
+including complete datasheets, on their websites. Analog Devices,
+Dallas Semiconductor, Maxim, and National Semiconductor have the widest selection
+of sensor chips. Their websites are:
+
+     <ul>
+  <li><a href="http://www.analog.com">http://www.analog.com</a>
+  <li><a href="http://www.dalsemi.com">http://www.dalsemi.com</a>
+  <li><a href="http://www.maxim-ic.com">http://www.maxim-ic.com</a>
+  <li><a href="http://www.national.com">http://www.national.com</a>
+</ul>
+
+   <p>Please see the file <a href="http://www.lm-sensors.org/wiki/UsefulLinks">http://www.lm-sensors.org/wiki/UsefulLinks</a>
+for links to other companies' websites.
+
+<div class="node">
+<p><hr>
+<a name="Basics"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Installation">Installation</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Overview">Overview</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
+
+</div>
+
+<h2 class="chapter">2 Sensor and Bus Basics</h2>
+
+<ul class="menu">
+<li><a accesskey="1" href="#Section-2_002e1">Section 2.1</a>:              What sensors are available on my PC? 
+<li><a accesskey="2" href="#Section-2_002e2">Section 2.2</a>:              What can a sensor chip like the "LM78" do? 
+<li><a accesskey="3" href="#Section-2_002e3">Section 2.3</a>:              Where do I find out more about any of these chips? 
+<li><a accesskey="4" href="#Section-2_002e4">Section 2.4</a>:              What sensors are available on my PC? 
+<li><a accesskey="5" href="#Section-2_002e5">Section 2.5</a>:              What can a sensor chip like the "LM78" do? 
+<li><a accesskey="6" href="#Section-2_002e6">Section 2.6</a>:              Where do I find out more about any of these chips? 
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-2.1"></a>
+<a name="Section-2_002e1"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-2_002e2">Section 2.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Basics">Basics</a>
+
+</div>
+
+<h3 class="section">2.1 How are these sensors read?</h3>
+
+<p>Sensor chips reside on either the ISA bus, the SMBus, or both. 
+See the file <samp><span class="file">doc/chips/SUMMARY</span></samp> in our package for a list.
+
+   <p>To communicate with chips on the ISA bus, the software uses
+simple I/O reads and writes.
+
+   <p>To communicate with chips on the SMBus, the software must
+use an SMBus interface device, explained below.
+
+<div class="node">
+<p><hr>
+<a name="Section-2.2"></a>
+<a name="Section-2_002e2"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-2_002e3">Section 2.3</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-2_002e1">Section 2.1</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Basics">Basics</a>
+
+</div>
+
+<h3 class="section">2.2 What is the SMBus? And the I2C bus?</h3>
+
+<p>The SMBus is the "System Management Bus".  More specifically, it is a
+2-wire, low-speed serial communication bus used for basic health monitoring
+and hardware management. It is a specific implementation of the more
+general I2C (pronunciation: I-squared-C) bus. In fact, both I2C devices
+and SMBus devices may be connected to the same (I2C) bus.
+
+   <p>The SMBus (or I2C bus) starts at the host controller, used for
+starting transactions on the SMBus.  From the host interface, the
+devices communicated with are the <dfn>slave</dfn> devices.  Each slave device has a
+unique 7-bit address which the host uses to refer to that device.
+
+   <p>For each supported SMBus host, there is a separate kernel module
+which implements the communication protocol with the host. Some SMBus hosts
+really operate on the SMBus level; these hosts can not cope with pure I2C
+devices. Other hosts are in fact I2C hosts: in this case, we implement
+the SMBus protocol in terms of I2C operations. But these hosts can also
+talk to pure I2C devices.
+
+<div class="node">
+<p><hr>
+<a name="Section-2.3"></a>
+<a name="Section-2_002e3"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-2_002e4">Section 2.4</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-2_002e2">Section 2.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Basics">Basics</a>
+
+</div>
+
+<h3 class="section">2.3 I don't have an ISA bus!</h3>
+
+<p>We promise, you do, even if you don't have any old ISA slots. 
+The "ISA Bus" exists in your computer even if you don't have ISA slots;
+it is simply a memory-mapped area, 64KB in size (0x0000 - 0xFFFF)
+where many "legacy" functions, such as keyboard and interrupt controllers,
+are found. It isn't necessarily a separate physical bus. 
+See the file <samp><span class="file">/proc/ioports</span></samp> for a list of devices living on
+the "ISA Bus" in your system. If you don't like the term "ISA Bus"
+think "I/O Space".
+
+<div class="node">
+<p><hr>
+<a name="Section-2.4"></a>
+<a name="Section-2_002e4"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-2_002e5">Section 2.5</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-2_002e3">Section 2.3</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Basics">Basics</a>
+
+</div>
+
+<h3 class="section">2.4 What sensors do processors have?</h3>
+
+<p>Most new processors contain a thermal diode on the die itself. 
+The electical properties of all diodes and transistors vary
+slightly with temperature. The thermal diode is exceptionally accurate
+because it is directly on the die. Newer temperature sensor chips,
+like the Analog Devices ADM1021 and clones, and the Winbond chips,
+have circuitry for measuring the the electrical properties of
+an external diode and converting this data to a temperature. 
+Any sensor chip listed in <samp><span class="file">doc/chips/SUMMARY</span></samp> in our package which
+has support for more than one temperature supports external temperature sensing.
+
+   <p>Older motherboards and processors without this feature generally use
+an LM75 placed close to the processor. This is much less accurate.
+
+   <p>The Pentium 2 'boxed' processor usually has an LM75 very close to the
+base of the box. It can be read through the SMBus to report the approximate
+temperature of the processor.  The processor also contains an internal
+temperature sensor (of low accuracy) used as a fail-safe to disable the
+processor in case it gets much too hot (usually around 130 degrees C).  And,
+the Pentium 2 also has a hard-wired signal (VID lines) on it's SEC (single
+edge connector) which indicates what power supply is required to operate the
+processor.
+
+   <p>The P6 (Pentium-Pro) may have an LM75 in or just under the socket. 
+P6's also have VID lines.
+
+   <p>Pentiums and Pentium w/ MMX do not have VID lines, and sometimes have
+LM75's under the sockets (depends on the mainboard, and how 'modern' the
+mainboard is).
+
+   <p>The P2 Xeon was the first Intel processor to include the SMBus
+interface on the P2 Xeon SEC.
+
+<div class="node">
+<p><hr>
+<a name="Section-2.5"></a>
+<a name="Section-2_002e5"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-2_002e6">Section 2.6</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-2_002e4">Section 2.4</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Basics">Basics</a>
+
+</div>
+
+<h3 class="section">2.5 How often are the sensor values updated?</h3>
+
+<p>The LM78, and most other sensor chips like it, reads its sensors one
+by one. A complete scanning sweep will take about 1.5 seconds. The LM78 stops
+readings sensors if you try to access it, so if you access it very often
+(by reading sensor values; writing new limits is safe) it will not find the
+time to update its sensor values at all! Fortunately, the kernel module takes
+care not to do this, and only reads new values each 1.5 seconds. If you
+read the values again, you will get the 'old' values again.
+
+<div class="node">
+<p><hr>
+<a name="Section-2.6"></a>
+<a name="Section-2_002e6"></a>
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-2_002e5">Section 2.5</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Basics">Basics</a>
+
+</div>
+
+<h3 class="section">2.6 How are alarms triggered?</h3>
+
+<p>It is possible to monitor each sensor and have an alarm go off if
+it crosses some pre-determined limits.  There are two sorts of interrupts
+which can be generated by sensor chips if this happens (it depends a bit on
+the actual chip if both are supported; the LM80, for example, has only
+IRQ interrupts): IRQ interrupts and SMI interrupts.  IRQ stands for
+Interrupt Request and are the interrupt lines you can find in <samp><span class="file">/proc/interrupts</span></samp>. 
+SMI stands for System Management Interrupt, and is a special interrupt which
+puts the processor in a secure environment independent of any other things
+running.  SMI is currently not supported by the Linux kernel.  IRQs are
+supported, of course.
+
+   <p>Even if no interrupt is generated, some bits in a status register
+will be set until the register is read the next time. If the alarm condition
+persists after that, the bits will be set on the next scanning sweep, etc.
+
+   <p>Most drivers in our package do not support interrupts at this time.
+
+<div class="node">
+<p><hr>
+<a name="Installation"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Problems">Problems</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Basics">Basics</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
+
+</div>
+
+<h2 class="chapter">3 Installation and Management</h2>
+
+<ul class="menu">
+<li><a accesskey="1" href="#Section-3_002e1">Section 3.1</a>:      Why so many modules, and how do I cope with them? 
+<li><a accesskey="2" href="#Section-3_002e2">Section 3.2</a>:      How do I know which chips I own? 
+<li><a accesskey="3" href="#Section-3_002e3">Section 3.3</a>:      Which modules should I insert? 
+<li><a accesskey="4" href="#Section-3_002e4">Section 3.4</a>:      Do I need the configuration file <samp><span class="file">/etc/sensors.conf</span></samp>? 
+<li><a accesskey="5" href="#Section-3_002e5">Section 3.5</a>:      What about the `<samp><span class="samp">No such file or directory</span></samp>' warnings
+<li><a accesskey="6" href="#Section-3_002e6">Section 3.6</a>:      I get all kinds of weird compilation errors? 
+<li><a accesskey="7" href="#Section-3_002e7">Section 3.7</a>:      It still does not compile or patch! 
+<li><a accesskey="8" href="#Section-3_002e8">Section 3.8</a>:      <samp><span class="command">make install</span></samp> fails on Mandrake kernels
+<li><a accesskey="9" href="#Section-3_002e9">Section 3.9</a>:      I get unresolved symbols when I <samp><span class="command">modprobe</span></samp> modules
+<li><a href="#Section-3_002e10">Section 3.10</a>:     I2C_DRIVERID_ADM1024 undefined (Red Hat especially)
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-3.1"></a>
+<a name="Section-3_002e1"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-3_002e2">Section 3.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.1 Why so many modules, and how do I cope with them?</h3>
+
+<p>We tried to make this package as modular as possible. This makes it
+easy to add new drivers, and unused drivers will take no precious kernel
+space. On the other hand, it can be a bit confusing at first.
+
+   <p>Here are two simple guidelines:
+     <ul>
+  <li>Run <samp><span class="command">sensors-detect</span></samp> and do what it tells you. 
+  <li>Always use <samp><span class="command">modprobe</span></samp>, not <samp><span class="command">insmod</span></samp>. 
+</ul>
+
+   <p>Further information is in <samp><span class="file">doc/modules</span></samp>.
+
+   <p><a name="How-do-I-know-which-chips-I-own"></a>
+<div class="node">
+<p><hr>
+<a name="Section-3.2"></a>
+<a name="Section-3_002e2"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-3_002e3">Section 3.3</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-3_002e1">Section 3.1</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.2 How do I know which chips I own?</h3>
+
+<p>We have an excellent program that scans all your hardware. 
+It is called <samp><span class="file">sensors-detect</span></samp> and is installed in <samp><span class="file">/usr/local/sbin</span></samp>
+by <samp><span class="command">make install</span></samp>. Just execute this script, and it will tell you.
+
+   <p>Chip detection in the drivers is fairly good. That means that it is
+usually harmless to insert more chip drivers than you need. However, this
+can still lead to problems, so we do not recommend it.
+
+   <p>If sensors-detect didn't find any sensors, either you don't have
+any, or the ones you have, we don't support. (Look at your motherboard
+for candidates, then see <a href="#Help">Help</a>)
+
+   <p><a name="Section-3_002e2_002e1"></a>
+
+<h4 class="subsection">3.2.1 What chips are on motherboard XYZ?</h4>
+
+<p><strong>!!!!!!!!! YES THIS IS THE MOST FREQUENT QUESTION WE GET !!!!!!!!!</strong>
+
+   <p>We have no idea. Here is what you should do:
+     <ol type=1 start=1>
+  <li>Run sensors-detect.
+        </ol>
+
+   <p>If that doesn't work:
+     <ol type=1 start=2>
+<li>Look at your motherboard. 
+<li>Check the manufacturer's website or ask their support
+<li>Check the
+<a href="http://www.lm-sensors.org/wiki/UsefulLinks">"links"</a>
+page on <a href="http://www.lm-sensors.org">our website</a> some good cross-references.
+        </ol>
+
+   <p><a name="Section-3_002e2_002e2"></a>
+
+<h4 class="subsection">3.2.2 Do you support motherboard XYZ?</h4>
+
+<p>We don't support boards, we support chips. See <a href="#Section-3_002e2_002e1">What chips are on motherboard XYZ</a>.
+
+   <p><a name="Section-3_002e2_002e3"></a>
+
+<h4 class="subsection">3.2.3 Do you support chip XYZ?</h4>
+
+<p>This we have good answers for.
+     <ul>
+<li>Sorted by Manufacturer:   <samp><span class="file">README</span></samp>
+<li>Sorted by Manufacturer:   <a href="http://www.lm-sensors.org/wiki/Devices">http://www.lm-sensors.org/wiki/Devices</a>
+<li>Sorted by Sensor Driver:  <samp><span class="file">doc/chips/SUMMARY</span></samp>
+</ul>
+
+   <p><a name="Section-3_002e2_002e4"></a>
+
+<h4 class="subsection">3.2.4 Anybody working on a driver for chip XYZ?</h4>
+
+<p>Newest Driver Status: <a href="http://www.lm-sensors.org/wiki/Devices">http://www.lm-sensors.org/wiki/Devices</a>
+
+<div class="node">
+<p><hr>
+<a name="Section-3.3"></a>
+<a name="Section-3_002e3"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-3_002e4">Section 3.4</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-3_002e2">Section 3.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.3 Which modules should I insert?</h3>
+
+<p><samp><span class="command">sensors-detect</span></samp> will tell you. Take the <samp><span class="command">modprobe</span></samp> lines it
+recommends and paste them into the appropriate <samp><span class="file">/etc/rc.d/xxxx</span></samp> file
+to be executed at startup.
+
+   <p>You need one module for each sensor chip and bus adapter you own;
+if there are sensor chips on the ISA bus, you also need <samp><span class="file">i2c-isa.o</span></samp>. 
+for each type of chip you own. That's all. On my computer, I could use the
+following lines:
+     <ul>
+<li><samp><span class="command">modprobe i2c-isa</span></samp>
+<li><samp><span class="command">modprobe i2c-piix4</span></samp>
+<li><samp><span class="command">modprobe lm78</span></samp>
+<li><samp><span class="command">modprobe lm75</span></samp>
+<li><samp><span class="command">modprobe i2c-dev</span></samp>
+<li><samp><span class="command">sensors -s</span></samp>
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-3.4"></a>
+<a name="Section-3_002e4"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-3_002e5">Section 3.5</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-3_002e3">Section 3.3</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.4 Do I need the configuration file <samp><span class="file">/etc/sensors.conf</span></samp>?</h3>
+
+<p>Yes, for any applications that use <samp><span class="file">libsensors,</span></samp> including the
+<samp><span class="command">sensors</span></samp> application included in our package. 
+It tells libsensors how to translate the values the chip
+measures to real-world values. This is especially important for voltage
+inputs. The default configuration file should usually do the trick. 
+It is automatically installed as <samp><span class="file">/etc/sensors.conf</span></samp>, but it will not
+overwrite any existing file with that name.
+
+   <p><a name="Section-3_002e4_002e1"></a>
+
+<h4 class="subsection">3.4.1 The labels for the voltage and temperature readings in <samp><span class="command">sensors</span></samp> are incorrect!</h4>
+
+<p>Every motherboard is different. You can customize the labels
+in the file <samp><span class="file">/etc/sensors.conf</span></samp>. That's why it exists! 
+The default labelling (in <samp><span class="file">lib/chips.c</span></samp> and <samp><span class="file">/etc/sensors.conf</span></samp>) is just
+a template.
+
+   <p><a name="Section-3_002e4_002e2"></a>
+
+<h4 class="subsection">3.4.2 The min and max for the readings in <samp><span class="command">sensors</span></samp> are incorrect!</h4>
+
+<p>You can customize them in the file <samp><span class="file">/etc/sensors.conf</span></samp>. See above.
+
+   <p><a name="Section-3_002e4_002e3"></a>
+
+<h4 class="subsection">3.4.3 The min and max settings in <samp><span class="file">/etc/sensors.conf</span></samp> didn't take effect!</h4>
+
+<p>You forgot to run <samp><span class="command">sensors -s</span></samp>. See above.
+
+   <p><a name="Section-3_002e4_002e4"></a>
+
+<h4 class="subsection">3.4.4 One sensor isn't hooked up on my board!</h4>
+
+<p>Use an <samp><span class="command">ignore</span></samp> line in <samp><span class="file">/etc/sensors.conf</span></samp> so it isn't
+displayed in <samp><span class="command">sensors</span></samp>.
+
+   <p><a name="Section-3_002e4_002e5"></a>
+
+<h4 class="subsection">3.4.5 I need help with <samp><span class="file">sensors.conf</span></samp>!</h4>
+
+<p>There is detailed help at the top of that file.
+
+   <p><a name="Section-3_002e4_002e6"></a>
+
+<h4 class="subsection">3.4.6 Do you have a database of <samp><span class="file">sensors.conf</span></samp> entries for specific boards?</h4>
+
+<p>No. Good idea though. If you would like to set one up on your website
+send us mail and we will set up a link to it.
+
+<div class="node">
+<p><hr>
+<a name="Section-3.5"></a>
+<a name="Section-3_002e5"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-3_002e6">Section 3.6</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-3_002e4">Section 3.4</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.5 What about the `<samp><span class="samp">No such file or directory</span></samp>' warnings when I compile?</h3>
+
+<p>Don't worry about them. The dependency files (which tell which
+files should be recompiled when certain files change) are created
+dynamically. They are not distributed with the package. The <samp><span class="command">make</span></samp> program
+notices they are not there, and warns about that - and the first thing
+it will do is generate them. So all is well.
+
+<div class="node">
+<p><hr>
+<a name="Section-3.6"></a>
+<a name="Section-3_002e6"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-3_002e7">Section 3.7</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-3_002e5">Section 3.5</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.6 I get all kinds of weird compilation errors?</h3>
+
+<p>Check that the correct i2c header files are used. Depending on
+how you installed, they should be under either <samp><span class="file">/usr/local/include</span></samp> or
+<samp><span class="file">/usr/src/linux*/include</span></samp>. Try to edit the <samp><span class="file">Makefile</span></samp> for the other setting.
+
+   <p><a name="Section-3_002e6_002e1"></a>
+
+<h4 class="subsection">3.6.1 `<samp><span class="samp">No rule to make target xxxx needed by xxxx</span></samp>' - how to fix?</h4>
+
+     <ul>
+<li>See <a href="#Section-3_002e6">I get all kinds of weird compilation errors</a>, also try <samp><span class="command">make clean</span></samp> in <samp><span class="file">lm_sensors</span></samp>. 
+<li>If that doesn't work, try <samp><span class="command">make clean</span></samp> in <samp><span class="file">i2c</span></samp>. 
+<li>If that doesn't work, try <samp><span class="command">make clean</span></samp> in the kernel. 
+<li>Also make sure <samp><span class="file">/usr/include/linux</span></samp> points to <samp><span class="file">/usr/src/linux/include/linux</span></samp>. 
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-3.7"></a>
+<a name="Section-3_002e7"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-3_002e8">Section 3.8</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-3_002e6">Section 3.6</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.7 It still does not compile or patch!</h3>
+
+<p>Have you installed the matching version of the i2c package? Remember,
+compilation is not enough, you also need to install it for the header
+files to be found!
+
+   <p>If you want to patch the kernel, you will have to apply the i2c
+patches first!
+
+<div class="node">
+<p><hr>
+<a name="Section-3.8"></a>
+<a name="Section-3_002e8"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-3_002e9">Section 3.9</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-3_002e7">Section 3.7</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.8 <samp><span class="command">make install</span></samp> fails on Mandrake kernels</h3>
+
+<p>Mandrake uses a non-standard <samp><span class="file">version.h</span></samp> file which confuses our <samp><span class="file">Makefile</span></samp>. 
+Edit our <samp><span class="file">Makefile</span></samp> on the <code>MODDIR :=</code> line to hard-code the module directory.
+
+<div class="node">
+<p><hr>
+<a name="Section-3.9"></a>
+<a name="Section-3_002e9"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-3_002e10">Section 3.10</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-3_002e8">Section 3.8</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.9 I get unresolved symbols when I <samp><span class="command">modprobe</span></samp> modules (Red Hat especially)</h3>
+
+<p>Example:
+<pre class="example">     *** Unresolved symbols in /lib/modules/2.4.5/kernel/drivers/i2c/i2c-i810.o
+     i2c_bit_add_bus_R8c3bc60e
+     i2c_bit_del_bus_R92b18f49
+</pre>
+   <p>You can also run <samp><span class="command">depmod -a -e</span></samp> to see all unresolved symbols.
+
+   <p>These are module versioning problems. Generally you did not compile
+against the kernel you are running. Sometimes the Red Hat source you
+have is not for the kernel you are running. 
+You must compile our package against the source for the kernel you
+are running with something like <samp><span class="command">make LINUX=/usr/src/linux-2.4.14</span></samp>.
+
+   <p>Try the following to be sure:
+
+     <ul>
+<li><samp><span class="command">nm --extern MODULE.o</span></samp>
+Filter out the kernel symbols, like <code>kmalloc</code>, <code>printk</code> etc. and note the
+number code behind them, like <code>printk_R1b7d4074</code>. If there is no numeric
+code after them, note this too. 
+<li><samp><span class="command">grep SYMBOL /proc/ksyms</span></samp>
+Substitute SYMBOL by the basename of the symbols above, like <code>kmalloc</code>,
+<code>printk</code> etc. Note the number code behind them, or the lack thereof. 
+<li>Compare both sets of symbols. Are they the same? If so, the problem
+lies somewhere else. Are they different? If so, you have a module
+versioning problem. 
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-3.10"></a>
+<a name="Section-3_002e10"></a>
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-3_002e9">Section 3.9</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Installation">Installation</a>
+
+</div>
+
+<h3 class="section">3.10 I2C_DRIVERID_ADM1024 undefined (Red Hat especially)</h3>
+
+<p>In some versions of Redhat, an RPM is included to provide i2c support. 
+However, this RPM does not place the header files in the kernel directory
+structure.  When you update kernels, they may persist.  To get rid of
+these obsolete header files, at a command prompt:
+
+     <ol type=1 start=1>
+<li><samp><span class="command">rpm -qa | grep i2c</span></samp>
+<li>Look for <samp><span class="file">kernel-i2c,</span></samp> or a similar rpm in the output
+<li>&lt;as root&gt;
+<samp><span class="command">rpm -ev kernel-i2c</span></samp> (or the name of the similar package)
+If this complains about dependencies, you can try adding
+<samp><span class="command">--nodeps</span></samp>, but this *MAY* break something else.  Not likely,
+as you have upgraded kernels, and nothing should be using the
+old i2c stuff anymore anyway.  Just don't use it with abandon. 
+<li>Try (in the build directory of <samp><span class="file">lm_sensors)</span></samp>
+     <pre class="example">          <samp><span class="command">make clean</span></samp>
+          <samp><span class="command">make</span></samp>
+     </pre>
+     <li><em>If</em> you still have problems, you may have to replace the include
+paths in the <samp><span class="file">.c/.h</span></samp> files with absolute paths to the header files. 
+More of a workaround than a real fix, but at least you can get it
+to work.
+        </ol>
+
+<div class="node">
+<p><hr>
+<a name="Problems"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Help">Help</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Installation">Installation</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
+
+</div>
+
+<h2 class="chapter">4 Problems</h2>
+
+<ul class="menu">
+<li><a accesskey="1" href="#Section-4_002e1">Section 4.1</a>:          My fans report exactly half/double their values? 
+<li><a accesskey="2" href="#Section-4_002e2">Section 4.2</a>:          Why do my two LM75's report "-48 degrees"? 
+<li><a accesskey="3" href="#Section-4_002e3">Section 4.3</a>:          Why do I have two Vcore readings? 
+<li><a accesskey="4" href="#Section-4_002e4">Section 4.4</a>:          How do those ALARMS work? 
+<li><a accesskey="5" href="#Section-4_002e5">Section 4.5</a>:          My voltage readings seem to drift a bit. What's wrong? 
+<li><a accesskey="6" href="#Section-4_002e6">Section 4.6</a>:          Some measurements are way out of range. What happened? 
+<li><a accesskey="7" href="#Section-4_002e7">Section 4.7</a>:          What are VID lines? Why is the VID reading wrong? 
+<li><a accesskey="8" href="#Section-4_002e8">Section 4.8</a>:          Sensor are only updated each second or so. Why? 
+<li><a accesskey="9" href="#Section-4_002e9">Section 4.9</a>:          It takes a second before reading sensor results. Why? 
+<li><a href="#Section-4_002e10">Section 4.10</a>:         Can I be alerted when an ALARM occurs? 
+<li><a href="#Section-4_002e11">Section 4.11</a>:         SMBus transactions on my PIIX4 simply don't work. Why? 
+<li><a href="#Section-4_002e12">Section 4.12</a>:         My BIOS reports a higher CPU temperature than you! 
+<li><a href="#Section-4_002e13">Section 4.13</a>:         I read strange values from the raw <samp><span class="file">/proc</span></samp> files! 
+<li><a href="#Section-4_002e14">Section 4.14</a>:         How do I set new limits? 
+<li><a href="#Section-4_002e15">Section 4.15</a>:         Some sensors are doubly detected? 
+<li><a href="#Section-4_002e16">Section 4.16</a>:         I ran sensors-detect, but now I get strange readings?! 
+<li><a href="#Section-4_002e17">Section 4.17</a>:         Bad readings from particular chips
+<li><a href="#Section-4_002e18">Section 4.18</a>:         How do I configure two chips (LM87) differently? 
+<li><a href="#Section-4_002e19">Section 4.19</a>:         Dmesg says `<samp><span class="samp">Upgrade BIOS</span></samp>'! I don't want to! 
+<li><a href="#Section-4_002e20">Section 4.20</a>:         Sensors says `<samp><span class="samp">Can't access procfs/sysfs file</span></samp>'
+<li><a href="#Section-4_002e21">Section 4.21</a>:         Sensors says `<samp><span class="samp">No sensors found!</span></samp>'
+<li><a href="#Section-4_002e22">Section 4.22</a>:         Sensors output is not correct! 
+<li><a href="#Section-4_002e23">Section 4.23</a>:         What is at I2C address XXX? 
+<li><a href="#Section-4_002e24">Section 4.24</a>:         Sensors-detect doesn't work at all
+<li><a href="#Section-4_002e25">Section 4.25</a>:         Sensors says `<samp><span class="samp">Error: Line xxx: zzzzzzz</span></samp>'
+<li><a href="#Section-4_002e26">Section 4.26</a>:         Sensors only gives the name and adapter! 
+<li><a href="#Section-4_002e27">Section 4.27</a>:         Sensors says `<samp><span class="samp">ERROR: Can't get xxxxx data!</span></samp>'
+<li><a href="#Section-4_002e28">Section 4.28</a>:         Sensors doesn't find any sensors, just eeproms. 
+<li><a href="#Section-4_002e29">Section 4.29</a>:         Inserting modules hangs my board
+<li><a href="#Section-4_002e30">Section 4.30</a>:         Inserting modules slows down my board
+<li><a href="#Section-4_002e31">Section 4.31</a>:         Problems on particular motherboards
+<li><a href="#Section-4_002e32">Section 4.32</a>:         Problems on 2.6 kernels
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-4.1"></a>
+<a name="Section-4_002e1"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e2">Section 4.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.1 My fans report exactly half/double their values compared to the BIOS?</h3>
+
+<p>The problem with much of the sensor data is that it is impossible to
+properly interpret some of the readings without knowing what the hardware
+configuration is.  Some fans report one 'tick' each rotation, some report
+two 'ticks' each rotation. It is easy to resolve this through the
+configuration file <samp><span class="file">/etc/sensors.conf</span></samp>:
+
+<pre class="example">     chip lm78-*             # Or whatever chip this relates to
+     compute fan1 2*@,@/2    # This will double the fan1 reading
+                             # -- or --
+     compute fan1 @/2,2*@    # This will halve the fan1 reading
+</pre>
+   <p>See <samp><span class="file">doc/fan-divisors</span></samp> in our package for further information.
+
+   <p><a name="Fans-sometimes_002falways-read-0_0021"></a>
+
+<h4 class="subsection">4.1.1 Fans sometimes/always read 0!!</h4>
+
+<p>You may not have a three-wire fan, which is required.
+
+   <p>You may need to increase the 'fan divisor'. See <samp><span class="file">doc/fan-divisors</span></samp>
+in our package for further information.
+
+   <p><a name="I-doubled-the-fan-divisor-and-the-fan-still-reads-7000"></a>
+
+<h4 class="subsection">4.1.2 I doubled the fan divisor and the fan still reads 7000!</h4>
+
+<p>Believe it or not, doubling the 'fan divisor' will not halve
+the fan reading. You have to add a compute line in <samp><span class="file">/etc/sensors.conf</span></samp>. 
+See <a href="#Section-4_002e1">My fans report exactly half/double their values compared to the BIOS</a>,
+and see <samp><span class="file">doc/fan-divisors</span></samp> in our package for further information.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.2"></a>
+<a name="Section-4_002e2"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e3">Section 4.3</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e1">Section 4.1</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.2 Why do my two LM75's report "-48 degrees"?</h3>
+
+<p>For starters, those aren't LM75's.  Your mainboard actually has the
+Winbond W83781D which emulates two LM75's, but many systems which use the
+Winbond chip (such as the Asus P2B) don't have the thermo-resisters connected
+to the chip resulting in these strange -48 degree readings.
+
+   <p>In upcoming versions, you will be able to disable non-interesting
+readings.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.3"></a>
+<a name="Section-4_002e3"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e4">Section 4.4</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e2">Section 4.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.3 Why do I have two Vcore readings, I have only one processor!</h3>
+
+<p>The LM78 has seven voltage sensors. The default way of
+connecting them is used in the configuration file. This includes a VCore2,
+even if you do not have one. You can easily edit the configuration file
+to give it another name, or make this reading disappear using
+an <samp><span class="command">ignore</span></samp> line.
+
+   <p>Note that Vcore2 is often the same as Vcore on motherboards which
+only support one processor. Another possibility is that Vcore2 is not
+connected at all and will not have a valid reading at all. 
+A third possibility, is that Vcore2 monitors something
+else, so you should not be too surprised if the values are completely
+different.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.4"></a>
+<a name="Section-4_002e4"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e5">Section 4.5</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e3">Section 4.3</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.4 How do those ALARMS work? The current value is within range but there is still an ALARM warning!</h3>
+
+<p>The ALARM indications in <samp><span class="command">sensors</span></samp> are those reported by the
+sensor chip itself. They are NOT calculated by <samp><span class="command">sensors</span></samp>. <samp><span class="command">sensors</span></samp>
+simply reads the ALARM bits and reports them.
+
+   <p>An ALARM will go off when a minimum or maximum limit is crossed. 
+The ALARM is then latched - that is, it will stay there until the
+chip's registers are next accessed - which will be the next time
+you read these values, but not within (usually) 1.5 seconds since the last
+update.
+
+   <p>Reading the registers clears the ALARMS, unless the current
+value is still out of range.
+
+   <p>The purpose of this scheme is to tell you if there has been
+a problem and report it to the user. Voltage or temperature spikes
+get detected without having to read the sensor chip hundreds of times
+a second. The implemetation details depend a bit on the kind of chip. 
+See the specific chip documentation in <samp><span class="file">doc/chips</span></samp> and the
+chip datasheet for more information.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.5"></a>
+<a name="Section-4_002e5"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e6">Section 4.6</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e4">Section 4.4</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.5 My voltage readings seem to drift a bit. Is something wrong?</h3>
+
+<p>No, probably not. If your motherboard heats up a bit, the sensed
+voltages will drift a bit. If your power supply is loaded (because a disk
+gets going, for example), the voltages may get a bit lower. Heavy
+processor activity, in particular, dramatically increases core voltage
+supply load which will often cause variation in the other supplies. 
+As long as they stay within a sensible range (say 5% of the nominal value
+for CPU core voltages, and 10% for other voltages), there is no
+reason to worry.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.6"></a>
+<a name="Section-4_002e6"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e7">Section 4.7</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e5">Section 4.5</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.6 Some measurements are way out of range. What happened?</h3>
+
+<p>Each module tries to set limits to sensible values on initialization,
+but a module does not know how a chip is actually connected. This is
+described in the configuration file, which is not read by kernel modules. 
+So limits can be strange, if the chip is connected in a non-standard way.
+
+   <p>Readings can also be strange; there are several reasons for this. 
+Temperature sensors, for example, can simply not be present, even though
+the chip supports them. Also, it can be that the input is used in a
+non-standard way. You can use the configuration file to describe how this
+measurement should be interpreted; see the comments the example file for
+more information.
+
+   <p><a name="g_t_002d5V-and-_002d12V-readings-are-way-out-of-range_0021"></a>
+
+<h4 class="subsection">4.6.1 -5V and -12V readings are way out of range!</h4>
+
+<p>It's very frequent that negative voltage lines are not wired because
+motherboard manufacturers don't think they're worth monitoring
+(they are mostly unused these days). You can just add
+<samp><span class="command">ignore inN</span></samp> lines to <samp><span class="file">/etc/sensors.conf</span></samp> to hide them.
+
+   <p>Another possibility is that these lines are used to monitor different
+voltages. Only the motherboard manufacturer can tell for sure. Taking
+a look at what voltage values the BIOS displays may provide valuable
+hints though.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.7"></a>
+<a name="Section-4_002e7"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e8">Section 4.8</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e6">Section 4.6</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.7 What are VID lines? Why is the VID reading wrong?</h3>
+
+<p>These describe the core voltage for your processor. They are
+supported for most processors, however they are not always
+correctly connected to the sensor chip, so the readings may be invalid. 
+A reading of 0V, +3.5V or +2.05V is especially suspect. 
+If this is the case, add a line <samp><span class="command">ignore vid</span></samp> to <samp><span class="file">/etc/sensors.conf</span></samp>,
+and change the min and max settings for the Processor Core voltage
+(often in0_min and in0_max) in that file so that they don't depend on vid.
+
+   <p>The CPU nominal voltage is computed from VID lines according to a formula
+that depends on the CPU type. Since Linux 2.6.9, the right formula is
+selected automatically. 
+See <samp><span class="file">doc/vid</span></samp> for more information.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.8"></a>
+<a name="Section-4_002e8"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e9">Section 4.9</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e7">Section 4.7</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.8 I read sensor values several times a second, but they are only updated only each second or so. Why?</h3>
+
+<p>If we would read the registers more often, it would not find the
+time to update them. So we only update our readings once each 1.5 seconds
+(the actual delay is chip-specific; for some chips, it may not be needed
+at all).
+
+<div class="node">
+<p><hr>
+<a name="Section-4.9"></a>
+<a name="Section-4_002e9"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e10">Section 4.10</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e8">Section 4.8</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.9 It sometimes seems to take almost a second before I see the sensor reading results. Why?</h3>
+
+<p>ISA bus access is fast, but SMBus access is really slow. If you have
+a lot of sensors, it just takes a lot of time to access them. Fortunately,
+this has almost no impact on the system as a whole, as another job can run
+while we are waiting for the transaction to finish.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.10"></a>
+<a name="Section-4_002e10"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e11">Section 4.11</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e9">Section 4.9</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.10 Can I be alerted when an ALARM occurs?</h3>
+
+<p>No, you can't; and it may well be never supported.
+
+   <p>Almost no mainboard we have encountered have actually connected the
+IRQ-out pin of sensor chips. That means that we could enable IRQ reporting, but
+nothing would happen. Also, even if a motherboard has it connected, it is
+unclear what interrupt number would be triggered. And IRQ lines are a scarce
+facility, which means that almost nobody would be able to use it anyway.
+
+   <p>The SMI interrupt is only available on a few types of chips. It is
+really a very obscure way to handle interrupts, and supporting it under Linux
+might be quite hard to do.
+
+   <p>Your best bet would be to poll the alarm file with a user-land daemon
+which alerts you if an alarm is raised. I am not aware of any program which
+does the job, though you might want to examine one of the graphical monitor
+programs under X, see <a href="http://www.lm-sensors.org/wiki/UsefulLinks">http://www.lm-sensors.org/wiki/UsefulLinks</a> for addresses.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.11"></a>
+<a name="Section-4_002e11"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e12">Section 4.12</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e10">Section 4.10</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.11 SMBus transactions on my PIIX4 simply don't work (timeouts happen).  Why?</h3>
+
+<p>Some chips which mainboard makers connect to the SMBus are not SMBus
+devices.  An example is the 91xx clock generator chips.  When read, these
+devices can lock up the SMBus until the next hard reboot.  This is because
+they have a similar serial interface (like the I2C), but don't conform to
+Intel's SMBus standard.
+
+   <p>Why did they connect these devices to the SMBus if they aren't
+compatible?  Good question! :')  Actually, these devices may support being
+written to, but lock things up when they are read.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.12"></a>
+<a name="Section-4_002e12"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e13">Section 4.13</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e11">Section 4.11</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.12 My BIOS reports a much higher CPU temperature than your modules!</h3>
+
+<p>We display the actual temperature of the sensor. This may not be the
+temperature you are interested in, though.  If a sensor should measure
+the CPU temperature, it must be in thermal contact with it.  In practice,
+it may be just somewhere nearby. Your BIOS may correct for this (by adding,
+for example, thirty degrees to the measured temperature).  The correction
+factor is regrettably different for each mainboard, so we can not do this
+in the module itself. You can do it through the configuration file, though:
+
+<pre class="example">     chip lm75-*-49                      # Or whatever chip this relates to
+     label temp "Processor"
+     compute temp @*1.2+13,(@-13)/1.2    # Or whatever formula
+</pre>
+   <p>However, the offset you are introducing might not be necessary. If you
+tried to have Linux idle temperature and BIOS "idle" temperature match,
+you may be misguided. 
+We have a Supermicro (370DLE) motherboard and we know
+that its BIOS has a closed, almost undelayed while(1) loop that
+keeps the CPU busy all the time. Linux reads 26 degrees idle, BIOS reads
+38 degrees. Linux at full load is in the 35-40 degrees range so this
+makes sense.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.13"></a>
+<a name="Section-4_002e13"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e14">Section 4.14</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e12">Section 4.12</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.13 I try to read the raw <samp><span class="file">/proc</span></samp> files, but the values are strange?!?</h3>
+
+<p>Remember, these values do not take the configuration file
+<samp><span class="file">compute</span></samp> lines in account. This is especially obvious for voltage readings
+(usually called in? or vin?). Use a program linked to libsensors (like
+the provided <samp><span class="command">sensors</span></samp> program) instead.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.14"></a>
+<a name="Section-4_002e14"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e15">Section 4.15</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e13">Section 4.13</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.14 How do I set new limits?</h3>
+
+<p>Change the limit values in <samp><span class="file">/etc/sensors.conf</span></samp> and then run
+<samp><span class="command">sensors -s</span></samp>.
+
+   <p><a name="I-set-new-limits-and-it-didnt-work"></a>
+
+<h4 class="subsection">4.14.1 I set new limits and it didn't work?</h4>
+
+<p>You forgot to run <samp><span class="command">sensors -s</span></samp>. Put it in a <samp><span class="file">/etc/rc.d/...</span></samp> file
+after the modprobe lines to run at startup.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.15"></a>
+<a name="Section-4_002e15"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e16">Section 4.16</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e14">Section 4.14</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.15 Some sensors are doubly detected?</h3>
+
+<p>Yes, this is still a problem. It is partially solved by alias detection
+and confidence values in sensors-detect, but it is really tough.
+
+   <p>Double detections can be caused by two things:
+sensors can be detected to both the ISA and the SMBus (and if you have
+loaded the approprate adapter drivers, it will be detected on both), and
+some chips simulate other chips (the Winbond W83781D simulates LM75 chips
+on the SMBus, for example). Remove the offending adapter or chip driver, or
+run sensors-detect and add the <samp><span class="command">ignore=</span></samp> modprobe parameters it suggests.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.16"></a>
+<a name="Section-4_002e16"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e17">Section 4.17</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e15">Section 4.15</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.16 I ran sensors-detect, but now I get very strange readings?!?</h3>
+
+<p>Your SMBus (PIIX4?) is probably crashed or hung. There are some mainboards
+which connect a clock chip to the SMBus. Unfortunately, this clock chip
+hangs the PIIX4 if it is read (it is an I2C device, but not SMBus compatible). 
+We have found no way of solving this, except for rebooting your computer. 
+Next time when you run sensors-detect, you may want to exclude addresses
+0x69 and/or 0x6a, by entering <kbd>s</kbd> when you are asked whether you want to
+scan the PIIX4.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.17"></a>
+<a name="Section-4_002e17"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e18">Section 4.18</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e16">Section 4.16</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.17 Bad readings from particular chips</h3>
+
+<p>See below for some particularly troublesome chips. 
+Also be sure and check <samp><span class="file">doc/chips/xxxxx</span></samp> for the particular driver.
+
+   <p><a name="Bad-readings-from-the-AS99127F"></a>
+
+<h4 class="subsection">4.17.1 Bad readings from the AS99127F!</h4>
+
+<p>The Asus AS99127F is a modified version of the Winbond W83781D. 
+Asus will not release a datasheet. The driver was developed by tedious
+experimentation. We've done the best we can. If you want to make adjustments
+to the readings please edit <samp><span class="file">/etc/sensors.conf.</span></samp> Please don't ask us to
+fix the driver. Ask Asus to release a datasheet.
+
+   <p><a name="Bad-readings-from-the-VIA-686A"></a>
+
+<h4 class="subsection">4.17.2 Bad readings from the VIA 686A!</h4>
+
+<p>The Via 686A datasheet is incomplete. 
+Via will not release details. The driver was developed by tedious
+experimentation. We've done the best we can. If you want to make adjustments
+to the readings please edit <samp><span class="file">/etc/sensors.conf.</span></samp> Please don't ask us to
+fix the driver. Ask Via to release a better datasheet. 
+Also, don't forget to <samp><span class="command">modprobe i2c-isa</span></samp>.
+
+   <p><a name="Bad-readings-from-the-MTP008"></a>
+
+<h4 class="subsection">4.17.3 Bad readings from the MTP008!</h4>
+
+<p>The MTP008 has programmable temperature sensor types. 
+If your sensor type does not match the default, you will have to change it. 
+See <samp><span class="file">doc/chips/mtp008</span></samp> for details. 
+Also, MTP008 chips seem to randomly refuse to respond, for
+unknown reasons. You can see this as 'XX' entries in i2cdump.
+
+   <p><a name="Bad-temperature-readings-from-the-SIS5595"></a>
+
+<h4 class="subsection">4.17.4 Bad temperature readings from the SIS5595!</h4>
+
+<p>This chip can use multiple thermistor types and there are also
+two different versions of the chip. We are trying to get the driver
+working better and develop formulas for different thermistors
+but we aren't there yet. Sorry. 
+Also, many times the chip isn't really a sis5595 but it was
+misidentified. We are working on improving that too.
+
+   <p><a name="Bad-readings-from-a-w8378_005b12_005dd"></a>
+
+<h4 class="subsection">4.17.5 Bad readings from a w8378[12]d!</h4>
+
+<p>Do you own an ASUS motherboard?  Perhaps your chip is being
+misidentified.  Look on the motherboard for a 'Winbond' or Asus chip. 
+Often the real device is an Asus as99127f. If so, the driver can be
+forced to recognize the as99127f with
+<samp><span class="command">force_as99127f=BUS,0x2d</span></samp> where <code>BUS</code> is your i2c bus number. 
+Cat /proc/bus/i2c to see a list of bus numbers. 
+Read the w83781d module documentation (<samp><span class="file">doc/chips/w83781d</span></samp>)
+for more details.
+
+   <p><a name="Bus-hangs-on-Ali-1543-on-Asus-P5A-boards"></a>
+
+<h4 class="subsection">4.17.6 Bus hangs on Ali 1543 on Asus P5A boards!</h4>
+
+<p>The SMBus tends to hang on this board and it seems to get worse
+at higher temperatures. Use ISA accesses to reliably use the w83781d
+monitor chip on this board and use the <samp><span class="command">ignore=1,0x2d</span></samp> or similar option
+to the w83781d module to prevent i2c accesses.
+
+   <p><a name="Bad-readings-from-LM75"></a>
+
+<h4 class="subsection">4.17.7 Bad readings from LM75!</h4>
+
+<p>The LM75 detection is poor and other hardware is often misdetected
+as an LM75. Figure out what you really have See <a href="#Section-3_002e2_002e1">What chips are on motherboard XYZ</a>.
+
+   <p><a name="Bad-readings-from-LM78"></a>
+
+<h4 class="subsection">4.17.8 Bad readings from LM78!</h4>
+
+<p>The LM78 is no longer manufactured by National Semiconductor. 
+You probably don't have a real LM78 but something similar that we
+do not recogize or support. Figure out what you really have See <a href="#Section-3_002e2_002e1">What chips are on motherboard XYZ</a>.
+
+   <p><a name="Bad-readings-from-LM80"></a>
+
+<h4 class="subsection">4.17.9 Bad readings from LM80!</h4>
+
+<p>The LM80 detection is poor and other hardware is often misdetected
+as an LM80. Figure out what you really have See <a href="#Section-3_002e2_002e1">What chips are on motherboard XYZ</a>.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.18"></a>
+<a name="Section-4_002e18"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e19">Section 4.19</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e17">Section 4.17</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.18 How do I configure two chips (LM87) differently?</h3>
+
+<p>There is a SuperMicro board with two LM87's on it that are
+not hooked up in the same way, so they need different defaults. 
+For example, both CPU temperatures go to one LM87.
+
+   <p>Make two different sections in <samp><span class="file">/etc/sensors.conf</span></samp> as follows:
+<pre class="example">     chip "lm87-i2c-*-2c"
+         put configuration for the chip at 0x2c here
+     chip "lm87-i2c-*-2d"
+         put configuration for the chip at 0x2d here
+</pre>
+   <p>There is a commented example in <samp><span class="file">sensors.conf.eg</span></samp> which should
+be helpful.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.19"></a>
+<a name="Section-4_002e19"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e20">Section 4.20</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e18">Section 4.18</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.19 Dmesg says `<samp><span class="samp">Upgrade BIOS</span></samp>'! I don't want to!</h3>
+
+<p>If the problem is a PCI device is not present in <samp><span class="command">lspci</span></samp>, the solution
+is complex. For the ALI M7101 device, there is a solution which uses the
+2.4 kernel's <samp><span class="command">hotplug</span></samp> facility. See <samp><span class="file">prog/hotplug</span></samp> in our package. 
+For other PCI devices, you can try to modify
+the m7101 solution in <samp><span class="file">prog/hotplug</span></samp>.
+
+   <p>If dmesg says `<samp><span class="samp">try force_addr</span></samp>', see below. Other drivers generally do not
+support the force_addr parameter. Sorry. Check the documentation
+for your driver in <samp><span class="file">doc/[chips,busses]</span></samp> and if we don't support it
+you can send us your request.
+
+   <p><a name="Dmesg-says-use-force_005faddr_003d0xaddr_0021-What-address-do-I-use"></a>
+
+<h4 class="subsection">4.19.1 Dmesg says `<samp><span class="samp">use force_addr=0xaddr</span></samp>'! What address do I use?</h4>
+
+<p>If the problem is a PCI device whose base address is not set,
+you may be able to set the address with a force parameter. The via686a
+and sis5595 chip drivers, and some bus drivers, support the command line
+<samp><span class="command">modprobe via686a force_addr=0xADDRESS</span></samp> where ADDRESS
+is the I/O address. You must select an address that is not in use. 
+<samp><span class="command">cat <samp>/proc/ioports</samp></span></samp> to check (carefully) for conflicts. A high number like
+0xf000 is generally safe.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.20"></a>
+<a name="Section-4_002e20"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e21">Section 4.21</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e19">Section 4.19</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.20 Sensors says `<samp><span class="samp">Can't access procfs/sysfs file</span></samp>'</h3>
+
+     <ul>
+<li>Linux 2.6
+          <ul>
+<li>Did you <samp><span class="command">modprobe i2c_sensor</span></samp>? Check <samp><span class="command">lsmod</span></samp>. 
+<li>Do you have sysfs support in your kernel and <samp><span class="file">/sys</span></samp> mounted (is <samp><span class="file">/sys</span></samp> there and populated)? 
+Create /sys with <samp><span class="command">mkdir /sys</span></samp> if needed. Then add the following line to <samp><span class="file">/etc/fstab</span></samp>:
+          <pre class="example">               sys              /sys             sysfs       default          0   0</pre>
+          <p>and <samp><span class="command">mount /sys</span></samp>. 
+</ul>
+     <li>Linux 2.4
+          <ul>
+<li>Did you <samp><span class="command">modprobe i2c-proc</span></samp>? Check <samp><span class="command">lsmod</span></samp>. 
+<li>Do you have procfs support in your kernel and <samp><span class="file">/proc</span></samp> mounted (is <samp><span class="file">/proc</span></samp> there and populated)? 
+Create /proc with <samp><span class="command">mkdir /proc</span></samp> if needed. Then add the following line to <samp><span class="file">/etc/fstab</span></samp>:
+          <pre class="example">               proc             /proc            proc        defaults         0   0</pre>
+          <p>and <samp><span class="command">mount /proc</span></samp>. 
+</ul>
+     <li>If you did <samp><span class="command">sensors -s</span></samp>, did you run it as root? 
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-4.21"></a>
+<a name="Section-4_002e21"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e22">Section 4.22</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e20">Section 4.20</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.21 Sensors says `<samp><span class="samp">No sensors found!</span></samp>'</h3>
+
+     <ul>
+<li>Did <samp><span class="command">sensors-detect</span></samp> find sensors? (If not see <a href="#Sensors_002ddetect-doesnt-find-any-sensors">Sensors-detect doesnt find any sensors</a>)
+<li>Did you do what <samp><span class="command">sensors-detect</span></samp> said? 
+<li>Did you <samp><span class="command">modprobe</span></samp> your sensor modules? 
+<li>Did you <samp><span class="command">modprobe</span></samp> your I2C adapter modules? 
+<li>Did you <samp><span class="command">modprobe i2c-isa</span></samp> if you have ISA sensor chips? 
+<li>Check <samp><span class="command">lsmod</span></samp>. 
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-4.22"></a>
+<a name="Section-4_002e22"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e23">Section 4.23</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e21">Section 4.21</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.22 Sensors output is not correct!</h3>
+
+<p>What specifically is the trouble?
+     <ul>
+<li>Labels: See <a href="#Section-3_002e4_002e1">The labels for the voltage and temperature readings in sensors are incorrect</a>. 
+<li>Min/max readings: See <a href="#Section-3_002e4_002e2">The min and max for the readings in sensors are incorrect</a>, and See <a href="#Section-3_002e4_002e3">The min and max settings didnt take effect</a>. 
+<li>AS99127F: See <a href="#Section-4_002e16">I ran sensors-detect but now I get very strange readings?</a>. 
+<li>Via 686A: See <a href="#Section-4_002e16">I ran sensors-detect but now I get very strange readings?</a>. 
+<li>Other specific chips: See <a href="#Section-4_002e16">I ran sensors-detect but now I get very strange readings?</a>. 
+<li>No output for a particular sensors chip: See <a href="#Section-5_002e3">What to do if it inserts but nothing happens</a>. 
+<li>No output at all: See <a href="#Section-4_002e21">Sensors says No sensors found</a>, See <a href="#Section-5_002e3">What to do if it inserts but nothing happens</a>. 
+<li>Completely bad output for a particular sensor chip: See <a href="#Section-5_002e4">What to do if I read only bogus information</a>. 
+<li>One particular sensor readings:
+          <ul>
+<li>Maybe it isn't hooked up? - tell 'sensors' to ignore it. See <a href="#Section-3_002e4_002e4">One sensor isnt hooked up on my board</a>. 
+<li>Maybe it is hooked up differently on your motherboard? - adjust <samp><span class="file">sensors.conf</span></samp> calculation. 
+</ul>
+     </ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-4.23"></a>
+<a name="Section-4_002e23"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e24">Section 4.24</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e22">Section 4.22</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.23 What is at I2C address XXX?</h3>
+
+<p>In general, we don't know. Start by running <samp><span class="command">sensors-detect</span></samp>. 
+If it doesn't recognize it, try running <samp><span class="command">i2cdump</span></samp>. A partial list
+of manufacturers' IDs are at the bottom of <samp><span class="file">doc/chips/SUMMARY</span></samp>.
+
+   <p><a name="What-is-at-I2C-address-0x69"></a>
+
+<h4 class="subsection">4.23.1 What is at I2C address 0x69?</h4>
+
+<p>A clock chip. Often, accessing these clock chips in the wrong
+way will instantly crash your computer. Sensors-detect carefully
+avoids these chips, and you should do too.  You have been warned.
+
+   <p><a name="What-is-at-I2C-addresses-0x50-_002d-0x57"></a>
+
+<h4 class="subsection">4.23.2 What is at I2C addresses 0x50 - 0x57?</h4>
+
+<p>EEPROMs on your SDRAM DIMMs. Load the eeprom module and use the script
+<samp><span class="command">decode-dimms.pl</span></samp> (in the i2c-tools package)
+to get more information than you ever wanted.
+
+   <p><a name="What-is-at-I2C-addresses-0x30-_002d-0x37"></a>
+
+<h4 class="subsection">4.23.3 What is at I2C addresses 0x30 - 0x37?</h4>
+
+<p>These are often 'shadows' of your EEPROMs on your SDRAM DIMMs
+at addresses 0x50 - 0x57. They are the 'software write-protect'
+registers of the SDRAM Serial Presence Detect EEPROMs. 
+If you try and
+do a <samp><span class="command">i2cdump</span></samp> on them to read the location, you won't get anything,
+because they contain a single write-only register. 
+This register can be used to permanently
+write-protect the contents of the eeprom.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.24"></a>
+<a name="Section-4_002e24"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e25">Section 4.25</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e23">Section 4.23</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.24 Sensors-detect doesn't work at all</h3>
+
+<p>It could be many things. What was the problem? See <a href="#Section-4_002e31">Problems on particular motherboards</a>.
+
+   <p><a name="Sensors_002ddetect-says-_0022Couldnt-open-_002fproc_002fbus_002fi2c_003f_0021_003f_0022"></a>
+
+<h4 class="subsection">4.24.1 Sensors-detect says "Couldn't open /proc/bus/i2c?!?"</h4>
+
+<p>You don't have i2c support in your kernel, or the i2c-core module
+was not loaded and you did not run sensors-detect as root.
+
+   <p><a name="Sensors_002ddetect-says-_0022Cant-open-_002fdev_002fi2c_005b_002d_002f_005d0_0022"></a>
+
+<h4 class="subsection">4.24.2 Sensors-detect says "Can't open /dev/i2c[-/]0"</h4>
+
+<p>Your <samp><span class="file">/dev/i2c-0,</span></samp> <samp><span class="file">/dev/i2c0</span></samp>, or <samp><span class="file">/dev/i2c/0</span></samp> files do not exist
+or you did not run <samp><span class="command">sensors-detect</span></samp> as root. 
+Use <samp><span class="command">MAKEDEV</span></samp> or <samp><span class="command">mknod</span></samp> to create the <samp><span class="file">/dev/i2c-x</span></samp> files. 
+Run <samp><span class="command">devfs</span></samp> in the kernel to get the <samp><span class="file">/dev/i2c/x</span></samp> files.
+
+   <p><a name="Sensors_002ddetect-doesnt-find-any-sensors"></a>
+
+<h4 class="subsection">4.24.3 Sensors-detect doesn't find any sensors!</h4>
+
+<p>Either
+     <ol type=1 start=1>
+<li>The board doesn't have any sensors. 
+<li>We don't support the sensors on the board. 
+<li>The sensors it has are on an I2C bus connected to an I2C bus adapter that we don't support. 
+<li>You don't have the latest version of lm_sensors.
+        </ol>
+
+   <p>But in any case you should figure out what is on the board:
+     <ol type=1 start=1>
+<li>Look at your motherboard. 
+<li>Check the manufacturer's website.
+        </ol>
+
+   <p>When you know what chips you have, check the
+<a href="http://www.lm-sensors.org/wiki/Devices">Driver Status</a> web page to
+see if support has been added for your chip in a later release or in SVN.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.25"></a>
+<a name="Section-4_002e25"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e26">Section 4.26</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e24">Section 4.24</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.25 Sensors says `<samp><span class="samp">Error: Line xxx: zzzzzzz</span></samp>'</h3>
+
+<p>These are errors from the libsensors library in
+reading the <samp><span class="file">/etc/sensors.conf</span></samp> configuration file. Go to that line
+number and fix it. If you have a parse error, perhaps you have
+to put the feature name in double quotes.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.26"></a>
+<a name="Section-4_002e26"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e27">Section 4.27</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e25">Section 4.25</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.26 Sensors only gives the name and adapter for my chip</h3>
+
+<p>If <samp><span class="command">sensors</span></samp> only says this, for example, and doesn't
+provide any actual data at all:
+
+<pre class="example">     it87-isa-0290
+     Adapter: ISA adapter
+</pre>
+   <p>Your chip is not currently supported by <samp><span class="command">sensors</span></samp> and so all it
+does is print out that information. Get the latest release
+and be sure you are running the <samp><span class="command">sensors</span></samp> program it installed
+and not some older <samp><span class="command">sensors</span></samp>.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.27"></a>
+<a name="Section-4_002e27"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e28">Section 4.28</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e26">Section 4.26</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.27 Sensors says `<samp><span class="samp">ERROR: Can't get xxxxx data!</span></samp>'</h3>
+
+     <ul>
+<li>(Linux 2.6) Make sure you are using one of the
+<a href="http://www.lm-sensors.org/wiki/Kernel2.6">recommended kernel/lm_sensors combination</a>. 
+<li>You have a <samp><span class="file">libsensors</span></samp>/<samp><span class="command">sensors</span></samp> mismatch. 
+<samp><span class="command">sensors</span></samp> is unable to
+get a data entry from <samp><span class="file">libsensors</span></samp>. You probably have an
+old <samp><span class="file">libsensors</span></samp> in your <samp><span class="file">/etc/ld.so.conf</span></samp> path. 
+Make sure you did (as root) a <samp><span class="command">make install</span></samp> (Linux 2.4) or
+<samp><span class="command">make user_install</span></samp> (Linux 2.6) followed by a <samp><span class="command">ldconfig</span></samp>. 
+Then check the output of <samp><span class="command">ldconfig -v | grep libsensors</span></samp> to
+verify that there is only ONE <samp><span class="file">libsensors</span></samp> entry and that it matches
+the <samp><span class="file">libsensors</span></samp> that was built in the <samp><span class="file">lib/</span></samp> directory in <samp><span class="file">lm_sensors2</span></samp>. 
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-4.28"></a>
+<a name="Section-4_002e28"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e29">Section 4.29</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e27">Section 4.27</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.28 Sensors doesn't find any sensors, just eeproms.</h3>
+
+<p>See <a href="#Section-4_002e24">Sensors-detect doesnt work at all</a>, if <samp><span class="command">sensors-detect</span></samp> failed to find any sensors.
+
+   <p>If <samp><span class="command">sensors-detect</span></samp> did find sensors, did you insert your modules? For chips on the ISA
+bus, did you insert i2c-isa?
+
+   <p>See <a href="#Section-5_002e2">What to do if a module wont insert</a>, if the modules didn't insert,
+also <a href="#Section-4_002e21">Sensors says No sensors found</a>.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.29"></a>
+<a name="Section-4_002e29"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e30">Section 4.30</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e28">Section 4.28</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.29 Inserting modules hangs my board</h3>
+
+<p>There are several possible causes:
+     <ol type=1 start=1>
+<li>Bus driver problems. Insert the bus driver first, before you have inserted any chip drivers, to verify. 
+<li>Wrong chip driver. Verify that you have a chip supported by the chip driver, see <a href="#Section-3_002e2_002e1">What chips are on motherboard XYZ</a>. 
+<li>The chip driver is reinitializing the chip, which undoes critical initialization done by the BIOS.  Try the parameter <samp><span class="command">init=0</span></samp> for the w83781d driver; this is the only driver supporting this parameter. 
+<li>Some chips on the bus don't like to be probed at all.  After inserting the bus driver (but not the chip drivers), run <samp><span class="command">i2cdetect</span></samp> on the bus, then <samp><span class="command">i2cdump</span></samp> on each address responding to <samp><span class="command">i2cdetect</span></samp>. This may find the culprit.  Do not <samp><span class="command">i2cdump address 0x69</span></samp>, the clock chip. 
+<li>The chip driver is incorrectly finding a second chip on the bus and is accessing it. For example, with the Tyan 2688 with a w83781d at 0x29, use <samp><span class="command">modprobe ignore_range=0,0x00,0x28,0,0x2a,0x7f</span></samp> to prevent access to other addresses. (<samp><span class="command">init=0</span></samp> also req'd for the Tyan 2688).
+        </ol>
+
+<div class="node">
+<p><hr>
+<a name="Section-4.30"></a>
+<a name="Section-4_002e30"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e31">Section 4.31</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e29">Section 4.29</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.30 Inserting modules slows down my board</h3>
+
+<p>Generally this is caused by an overtemperature alarm output from
+the sensor chip. This triggers hardware on the board which
+automatically slows down the CPU clock. Be sure that your
+temperature limits are above the temperature reading. Put
+the new limits in <samp><span class="file">/etc/sensors.conf</span></samp> and run <samp><span class="command">sensors -s</span></samp>.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.31"></a>
+<a name="Section-4_002e31"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-4_002e32">Section 4.32</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e30">Section 4.30</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.31 Problems on particular motherboards</h3>
+
+<p>The following boards have unique problems and solutions.
+
+   <p><a name="Asus-P4B"></a>
+
+<h4 class="subsection">4.31.1 Asus P4B</h4>
+
+<p>See <samp><span class="file">prog/hotplug/README.p4b</span></samp> if your SMBus master is not found.
+
+   <p><a name="Tyan-2460-2462"></a>
+
+<h4 class="subsection">4.31.2 Tyan 2460, 2462</h4>
+
+<p>See support tickets 805, 765, 781, 812, 813, and 867 for information.
+
+   <p><a name="Tyan-2466"></a>
+
+<h4 class="subsection">4.31.3 Tyan 2466</h4>
+
+<p>See support tickets 941, 840, and 841 for information.
+
+   <p><a name="Tyan-2688"></a>
+
+<h4 class="subsection">4.31.4 Tyan 2688</h4>
+
+<p>For board hangs, see support ticket 721 for information. 
+Also <a href="#Section-4_002e29">Inserting modules hangs my board</a>.
+
+<div class="node">
+<p><hr>
+<a name="Section-4.32"></a>
+<a name="Section-4_002e32"></a>
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-4_002e31">Section 4.31</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Problems">Problems</a>
+
+</div>
+
+<h3 class="section">4.32 Problems on 2.6 kernels</h3>
+
+<p>Not all drivers have been ported to 2.6. If your favorite driver is not
+in 2.6, the reason is that nobody has ported it, or the ported code did
+not get a proper review yet. 
+If you would like to port the driver, see the file
+Documentation/i2c/porting-clients in the 2.6 kernel tree for help,
+then send us the ported driver when you are done.
+
+<h4 class="subsection">4.32.1 i2c-viapro and via686a</h4>
+
+<p>Until kernel 2.6.11, there was a PCI resource conflict between
+i2c-viapro (the SMBus driver for VIA bridges) and via686a (the integrated
+sensors driver for VIA bridges). This caused the second loaded driver to
+silently fail working. So do not load both i2c-viapro and via686a together
+unless you have a recent kernel.
+
+<h4 class="subsection">4.32.2 Where are my EEPROMs?</h4>
+
+<p>The 2.6.14-rc1 kernel introduced the hwmon class, which groups all
+hardware monitoring drivers in a logical way. The goal was to help
+libsensors grab the relevant sensors information in /sys. In particular:
+     <ul>
+<li>libsensors will no more need to know about the underlying bus types
+(I2C/SMBus, ISA or other);
+<li>libsensors will no more list non-hardware monitoring chips. 
+</ul>
+   This explains why EEPROMs are no more displayed by <samp><span class="command">sensors</span></samp>:
+they are no hardware monitoring chips. The medium term plan is to drop
+eeprom support for all Linux 2.6 kernels, as it didn't fit well in
+the library code in the first place.
+
+   <p>Note that you can still obtain information about your EEPROMs by using
+the dedicated perl scripts in the i2c-tools package: <samp><span class="command">ddcmon</span></samp>,
+<samp><span class="command">decode-dimms.pl</span></samp>, <samp><span class="command">decode-edid.pl</span></samp> and
+<samp><span class="command">decode-vaio.pl</span></samp>.
+
+<div class="node">
+<p><hr>
+<a name="Help"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Contribute">Contribute</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Problems">Problems</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
+
+</div>
+
+<h2 class="chapter">5 How to Ask for Help</h2>
+
+<ul class="menu">
+<li><a accesskey="1" href="#Section-5_002e1">Section 5.1</a>:   What to send us when asking for help
+<li><a accesskey="2" href="#Section-5_002e2">Section 5.2</a>:   What to do if a module won't insert? 
+<li><a accesskey="3" href="#Section-5_002e3">Section 5.3</a>:   What to do if it inserts, but nothing happens? 
+<li><a accesskey="4" href="#Section-5_002e4">Section 5.4</a>:   What to do if I read only bogus information? 
+<li><a accesskey="5" href="#Section-5_002e5">Section 5.5</a>:   What to do if you have other problems? 
+<li><a accesskey="6" href="#Section-5_002e6">Section 5.6</a>:   What if it just works like a charm? 
+<li><a accesskey="7" href="#Section-5_002e7">Section 5.7</a>:   How do I update a ticket? 
+<li><a accesskey="8" href="#Section-5_002e8">Section 5.8</a>:   How do I follow up on a ticket? 
+<li><a accesskey="9" href="#Section-5_002e9">Section 5.9</a>:   Why did you decide not to support undocumented chips? 
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-5.1"></a>
+<a name="Section-5_002e1"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-5_002e2">Section 5.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Help">Help</a>
+
+</div>
+
+<h3 class="section">5.1 What to send us when asking for help</h3>
+
+<p>We are always willing to answer questions if things don't work out. 
+Post your question to our <a href="http://lists.lm-sensors.org/mailman/listinfo/lm-sensors">discussion list</a>,
+and not the individual authors,
+unless you have something private to say.
+
+   <p>Instead of using email, you can also use the web-based support
+area, at <a href="http://www.lm-sensors.org/wiki/FeedbackAndSupport">http://www.lm-sensors.org/wiki/FeedbackAndSupport</a>. You will be helped
+just as fast, and others may profit from the answer too. You will be
+emailed automatically when your question has been answered.
+
+   <p>Here's what you should send us:
+
+     <ul>
+<li>The dmesg or syslog output if applicable
+<li>The output of (as root) <samp><span class="command">prog/detect/sensors-detect</span></samp>
+<li>The output of <samp><span class="command">lsmod</span></samp>
+<li>If a PCI chip problem:
+          <ul>
+<li>The output of <samp><span class="command">lspci -n</span></samp>
+</ul>
+     <li>If an I2C sensor chip problem:
+          <ul>
+<li>The output of (as root) <samp><span class="command">prog/detect/i2cdetect X</span></samp>
+where X = the bus number (run <samp><span class="command">i2cdetect</span></samp> with no arguments to list the busses)
+(please send this only if it's not all `<samp><span class="samp">XX</span></samp>')
+<li>The output of (as root) <samp><span class="command">prog/dump/i2cdump X 0xXX</span></samp>
+where XX = the address of each chip you see in the output of <samp><span class="command">i2cdetect</span></samp>. (run once for each chip)
+(please send this only if it's not all `<samp><span class="samp">ff</span></samp>')
+</ul>
+     <li>If an ISA sensor chip problem:
+          <ul>
+<li>The output of (as root) <samp><span class="command">prog/dump/isadump 0x295 0x296</span></samp> (only if it's not all `<samp><span class="samp">XX</span></samp>')
+</ul>
+     <li>Part numbers of chips on your motherboard you think are the sensor chips (look at your motherboard)
+<li>Motherboard type
+<li>Sensors version
+<li>Kernel version
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-5.2"></a>
+<a name="Section-5_002e2"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-5_002e3">Section 5.3</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-5_002e1">Section 5.1</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Help">Help</a>
+
+</div>
+
+<h3 class="section">5.2 What to do if a module won't insert?</h3>
+
+<p>Did you use <samp><span class="command">modprobe</span></samp> instead of <samp><span class="command">insmod</span></samp>??? Don't use insmod.
+
+   <p>Were there unresolved symbols? Did you run <samp><span class="command">depmod -a</span></samp>? Run
+<samp><span class="command">depmod -a -e</span></samp> to see where the symbol problem is.
+
+   <p>ALWAYS inspect the output of <samp><span class="command">dmesg</span></samp>. That's where the error
+messages come out!!! Don't rely on the generic message from <samp><span class="command">modprobe</span></samp>. 
+If you still can't figure it out, send us the information
+listed above.
+
+<div class="node">
+<p><hr>
+<a name="Section-5.3"></a>
+<a name="Section-5_002e3"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-5_002e4">Section 5.4</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-5_002e2">Section 5.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Help">Help</a>
+
+</div>
+
+<h3 class="section">5.3 What to do if it inserts, but nothing happens?</h3>
+
+<p>For an ISA sensor chip, did you also <samp><span class="command">modprobe i2c-isa</span></samp>? It must be inserted.
+
+   <p>For an I2C sensor chip, did you also <samp><span class="command">modprobe i2c-xxx</span></samp> where xxx is your
+I2C bus adapter? It must be inserted.
+
+   <p>Always inspect the output of <samp><span class="command">dmesg</span></samp>. That's where the error
+messages come out. If you still can't figure it out, send us the information
+listed above.
+
+<div class="node">
+<p><hr>
+<a name="Section-5.4"></a>
+<a name="Section-5_002e4"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-5_002e5">Section 5.5</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-5_002e3">Section 5.3</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Help">Help</a>
+
+</div>
+
+<h3 class="section">5.4 What to do if I read only bogus information?</h3>
+
+<p>It may be that this was a mis-detection: the chip may not be
+present. If you are convinced there is something wrong, verify that you
+indeed have the devices on your motherboard that you think you do. 
+Look at the motherboard and make sure. If you are still stuck,
+please send us the usual information (see <a href="#Help">Help</a>)
+
+<div class="node">
+<p><hr>
+<a name="Section-5.5"></a>
+<a name="Section-5_002e5"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-5_002e6">Section 5.6</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-5_002e4">Section 5.4</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Help">Help</a>
+
+</div>
+
+<h3 class="section">5.5 What to do if you have other problems?</h3>
+
+<p>Again, send the output listed above.
+
+<div class="node">
+<p><hr>
+<a name="Section-5.6"></a>
+<a name="Section-5_002e6"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-5_002e7">Section 5.7</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-5_002e5">Section 5.5</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Help">Help</a>
+
+</div>
+
+<h3 class="section">5.6 What if it just works like a charm?</h3>
+
+<p>Drop us a mail if you feel like it, mentioning the mainboard and
+detected chip type. That way, we have some positive feedback, too!
+
+<div class="node">
+<p><hr>
+<a name="Section-5.7"></a>
+<a name="Section-5_002e7"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-5_002e8">Section 5.8</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-5_002e6">Section 5.6</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Help">Help</a>
+
+</div>
+
+<h3 class="section">5.7 How do I update a ticket?</h3>
+
+<p>You can't. Only developers can. Follow up by emailing us
+and reference your ticket number
+in the subject. Please don't enter a new ticket with
+follow-up information, email us instead. Thanks.
+
+<div class="node">
+<p><hr>
+<a name="Section-5.8"></a>
+<a name="Section-5_002e8"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-5_002e9">Section 5.9</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-5_002e7">Section 5.7</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Help">Help</a>
+
+</div>
+
+<h3 class="section">5.8 How do I follow up on a ticket?</h3>
+
+<p>Follow up by emailing us
+and reference your ticket number in the subject.
+
+<div class="node">
+<p><hr>
+<a name="Section-5.9"></a>
+<a name="Section-5_002e9"></a>
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-5_002e8">Section 5.8</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Help">Help</a>
+
+</div>
+
+<h3 class="section">5.9 Why did you decide not to support undocumented chips?</h3>
+
+<p>There are several reasons why we are generally not interested in writing
+drivers for undocumented chips:
+
+     <ul>
+<li>Writing a driver without a datasheet is much harder, as you have to
+guess most things. Remember that, most of the time, we write drivers for fun
+and for free, so there is no reason we would write a driver in conditions
+that promise more pain than fun. 
+<li>If we hit a problem, we are certain never to get any support from the
+chip manufacturer. This means that we may spend days on code which will
+finally never work. 
+<li>There are several chips out there which are fully documented and lack
+a driver. This is natural for us to give these the priority when we
+finally have some spare time to spend on driver coding. 
+<li>Hardware monitoring chips are not toys. Misprogramming them can
+result in data loss or hardware breakage. This is obviously more likely
+to happen with undocumented chips. This is a responsability we do not
+want to endorse (the GPL is pretty clear than we are not legally
+liable, but still). 
+</ul>
+
+   <p>There are also several reasons why we do not want to support such drivers,
+even if they were written by other people:
+
+     <ul>
+<li>Problems are much more likely to happen with such drivers. 
+This means increased needs of support. User support if very
+time-consuming and we are usually short of time. 
+<li>Support should be done by the driver author (as only him/her knows
+the driver and chip) but in the reality of facts, people will always ask
+us for help if the driver is part of our package. Redirecting all user
+requests to the driver's author manually is boring. 
+<li>The lack of datasheet usually results in an original driver which
+works relatively fine for its author, but will happen not to work
+completely for other users. This means that the driver will need many
+more additions and fixes than other drivers do, resulting in an increased
+maitainance workload, which we can hardly afford. Of course this too should
+be handled by the original driver author, but we never know whether he/she
+will actually do the work. 
+</ul>
+
+   <p>Lastly, there are other considerations, some of which are deliberately
+political:
+
+     <ul>
+<li>We do not want to trick hardware buyers into thinking that a chip is
+fully supported under Linux when in fact it is only partly supported by a
+driver which was written without a datasheet. Clearly stating that such
+chips are not supported makes it much easier for anyone who really needs
+fully working hardware monitoring under Linux to avoid motherboards with
+these partly supported chips. 
+<li>Drivers written without a datasheet are a pain for developers and
+users, but are a complete win for the manufacturers of these chips:
+they don't have to write the driver, they don't have to help us,
+they don't have to support the users, and they still sell their
+hardware. We do not want to encourage such a selfish behavior. 
+</ul>
+
+   <p>That being said, authors of such drivers can still submit their code to
+the Linux kernel folks for inclusion into Linux 2.6. Their driver may be
+accepted there, under conditions.
+
+   <p>If such a driver is ever accepted into the Linux 2.6 tree, and someone
+provides a patch to libsensors and/or sensors to add support for this
+driver, we will apply it. This generic code is unlikely to cause trouble.
+
+<div class="node">
+<p><hr>
+<a name="Contribute"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Document-Revisions">Document Revisions</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Help">Help</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
+
+</div>
+
+<h2 class="chapter">6 How to Contribute</h2>
+
+<ul class="menu">
+<li><a accesskey="1" href="#Section-6_002e1">Section 6.1</a>:   How to write a driver
+<li><a accesskey="2" href="#Section-6_002e2">Section 6.2</a>:   How to get SVN access
+<li><a accesskey="3" href="#Section-6_002e3">Section 6.3</a>:   How to donate hardware to the project
+<li><a accesskey="4" href="#Section-6_002e4">Section 6.4</a>:   How to join the project mailing list
+<li><a accesskey="5" href="#Section-6_002e5">Section 6.5</a>:   How to access mailing list archives
+<li><a accesskey="6" href="#Section-6_002e6">Section 6.6</a>:   How to submit a patch
+<li><a accesskey="7" href="#Section-6_002e7">Section 6.7</a>:   How to REALLY help
+<li><a accesskey="8" href="#Section-6_002e8">Section 6.8</a>:   How to get release announcements
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-6.1"></a>
+<a name="Section-6_002e1"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-6_002e2">Section 6.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Contribute">Contribute</a>
+
+</div>
+
+<h3 class="section">6.1 How to write a driver</h3>
+
+<p>See <samp><span class="file">doc/developers/new_drivers</span></samp> in our package for instructions.
+
+<div class="node">
+<p><hr>
+<a name="Section-6.2"></a>
+<a name="Section-6_002e2"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-6_002e3">Section 6.3</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-6_002e1">Section 6.1</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Contribute">Contribute</a>
+
+</div>
+
+<h3 class="section">6.2 How to get SVN access</h3>
+
+<p>For anonymous SVN read access, see the instructions on our
+<a href="http://www.lm-sensors.org/wiki/Download">download page</a>.
+
+   <p>For write access, please contact us.
+
+<div class="node">
+<p><hr>
+<a name="Section-6.3"></a>
+<a name="Section-6_002e3"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-6_002e4">Section 6.4</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-6_002e2">Section 6.2</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Contribute">Contribute</a>
+
+</div>
+
+<h3 class="section">6.3 How to donate hardware to the project</h3>
+
+<p><a href="http://www.lm-sensors.org/wiki/FeedbackAndSupport">Contact us</a>.
+
+<div class="node">
+<p><hr>
+<a name="Section-6.4"></a>
+<a name="Section-6_002e4"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-6_002e5">Section 6.5</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-6_002e3">Section 6.3</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Contribute">Contribute</a>
+
+</div>
+
+<h3 class="section">6.4 How to join the project mailing lists</h3>
+
+<p>There are two lists you can subscribe to:
+
+     <ul>
+<li>A <a href="http://lists.lm-sensors.org/mailman/listinfo/lm-sensors">general discussion list</a>,
+meant for both development and user support. You do not need to be subscribed to post. 
+<li>A <a href="http://lists.lm-sensors.org/mailman/listinfo/lm-sensors-commit">CVS commits list</a>,
+for watching the changes made to the CVS repositories. This list is read-only. 
+</ul>
+
+<div class="node">
+<p><hr>
+<a name="Section-6.5"></a>
+<a name="Section-6_002e5"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-6_002e6">Section 6.6</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-6_002e4">Section 6.4</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Contribute">Contribute</a>
+
+</div>
+
+<h3 class="section">6.5 How to access mailing list archives</h3>
+
+<p>The primary mailing list archive is at:
+<a href="http://lists.lm-sensors.org/pipermail/lm-sensors/">http://lists.lm-sensors.org/pipermail/lm-sensors/</a>. 
+It contains messages since October 28, 2001.
+
+   <p>There is another mailing list archive at:
+<a href="http://news.gmane.org/gmane.linux.drivers.sensors">http://news.gmane.org/gmane.linux.drivers.sensors</a>. 
+It contains messages since December 31, 2004. 
+This archive may also be accessed via a news reader:
+<a href="nntp://news.gmane.org/gmane.linux.drivers.sensors">nntp://news.gmane.org/gmane.linux.drivers.sensors</a>
+and RSS:
+<a href="http://rss.gmane.org/gmane.linux.drivers.sensors">http://rss.gmane.org/gmane.linux.drivers.sensors</a>.
+
+   <p>And last there is a legacy archive at:
+<a href="http://archives.andrew.net.au/lm-sensors">http://archives.andrew.net.au/lm-sensors</a>. 
+It contains messages from October 28, 2001 through May 16, 2005.
+
+<div class="node">
+<p><hr>
+<a name="Section-6.6"></a>
+<a name="Section-6_002e6"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-6_002e7">Section 6.7</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-6_002e5">Section 6.5</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Contribute">Contribute</a>
+
+</div>
+
+<h3 class="section">6.6 How to submit a patch</h3>
+
+<p>Check out the latest from CVS, then copy the directory to another
+directory, and make your changes. Generate the diff with
+<samp><span class="command">diff -u2 -r DIR1 DIR2</span></samp>. Or you can generate the diff in CVS with
+<samp><span class="command">cvs diff -u2</span></samp>. Send us the patch in an email and tell us what it does.
+
+<div class="node">
+<p><hr>
+<a name="Section-6.7"></a>
+<a name="Section-6_002e7"></a>
+Next:&nbsp;<a rel="next" accesskey="n" href="#Section-6_002e8">Section 6.8</a>,
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-6_002e6">Section 6.6</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Contribute">Contribute</a>
+
+</div>
+
+<h3 class="section">6.7 How to REALLY help</h3>
+
+<p>Believe it or not, what we really need help with are:
+     <ul>
+<li>Answering email
+<li>Answering support tickets
+<li>Porting drivers to Linux 2.6
+<li>Creating a sensors.conf database
+<li>Reviewing patches
+</ul>
+
+   <p>If you are willing to help, simply join our
+<a href="http://lists.lm-sensors.org/mailman/listinfo/lm-sensors">discussion list</a>,
+and we'll help you help us.
+
+<div class="node">
+<p><hr>
+<a name="Section-6.8"></a>
+<a name="Section-6_002e8"></a>
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Section-6_002e7">Section 6.7</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Contribute">Contribute</a>
+
+</div>
+
+<h3 class="section">6.8 How to get release announcements</h3>
+
+<p>We don't have a separate release announcement mailing list;
+however, we put all our releases on freshmeat: <a href="http://freshmeat.net">http://freshmeat.net</a>
+and you can register on our freshmeat project page  <a href="http://freshmeat.net/projects/lm_sensors">http://freshmeat.net/projects/lm_sensors</a>
+to 'subscribe to new releases' and then freshmeat
+will email you announcement.
+
+<div class="node">
+<p><hr>
+<a name="Document-Revisions"></a>
+Previous:&nbsp;<a rel="previous" accesskey="p" href="#Contribute">Contribute</a>,
+Up:&nbsp;<a rel="up" accesskey="u" href="#Top">Top</a>
+
+</div>
+
+<h2 class="appendix">Appendix A Revision History of This Document</h2>
+
+     <ul>
+<li>Rev 2.18 (JD) Removed version 1 specifics part, 2005-12-17
+<li>Rev 2.17 (JD) Added 5.9 (why we don't support undocumented chips),
+	removed 6.9 (doesn't apply to the new mailing list), 2005-10-05
+<li>Rev 2.16 (JD) Added 4.33.2, 2005-09-06
+<li>Rev 2.15 (JD) Updates, including mailing-list change, 2005-05-21
+<li>Rev 2.14 (MDS) Updated 4.12, 2004-11-26
+<li>Rev 2.13 (JD) Added 4.6.1, updated 4.7, 2004-06-23
+<li>Rev 2.12 (JD) Updated 4.27, 2004-04-11
+<li>Rev 2.11 (JD) Various updates, 2004-01-18
+<li>Rev 2.10 (MDS) Various updates, 2004-01-03
+<li>Rev 2.9 (CP) Converted to Gnu texinfo format, 2002-09-10
+<li>Rev 2.8 (MDS) Minor updates 2002-07-10, released with lm_sensors 2.6.4
+<li>Rev 2.7 (MDS) Minor updates 2002-04-25
+<li>Rev 2.6 (MDS) Minor updates 2002-01-15, released with lm_sensors 2.6.3
+<li>Rev 2.5 (MDS) Minor updates 2001-11-11, released with lm_sensors 2.6.2
+<li>Rev 2.4 (MDS) Minor updates 2001-07-22
+<li>Rev 2.3 (MDS) General update, 2001-02-24, released with lm_sensors 2.6.0. 
+<li>Rev 2.2 (Frodo) Corrections for lm_sensors 2.4, 1999-09-20
+<li>Rev 2.1 (Frodo) Corrections for lm_sensors 2.2, 1999-01-12
+<li>Rev 2.0 (Frodo) Major revision for lm_sensors 2.1, 1998-12-29
+<li>Rev 1.10 (Frodo) Modified 3.8, updated some other things, 1998-09-24
+<li>Rev 1.9 (Frodo) Added 3.15, 1998-09-06
+<li>Rev 1.8 (Frodo) Added 3.14, 1998-09-05
+<li>Rev 1.7 (Phil) Added 3.13 and some other minor changes, 1998-09-01
+<li>Rev 1.6 (Frodo) Added 4, 4.1, 4.2, 4.3, 4.4, 4.5, 1998-09-01
+<li>Rev 1.5 (Frodo) Added 2.3, 2.4, 3.9, 3.10, 3.11, 1998-08-26
+<li>Rev 1.4 (Frodo) Added some more Winbond information, and 3.5-3.8, 1998-08-17
+<li>Rev 1.3 (Phil) Added info on the Winbond chip, 1998-08-16
+<li>Rev 1.2 (Frodo) Adapation, 1998-08-10
+<li>Rev 1.1 (Phil) Modifications, 1998-08-09
+<li>Rev 1.0 (Phil) First version, 1998-08-03
+</ul>
+
+</body></html>
+
Index: /lm-sensors/tags/V3-0-0-RC2/doc/Makefile
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/Makefile	(revision 2199)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/Makefile	(revision 2199)
@@ -0,0 +1,19 @@
+#
+# quick makefile for the FAQ.
+# So that both the text and html FAQ are accessible on the web
+# (the website points into CVS for the FAQ),
+# they are checked into CVS along with the .texi source.
+# Don't forget to update version.texi.
+# Run 'make' and then check in all 4 files after editing the .texi source.
+# Or do 'make ci'
+#
+all::  lm_sensors-FAQ.html FAQ
+
+%.html: %.texi version.texi
+	makeinfo --html --no-split --number-sections $<
+
+FAQ: lm_sensors-FAQ.texi
+	makeinfo --no-headers --number-sections -o FAQ $<
+
+ci: all
+	cvs ci lm_sensors-FAQ.texi lm_sensors-FAQ.html FAQ version.texi
Index: /lm-sensors/tags/V3-0-0-RC2/doc/version.texi
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/version.texi	(revision 4865)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/version.texi	(revision 4865)
@@ -0,0 +1,2 @@
+@set UPDATED 24 September 2007
+@set VERSION 2.19
Index: /lm-sensors/tags/V3-0-0-RC2/doc/donations
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/doc/donations	(revision 4577)
+++ /lm-sensors/tags/V3-0-0-RC2/doc/donations	(revision 4577)
@@ -0,0 +1,109 @@
+The lm_sensors team gratefully acknowledges the following donations.
+
+Drivers are very difficult to develop without actual hardware.
+Generally, the work goes quickly once we have the hardware.
+
+Evaluation boards are fine. Real computer hardware is much better though,
+because it lets us do real-world testing over a longer period of time.
+In many cases, the way a chipset is integrated in systems must be taken
+into account in the driver, and evaluation boards don't help much there.
+Donation of usable computer hardware also supports the project in general,
+so hardware which isn't directly related to the development of a hardware
+monitoring driver, but can be used to build test systems, is welcome too.
+
+If you would like to make a donation, please contact us. See
+http://www.lm-sensors.org/wiki/AuthorsAndContributors. Thanks!
+
+
+Donations are listed in chronological order. Note that the person mentioned
+is the one who holds the device now, which is not necessarily the one to whom
+the donation was sent in the first place.
+
+
+Donation from	Donation and subsequent development work	Date & Person
+-------------	----------------------------------------	-------------
+
+TI		i810 motherboard w/ 366 Celeron			1999-07
+		Drivers developed: i801, i810, w83627hf		??
+
+AMD		various sensor evaluation boards		2000
+		Drivers developed: various			??
+
+SiS		SiS 540/630 motherboard w/ 5595			2000-01
+		Drivers developed: sis5595 improvements		Phil
+
+Cendio Systems 	Asus P3B-F w/ AS99127F				2000-05
+		Drivers developed: as99127f improvements	MDS
+
+Atipa		SuperMicro 370DLE w/ Serverworks, LM87		2000-09
+		Drivers developed: serverworks support added	Jean Delvare
+		to i2c-piix4; lm87 testing and improvements
+		(on-board NIC broken)
+
+Fujitsu		Complete system for general project support	2001-11
+Siemens		(broken)					Phil
+Computers
+
+HardData Ltd.	Tyan 2466 w/ 1G Duron; W83627HF and W83782D	2002-05
+		Drivers developed: Tyan 2466 initialization;	MDS
+		DDR recognition
+
+Intel		SMBus 2.0 system				2002-06
+		Drivers developed: SMBus 2.0 support in		MDS
+		i2c-core and i2c-i801; ADM1025 improvements;
+		82801 improvements; smsc47m1 driver
+
+VIA		8231 and two 8233 motherboards			2002-06
+		Drivers developed: VT8231 support in via686a;	MDS
+		vt1211; VT8233A and VT8231 support in
+		i2c-viapro
+
+HP		IPMI system					2002-10
+		Drivers developed: bmcsensors, i2c-ipmi		MDS
+
+Analog Devices	ADM1032 evaluation board			2003-10
+		Drivers developed: ADM1032 support in lm90;	Jean Delvare
+		lm90 ported to Linux 2.6
+
+National	LM83 evaluation board				2003-12
+Semiconductor	Drivers developed: lm83 testing and		Jean Delvare
+		improvements; lm83 ported to Linux 2.6
+
+Analog Devices	ADM1025 evaluation board			2004-01
+		Drivers developed: adm1025 testing and		Jean Delvare
+		improvements; adm1025 ported to Linux 2.6
+
+Analog Devices	ADT7467/8 evaluation board			2004-01
+		Drivers developed: nothing yet			Jean Delvare
+
+Analog Devices	ADM1031 evaluation board			2004-04
+		Drivers developed: adm1031 for Linux 2.4 and	Jean Delvare
+		2.6
+
+Wincor Nixdorf	Seagate Barracuda 7200.7 160GB harddisk drive	2004-10
+								Jean Delvare
+
+Aweta		Intel Server system				2005-09
+		Drivers developed: PC87431 (IPMI SMB)		MDS
+
+Barracuda	Jetway K8M8MS, Sempron 2600+, 256 MB RAM	2005-10
+Networks	Drivers developed: f71805f			Jean Delvare
+
+Winbond		Celeron CPU, 512MB RAM				2006-03
+		W83792D watchdog and VID support		Rudolf Marek
+
+ASUSTeK		ASUS P5MT-S					2006-03
+		Platform for W83792D related development	Rudolf Marek
+
+Winbond		Asus P4P800-X, Pentium 4 2.8 GHz, 512 MB RAM	2006-08
+		This board has an (hidden) Intel 82801EB	Jean Delvare
+		(ICH5) SMBus with SPD EEPROMs connected, and
+		a Winbond W83627THF hardware monitoring chip.
+
+Observit	Intel D865GSA, Celeron D-352, 128 MB RAM	2007-06
+		Resulted in: backport of the w83627ehf driver	Jean Delvare
+		to Linux 2.4, improvements to the Linux 2.6
+		w83627ehf driver.
+
+Observit	Intel D865GBF, Celeron 2.4 GHz, 512 MB RAM	2007-06
+		Resulted in: improvements to the lm85 driver.	Jean Delvare
Index: /lm-sensors/tags/V3-0-0-RC2/INSTALL
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/INSTALL	(revision 4876)
+++ /lm-sensors/tags/V3-0-0-RC2/INSTALL	(revision 4876)
@@ -0,0 +1,85 @@
+INSTALLATION INSTRUCTIONS
+=========================
+
+The lm-sensors package, version 3, provides user-space support for the
+hardware monitoring drivers in Linux 2.6.5 and later. For older kernel
+versions, you have to use lm-sensors version 2.
+
+
+Dependencies
+============
+
+Build-time dependencies:
+* GNU make
+* gcc
+* bison
+* flex
+* libsysfs header files (from sysfsutils-devel)
+* rrd header files (optional, for sensord)
+
+Run-time dependencies:
+* libsysfs (from sysfsutils)
+* perl (for sensors-detect)
+* rrd (optional, for sensord)
+* proper kernel configuration (see below)
+
+
+Compilation
+===========
+
+At the top of the Makefile are a couple of configuration variables that
+you may want to change. There's a description of what each variable does
+in the Makefile itself.
+
+Compilation is done by `make all'. You will get a lot of warnings about
+files which are not found, all ending in `.*d'. You can safely ignore
+this; they contain dependency information, which is regenerated on the
+spot.
+
+`make install' installs the package (to /usr/local by default).
+
+
+Kernel configuration
+====================
+
+This package assumes that you have a properly configured kernel. If
+you run a distribution kernel, that should be the case. If you're
+building your own kernel, here are some recommendations:
+* Enable "I2C support" (CONFIG_I2C=y or m). On many motherboards, the
+  sensor chip is connected to the SMBus, which is supported by I2C
+  in the Linux kernel.
+* Enable "I2C device interface" (CONFIG_I2C_CHARDEV=m). sensors-detect
+  needs this to probe for SMBus hardware monitoring chips.
+* In I2C Hardware Bus support, enable all drivers you might need,
+  preferably as modules. If you're not sure, select them all.
+* Enable "Hardware Monitoring support" (CONFIG_HWMON=y or m).
+* Enable all hardware monitoring drivers you might need, preferably
+  as modules. If you're not sure, select them all.
+
+
+Using the sensors package
+=========================
+
+There is a scanning program installed called sensors-detect. It
+will scan all available I2C and SMBus adapters for all known sensor
+devices, and will also look for ISA, PCI and Super-I/O chips with
+sensors, and give you a list of what kernel drivers you need to load
+(using modprobe).
+
+After loading the suggested drivers, you can use the installed sensors
+program to get a report of all detected sensor devices. Chek the manual
+page for available options.
+
+The initial output of `sensors' will not be perfect. You have to adjust
+the configuration file (/etc/sensors.conf) to match your motherboard.
+This includes (re)labelling inputs, ignoring unused inputs, changing
+voltage compute lines and setting limits. Write down all the sensor
+information your BIOS displays as a hint to what you are supposed to
+obtain in the end. Make sure you modify the right chip section.
+
+Once you are done with editing the configuration file, calling
+`sensors -s' will set the new limits. Then the output of `sensors'
+should look much better.
+
+There are many auxiliary programs not installed. You can find them under
+the prog subdirectory. A list can be found in doc/progs.
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/test-scanner.pl
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/test-scanner.pl	(revision 4275)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/test-scanner.pl	(revision 4275)
@@ -0,0 +1,100 @@
+#!/usr/bin/perl -w
+
+# test-scanner.pl - test script for the libsensors config-file scanner
+# Copyright (C) 2006 Mark M. Hoffman <mhoffman@lightlink.com>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; version 2 of the License.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+require 5.004;
+
+use strict;
+use Test::More;
+use Test::Cmd;
+
+my ($scenario, $test);
+my @scenarios = (
+	{ base => 'empty', status => 0,
+		desc => 'empty file' },
+	{ base => 'comment', status => 0,
+		desc => 'one comment line' },
+	{ base => 'comment-without-eol', status => 0,
+		desc => 'one comment line, without a trailing newline' },
+	{ base => 'keywords', status => 0,
+		desc => 'keywords with various whitespace variations' },
+	{ base => 'non-keywords', status => 0,
+		desc => 'various invalid keyword scenarios' },
+	{ base => 'names', status => 0,
+		desc => 'normal, unquoted names' },
+	{ base => 'names-errors', status => 0,
+		desc => 'invalid, unquoted names' },
+	{ base => 'names-quoted', status => 0,
+		desc => 'normal, quoted names' },
+	{ base => 'names-quoted-errors', status => 0,
+		desc => 'invalid, quoted names' },
+);
+
+plan tests => ($#scenarios + 1) * 3;
+
+chomp(my $valgrind = `which valgrind 2>/dev/null`);
+
+if ($valgrind) {
+	$test = Test::Cmd->new(prog => "$valgrind --tool=memcheck --show-reachable=yes --leak-check=full --quiet ./test-scanner", workdir => '');
+} else {
+	diag("Couldn't find valgrind(1), running tests without it...");
+	$test = Test::Cmd->new(prog => "test-scanner", workdir => '');
+}
+
+foreach $scenario (@scenarios) {
+	my ($filename, @stdin, @stdout, @expout, @stderr, @experr, @diff);
+
+	$filename = $scenario->{"base"} . ".conf";
+	open INPUT, "< $filename" or die "Cannot open $filename: $!";
+	@stdin = <INPUT>;
+	close INPUT or die "Cannot close $filename: $!";
+
+	$filename = $scenario->{"base"} . ".conf.stdout";
+	open OUTPUT, "< $filename" or die "Cannot open $filename: $!";
+	@expout = <OUTPUT>;
+	close OUTPUT or die "Cannot close $filename: $!";
+
+	# if stderr file is not present, assume none is expected
+	$filename = $scenario->{"base"} . ".conf.stderr";
+	if (open ERROR, "< $filename") {
+		@experr = <ERROR>;
+		close ERROR or die "Cannot close $filename: $!";
+	} else {
+		@experr = ();
+	}
+
+	$test->string($scenario->{"desc"});
+	$test->run(stdin => \@stdin);
+
+	# test return status
+	ok($scenario->{"status"} == $?, "status: " . $scenario->{"desc"});
+
+	# force the captured outputs into an array - for some reason, the
+	# 'standard invocation' of diff_exact() chokes without this
+	@stdout = $test->stdout;
+	@stderr = $test->stderr;
+
+	# test stdout
+	ok($test->diff_exact(\@stdout, \@expout, \@diff),
+		"stdout: " . $scenario->{"desc"}) or print @diff;
+
+	# test stderr
+	ok($test->diff_exact(\@stderr, \@experr, \@diff),
+		"stderr: " . $scenario->{"desc"}) or print @diff;
+}
+
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted-errors.conf.stdout
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted-errors.conf.stdout	(revision 4234)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted-errors.conf.stdout	(revision 4234)
@@ -0,0 +1,19 @@
+1: CHIP
+1: NAME: blah-*
+2: EOL
+4: LABEL
+4: ERROR
+5: EOL
+7: LABEL
+7: NAME: in1
+7: ERROR
+8: EOL
+10: LABEL
+10: NAME: in2
+10: NAME: baz
+11: EOL
+13: LABEL
+13: NAME: in3
+13: ERROR
+13: EOL
+13: EOF
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/names-errors.conf.stdout
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/names-errors.conf.stdout	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/names-errors.conf.stdout	(revision 4222)
@@ -0,0 +1,15 @@
+2: LABEL
+2: ERROR
+3: EOL
+3: LABEL
+3: NAME: bar
+3: ERROR
+4: EOL
+4: LABEL
+4: NAME: baz
+4: ERROR
+5: EOL
+5: LABEL
+5: ERROR
+6: EOL
+6: EOF
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/non-keywords.conf
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/non-keywords.conf	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/non-keywords.conf	(revision 4222)
@@ -0,0 +1,8 @@
+# these are not keywords
+ignored
+
+labs
+
+extra
+stuff
+
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/comment-without-eol.conf.stdout
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/comment-without-eol.conf.stdout	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/comment-without-eol.conf.stdout	(revision 4222)
@@ -0,0 +1,1 @@
+1: EOF
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/comment.conf
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/comment.conf	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/comment.conf	(revision 4222)
@@ -0,0 +1,1 @@
+# this is a comment
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted.conf
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted.conf	(revision 4233)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted.conf	(revision 4233)
@@ -0,0 +1,28 @@
+chip "blah-*"
+
+# keyword with some quoted names
+label "foo" "bar"
+
+# keyword with escaped newline, names, and whitespace
+label		\
+ "foo" "bar"
+
+# quoted names with full range of alpha-numeric and underscores
+label "abcdefg" "hijklmnop"
+label "qrs" "tuv"
+label "wx" "yz"
+label "a0123456789" "982lksdf"
+label "_abcd" "1234_"
+label "_" "foo_bar_baz" 
+label "liajesiajef82197fjadf" "blah"
+
+# quoted names with escaped characters, like C
+# bell, backspace, formfeed, newline, carriage return, h-tab, v-tab, \, ?, ', "
+label escapes "\a\b\f\n\r\t\v\\\?\'\""
+
+# quoted names with escaped chars that have no special significance
+# i.e. the second string below should collapse to "hello"
+label more "\h\e\l\l\o"
+
+# keyword with quoted names, immediate EOF
+label "blue" "green"
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/test-scanner.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/test-scanner.c	(revision 4274)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/test-scanner.c	(revision 4274)
@@ -0,0 +1,105 @@
+/*
+    test-scanner.c - Regression test driver for the libsensors config file scanner.
+    Copyright (C) 2006 Mark M. Hoffman <mhoffman@lightlink.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../data.h"
+#include "../conf.h"
+#include "../conf-parse.h"
+#include "../scanner.h"
+
+YYSTYPE sensors_yylval;
+
+int main(void)
+{
+	int result;
+
+	/* init the scanner */
+	if ((result = sensors_scanner_init(stdin)))
+		return result;
+
+	do {
+		result = sensors_yylex();
+
+		printf("%d: ", sensors_yylineno);
+
+		switch (result) {
+
+			case 0:
+				printf("EOF\n");
+				break;
+
+			case NEG:
+				printf("NEG\n");
+				break;
+	
+			case EOL:
+				printf("EOL\n");
+				break;
+	
+			case BUS:
+				printf("BUS\n");
+				break;
+	
+			case LABEL:
+				printf("LABEL\n");
+				break;
+	
+			case SET:
+				printf("SET\n");
+				break;
+	
+			case CHIP:
+				printf("CHIP\n");
+				break;
+	
+			case COMPUTE:
+				printf("COMPUTE\n");
+				break;
+	
+			case IGNORE:
+				printf("IGNORE\n");
+				break;
+	
+			case FLOAT:
+				printf("FLOAT: %f\n", sensors_yylval.value);
+				break;
+	
+			case NAME:
+				printf("NAME: %s\n", sensors_yylval.name);
+				free(sensors_yylval.name);
+				break;
+	
+			case ERROR:
+				printf("ERROR\n");
+				break;
+
+			default:
+				printf("%c\n", (char)result);
+				break;
+		}
+
+	} while (result);
+
+	/* clean up the scanner */
+	sensors_scanner_exit();
+
+	return 0;
+}
+
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/names.conf
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/names.conf	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/names.conf	(revision 4222)
@@ -0,0 +1,25 @@
+# keyword with some unquoted names
+label foo bar
+
+# keyword with escaped newline, names, and whitespace
+label		\
+ foo bar
+
+# names with full range of alpha-numeric and underscores
+label \
+	abcdefg \
+	hijklmnop \
+	qrs \
+	tuv \
+	wx \
+	yz \
+	a0123456789 \
+	982lksdf \
+	_abcd \
+	1234_ \
+	_ \
+	foo_bar_baz \
+	liajesiajef82197fjadf
+
+# keyword with names, immediate EOF
+label foo bar
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/Module.mk
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/Module.mk	(revision 4655)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/Module.mk	(revision 4655)
@@ -0,0 +1,24 @@
+LIB_DIR		:= lib
+LIB_TEST_DIR	:= lib/test
+
+LIB_TEST_TARGETS := $(LIB_TEST_DIR)/test-scanner
+LIB_TEST_SOURCES := $(LIB_TEST_DIR)/test-scanner.c
+
+LIB_TEST_SCANNER_OBJS := \
+	$(LIB_TEST_DIR)/test-scanner.ro \
+	$(LIB_DIR)/conf-lex.ao \
+	$(LIB_DIR)/error.ao \
+	$(LIB_DIR)/general.ao
+
+$(LIB_TEST_DIR)/test-scanner: $(LIB_TEST_SCANNER_OBJS)
+	$(CC) $(EXLDFLAGS) -o $@ $(LIB_TEST_SCANNER_OBJS) -Llib
+
+all-lib-test: $(LIB_TEST_TARGETS)
+user :: all-lib-test
+
+$(LIB_TEST_DIR)/test-scanner.ro: $(LIB_DIR)/data.h $(LIB_DIR)/conf.h $(LIB_DIR)/conf-parse.h $(LIB_DIR)/scanner.h
+
+clean-lib-test:
+	$(RM) $(LIB_TEST_DIR)/*.rd $(LIB_TEST_DIR)/*.ro 
+	$(RM) $(LIB_TEST_TARGETS)
+clean :: clean-lib-test
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/keywords.conf
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/keywords.conf	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/keywords.conf	(revision 4222)
@@ -0,0 +1,42 @@
+# chip keyword on a line by itself
+chip
+
+# preceded by whitespace
+	 chip
+
+# with trailing whitespace
+chip	 
+
+# ditto for the rest of the keywords
+label
+
+	  label
+
+label	 	
+
+set
+
+ set
+
+set 
+
+compute
+
+	compute
+
+compute	
+
+bus
+
+	  	bus
+
+bus	  	
+
+ignore
+
+	ignore
+
+ignore	
+
+# keyword followed by EOL/EOF
+chip
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted-errors.conf
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted-errors.conf	(revision 4234)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted-errors.conf	(revision 4234)
@@ -0,0 +1,13 @@
+chip "blah-*"
+
+# keyword with two quoted names, no intermediate whitespace
+label "in0""foo"
+
+# missing closing quote before EOL
+label "in1" "bar
+
+# (correct label statement, just for separation)
+label "in2" "baz"
+
+# missing closing quote before immediate EOF
+label "in3" "baz
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/names-errors.conf
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/names-errors.conf	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/names-errors.conf	(revision 4222)
@@ -0,0 +1,5 @@
+# keyword with bogus names
+label ?foo
+label bar%
+label baz$foo
+label !
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/empty.conf.stdout
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/empty.conf.stdout	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/empty.conf.stdout	(revision 4222)
@@ -0,0 +1,1 @@
+1: EOF
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/comment-without-eol.conf
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/comment-without-eol.conf	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/comment-without-eol.conf	(revision 4222)
@@ -0,0 +1,1 @@
+# this is a comment without a trailing newline 
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/non-keywords.conf.stdout
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/non-keywords.conf.stdout	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/non-keywords.conf.stdout	(revision 4222)
@@ -0,0 +1,9 @@
+2: ERROR
+3: EOL
+4: ERROR
+5: EOL
+6: ERROR
+7: EOL
+7: ERROR
+8: EOL
+9: EOF
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted.conf.stdout
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted.conf.stdout	(revision 4233)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/names-quoted.conf.stdout	(revision 4233)
@@ -0,0 +1,54 @@
+1: CHIP
+1: NAME: blah-*
+2: EOL
+4: LABEL
+4: NAME: foo
+4: NAME: bar
+5: EOL
+7: LABEL
+8: NAME: foo
+8: NAME: bar
+9: EOL
+11: LABEL
+11: NAME: abcdefg
+11: NAME: hijklmnop
+12: EOL
+12: LABEL
+12: NAME: qrs
+12: NAME: tuv
+13: EOL
+13: LABEL
+13: NAME: wx
+13: NAME: yz
+14: EOL
+14: LABEL
+14: NAME: a0123456789
+14: NAME: 982lksdf
+15: EOL
+15: LABEL
+15: NAME: _abcd
+15: NAME: 1234_
+16: EOL
+16: LABEL
+16: NAME: _
+16: NAME: foo_bar_baz
+17: EOL
+17: LABEL
+17: NAME: liajesiajef82197fjadf
+17: NAME: blah
+18: EOL
+21: LABEL
+21: NAME: escapes
+21: NAME: 
+
+	\?'"
+22: EOL
+25: LABEL
+25: NAME: more
+25: NAME: hello
+26: EOL
+28: LABEL
+28: NAME: blue
+28: NAME: green
+28: EOL
+28: EOF
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/comment.conf.stdout
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/comment.conf.stdout	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/comment.conf.stdout	(revision 4222)
@@ -0,0 +1,1 @@
+2: EOF
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/names.conf.stdout
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/names.conf.stdout	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/names.conf.stdout	(revision 4222)
@@ -0,0 +1,28 @@
+2: LABEL
+2: NAME: foo
+2: NAME: bar
+3: EOL
+5: LABEL
+6: NAME: foo
+6: NAME: bar
+7: EOL
+9: LABEL
+10: NAME: abcdefg
+11: NAME: hijklmnop
+12: NAME: qrs
+13: NAME: tuv
+14: NAME: wx
+15: NAME: yz
+16: NAME: a0123456789
+17: NAME: 982lksdf
+18: NAME: _abcd
+19: NAME: 1234_
+20: NAME: _
+21: NAME: foo_bar_baz
+22: NAME: liajesiajef82197fjadf
+23: EOL
+25: LABEL
+25: NAME: foo
+25: NAME: bar
+25: EOL
+25: EOF
Index: /lm-sensors/tags/V3-0-0-RC2/lib/test/keywords.conf.stdout
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/test/keywords.conf.stdout	(revision 4222)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/test/keywords.conf.stdout	(revision 4222)
@@ -0,0 +1,39 @@
+2: CHIP
+3: EOL
+5: CHIP
+6: EOL
+8: CHIP
+9: EOL
+11: LABEL
+12: EOL
+13: LABEL
+14: EOL
+15: LABEL
+16: EOL
+17: SET
+18: EOL
+19: SET
+20: EOL
+21: SET
+22: EOL
+23: COMPUTE
+24: EOL
+25: COMPUTE
+26: EOL
+27: COMPUTE
+28: EOL
+29: BUS
+30: EOL
+31: BUS
+32: EOL
+33: BUS
+34: EOL
+35: IGNORE
+36: EOL
+37: IGNORE
+38: EOL
+39: IGNORE
+40: EOL
+42: CHIP
+43: EOL
+43: EOF
Index: /lm-sensors/tags/V3-0-0-RC2/lib/error.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/error.h	(revision 4899)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/error.h	(revision 4899)
@@ -0,0 +1,61 @@
+/*
+    error.h - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LIB_SENSORS_ERROR_H
+#define LIB_SENSORS_ERROR_H
+
+#define SENSORS_ERR_WILDCARDS	1 /* Wildcard found in chip name */
+#define SENSORS_ERR_NO_ENTRY	2 /* No such subfeature known */
+#define SENSORS_ERR_ACCESS_R	3 /* Can't read */
+#define SENSORS_ERR_KERNEL	4 /* Kernel interface error */
+#define SENSORS_ERR_DIV_ZERO	5 /* Divide by zero */
+#define SENSORS_ERR_CHIP_NAME	6 /* Can't parse chip name */
+#define SENSORS_ERR_BUS_NAME	7 /* Can't parse bus name */
+#define SENSORS_ERR_PARSE	8 /* General parse error */
+#define SENSORS_ERR_ACCESS_W	9 /* Can't write */
+#define SENSORS_ERR_IO		10 /* I/O error */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* This function returns a pointer to a string which describes the error.
+   errnum may be negative (the corresponding positive error is returned).
+   You may not modify the result! */
+const char *sensors_strerror(int errnum);
+
+/* This function is called when a parse error is detected. Give it a new
+   value, and your own function is called instead of the default (which
+   prints to stderr). This function may terminate the program, but it
+   usually outputs an error and returns. */
+extern void (*sensors_parse_error) (const char *err, int lineno);
+
+/* This function is called when an immediately fatal error (like no
+   memory left) is detected. Give it a new value, and your own function
+   is called instead of the default (which prints to stderr and ends
+   the program). Never let it return! */
+extern void (*sensors_fatal_error) (const char *proc, const char *err);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* def LIB_SENSORS_ERROR_H */
Index: /lm-sensors/tags/V3-0-0-RC2/lib/scanner.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/scanner.h	(revision 4736)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/scanner.h	(revision 4736)
@@ -0,0 +1,27 @@
+/*
+    scanner.h - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 2006 Mark M. Hoffman <mhoffman@lightlink.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LIB_SENSORS_SCANNER_H
+#define LIB_SENSORS_SCANNER_H
+
+int sensors_scanner_init(FILE *input);
+void sensors_scanner_exit(void);
+
+#endif
+
Index: /lm-sensors/tags/V3-0-0-RC2/lib/sensors.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/sensors.h	(revision 4871)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/sensors.h	(revision 4871)
@@ -0,0 +1,231 @@
+/*
+    sensors.h - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LIB_SENSORS_SENSORS_H
+#define LIB_SENSORS_SENSORS_H
+
+#include <stdio.h>
+#include <limits.h>
+
+/* Publicly accessible library functions */
+
+#define SENSORS_CHIP_NAME_PREFIX_ANY NULL
+#define SENSORS_CHIP_NAME_ADDR_ANY -1
+
+#define SENSORS_BUS_TYPE_ANY	(-1)
+#define SENSORS_BUS_TYPE_I2C	0
+#define SENSORS_BUS_TYPE_ISA	1
+#define SENSORS_BUS_TYPE_PCI	2
+#define SENSORS_BUS_TYPE_SPI	3
+#define SENSORS_BUS_NR_ANY	(-1)
+#define SENSORS_BUS_NR_IGNORE	(-2)
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern const char *libsensors_version;
+
+typedef struct sensors_bus_id {
+	short type;
+	short nr;
+} sensors_bus_id;
+
+/* A chip name is encoded in this structure */
+typedef struct sensors_chip_name {
+	char *prefix;
+	sensors_bus_id bus;
+	int addr;
+	char *path;
+} sensors_chip_name;
+
+/* Load the configuration file and the detected chips list. If this
+   returns a value unequal to zero, you are in trouble; you can not
+   assume anything will be initialized properly. If you want to
+   reload the configuration file, call sensors_cleanup() below before
+   calling sensors_init() again. */
+int sensors_init(FILE *input);
+
+/* Clean-up function: You can't access anything after
+   this, until the next sensors_init() call! */
+void sensors_cleanup(void);
+
+/* Parse a chip name to the internal representation. Return 0 on success, <0
+   on error. */
+int sensors_parse_chip_name(const char *orig_name, sensors_chip_name *res);
+
+/* Print a chip name from its internal representation. Note that chip should
+   not contain wildcard values! Return the number of characters printed on
+   success (same as snprintf), <0 on error. */
+int sensors_snprintf_chip_name(char *str, size_t size,
+			       const sensors_chip_name *chip);
+
+/* This function returns the adapter name of a bus,
+   as used within the sensors_chip_name structure. If it could not be found,
+   it returns NULL */
+const char *sensors_get_adapter_name(const sensors_bus_id *bus);
+
+typedef struct sensors_feature sensors_feature;
+
+/* Look up the label for a given feature. Note that chip should not
+   contain wildcard values! The returned string is newly allocated (free it
+   yourself). On failure, NULL is returned.
+   If no label exists for this feature, its name is returned itself. */
+char *sensors_get_label(const sensors_chip_name *name,
+			const sensors_feature *feature);
+
+/* Read the value of a subfeature of a certain chip. Note that chip should not
+   contain wildcard values! This function will return 0 on success, and <0
+   on failure.  */
+int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
+		      double *value);
+
+/* Set the value of a subfeature of a certain chip. Note that chip should not
+   contain wildcard values! This function will return 0 on success, and <0
+   on failure. */
+int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
+		      double value);
+
+/* Execute all set statements for this particular chip. The chip may contain
+   wildcards!  This function will return 0 on success, and <0 on failure. */
+int sensors_do_chip_sets(const sensors_chip_name *name);
+
+/* This function returns all detected chips that match a given chip name,
+   one by one. If no chip name is provided, all detected chips are returned.
+   To start at the beginning of the list, use 0 for nr; NULL is returned if
+   we are at the end of the list. Do not try to change these chip names, as
+   they point to internal structures! */
+const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
+						    *match, int *nr);
+
+/* These defines are used in the flags field of sensors_subfeature */
+#define SENSORS_MODE_R			1
+#define SENSORS_MODE_W			2
+#define SENSORS_COMPUTE_MAPPING		4
+
+typedef enum sensors_feature_type {
+	SENSORS_FEATURE_IN		= 0x00,
+	SENSORS_FEATURE_FAN		= 0x01,
+	SENSORS_FEATURE_TEMP		= 0x02,
+	SENSORS_FEATURE_VID		= 0x10,
+	SENSORS_FEATURE_BEEP_ENABLE	= 0x18,
+	SENSORS_FEATURE_UNKNOWN		= INT_MAX,
+} sensors_feature_type;
+
+/* All the sensor types (in, fan, temp, vid) are a multiple of 0x100 apart,
+   and sensor subfeatures which have no compute mapping have bit 7 set. */
+typedef enum sensors_subfeature_type {
+	SENSORS_SUBFEATURE_IN_INPUT = SENSORS_FEATURE_IN << 8,
+	SENSORS_SUBFEATURE_IN_MIN,
+	SENSORS_SUBFEATURE_IN_MAX,
+	SENSORS_SUBFEATURE_IN_ALARM = (SENSORS_FEATURE_IN << 8) | 0x80,
+	SENSORS_SUBFEATURE_IN_MIN_ALARM,
+	SENSORS_SUBFEATURE_IN_MAX_ALARM,
+	SENSORS_SUBFEATURE_IN_BEEP,
+
+	SENSORS_SUBFEATURE_FAN_INPUT = SENSORS_FEATURE_FAN << 8,
+	SENSORS_SUBFEATURE_FAN_MIN,
+	SENSORS_SUBFEATURE_FAN_ALARM = (SENSORS_FEATURE_FAN << 8) | 0x80,
+	SENSORS_SUBFEATURE_FAN_FAULT,
+	SENSORS_SUBFEATURE_FAN_DIV,
+	SENSORS_SUBFEATURE_FAN_BEEP,
+
+	SENSORS_SUBFEATURE_TEMP_INPUT = SENSORS_FEATURE_TEMP << 8,
+	SENSORS_SUBFEATURE_TEMP_MAX,
+	SENSORS_SUBFEATURE_TEMP_MAX_HYST,
+	SENSORS_SUBFEATURE_TEMP_MIN,
+	SENSORS_SUBFEATURE_TEMP_CRIT,
+	SENSORS_SUBFEATURE_TEMP_CRIT_HYST,
+	SENSORS_SUBFEATURE_TEMP_ALARM = (SENSORS_FEATURE_TEMP << 8) | 0x80,
+	SENSORS_SUBFEATURE_TEMP_MAX_ALARM,
+	SENSORS_SUBFEATURE_TEMP_MIN_ALARM,
+	SENSORS_SUBFEATURE_TEMP_CRIT_ALARM,
+	SENSORS_SUBFEATURE_TEMP_FAULT,
+	SENSORS_SUBFEATURE_TEMP_TYPE,
+	SENSORS_SUBFEATURE_TEMP_OFFSET,
+	SENSORS_SUBFEATURE_TEMP_BEEP,
+
+	SENSORS_SUBFEATURE_VID = SENSORS_FEATURE_VID << 8,
+
+	SENSORS_SUBFEATURE_BEEP_ENABLE = SENSORS_FEATURE_BEEP_ENABLE << 8,
+
+	SENSORS_SUBFEATURE_UNKNOWN = INT_MAX,
+} sensors_subfeature_type;
+
+/* Data about a single chip feature (or category leader) */
+struct sensors_feature {
+	char *name;
+	int number;
+	sensors_feature_type type;
+	/* Members below are for libsensors internal use only */
+	int first_subfeature;
+	int padding1;
+};
+
+/* Data about a single chip subfeature:
+   name is the string name used to refer to this subfeature (in config files)
+   number is the internal subfeature number, used in many functions to refer
+     to this subfeature
+   type is the subfeature type
+   mapping is the number of a main feature this subfeature belongs to
+     (for example subfeatures fan1_input, fan1_min, fan1_div and fan1_alarm
+      are mapped to main feature fan1)
+   flags is a bitfield, its value is a combination of SENSORS_MODE_R (readable),
+     SENSORS_MODE_W (writable) and SENSORS_COMPUTE_MAPPING (affected by the
+     computation rules of the main feature) */
+typedef struct sensors_subfeature {
+	char *name;
+	int number;
+	sensors_subfeature_type type;
+	int mapping;
+	unsigned int flags;
+} sensors_subfeature;
+
+/* This returns all main features of a specific chip. nr is an internally
+   used variable. Set it to zero to start at the begin of the list. If no
+   more features are found NULL is returned.
+   Do not try to change the returned structure; you will corrupt internal
+   data structures. */
+const sensors_feature *
+sensors_get_features(const sensors_chip_name *name, int *nr);
+
+/* This returns all subfeatures of a given main feature. nr is an internally
+   used variable. Set it to zero to start at the begin of the list. If no
+   more features are found NULL is returned.
+   Do not try to change the returned structure; you will corrupt internal
+   data structures. */
+const sensors_subfeature *
+sensors_get_all_subfeatures(const sensors_chip_name *name,
+			    const sensors_feature *feature, int *nr);
+
+/* This returns the subfeature of the given type for a given main feature,
+   if it exists, NULL otherwise.
+   Do not try to change the returned structure; you will corrupt internal
+   data structures. */
+const sensors_subfeature *
+sensors_get_subfeature(const sensors_chip_name *name,
+		       const sensors_feature *feature,
+		       sensors_subfeature_type type);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* def LIB_SENSORS_ERROR_H */
Index: /lm-sensors/tags/V3-0-0-RC2/lib/access.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/access.c	(revision 4851)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/access.c	(revision 4851)
@@ -0,0 +1,536 @@
+/*
+    access.c - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "access.h"
+#include "sensors.h"
+#include "data.h"
+#include "error.h"
+#include "sysfs.h"
+#include "general.h"
+
+static int sensors_eval_expr(const sensors_chip_features *chip_features,
+			     const sensors_expr *expr,
+			     double val, double *result);
+
+/* Compare two chips name descriptions, to see whether they could match.
+   Return 0 if it does not match, return 1 if it does match. */
+static int sensors_match_chip(const sensors_chip_name *chip1,
+		       const sensors_chip_name *chip2)
+{
+	if ((chip1->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
+	    (chip2->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
+	    strcmp(chip1->prefix, chip2->prefix))
+		return 0;
+
+	if ((chip1->bus.type != SENSORS_BUS_TYPE_ANY) &&
+	    (chip2->bus.type != SENSORS_BUS_TYPE_ANY) &&
+	    (chip1->bus.type != chip2->bus.type))
+		return 0;
+
+	if ((chip1->bus.nr != SENSORS_BUS_NR_ANY) &&
+	    (chip2->bus.nr != SENSORS_BUS_NR_ANY) &&
+	    (chip1->bus.nr != chip2->bus.nr))
+		return 0;
+
+	if ((chip1->addr != chip2->addr) &&
+	    (chip1->addr != SENSORS_CHIP_NAME_ADDR_ANY) &&
+	    (chip2->addr != SENSORS_CHIP_NAME_ADDR_ANY))
+		return 0;
+
+	return 1;
+}
+
+/* Returns, one by one, a pointer to all sensor_chip structs of the
+   config file which match with the given chip name. Last should be
+   the value returned by the last call, or NULL if this is the first
+   call. Returns NULL if no more matches are found. Do not modify
+   the struct the return value points to! 
+   Note that this visits the list of chips from last to first. Usually,
+   you want the match that was latest in the config file. */
+static sensors_chip *
+sensors_for_all_config_chips(const sensors_chip_name *name,
+			     const sensors_chip *last)
+{
+	int nr, i;
+	sensors_chip_name_list chips;
+
+	for (nr = last ? last - sensors_config_chips - 1 :
+			 sensors_config_chips_count - 1; nr >= 0; nr--) {
+
+		chips = sensors_config_chips[nr].chips;
+		for (i = 0; i < chips.fits_count; i++) {
+			if (sensors_match_chip(&chips.fits[i], name))
+				return sensors_config_chips + nr;
+		}
+	}
+	return NULL;
+}
+
+/* Look up a chip in the intern chip list, and return a pointer to it.
+   Do not modify the struct the return value points to! Returns NULL if
+   not found.*/
+static const sensors_chip_features *
+sensors_lookup_chip(const sensors_chip_name *name)
+{
+	int i;
+
+	for (i = 0; i < sensors_proc_chips_count; i++)
+		if (sensors_match_chip(&sensors_proc_chips[i].chip, name))
+			return &sensors_proc_chips[i];
+
+	return NULL;
+}
+
+/* Look up a subfeature of the given chip, and return a pointer to it.
+   Do not modify the struct the return value points to! Returns NULL if
+   not found.*/
+static const sensors_subfeature *
+sensors_lookup_subfeature_nr(const sensors_chip_features *chip,
+			     int subfeat_nr)
+{
+	if (subfeat_nr < 0 ||
+	    subfeat_nr >= chip->subfeature_count)
+		return NULL;
+	return chip->subfeature + subfeat_nr;
+}
+
+/* Look up a feature of the given chip, and return a pointer to it.
+   Do not modify the struct the return value points to! Returns NULL if
+   not found.*/
+static const sensors_feature *
+sensors_lookup_feature_nr(const sensors_chip_features *chip, int feat_nr)
+{
+	if (feat_nr < 0 ||
+	    feat_nr >= chip->feature_count)
+		return NULL;
+	return chip->feature + feat_nr;
+}
+
+/* Look up a subfeature by name, and return a pointer to it.
+   Do not modify the struct the return value points to! Returns NULL if 
+   not found.*/
+static const sensors_subfeature *
+sensors_lookup_subfeature_name(const sensors_chip_features *chip,
+			       const char *name)
+{
+	int j;
+
+	for (j = 0; j < chip->subfeature_count; j++)
+		if (!strcmp(chip->subfeature[j].name, name))
+			return chip->subfeature + j;
+	return NULL;
+}
+
+/* Check whether the chip name is an 'absolute' name, which can only match
+   one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
+   if there are wildcards. */
+int sensors_chip_name_has_wildcards(const sensors_chip_name *chip)
+{
+	if ((chip->prefix == SENSORS_CHIP_NAME_PREFIX_ANY) ||
+	    (chip->bus.type == SENSORS_BUS_TYPE_ANY) ||
+	    (chip->bus.nr == SENSORS_BUS_NR_ANY) ||
+	    (chip->addr == SENSORS_CHIP_NAME_ADDR_ANY))
+		return 1;
+	else
+		return 0;
+}
+
+/* Look up the label for a given feature. Note that chip should not
+   contain wildcard values! The returned string is newly allocated (free it
+   yourself). On failure, NULL is returned.
+   If no label exists for this feature, its name is returned itself. */
+char *sensors_get_label(const sensors_chip_name *name,
+			const sensors_feature *feature)
+{
+	char *label;
+	const sensors_chip *chip;
+	char buf[128], path[PATH_MAX];
+	FILE *f;
+	int i;
+
+	if (sensors_chip_name_has_wildcards(name))
+		return NULL;
+
+	for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
+		for (i = 0; i < chip->labels_count; i++)
+			if (!strcmp(feature->name, chip->labels[i].name)) {
+				label = strdup(chip->labels[i].value);
+				goto sensors_get_label_exit;
+			}
+
+	/* No user specified label, check for a _label sysfs file */
+	snprintf(path, PATH_MAX, "%s/%s_label", name->path, feature->name);
+	
+	if ((f = fopen(path, "r"))) {
+		i = fread(buf, 1, sizeof(buf) - 1, f);
+		fclose(f);
+		if (i > 0) {
+			/* i - 1 to strip the '\n' at the end */
+			buf[i - 1] = 0;
+			label = strdup(buf);
+			goto sensors_get_label_exit;
+		}
+	}
+
+	/* No label, return the feature name instead */
+	label = strdup(feature->name);
+	
+sensors_get_label_exit:
+	if (!label)
+		sensors_fatal_error("sensors_get_label",
+				    "Allocating label text");
+	return label;
+}
+
+/* Looks up whether a feature should be ignored. Returns
+   1 if it should be ignored, 0 if not. */
+static int sensors_get_ignored(const sensors_chip_name *name,
+			       const sensors_feature *feature)
+{
+	const sensors_chip *chip;
+	int i;
+
+	for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
+		for (i = 0; i < chip->ignores_count; i++)
+			if (!strcmp(feature->name, chip->ignores[i].name))
+				return 1;
+	return 0;
+}
+
+/* Read the value of a subfeature of a certain chip. Note that chip should not
+   contain wildcard values! This function will return 0 on success, and <0
+   on failure. */
+int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
+		      double *result)
+{
+	const sensors_chip_features *chip_features;
+	const sensors_subfeature *subfeature;
+	const sensors_expr *expr = NULL;
+	double val;
+	int res, i;
+
+	if (sensors_chip_name_has_wildcards(name))
+		return -SENSORS_ERR_WILDCARDS;
+	if (!(chip_features = sensors_lookup_chip(name)))
+		return -SENSORS_ERR_NO_ENTRY;
+	if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
+							subfeat_nr)))
+		return -SENSORS_ERR_NO_ENTRY;
+	if (!(subfeature->flags & SENSORS_MODE_R))
+		return -SENSORS_ERR_ACCESS_R;
+
+	/* Apply compute statement if it exists */
+	if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
+		const sensors_feature *feature;
+		const sensors_chip *chip;
+
+		feature = sensors_lookup_feature_nr(chip_features,
+					subfeature->mapping);
+
+		chip = NULL;
+		while ((chip = sensors_for_all_config_chips(name, chip)))
+			for (i = 0; i < chip->computes_count; i++) {
+				if (!strcmp(feature->name,
+					    chip->computes[i].name)) {
+					expr = chip->computes[i].from_proc;
+					break;
+				}
+			}
+	}
+
+	res = sensors_read_sysfs_attr(name, subfeature, &val);
+	if (res)
+		return res;
+	if (!expr)
+		*result = val;
+	else if ((res = sensors_eval_expr(chip_features, expr, val, result)))
+		return res;
+	return 0;
+}
+
+/* Set the value of a subfeature of a certain chip. Note that chip should not
+   contain wildcard values! This function will return 0 on success, and <0
+   on failure. */
+int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
+		      double value)
+{
+	const sensors_chip_features *chip_features;
+	const sensors_subfeature *subfeature;
+	const sensors_expr *expr = NULL;
+	int i, res;
+	double to_write;
+
+	if (sensors_chip_name_has_wildcards(name))
+		return -SENSORS_ERR_WILDCARDS;
+	if (!(chip_features = sensors_lookup_chip(name)))
+		return -SENSORS_ERR_NO_ENTRY;
+	if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
+							subfeat_nr)))
+		return -SENSORS_ERR_NO_ENTRY;
+	if (!(subfeature->flags & SENSORS_MODE_W))
+		return -SENSORS_ERR_ACCESS_W;
+
+	/* Apply compute statement if it exists */
+	if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
+		const sensors_feature *feature;
+		const sensors_chip *chip;
+
+		feature = sensors_lookup_feature_nr(chip_features,
+					subfeature->mapping);
+
+		chip = NULL;
+		while ((chip = sensors_for_all_config_chips(name, chip)))
+			for (i = 0; i < chip->computes_count; i++) {
+				if (!strcmp(feature->name,
+					    chip->computes[i].name)) {
+					expr = chip->computes[i].to_proc;
+					break;
+				}
+			}
+	}
+
+	to_write = value;
+	if (expr)
+		if ((res = sensors_eval_expr(chip_features, expr,
+					     value, &to_write)))
+			return res;
+	return sensors_write_sysfs_attr(name, subfeature, to_write);
+}
+
+const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
+						    *match, int *nr)
+{
+	const sensors_chip_name *res;
+
+	while (*nr < sensors_proc_chips_count) {
+		res = &sensors_proc_chips[(*nr)++].chip;
+		if (!match || sensors_match_chip(res, match))
+			return res;
+	}
+	return NULL;
+}
+
+const char *sensors_get_adapter_name(const sensors_bus_id *bus)
+{
+	int i;
+
+	/* bus types with a single instance */
+	switch (bus->type) {
+	case SENSORS_BUS_TYPE_ISA:
+		return "ISA adapter";
+	case SENSORS_BUS_TYPE_PCI:
+		return "PCI adapter";
+	/* SPI should not be here, but for now SPI adapters have no name
+	   so we don't have any custom string to return. */
+	case SENSORS_BUS_TYPE_SPI:
+		return "SPI adapter";
+	}
+
+	/* bus types with several instances */
+	for (i = 0; i < sensors_proc_bus_count; i++)
+		if (sensors_proc_bus[i].bus.type == bus->type &&
+		    sensors_proc_bus[i].bus.nr == bus->nr)
+			return sensors_proc_bus[i].adapter;
+	return NULL;
+}
+
+const sensors_feature *
+sensors_get_features(const sensors_chip_name *name, int *nr)
+{
+	const sensors_chip_features *chip;
+
+	if (!(chip = sensors_lookup_chip(name)))
+		return NULL;	/* No such chip */
+
+	while (*nr < chip->feature_count
+	    && sensors_get_ignored(name, &chip->feature[*nr]))
+		(*nr)++;
+	if (*nr >= chip->feature_count)
+		return NULL;
+	return &chip->feature[(*nr)++];
+}
+
+const sensors_subfeature *
+sensors_get_all_subfeatures(const sensors_chip_name *name,
+			const sensors_feature *feature, int *nr)
+{
+	const sensors_chip_features *chip;
+	const sensors_subfeature *subfeature;
+
+	if (!(chip = sensors_lookup_chip(name)))
+		return NULL;	/* No such chip */
+
+	/* Seek directly to the first subfeature */
+	if (*nr < feature->first_subfeature)
+		*nr = feature->first_subfeature;
+
+	if (*nr >= chip->subfeature_count)
+		return NULL;	/* end of list */
+	subfeature = &chip->subfeature[(*nr)++];
+	if (subfeature->mapping == feature->number)
+		return subfeature;
+	return NULL;	/* end of subfeature list */
+}
+
+const sensors_subfeature *
+sensors_get_subfeature(const sensors_chip_name *name,
+		       const sensors_feature *feature,
+		       sensors_subfeature_type type)
+{
+	const sensors_chip_features *chip;
+	int i;
+
+	if (!(chip = sensors_lookup_chip(name)))
+		return NULL;	/* No such chip */
+
+	for (i = feature->first_subfeature; i < chip->subfeature_count &&
+	     chip->subfeature[i].mapping == feature->number; i++) {
+		if (chip->subfeature[i].type == type)
+			return &chip->subfeature[i];
+	}
+	return NULL;	/* No such subfeature */
+}
+
+/* Evaluate an expression */
+int sensors_eval_expr(const sensors_chip_features *chip_features,
+		      const sensors_expr *expr,
+		      double val, double *result)
+{
+	double res1, res2;
+	int res;
+	const sensors_subfeature *subfeature;
+
+	if (expr->kind == sensors_kind_val) {
+		*result = expr->data.val;
+		return 0;
+	}
+	if (expr->kind == sensors_kind_source) {
+		*result = val;
+		return 0;
+	}
+	if (expr->kind == sensors_kind_var) {
+		if (!(subfeature = sensors_lookup_subfeature_name(chip_features,
+							    expr->data.var)))
+			return SENSORS_ERR_NO_ENTRY;
+		if (!(res = sensors_get_value(&chip_features->chip,
+					      subfeature->number, result)))
+			return res;
+		return 0;
+	}
+	if ((res = sensors_eval_expr(chip_features, expr->data.subexpr.sub1,
+				     val, &res1)))
+		return res;
+	if (expr->data.subexpr.sub2 &&
+	    (res = sensors_eval_expr(chip_features, expr->data.subexpr.sub2,
+				     val, &res2)))
+		return res;
+	switch (expr->data.subexpr.op) {
+	case sensors_add:
+		*result = res1 + res2;
+		return 0;
+	case sensors_sub:
+		*result = res1 - res2;
+		return 0;
+	case sensors_multiply:
+		*result = res1 * res2;
+		return 0;
+	case sensors_divide:
+		if (res2 == 0.0)
+			return -SENSORS_ERR_DIV_ZERO;
+		*result = res1 / res2;
+		return 0;
+	case sensors_negate:
+		*result = -res1;
+		return 0;
+	case sensors_exp:
+		*result = exp(res1);
+		return 0;
+	case sensors_log:
+		if (res1 < 0.0)
+			return -SENSORS_ERR_DIV_ZERO;
+		*result = log(res1);
+		return 0;
+	}
+	return 0;
+}
+
+/* Execute all set statements for this particular chip. The chip may not 
+   contain wildcards!  This function will return 0 on success, and <0 on 
+   failure. */
+static int sensors_do_this_chip_sets(const sensors_chip_name *name)
+{
+	const sensors_chip_features *chip_features;
+	sensors_chip *chip;
+	double value;
+	int i;
+	int err = 0, res;
+	const sensors_subfeature *subfeature;
+
+	chip_features = sensors_lookup_chip(name);	/* Can't fail */
+
+	for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
+		for (i = 0; i < chip->sets_count; i++) {
+			subfeature = sensors_lookup_subfeature_name(chip_features,
+							chip->sets[i].name);
+			if (!subfeature) {
+				sensors_parse_error("Unknown feature name",
+						    chip->sets[i].lineno);
+				err = SENSORS_ERR_NO_ENTRY;
+				continue;
+			}
+
+			res = sensors_eval_expr(chip_features,
+						chip->sets[i].value, 0,
+						&value);
+			if (res) {
+				sensors_parse_error("Error parsing expression",
+						    chip->sets[i].lineno);
+				err = res;
+				continue;
+			}
+			if ((res = sensors_set_value(name, subfeature->number,
+						     value))) {
+				sensors_parse_error("Failed to set value",
+						chip->sets[i].lineno);
+				err = res;
+				continue;
+			}
+		}
+	return err;
+}
+
+/* Execute all set statements for this particular chip. The chip may contain
+   wildcards!  This function will return 0 on success, and <0 on failure. */
+int sensors_do_chip_sets(const sensors_chip_name *name)
+{
+	int nr, this_res;
+	const sensors_chip_name *found_name;
+	int res = 0;
+
+	for (nr = 0; (found_name = sensors_get_detected_chips(name, &nr));) {
+		this_res = sensors_do_this_chip_sets(found_name);
+		if (this_res)
+			res = this_res;
+	}
+	return res;
+}
Index: /lm-sensors/tags/V3-0-0-RC2/lib/sensors.conf.5
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/sensors.conf.5	(revision 4782)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/sensors.conf.5	(revision 4782)
@@ -0,0 +1,405 @@
+.\" Copyright 1998, 1999 Adrian Baugh <adrian.baugh@keble.ox.ac.uk> and
+.\" Frodo Looijaard <frodol@dds.nl>
+.\"
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one
+.\" 
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date.  The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein.  The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\" 
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\"
+.\" References consulted:
+.\"     sensors.conf.eg by Frodo Looijaard
+.TH sensors.conf 5  "September 2007" "lm-sensors 3" "Linux User's Manual"
+.SH NAME
+sensors.conf \- libsensors configuration file
+
+.SH DESCRIPTION
+sensors.conf describes how libsensors, and so all programs using it, should
+translate the raw readings from the kernel modules to real\-world values.
+
+.SH SYNTAX
+Comments are introduces by hash marks. A comment continues to the end of the
+line. Empty lines, and lines containing only whitespace or comments are 
+ignored.  Other lines have one of the below forms. There must be whitespace
+between each element, but the amount of whitespace is unimportant. A line
+may be continued on the next line by ending it with a backslash; this does
+not work within a comment,
+.B NAME
+or
+.BR NUMBER .
+
+.RS
+bus 
+.B NAME NAME NAME
+.sp 0
+chip 
+.B NAME\-LIST
+.sp 0
+label 
+.B NAME NAME
+.sp 0
+compute 
+.B NAME EXPR 
+, 
+.B EXPR
+.sp 0
+ignore
+.B NAME
+.sp 0
+set 
+.B NAME EXPR
+.RE
+.sp
+A
+.B NAME
+is a string. If it only contains letters, digits and underscores, it does not
+have to quoted; in all other cases, you should use double quotes around it.
+Within quotes, you can use the normal escape\-codes from C.
+
+A
+.B NAME\-LIST
+is one or more
+.B NAME
+items behind each other, separated by whitespace.
+
+A
+.B EXPR
+is of one of the below forms:
+
+.RS
+.B NUMBER
+.sp 0
+.B NAME
+.sp 0
+@
+.sp 0
+.B EXPR 
++
+.B EXPR
+.sp 0
+.B EXPR 
+\- 
+.B EXPR
+.sp 0
+.B EXPR 
+* 
+.B EXPR
+.sp 0
+.B EXPR 
+/ 
+.B EXPR
+.sp 0
+\- 
+.B EXPR
+.sp 0
+( 
+.B EXPR 
+)
+.RE
+
+A
+.B NUMBER
+is a floating\-point number. `10', `10.4' and `.4' are examples of valid
+floating\-point numbers; `10.' or `10E4' are not valid.
+
+.SH SEMANTICS
+
+This section describes the meaning of each statement. Each statement is
+accompanied by an example line. Please ignore line wrap\-arounds.
+
+.SS BUS STATEMENT
+
+.RS
+bus "i2c\-0" "SMBus PIIX4 adapter at e800"
+.RE
+
+A
+.I bus
+statement binds the description of an I2C or SMBus adapter to a bus number. 
+This makes it possible to refer to an adapter in the configuration file,
+independent of the actual correspondence of bus numbers and actual
+adapters (which may change from moment to moment).
+
+The first argument is the bus number. It is the literal text
+.IR i2c\- ,
+followed by a number. As there is a dash in this argument, it must
+always be quoted.
+
+The second argument is the adapter name, it must match exactly the
+adapter name as it appears in
+.IR /sys/class/i2c-adapter/i2c-*/name .
+It should always be quoted as well as it will most certainly contain
+spaces or dashes.
+
+The
+.I bus
+statements may be scattered randomly throughout the configuration file;
+there is no need to place the bus line before the place where its binding
+is referred to. Still, as a matter of good style, we suggest you place
+all
+.I bus
+statements together at the top of your configuration file.
+
+Running
+.B sensors --bus-list
+will generate these lines for you.
+
+.SS CHIP STATEMENT
+
+.RS
+chip "lm78\-*" "lm79\-*"
+.RE
+
+The 
+.I chip
+statement selects for which chips all following configuration
+statements are meant. The chip selection remains valid until the next
+.I chip
+statement. It does not influence the operation of a
+.I bus
+statement.
+
+If a chip matches at least one of the chip descriptions, all following
+configuration lines are examined for it. If it matches none of the
+chip descriptions, every 
+.RI non\- bus
+statement is ignored upto the next
+.I chip
+statement.
+
+A chip description is built from a couple of elements, separated by
+dashes.
+
+The first element is the name of the chip type. Sometimes a single driver
+implements several chip types, with several names. The driver documentation
+should tell you. You may substitute the wildcard operator
+.I *
+for this element.
+
+The second element is the name of the bus. This is either
+.IR isa ,
+.I pci
+or
+.IR i2c-N ,
+with 
+.I N
+being any number as binded with a 
+.I bus
+statement. You may substitute the wildcard operator
+.I *
+for this element, or only for the number of the I2C bus
+(which means 'any I2C bus').
+
+The third element is the hexadecimal address of the chip. The valid range
+depends on the bus type. You may substitute
+the wildcard operator
+.I *
+for this element. 
+
+Note that it wouldn't make any sense to specify the address without the
+bus type. For this reason, the address part is plain omitted when the bus
+type isn't specified.
+The following are all valid chip type specification based on
+.I lm78\-i2c\-1\-2d
+or
+.IR lm78\-isa\-0290 :
+
+.RS
+lm78\-i2c\-1\-2d
+.sp 0
+lm78\-i2c\-1\-*
+.sp 0
+lm78\-i2c\-*\-2d
+.sp 0
+lm78\-i2c\-*\-*
+.sp 0
+lm78\-isa\-0290
+.sp 0
+lm78\-isa\-*    
+.sp 0
+lm78\-*       
+.sp 0
+*\-i2c\-1\-2d
+.sp 0
+*\-i2c\-1\-*
+.sp 0
+*\-i2c\-*\-2d
+.sp 0
+*\-i2c-*\-*
+.sp 0
+*\-isa\-0290
+.sp 0
+*\-isa\-*
+.RE
+
+.SS COMPUTE STATEMENT
+.RS
+compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+.RE
+
+The 
+.I compute
+statement describes how you should translate a feature's raw value to a
+real\-world value, and how you should translate it back to a raw value again.
+
+The first argument is the feature name, which may be the name of a feature
+class (see below). The second is an expression which specifies how a
+raw value must be translated to a real\-world value; `@' stands here for 
+the raw value. The third is an expression that specifies how a real\-world
+value should be translated back to a raw value; `@' stands here for the
+real\-world value.
+
+You may use the name of other features in these expressions; you should be
+careful though to avoid circular references, as this may hang the expression
+evaluator.
+
+If at any moment a translation between a raw and a real\-world value is
+called for, but no 
+.I compute
+statement applies, a one\-on\-one translation is used instead.
+
+The comma is an unfortunate necessity to stop the statement from becoming
+ambiguous.
+
+.SS IGNORE STATEMENT
+.RS
+ignore fan1
+.RE
+
+The 
+.I ignore
+statement is a hint that a specific feature should be ignored - probably
+because it returns bogus values (for example, because a fan or temperature
+sensor is not connected).
+
+The only argument is the feature name, which may be a feature class;
+in that case the label class is used (see below).
+
+.SS LABEL STATEMENT
+.RS
+label in3 "+5V"
+.RE
+
+The
+.I label
+statement describes how a feature should be called. Features without a
+.I label
+statement are just called by their feature name. Applications can use this
+to label the readings they present (but they don't have to).
+
+The first argument is the feature name, which may be a feature class (see
+below). The second argument is the feature description.
+
+.SS SET STATEMENT
+.RS
+set in3_min  5 * 0.95
+.RE
+
+The
+.I set
+statement gives an initial value for a feature. Not each feature can be
+given a sensible initial value; valid features are usually min/max limits.
+
+The first argument is the feature name. The second argument is an expression
+which determines the initial value. If there is an applying 
+.I compute
+statement, this value is fed to its third argument to translate it to a
+raw value. 
+
+You may use the name of other features in these expressions; current readings
+are substituted. You should be careful though to avoid circular references, 
+as this may hang the expression evaluator. Also, you can't be sure in which
+order 
+.I set
+statements are evaluated, so this can lead to nasty surprises.
+
+.SH FEATURE CLASSES
+
+There are two kinds of classes, here called
+.I compute
+and
+.I label
+classes, after the statements for which they are defined. Classes are
+defined over features: the kind of values that can be read from or set
+for a specific kind of chip.
+
+Each class has a class name, which is usually the same as its most 
+prominent feature. A 
+.I label
+or
+.I compute
+statement for the class name feature forces the same settings for all other
+class members. A specific statement for a class member feature always
+overrides the general class setting, though. This means that you can't
+override the class name feature explicitly.
+
+A simple example will explain this better. The
+.I fan1
+label class of the 
+.I lm78
+chip contains three members:
+.I fan1
+itself,
+.I fan1_min
+and 
+.IR fan1_div .
+The last feature sets the number by which readings are divided (to give the
+fan less resolution, but a larger field of operation). The following
+line will set the name of all these features to describe the fan:
+.RS
+label fan1 "Processor 1 FAN"
+.RE
+Now we happen to know that, due to the type of fan we use, all readings
+are always off by a factor of two (some fans only return one 'tick' each
+rotation, others return two):
+.RS
+compute fan1 @/2 , @*2
+.RE
+It will be clear that this should be done for the 
+.I fan1_min 
+feature too, but not for the
+.I fan1_div
+feature! Fortunately, the 
+.I fan1
+compute class contains 
+.IR fan1_min ,
+but not 
+.IR fan1_div ,
+so this works out right.
+
+.SH WHICH STATEMENT APPLIES
+
+If more than one statement of the same kind applies at a certain moment,
+the last one in the configuration file is used. So usually, you should
+put more genereal 
+.I chip
+statements at the top, so you can overrule them below.
+
+There is one exception to this rule: if a statement only applies because
+the feature is in the same class as the feature the statement contains,
+and there is anywhere else a statement for this specific class member,
+that one takes always precedence.
+
+.SH SEE ALSO
+libsensors(3)
+
+.SH AUTHOR
+Frodo Looijaard and the lm_sensors group
+http://www.lm-sensors.org/
+
+
+
Index: /lm-sensors/tags/V3-0-0-RC2/lib/init.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/init.c	(revision 4902)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/init.c	(revision 4902)
@@ -0,0 +1,171 @@
+/*
+    init.c - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "sensors.h"
+#include "data.h"
+#include "error.h"
+#include "access.h"
+#include "conf.h"
+#include "sysfs.h"
+#include "scanner.h"
+#include "init.h"
+
+int sensors_init(FILE *input)
+{
+	int res;
+
+	if (!sensors_init_sysfs())
+		return -SENSORS_ERR_KERNEL;
+	if ((res = sensors_read_sysfs_bus()) ||
+	    (res = sensors_read_sysfs_chips()))
+		return res;
+	if ((res = sensors_scanner_init(input)))
+		return -SENSORS_ERR_PARSE;
+	if ((res = sensors_yyparse()))
+		return -SENSORS_ERR_PARSE;
+	if ((res = sensors_substitute_busses()))
+		return res;
+	return 0;
+}
+
+static void free_chip_name(sensors_chip_name *name)
+{
+	free(name->prefix);
+	free(name->path);
+}
+
+static void free_chip_features(sensors_chip_features *features)
+{
+	int i;
+
+	for (i = 0; i < features->subfeature_count; i++)
+		free(features->subfeature[i].name);
+	free(features->subfeature);
+	for (i = 0; i < features->feature_count; i++)
+		free(features->feature[i].name);
+	free(features->feature);
+}
+
+static void free_bus(sensors_bus *bus)
+{
+	free(bus->adapter);
+}
+
+static void free_label(sensors_label *label)
+{
+	free(label->name);
+	free(label->value);
+}
+
+void free_expr(sensors_expr *expr)
+{
+	if (expr->kind == sensors_kind_var)
+		free(expr->data.var);
+	else if (expr->kind == sensors_kind_sub) {
+		if (expr->data.subexpr.sub1)
+			free_expr(expr->data.subexpr.sub1);
+		if (expr->data.subexpr.sub2)
+			free_expr(expr->data.subexpr.sub2);
+	}
+	free(expr);
+}
+
+static void free_set(sensors_set *set)
+{
+	free(set->name);
+	free_expr(set->value);
+}
+
+static void free_compute(sensors_compute *compute)
+{
+	free(compute->name);
+	free_expr(compute->from_proc);
+	free_expr(compute->to_proc);
+}
+
+static void free_ignore(sensors_ignore *ignore)
+{
+	free(ignore->name);
+}
+
+static void free_chip(sensors_chip *chip)
+{
+	int i;
+
+	for (i = 0; i < chip->chips.fits_count; i++)
+		free_chip_name(&chip->chips.fits[i]);
+	free(chip->chips.fits);
+	chip->chips.fits_count = chip->chips.fits_max = 0;
+
+	for (i = 0; i < chip->labels_count; i++)
+		free_label(&chip->labels[i]);
+	free(chip->labels);
+	chip->labels_count = chip->labels_max = 0;
+
+	for (i = 0; i < chip->sets_count; i++)
+		free_set(&chip->sets[i]);
+	free(chip->sets);
+	chip->sets_count = chip->sets_max = 0;
+
+	for (i = 0; i < chip->computes_count; i++)
+		free_compute(&chip->computes[i]);
+	free(chip->computes);
+	chip->computes_count = chip->computes_max = 0;
+
+	for (i = 0; i < chip->ignores_count; i++)
+		free_ignore(&chip->ignores[i]);
+	free(chip->ignores);
+	chip->ignores_count = chip->ignores_max = 0;
+}
+
+void sensors_cleanup(void)
+{
+	int i;
+
+	sensors_scanner_exit();
+
+	for (i = 0; i < sensors_proc_chips_count; i++) {
+		free_chip_name(&sensors_proc_chips[i].chip);
+		free_chip_features(&sensors_proc_chips[i]);
+	}
+	free(sensors_proc_chips);
+	sensors_proc_chips = NULL;
+	sensors_proc_chips_count = sensors_proc_chips_max = 0;
+
+	for (i = 0; i < sensors_config_busses_count; i++)
+		free_bus(&sensors_config_busses[i]);
+	free(sensors_config_busses);
+	sensors_config_busses = NULL;
+	sensors_config_busses_count = sensors_config_busses_max = 0;
+
+	for (i = 0; i < sensors_config_chips_count; i++)
+		free_chip(&sensors_config_chips[i]);
+	free(sensors_config_chips);
+	sensors_config_chips = NULL;
+	sensors_config_chips_count = sensors_config_chips_max = 0;
+
+	for (i = 0; i < sensors_proc_bus_count; i++)
+		free_bus(&sensors_proc_bus[i]);
+	free(sensors_proc_bus);
+	sensors_proc_bus = NULL;
+	sensors_proc_bus_count = sensors_proc_bus_max = 0;
+}
Index: /lm-sensors/tags/V3-0-0-RC2/lib/libsensors.3
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/libsensors.3	(revision 4860)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/libsensors.3	(revision 4860)
@@ -0,0 +1,177 @@
+.\" Copyright 1998, 1999 Adrian Baugh <adrian.baugh@keble.ox.ac.uk>
+.\" based on sensors.h, part of libsensors by Frodo Looijaard
+.\" libsensors is distributed under the GPL
+.\"
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one
+.\" 
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date.  The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein.  The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\" 
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\"
+.\" References consulted:
+.\"     libsensors source code
+.TH libsensors 3  "June 2007" "lm-sensors 3" "Linux Programmer's Manual"
+.SH NAME
+libsensors \- publicly accessible functions provided by the sensors library
+.SH SYNOPSIS
+.nf
+.B #include <sensors/sensors.h>
+
+.B int sensors_init(FILE *input);
+.B void sensors_cleanup(void);
+.B int sensors_parse_chip_name(const char *orig_name,
+                            \fBsensors_chip_name *res);\fP
+.B const char *sensors_get_adapter_name(int bus_nr);
+.B char *sensors_get_label(const sensors_chip_name *name, const sensors_feature *feature);\fP
+.B int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
+                      \fBdouble *value);\fP
+.B int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
+                      \fBdouble value);\fP
+.B int sensors_do_chip_sets(const sensors_chip_name *name);
+.B const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
+                                                    \fB*match, int *nr);\fP
+.B const sensors_feature *sensors_get_features(const sensors_chip_name *name, int *nr);\fP
+.B const sensors_subfeature *sensors_get_all_subfeatures(const sensors_chip_name *name, const sensors_feature *feature, int *nr);\fP
+.B const sensors_subfeature *sensors_get_subfeature(const sensors_chip_name *name, const sensors_feature *feature, sensors_subfeature_type type);\fP
+.B const char *libsensors_version;
+.fi
+.SH DESCRIPTION
+.B int sensors_init(FILE *input);
+.br
+Load the configuration file and the detected chips list. If this returns a
+value unequal to zero, you are in trouble; you can not assume anything will
+be initialized properly. If you want to reload the configuration file, call
+sensors_cleanup() below before calling sensors_init() again.
+
+.B void sensors_cleanup(void);
+.br
+Clean-up function: You can't access anything after this, until the next sensors_init() call!
+.br
+
+\fBint sensors_parse_chip_name(const char *orig_name,
+                            sensors_chip_name *res);\fP
+.br
+Parse a chip name to the internal representation. Return 0 on succes, <0 on error.
+
+.B const char *sensors_get_adapter_name(int bus_nr);
+.br
+This function returns the adapter name of a bus number, as used within the
+sensors_chip_name structure. If it could not be found, it returns NULL.
+
+\fBchar *sensors_get_label(const sensors_chip_name *name, const sensors_feature *feature);\fP
+.br
+Look up the label which belongs to this chip. Note that chip should not
+contain wildcard values! The returned string is newly allocated (free it
+yourself). On failure, NULL is returned.
+If no label exists for this feature, its name is returned itself.
+
+\fBint sensors_get_value(const sensors_chip_name *name, int subfeat_nr, double *value);\fP
+.br
+Read the value of a subfeature of a certain chip. Note that chip should not
+contain wildcard values! This function will return 0 on success, and <0 on
+failure.
+
+\fBint sensors_set_value(const sensors_chip_name *name, int subfeat_nr, double value);\fP
+.br
+Set the value of a subfeature of a certain chip. Note that chip should not
+contain wildcard values! This function will return 0 on success, and <0 on
+failure.
+
+.B int sensors_do_chip_sets(const sensors_chip_name *name);
+.br
+Execute all set statements for this particular chip. The chip may contain wildcards!  This function will return 0 on success, and <0 on failure.
+
+\fBconst sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
+                                                    *match, int *nr);\fP
+.br
+This function returns all detected chips that match a given chip name,
+one by one. If no chip name is provided, all detected chips are returned.
+To start at the beginning of the list, use 0 for nr; NULL is returned if
+we are at the end of the list. Do not try to change these chip names, as
+they point to internal structures!
+
+This structure contains information related to a given feature of a
+specific chip.
+.br
+\fBtypedef struct sensors_feature {
+.br
+  const char *name;
+.br
+  int number;
+.br
+  sensors_feature_type type;
+.br
+} sensors_feature;\fP
+.br
+There are other member not documented here, which are only meant for libsensors
+internal use.
+
+This structure contains information related to a given subfeature of a
+specific chip feature.
+.br
+\fBtypedef struct sensors_subfeature {
+.br
+  const char *name;
+.br
+  int number;
+.br
+  sensors_subfeature_type type;
+.br
+  int mapping;
+.br
+  unsigned int flags;
+.br
+} sensors_subfeature;\fP
+.br
+The flags field is a bitfield, its value is a combination of
+SENSORS_MODE_R (readable), SENSORS_MODE_W (writable) and SENSORS_COMPUTE_MAPPING
+(affected by the computation rules of the main feature).
+
+\fBconst sensors_feature *sensors_get_features(const sensors_chip_name *name, int *nr);\fP
+.br
+This returns all main features of a specific chip. nr is an internally
+used variable. Set it to zero to start at the begin of the list. If no
+more features are found NULL is returned.
+Do not try to change the returned structure; you will corrupt internal
+data structures.
+
+\fBconst sensors_subfeature *sensors_get_all_subfeatures(const sensors_chip_name *name, const sensors_feature *feature, int *nr);\fP
+.br
+This returns all subfeatures of a given main feature. nr is an internally
+used variable. Set it to zero to start at the begin of the list. If no
+more subfeatures are found NULL is returned.
+Do not try to change the returned structure; you will corrupt internal
+data structures.
+
+\fBconst sensors_subfeature *sensors_get_subfeature(const sensors_chip_name *name, const sensors_feature *feature, sensors_subfeature_type type);\fP
+.br
+This returns the subfeature of the given type for a given main feature,
+if it exists, NULL otherwise.
+Do not try to change the returned structure; you will corrupt internal
+data structures.
+
+\fBconst char *libsensors_version;\fP
+.br
+A string representing the version of libsensors.
+
+.SH SEE ALSO
+sensors.conf(5)
+
+.SH AUTHOR
+Frodo Looijaard and the lm_sensors group
+http://www.lm-sensors.org/
+
Index: /lm-sensors/tags/V3-0-0-RC2/lib/access.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/access.h	(revision 4902)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/access.h	(revision 4902)
@@ -0,0 +1,32 @@
+/*
+    access.h - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LIB_SENSORS_ACCESS_H
+#define LIB_SENSORS_ACCESS_H
+
+#include "sensors.h"
+#include "data.h"
+
+/* Check whether the chip name is an 'absolute' name, which can only match
+   one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
+   if there are wildcards. */
+int sensors_chip_name_has_wildcards(const sensors_chip_name *chip);
+
+#endif /* def LIB_SENSORS_ACCESS_H */
Index: /lm-sensors/tags/V3-0-0-RC2/lib/sysfs.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/sysfs.c	(revision 4899)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/sysfs.c	(revision 4899)
@@ -0,0 +1,616 @@
+/*
+    sysfs.c - Part of libsensors, a library for reading Linux sensor data
+    Copyright (c) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
+    Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* this define needed for strndup() */
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <sysfs/libsysfs.h>
+#include "data.h"
+#include "error.h"
+#include "access.h"
+#include "general.h"
+#include "sysfs.h"
+
+char sensors_sysfs_mount[NAME_MAX];
+
+#define MAX_SENSORS_PER_TYPE	20
+#define MAX_SUBFEATURES		8
+/* Room for all 3 types (in, fan, temp) with all their subfeatures + VID
+   + misc features */
+#define ALL_POSSIBLE_SUBFEATURES \
+				(MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 \
+				 + MAX_SENSORS_PER_TYPE + 1)
+
+static
+int get_type_scaling(sensors_subfeature_type type)
+{
+	switch (type & 0xFF80) {
+	case SENSORS_SUBFEATURE_IN_INPUT:
+	case SENSORS_SUBFEATURE_TEMP_INPUT:
+		return 1000;
+	case SENSORS_SUBFEATURE_FAN_INPUT:
+		return 1;
+	}
+
+	switch (type) {
+	case SENSORS_SUBFEATURE_VID:
+	case SENSORS_SUBFEATURE_TEMP_OFFSET:
+		return 1000;
+	default:
+		return 1;
+	}
+}
+
+static
+char *get_feature_name(sensors_feature_type ftype, char *sfname)
+{
+	char *name, *underscore;
+
+	switch (ftype) {
+	case SENSORS_FEATURE_IN:
+	case SENSORS_FEATURE_FAN:
+	case SENSORS_FEATURE_TEMP:
+		underscore = strchr(sfname, '_');
+		name = strndup(sfname, underscore - sfname);
+		break;
+	default:
+		name = strdup(sfname);
+	}
+
+	return name;
+}
+
+/* Static mappings for use by sensors_subfeature_get_type() */
+struct subfeature_type_match
+{
+	const char *name;
+	sensors_subfeature_type type;
+};
+
+struct feature_type_match
+{
+	const char *name;
+	const struct subfeature_type_match *submatches;
+};
+
+static const struct subfeature_type_match temp_matches[] = {
+	{ "input", SENSORS_SUBFEATURE_TEMP_INPUT },
+	{ "max", SENSORS_SUBFEATURE_TEMP_MAX },
+	{ "max_hyst", SENSORS_SUBFEATURE_TEMP_MAX_HYST },
+	{ "min", SENSORS_SUBFEATURE_TEMP_MIN },
+	{ "crit", SENSORS_SUBFEATURE_TEMP_CRIT },
+	{ "crit_hyst", SENSORS_SUBFEATURE_TEMP_CRIT_HYST },
+	{ "alarm", SENSORS_SUBFEATURE_TEMP_ALARM },
+	{ "min_alarm", SENSORS_SUBFEATURE_TEMP_MIN_ALARM },
+	{ "max_alarm", SENSORS_SUBFEATURE_TEMP_MAX_ALARM },
+	{ "crit_alarm", SENSORS_SUBFEATURE_TEMP_CRIT_ALARM },
+	{ "fault", SENSORS_SUBFEATURE_TEMP_FAULT },
+	{ "type", SENSORS_SUBFEATURE_TEMP_TYPE },
+	{ "offset", SENSORS_SUBFEATURE_TEMP_OFFSET },
+	{ NULL, 0 }
+};
+
+static const struct subfeature_type_match in_matches[] = {
+	{ "input", SENSORS_SUBFEATURE_IN_INPUT },
+	{ "min", SENSORS_SUBFEATURE_IN_MIN },
+	{ "max", SENSORS_SUBFEATURE_IN_MAX },
+	{ "alarm", SENSORS_SUBFEATURE_IN_ALARM },
+	{ "min_alarm", SENSORS_SUBFEATURE_IN_MIN_ALARM },
+	{ "max_alarm", SENSORS_SUBFEATURE_IN_MAX_ALARM },
+	{ NULL, 0 }
+};
+
+static const struct subfeature_type_match fan_matches[] = {
+	{ "input", SENSORS_SUBFEATURE_FAN_INPUT },
+	{ "min", SENSORS_SUBFEATURE_FAN_MIN },
+	{ "div", SENSORS_SUBFEATURE_FAN_DIV },
+	{ "alarm", SENSORS_SUBFEATURE_FAN_ALARM },
+	{ "fault", SENSORS_SUBFEATURE_FAN_FAULT },
+	{ NULL, 0 }
+};
+
+static const struct subfeature_type_match cpu_matches[] = {
+	{ "vid", SENSORS_SUBFEATURE_VID },
+	{ NULL, 0 }
+};
+
+static struct feature_type_match matches[] = {
+	{ "temp%d%c", temp_matches },
+	{ "in%d%c", in_matches },
+	{ "fan%d%c", fan_matches },
+	{ "cpu%d%c", cpu_matches },
+};
+
+/* Return the subfeature type and channel number based on the subfeature
+   name */
+static
+sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr)
+{
+	char c;
+	int i, count;
+	const struct subfeature_type_match *submatches;
+
+	/* Special case */
+	if (!strcmp(name, "beep_enable")) {
+		*nr = 0;
+		return SENSORS_SUBFEATURE_BEEP_ENABLE;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(matches); i++)
+		if ((count = sscanf(name, matches[i].name, nr, &c)))
+			break;
+
+	if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
+		return SENSORS_SUBFEATURE_UNKNOWN;  /* no match */
+
+	submatches = matches[i].submatches;
+	name = strchr(name + 3, '_') + 1;
+	for (i = 0; submatches[i].name != NULL; i++)
+		if (!strcmp(name, submatches[i].name))
+			return submatches[i].type;
+
+	return SENSORS_SUBFEATURE_UNKNOWN;
+}
+
+static int sensors_read_dynamic_chip(sensors_chip_features *chip,
+				     struct sysfs_device *sysdir)
+{
+	int i, fnum = 0, sfnum = 0, prev_slot;
+	struct sysfs_attribute *attr;
+	struct dlist *attrs;
+	sensors_subfeature *all_subfeatures;
+	sensors_subfeature *dyn_subfeatures;
+	sensors_feature *dyn_features;
+	sensors_feature_type ftype;
+	sensors_subfeature_type sftype;
+
+	attrs = sysfs_get_device_attributes(sysdir);
+
+	if (attrs == NULL)
+		return -ENOENT;
+
+	/* We use a large sparse table at first to store all found
+	   subfeatures, so that we can store them sorted at type and index
+	   and then later create a dense sorted table. */
+	all_subfeatures = calloc(ALL_POSSIBLE_SUBFEATURES,
+				 sizeof(sensors_subfeature));
+	if (!all_subfeatures)
+		sensors_fatal_error(__FUNCTION__, "Out of memory");
+
+	dlist_for_each_data(attrs, attr, struct sysfs_attribute) {
+		char *name = attr->name;
+		int nr;
+
+		sftype = sensors_subfeature_get_type(name, &nr);
+		if (sftype == SENSORS_SUBFEATURE_UNKNOWN)
+			continue;
+
+		/* Adjust the channel number */
+		switch (sftype & 0xFF00) {
+			case SENSORS_SUBFEATURE_FAN_INPUT:
+			case SENSORS_SUBFEATURE_TEMP_INPUT:
+				nr--;
+				break;
+		}
+
+		if (nr < 0 || nr >= MAX_SENSORS_PER_TYPE) {
+			/* More sensors of one type than MAX_SENSORS_PER_TYPE,
+			   we have to ignore it */
+#ifdef DEBUG
+			sensors_fatal_error(__FUNCTION__,
+					    "Increase MAX_SENSORS_PER_TYPE!");
+#endif
+			continue;
+		}
+
+		/* "calculate" a place to store the subfeature in our sparse,
+		   sorted table */
+		switch (sftype) {
+		case SENSORS_SUBFEATURE_VID:
+			i = nr + MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6;
+			break;
+		case SENSORS_SUBFEATURE_BEEP_ENABLE:
+			i = MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 +
+			    MAX_SENSORS_PER_TYPE;
+			break;
+		default:
+			i = (sftype >> 8) * MAX_SENSORS_PER_TYPE *
+			    MAX_SUBFEATURES * 2 + nr * MAX_SUBFEATURES * 2 +
+			    ((sftype & 0x80) >> 7) * MAX_SUBFEATURES +
+			    (sftype & 0x7F);
+		}
+
+		if (all_subfeatures[i].name) {
+#ifdef DEBUG
+			sensors_fatal_error(__FUNCTION__,
+					    "Duplicate subfeature");
+#endif
+			continue;
+		}
+
+		/* fill in the subfeature members */
+		all_subfeatures[i].type = sftype;
+		all_subfeatures[i].name = strdup(name);
+		if (!(sftype & 0x80))
+			all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING;
+		if (attr->method & SYSFS_METHOD_SHOW)
+			all_subfeatures[i].flags |= SENSORS_MODE_R;
+		if (attr->method & SYSFS_METHOD_STORE)
+			all_subfeatures[i].flags |= SENSORS_MODE_W;
+
+		sfnum++;
+	}
+
+	if (!sfnum) { /* No subfeature */
+		chip->subfeature = NULL;
+		goto exit_free;
+	}
+
+	/* How many main features? */
+	prev_slot = -1;
+	for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
+		if (!all_subfeatures[i].name)
+			continue;
+
+		if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 ||
+		    i / (MAX_SUBFEATURES * 2) != prev_slot) {
+			fnum++;
+			prev_slot = i / (MAX_SUBFEATURES * 2);
+		}
+	}
+
+	dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature));
+	dyn_features = calloc(fnum, sizeof(sensors_feature));
+	if (!dyn_subfeatures || !dyn_features)
+		sensors_fatal_error(__FUNCTION__, "Out of memory");
+
+	/* Copy from the sparse array to the compact array */
+	sfnum = 0;
+	fnum = -1;
+	prev_slot = -1;
+	for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
+		if (!all_subfeatures[i].name)
+			continue;
+
+		/* New main feature? */
+		if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 ||
+		    i / (MAX_SUBFEATURES * 2) != prev_slot) {
+			ftype = all_subfeatures[i].type >> 8;
+			fnum++;
+			prev_slot = i / (MAX_SUBFEATURES * 2);
+
+			dyn_features[fnum].name = get_feature_name(ftype,
+						all_subfeatures[i].name);
+			dyn_features[fnum].number = fnum;
+			dyn_features[fnum].first_subfeature = sfnum;
+			dyn_features[fnum].type = ftype;
+		}
+
+		dyn_subfeatures[sfnum] = all_subfeatures[i];
+		dyn_subfeatures[sfnum].number = sfnum;
+		/* Back to the feature */
+		dyn_subfeatures[sfnum].mapping = fnum;
+
+		sfnum++;
+	}
+
+	chip->subfeature = dyn_subfeatures;
+	chip->subfeature_count = sfnum;
+	chip->feature = dyn_features;
+	chip->feature_count = ++fnum;
+
+exit_free:
+	free(all_subfeatures);
+	return 0;
+}
+
+/* returns !0 if sysfs filesystem was found, 0 otherwise */
+int sensors_init_sysfs(void)
+{
+	struct stat statbuf;
+
+	/* libsysfs will return success even if sysfs is not mounted,
+	   so we have to double-check */
+	if (sysfs_get_mnt_path(sensors_sysfs_mount, NAME_MAX)
+	 || stat(sensors_sysfs_mount, &statbuf) < 0
+	 || statbuf.st_nlink <= 2)	/* Empty directory */
+		return 0;
+
+	return 1;
+}
+
+/* returns: 0 if successful, !0 otherwise */
+static int sensors_read_one_sysfs_chip(struct sysfs_device *dev)
+{
+	int domain, bus, slot, fn;
+	int err = -SENSORS_ERR_KERNEL;
+	struct sysfs_attribute *attr, *bus_attr;
+	char bus_path[SYSFS_PATH_MAX];
+	sensors_chip_features entry;
+
+	/* ignore any device without name attribute */
+	if (!(attr = sysfs_get_device_attr(dev, "name")))
+		return 0;
+
+	/* NB: attr->value[attr->len-1] == '\n'; chop that off */
+	entry.chip.prefix = strndup(attr->value, attr->len - 1);
+	if (!entry.chip.prefix)
+		sensors_fatal_error(__FUNCTION__, "out of memory");
+
+	entry.chip.path = strdup(dev->path);
+	if (!entry.chip.path)
+		sensors_fatal_error(__FUNCTION__, "out of memory");
+
+	if (sscanf(dev->name, "%hd-%x", &entry.chip.bus.nr, &entry.chip.addr) == 2) {
+		/* find out if legacy ISA or not */
+		if (entry.chip.bus.nr == 9191) {
+			entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
+			entry.chip.bus.nr = 0;
+		} else {
+			entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
+			snprintf(bus_path, sizeof(bus_path),
+				"%s/class/i2c-adapter/i2c-%d/device/name",
+				sensors_sysfs_mount, entry.chip.bus.nr);
+
+			if ((bus_attr = sysfs_open_attribute(bus_path))) {
+				if (sysfs_read_attribute(bus_attr)) {
+					sysfs_close_attribute(bus_attr);
+					goto exit_free;
+				}
+
+				if (bus_attr->value
+				 && !strncmp(bus_attr->value, "ISA ", 4)) {
+					entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
+					entry.chip.bus.nr = 0;
+				}
+
+				sysfs_close_attribute(bus_attr);
+			}
+		}
+	} else if (sscanf(dev->name, "spi%hd.%d", &entry.chip.bus.nr,
+			  &entry.chip.addr) == 2) {
+		/* SPI */
+		entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
+	} else if (sscanf(dev->name, "%*[a-z0-9_].%d", &entry.chip.addr) == 1) {
+		/* must be new ISA (platform driver) */
+		entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
+		entry.chip.bus.nr = 0;
+	} else if (sscanf(dev->name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
+		/* PCI */
+		entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
+		entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
+		entry.chip.bus.nr = 0;
+	} else {
+		/* platform device with no id? */
+		entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
+		entry.chip.bus.nr = 0;
+		entry.chip.addr = 0;
+	}
+
+	if (sensors_read_dynamic_chip(&entry, dev) < 0)
+		goto exit_free;
+	if (!entry.subfeature) { /* No subfeature, discard chip */
+		err = 0;
+		goto exit_free;
+	}
+	sensors_add_proc_chips(&entry);
+
+	return 0;
+
+exit_free:
+	free(entry.chip.prefix);
+	free(entry.chip.path);
+	return err;
+}
+
+/* returns 0 if successful, !0 otherwise */
+static int sensors_read_sysfs_chips_compat(void)
+{
+	struct sysfs_bus *bus;
+	struct dlist *devs;
+	struct sysfs_device *dev;
+	int ret = 0;
+
+	if (!(bus = sysfs_open_bus("i2c"))) {
+		if (errno && errno != ENOENT)
+			ret = -SENSORS_ERR_KERNEL;
+		goto exit0;
+	}
+
+	if (!(devs = sysfs_get_bus_devices(bus))) {
+		if (errno && errno != ENOENT)
+			ret = -SENSORS_ERR_KERNEL;
+		goto exit1;
+	}
+
+	dlist_for_each_data(devs, dev, struct sysfs_device)
+		if ((ret = sensors_read_one_sysfs_chip(dev)))
+			goto exit1;
+
+exit1:
+	/* this frees bus and devs */
+	sysfs_close_bus(bus);
+
+exit0:
+	return ret;
+}
+
+/* returns 0 if successful, !0 otherwise */
+int sensors_read_sysfs_chips(void)
+{
+	struct sysfs_class *cls;
+	struct dlist *clsdevs;
+	struct sysfs_class_device *clsdev;
+	int ret = 0;
+
+	if (!(cls = sysfs_open_class("hwmon"))) {
+		/* compatibility function for kernel 2.6.n where n <= 13 */
+		return sensors_read_sysfs_chips_compat();
+	}
+
+	if (!(clsdevs = sysfs_get_class_devices(cls))) {
+		if (errno && errno != ENOENT)
+			ret = -SENSORS_ERR_KERNEL;
+		goto exit;
+	}
+
+	dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
+		struct sysfs_device *dev;
+		if (!(dev = sysfs_get_classdev_device(clsdev))) {
+			ret = -SENSORS_ERR_KERNEL;
+			goto exit;
+		}
+		if ((ret = sensors_read_one_sysfs_chip(dev)))
+			goto exit;
+	}
+
+exit:
+	/* this frees cls and clsdevs */
+	sysfs_close_class(cls);
+	return ret;
+}
+
+/* returns 0 if successful, !0 otherwise */
+int sensors_read_sysfs_bus(void)
+{
+	struct sysfs_class *cls;
+	struct dlist *clsdevs;
+	struct sysfs_class_device *clsdev;
+	sensors_bus entry;
+	int ret = 0;
+
+	if (!(cls = sysfs_open_class("i2c-adapter"))) {
+		if (errno && errno != ENOENT)
+			ret = -SENSORS_ERR_KERNEL;
+		goto exit0;
+	}
+
+	if (!(clsdevs = sysfs_get_class_devices(cls))) {
+		if (errno && errno != ENOENT)
+			ret = -SENSORS_ERR_KERNEL;
+		goto exit1;
+	}
+
+	dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
+		struct sysfs_device *dev;
+		struct sysfs_attribute *attr;
+
+		/* Get the adapter name from the classdev "name" attribute
+		 * (Linux 2.6.20 and later). If it fails, fall back to
+		 * the device "name" attribute (for older kernels). */
+		if (!(attr = sysfs_get_classdev_attr(clsdev, "name"))
+		 && !((dev = sysfs_get_classdev_device(clsdev)) &&
+		      (attr = sysfs_get_device_attr(dev, "name"))))
+			continue;
+
+		if (sscanf(clsdev->name, "i2c-%hd", &entry.bus.nr) != 1 ||
+		    entry.bus.nr == 9191) /* legacy ISA */
+			continue;
+		entry.bus.type = SENSORS_BUS_TYPE_I2C;
+
+		/* NB: attr->value[attr->len-1] == '\n'; chop that off */
+		entry.adapter = strndup(attr->value, attr->len - 1);
+		if (!entry.adapter)
+			sensors_fatal_error(__FUNCTION__, "out of memory");
+
+		sensors_add_proc_bus(&entry);
+	}
+
+exit1:
+	/* this frees *cls _and_ *clsdevs */
+	sysfs_close_class(cls);
+
+exit0:
+	return ret;
+}
+
+int sensors_read_sysfs_attr(const sensors_chip_name *name,
+			    const sensors_subfeature *subfeature,
+			    double *value)
+{
+	char n[NAME_MAX];
+	FILE *f;
+
+	snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
+	if ((f = fopen(n, "r"))) {
+		int res, err = 0;
+
+		errno = 0;
+		res = fscanf(f, "%lf", value);
+		if (res == EOF && errno == EIO)
+			err = -SENSORS_ERR_IO;
+		else if (res != 1)
+			err = -SENSORS_ERR_ACCESS_R;
+		res = fclose(f);
+		if (err)
+			return err;
+
+		if (res == EOF) {
+			if (errno == EIO)
+				return -SENSORS_ERR_IO;
+			else 
+				return -SENSORS_ERR_ACCESS_R;
+		}
+		*value /= get_type_scaling(subfeature->type);
+	} else
+		return -SENSORS_ERR_KERNEL;
+
+	return 0;
+}
+
+int sensors_write_sysfs_attr(const sensors_chip_name *name,
+			     const sensors_subfeature *subfeature,
+			     double value)
+{
+	char n[NAME_MAX];
+	FILE *f;
+
+	snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
+	if ((f = fopen(n, "w"))) {
+		int res, err = 0;
+
+		value *= get_type_scaling(subfeature->type);
+		res = fprintf(f, "%d", (int) value);
+		if (res == -EIO)
+			err = -SENSORS_ERR_IO;
+		else if (res < 0)
+			err = -SENSORS_ERR_ACCESS_W;
+		res = fclose(f);
+		if (err)
+			return err;
+
+		if (res == EOF) {
+			if (errno == EIO)
+				return -SENSORS_ERR_IO;
+			else 
+				return -SENSORS_ERR_ACCESS_W;
+		}
+	} else
+		return -SENSORS_ERR_KERNEL;
+
+	return 0;
+}
Index: /lm-sensors/tags/V3-0-0-RC2/lib/init.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/init.h	(revision 4779)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/init.h	(revision 4779)
@@ -0,0 +1,27 @@
+/*
+    init.h - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (C) 2007  Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LIB_SENSORS_INIT_H
+#define LIB_SENSORS_INIT_H
+
+#include "data.h"
+
+void free_expr(sensors_expr *expr);
+
+#endif /* def LIB_SENSORS_INIT_H */
Index: /lm-sensors/tags/V3-0-0-RC2/lib/data.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/data.c	(revision 4736)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/data.c	(revision 4736)
@@ -0,0 +1,241 @@
+/*
+    data.c - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* this define needed for strndup() */
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "access.h"
+#include "error.h"
+#include "data.h"
+#include "sensors.h"
+#include "../version.h"
+
+const char *libsensors_version = LM_VERSION;
+
+sensors_chip *sensors_config_chips = NULL;
+int sensors_config_chips_count = 0;
+int sensors_config_chips_max = 0;
+
+sensors_bus *sensors_config_busses = NULL;
+int sensors_config_busses_count = 0;
+int sensors_config_busses_max = 0;
+
+sensors_chip_features *sensors_proc_chips = NULL;
+int sensors_proc_chips_count = 0;
+int sensors_proc_chips_max = 0;
+
+sensors_bus *sensors_proc_bus = NULL;
+int sensors_proc_bus_count = 0;
+int sensors_proc_bus_max = 0;
+
+static int sensors_substitute_chip(sensors_chip_name *name, int lineno);
+
+/*
+   Parse a chip name to the internal representation. These are valid names:
+
+     lm78-i2c-10-5e		*-i2c-10-5e
+     lm78-i2c-10-*		*-i2c-10-*
+     lm78-i2c-*-5e		*-i2c-*-5e
+     lm78-i2c-*-*		*-i2c-*-*
+     lm78-isa-10dd		*-isa-10dd
+     lm78-isa-*			*-isa-*
+     lm78-*			*-*
+
+   Here 'lm78' can be any prefix. 'i2c' and 'isa' are
+   literal strings, just like all dashes '-' and wildcards '*'. '10' can
+   be any decimal i2c bus number. '5e' can be any hexadecimal i2c device
+   address, and '10dd' any hexadecimal isa address.
+
+   The 'prefix' part in the result is freshly allocated. All old contents
+   of res is overwritten. res itself is not allocated. In case of an error
+   return (ie. != 0), res is undefined, but all allocations are undone.
+*/
+
+int sensors_parse_chip_name(const char *name, sensors_chip_name *res)
+{
+	char *dash;
+
+	/* First, the prefix. It's either "*" or a real chip name. */
+	if (!strncmp(name, "*-", 2)) {
+		res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY;
+		name += 2;
+	} else {
+		if (!(dash = strchr(name, '-')))
+			return -SENSORS_ERR_CHIP_NAME;
+		res->prefix = strndup(name, dash - name);
+		if (!res->prefix)
+			sensors_fatal_error("sensors_parse_chip_name",
+					    "Allocating name prefix");
+		name = dash + 1;
+	}
+
+	/* Then we have either a sole "*" (all chips with this name) or a bus
+	   type and an address. */
+	if (!strcmp(name, "*")) {
+		res->bus.type = SENSORS_BUS_TYPE_ANY;
+		res->bus.nr = SENSORS_BUS_NR_ANY;
+		res->addr = SENSORS_CHIP_NAME_ADDR_ANY;
+		return 0;
+	}
+
+	if (!(dash = strchr(name, '-')))
+		goto ERROR;
+	if (!strncmp(name, "i2c", dash - name))
+		res->bus.type = SENSORS_BUS_TYPE_I2C;
+	else if (!strncmp(name, "isa", dash - name))
+		res->bus.type = SENSORS_BUS_TYPE_ISA;
+	else if (!strncmp(name, "pci", dash - name))
+		res->bus.type = SENSORS_BUS_TYPE_PCI;
+	else if (!strncmp(name, "spi", dash - name))
+		res->bus.type = SENSORS_BUS_TYPE_SPI;
+	else
+		goto ERROR;
+	name = dash + 1;
+
+	/* Some bus types (i2c, spi) have an additional bus number.
+	   For these, the next part is either a "*" (any bus of that type)
+	   or a decimal number. */
+	switch (res->bus.type) {
+	case SENSORS_BUS_TYPE_I2C:
+	case SENSORS_BUS_TYPE_SPI:
+		if (!strncmp(name, "*-", 2)) {
+			res->bus.nr = SENSORS_BUS_NR_ANY;
+			name += 2;
+			break;
+		}
+
+		res->bus.nr = strtoul(name, &dash, 10);
+		if (*name == '\0' || *dash != '-' || res->bus.nr < 0)
+			goto ERROR;
+		name = dash + 1;
+		break;
+	default:
+		res->bus.nr = SENSORS_BUS_NR_ANY;
+	}
+
+	/* Last part is the chip address, or "*" for any address. */
+	if (!strcmp(name, "*")) {
+		res->addr = SENSORS_CHIP_NAME_ADDR_ANY;
+	} else {
+		res->addr = strtoul(name, &dash, 16);
+		if (*name == '\0' || *dash != '\0' || res->addr < 0)
+			goto ERROR;
+	}
+
+	return 0;
+
+ERROR:
+	free(res->prefix);
+	return -SENSORS_ERR_CHIP_NAME;
+}
+
+int sensors_snprintf_chip_name(char *str, size_t size,
+			       const sensors_chip_name *chip)
+{
+	if (sensors_chip_name_has_wildcards(chip))
+		return -SENSORS_ERR_WILDCARDS;
+
+	switch (chip->bus.type) {
+	case SENSORS_BUS_TYPE_ISA:
+		return snprintf(str, size, "%s-isa-%04x", chip->prefix,
+				chip->addr);
+	case SENSORS_BUS_TYPE_PCI:
+		return snprintf(str, size, "%s-pci-%04x", chip->prefix,
+				chip->addr);
+	case SENSORS_BUS_TYPE_I2C:
+		return snprintf(str, size, "%s-i2c-%hd-%02x", chip->prefix,
+				chip->bus.nr, chip->addr);
+	case SENSORS_BUS_TYPE_SPI:
+		return snprintf(str, size, "%s-spi-%hd-%x", chip->prefix,
+				chip->bus.nr, chip->addr);
+	}
+
+	return -SENSORS_ERR_CHIP_NAME;
+}
+
+int sensors_parse_bus_id(const char *name, sensors_bus_id *bus)
+{
+	char *endptr;
+
+	if (strncmp(name, "i2c-", 4)) {
+		return -SENSORS_ERR_BUS_NAME;
+	}
+	name += 4;
+	bus->type = SENSORS_BUS_TYPE_I2C;
+	bus->nr = strtoul(name, &endptr, 10);
+	if (*name == '\0' || *endptr != '\0' || bus->nr < 0)
+		return -SENSORS_ERR_BUS_NAME;
+	return 0;
+}
+
+int sensors_substitute_chip(sensors_chip_name *name, int lineno)
+{
+	int i, j;
+	for (i = 0; i < sensors_config_busses_count; i++)
+		if (sensors_config_busses[i].bus.type == name->bus.type &&
+		    sensors_config_busses[i].bus.nr == name->bus.nr)
+			break;
+
+	if (i == sensors_config_busses_count) {
+		sensors_parse_error("Undeclared bus id referenced", lineno);
+		name->bus.nr = SENSORS_BUS_NR_IGNORE;
+		return -SENSORS_ERR_BUS_NAME;
+	}
+
+	/* Compare the adapter names */
+	for (j = 0; j < sensors_proc_bus_count; j++) {
+		if (!strcmp(sensors_config_busses[i].adapter,
+			    sensors_proc_bus[j].adapter)) {
+			name->bus.nr = sensors_proc_bus[j].bus.nr;
+			return 0;
+		}
+	}
+
+	/* We did not find a matching bus name, simply ignore this chip
+	   config entry. */
+	name->bus.nr = SENSORS_BUS_NR_IGNORE;
+	return 0;
+}
+
+int sensors_substitute_busses(void)
+{
+	int err, i, j, lineno;
+	sensors_chip_name_list *chips;
+	int res = 0;
+
+	for (i = 0; i < sensors_config_chips_count; i++) {
+		lineno = sensors_config_chips[i].lineno;
+		chips = &sensors_config_chips[i].chips;
+		for (j = 0; j < chips->fits_count; j++) {
+			/* We can only substitute if a specific bus number
+			   is given. */
+			if (chips->fits[j].bus.nr == SENSORS_BUS_NR_ANY)
+				continue;
+
+			err = sensors_substitute_chip(&chips->fits[j], lineno);
+			if (err)
+				res = err;
+		}
+	}
+	return res;
+}
Index: /lm-sensors/tags/V3-0-0-RC2/lib/Module.mk
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/Module.mk	(revision 4848)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/Module.mk	(revision 4848)
@@ -0,0 +1,169 @@
+#  Module.mk - Makefile for a Linux module for reading sensor data.
+#  Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Note that MODULE_DIR (the directory in which this file resides) is a
+# 'simply expanded variable'. That means that its value is substituted
+# verbatim in the rules, until it is redefined. 
+MODULE_DIR := lib
+LIB_DIR := $(MODULE_DIR)
+
+# The manual dirs and files
+LIBMAN3DIR := $(MANDIR)/man3
+LIBMAN3FILES := $(MODULE_DIR)/libsensors.3
+LIBMAN5DIR := $(MANDIR)/man5
+LIBMAN5FILES := $(MODULE_DIR)/sensors.conf.5
+
+# The main and minor version of the library
+# The library soname (major number) must be changed if and only if the interface is
+# changed in a backward incompatible way.  The interface is defined by
+# the public header files - in this case they are error.h and sensors.h.
+LIBMAINVER := 4
+LIBMINORVER := 0.0
+LIBVER := $(LIBMAINVER).$(LIBMINORVER)
+
+# The static lib name, the shared lib name, and the internal ('so') name of
+# the shared lib.
+LIBSHBASENAME := libsensors.so
+LIBSHLIBNAME := libsensors.so.$(LIBVER)
+LIBSTLIBNAME := libsensors.a
+LIBSHSONAME := libsensors.so.$(LIBMAINVER)
+
+LIBTARGETS := $(MODULE_DIR)/$(LIBSTLIBNAME) $(MODULE_DIR)/$(LIBSHLIBNAME) \
+              $(MODULE_DIR)/$(LIBSHSONAME) $(MODULE_DIR)/$(LIBSHBASENAME)
+
+LIBCSOURCES := $(MODULE_DIR)/data.c $(MODULE_DIR)/general.c \
+               $(MODULE_DIR)/error.c $(MODULE_DIR)/access.c \
+               $(MODULE_DIR)/init.c $(MODULE_DIR)/sysfs.c
+
+LIBOTHEROBJECTS := $(MODULE_DIR)/conf-parse.o $(MODULE_DIR)/conf-lex.o
+LIBSHOBJECTS := $(LIBCSOURCES:.c=.lo) $(LIBOTHEROBJECTS:.o=.lo)
+LIBSTOBJECTS := $(LIBCSOURCES:.c=.ao) $(LIBOTHEROBJECTS:.o=.ao)
+LIBEXTRACLEAN := $(MODULE_DIR)/conf-parse.h $(MODULE_DIR)/conf-parse.c \
+                 $(MODULE_DIR)/conf-lex.c
+
+LIBHEADERFILES := $(MODULE_DIR)/error.h $(MODULE_DIR)/sensors.h
+
+# How to create the shared library
+$(MODULE_DIR)/$(LIBSHLIBNAME): $(LIBSHOBJECTS)
+	$(CC) -shared -Wl,-soname,$(LIBSHSONAME) -o $@ $^ -lc -lm -lsysfs
+
+$(MODULE_DIR)/$(LIBSHSONAME): $(MODULE_DIR)/$(LIBSHLIBNAME)
+	$(RM) $@
+	$(LN) $(LIBSHLIBNAME) $@
+
+$(MODULE_DIR)/$(LIBSHBASENAME): $(MODULE_DIR)/$(LIBSHLIBNAME)
+	$(RM) $@ 
+	$(LN) $(LIBSHLIBNAME) $@
+
+# And the static library
+$(MODULE_DIR)/$(LIBSTLIBNAME): $(LIBSTOBJECTS)
+	$(RM) $@
+	$(AR) rcvs $@ $^
+
+# Depencies for non-C sources
+$(MODULE_DIR)/conf-lex.c: $(MODULE_DIR)/conf-lex.l $(MODULE_DIR)/general.h \
+                          $(MODULE_DIR)/data.h $(MODULE_DIR)/conf-parse.h
+$(MODULE_DIR)/conf-parse.c: $(MODULE_DIR)/conf-parse.y $(MODULE_DIR)/general.h \
+                            $(MODULE_DIR)/data.h
+$(MODULE_DIR)/conf-parse.h: $(MODULE_DIR)/conf-parse.c
+
+# Include all dependency files
+INCLUDEFILES += $(LIBCSOURCES:.c=.ld) $(LIBCSOURCES:.c=.ad)
+
+# Special warning prevention for flex-generated files
+FLEXNOWARN:=-Wno-shadow -Wno-undef -Wno-unused -Wno-missing-prototypes -Wno-sign-compare
+$(MODULE_DIR)/conf-lex.ao: $(MODULE_DIR)/conf-lex.c
+	$(CC) $(ARCPPFLAGS) $(ARCFLAGS) $(FLEXNOWARN) -c $< -o $@
+$(MODULE_DIR)/conf-lex.lo: $(MODULE_DIR)/conf-lex.c
+	$(CC) $(LIBCPPFLAGS) $(LIBCFLAGS) $(FLEXNOWARN) -c $< -o $@
+
+# Special warning prevention for bison-generated files
+YACCNOWARN:=-Wno-undef
+$(MODULE_DIR)/conf-parse.ao: $(MODULE_DIR)/conf-parse.c
+	$(CC) $(ARCPPFLAGS) $(ARCFLAGS) $(YACCNOWARN) -c $< -o $@
+$(MODULE_DIR)/conf-parse.lo: $(MODULE_DIR)/conf-parse.c
+	$(CC) $(LIBCPPFLAGS) $(LIBCFLAGS) $(YACCNOWARN) -c $< -o $@
+
+REMOVELIBST := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(LIBDIR)/%,$(LIB_DIR)/$(LIBSTLIBNAME))
+REMOVELIBSH := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(LIBDIR)/%,$(LIB_DIR)/$(LIBSHLIBNAME))
+REMOVELNSO  := $(DESTDIR)$(LIBDIR)/$(LIBSHSONAME)
+REMOVELNBS  := $(DESTDIR)$(LIBDIR)/$(LIBSHBASENAME)
+REMOVELIBHF := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(LIBINCLUDEDIR)/%,$(LIBHEADERFILES))
+REMOVEMAN3  := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(LIBMAN3DIR)/%,$(LIBMAN3FILES))
+REMOVEMAN5  := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(LIBMAN5DIR)/%,$(LIBMAN5FILES))
+
+all-lib: $(LIBTARGETS)
+user :: all-lib
+
+# Generate warnings if the install directory isn't in /etc/ld.so.conf
+# or if the library wasn't there before (which means ldconfig must be run).
+# Note that some ld.so's put /usr/lib and /lib first, others put them last,
+# so we can't make any assumptions.
+install-lib: all-lib
+	$(MKDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(LIBINCLUDEDIR) $(DESTDIR)$(LIBMAN3DIR) $(DESTDIR)$(LIBMAN5DIR)
+	@if [ ! -e "$(DESTDIR)$(LIBDIR)/$(LIBSHSONAME)" ] ; then \
+	     echo '******************************************************************************' ; \
+	     echo 'Warning: This is the first installation of the $(LIBSHSONAME)*' ; \
+	     echo '         library files in $(DESTDIR)$(LIBDIR)!' ; \
+	     echo '         You must update the library cache or the userspace tools may fail' ; \
+	     echo '         or have unpredictable results!' ; \
+		 echo '         Run the following command: /sbin/ldconfig' ; \
+	     echo '******************************************************************************' ; \
+	fi
+	$(INSTALL) -m 644 $(LIB_DIR)/$(LIBSTLIBNAME) $(DESTDIR)$(LIBDIR)
+	$(INSTALL) -m 755 $(LIB_DIR)/$(LIBSHLIBNAME) $(DESTDIR)$(LIBDIR)
+	$(LN) $(LIBSHLIBNAME) $(DESTDIR)$(LIBDIR)/$(LIBSHSONAME)
+	$(LN) $(LIBSHSONAME) $(DESTDIR)$(LIBDIR)/$(LIBSHBASENAME)
+	@if [ "$(DESTDIR)$(LIBDIR)" != "/usr/lib" -a "$(DESTDIR)$(LIBDIR)" != "/lib" ] ; then \
+	   if [ -e "/usr/lib/$(LIBSHSONAME)" -o -e "/usr/lib/$(LIBSHBASENAME)" ] ; then \
+	     echo '******************************************************************************' ; \
+	     echo 'Warning: You have at least one $(LIBSHBASENAME) library file in /usr/lib' ; \
+	     echo '         and the new library files are in $(DESTDIR)$(LIBDIR)!' ; \
+	     echo '         These old files must be removed or the userspace tools may fail' ; \
+	     echo '         or have unpredictable results!' ; \
+	     echo '         Run the following command: rm /usr/lib/$(LIBSHBASENAME)*' ; \
+	     echo '******************************************************************************' ; \
+	   fi ; \
+	   grep -q '^$(DESTDIR)$(LIBDIR)$$' /etc/ld.so.conf || \
+	   grep -q '^$(DESTDIR)$(LIBDIR)[[:space:]:,=]' /etc/ld.so.conf || \
+	   grep -q '[[:space:]:,]$(DESTDIR)$(LIBDIR)$$' /etc/ld.so.conf || \
+	   grep -q '[[:space:]:,]$(DESTDIR)$(LIBDIR)[[:space:]:,=]' /etc/ld.so.conf || \
+		( echo '******************************************************************************' ; \
+		  echo 'Warning: Library directory $(DESTDIR)$(LIBDIR) is not in /etc/ld.so.conf!' ; \
+		  echo '         Add it and run /sbin/ldconfig for the userspace tools to work.' ; \
+		  echo '******************************************************************************' ) ; \
+	fi
+	$(INSTALL) -m 644 $(LIBHEADERFILES) $(DESTDIR)$(LIBINCLUDEDIR)
+	$(INSTALL) -m 644 $(LIBMAN3FILES) $(DESTDIR)$(LIBMAN3DIR)
+	$(INSTALL) -m 644 $(LIBMAN5FILES) $(DESTDIR)$(LIBMAN5DIR)
+
+
+user_install :: install-lib
+
+user_uninstall::
+	$(RM) $(REMOVELIBST) $(REMOVELIBSH) $(REMOVELNSO) $(REMOVELNBS) 
+	$(RM) $(REMOVELIBHF) $(REMOVEMAN3) $(REMOVEMAN5)
+# Remove directory if empty, ignore failure
+	$(RMDIR) $(DESTDIR)$(LIBINCLUDEDIR) 2> /dev/null || true
+
+clean-lib:
+	$(RM) $(LIB_DIR)/*.ld $(LIB_DIR)/*.ad
+	$(RM) $(LIB_DIR)/*.lo $(LIB_DIR)/*.ao
+	$(RM) $(LIBTARGETS) $(LIBEXTRACLEAN)
+# old versions
+	$(RM) $(LIB_DIR)/$(LIBSHBASENAME).*
+clean :: clean-lib
Index: /lm-sensors/tags/V3-0-0-RC2/lib/sysfs.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/sysfs.h	(revision 4902)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/sysfs.h	(revision 4902)
@@ -0,0 +1,42 @@
+/*
+    sysfs.h - part of libsensors, a library for reading Linux sensor data
+    Copyright (C)             Mark M. Hoffman <mhoffman@lightlink.com>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef SENSORS_LIB_SYSFS_H
+#define SENSORS_LIB_SYSFS_H
+
+extern char sensors_sysfs_mount[];
+
+int sensors_init_sysfs(void);
+
+int sensors_read_sysfs_chips(void);
+
+int sensors_read_sysfs_bus(void);
+
+/* Read a value out of a sysfs attribute file */
+int sensors_read_sysfs_attr(const sensors_chip_name *name,
+			    const sensors_subfeature *subfeature,
+			    double *value);
+
+/* Write a value to a sysfs attribute file */
+int sensors_write_sysfs_attr(const sensors_chip_name *name,
+			     const sensors_subfeature *subfeature,
+			     double value);
+
+#endif /* !SENSORS_LIB_SYSFS_H */
Index: /lm-sensors/tags/V3-0-0-RC2/lib/general.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/general.c	(revision 4756)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/general.c	(revision 4756)
@@ -0,0 +1,85 @@
+/*
+    general.c - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "error.h"
+#include "general.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+#define A_BUNCH 16
+
+void sensors_malloc_array(void *list, int *num_el, int *max_el, int el_size)
+{
+	void **my_list = (void **)list;
+
+	*my_list = malloc(el_size*A_BUNCH);
+	if (! *my_list)
+		sensors_fatal_error("sensors_malloc_array",
+				    "Allocating new elements");
+	*max_el = A_BUNCH;
+	*num_el = 0;
+}
+
+void sensors_free_array(void *list, int *num_el, int *max_el)
+{
+	void **my_list = (void **)list;
+
+	free(*my_list);
+	*my_list = NULL;
+	*num_el = 0;
+	*max_el = 0;
+}
+
+void sensors_add_array_el(const void *el, void *list, int *num_el,
+			  int *max_el, int el_size)
+{
+	int new_max_el;
+	void **my_list = (void *)list;
+	if (*num_el + 1 > *max_el) {
+		new_max_el = *max_el + A_BUNCH;
+		*my_list = realloc(*my_list, new_max_el * el_size);
+		if (! *my_list)
+			sensors_fatal_error("sensors_add_array_el",
+					    "Allocating new elements");
+		*max_el = new_max_el;
+	}
+	memcpy(((char *) *my_list) + *num_el * el_size, el, el_size);
+	(*num_el) ++;
+}
+
+void sensors_add_array_els(const void *els, int nr_els, void *list,
+			   int *num_el, int *max_el, int el_size)
+{
+	int new_max_el;
+	void **my_list = (void *)list;
+	if (*num_el + nr_els > *max_el) {
+		new_max_el = (*max_el + nr_els + A_BUNCH);
+		new_max_el -= new_max_el % A_BUNCH;
+		*my_list = realloc(*my_list, new_max_el * el_size);
+		if (! *my_list)
+			sensors_fatal_error("sensors_add_array_els",
+					    "Allocating new elements");
+		*max_el = new_max_el;
+	}
+	memcpy(((char *)*my_list) + *num_el * el_size, els, el_size * nr_els);
+	*num_el += nr_els;
+}
Index: /lm-sensors/tags/V3-0-0-RC2/lib/data.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/data.h	(revision 4902)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/data.h	(revision 4902)
@@ -0,0 +1,167 @@
+/*
+    data.h - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LIB_SENSORS_DATA_H
+#define LIB_SENSORS_DATA_H
+
+#include "sensors.h"
+
+/* This header file contains all kinds of data structures which are used
+   for the representation of the config file data and the /proc/...
+   data. */
+
+/* Kinds of expression operators recognized */
+typedef enum sensors_operation {
+	sensors_add, sensors_sub, sensors_multiply, sensors_divide,
+	sensors_negate, sensors_exp, sensors_log,
+} sensors_operation;
+
+/* An expression can have several forms */
+typedef enum sensors_expr_kind {
+	sensors_kind_val, sensors_kind_source, sensors_kind_var,
+	sensors_kind_sub
+} sensors_expr_kind;
+
+/* An expression. It is either a floating point value, a variable name,
+   an operation on subexpressions, or the special value 'sub' } */
+struct sensors_expr;
+
+typedef struct sensors_subexpr {
+	sensors_operation op;
+	struct sensors_expr *sub1;
+	struct sensors_expr *sub2;
+} sensors_subexpr;
+
+typedef struct sensors_expr {
+	sensors_expr_kind kind;
+	union {
+		double val;
+		char *var;
+		sensors_subexpr subexpr;
+	} data;
+} sensors_expr;
+
+/* Config file label declaration: a feature name, combined with the label
+   value */
+typedef struct sensors_label {
+	char *name;
+	char *value;
+	int lineno;
+} sensors_label;
+
+/* Config file set declaration: a subfeature name, combined with an
+   expression */
+typedef struct sensors_set {
+	char *name;
+	sensors_expr *value;
+	int lineno;
+} sensors_set;
+
+/* Config file compute declaration: a feature name, combined with two
+   expressions */
+typedef struct sensors_compute {
+	char *name;
+	sensors_expr *from_proc;
+	sensors_expr *to_proc;
+	int lineno;
+} sensors_compute;
+
+/* Config file ignore declaration: a feature name */
+typedef struct sensors_ignore {
+	char *name;
+	int lineno;
+} sensors_ignore;
+
+/* A list of chip names, used to represent a config file chips declaration */
+typedef struct sensors_chip_name_list {
+	sensors_chip_name *fits;
+	int fits_count;
+	int fits_max;
+} sensors_chip_name_list;
+
+/* A config file chip block */
+typedef struct sensors_chip {
+	sensors_chip_name_list chips;
+	sensors_label *labels;
+	int labels_count;
+	int labels_max;
+	sensors_set *sets;
+	int sets_count;
+	int sets_max;
+	sensors_compute *computes;
+	int computes_count;
+	int computes_max;
+	sensors_ignore *ignores;
+	int ignores_count;
+	int ignores_max;
+	int lineno;
+} sensors_chip;
+
+/* Config file bus declaration: the bus type and number, combined with adapter
+   name */
+typedef struct sensors_bus {
+	char *adapter;
+	sensors_bus_id bus;
+	int lineno;
+} sensors_bus;
+
+/* Internal data about all features and subfeatures of a chip */
+typedef struct sensors_chip_features {
+	struct sensors_chip_name chip;
+	struct sensors_feature *feature;
+	struct sensors_subfeature *subfeature;
+	int feature_count;
+	int subfeature_count;
+} sensors_chip_features;
+
+extern sensors_chip *sensors_config_chips;
+extern int sensors_config_chips_count;
+extern int sensors_config_chips_max;
+
+extern sensors_bus *sensors_config_busses;
+extern int sensors_config_busses_count;
+extern int sensors_config_busses_max;
+
+extern sensors_chip_features *sensors_proc_chips;
+extern int sensors_proc_chips_count;
+extern int sensors_proc_chips_max;
+
+#define sensors_add_proc_chips(el) sensors_add_array_el( \
+	(el), &sensors_proc_chips, &sensors_proc_chips_count,\
+	&sensors_proc_chips_max, sizeof(struct sensors_chip_features))
+
+extern sensors_bus *sensors_proc_bus;
+extern int sensors_proc_bus_count;
+extern int sensors_proc_bus_max;
+
+#define sensors_add_proc_bus(el) sensors_add_array_el( \
+	(el), &sensors_proc_bus, &sensors_proc_bus_count,\
+	&sensors_proc_bus_max, sizeof(struct sensors_bus))
+
+/* Substitute configuration bus numbers with real-world /proc bus numbers
+   in the chips lists */
+int sensors_substitute_busses(void);
+
+
+/* Parse a bus id into its components. Returns 0 on succes, a value from
+   error.h on failure. */
+int sensors_parse_bus_id(const char *name, sensors_bus_id *bus);
+
+#endif /* def LIB_SENSORS_DATA_H */
Index: /lm-sensors/tags/V3-0-0-RC2/lib/general.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/general.h	(revision 4756)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/general.h	(revision 4756)
@@ -0,0 +1,38 @@
+/*
+    general.h - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LIB_SENSORS_GENERAL
+#define LIB_SENSORS_GENERAL
+
+/* These are general purpose functions. They allow you to use variable-
+   length arrays, which are extended automatically. A distinction is
+   made between the current number of elements and the maximum number.
+   You can only add elements at the end. Primitive, but very useful
+   for internal use. */
+void sensors_malloc_array(void *list, int *num_el, int *max_el,
+			  int el_size);
+void sensors_free_array(void *list, int *num_el, int *max_el);
+void sensors_add_array_el(const void *el, void *list, int *num_el,
+			  int *max_el, int el_size);
+void sensors_add_array_els(const void *els, int nr_els, void *list,
+			   int *num_el, int *max_el, int el_size);
+
+#define ARRAY_SIZE(arr)	(int)(sizeof(arr) / sizeof((arr)[0]))
+
+#endif /* LIB_SENSORS_GENERAL */
Index: /lm-sensors/tags/V3-0-0-RC2/lib/conf-parse.y
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/conf-parse.y	(revision 4793)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/conf-parse.y	(revision 4793)
@@ -0,0 +1,347 @@
+%{
+/*
+    conf-parse.y - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define YYERROR_VERBOSE
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "data.h"
+#include "general.h"
+#include "error.h"
+#include "conf.h"
+#include "access.h"
+#include "init.h"
+
+static void sensors_yyerror(const char *err);
+static sensors_expr *malloc_expr(void);
+
+static sensors_chip *current_chip = NULL;
+
+#define bus_add_el(el) sensors_add_array_el(el,\
+                                      &sensors_config_busses,\
+                                      &sensors_config_busses_count,\
+                                      &sensors_config_busses_max,\
+                                      sizeof(sensors_bus))
+#define label_add_el(el) sensors_add_array_el(el,\
+                                        &current_chip->labels,\
+                                        &current_chip->labels_count,\
+                                        &current_chip->labels_max,\
+                                        sizeof(sensors_label));
+#define set_add_el(el) sensors_add_array_el(el,\
+                                      &current_chip->sets,\
+                                      &current_chip->sets_count,\
+                                      &current_chip->sets_max,\
+                                      sizeof(sensors_set));
+#define compute_add_el(el) sensors_add_array_el(el,\
+                                          &current_chip->computes,\
+                                          &current_chip->computes_count,\
+                                          &current_chip->computes_max,\
+                                          sizeof(sensors_compute));
+#define ignore_add_el(el) sensors_add_array_el(el,\
+                                          &current_chip->ignores,\
+                                          &current_chip->ignores_count,\
+                                          &current_chip->ignores_max,\
+                                          sizeof(sensors_ignore));
+#define chip_add_el(el) sensors_add_array_el(el,\
+                                       &sensors_config_chips,\
+                                       &sensors_config_chips_count,\
+                                       &sensors_config_chips_max,\
+                                       sizeof(sensors_chip));
+
+#define fits_add_el(el,list) sensors_add_array_el(el,\
+                                                  &(list).fits,\
+                                                  &(list).fits_count,\
+                                                  &(list).fits_max, \
+		                                  sizeof(sensors_chip_name));
+
+%}
+
+%union {
+  double value;
+  char *name;
+  void *nothing;
+  sensors_chip_name_list chips;
+  sensors_expr *expr;
+  sensors_bus_id bus;
+  sensors_chip_name chip;
+  int line;
+}  
+
+%left <nothing> '-' '+'
+%left <nothing> '*' '/'
+%left <nothing> NEG
+%right <nothing> '^' '`'
+
+%token <nothing> ','
+%token <nothing> EOL
+%token <line> BUS
+%token <line> LABEL
+%token <line> SET
+%token <line> CHIP
+%token <line> COMPUTE
+%token <line> IGNORE
+%token <value> FLOAT
+%token <name> NAME
+%token <nothing> ERROR
+
+%type <chips> chip_name_list
+%type <expr> expression
+%type <bus> bus_id
+%type <name> adapter_name
+%type <name> function_name
+%type <name> string
+%type <chip> chip_name
+
+%start input
+
+%%
+
+input:	  /* empty */
+	| input line
+;
+
+line:	  bus_statement EOL
+	| label_statement EOL
+	| set_statement EOL
+	| chip_statement EOL
+	| compute_statement EOL
+	| ignore_statement EOL
+	| error	EOL
+;
+
+bus_statement:	  BUS bus_id adapter_name
+		  { sensors_bus new_el;
+		    new_el.lineno = $1;
+		    new_el.bus = $2;
+                    new_el.adapter = $3;
+		    bus_add_el(&new_el);
+		  }
+;
+
+label_statement:	  LABEL function_name string
+			  { sensors_label new_el;
+			    if (!current_chip) {
+			      sensors_yyerror("Label statement before first chip statement");
+			      free($2);
+			      free($3);
+			      YYERROR;
+			    }
+			    new_el.lineno = $1;
+			    new_el.name = $2;
+			    new_el.value = $3;
+			    label_add_el(&new_el);
+			  }
+;
+
+set_statement:	  SET function_name expression
+		  { sensors_set new_el;
+		    if (!current_chip) {
+		      sensors_yyerror("Set statement before first chip statement");
+		      free($2);
+		      free_expr($3);
+		      YYERROR;
+		    }
+		    new_el.lineno = $1;
+		    new_el.name = $2;
+		    new_el.value = $3;
+		    set_add_el(&new_el);
+		  }
+;
+
+compute_statement:	  COMPUTE function_name expression ',' expression
+			  { sensors_compute new_el;
+			    if (!current_chip) {
+			      sensors_yyerror("Compute statement before first chip statement");
+			      free($2);
+			      free_expr($3);
+			      free_expr($5);
+			      YYERROR;
+			    }
+			    new_el.lineno = $1;
+			    new_el.name = $2;
+			    new_el.from_proc = $3;
+			    new_el.to_proc = $5;
+			    compute_add_el(&new_el);
+			  }
+;
+
+ignore_statement:	IGNORE function_name
+			{ sensors_ignore new_el;
+			  if (!current_chip) {
+			    sensors_yyerror("Ignore statement before first chip statement");
+			    free($2);
+			    YYERROR;
+			  }
+			  new_el.lineno = $1;
+			  new_el.name = $2;
+			  ignore_add_el(&new_el);
+			}
+;
+
+chip_statement:	  CHIP chip_name_list
+		  { sensors_chip new_el;
+		    new_el.lineno = $1;
+		    new_el.labels = NULL;
+		    new_el.sets = NULL;
+		    new_el.computes = NULL;
+		    new_el.ignores = NULL;
+		    new_el.labels_count = new_el.labels_max = 0;
+		    new_el.sets_count = new_el.sets_max = 0;
+		    new_el.computes_count = new_el.computes_max = 0;
+		    new_el.ignores_count = new_el.ignores_max = 0;
+		    new_el.chips = $2;
+		    chip_add_el(&new_el);
+		    current_chip = sensors_config_chips + 
+		                   sensors_config_chips_count - 1;
+		  }
+;
+
+chip_name_list:	  chip_name
+		  { 
+		    $$.fits = NULL;
+		    $$.fits_count = $$.fits_max = 0;
+		    fits_add_el(&$1,$$);
+		  }
+		| chip_name_list chip_name
+		  { $$ = $1;
+		    fits_add_el(&$2,$$);
+		  }
+;
+	
+expression:	  FLOAT	
+		  { $$ = malloc_expr(); 
+		    $$->data.val = $1; 
+		    $$->kind = sensors_kind_val;
+		  }
+		| NAME
+		  { $$ = malloc_expr(); 
+		    $$->data.var = $1;
+		    $$->kind = sensors_kind_var;
+		  }
+		| '@'
+		  { $$ = malloc_expr();
+		    $$->kind = sensors_kind_source;
+		  }
+		| expression '+' expression
+		  { $$ = malloc_expr(); 
+		    $$->kind = sensors_kind_sub;
+		    $$->data.subexpr.op = sensors_add;
+		    $$->data.subexpr.sub1 = $1;
+		    $$->data.subexpr.sub2 = $3;
+		  }
+		| expression '-' expression
+		  { $$ = malloc_expr(); 
+		    $$->kind = sensors_kind_sub;
+		    $$->data.subexpr.op = sensors_sub;
+		    $$->data.subexpr.sub1 = $1;
+		    $$->data.subexpr.sub2 = $3;
+		  }
+		| expression '*' expression
+		  { $$ = malloc_expr(); 
+		    $$->kind = sensors_kind_sub;
+		    $$->data.subexpr.op = sensors_multiply;
+		    $$->data.subexpr.sub1 = $1;
+		    $$->data.subexpr.sub2 = $3;
+		  }
+		| expression '/' expression
+		  { $$ = malloc_expr(); 
+		    $$->kind = sensors_kind_sub;
+		    $$->data.subexpr.op = sensors_divide;
+		    $$->data.subexpr.sub1 = $1;
+		    $$->data.subexpr.sub2 = $3;
+		  }
+		| '-' expression  %prec NEG
+		  { $$ = malloc_expr(); 
+		    $$->kind = sensors_kind_sub;
+		    $$->data.subexpr.op = sensors_negate;
+		    $$->data.subexpr.sub1 = $2;
+		    $$->data.subexpr.sub2 = NULL;
+		  }
+		| '(' expression ')'
+		  { $$ = $2; }
+		| '^' expression
+		  { $$ = malloc_expr(); 
+		    $$->kind = sensors_kind_sub;
+		    $$->data.subexpr.op = sensors_exp;
+		    $$->data.subexpr.sub1 = $2;
+		    $$->data.subexpr.sub2 = NULL;
+		  }
+		| '`' expression
+		  { $$ = malloc_expr(); 
+		    $$->kind = sensors_kind_sub;
+		    $$->data.subexpr.op = sensors_log;
+		    $$->data.subexpr.sub1 = $2;
+		    $$->data.subexpr.sub2 = NULL;
+		  }
+;
+
+bus_id:		  NAME
+		  { int res = sensors_parse_bus_id($1,&$$);
+		    free($1);
+		    if (res) {
+                      sensors_yyerror("Parse error in bus id");
+		      YYERROR;
+                    }
+		  }
+;
+
+adapter_name:	  NAME
+		  { $$ = $1; }
+;
+
+function_name:	  NAME
+		  { $$ = $1; }
+;
+
+string:	  NAME
+	  { $$ = $1; }
+;
+
+chip_name:	  NAME
+		  { int res = sensors_parse_chip_name($1,&$$); 
+		    free($1);
+		    if (res) {
+		      sensors_yyerror("Parse error in chip name");
+		      YYERROR;
+		    }
+		  }
+;
+
+%%
+
+void sensors_yyerror(const char *err)
+{
+  if (sensors_lex_error[0]) {
+    sensors_parse_error(sensors_lex_error,sensors_yylineno);
+    sensors_lex_error[0] = '\0';
+  } else
+    sensors_parse_error(err,sensors_yylineno);
+}
+
+sensors_expr *malloc_expr(void)
+{
+  sensors_expr *res = malloc(sizeof(sensors_expr));
+  if (! res)
+    sensors_fatal_error("malloc_expr","Allocating a new expression");
+  return res;
+}
+  
Index: /lm-sensors/tags/V3-0-0-RC2/lib/conf-lex.l
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/conf-lex.l	(revision 4797)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/conf-lex.l	(revision 4797)
@@ -0,0 +1,353 @@
+%{
+/*
+    conf-lex.l - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "general.h"
+#include "data.h"
+#include "conf-parse.h"
+#include "error.h"
+#include "scanner.h"
+
+static int buffer_count;
+static int buffer_max;
+static char *buffer;
+
+char sensors_lex_error[100];
+
+int sensors_yylineno;
+
+#define buffer_malloc() sensors_malloc_array(&buffer,&buffer_count,\
+                                             &buffer_max,1)
+#define buffer_free() sensors_free_array(&buffer,&buffer_count,\
+                                         &buffer_max)
+#define buffer_add_char(c) sensors_add_array_el(c,&buffer,\
+                                                &buffer_count,\
+                                                &buffer_max,1)
+#define buffer_add_string(s) sensors_add_array_els(s,strlen(s),\
+                                                   &buffer, \
+                                                   &buffer_count,&buffer_max,1)
+
+%}
+
+ /* Scanner for configuration files */
+
+%option nodefault
+%option noyywrap
+%option nounput
+
+ /* All states are exclusive */
+
+%x MIDDLE
+%x STRING
+%x ERR
+
+ /* Any whitespace-like character */
+
+BLANK		[ \f\t\v]
+
+IDCHAR		[[:alnum:]_]
+
+ /* Note: `10', `10.4' and `.4' are valid, `10.' is not */
+
+FLOAT   [[:digit:]]*\.?[[:digit:]]+
+
+ /* Only positive whole numbers are recognized here */
+
+NUM	0|([1-9][[:digit:]]*)
+
+
+%%
+
+ /*
+  * STATE: INITIAL
+  */
+
+<INITIAL>{
+
+<<EOF>>		{ /* EOF from this state terminates */
+		  return 0;
+		}
+
+{BLANK}+	; /* eat as many blanks as possible at once */
+
+{BLANK}*\n	{ /* eat a bare newline (possibly preceded by blanks) */
+		  sensors_yylineno++;
+		}
+
+ /* comments */
+
+#.*		; /* eat the rest of the line after comment char */
+
+#.*\n		{ /* eat the rest of the line after comment char */
+		  sensors_yylineno++;
+		}
+
+ /*
+  * Keywords must be followed by whitespace - eat that too.
+  * If there isn't trailing whitespace, we still need to
+  * accept it as lexically correct (even though the parser
+  * will reject it anyway.)
+  */
+
+label{BLANK}*	{
+		  sensors_yylval.line = sensors_yylineno;
+		  BEGIN(MIDDLE);
+		  return LABEL;
+		}
+
+set{BLANK}*	{
+		  sensors_yylval.line = sensors_yylineno;
+		  BEGIN(MIDDLE);
+		  return SET;
+		}
+
+compute{BLANK}*	{
+		  sensors_yylval.line = sensors_yylineno;
+		  BEGIN(MIDDLE);
+		  return COMPUTE;
+		}
+
+bus{BLANK}*	{
+		  sensors_yylval.line = sensors_yylineno;
+		  BEGIN(MIDDLE);
+		  return BUS;
+		}
+
+chip{BLANK}*	{
+		  sensors_yylval.line = sensors_yylineno;
+		  BEGIN(MIDDLE);
+		  return CHIP;
+		}
+
+ignore{BLANK}*	{
+		  sensors_yylval.line = sensors_yylineno;
+		  BEGIN(MIDDLE);
+		  return IGNORE;
+		}
+
+ /* Anything else at the beginning of a line is an error */
+
+[a-z]+		|
+.		{
+		  BEGIN(ERR);
+		  strcpy(sensors_lex_error,"Invalid keyword");
+		  return ERROR;
+		}
+}
+
+ /*
+  * STATE: ERROR
+  */
+
+<ERR>{
+
+.*		; /* eat whatever is left on this line */
+
+\n		{
+		  BEGIN(INITIAL);
+		  sensors_yylineno++;
+		  return EOL;
+		}
+}
+
+ /*
+  * STATE: MIDDLE
+  */
+
+<MIDDLE>{
+
+{BLANK}+	; /* eat as many blanks as possible at once */
+
+\n		{ /* newline here sends EOL token to parser */
+		  BEGIN(INITIAL);
+		  sensors_yylineno++;
+		  return EOL;
+		}
+
+<<EOF>>		{ /* EOF here sends EOL token to parser also */
+		  BEGIN(INITIAL);
+		  return EOL;
+		}
+
+\\{BLANK}*\n	{ /* eat an escaped newline with no state change */
+		  sensors_yylineno++;
+		}
+
+ /* comments */
+
+#.*		; /* eat the rest of the line after comment char */
+
+#.*\n		{ /* eat the rest of the line after comment char */
+		  BEGIN(INITIAL);
+		  sensors_yylineno++;
+		  return EOL;
+		}
+
+ /* A number */
+
+{FLOAT}		{
+		  sensors_yylval.value = atof(sensors_yytext);
+		  return FLOAT;
+		}
+
+ /* Some operators */
+
+"+"		return '+';
+"-"		return '-';
+"*"		return '*';
+"/"		return '/';
+"("		return '(';
+")"		return ')';
+","		return ',';
+"@"		return '@';
+"^"		return '^';
+"`"		return '`';
+
+ /* Quoted string */
+
+\"		{
+		  buffer_malloc();
+		  BEGIN(STRING);
+		}
+
+ /* A normal, unquoted identifier */
+
+{IDCHAR}+	{
+		  sensors_yylval.name = strdup(sensors_yytext);
+		  if (! sensors_yylval.name)
+		    sensors_fatal_error("conf-lex.l",
+                                        "Allocating a new string");
+		  
+		  return NAME;
+		}
+
+ /* anything else is bogus */
+
+.		|
+[[:digit:]]*\.	|
+\\{BLANK}*	{
+		  BEGIN(ERR);
+		  return ERROR;
+		}
+}
+
+ /*
+  * STATE: STRING
+  */
+
+<STRING>{
+
+ /* Oops, newline or EOF while in a string is not good */
+
+\n		|
+\\\n		{
+		  buffer_add_char("\0");
+		  strcpy(sensors_lex_error,
+			"No matching double quote.");
+		  buffer_free();
+		  yyless(0);
+		  BEGIN(ERR);
+		  return ERROR;
+		}
+
+<<EOF>>		{
+		  strcpy(sensors_lex_error,
+			"Reached end-of-file without a matching double quote.");
+		  buffer_free();
+		  BEGIN(MIDDLE);
+		  return ERROR;
+		}
+
+ /* At the end */
+
+\"\"		{
+		  buffer_add_char("\0");
+		  strcpy(sensors_lex_error,
+			"Quoted strings must be separated by whitespace.");
+		  buffer_free();
+		  BEGIN(ERR);
+		  return ERROR;
+		}
+		
+\"		{
+		  buffer_add_char("\0");
+		  sensors_yylval.name = strdup(buffer);
+		  if (! sensors_yylval.name)
+		    sensors_fatal_error("conf-lex.l",
+                                        "Allocating a new string");
+		  buffer_free();
+		  BEGIN(MIDDLE);
+		  return NAME;
+		}
+
+\\a		buffer_add_char("\a");
+\\b		buffer_add_char("\b");
+\\f		buffer_add_char("\f");
+\\n		buffer_add_char("\n");
+\\r		buffer_add_char("\r");
+\\t		buffer_add_char("\t");
+\\v		buffer_add_char("\v");
+
+ /* Other escapes: just copy the character behind the slash */
+
+\\.		{
+		  buffer_add_char(&sensors_yytext[1]);
+		}
+
+ /* Anything else (including a bare '\' which may be followed by EOF) */
+
+\\		|
+[^\\\n\"]+	{
+		  buffer_add_string(sensors_yytext);
+		}
+}
+
+%%
+
+/*
+	Do the buffer handling manually.  This allows us to scan as many
+	config files as we need to, while cleaning up properly after each
+	one.  The "BEGIN(0)" line ensures that we start in the default state,
+	even if e.g. the previous config file was syntactically broken.
+
+	Returns 0 if successful, !0 otherwise.
+*/
+
+static YY_BUFFER_STATE scan_buf = (YY_BUFFER_STATE)0;
+
+int sensors_scanner_init(FILE *input)
+{
+	BEGIN(0);
+	if (!(scan_buf = sensors_yy_create_buffer(input, YY_BUF_SIZE)))
+		return -1;
+
+	sensors_yy_switch_to_buffer(scan_buf);
+	sensors_yylineno = 1;
+	return 0;
+}
+
+void sensors_scanner_exit(void)
+{
+	sensors_yy_delete_buffer(scan_buf);
+	scan_buf = (YY_BUFFER_STATE)0;
+}
+
Index: /lm-sensors/tags/V3-0-0-RC2/lib/error.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/error.c	(revision 4899)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/error.c	(revision 4899)
@@ -0,0 +1,66 @@
+/*
+    error.c - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "error.h"
+#include "general.h"
+
+static void sensors_default_parse_error(const char *err, int lineno);
+static void sensors_default_fatal_error(const char *proc, const char *err);
+
+void (*sensors_parse_error) (const char *err, int lineno) =
+						sensors_default_parse_error;
+void (*sensors_fatal_error) (const char *proc, const char *err) =
+						sensors_default_fatal_error;
+
+static const char *errorlist[] = {
+	/* Invalid error code    */ NULL,
+	/* SENSORS_ERR_WILDCARDS */ "Wildcard found in chip name",
+	/* SENSORS_ERR_NO_ENTRY  */ "No such subfeature known",
+	/* SENSORS_ERR_ACCESS_R  */ "Can't read",
+	/* SENSORS_ERR_KERNEL    */ "Kernel interface error",
+	/* SENSORS_ERR_DIV_ZERO  */ "Divide by zero",
+	/* SENSORS_ERR_CHIP_NAME */ "Can't parse chip name",
+	/* SENSORS_ERR_BUS_NAME  */ "Can't parse bus name",
+	/* SENSORS_ERR_PARSE     */ "General parse error",
+	/* SENSORS_ERR_ACCESS_W  */ "Can't write",
+	/* SENSORS_ERR_IO        */ "I/O error",
+};
+
+const char *sensors_strerror(int errnum)
+{
+	if (errnum < 0)
+		errnum = -errnum;
+	if (errnum >= ARRAY_SIZE(errorlist))
+		errnum = 0;
+	return errorlist[errnum];
+}
+
+void sensors_default_parse_error(const char *err, int lineno)
+{
+	fprintf(stderr, "Error: Line %d: %s\n", lineno, err);
+}
+
+void sensors_default_fatal_error(const char *proc, const char *err)
+{
+	fprintf(stderr, "Fatal error in `%s': %s\n", proc, err);
+	exit(1);
+}
Index: /lm-sensors/tags/V3-0-0-RC2/lib/conf.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/lib/conf.h	(revision 4736)
+++ /lm-sensors/tags/V3-0-0-RC2/lib/conf.h	(revision 4736)
@@ -0,0 +1,32 @@
+/*
+    conf.h - Part of libsensors, a Linux library for reading sensor data.
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LIB_SENSORS_CONF_H
+#define LIB_SENSORS_CONF_H
+
+/* This is defined in conf-lex.l */
+int sensors_yylex(void);
+extern char sensors_lex_error[];
+extern int sensors_yylineno;
+extern FILE *sensors_yyin;
+
+/* This is defined in conf-parse.y */
+int sensors_yyparse(void);
+
+#endif /* LIB_SENSORS_CONF_H */
Index: /lm-sensors/tags/V3-0-0-RC2/prog/hotplug/README.p4b
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/hotplug/README.p4b	(revision 4402)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/hotplug/README.p4b	(revision 4402)
@@ -0,0 +1,39 @@
+What is it?
+-----------
+
+It unhides the SMBus of Intel ICH southbridges hidden on Asus P4B series
+and some other Asus and non-Asus systems. It is implemented as a shell
+script for the 2.6 kernel: unhide_ICH_SMBus.
+
+It works with the following chips:
+ * ICH2   (82801BA)
+ * ICH2-M (82801BAM)
+ * ICH3   (82801CA)
+ * ICH3-M (82801CAM)
+ * ICH4   (82801DB)
+ * ICH4-M (82801DBM)
+ * ICH5   (82801EB)
+
+ASUS switches off the SMBus PCI Device in the i801 ICH chip. I spoke twice
+with the German support and learned that: "We do not want the users to be
+irritated by just another PCI Device in the Win98 device manager."
+Really funny :-).
+
+For 2.6 kernels, activation is normally handled by the code in
+drivers/pci/quirks.c in the kernel source. If you have the 2.6 kernel and
+the quirks code does not activate your SMBus, you may:
+
+ * first of all, read the paragraph "Hidden ICH SMBus" in
+   Documentation/i2c/busses/i2c-i801 in the kernel source.
+
+ * check if you have kernel version from 2.6.16 to 2.6.19
+   If so, you need to disable ACPI sleep support and recompile kernel. 
+   If you don't use suspend try below instead of recompilation.
+
+ * run as root the ./unhide_ICH_SMBus script. It will unhide the bus 
+   and load the i2c-i801 driver. Beware that you should then no longer
+   use system suspend as bad things might happen on resume.
+
+ * if above script works and you have latest kernel, you may 
+   try to fix the quirks.c, recompile and test your new kernel,
+   and then submit a patch to us. Contact us if you need assistance.
Index: /lm-sensors/tags/V3-0-0-RC2/prog/hotplug/unhide_ICH_SMBus
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/hotplug/unhide_ICH_SMBus	(revision 4294)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/hotplug/unhide_ICH_SMBus	(revision 4294)
@@ -0,0 +1,71 @@
+#!/bin/bash
+# (C) Rudolf Marek <r.marek@assembler.cz>,
+#     Jean Delvare <khali@linux-fr.org>
+#
+#    Thanks Jean Delvare and Oliver Dreier <oliver@dinux.de> for testing.
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License version 2
+#    as published by the Free Software Foundation
+#
+# Supports the following Intel ICH chipsets:
+#              PCI ID
+#   ICH2      8086:2440
+#   ICH2-M    8086:244C
+#   ICH3      8086:2480
+#   ICH3-M    8086:248C
+#   ICH4      8086:24C0
+#   ICH4-M    8086:24CC
+#   ICH5      8086:24D0
+
+pcibus="/sys/bus/pci/slots/"
+device="00:1f"
+
+if [ "$UID" -ne 0 ] ; then
+	echo "You need to be root to run this script!"
+	exit 252
+fi
+
+smbus=`lspci -n -s $device.3 | grep -i '0c05: *8086'`
+if [ -n "$smbus" ] ; then
+	echo "ICH SMBus is already there!"
+	lspci -s $device.3
+	exit
+fi
+
+intel=`lspci -n -s $device.0 | grep -i '8086:24[48CD][0C]'`
+if [ -z "$intel" ] ; then
+	echo "Not for your chipset - Intel (ICH) only"
+	echo "Supported: ICH2, ICH2-M, ICH3, ICH3-M, ICH4, ICH4-M, ICH5"
+	exit 255;
+fi
+modprobe fakephp &> /dev/null
+
+if [ ! -d "$pcibus" ] ; then
+	echo "You need the fake PCI hotplug driver! (fakephp.ko and 2.6 kernel)"
+	exit 255;
+fi
+
+echo "Enabling SMBus PCI device ..."
+
+newval=$( printf '%x' $((0x$(setpci -s $device.0 f2.w) & 0xfff7))) 
+setpci -s $device.0 f2.w=$newval
+
+echo "Rescanning the bus ..."
+echo 1 > $pcibus/0000:$device.0/power 2>/dev/null
+if [ ! -d "$pcibus/0000:$device.3" ] ; then
+	echo "Failed to enable the SMBUS"
+	exit 253;
+fi
+
+if [ ! -d "/sys/bus/pci/drivers/i801_smbus" ] ; then
+	echo "Loading i2c-i801 ..."
+	modprobe i2c-i801
+	if [ $? -ne 0 ] ; then
+		exit 251
+	fi
+fi
+
+lspci -s $device.3
+echo "Done!"
+echo "Remember: system suspend/resume is no longer safe to use."
Index: /lm-sensors/tags/V3-0-0-RC2/prog/daemon/healthd.sh
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/daemon/healthd.sh	(revision 229)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/daemon/healthd.sh	(revision 229)
@@ -0,0 +1,42 @@
+#!/bin/bash
+#
+# healthd -- 	This is a simple daemon which can be used to alert you in the
+#		event of a hardware health monitoring alarm by sending an 
+#		email to the value of ADMIN_EMAIL (defined below).
+#
+# To Use  --	Simply start the daemon from a shell (may be backgrounded)
+#
+# Other details -- Checks status every 15 seconds.  Sends warning emails every
+#		   ten minutes during alarm until the alarm is cleared.
+#		   It won't start up if there is a pending alarm on startup.
+#		   Very low loading on the machine (sleeps almost all the time).
+#		   This is just an example.  It works, but hopefully we can
+#		   get something better written. :')
+#
+# Requirements -- grep, mail, sensors, bash
+#		  (You may need to alter the PATH, but probably not.)
+#
+# Written & Copyrighten by Philip Edelbrock, 1999.
+#
+# Version: 1.0.0
+#
+
+PATH="/bin:/usr/bin:/usr/local/bin:${PATH}"
+
+ADMIN_EMAIL="root@localhost"
+
+if [ -n "`sensors | grep ALARM`" ]
+then
+        echo "Pending Alarms on start up!  Exiting!"
+        exit
+fi
+
+while true
+do
+ sleep 15
+ if [ -n "`sensors | grep ALARM`" ]
+ then
+        sensors | mail -s "**** Hardware Health Warning ****"  $ADMIN_EMAIL
+        sleep 600
+ fi
+done
Index: /lm-sensors/tags/V3-0-0-RC2/prog/init/sensord.init
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/init/sensord.init	(revision 2777)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/init/sensord.init	(revision 2777)
@@ -0,0 +1,157 @@
+#!@BASH@
+#
+# @INITRDDIR@/sensord
+#
+# sensord       This shell script takes care of starting and stopping
+#               sensord, the lm_sensors hardware health monitoring daemon.
+#
+# Here is the sensors service for SysV init, based on lm_sensors-2.5.5-sensors
+# from Mandrake lm_sensors source RPM. It is modified according to recommendations
+# for RedHat initscripts. The drivers starting part is taken from alsasound
+# service. To configure this service one should put appropriate "alias i2c-bus-0
+# xxx" and "alias i2c-sensors-chip-0 xxx" in /etc/modules.conf. The rest should be
+# self explaining.
+#
+# You put it into /etc/rc.d/init.d/, you make a symlink (probably using
+# chkconfig, ntsysv, tksysv or serviceconf program) named S95xxx and K05xxx
+# into /etc/rc#.d (where # is the number of runlevel), and sensors service
+# (which starts lm_sensors modules, runs sensors -s and starts sensord)
+# will be started automatically at startup/reboot and stopped at shutdown.
+# One could also start/stop service manually.
+#
+# This service was tested for RedHat 7.2 only.
+# Jakub Narêbski, Poland
+#
+
+# chkconfig: 2345 05 95
+# processname: sensord
+# config: @SYSCONFDIR@/sensors.conf
+# pidfile: /var/run/sensord.pid
+# description: Sensors is a sensors daemon which can be used to alert you \
+#              in the event of a hardware health monitoring alarm.
+
+# Source function library.
+. @INITRDDIR@/functions
+
+# Set default return value to 0 (success)
+RETVAL=0
+# Add @SBINDIR@ (sensord) and @BINDIR@ (sensors) to PATH if necessary
+echo "$PATH" | grep -q @SBINDIR@ || PATH=$PATH:@SBINDIR@
+echo "$PATH" | grep -q  @BINDIR@ || PATH=$PATH:@BINDIR@
+export PATH
+
+# Modules to load from modules.conf (modules configuration)
+i2c_bus_drivers=Žmodprobe -c | \
+  awk Ž/^[[:space:]]*alias[[:space:]]+i2c-bus-[[:digit:]]/ { print $3 }ŽŽ
+i2c_chip_drivers=Žmodprobe -c | \
+  awk Ž/^[[:space:]]*alias[[:space:]]+i2c-sensors-chip-[[:digit:]]/ { print $3
+}ŽŽ
+
+# Configuration of sensord
+interval=1m      # interval between scanning for sensor alarms
+log_interval=30m # interval between logging all sensor readings
+
+# Check that we use kernel for which lm_sensors-drivers was installed
+[ Žuname -rŽ = @MVERSION@ ] || exit 0
+
+# Check that lm_sensors is installed.
+[ -x @SBINDIR@/sensord ] || exit 0
+[ -x  @BINDIR@/sensors ] || exit 0
+
+echo_status()
+{
+        if [ $1 -eq 0 ]; then
+                echo_success
+        else
+                echo_failure
+        fi
+        echo
+}
+
+start()
+{
+        # Start modules
+        echo "Starting I2C bus (adapter) drivers: "
+        for driver in $i2c_bus_drivers; do
+                echo -n "Starting I2C driver: $driver "
+                /sbin/modprobe Žecho $driverŽ
+                echo_status $?
+        done
+        echo "Starting I2C chip (sensors) drivers: "
+        for driver in $i2c_chip_drivers; do
+                echo -n "Starting I2C driver: $driver "
+                /sbin/modprobe $(echo $driver)
+                echo_status $?
+        done
+        # Set Alarm
+        echo -n "Configuring sensors: "
+        sensors -s && sleep 2
+        echo_status $?
+        # Start daemons.
+        echo -n $"Starting sensord: "
+        daemon sensord -i $interval -l $log_interval
+        RETVAL=$?
+
+        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/sensord
+
+        echo
+        return $RETVAL
+}
+
+stop()
+{
+        # Stop daemons.
+        echo -n $"Shutting down sensord: "
+        killproc sensord
+        RETVAL=$?
+
+        echo
+        # Remove modules
+        drivers=Žecho "$i2c_chip_drivers $i2c_bus_drivers" | \
+          tr -s "[:space:]\n" " "Ž
+        echo -n "Removing I2C drivers: $drivers"
+        /sbin/modprobe -r -q $drivers
+        echo_status $?
+
+        echo
+        [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/sensord
+
+        return $RETVAL
+}
+
+reload()
+{
+        # Reread configuration file
+        sensors -s
+
+        return $?
+}
+
+# See how we were called.
+case "$1" in
+  start)
+        start
+        ;;
+  stop)
+        stop
+        ;;
+  status)
+        status sensord
+        ;;
+  restart)
+        stop
+        start
+        ;;
+  reload)
+        reload
+        ;;
+  condrestart)
+        [ -e /var/lock/subsys/sensord ] && restart || :
+        ;;
+  *)
+        echo "Usage: sensord {start|stop|restart|reload|condrestart|status}"
+        exit 1
+        ;;
+esac
+
+exit $?
Index: /lm-sensors/tags/V3-0-0-RC2/prog/init/lm_sensors.init.suse
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/init/lm_sensors.init.suse	(revision 4379)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/init/lm_sensors.init.suse	(revision 4379)
@@ -0,0 +1,174 @@
+#!/bin/sh
+#
+### BEGIN INIT INFO
+# Provides:			lm_sensors
+# Required-Start:		$local_fs 
+# X-UnitedLinux-Should-Start:	
+# Required-Stop:		$local_fs 
+# X-UnitedLinux-Should-Stop:	
+# Default-Start:		3 4 5
+# Default-Stop:			0 1 2 6
+# Short-Description:		LM Sensors
+# Description:			LM Sensors for hardware monitoring
+### END INIT INFO
+# chkconfig: 2345 26 74
+# description: sensors is used for monitoring motherboard sensor values.
+# config: /etc/sysconfig/lm_sensors
+#
+#    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# See also the lm_sensors homepage at:
+#     http://www.lm-sensors.org
+
+# It uses a config file /etc/sysconfig/lm_sensors that contains the modules
+# to be loaded/unloaded. That file is sourced into this one.
+
+# The format of that file a shell script that simply defines the modules 
+# in order as normal shell variables with the special names:
+#    MODULE_1, MODULE_2, MODULE_3, etc.
+
+# If sensors isn't supported by the kernel, try loading the module...
+[ -e /proc/sys/dev/sensors ] || /sbin/modprobe i2c-proc &>/dev/null
+
+# Don't bother if /proc/sensors still doesn't exist, kernel doesn't have
+# support for sensors.
+[ -e /proc/sys/dev/sensors ] || exit 0
+
+# If sensors was not already running, unload the module...
+[ -e /var/lock/subsys/lm_sensors ] || /sbin/modprobe -r i2c-proc &>/dev/null
+
+CONFIG=/etc/sysconfig/lm_sensors
+PSENSORS=/usr/local/bin/sensors
+
+# Source function library.
+#. /etc/init.d/functions
+
+# Shell functions sourced from /etc/rc.status:
+#      rc_check         check and set local and overall rc status
+#      rc_status        check and set local and overall rc status
+#      rc_status -v     ditto but be verbose in local rc status
+#      rc_status -v -r  ditto and clear the local rc status
+#      rc_status -s     display "skipped" and exit with status 3
+#      rc_status -u     display "unused" and exit with status 3
+#      rc_failed        set local and overall rc status to failed
+#      rc_failed <num>  set local and overall rc status to <num>
+#      rc_reset         clear local rc status (overall remains)
+#      rc_exit          exit appropriate to overall rc status
+#      rc_active	checks whether a service is activated by symlinks
+#      rc_splash arg    sets the boot splash screen to arg (if active)
+. /etc/rc.status
+
+# Reset status of this service
+rc_reset
+
+# Return values acc. to LSB for all commands but status:
+# 0	  - success
+# 1       - generic or unspecified error
+# 2       - invalid or excess argument(s)
+# 3       - unimplemented feature (e.g. "reload")
+# 4       - user had insufficient privileges
+# 5       - program is not installed
+# 6       - program is not configured
+# 7       - program is not running
+# 8--199  - reserved (8--99 LSB, 100--149 distrib, 150--199 appl)
+# 
+# Note that starting an already running service, stopping
+# or restarting a not-running service as well as the restart
+# with force-reload (in case signaling is not supported) are
+# considered a success.
+
+RETVAL=0
+
+start() {
+	echo -n $"Starting up sensors: "
+	test -r "$CONFIG" && . "$CONFIG"
+
+        modules=`grep \^MODULE_ $CONFIG | wc -l | tr -d ' '`
+        i=0
+        while [ $i -lt $modules ] ; do
+                module=`eval echo '$'MODULE_$i`
+		echo starting module __${module}__
+		/sbin/modprobe $module &>/dev/null
+		i=`expr $i + 1`
+	done
+        $PSENSORS -s
+
+	RETVAL=$?
+	if [ $RETVAL -eq 0 ] && touch /var/lock/subsys/lm_sensors ; then
+	    rc_status -v
+	else
+	    rc_status -v
+	fi
+}
+
+stop() {
+	echo -n $"Shutting down sensors: "
+	test -r "$CONFIG" && . "$CONFIG"
+
+        modules=`grep \^MODULE_ $CONFIG | wc -l | tr -d ' '`
+        i=`expr $modules`
+        while [ $i -ge 0 ] ; do
+                module=`eval echo '$'MODULE_$i`
+		/sbin/modprobe -r $module &>/dev/null
+		i=`expr $i - 1`
+	done
+	/sbin/modprobe -r i2c-proc &>/dev/null
+
+	RETVAL=$?
+	if [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/lm_sensors ; then
+	    rc_status -v
+	else
+	    rc_status -v
+	fi
+}
+
+dostatus() {
+        $PSENSORS
+	RETVAL=$?
+}
+
+restart() {
+	stop
+	start
+	RETVAL=$?
+}
+
+condrestart() {
+	[ -e /var/lock/subsys/lm_sensors ] && restart || :
+}
+
+# See how we were called.
+case "$1" in
+  start)
+	start
+	;;
+  stop)
+	stop
+	;;
+  status)
+	dostatus
+	;;
+  restart|reload)
+	restart
+	;;
+  condrestart)
+	condrestart
+	;;
+  *)
+	echo "Usage: sensors.init {start|stop|status|restart|reload|condrestart}"
+	exit 1
+esac
+
+exit $RETVAL
Index: /lm-sensors/tags/V3-0-0-RC2/prog/init/lm_sensors.init
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/init/lm_sensors.init	(revision 4379)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/init/lm_sensors.init	(revision 4379)
@@ -0,0 +1,153 @@
+#!/bin/sh
+#
+# chkconfig: 2345 26 74
+# description: sensors is used for monitoring motherboard sensor values.
+# config: /etc/sysconfig/lm_sensors
+#
+#    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# See also the lm_sensors homepage at:
+#     http://www.lm-sensors.org
+
+# It uses a config file /etc/sysconfig/lm_sensors that contains the modules
+# to be loaded/unloaded. That file is sourced into this one.
+
+# The format of that file a shell script that simply defines the modules 
+# in order as normal shell variables with the special names:
+#    MODULE_1, MODULE_2, MODULE_3, etc.
+
+if grep -q sysfs /proc/mounts; then
+	WITHSYS=1
+else
+	WITHSYS=0
+fi
+
+if [ $WITHSYS == "0" ]; then
+	# If sensors isn't supported by the kernel, try loading the module...
+	[ -e /proc/sys/dev/sensors ] || /sbin/modprobe i2c-proc >/dev/null 2>&1
+
+	# Don't bother if /proc/sensors still doesn't exist, kernel doesn't have
+	# support for sensors.
+	[ -e /proc/sys/dev/sensors ] || exit 0
+
+	# If sensors was not already running, unload the module...
+	[ -e /var/lock/subsys/lm_sensors ] || /sbin/modprobe -r i2c-proc >/dev/null 2>&1
+fi
+
+CONFIG=/etc/sysconfig/lm_sensors
+[ -r "$CONFIG" ] || exit 0
+grep '^MODULE_' $CONFIG >/dev/null 2>&1 || exit 0
+
+# Load config file
+. "$CONFIG"
+
+PSENSORS=/usr/local/bin/sensors
+
+if [ ! -x $PSENSORS ]; then
+	PSENSORS=/usr/bin/sensors
+fi
+
+# Source function library.
+. /etc/init.d/functions
+
+RETVAL=0
+prog="lm_sensors"
+
+start() {
+	echo -n "Starting $prog: loading module "
+
+	modules=`grep \^MODULE_ $CONFIG | wc -l | tr -d ' '`
+	i=0
+	while [ $i -lt $modules ] ; do
+		module=`eval echo '$'MODULE_$i`
+		echo -n "${module} "
+		/sbin/modprobe $module >/dev/null 2>&1
+		i=`expr $i + 1`
+	done
+	$PSENSORS -s
+
+	RETVAL=$?
+	if [ $RETVAL -eq 0 ] && touch /var/lock/subsys/lm_sensors ; then
+		echo_success
+		echo
+	else
+		echo_failure
+		echo
+	fi
+}
+
+stop() {
+	echo -n "Stopping $prog: "
+
+	modules=`grep \^MODULE_ $CONFIG | wc -l | tr -d ' '`
+	i=`expr $modules`
+	while [ $i -ge 0 ] ; do
+		module=`eval echo '$'MODULE_$i`
+		/sbin/modprobe -r $module >/dev/null 2>&1
+		i=`expr $i - 1`
+	done
+
+	if [ $WITHSYS == "0" ]; then
+		/sbin/modprobe -r i2c-proc >/dev/null 2>&1
+	fi
+
+	RETVAL=$?
+	if [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/lm_sensors ; then
+		echo_success
+		echo
+	else
+		echo_failure
+		echo
+	fi
+}
+
+dostatus() {
+	$PSENSORS
+	RETVAL=$?
+}
+
+restart() {
+	stop
+	start
+	RETVAL=$?
+}
+
+condrestart() {
+	[ -e /var/lock/subsys/lm_sensors ] && restart || :
+}
+
+# See how we were called.
+case "$1" in
+  start)
+	start
+	;;
+  stop)
+	stop
+	;;
+  status)
+	dostatus
+	;;
+  restart|reload)
+	restart
+	;;
+  condrestart)
+	condrestart
+	;;
+  *)
+	echo "Usage: $0 {start|stop|status|restart|reload|condrestart}"
+	exit 1
+esac
+
+exit $RETVAL
Index: /lm-sensors/tags/V3-0-0-RC2/prog/init/fancontrol.init
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/init/fancontrol.init	(revision 2607)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/init/fancontrol.init	(revision 2607)
@@ -0,0 +1,101 @@
+#!/bin/sh
+#
+# $Id$
+#
+# fancontrol
+#
+# chkconfig: 2345 90 01
+# description: start/stop fancontrol
+# pidfile: /var/run/fancontrol.pid
+#
+
+PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+export PATH
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+FANCONTROL="/usr/local/sbin/fancontrol"
+PIDFILE="/var/run/fancontrol.pid"
+
+RETVAL=0
+
+start()
+{
+   echo -n "Starting fancontrol daemon"
+   daemon $FANCONTROL -d
+   RETVAL=$?
+   [ $RETVAL -eq 0 ] && touch /var/lock/subsys/fancontrol
+   echo
+}
+
+stop()
+{
+   echo -n "Stopping fancontrol daemon"
+   killproc $FANCONTROL
+   RETVAL=$?
+   rm -f $PIDFILE
+   rm -f /var/lock/subsys/fancontrol
+   echo
+}
+
+status()
+{
+   if [ -f $PIDFILE ] ; then
+     pid=`cat $PIDFILE`
+   else
+     echo -n "$FANCONTROL does not appear to be running"
+     echo
+     exit
+   fi
+
+   if [ -n "$pid" ] ; then
+     ps -p $pid > /dev/null
+     if [ $? ] ; then
+       echo -n "$FANCONTROL appears to be running"
+     else
+       echo -n "$FANCONTROL does not appear to be running"
+     fi
+     echo
+   fi
+}
+
+condrestart()
+{
+   [ -e /var/lock/subsys/fancontrol ] && restart || :
+}
+
+if [ ! -x $FANCONTROL ] ; then
+   echo "Cannot run $FANCONTROL"
+   exit 0
+fi
+
+case "$1" in
+   start)
+     start
+     ;;
+
+   stop)
+     stop
+     ;;
+
+   status)
+     status
+     ;;
+
+   restart)
+     stop
+     start
+     ;;
+
+   condrestart)
+     condrestart
+     ;;
+
+   *)
+     echo "Usage: /etc/init.d/fancontrol 
+{start|stop|status|restart|condrestart}"
+     RETVAL=1
+esac
+
+exit $RETVAL
Index: /lm-sensors/tags/V3-0-0-RC2/prog/init/README
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/init/README	(revision 4379)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/init/README	(revision 4379)
@@ -0,0 +1,37 @@
+This directory contains files useful for initialization
+scripts, especially for RedHat and SuSE.
+
+There are two choices, lm_sensors.init and sensord.init.
+Use one or the other but not both!
+
+----------------
+
+The script lm_sensors.init is a nice startup/shutdown script.
+On RH and other RH-based systems (MDK, notably) use this sort of startup
+mechanism (i.e. SVR4-based), as opposed to the everything-in-one-script
+(/etc/rc or /etc/rc.local) like the BSD-based systems do.
+The lm_sensors.init file should be copied to /etc/rc.d/init.d/lm_sensors.
+For more information see the top of the file.
+It requires the /etc/sysconfig/lm_sensors file, which identifies
+the correct modules.
+
+The /etc/sysconfig/lm_sensors file is generated by running sensors-detect.
+Once the script is done detecting the hardware monitoring devices, it will
+list all the required modules in that file, so that they can be loaded
+automatically at boot time.
+
+SuSE users will want to use lm_sensors.init.suse instead, which is
+more specifically designed for this distribution. Changes were contributed
+by Marc Rieffel <marc@paracel.com>.
+
+----------------
+
+The script sensord.init also loads the modules, and then
+starts the sensord daemon. See the directory ../sensord for
+more information on the daemon.
+
+The sensord.init file should be copied to /etc/rc.d/init.d/sensord.
+For more information see the top of the file.
+
+To configure this service one should put appropriate "alias i2c-bus-0 xxx"
+and "alias i2c-sensors-chip-0 xxx" in /etc/modules.conf.
Index: /lm-sensors/tags/V3-0-0-RC2/prog/pwm/pwmconfig.8
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/pwm/pwmconfig.8	(revision 4699)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/pwm/pwmconfig.8	(revision 4699)
@@ -0,0 +1,30 @@
+.TH PWMCONFIG 8 "January 27, 2005" "lm-sensors 3"
+.SH NAME
+pwmconfig \- tests the PWM outputs of sensors and configures fancontrol
+
+.SH SYNOPSIS
+.B pwmconfig
+
+.SH DESCRIPTION
+.B pwmconfig
+searches your sensors for pulse width modulation (PWM)
+controls, and test each one to see if it controls a fan on
+your motherboard. Note that many motherboards do not have PWM
+circuitry installed, even if your sensor chip supports PWM.
+
+It attempts to briefly stop each fan using the PWM controls. It then
+attempts to restore each fan to full speed after testing. However, it
+is \fBvery important\fP that you physically verify that the fans have 
+been returned to full speed after the program has completed.
+
+.SH WARNING
+This program will stop your fans, one at a time, for approximately 5 seconds each.
+This may cause your processor temperature to rise. Verify that all fans are running 
+at normal speed after this program has exited.
+
+.SH SEE ALSO
+fancontrol(8), sensors(1).
+
+.SH AUTHOR
+.PP
+Marius Reiner <marius.reiner@hdev.de>
Index: /lm-sensors/tags/V3-0-0-RC2/prog/pwm/fancontrol
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/pwm/fancontrol	(revision 4591)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/pwm/fancontrol	(revision 4591)
@@ -0,0 +1,373 @@
+#!/bin/bash
+#
+# Simple script implementing a temperature dependent fan speed control
+#
+# Version 0.66
+#
+# Usage: fancontrol [CONFIGFILE]
+#
+# Dependencies:
+#   bash, egrep, sed, cut, sleep, lm_sensors :)
+#
+# Please send any questions, comments or success stories to
+# marius.reiner@hdev.de
+# Thanks!
+#
+# The latest version of this script is available at:
+# http://www.hdev.de/fancontrol/fancontrol.html
+# or in the SVN version of lm_sensors
+#
+# For configuration instructions and warnings please see fancontrol.txt, which
+# can be found in the doc/ directory or at the website mentioned above.
+#
+#
+#    Copyright 2003 Marius Reiner <marius.reiner@hdev.de>
+#    Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#
+
+#DEBUG=1
+MAX=255
+
+echo $$ > /var/run/fancontrol.pid
+
+declare -i pwmval
+
+function LoadConfig {
+	echo "Loading configuration from $1 ..."
+	# grep configuration from file
+	INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL=//g'`
+	FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS=//g'`
+	MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP=//g'`
+	MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP=//g'`
+	MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART=//g'`
+	MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP=//g'`
+	# optional settings:
+	FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS=//g'`
+	MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM=//g'`
+	MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM=//g'`
+	
+	# Check whether all mandatory settings are set
+	if [[ -z ${INTERVAL} || -z ${FCTEMPS} || -z ${MINTEMP} || -z ${MAXTEMP} || -z ${MINSTART} || -z ${MINSTOP} ]]
+	then
+		echo "Some mandatory settings missing, please check your config file!"
+		exit 1
+	fi
+	if [ "$INTERVAL" -le 0 ]
+	then
+		echo "Error in configuration file:"
+		echo "INTERVAL must be at least 1"
+		exit 1
+	fi
+
+	# write settings to arrays for easier use and print them
+        echo
+	echo "Common settings:"
+	echo "  INTERVAL=$INTERVAL"
+						
+	let fcvcount=0
+	for fcv in $FCTEMPS
+	do
+		AFCPWM[$fcvcount]=`echo $fcv |cut -d'=' -f1`
+		AFCTEMP[$fcvcount]=`echo $fcv |cut -d'=' -f2`
+		AFCFAN[$fcvcount]=`echo $FCFANS |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
+		AFCMINTEMP[$fcvcount]=`echo $MINTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
+		AFCMAXTEMP[$fcvcount]=`echo $MAXTEMP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
+		AFCMINSTART[$fcvcount]=`echo $MINSTART |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
+		AFCMINSTOP[$fcvcount]=`echo $MINSTOP |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
+		AFCMINPWM[$fcvcount]=`echo $MINPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
+		[ -z "${AFCMINPWM[$fcvcount]}" ] && AFCMINPWM[$fcvcount]=0
+		AFCMAXPWM[$fcvcount]=`echo $MAXPWM |sed -e 's/ /\n/g' |egrep "${AFCPWM[$fcvcount]}" |cut -d'=' -f2`
+		[ -z "${AFCMAXPWM[$fcvcount]}" ] && AFCMAXPWM[$fcvcount]=255
+
+		# verify the validity of the settings
+		if [ "${AFCMINTEMP[$fcvcount]}" -ge "${AFCMAXTEMP[$fcvcount]}" ]
+		then
+			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+			echo "MINTEMP must be less than MAXTEMP"
+			exit 1
+		fi
+		if [ "${AFCMAXPWM[$fcvcount]}" -gt 255 ]
+		then
+			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+			echo "MAXPWM must be at most 255"
+			exit 1
+		fi
+		if [ "${AFCMINSTOP[$fcvcount]}" -ge "${AFCMAXPWM[$fcvcount]}" ]
+		then
+			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+			echo "MINSTOP must be less than MAXPWM"
+			exit 1
+		fi
+		if [ "${AFCMINSTOP[$fcvcount]}" -lt "${AFCMINPWM[$fcvcount]}" ]
+		then
+			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+			echo "MINSTOP must be greater than or equal to MINPWM"
+			exit 1
+		fi
+		if [ "${AFCMINPWM[$fcvcount]}" -lt 0 ]
+		then
+			echo "Error in configuration file (${AFCPWM[$fcvcount]}):"
+			echo "MINPWM must be at least 0"
+			exit 1
+		fi
+
+		echo
+		echo "Settings for ${AFCPWM[$fcvcount]}:"
+		echo "  Depends on ${AFCTEMP[$fcvcount]}"
+		echo "  Controls ${AFCFAN[$fcvcount]}"
+		echo "  MINTEMP=${AFCMINTEMP[$fcvcount]}"
+		echo "  MAXTEMP=${AFCMAXTEMP[$fcvcount]}"
+		echo "  MINSTART=${AFCMINSTART[$fcvcount]}"
+		echo "  MINSTOP=${AFCMINSTOP[$fcvcount]}"
+		echo "  MINPWM=${AFCMINPWM[$fcvcount]}"
+		echo "  MAXPWM=${AFCMAXPWM[$fcvcount]}"
+		let fcvcount=fcvcount+1
+	done
+	echo
+}
+
+if [ -f "$1" ]
+then 
+	LoadConfig $1
+else
+	LoadConfig /etc/fancontrol
+fi
+
+DIR=/proc/sys/dev/sensors
+if [ ! -d $DIR ]
+then
+	# For Linux 2.6, detect if config file uses the hwmon class or not yet
+	if echo "${AFCPWM[0]}" | egrep -q '^hwmon[0-9]'
+	then
+		SDIR=/sys/class/hwmon
+	else
+		SDIR=/sys/bus/i2c/devices
+	fi
+
+	if [ ! -d $SDIR ]
+	then
+		echo $0: 'No sensors found! (did you load the necessary modules?)'
+		exit 1
+	else
+		SYSFS=1
+		DIR=$SDIR
+	fi	
+fi
+cd $DIR
+
+# $1 = pwm file name
+function pwmdisable()
+{
+	if [ -n "$SYSFS" ]
+	then
+		ENABLE=${1}_enable
+		# No enable file? Just set to max
+		if [ ! -f $ENABLE ]
+		then
+			echo $MAX > $1
+			return 0
+		fi
+
+		# Try pwmN_enable=0
+		echo 0 > $ENABLE 2> /dev/null
+		if [ `cat $ENABLE` -eq 0 ]
+		then
+			# Success
+			return 0
+		fi
+
+		# It didn't work, try pwmN_enable=1 pwmN=255
+		echo 1 > $ENABLE 2> /dev/null
+		echo $MAX > $1
+		if [ `cat $ENABLE` -eq 1 -a `cat $1` -ge 190 ]
+		then
+			# Success
+			return 0
+		fi
+
+		# Nothing worked
+		echo "$ENABLE stuck to" `cat $ENABLE` >&2
+		return 1
+	else
+		echo $MAX 0 > $1
+	fi
+}
+
+# $1 = pwm file name
+function pwmenable()
+{
+	if [ "$SYSFS" = "1" ]
+	then
+		ENABLE=${1}_enable
+		if [ -f $ENABLE ]
+		then
+			echo 1 > $ENABLE 2> /dev/null
+			if [ $? -ne 0 ]
+			then
+				return 1
+			fi
+		fi
+		echo $MAX > $1
+	else
+		echo $MAX 1 > $1
+	fi
+}
+
+function restorefans()
+{
+	local status=$1
+	echo 'Aborting, restoring fans...'
+	let fcvcount=0
+	while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
+	do
+		pwmo=${AFCPWM[$fcvcount]}
+		pwmdisable $pwmo
+		let fcvcount=$fcvcount+1
+	done
+	echo 'Verify fans have returned to full speed'
+	exit $status
+}
+
+trap 'restorefans 0' SIGQUIT SIGTERM
+trap 'restorefans 1' SIGHUP SIGINT
+
+# main function
+function UpdateFanSpeeds {
+	let fcvcount=0
+	while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
+	do
+		#hopefully shorter vars will improve readability:
+		pwmo=${AFCPWM[$fcvcount]}
+		tsens=${AFCTEMP[$fcvcount]}
+		fan=${AFCFAN[$fcvcount]}
+		mint=${AFCMINTEMP[$fcvcount]}
+		maxt=${AFCMAXTEMP[$fcvcount]}
+		minsa=${AFCMINSTART[$fcvcount]}
+		minso=${AFCMINSTOP[$fcvcount]}
+		minpwm=${AFCMINPWM[$fcvcount]}
+		maxpwm=${AFCMAXPWM[$fcvcount]}
+		
+		read tval < ${tsens}
+		if [ $? -ne 0 ]
+		then
+			echo "Error reading temperature from $DIR/$tsens"
+			restorefans 1
+		fi
+		if [ "$SYSFS" = "1" ]
+		then
+			let tval="($tval+500)/1000"
+		else
+			tval=`echo ${tval} | cut -d' ' -f3 | cut -d'.' -f1`
+		fi
+
+		read pwmpval < ${pwmo}
+		if [ $? -ne 0 ]
+		then
+			echo "Error reading PWM value from $DIR/$pwmo"
+			restorefans 1
+		fi
+		if [ "$SYSFS" != "1" ]
+		then
+			pwmpval=`echo ${pwmpval} | cut -d' ' -f1`
+		fi
+		
+		# If fanspeed-sensor output shall be used, do it
+		if [[ -n ${fan} ]]
+		then
+			read fanval < ${fan}
+			if [ $? -ne 0 ]
+			then
+				echo "Error reading Fan value from $DIR/$fan"
+				restorefans 1
+			fi
+			if [ "$SYSFS" != "1" ]
+			then
+				fanval=`echo ${fanval} | cut -d' ' -f2`
+			fi
+		else
+			fanval=1  # set it to a non zero value, so the rest of the script still works
+		fi
+		
+		# debug info
+		if [ "$DEBUG" != "" ]
+		then
+			echo "pwmo=$pwmo"
+			echo "tsens=$tsens"
+			echo "fan=$fan"
+			echo "mint=$mint"
+			echo "maxt=$maxt"
+			echo "minsa=$minsa"
+			echo "minso=$minso"
+			echo "minpwm=$minpwm"
+			echo "maxpwm=$maxpwm"
+			echo "tval=$tval"
+			echo "pwmpval=$pwmpval"
+			echo "fanval=$fanval"
+		fi
+		
+		if (( $tval <= $mint ))
+		  then pwmval=$minpwm # below min temp, use defined min pwm
+		elif (( $tval >= $maxt ))
+		  then pwmval=$maxpwm # over max temp, use defined max pwm
+		else 
+		  # calculate the new value from temperature and settings
+		  pwmval="(${tval}-${mint})*(${maxpwm}-${minso})/(${maxt}-${mint})+${minso}"
+		  if [ $pwmpval -eq 0 -o $fanval -eq 0 ]
+		  then # if fan was stopped start it using a safe value
+		  	echo $minsa > $pwmo
+			# Sleep while still handling signals
+			read < <(exec sleep 1)
+		  fi
+		fi
+		echo $pwmval > $pwmo # write new value to pwm output
+		if [ $? -ne 0 ]
+		then
+			echo "Error writing PWM value to $DIR/$pwmo"
+			restorefans 1
+		fi
+		if [ "$DEBUG" != "" ]
+		then
+			echo "new pwmval=$pwmval"
+		fi
+		let fcvcount=$fcvcount+1
+	done
+}
+
+echo 'Enabling PWM on fans...'
+let fcvcount=0
+while (( $fcvcount < ${#AFCPWM[@]} )) # go through all pwm outputs
+do
+	pwmo=${AFCPWM[$fcvcount]}
+	pwmenable $pwmo
+	if [ $? -ne 0 ]
+	then
+		echo "Error enabling PWM on $DIR/$pwmo"
+		restorefans 1
+	fi
+	let fcvcount=$fcvcount+1
+done
+
+echo 'Starting automatic fan control...'
+
+# main loop calling the main function at specified intervals
+while true
+do
+	UpdateFanSpeeds
+	# Sleep while still handling signals
+	read < <(exec sleep $INTERVAL)
+done
Index: /lm-sensors/tags/V3-0-0-RC2/prog/pwm/pwmconfig
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/pwm/pwmconfig	(revision 4900)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/pwm/pwmconfig	(revision 4900)
@@ -0,0 +1,751 @@
+#!/bin/bash
+#
+# pwmconfig v0.8
+# Tests the pwm outputs of sensors and configures fancontrol
+#
+#    Warning!!! This program will stop your fans, one at a time,
+#    for approximately 5 seconds each!!!
+#    This may cause your processor temperature to rise!!!
+#    Verify that all fans are running at normal speed after this
+#    program has exited!!!
+#
+#    Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#
+echo 'This program will search your sensors for pulse width modulation (pwm)'
+echo 'controls, and test each one to see if it controls a fan on'
+echo 'your motherboard. Note that many motherboards do not have pwm'
+echo 'circuitry installed, even if your sensor chip supports pwm.'
+echo
+echo 'We will attempt to briefly stop each fan using the pwm controls.'
+echo 'The program will attempt to restore each fan to full speed'
+echo 'after testing. However, it is ** very important ** that you'
+echo 'physically verify that the fans have been to full speed'
+echo 'after the program has completed.'
+echo
+
+DELAY=5 # 3 seconds delay is too short for large fans, thus I increased it to 5
+MAX=255
+
+DIR=/proc/sys/dev/sensors
+if [ ! -d $DIR ]
+then
+	if [ -d "/sys/class/hwmon" ]
+	then
+		SYSFS=2
+		DIR="/sys/class/hwmon"
+	elif [ -d "/sys/bus/i2c/devices" ]
+	then
+		SYSFS=1
+		DIR="/sys/bus/i2c/devices"
+	else
+		echo $0: 'No sensors found! (modprobe sensor modules?)'
+		exit 1
+	fi	
+fi
+
+cd $DIR
+if [ "$SYSFS" = "2" ]
+then
+	PREFIX='hwmon*/device'
+else
+	PREFIX='*-*'
+fi
+DEVICES=`echo $PREFIX`
+if [ "$PREFIX" = "$DEVICES" ]
+then
+	echo $0: 'No sensors found! (modprobe sensor modules?)'
+	exit 1
+fi
+
+MATCH=$PREFIX/'pwm[1-9]'
+PWM=`echo $MATCH`
+if [ "$SYSFS" = "1" -a "$MATCH" = "$PWM" ]
+then
+	# Deprecated naming scheme (used in kernels 2.6.5 to 2.6.9)
+	MATCH=$PREFIX/'fan[1-9]_pwm'
+	PWM=`echo $MATCH`
+fi
+if [ "$MATCH" = "$PWM" ]
+then
+	echo $0: 'There are no pwm-capable sensor modules installed'
+	exit 1
+fi
+
+if [ -n "$SYSFS" ]
+then
+	MATCH=$PREFIX/'fan[1-9]_input'
+else
+	MATCH=$PREFIX/'fan[1-9]'
+fi
+FAN=`echo $MATCH`
+if [ "$MATCH" = "$FAN" ]
+then
+	echo $0: 'There are no fan-capable sensor modules installed'
+	exit 1
+fi
+
+# $1 = padding
+# Only works with Linux 2.6
+function print_devices()
+{
+	for device in $DEVICES
+	do
+		echo "$1$device is `cat $device/name`"
+	done
+}
+
+# $1 = pwm file name
+function pwmdisable()
+{
+	if [ -n "$SYSFS" ]
+	then
+		ENABLE=${1}_enable
+		# No enable file? Just set to max
+		if [ ! -f $ENABLE ]
+		then
+			echo $MAX > $1
+			return 0
+		fi
+
+		# Try pwmN_enable=0
+		echo 0 > $ENABLE 2> /dev/null
+		if [ "`cat $ENABLE`" -eq 0 ]
+		then
+			# Success
+			return 0
+		fi
+
+		# It didn't work, try pwmN_enable=1 pwmN=255
+		echo 1 > $ENABLE 2> /dev/null
+		echo $MAX > $1
+		if [ "`cat $ENABLE`" -eq 1 -a "`cat $1`" -ge 190 ]
+		then
+			# Success
+			return 0
+		fi
+
+		# Nothing worked
+		echo "$ENABLE stuck to `cat $ENABLE`" >&2
+		return 1
+	else
+		echo $MAX 0 > $1
+	fi
+}
+
+# $1 = pwm file name
+function pwmenable()
+{
+	if [ -n "$SYSFS" ]
+	then
+		ENABLE=${1}_enable
+		if [ -w $ENABLE ]
+		then
+			echo 1 > $ENABLE 2> /dev/null
+			if [ $? -ne 0 ]
+			then
+				return 1
+			fi
+		fi
+		echo $MAX > $1
+	else
+		echo $MAX 1 > $1
+	fi
+}
+
+# $1 = pwm file name; $2 = pwm value 0-255
+function pwmset()
+{
+	echo $2 > $1
+}
+
+if [ -n "$SYSFS" ]
+then
+	echo 'Found the following devices:'
+	print_devices "   "
+	echo
+fi
+
+echo 'Found the following PWM controls:'
+for i in $PWM
+do
+	echo "   $i"
+	if [ -w $i ]
+	then
+		pwmdisable $i
+		if [ $? -ne 0 ]
+		then
+			echo "Failed to set $i to full speed" >&2
+			echo "Something's wrong, check your fans!" >&2
+			exit 1
+		fi
+	else
+		NOTROOT=1
+	fi
+done
+
+echo
+echo 'Found the following fan sensors:'
+for i in $FAN
+do
+	# this will return the first field if there's only one (sysfs)
+	S=`cat $i | cut -d' ' -f2`
+	if [ "$S" = "0" -o "$S" = "-1" ]
+	then
+		echo "   $i     current speed: 0 ... skipping!"
+	else
+		echo "   $i     current speed: $S RPM"
+		if [ "$GOODFAN" = "" ]
+		then
+			GOODFAN=$i
+			SPEEDS=$S
+		else
+			GOODFAN="$GOODFAN $i"
+			SPEEDS="$SPEEDS $S"
+		fi
+	fi
+done
+echo
+
+if [ "$GOODFAN" = "" ]
+then
+	echo 'There are no working fan sensors, all readings are 0.'
+	echo 'Make sure you have a 3-wire fan connected.'
+	echo 'You may also need to increase the fan divisors.'
+	echo 'See doc/fan-divisors for more information.'
+	exit 1
+fi
+
+if [ "$NOTROOT" = "1" ]
+then
+	echo 'As you are not root, we cannot write the PWM settings.'
+	echo 'Please run as root to continue.'
+	exit 1
+fi
+
+echo 'Warning!!! This program will stop your fans, one at a time,'
+echo "for approximately $DELAY seconds each!!!"
+echo 'This may cause your processor temperature to rise!!!'
+echo 'If you do not want to do this hit control-C now!!!'
+echo -n 'Hit return to continue: '
+read X
+echo
+
+PLOTTER=gnuplot
+STEP=15
+PDELAY=2
+# Use a smaller step for low PWM values as this is typically where the
+# more important fan speed changes are happening.
+STEP2=2
+STEP2_BELOW=31
+
+function pwmdetail()
+{
+	P=$1
+	F=$2
+	PLOT=
+
+	type $PLOTTER > /dev/null 2>&1
+	if [ $? -eq 0 ]
+	then
+		echo -n "Would you like to generate a graphical plot using $PLOTTER (y)? "
+		read X
+		if [ "$X" = "y" -o "$X" = "Y" -o "$X" = "" ]
+		then
+			PLOT=y  	
+		fi
+	fi
+
+	if [ "$PLOT" = "y" ]
+	then
+		TMP1=`mktemp -t pwmtest1.XXXXXXXXXX` || { echo "$0: Cannot create temporary file" >&2; exit 1; }
+		TMP2=`mktemp -t pwmtest2.XXXXXXXXXX` || { rm -f $TMP1 ; echo "$0: Cannot create temporary file" >&2; exit 1; }
+		echo "set xlabel \"PWM: $P\"" > $TMP1
+		echo "set ylabel \"FAN: $F (RPM)\"" >> $TMP1
+		echo 'set nokey' >> $TMP1
+		echo 'set xrange [0:255]' >> $TMP1
+		echo "plot \"$TMP2\" with lines" >> $TMP1
+		echo 'pause -1 "    Hit return to continue..."' >> $TMP1
+		> $TMP2
+	fi
+
+	let pwm=$MAX
+	pwmenable $P
+	while [ $pwm -ge 0 ]
+	do
+		pwmset $P $pwm  
+		sleep $PDELAY
+		if [ $? -ne 0 ]
+		then
+			pwmdisable $P	
+			echo '^C received, aborting...'
+			rm -f $TMP1 $TMP2
+			exit 1
+		fi		
+		# this will return the first field if there's only one (sysfs)
+		S=`cat $F | cut -d' ' -f2`
+		echo "    PWM $pwm FAN $S"
+		if [ "$PLOT" = "y" ]
+		then
+			echo "$pwm $S" >> $TMP2
+		fi
+		if [ "$S" = "0" -o "$S" = "-1" ]
+		then
+			pwmdisable $P	
+			echo "    Fan Stopped at PWM = $pwm"
+			if [ $pwm -eq $MAX ]
+			then
+				echo "    This fan appears to stop when the PWM is enabled;"
+				echo "    perhaps the fan input shares a pin with the PWM output"
+				echo "    on the sensor chip."
+				echo "    You cannot control this fan with this PWM output."
+				rm -f $TMP1 $TMP2
+				echo
+				return 0
+			fi
+			break
+		fi
+		if [ $pwm -lt $STEP2_BELOW ]
+		then
+			let pwm=$pwm-$STEP2
+		else
+			let pwm=$pwm-$STEP
+		fi
+	done
+	pwmdisable $P	
+	if [ "$PLOT" = "y" ]
+	then
+		$PLOTTER  $TMP1
+		rm -f $TMP1 $TMP2
+	fi
+	echo
+}
+
+for i in $PWM
+do
+	echo Testing pwm control $i ...
+	pwmenable $i
+	if [ $? -ne 0 ]
+	then
+		echo "Manual control mode not supported, skipping."
+		continue
+	fi
+	pwmset $i 0
+	sleep $DELAY
+	if [ $? -ne 0 ]
+	then
+		pwmdisable $i
+		echo '^C received, restoring PWM and aborting...'
+		exit 1
+	fi		
+	let pwmactivecount=0
+	let count=1
+	for j in $GOODFAN
+	do
+		OS=`echo $SPEEDS | cut -d' ' -f$count`
+		# this will return the first field if there's only one (sysfs)
+		S=`cat $j | cut -d' ' -f2`
+		echo "  $j ... speed was $OS now $S"
+		pwmdisable $i
+		let threshold=2*$OS/3
+		if [ $S -lt $threshold ]
+		then
+			echo "    It appears that fan $j"
+			echo "    is controlled by pwm $i"
+#
+# a PWM can control more than one fan....
+#
+			if [ $pwmactivecount -eq 0 ]
+			then
+				let pwmactivecount=1
+				pwmactive="$i ${pwmactive}"
+				fanactive="$j ${fanactive}"
+			else
+				fanactive="$j+${fanactive}" #not supported yet by fancontrol
+			fi
+			sleep $DELAY
+			if [ $? -ne 0 ]
+			then
+				echo '^C received, aborting...'
+				exit 1
+			fi		
+			# this will return the first field if there's only one (sysfs)
+			S=`cat $j | cut -d' ' -f2`
+			if [ $S -lt $threshold ]
+			then
+				echo "    Fan $j has not returned to speed, please investigate!"
+			else
+				echo -n "Would you like to generate a detailed correlation (y)? "
+				read X
+				if [ "$X" = "y" -o "$X" = "Y" -o "$X" = "" ]
+				then
+					pwmdetail $i $j
+				fi
+			fi
+		else
+			echo "    no correlation"
+		fi
+		let count=count+1
+	done
+	echo
+	if [ "$pwmactivecount" = "0" ]
+	then
+		echo "No correlations were detected."
+		echo "There is either no fan connected to the output of $i,"
+		echo "or the connected fan has no rpm-signal connected to one of"
+		echo "the tested fan sensors. (Note: not all motherboards have"
+		echo "the pwm outputs connected to the fan connectors,"
+		echo "check out the hardware database on http://www.almico.com/forumindex.php)"
+		echo
+		echo -n "Did you see/hear a fan stopping during the above test (n)? "
+		read X
+		if [ "$X" = "y" -o "$X" = "Y" ]
+		then
+			pwmactive="$i ${pwmactive}"
+		fi
+		echo
+	fi
+done
+
+
+echo 'Testing is complete.'
+echo 'Please verify that all fans have returned to their normal speed.'
+echo
+echo 'The fancontrol script can automatically respond to temperature changes'
+echo 'of your system by changing fanspeeds.'
+echo -n 'Do you want to set up its configuration file now (y)? '
+
+read X
+if [ "$X" = "n" -o "$X" = "N" ]
+then
+	exit
+fi
+
+if [ -n "$SYSFS" ]
+then
+	MATCH=$PREFIX/'temp[1-9]_input'
+else
+	MATCH=$PREFIX/'temp[1-9]'
+fi
+TEMPS=`echo $MATCH`
+if [ "$MATCH" = "$TEMPS" ]
+then
+	echo $0: 'There are no temperature-capable sensor modules installed'
+	exit 1
+fi
+
+function AskPath {
+	echo -n 'What should be the path to your fancontrol config file (/etc/fancontrol)? '
+
+	read X
+	if [ "$X" = "y" -o "$X" = "Y" -o "$X" = "" ]
+	then
+		X=/etc/fancontrol
+	fi
+	if [ -f $X ]
+	then
+		FCCONFIG=$X
+	else
+		echo -n "$X does not exist, shall I create it now (y)? "
+		read Y
+		if [ "$Y" = "y" -o "$Y" = "Y" -o "$Y" = "" ]
+		then
+			touch $X
+			chmod 0660 $X
+			chown root.root $X
+			FCCONFIG=$X
+		else
+			AskPath
+		fi
+	fi
+}
+
+AskPath
+
+function LoadConfig {
+	echo "Loading configuration from $1 ..."
+	INTERVAL=`egrep '^INTERVAL=.*$' $1 | sed -e 's/INTERVAL= *//g'`
+	FCTEMPS=`egrep '^FCTEMPS=.*$' $1 | sed -e 's/FCTEMPS= *//g'`
+	FCFANS=`egrep '^FCFANS=.*$' $1 | sed -e 's/FCFANS= *//g'`
+	MINTEMP=`egrep '^MINTEMP=.*$' $1 | sed -e 's/MINTEMP= *//g'`
+	MAXTEMP=`egrep '^MAXTEMP=.*$' $1 | sed -e 's/MAXTEMP= *//g'`
+	MINSTART=`egrep '^MINSTART=.*$' $1 | sed -e 's/MINSTART= *//g'`
+	MINSTOP=`egrep '^MINSTOP=.*$' $1 | sed -e 's/MINSTOP= *//g'`
+	MINPWM=`egrep '^MINPWM=.*$' $1 | sed -e 's/MINPWM= *//g'`
+	MAXPWM=`egrep '^MAXPWM=.*$' $1 | sed -e 's/MAXPWM= *//g'`
+
+	# Check for configuration change
+	local item
+	for item in $FCFANS
+	do
+		if [ ! -f "`echo $item | sed -e 's/=.*$//'`" ]
+		then
+			echo "Configuration appears to be outdated, discarded"
+			FCTEMPS=""
+			FCFANS=""
+			MINTEMP=""
+			MAXTEMP=""
+			MINSTART=""
+			MINSTOP=""
+			MINPWM=""
+			MAXPWM=""
+		fi
+	done
+}
+
+LoadConfig $FCCONFIG
+
+function TestMinStart {
+	echo
+	echo 'Now we increase the PWM value in 10-unit-steps.'
+	echo 'Let the fan stop completely, then press return until the'
+	echo "fan starts spinning. Then enter 'y'."
+	echo 'We will use this value +20 as the starting speed.'
+	let fanok=0
+	let fanval=0
+	until [ "$fanok" = "1" ]
+	do
+		let fanval=fanval+10
+		if [ $fanval -gt 240 ] ; then let fanval=$MAX ; let fanok=1 ; fi
+		echo -n "Setting $pwms to $fanval..."
+		echo $fanval > $pwms
+		read FANTEST
+		if [ "$FANTEST" != "" ] ; then let fanok=1 ; fi
+	done
+	let fanval=fanval+20
+	if [ $fanval -gt 240 ] ; then let fanval=$MAX ; fi
+	echo "OK, using $fanval"
+	echo $MAX > $pwms
+}
+
+function TestMinStop {
+        echo
+        echo 'Now we decrease the PWM value in 10-unit-steps.'
+	echo 'Let the fan reach full speed, then press return until the'
+	echo "fan stops spinning. Then enter 'y'."
+	echo 'We will use this value +20 as the minimum speed.'
+        let fanok=0
+        let fanval=$MAX
+        until [ "$fanok" = "1" ]
+        do
+                let fanval=fanval-10
+		if [ $fanval -lt 0 ] ; then let fanval=0 ; let fanok=1 ; fi
+                echo -n "Setting $pwms to $fanval..."
+                echo $fanval > $pwms
+                read FANTEST
+		if [ "$FANTEST" != "" ] ; then let fanok=1 ; fi
+        done
+        let fanval=fanval+20
+        if [ $fanval -gt $MAX ] ; then let fanval=$MAX ; fi
+        echo "OK, using $fanval"
+	echo $MAX > $pwms
+}
+
+function SaveConfig {
+	echo
+	echo "Saving configuration to $FCCONFIG..."
+	tmpfile=`mktemp -t pwmcfg.XXXXXXXXXX` || { echo "$0: Cannot create temporary file" >&2; exit 1;  }
+	trap " [ -f \"$tmpfile\" ] && /bin/rm -f -- \"$tmpfile\"" 0 1 2 3 13 15
+	egrep -v '(INTERVAL|FCTEMPS|FCFANS|MAXTEMP|MINTEMP|MINSTART|MINSTOP|MINPWM|MAXPWM)' $FCCONFIG >$tmpfile
+	echo -e "INTERVAL=$INTERVAL\nFCTEMPS=$FCTEMPS\nFCFANS=$FCFANS\nMINTEMP=$MINTEMP\nMAXTEMP=$MAXTEMP\nMINSTART=$MINSTART\nMINSTOP=$MINSTOP" >>$tmpfile
+	[ -n "$MINPWM" ] && echo "MINPWM=$MINPWM" >>$tmpfile
+	[ -n "$MAXPWM" ] && echo "MAXPWM=$MAXPWM" >>$tmpfile
+	mv $tmpfile $FCCONFIG
+	#check if file was written correctly
+	echo 'Configuration saved'
+}
+
+INTERVAL=10
+PS3='select (1-n): '
+DEFMINTEMP=0
+DEFMAXTEMP=60
+DEFMINSTART=150
+DEFMINSTOP=100
+
+#the section below has a high potential for usability improvements
+echo
+echo 'Select fan output to configure, or other action:'
+select pwms in $pwmactive "Change INTERVAL" "Just quit" "Save and quit" "Show configuration"; do
+	case $pwms in
+	"Change INTERVAL")
+		echo
+		echo "Current interval is $INTERVAL seconds."
+		echo -n "Enter the interval at which fancontrol should update PWM values (in s):"
+		read INTERVAL ;; #check user input here
+	"Just quit")
+		exit ;;
+	"Save and quit")
+		SaveConfig
+		exit ;;
+	"Show configuration")
+		echo
+		echo "Common Settings:"
+		echo "INTERVAL=$INTERVAL"
+		for pwmo in $pwmactive
+		do
+			echo
+			echo "Settings of ${pwmo}:"
+			echo "  Depends on `echo $FCTEMPS |sed -e 's/ /\n/g' |egrep \"${pwmo}\" |sed -e 's/.*=//g'`"
+			echo "  Controls `echo $FCFANS |sed -e 's/ /\n/g' |egrep \"${pwmo}\" |sed -e 's/.*=//g'`"
+			echo "  MINTEMP=`echo $MINTEMP |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
+			echo "  MAXTEMP=`echo $MAXTEMP |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
+			echo "  MINSTART=`echo $MINSTART |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
+			echo "  MINSTOP=`echo $MINSTOP |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
+			echo "  MINPWM=`echo $MINPWM |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
+			echo "  MAXPWM=`echo $MAXPWM |sed -e \"s/ /\n/g\" |egrep \"${pwmo}\" |sed -e \"s/.*=//g\"`"
+		done
+		echo ;;
+
+	"`echo ${pwmactive} |sed -e 's/ /\n/g' | egrep \"${pwms}\"`" )
+		pwmsed=`echo ${pwms} | sed -e 's/\//\\\\\//g'` #escape / for sed
+		echo
+		if [ -n "$SYSFS" ]
+		then
+			echo 'Devices:'
+			print_devices ""
+			echo
+		fi
+		echo 'Current temperature readings are as follows:'
+		for j in $TEMPS
+		do
+			# this will return the first field if there's only one (sysfs)
+			S=`cat $j | cut -d' ' -f3`
+			if [ -n "$SYSFS" ]
+			then
+				let S="$S / 1000"
+			fi
+			echo "$j	$S"
+		done
+		FAN=`echo $fanactive|cut -d' ' -f$REPLY`
+	       	FCFANS="`echo $FCFANS | sed -e "s/${pwmsed}[^ ]* *//g\"` ${pwms}=$FAN"
+		echo
+		echo "Select a temperature sensor as source for ${pwms}:"
+		select tempss in $TEMPS "None (Do not affect this PWM output)"; do
+			if [ "$tempss" = "None (Do not affect this PWM output)" ]
+			then
+			
+				break;
+			else
+				if [ "$FCTEMPS" = "" ]
+				then
+					FCTEMPS="${pwms}=${tempss}"
+				else
+					FCTEMPS="`echo $FCTEMPS | sed -e "s/${pwmsed}[^ ]* *//g\"` ${pwms}=${tempss}"
+				fi
+			fi
+			echo
+			echo 'Enter the low temperature (degree C)'
+			echo -n "below which the fan should spin at minimum speed ($DEFMINTEMP): "
+			read XMT
+			if [ "$XMT" = "" ]
+			then
+				XMT=$DEFMINTEMP
+			fi
+			if [ "$MINTEMP" = "" ]
+			then
+				MINTEMP="${pwms}=${XMT}"
+			else
+				MINTEMP="`echo $MINTEMP | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMT}"
+			fi
+			echo
+			echo 'Enter the high temperature (degree C)'
+			echo -n "over which the fan should spin at maximum speed ($DEFMAXTEMP): "
+			read XMT
+			if [ "$XMT" = "" ]
+			then
+				XMT=$DEFMAXTEMP
+			fi
+			if [ "$MAXTEMP" = "" ]
+			then
+				MAXTEMP="${pwms}=${XMT}"
+                        else
+				MAXTEMP="`echo $MAXTEMP | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMT}"
+			fi
+			echo
+			echo "Enter the minimum PWM value (0-$MAX)"
+			echo -n "at which the fan STARTS spinning (press t to test) ($DEFMINSTART): "
+			read XMV
+			if [ "$XMV" = "" ]
+			then
+				XMV=$DEFMINSTART
+			fi
+			if [ "$XMV" = "t" -o "$XMV" = "T" ]
+			then
+				TestMinStart
+				XMV=$fanval
+			fi
+			if [ "$MINSTART" = "" ]
+			then
+				MINSTART="${pwms}=${XMV}"
+			else
+				MINSTART="`echo $MINSTART | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMV}"
+			fi
+			echo
+			echo "Enter the minimum PWM value (0-$MAX)"
+			echo -n "at which the fan STOPS spinning (press t to test) ($DEFMINSTOP): "
+			read XMV
+			if [ "$XMV" = "" ]
+			then
+				XMV=$DEFMINSTOP
+			fi
+			if [ "$XMV" = "t" -o "$XMV" = "T" ]
+			then
+				TestMinStop
+				XMV=$fanval
+			fi
+			if [ "$MINSTOP" = "" ]
+			then
+				MINSTOP="${pwms}=${XMV}"
+			else
+				MINSTOP="`echo $MINSTOP | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMV}"
+			fi
+			echo
+			echo "Enter the PWM value (0-$XMV) to use when the temperature"
+			echo -n "is below the low temperature limit (0): "
+			read XMINP
+			if [ -n "$XMINP" ]
+			then
+				if [ "$MINPWM" = "" ]
+				then
+					MINPWM="${pwms}=${XMINP}"
+				else
+					MINPWM="`echo $MINPWM | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMINP}"
+				fi
+			fi
+			echo
+			echo "Enter the PWM value ($XMV-$MAX) to use when the temperature"
+			echo -n "is over the high temperature limit ($MAX): "
+			read XMAXP
+			if [ -n "$XMAXP" ]
+			then
+				if [ "$MAXPWM" = "" ]
+				then
+					MAXPWM="${pwms}=${XMAXP}"
+				else
+					MAXPWM="`echo $MAXPWM | sed -e \"s/${pwmsed}[^ ]* *//g\"` ${pwms}=${XMAXP}"
+				fi
+			fi
+			echo
+			break;
+		done ;;
+	
+	*)
+		grep $pwm
+
+		echo "No such option. Enter a number." ;;
+	esac
+done
Index: /lm-sensors/tags/V3-0-0-RC2/prog/pwm/Module.mk
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/pwm/Module.mk	(revision 4590)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/pwm/Module.mk	(revision 4590)
@@ -0,0 +1,39 @@
+#  Module.mk
+#  Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+MODULE_DIR := prog/pwm
+PROGPWMDIR := $(MODULE_DIR)
+
+PROGPWMMAN8DIR := $(MANDIR)/man8
+PROGPWMMAN8FILES := $(MODULE_DIR)/fancontrol.8 $(MODULE_DIR)/pwmconfig.8
+
+PROGPWMTARGETS := $(MODULE_DIR)/fancontrol \
+                  $(MODULE_DIR)/pwmconfig
+
+REMOVEPWMBIN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(SBINDIR)/%,$(PROGPWMTARGETS))
+REMOVEPWMMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGPWMMAN8DIR)/%,$(PROGPWMMAN8FILES))
+
+install-prog-pwm: $(PROGPWMTARGETS)
+	$(MKDIR) $(DESTDIR)$(SBINDIR) $(DESTDIR)$(PROGPWMMAN8DIR)
+	$(INSTALL) -m 755 $(PROGPWMTARGETS) $(DESTDIR)$(SBINDIR)
+	$(INSTALL) -m 644 $(PROGPWMMAN8FILES) $(DESTDIR)$(PROGPWMMAN8DIR)
+
+user_install :: install-prog-pwm
+
+user_uninstall::
+	$(RM) $(REMOVEPWMBIN)
+	$(RM) $(REMOVEPWMMAN)
Index: /lm-sensors/tags/V3-0-0-RC2/prog/pwm/fancontrol.8
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/pwm/fancontrol.8	(revision 4699)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/pwm/fancontrol.8	(revision 4699)
@@ -0,0 +1,110 @@
+.TH FANCONTROL 8 "June 2007" "lm-sensors 3"
+.SH NAME
+fancontrol \- automated software based fan speed regulation
+
+.SH SYNOPSIS
+.B fancontrol
+.I [configfile]
+
+.SH DESCRIPTION
+\fBfancontrol\fP is a shell script for use with lm_sensors. It reads its
+configuration from a file, then calculates fan speeds from temperatures and
+sets the corresponding PWM outputs to the computed values.
+
+.SH WARNING
+Please be careful when using the fan control features of your mainboard, in
+addition to the risk of burning your CPU, at higher temperatures there will be
+a higher wearout of your other hardware components, too. So if you plan to use
+these components in 50 years, \fBmaybe\fP you shouldn't use fancontrol
+at all.  Also please keep in mind most fans aren't designed to be
+powered by a PWMed voltage.
+
+In practice it doesn't seem to be a major issue, the fans will get slightly
+warmer, just be sure to have a temperature alarm and/or shutdown call, in case
+some fan fails, because you probably won't hear it anymore ;)
+
+.SH CONFIGURATION
+For easy configuration, there's a script
+named \fBpwmconfig\fP(8) which lets you interactively write your 
+configuration file for \fBfancontrol\fP. Alternatively you can write this 
+file yourself using the information from this manpage.
+
+Since most of you are going to use \fBpwmconfig\fP(8) script, the config
+file syntax will be discussed last. First I'm going to describe the various
+variables available for changing \fBfancontrol\fP's behaviour:
+
+.TP
+.B INTERVAL
+This variable defines at which interval in seconds the main loop of
+\fBfancontrol\fP will be executed
+.TP
+.B FCTEMPS
+Maps PWM outputs to temperature sensors so \fBfancontrol\fP knows which
+temperature sensors should be used for calculation of new values for
+the corresponding PWM outputs.
+.TP
+.B FCFANS
+FCFANS records the association between a PWM and a fan.
+Then \fBfancontrol\fP can check the fan speed and restart it if it
+stops unexpectedly.
+.TP
+.B MINTEMP
+The temperature below which the fan gets switched to minimum speed.
+.TP
+.B MAXTEMP
+The temperature over which the fan gets switched to maximum speed.
+.TP
+.B MINSTART
+Sets the minimum speed at which the fan begins spinning. You should
+use a safe value to be sure it works, even when the fan gets old.
+.TP
+.B MINSTOP
+The minimum speed at which the fan still spins. Use a safe value here,
+too.
+.TP
+.B MINPWM
+The PWM value to use when the temperature is below MINTEMP.
+Typically, this will be either 0 if it is OK for the fan to plain
+stop, or the same value as MINSTOP if you don't want the fan to
+ever stop.
+If this value isn't defined, it defaults to 0 (stopped fan).
+.TP
+.B MAXPWM
+The PWM value to use when the temperature is over MAXTEMP.
+If this value isn't defined, it defaults to 255 (full speed).
+.PP
+The configuration file format is a bit strange:
+.IP
+.nf
+VARIABLE=chip/pwmdev=value chip/pwmdev2=value2
+VARIABLE2=...
+.fi
+.PP
+Each variable has its own line. The variable name is followed by an equal sign
+and the device=value pairs. These consist of the relative path to the pwm
+output (from /proc/sys/dev/sensors, /sys/bus/i2c/devices or /sys/class/hwmon
+depending on the kernel version) for which the value is valid, equal sign
+followed by the value and are separated by a blank. Example:
+.IP
+MINTEMP=w83627hf-isa-0290/pwm2=40 w83627hf-isa-0290/pwm1=54
+.PP
+You have to play with the temperature values a bit to get happy. For initial
+setup I recommend using the \fBpwmconfig\fP script. Small changes can be made by
+editing the config file directly following the rules above.
+
+.SH THE ALGORITHM
+
+\fBfancontrol\fP first reads its configuration, writes it to arrays and loops its
+main function.  This function gets the temperatures and fanspeeds from
+kernel driver files and calculates new speeds depending on temperature
+changes, but only if the temp is between MINTEMP and MAXTEMP. After that, the
+new values are written to the PWM outputs. Currently the speed increases
+quadratically with rising temperature. This way you won't hear your fans most
+of the time at best.
+
+.SH SEE ALSO
+pwmconfig(8), sensors(1).
+
+.SH AUTHOR
+.PP
+Marius Reiner <marius.reiner@hdev.de>
Index: /lm-sensors/tags/V3-0-0-RC2/prog/dump/isadump.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/dump/isadump.c	(revision 4900)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/dump/isadump.c	(revision 4900)
@@ -0,0 +1,316 @@
+/*
+    isadump.c - isadump, a user-space program to dump ISA registers
+    Copyright (C) 2000  Frodo Looijaard <frodol@dds.nl>, and
+                        Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Copyright (C) 2004,2007  Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+	Typical usage:
+	isadump 0x295 0x296		Basic winbond dump using address/data registers
+	isadump 0x295 0x296 2		Winbond dump, bank 2
+	isadump 0x2e 0x2f 0x09		Super-I/O, logical device 9
+	isadump -f 0x5000		Flat address space dump like for Via 686a
+	isadump -f 0xecf0 0x10 1	PC87366, temperature channel 2
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "util.h"
+#include "superio.h"
+
+
+/* To keep glibc2 happy */
+#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 0
+#include <sys/io.h>
+#else
+#include <asm/io.h>
+#endif
+
+#ifdef __powerpc__
+unsigned long isa_io_base = 0; /* XXX for now */
+#endif /* __powerpc__ */
+
+static void help(void)
+{
+	fprintf(stderr,
+	        "Syntax for I2C-like access:\n"
+	        "  isadump [-y] [-k V1,V2...] ADDRREG DATAREG [BANK [BANKREG]]\n"
+	        "Syntax for flat address space:\n"
+	        "  isadump [-y] -f ADDRESS [RANGE [BANK [BANKREG]]]\n");
+}
+
+static int default_bankreg(int flat, int addrreg, int datareg)
+{
+	if (flat) {
+		return 0x09; /* Works for National Semiconductor
+		                Super-IO chips */
+	}
+
+	if ((addrreg == 0x2e && datareg == 0x2f)
+	 || (addrreg == 0x4e && datareg == 0x4f)) {
+		return 0x07; /* Works for all Super-I/O chips */
+	}
+	
+	return 0x4e; /* Works for Winbond ISA chips, default */
+}
+
+static int set_bank(int flat, int addrreg, int datareg, int bank, int bankreg)
+{
+	int oldbank;
+
+	if (flat) {
+		oldbank = inb(addrreg+bankreg);
+		outb(bank, addrreg+bankreg);
+	} else {
+		outb(bankreg, addrreg);
+		oldbank = inb(datareg);
+		outb(bank, datareg);
+	}
+
+	return oldbank;
+}
+
+int main(int argc, char *argv[])
+{
+	int addrreg;        /* address in flat mode */
+	int datareg = 0;    /* unused in flat mode */
+	int range = 256;    /* can be changed only in flat mode */
+	int bank = -1;      /* -1 means no bank operation */
+	int bankreg;
+	int oldbank = 0;
+	int i, j, res;
+	int flags = 0;
+	int flat = 0, yes = 0;
+	char *end;
+	unsigned char enter_key[SUPERIO_MAX_KEY+1];
+
+	enter_key[0] = 0;
+
+	/* handle (optional) flags first */
+	while (1+flags < argc && argv[1+flags][0] == '-') {
+		switch (argv[1+flags][1]) {
+		case 'f': flat = 1; break;
+		case 'y': yes = 1; break;
+		case 'k':
+			if (2+flags >= argc
+			 || superio_parse_key(enter_key, argv[2+flags]) < 0) {
+				fprintf(stderr, "Invalid or missing key\n");
+				help();
+				exit(1);
+			}
+			flags++;
+			break;
+		default:
+			fprintf(stderr, "Warning: Unsupported flag "
+				"\"-%c\"!\n", argv[1+flags][1]);
+			help();
+			exit(1);
+		}
+		flags++;
+	}
+
+	/* key is never needed in flat mode */
+	if (flat && enter_key[0]) {
+		fprintf(stderr, "Error: Cannot use key in flat mode\n");
+		exit(1);
+	}
+
+	/* verify that the argument count is correct */
+	if ((!flat && argc < 1+flags+2)
+	 || (flat && argc < 1+flags+1)) {
+		help();
+		exit(1);
+	}
+
+	addrreg = strtol(argv[1+flags], &end, 0);
+	if (*end) {
+		fprintf(stderr, "Error: Invalid address!\n");
+		help();
+		exit(1);
+	}
+	if (addrreg < 0 || addrreg > (flat?0xffff:0x3fff)) {
+		fprintf(stderr, "Error: Address out of range "
+		        "(0x0000-0x%04x)!\n", flat?0xffff:0x3fff);
+		help();
+		exit(1);
+	}
+
+	if (flat) {
+		if (1+flags+1 < argc) {
+			range = strtol(argv[1+flags+1], &end, 0);
+			if (*end || range <= 0 || range > 0x100
+			 || range & 0xf) {
+				fprintf(stderr, "Error: Invalid range!\n"
+				        "Hint: Must be a multiple of 16 no "
+				        "greater than 256.\n");
+				help();
+				exit(1);
+			}
+		} else {
+			addrreg &= 0xff00; /* Force alignment */
+		}
+	} else {
+		datareg = strtol(argv[1+flags+1], &end, 0);
+		if (*end) {
+			fprintf(stderr, "Error: Invalid data register!\n");
+			help();
+			exit(1);
+		}
+		if (datareg < 0 || datareg > 0x3fff) {
+			fprintf(stderr, "Error: Data register out of range "
+			        "(0x0000-0x3fff)!\n");
+			help();
+			exit(1);
+		}
+	}
+
+	bankreg = default_bankreg(flat, addrreg, datareg);
+
+	if (1+flags+2 < argc) {
+		bank = strtol(argv[1+flags+2], &end, 0);
+		if (*end) {
+			fprintf(stderr, "Error: Invalid bank number!\n");
+			help();
+			exit(1);
+		}
+		if ((bank < 0) || (bank > 31)) {
+			fprintf(stderr, "Error: bank out of range (0-31)!\n");
+			help();
+			exit(1);
+		}
+
+		if (1+flags+3 < argc) {
+			bankreg = strtol(argv[1+flags+3], &end, 0);
+			if (*end) {
+				fprintf(stderr, "Error: Invalid bank "
+				        "register!\n");
+				help();
+				exit(1);
+			}
+			if (bankreg < 0 || bankreg >= range) {
+				fprintf(stderr, "Error: bank out of range "
+				        "(0x00-0x%02x)!\n", range-1);
+				help();
+				exit(1);
+			}
+		}
+	}
+
+	if (getuid()) {
+		fprintf(stderr, "Error: Can only be run as root (or make it "
+		        "suid root)\n");
+		exit(1);
+	}
+
+	if (!yes) {
+		fprintf(stderr, "WARNING! Running this program can cause "
+		        "system crashes, data loss and worse!\n");
+
+		if (flat)
+			fprintf(stderr, "I will probe address range 0x%x to "
+			        "0x%x.\n", addrreg, addrreg + range - 1);
+		else
+			fprintf(stderr, "I will probe address register 0x%x "
+			        "and data register 0x%x.\n", addrreg, datareg);
+
+		if (bank>=0) 	
+			fprintf(stderr, "Probing bank %d using bank register "
+			        "0x%02x.\n", bank, bankreg);
+
+		fprintf(stderr, "Continue? [Y/n] ");
+		fflush(stderr);
+		if (!user_ack(1)) {
+			fprintf(stderr, "Aborting on user request.\n");
+			exit(0);
+		}
+	}
+
+#ifndef __powerpc__
+	if ((datareg < 0x400) && (addrreg < 0x400) && !flat) {
+		if (ioperm(datareg, 1, 1)) {
+			fprintf(stderr, "Error: Could not ioperm() data "
+			        "register!\n");
+			exit(1);
+		}
+		if (ioperm(addrreg, 1, 1)) {
+			fprintf(stderr, "Error: Could not ioperm() address "
+			        "register!\n");
+			exit(1);
+		}
+	} else {
+		if (iopl(3)) {
+			fprintf(stderr, "Error: Could not do iopl(3)!\n");
+			exit(1);
+		}
+	}
+#endif
+
+	/* Enter Super-I/O configuration mode */
+	if (enter_key[0])
+		superio_write_key(addrreg, enter_key);
+
+	if (bank >= 0)
+		oldbank = set_bank(flat, addrreg, datareg, bank, bankreg);
+
+	if (flat)
+		printf("  ");
+	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
+	for (i = 0; i < range; i += 16) {
+		if (flat)
+			printf("%04x: ", addrreg + i);
+		else
+			printf("%02x: ", i);
+
+		/* It was noticed that Winbond Super-I/O chips
+		   would leave the configuration mode after
+		   an arbitrary number of register reads,
+		   causing any subsequent read attempt to
+		   silently fail. Repeating the key every 16 reads
+		   prevents that. */
+		if (enter_key[0])
+			superio_write_key(addrreg, enter_key);
+
+		for (j = 0; j < 16; j++) {
+			fflush(stdout);
+			if (flat) {
+				res = inb(addrreg + i + j);
+			} else {	
+				outb(i+j, addrreg);
+				if (i+j == 0 && inb(addrreg) == 0x80) {
+					/* Bit 7 appears to be a busy flag */
+					range = 128;
+				}
+				res = inb(datareg);
+			}
+			printf("%02x ", res);
+		}
+		printf("\n");
+	}
+
+	/* Restore the original bank value */
+	if (bank >= 0)
+		set_bank(flat, addrreg, datareg, oldbank, bankreg);
+
+	/* Exit Super-I/O configuration mode */
+	if (enter_key[0])
+		superio_reset(addrreg, datareg);
+
+	exit(0);
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/dump/util.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/dump/util.h	(revision 4670)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/dump/util.h	(revision 4670)
@@ -0,0 +1,16 @@
+/*
+    util - helper functions
+    Copyright (C) 2006 Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+*/
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+extern int user_ack(int def);
+
+#endif /* _UTIL_H */
Index: /lm-sensors/tags/V3-0-0-RC2/prog/dump/superio.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/dump/superio.c	(revision 4407)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/dump/superio.c	(revision 4407)
@@ -0,0 +1,75 @@
+/*
+    superio: Handle special I/O operations needed by most Super-I/O chips
+   
+    Copyright (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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdlib.h>
+
+#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 0
+#include <sys/io.h>
+#else
+#include <asm/io.h>
+#endif
+
+#include "superio.h"
+
+int superio_parse_key(unsigned char *key, const char *s)
+{
+	char *end;
+	int tmp;
+	key[0] = 0;
+	
+	while (*s != '\0') {
+		tmp = strtol(s, &end, 0);
+		if ((*end != '\0' && *end != ',')
+		 || (tmp < 0x00 || tmp > 0xff))
+			return -1;
+
+		/* Byte is valid, store it */
+		key[++key[0]] = tmp;
+
+		/* Last byte? */
+		if (key[0] == SUPERIO_MAX_KEY
+		 || *end == '\0')
+			return 0;
+
+		/* Skip comma */
+		s = end + 1;
+	}
+	
+	/* Unexpected end of string */
+	return -1;
+}
+
+void superio_write_key(int addrreg, unsigned char *key)
+{
+	int i;
+
+	for (i = 1; i <= key[0]; i++)
+		outb(key[i], addrreg);
+}
+
+void superio_reset(int addrreg, int datareg)
+{
+	/* Some chips (SMSC, Winbond) want this */
+	outb(0xaa, addrreg);
+
+	/* Return to "Wait For Key" state (PNP-ISA spec) */
+	outb(0x02, addrreg);
+	outb(0x02, datareg);
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/dump/isadump.8
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/dump/isadump.8	(revision 4471)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/dump/isadump.8	(revision 4471)
@@ -0,0 +1,105 @@
+.TH ISADUMP 8 "August 2004"
+.SH NAME
+isadump \- examine ISA registers
+
+.SH SYNOPSIS
+.B isadump
+.RB [ -y ]
+.RB [ "-k V1,V2..." ]
+.I addrreg
+.I datareg
+.RI [ "bank " [ bankreg ]]
+#for I2C-like access
+.br
+.B isadump
+.RB [ -y ]
+.BI "-f " address
+.RI [ "range " [ "bank " [ bankreg ]]]
+#for flat address space
+
+.SH DESCRIPTION
+isadump is a small helper program to examine registers visible through the ISA
+bus. It is intended to probe any chip that lives on the ISA bus working with an
+address register and a data register (I2C-like access) or a flat range (of up
+to 256 bytes).
+
+.SH OPTIONS
+.TP
+.B -f
+Enable flat address space mode.
+.TP
+.B -y
+Disable interactive mode. By default, isadump will wait for a confirmation
+from the user before messing with the ISA bus. When this flag is used, it
+will perform the operation directly. This is mainly meant to be used in
+scripts.
+.TP
+.B -k V1,V2...
+Specify a comma-separated list of bytes to send as the key sequence to enter
+the chip configuration mode. Most Super-I/O chips need this.
+Known key sequences are: 0x87,0x01,0x55,0x55 for ITE, 0x55 for SMSC, 0x87,0x87
+for Winbond and VIA, none needed for National Semiconductor.
+
+.SH OPTIONS (I2C-like access mode)
+At least two options must be provided to isadump. \fIaddrreg\fR contains the
+ISA address of the address register for the chip to probe; \fIdatareg\fR
+contains the address of the data register. Both addresses are integers between
+0x0000 and 0x3FFF. Usually, if the chip's base address is 0x0nn0, the
+address register is at 0x0nn5 and the data register is at 0x0nn6. The most
+common base address for hardware monitoring chips is 0x0290.
+.PP
+For Super-I/O chips, address register is typically at 0x2E with data
+register at 0x2F.
+.PP
+The \fIbank\fR and \fIbankreg\fR parameters are useful on the Winbond chips
+as well as on Super-I/O chips.
+\fIbank\fR is an integer between 0 and 31, and \fIbankreg\fR is an integer
+between 0x00 and 0xFF (default value: 0x4E for Winbond chips, 0x07
+for Super-I/O chips). The W83781D datasheet has more information on bank
+selection.
+
+.SH OPTIONS (flat address space mode)
+In flat mode, only one parameter is
+mandatory. \fIaddress\fR contains the ISA address of the chip to probe;
+it is an integer between 0x0000 and 0xFFFF.
+If provided, \fIrange\fR is how many bytes should be read (must be a
+multiple of 16). If the range isn't provided, it defaults to 256 bytes
+and the address is forcibly aligned on a 256-byte boundary.
+.PP
+The \fIbank\fR and \fIbankreg\fR parameters are useful on the National
+Semiconductor PC87365 and PC87366 Super-I/O chips.
+\fIbank\fR is an integer between 0 and 31, and \fIbankreg\fR is an integer
+between 0x00 and 0xFF (default value: 0x09; must fit in the specified
+range). See the PC87365 datasheet for more information on bank selection.
+
+.SH NOTES
+If no bank is specified, no bank change operation is performed.
+.PP
+If a bank is specified, the original value is restored before isadump exits.
+.PP
+Dumping Super-I/O chips is typically a two-step process. First, you will have
+to access the main Super-I/O address using a command like:
+isadump 0x2e 0x2f 0x09.
+This will select logical device 9 (correct value depend on the chip). At 0x60
+you will find the logical device address word, for example "ec c0".
+Then you can use a command like:
+isadump -f 0xecc0 16.
+This will dump the logical device registers. The correct range depends on
+the chip.
+
+.SH WARNING
+Poking around in ISA data space is extremely dangerous.
+Running isadump with random parameters can cause system
+crashes, data loss, and worse!  Be extremely careful when using
+this program.
+
+.SH SEE ALSO
+i2cdump(8), isaset(8)
+
+.SH AUTHOR
+Frodo Looijaard, Mark D. Studebaker, and the lm_sensors group
+(http://www.lm-sensors.org/)
+.PP
+This manual page was originally written by David Z Maze <dmaze@debian.org> for
+the Debian GNU/Linux system. It was then reviewed and augmented by the lm_sensors
+team and is now part of the lm_sensors source distribution.
Index: /lm-sensors/tags/V3-0-0-RC2/prog/dump/isaset.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/dump/isaset.c	(revision 4900)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/dump/isaset.c	(revision 4900)
@@ -0,0 +1,260 @@
+/*
+    isaset.c - isaset, a user-space program to write ISA registers
+    Copyright (C) 2000  Frodo Looijaard <frodol@dds.nl>, and
+                        Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Copyright (C) 2004,2007  Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+	Typical usage:
+	isaset 0x295 0x296 0x10 0x12	Write 0x12 to address 0x10 using address/data registers
+	isaset -f 0x5010 0x12		Write 0x12 to location 0x5010
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "util.h"
+
+
+/* To keep glibc2 happy */
+#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 0
+#include <sys/io.h>
+#else
+#include <asm/io.h>
+#endif
+
+#ifdef __powerpc__
+unsigned long isa_io_base = 0; /* XXX for now */
+#endif /* __powerpc__ */
+
+static void help(void)
+{
+	fprintf(stderr,
+	        "Syntax for I2C-like access:\n"
+	        "  isaset [-y] ADDRREG DATAREG ADDRESS VALUE [MASK]\n"
+	        "Syntax for flat address space:\n"
+	        "  isaset [-y] -f ADDRESS VALUE [MASK]\n");
+}
+
+int main(int argc, char *argv[])
+{
+	int addrreg, datareg = 0, value, addr = 0, vmask = 0;
+	unsigned char res;
+	int flags = 0;
+	int flat = 0, yes = 0;
+	char *end;
+
+	/* handle (optional) flags first */
+	while (1+flags < argc && argv[1+flags][0] == '-') {
+		switch (argv[1+flags][1]) {
+		case 'f': flat = 1; break;
+		case 'y': yes = 1; break;
+		default:
+			fprintf(stderr, "Warning: Unsupported flag "
+				"\"-%c\"!\n", argv[1+flags][1]);
+			help();
+			exit(1);
+		}
+		flags++;
+	}
+
+	/* verify that the argument count is correct */
+	if ((!flat && (argc < 1+flags+4 || argc > 1+flags+5))
+	 || (flat && (argc < 1+flags+2 || argc > 1+flags+3))) {
+		help();
+		exit(1);
+	}
+
+	addrreg = strtol(argv[1+flags], &end, 0);
+	if (*end) {
+		fprintf(stderr, "Error: Invalid address!\n");
+		help();
+		exit(1);
+	}
+	if (addrreg < 0 || addrreg > (flat?0xffff:0x3fff)) {
+		fprintf(stderr,
+		        "Error: Address out of range (0x0000-0x%04x)!\n",
+			flat?0xffff:0x3fff);
+		help();
+		exit(1);
+	}
+
+	if (!flat) {
+		datareg = strtol(argv[1+flags+1], &end, 0);
+		if (*end) {
+			fprintf(stderr, "Error: Invalid data register!\n");
+			help();
+			exit(1);
+		}
+		if (datareg < 0 || datareg > 0x3fff) {
+			fprintf(stderr, "Error: Data register out of range "
+			        "(0x0000-0x3fff)!\n");
+			help();
+			exit(1);
+		}
+
+		addr = strtol(argv[1+flags+2], &end, 0);
+		if (*end) {
+			fprintf(stderr, "Error: Invalid address!\n");
+			help();
+			exit(1);
+		}
+		if (addr < 0 || addr > 0xff) {
+			fprintf(stderr, "Error: Address out of range "
+			        "(0x00-0xff)!\n");
+			help();
+			exit(1);
+		}
+	}
+
+	/* rest is the same for both modes so we cheat on flags */
+	if (!flat)
+		flags += 2;
+
+	value = strtol(argv[flags+2], &end, 0);
+	if (*end) {
+		fprintf(stderr, "Error: Invalid value!\n");
+		help();
+		exit(1);
+	}
+	if (value < 0 || value > 0xff) {
+		fprintf(stderr, "Error: Value out of range "
+			"(0x00-0xff)!\n");
+		help();
+		exit(1);
+	}
+
+	if (flags+3 < argc) {
+		vmask = strtol(argv[flags+3], &end, 0);
+		if (*end) {
+			fprintf(stderr, "Error: Invalid mask!\n");
+			help();
+			exit(1);
+		}
+		if (vmask < 0 || vmask > 0xff) {
+			fprintf(stderr, "Error: Mask out of range "
+				"(0x00-0xff)!\n");
+			help();
+			exit(1);
+		}
+	}
+
+	if (getuid()) {
+		fprintf(stderr, "Error: Can only be run as root "
+		        "(or make it suid root)\n");
+		exit(1);
+	}
+
+	if (!yes) {
+		fprintf(stderr, "WARNING! Running this program can cause "
+		        "system crashes, data loss and worse!\n");
+
+		if (flat)
+			fprintf(stderr, "I will write value 0x%02x%s to address "
+		                "0x%x.\n", value, vmask ? " (masked)" : "",
+			        addrreg);
+		else
+			fprintf(stderr, "I will write value 0x%02x%s to address "
+		                "0x%02x of chip with address register 0x%x\n"
+		                "and data register 0x%x.\n",
+		                value, vmask ? " (masked)" : "", addr,
+			        addrreg, datareg);
+
+		fprintf(stderr, "Continue? [Y/n] ");
+		fflush(stderr);
+		if (!user_ack(1)) {
+			fprintf(stderr, "Aborting on user request.\n");
+			exit(0);
+		}
+	}
+
+#ifndef __powerpc__
+	if (!flat && datareg < 0x400 && addrreg < 0x400) {
+		if (ioperm(datareg, 1, 1)) {
+			fprintf(stderr, "Error: Could not ioperm() data "
+			        "register!\n");
+			exit(1);
+		}
+		if (ioperm(addrreg, 1, 1)) {
+			fprintf(stderr, "Error: Could not ioperm() address "
+		        	"register!\n");
+			exit(1);
+		}
+	} else {
+		if (iopl(3)) {
+			fprintf(stderr, "Error: Could not do iopl(3)!\n");
+			exit(1);
+		}
+	}
+#endif
+
+	if (vmask) {
+		int oldvalue;
+
+		if (flat) {
+			oldvalue = inb(addrreg);
+		} else {	
+			outb(addr, addrreg);
+			oldvalue = inb(datareg);
+		}
+
+		if (oldvalue < 0) {
+			fprintf(stderr, "Error: Failed to read old value\n");
+			exit(1);
+		}
+
+		value = (value & vmask) | (oldvalue & ~vmask);
+
+		if (!yes) {
+			fprintf(stderr, "Old value 0x%02x, write mask "
+				"0x%02x: Will write 0x%02x to %s "
+				"0x%02x\n", oldvalue, vmask, value,
+				flat ? "address" : "register",
+				flat ? addrreg : addr);
+
+			fprintf(stderr, "Continue? [Y/n] ");
+			fflush(stderr);
+			if (!user_ack(1)) {
+				fprintf(stderr, "Aborting on user request.\n");
+				exit(0);
+			}
+		}
+	}
+
+	/* do the real thing */
+	if (flat) {
+		/* write */
+		outb(value, addrreg);
+		/* readback */
+		res = inb(addrreg);
+	} else {	
+		/* write */
+		outb(addr, addrreg);
+		outb(value, datareg);
+		/* readback */
+		res = inb(datareg);
+	}
+
+	if (res != value) {
+		fprintf(stderr, "Data mismatch, wrote 0x%02x, "
+		        "read 0x%02x back.\n", value, res);
+	}
+
+	exit(0);
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/dump/Module.mk
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/dump/Module.mk	(revision 4480)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/dump/Module.mk	(revision 4480)
@@ -0,0 +1,70 @@
+#  Module.mk - Makefile for a Linux module for reading sensor data.
+#  Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Note that MODULE_DIR (the directory in which this file resides) is a
+# 'simply expanded variable'. That means that its value is substituted
+# verbatim in the rules, until it is redefined. 
+MODULE_DIR := prog/dump
+PROGDUMPDIR := $(MODULE_DIR)
+
+PROGDUMPMAN8DIR := $(MANDIR)/man8
+PROGDUMPMAN8FILES :=
+
+# Regrettably, even 'simply expanded variables' will not put their currently
+# defined value verbatim into the command-list of rules...
+PROGDUMPTARGETS :=
+PROGDUMPSOURCES := $(MODULE_DIR)/util.c
+PROGDUMPBININSTALL :=
+
+# Only build isadump and isaset on x86 machines.
+ifneq (,$(findstring $(MACHINE), i386 i486 i586 i686 x86_64))
+PROGDUMPMAN8FILES += $(MODULE_DIR)/isadump.8 $(MODULE_DIR)/isaset.8
+PROGDUMPTARGETS += $(MODULE_DIR)/isadump $(MODULE_DIR)/isaset
+PROGDUMPSOURCES += $(MODULE_DIR)/isadump.c $(MODULE_DIR)/isaset.c \
+		   $(MODULE_DIR)/superio.c
+PROGDUMPBININSTALL += $(MODULE_DIR)/isadump $(MODULE_DIR)/isaset
+endif
+
+# Include all dependency files. We use '.rd' to indicate this will create
+# executables.
+INCLUDEFILES += $(PROGDUMPSOURCES:.c=.rd)
+
+REMOVEDUMPBIN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(SBINDIR)/%,$(PROGDUMPBININSTALL))
+REMOVEDUMPMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGDUMPMAN8DIR)/%,$(PROGDUMPMAN8FILES))
+
+all-prog-dump: $(PROGDUMPTARGETS)
+user :: all-prog-dump
+
+$(MODULE_DIR)/isadump: $(MODULE_DIR)/isadump.ro $(MODULE_DIR)/superio.ro $(MODULE_DIR)/util.ro
+	$(CC) $(EXLDFLAGS) -o $@ $^
+
+$(MODULE_DIR)/isaset: $(MODULE_DIR)/isaset.ro $(MODULE_DIR)/util.ro
+	$(CC) $(EXLDFLAGS) -o $@ $^
+
+install-prog-dump: all-prog-dump
+	$(MKDIR) $(DESTDIR)$(SBINDIR) $(DESTDIR)$(PROGDUMPMAN8DIR)
+	$(INSTALL) -m 755 $(PROGDUMPBININSTALL) $(DESTDIR)$(SBINDIR)
+	$(INSTALL) -m 644 $(PROGDUMPMAN8FILES) $(DESTDIR)$(PROGDUMPMAN8DIR)
+user_install :: install-prog-dump
+
+user_uninstall::
+	$(RM) $(REMOVEDUMPBIN)
+	$(RM) $(REMOVEDUMPMAN)
+
+clean-prog-dump:
+	$(RM) $(PROGDUMPDIR)/*.rd $(PROGDUMPDIR)/*.ro $(PROGDUMPTARGETS)
+clean :: clean-prog-dump
Index: /lm-sensors/tags/V3-0-0-RC2/prog/dump/superio.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/dump/superio.h	(revision 2899)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/dump/superio.h	(revision 2899)
@@ -0,0 +1,30 @@
+/*
+    superio: Handle special I/O operations needed by most Super-I/O chips
+
+    Copyright (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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SUPERIO_H
+#define _SUPERIO_H
+
+#define SUPERIO_MAX_KEY	8
+
+int superio_parse_key(unsigned char *key, const char *s);
+void superio_write_key(int addrreg, unsigned char *key);
+void superio_reset(int addrreg, int datareg);
+
+#endif /* _SUPERIO_H */
Index: /lm-sensors/tags/V3-0-0-RC2/prog/dump/isaset.8
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/dump/isaset.8	(revision 4471)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/dump/isaset.8	(revision 4471)
@@ -0,0 +1,74 @@
+.TH ISASET 8 "May 2005"
+.SH "NAME"
+isaset \- set ISA registers
+
+.SH SYNOPSIS
+.B isaset
+.RB [ -y ]
+.I addrreg
+.I datareg
+.I address
+.I value
+.RI [ mask ]
+#for I2C-like access
+.br
+.B isaset
+.RB [ -y ]
+.BI "-f " address
+.I value
+.RI [ mask ]
+#for flat address space
+
+.SH DESCRIPTION
+isaset is a small helper program to set registers visible through the ISA
+bus.
+
+.SH OPTIONS
+.TP
+.B -f
+Enable flat address space mode.
+.TP
+.B -y
+Disable interactive mode. By default, isaset will wait for a confirmation
+from the user before messing with the ISA bus. When this flag is used, it
+will perform the operation directly. This is mainly meant to be used in
+scripts.
+
+.SH OPTIONS (I2C-like access mode)
+Four options must be provided to isaset. \fIaddrreg\fR contains the
+ISA address of the address register for the chip to probe; \fIdatareg\fR
+contains the address of the data register. Both addresses are integers between
+0x0000 and 0x3FFF. Usually, if the chip's base address is 0x0nn0, the
+address register is at 0x0nn5 and the data register is at 0x0nn6. The most
+common base address for hardware monitoring chips is 0x0290.
+For Super-I/O chips, address register is typically at 0x2E with data
+register at 0x2F.
+The \fIaddress\fR and \fIvalue\fR parameters are two integers between
+0x00 and 0xFF. isaset will write value \fIvalue\fR to address \fIaddress\fR.
+An optional \fImask\fR can be provided as a fifth parameter, preserving
+unmasked bits at the written location.
+
+.SH OPTIONS (flat address space mode)
+In flat mode, two parameters must
+be provided. \fIaddress\fR contains the ISA address of the register to
+write to; it is an integer between 0x0000 and 0xFFFF. Basically, it is
+the sum of the chip's base address and the chip register's address. isaset
+will write value \fIvalue\fR at this address.
+An optional \fImask\fR can be provided as a third parameter, preserving
+unmasked bits at the written location.
+
+.SH WARNING
+Poking around in ISA data space is extremely dangerous.
+Running isaset with random parameters can cause system
+crashes, data loss, and worse!  Be extremely careful when using
+this program.
+
+.SH SEE ALSO
+i2cset(8), isadump(8)
+
+.SH AUTHOR
+Mark D. Studebaker, and the lm_sensors group
+(http://www.lm-sensors.org/)
+.PP
+This manual page was shamelessly ripped from the i2cset and isadump manual
+pages by Jean Delvare.
Index: /lm-sensors/tags/V3-0-0-RC2/prog/dump/util.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/dump/util.c	(revision 4670)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/dump/util.c	(revision 4670)
@@ -0,0 +1,48 @@
+/*
+    util.c - helper functions
+    Copyright (C) 2006 Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+*/
+
+#include <stdio.h>
+#include "util.h"
+
+/* Return 1 if we should continue, 0 if we should abort */
+int user_ack(int def)
+{
+	char s[2];
+	int ret;
+
+	if (!fgets(s, 2, stdin))
+		return 0; /* Nack by default */
+
+	switch (s[0]) {
+	case 'y':
+	case 'Y':
+		ret = 1;
+		break;
+	case 'n':
+	case 'N':
+		ret = 0;
+		break;
+	default:
+		ret = def;
+	}
+
+	/* Flush extra characters */
+	while (s[0] != '\n') {
+		int c = fgetc(stdin);
+		if (c == EOF) {
+			ret = 0;
+			break;
+		}
+		s[0] = c;
+	}
+
+	return ret;
+}
+
Index: /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/tellerstats.sh
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/tellerstats.sh	(revision 4900)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/tellerstats.sh	(revision 4900)
@@ -0,0 +1,165 @@
+#!/bin/bash
+#
+#    tellerstats.sh                  3
+#	generate graphs from the data
+#
+#    Copyright (C) 2001  Philip Edelbrock
+#
+#    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# generic tellerstats init BEGIN
+
+# get config information from /etc/tellerstats.conf or whereever we are pointed
+
+if [ -z "$TELLERSTATS_CONF" ]
+then
+   TELLERSTATS_CONF=/etc/tellerstats.conf
+fi   
+
+export TELLERSTATS_CONF
+
+if [ ! -r $TELLERSTATS_CONF ]
+then
+   echo "$0: Could not find config file $TELLERSTATS_CONF"
+   exit 1
+fi   
+
+. $TELLERSTATS_CONF
+
+if [ ! -d $DBPATH ]
+then
+   echo "$0: data directory $DBPATH does not exist"
+   exit 1
+fi
+
+if [ ! -d $SENSORPATH ]
+then
+   echo "$0: sensor information directory $SENSORPATH does not exist."
+   exit 1
+fi
+
+if [ ! -d $HTMLROOT ]
+then
+   echo "$0: The root of your webserver - $HTMLROOT - does not exist..bailing out"
+   exit 1
+fi
+
+if [ ! -d $HTMLPATH ]
+then
+   echo "$0: The place where we keep HTML files and pictures - $HTMLPATH - does not exist..bailing out"
+   exit 1
+fi
+
+if [ ! -r $GNUPLOTSCRIPT_TMPL ]
+then
+   echo "$0: The gnuplot script template $GNUPLOTSCRIPT_TMPL does not exist..bailing out"
+   exit 1
+fi
+
+export DBPATH SENSORPATH TEMPPATH HTMLROOT HTMLPATH GNUPLOTSCRIPT_TMPL
+
+if [ -n "$DEBUG" ]
+then
+   echo "DBPATH = $DBPATH"
+   echo "SENSORPATH = $SENSORPATH"
+   echo "TEMPPATH = $TEMPPATH"
+   echo "HTMLROOT = $HTMLROOT"
+   echo "HTMLPATH = $HTMLPATH"
+   echo "GNUPLOTSCRIPT_TMPL = $GNUPLOTSCRIPT_TMPL"
+fi
+
+# generic tellerstats init END
+
+if [ -z "$LINEWIDTH" ]
+then
+   LINEWIDTH=5
+fi
+export LINEWIDTH   
+
+if [ -z "$PLOTFORMAT" ]
+then
+   PLOTFORMAT=ps
+fi
+export PLOTFORMAT
+
+if [ -z "$PLOTTERMINAL" ]
+then
+   PLOTTERMINAL="postscript eps enhanced color \"Helvetica\" 22"
+fi
+export PLOTTERMINAL
+
+if [ -n "$DEBUG" ]
+then
+   echo "LINEWIDTH = $LINEWIDTH"
+   echo "PLOTFORMAT = $PLOTFORMAT"
+   echo "PLOTTERMINAL = $PLOTTERMINAL"
+fi
+
+# Trim files to 48 hour window
+
+cd $DBPATH
+files="`echo *`"
+
+for this in $files
+do
+   tail $this -n576 > ${this}.tmp
+   mv ${this}.tmp $this
+done
+
+###############################################
+
+rm -rf $TEMPPATH
+mkdir -p $TEMPPATH
+
+cd $TEMPPATH
+
+# Update primary plots
+GNUPLOTSCRIPT="$TEMPPATH/gnuplotscript"
+cat $GNUPLOTSCRIPT_TMPL | perl -p -e's/\$(\w+)/$ENV{$1}/g' > $GNUPLOTSCRIPT
+gnuplot < $GNUPLOTSCRIPT
+rm $GNUPLOTSCRIPT
+
+files="`echo *`"
+
+CONVERT_OPTS_A="-interlace none -scale 320x240 -quality 100"
+CONVERT_OPTS_B="-interlace none -scale 800x600 -quality 100"
+
+for this in $files
+do
+   prefix=`echo $this|perl -p -e's/\.\w+$//'`
+   convert $CONVERT_OPTS_A $TEMPPATH/$this $HTMLPATH/${prefix}.png
+   convert $CONVERT_OPTS_B $TEMPPATH/$this $HTMLPATH/${prefix}B.png
+   touch $HTMLPATH/${prefix}.png $HTMLPATH/${prefix}B.png
+done
+
+# Update timestamp
+
+touch $HTMLPATH/index.shtml
+
+# if this was called as a cgi script, it should redirect to the index.shtml file
+if [ -n "$REMOTE_HOST" ]
+then
+   REL_HTML=${HTMLPATH#$HTMLROOT}
+   echo "Location: $REL_HTML/index.shtml"
+   echo
+fi
+
+if [ -z "$DEBUG" ]
+then
+   rm -rf $TEMPPATH
+fi   
+
+exit 0
Index: /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/gather.sh
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/gather.sh	(revision 4900)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/gather.sh	(revision 4900)
@@ -0,0 +1,143 @@
+#!/bin/bash
+#
+#    gather.sh
+#	gather the data.
+#	run from cron every 5 minutes.
+#	Don't run manually as root or else files in data/ will get
+#	root ownership then your (non-root) cron daemon won't work
+#
+#    Copyright (C) 2001  Philip Edelbrock
+#
+#    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# generic tellerstats init BEGIN
+
+# get config information from /etc/tellerstats.conf or whereever we are pointed
+
+if [ -z "$TELLERSTATS_CONF" ]
+then
+   TELLERSTATS_CONF=/etc/tellerstats.conf
+fi   
+
+export TELLERSTATS_CONF
+
+if [ ! -r $TELLERSTATS_CONF ]
+then
+   echo "$0: Could not find config file $TELLERSTATS_CONF"
+   exit 1
+fi   
+
+. $TELLERSTATS_CONF
+
+if [ ! -d $DBPATH ]
+then
+   echo "$0: data directory $DBPATH does not exist"
+   exit 1
+fi
+
+if [ ! -d $SENSORPATH ]
+then
+   echo "$0: sensor information directory $SENSORPATH does not exist."
+   exit 1
+fi
+
+if [ ! -d $HTMLROOT ]
+then
+   echo "$0: The root of your webserver - $HTMLROOT - does not exist..bailing out"
+   exit 1
+fi
+
+if [ ! -d $HTMLPATH ]
+then
+   echo "$0: The place where we keep HTML files and pictures - $HTMLPATH - does not exist..bailing out"
+   exit 1
+fi
+
+if [ ! -r $GNUPLOTSCRIPT_TMPL ]
+then
+   echo "$0: The gnuplot script template $GNUPLOTSCRIPT_TMPL does not exist..bailing out"
+   exit 1
+fi
+
+export DBPATH SENSORPATH TEMPPATH HTMLROOT HTMLPATH GNUPLOTSCRIPT_TMPL
+
+if [ -n "$DEBUG" ]
+then
+   echo "DBPATH = $DBPATH"
+   echo "SENSORPATH = $SENSORPATH"
+   echo "TEMPPATH = $TEMPPATH"
+   echo "HTMLROOT = $HTMLROOT"
+   echo "HTMLPATH = $HTMLPATH"
+   echo "GNUPLOTSCRIPT_TMPL = $GNUPLOTSCRIPT_TMPL"
+fi
+
+# generic tellerstats init END
+
+# From /etc/sensors.conf for the W83781D:
+#
+#    compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+#    compute in4 ((28/10)+1)*@  ,  @/((28/10)+1)
+#    compute in5 -(210/60.4)*@  ,  -@/(210/60.4)
+#    compute in6 -(90.9/60.4)*@ ,  -@/(90.9/60.4)
+#
+
+#date=yyyyMMddHHmmss, the same format gnuplot expects for the x-axis
+DATE=`date +%Y%m%d%H%M%S`
+
+T=`cat $SENSORPATH/in0   | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+echo $DATE $T >> $DBPATH/cpu1V
+
+T=`cat $SENSORPATH/in1   | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+echo $DATE $T >> $DBPATH/cpu2V
+
+T=`cat $SENSORPATH/in2   | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+echo $DATE $T >> $DBPATH/ThreeVOLT
+
+T=`cat $SENSORPATH/in3   | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+T=`echo $T \* 1.68 | bc`
+echo $DATE $T >> $DBPATH/FiveVOLT
+
+T=`cat $SENSORPATH/in4   | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+T=`echo $T \* 3.8 | bc`
+echo $DATE $T >> $DBPATH/TwelveVOLT
+
+T=`cat $SENSORPATH/in5   | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+T=`echo $T \* -3.477 | bc`
+echo $DATE $T >> $DBPATH/NegTwelveVOLT
+
+T=`cat $SENSORPATH/in6   | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+T=`echo $T \* -1.505 | bc`
+echo $DATE $T >> $DBPATH/NegFiveVOLT
+
+T=`cat $SENSORPATH/temp1 | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+echo $DATE $T >> $DBPATH/mb_temp
+
+T=`cat $SENSORPATH/temp2 | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+echo $DATE $T >> $DBPATH/cpu_temp
+
+T=`cat $SENSORPATH/fan1  | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+echo $DATE $T >> $DBPATH/fanone
+
+T=`cat $SENSORPATH/fan2  | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+echo $DATE $T >> $DBPATH/fantwo
+
+T=`cat $SENSORPATH/fan3  | perl -p -e 's/^.+ ([^ ]+)$/$1/'`
+echo $DATE $T >> $DBPATH/fanthree
+
+T=`cat /proc/loadavg     | perl -p -e 's/^([^ ]+) .+$/$1/'`
+echo $DATE $T >> $DBPATH/load
+
+exit 0
Index: /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/gnuplotscript.tmpl
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/gnuplotscript.tmpl	(revision 1051)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/gnuplotscript.tmpl	(revision 1051)
@@ -0,0 +1,79 @@
+set term $PLOTTERMINAL
+set timefmt "%Y%m%d%H%M%S"
+set notime
+set autoscale xy
+set size 2,2
+set data style lp
+set xlabel "Time"
+set xdata time
+
+set ylabel "Voltage (V)"
+
+set output "$TEMPPATH/cpu1V.$PLOTFORMAT"
+plot "$DBPATH/cpu1V"         using 1:2 title ''     w lp lw $LINEWIDTH, \
+     2.1                               title 'min'  w lp lw $LINEWIDTH, \
+     2.3                               title 'max'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/cpu2V.$PLOTFORMAT"
+plot "$DBPATH/cpu2V"         using 1:2 title ''     w lp lw $LINEWIDTH, \
+     2.1                               title 'min'  w lp lw $LINEWIDTH, \
+     2.3                               title 'max'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/ThreeVOLT.$PLOTFORMAT"
+plot "$DBPATH/ThreeVOLT"     using 1:2 title ''     w lp lw $LINEWIDTH, \
+     3.0                               title 'min'  w lp lw $LINEWIDTH, \
+     3.6                               title 'max'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/FiveVOLT.$PLOTFORMAT"
+plot "$DBPATH/FiveVOLT"      using 1:2 title ''     w lp lw $LINEWIDTH, \
+     4.85                              title 'min'  w lp lw $LINEWIDTH, \
+     5.15                              title 'max'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/TwelveVOLT.$PLOTFORMAT"
+plot "$DBPATH/TwelveVOLT"    using 1:2 title ''     w lp lw $LINEWIDTH, \
+     11.3                              title 'min'  w lp lw $LINEWIDTH, \
+     12.7                              title 'max'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/NegTwelveVOLT.$PLOTFORMAT"
+plot "$DBPATH/NegTwelveVOLT" using 1:2 title ''     w lp lw $LINEWIDTH, \
+     -12.7                             title 'min'  w lp lw $LINEWIDTH, \
+     -11.3                             title 'max'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/NegFiveVOLT.$PLOTFORMAT"
+plot "$DBPATH/NegFiveVOLT"   using 1:2 title ''     w lp lw $LINEWIDTH, \
+     -5.25                             title 'min'  w lp lw $LINEWIDTH, \
+     -4.75                             title 'max'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/voltages.$PLOTFORMAT"
+plot "$DBPATH/cpu1V"         using 1:2 title '1V'   w lp lw $LINEWIDTH,\
+     "$DBPATH/cpu2V"         using 1:2 title '2V'   w lp lw $LINEWIDTH,\
+     "$DBPATH/ThreeVOLT"     using 1:2 title '3V'   w lp lw $LINEWIDTH,\
+     "$DBPATH/FiveVOLT"      using 1:2 title '5V'   w lp lw $LINEWIDTH,\
+     "$DBPATH/TwelveVOLT"    using 1:2 title '12V'  w lp lw $LINEWIDTH,\
+     "$DBPATH/NegTwelveVOLT" using 1:2 title '-12V' w lp lw $LINEWIDTH,\
+     "$DBPATH/NegFiveVOLT"   using 1:2 title '-5V'  w lp lw $LINEWIDTH
+
+set ylabel "Temperature (Degree C)"
+
+set output "$TEMPPATH/mb_temp.$PLOTFORMAT"
+plot "$DBPATH/mb_temp"       using 1:2 title ''     w lp lw $LINEWIDTH, \
+     50                                title 'max'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/cpu_temp.$PLOTFORMAT"
+plot "$DBPATH/cpu_temp"      using 1:2 title ''     w lp lw $LINEWIDTH, \
+     50                                title 'max'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/temps.$PLOTFORMAT"
+plot "$DBPATH/mb_temp"       using 1:2 title 'motherboard' w lp lw $LINEWIDTH, \
+     "$DBPATH/cpu_temp"      using 1:2 title 'CPU'  w lp lw $LINEWIDTH
+
+set ylabel "Fan Speed (RPM)"
+
+set output "$TEMPPATH/fanone.$PLOTFORMAT"
+plot "$DBPATH/fanone"        using 1:2 title ''     w lp lw $LINEWIDTH, \
+     3000                              title 'min'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/fantwo.$PLOTFORMAT"
+plot "$DBPATH/fantwo"        using 1:2 title ''     w lp lw $LINEWIDTH, \
+     3000                              title 'min'  w lp lw $LINEWIDTH
+set output "$TEMPPATH/fanthree.$PLOTFORMAT"
+plot "$DBPATH/fanthree"      using 1:2 title ''     w lp lw $LINEWIDTH, \
+     3000                              title 'min'  w lp lw $LINEWIDTH
+
+set ylabel "Load Average"
+
+set output "$TEMPPATH/load.$PLOTFORMAT"
+plot "$DBPATH/load"          using 1:2 title ''     w lp lw $LINEWIDTH
+
+exit
+
Index: /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/tellerstats.conf
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/tellerstats.conf	(revision 1051)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/tellerstats.conf	(revision 1051)
@@ -0,0 +1,30 @@
+# this is the tellerstats config file. Please be sure to
+# edit these for your setup!!!
+
+
+# where we keep the log of sensor data
+DBPATH="/var/local/LM78DB/data"
+
+# where we get the sensor data from
+SENSORPATH="/proc/sys/dev/sensors/w83781d-isa-0290"
+
+# where temporary plots and files are kept
+TEMPPATH="/usr/tmp/lm78plots"
+
+# the root of the webserver
+HTMLROOT="/home/httpd/html"
+
+# where all the web-visible files are
+HTMLPATH="$HTMLROOT/tellerstats"
+
+# the template of the gnuplot script
+GNUPLOTSCRIPT_TMPL=/usr/local/install/tellerstats/gnuplotscript.tmpl
+
+# linewidth of the plots
+LINEWIDTH=5
+
+# format (fileextensions) for primary plots
+PLOTFORMAT=ps
+# terminal and options for primary plots (should match above) as give to gnuplot. 
+# Please see gnuplot online help for "set terminal"
+PLOTTERMINAL="postscript eps enhanced color \"Helvetica\" 22"
Index: /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/README
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/README	(revision 3075)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/README	(revision 3075)
@@ -0,0 +1,44 @@
+This is tellerstats Version 1.9.2
+
+
+Author: Phil Edelbrock <phil@netroedge.com>
+with Changes by 
+   Mark D. Studebaker <mdsxyz123@yahoo.com> and
+   Hans Ecke <hans@ecke.ws>
+
+
+Required Utilities and Packages:
+
+	apache or other web server
+
+	'convert' from ImageMagick or X11
+		http://www.imagemagick.org
+
+	'bc' command line calculator
+
+	gnuplot
+		http://www.gnuplot.org
+
+	lm_sensors
+
+	perl
+
+
+Follow those steps to install tellerstats:
+
+
+* Put the following line into your /etc/crontab file
+
+       */5 * * * * root /usr/local/install/tellerstats/gather.sh
+       
+  (change the directory to reflect where you installed gather.sh)     
+
+* Link tellerstats.sh to /etc/cron.hourly/tellerstats.sh
+
+* move index.shtml into a directory accessible with a webbrowser
+  and configure your webserver for SSI (server side includes)
+ 
+* move tellerstats.conf to /etc and edit it to reflect correct directories
+
+
+
Index: /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/index.shtml
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/index.shtml	(revision 4157)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/tellerstats/index.shtml	(revision 4157)
@@ -0,0 +1,48 @@
+<html>
+<META HTTP-EQUIV="expires" CONTENT="300">
+<META HTTP-EQUIV="Refresh" CONTENT="3600;URL=http:index.shtml">
+<title>Computer Hardware Statistics</title>
+<body bgcolor=FFFFFF>
+
+<center><font size=5>Computer Hardware Statistics</font><br>
+<font size=4>Running 48 Hour Window</font><p>
+
+<!--#config timefmt="%c" -->
+These plots were generated <!--#echo var="LAST_MODIFIED" -->
+<br>
+
+<table border=2>
+<tr>
+<td valign=center align=center><a href=voltagesB.png><img src=voltages.png width=320 height=240><br>All Voltages</a></td>
+<td valign=center align=center><a href=tempsB.png><img src=temps.png width=320 height=240><br>All Temps</td>
+<td valign=center align=center><a href=loadB.png><img src=load.png width=320 height=240><br>System Loading</td>
+</tr>
+<tr>
+<td valign=center align=center><a href=TwelveVOLTB.png><img src=TwelveVOLT.png width=320 height=240><br>+12 Volt Supply</td>
+<td valign=center align=center><a href=NegFiveVOLTB.png><img src=NegFiveVOLT.png width=320 height=240><br>-5 Volt Supply</td>
+<td valign=center align=center><a href=NegTwelveVOLTB.png><img src=NegTwelveVOLT.png width=320 height=240><br>-12 Volt Supply</td>
+</tr>
+<tr>
+<td valign=center align=center><a href=cpu1VB.png><img src=cpu1V.png width=320 height=240><br>CPU1 Core Voltage</td>
+<td valign=center align=center><a href=cpu2VB.png><img src=cpu2V.png width=320 height=240><br>CPU2 Core Voltage</td>
+<td valign=center align=center><a href=ThreeVOLTB.png><img src=ThreeVOLT.png width=320 height=240><br>+3.3 Volt Supply</td>
+</tr>
+<tr>
+<td valign=center align=center><a href=FiveVOLTB.png><img src=FiveVOLT.png width=320 height=240><br>+5 Volt Supply</td>
+<td valign=center align=center><a href=cpu_tempB.png><img src=cpu_temp.png width=320 height=240><br>CPU Temperature (degrees C)</td>
+<td valign=center align=center><a href=mb_tempB.png><img src=mb_temp.png width=320 height=240><br>Motherboard Temperature (degrees C)</td>
+</tr>
+<tr>
+<td valign=center align=center><a href=fanoneB.png><img src=fanone.png width=320 height=240><br>Fan #1 Speed (RPM)</td>
+<td valign=center align=center><a href=fantwoB.png><img src=fantwo.png width=320 height=240><br>Fan #2 Speed (RPM)</td>
+<td valign=center align=center><a href=fanthreeB.png><img src=fanthree.png width=320 height=240><br>Fan #3 Speed (RPM)</td>
+</tr>
+</table><p>
+
+This page generated with drivers and the tellerstats scripts from
+<a href="http://www.lm-sensors.org/">The lm_sensors drivers</a>.
+
+<p>
+
+</body>
+</html>
Index: /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_update_rrd
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_update_rrd	(revision 4372)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_update_rrd	(revision 4372)
@@ -0,0 +1,101 @@
+#!/bin/sh
+#
+#    sens_update_rrd -
+#	Update a sensors rrd database.
+#	Sample usage:
+#		sens_update_rrd /var/lib/database.rrd hwmon0
+#	Sample cron entry:
+#		*/5 * * * * /usr/local/bin/sens_update_rrd /var/lib/sensors-rrd/sensors.rrd hwmon0
+#
+#################################################################
+#
+#    Copyright 2001,2005 Mark D. Studebaker <mdsxyz123@yahoo.com>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#################################################################
+#
+if [ $# -lt 1 -o $# -gt 2 ]
+then
+	echo "usage: $0 database.rrd [hwmonN]"
+	exit 1
+elif [ $# -eq 2 ]
+then
+	HWMON=$2
+else
+	HWMON=hwmon0
+fi
+#
+RRDPATH=/usr/bin
+RRDB=$1
+
+SENSDIR=/sys/class/hwmon
+SENS=$SENSDIR/$HWMON/device
+
+if [ ! -d $SENS ]
+then
+	echo "No sensors found in: $SENS"
+	echo "(modprobe sensor modules?)"
+	exit 1
+fi
+
+STRING=N
+#
+# Get the value from these sensor files (/sys)
+#
+SENSORS="fan1 fan2 fan3"
+for i in $SENSORS
+do
+	V="`cat $SENS/${i}_input 2> /dev/null`"
+	if [ $? -ne 0 ]
+	then
+		STRING="${STRING}:U"
+	else
+		STRING="${STRING}:${V}"
+	fi
+done
+#
+# Get the value from these sensor files (/sys) and divide by 1000
+#
+SENSORS="temp1 temp2 temp3 in0 in1 in2 in3 in4 in5 in6"
+for i in $SENSORS
+do
+	V="`cat $SENS/${i}_input 2> /dev/null`"
+	if [ $? -ne 0 ]
+	then
+		STRING="${STRING}:U"
+	else
+		V=`echo "3k0 ${V/-/_} 1000/p"|dc`
+		STRING="${STRING}:${V}"
+	fi
+done
+
+#
+# Get the first value from these /proc files
+#
+SENSORS="loadavg"
+for i in $SENSORS
+do
+	V="`cat /proc/$i 2> /dev/null`"
+	if [ $? -ne 0 ]
+	then
+		STRING="${STRING}:U"
+	else
+		V="`echo $V | cut -d ' ' -f 1`"
+		STRING="${STRING}:${V}"
+	fi
+done
+
+$RRDPATH/rrdtool update $RRDB $STRING
Index: /lm-sensors/tags/V3-0-0-RC2/prog/rrd/summ_week.in
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/rrd/summ_week.in	(revision 4372)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/rrd/summ_week.in	(revision 4372)
@@ -0,0 +1,103 @@
+#!%%RRDPATH%%/rrdcgi 
+
+<HTML>
+<HEAD>
+<TITLE>One Week Summary Hardware Statistics for %%MACH%%</TITLE>
+</HEAD>
+<BODY>
+<H1>ONE WEEK SUMMARY VIEW</H1>
+See also: <br>
+<a href="sens_day.cgi">One Day View</a> <br>
+<a href="sens_week.cgi">One Week View</a> <br>
+
+<H1>TEMPERATURES</H1>
+
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/tempall.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Temperature (degrees C); Load Avg * 10"
+	-t "Temperatures and Load Average"
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 5:10
+	DEF:temp=%%RRDDIR%%/sensors.rrd:temp1:AVERAGE
+	DEF:ttemp=%%RRDDIR%%/sensors.rrd:temp2:AVERAGE
+	DEF:la=%%RRDDIR%%/sensors.rrd:loadavg:AVERAGE
+	CDEF:lla=10,la,*
+	LINE2:ttemp#FF0000:"CPU Temp"
+	LINE2:temp#FF00FF:"Motherboard Temp"
+	LINE2:lla#00FFFF:"Load Average * 10">
+</P>
+
+
+<H1>FANS</H1>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/fanall.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Fan speed (RPM)"
+	-t "Fan speeds"
+	-u 5000
+	--units-exponent 0
+	--alt-autoscale
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	DEF:f1=%%RRDDIR%%/sensors.rrd:fan1:AVERAGE
+	DEF:f2=%%RRDDIR%%/sensors.rrd:fan2:AVERAGE
+	DEF:f3=%%RRDDIR%%/sensors.rrd:fan3:AVERAGE
+	LINE2:f1#FF00FF:"Fan 1"
+	LINE2:f2#FF0000:"Fan 2"
+	LINE2:f3#00FFFF:"Fan 3">
+</P>
+
+<H1>POWER SUPPLIES</H1>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/inall.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Volts"
+	-t "All Power Supplies"
+	-l -15 -u 15 --rigid
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 1:5
+	DEF:i0=%%RRDDIR%%/sensors.rrd:in0:AVERAGE
+	DEF:i1=%%RRDDIR%%/sensors.rrd:in1:AVERAGE
+	DEF:i2=%%RRDDIR%%/sensors.rrd:in2:AVERAGE
+	DEF:i3=%%RRDDIR%%/sensors.rrd:in3:AVERAGE
+	DEF:i4=%%RRDDIR%%/sensors.rrd:in4:AVERAGE
+	DEF:i5=%%RRDDIR%%/sensors.rrd:in5:AVERAGE
+	DEF:i6=%%RRDDIR%%/sensors.rrd:in6:AVERAGE
+	CDEF:ii3=1.68,i3,*
+	CDEF:ii4=3.8,i4,*
+	CDEF:ii5=-3.48,i5,*
+	CDEF:ii6=-1.5,i6,*
+	LINE2:ii4#00FF00:"+12V"
+	LINE2:ii3#FF0000:"+5V"
+	LINE2:i2#FF8000:"+3.3V"
+	LINE2:i0#FF00FF:"Core 1"
+	LINE2:i1#00FFFF:"Core 2"
+	LINE2:ii6#FF0080:"-5V"
+	LINE2:ii5#0000FF:"-12V">
+</P>
+
+This page generated with data and scripts from
+<a href="http://www.lm-sensors.org/">the lm_sensors project</a>;
+the data are stored in a Round Robin Database and
+the graphs are generated by
+<a href="http://oss.oetiker.ch/rrdtool/">
+RRD</a>.
+
+</BODY>
+</HTML>
+
+
+
+
Index: /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_create_rrd
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_create_rrd	(revision 4372)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_create_rrd	(revision 4372)
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+#    sens_create_rrd -
+#	Create a sensors rrd database of 14 sensor readings
+#	at 5 minute intervals for 1 week.
+#
+#    Copyright 2001 Mark D. Studebaker <mdsxyz123@yahoo.com>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+RRDPATH=/usr/bin
+RRDB=$1
+#Heartbeat 15 minutes
+HB=900
+#Rows 12 * 24 * 7 = 1 week of every 5 minutes
+RW=2016
+
+if [ $# -ne 1 ]
+then
+	echo usage: $0 database.rrd
+	exit 1
+fi
+
+DIR=`dirname $1`
+if [ ! -w $DIR ]
+then
+	echo $0: directory $DIR not present or not writable
+	exit 1
+fi
+
+$RRDPATH/rrdtool create $RRDB --step 300 \
+	DS:fan1:GAUGE:${HB}:0:12000 \
+	DS:fan2:GAUGE:${HB}:0:12000 \
+	DS:fan3:GAUGE:${HB}:0:12000 \
+	DS:temp1:GAUGE:${HB}:-25:250 \
+	DS:temp2:GAUGE:${HB}:-25:250 \
+	DS:temp3:GAUGE:${HB}:-25:250 \
+	DS:in0:GAUGE:${HB}:-25:25 \
+	DS:in1:GAUGE:${HB}:-25:25 \
+	DS:in2:GAUGE:${HB}:-25:25 \
+	DS:in3:GAUGE:${HB}:-25:25 \
+	DS:in4:GAUGE:${HB}:-25:25 \
+	DS:in5:GAUGE:${HB}:-25:25 \
+	DS:in6:GAUGE:${HB}:-25:25 \
+	DS:loadavg:GAUGE:${HB}:0:U \
+	RRA:AVERAGE:0.5:1:$RW
+
Index: /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_week.in
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_week.in	(revision 4372)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_week.in	(revision 4372)
@@ -0,0 +1,231 @@
+#!%%RRDPATH%%/rrdcgi 
+
+<HTML>
+<HEAD>
+<TITLE>One Week Hardware Statistics for %%MACH%%</TITLE>
+</HEAD>
+<BODY>
+<H1>ONE WEEK VIEW</H1>
+See also: <br>
+<a href="sens_day.cgi">One Day View</a> <br>
+<a href="summ_week.cgi">One Week Summary View</a>
+
+<H1>TEMPERATURES</H1>
+
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/temp1.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Temperature (degrees C)"
+	-t "Motherboard temperature"
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 1:5
+	DEF:temp=%%RRDDIR%%/sensors.rrd:temp1:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/temp2.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Temperature (degrees C)"
+	-t "CPU 1 temperature"
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 1:5
+	DEF:temp=%%RRDDIR%%/sensors.rrd:temp2:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/temp3.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Temperature (degrees C)"
+	-t "CPU 2 temperature"
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 1:5
+	DEF:temp=%%RRDDIR%%/sensors.rrd:temp3:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<H1>FANS</H1>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/fan1.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Fan speed (RPM)"
+	-t "Fan 1 speed"
+	-u 5000
+	--units-exponent 0
+	--alt-autoscale
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	DEF:temp=%%RRDDIR%%/sensors.rrd:fan1:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/fan2.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Fan speed (RPM)"
+	-t "Fan 2 speed"
+	-u 5000
+	--units-exponent 0
+	--alt-autoscale
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	DEF:temp=%%RRDDIR%%/sensors.rrd:fan2:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/fan3.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Fan speed (RPM)"
+	-t "Fan 3 speed"
+	-u 5000
+	--units-exponent 0
+	--alt-autoscale
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	DEF:temp=%%RRDDIR%%/sensors.rrd:fan3:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<H1>POWER SUPPLIES</H1>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in0.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Volts"
+	-t "Core 1 Voltage"
+	-l 1 -u 3 --rigid
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 0.2:1
+	DEF:temp=%%RRDDIR%%/sensors.rrd:in0:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in1.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Volts"
+	-t "Core 2 Voltage"
+	-l 1 -u 3 --rigid
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 0.2:1
+	DEF:temp=%%RRDDIR%%/sensors.rrd:in1:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in2.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Volts"
+	-t "+3.3 Volt Supply"
+	-l 2 -u 4 --rigid
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 0.2:1
+	DEF:temp=%%RRDDIR%%/sensors.rrd:in2:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in3.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Volts"
+	-t "+5 Volt Supply"
+	-l 4 -u 6 --rigid
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 0.2:1
+	DEF:x=%%RRDDIR%%/sensors.rrd:in3:AVERAGE
+	CDEF:temp=1.68,x,*
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in4.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Volts"
+	-t "+12 Volt Supply"
+	-l 10 -u 14
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 1:1
+	DEF:x=%%RRDDIR%%/sensors.rrd:in4:AVERAGE
+	CDEF:temp=3.8,x,*
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in5.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Volts"
+	-t "-12 Volt Supply"
+	-l -14 -u -10
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 1:1
+	DEF:x=%%RRDDIR%%/sensors.rrd:in5:AVERAGE
+	CDEF:temp=-3.48,x,*
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in6.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1week
+	-v "Volts"
+	-t "-5 Volt Supply"
+	-l -6 -u -4 --rigid
+	-x HOUR:6:DAY:1:DAY:1:86400:'%a %b %d'
+	-y 0.2:1
+	DEF:x=%%RRDDIR%%/sensors.rrd:in6:AVERAGE
+	CDEF:temp=-1.5,x,*
+	LINE2:temp#FF00FF>
+</P>
+
+This page generated with data and scripts from
+<a href="http://www.lm-sensors.org/">the lm_sensors project</a>;
+the data are stored in a Round Robin Database and
+the graphs are generated by
+<a href="http://oss.oetiker.ch/rrdtool/">
+RRD</a>.
+
+</BODY>
+</HTML>
+
+
+
+
Index: /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_day.in
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_day.in	(revision 4372)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/rrd/sens_day.in	(revision 4372)
@@ -0,0 +1,231 @@
+#!%%RRDPATH%%/rrdcgi 
+
+<HTML>
+<HEAD>
+<TITLE>One Day Hardware Statistics for %%MACH%%</TITLE>
+</HEAD>
+<BODY>
+<H1>ONE DAY VIEW</H1>
+See also: <br>
+<a href="sens_week.cgi">One Week View</a> <br>
+<a href="summ_week.cgi">One Week Summary View</a>
+
+<H1>TEMPERATURES</H1>
+
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/temp1d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Temperature (degrees C)"
+	-t "Motherboard temperature"
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 1:5
+	DEF:temp=%%RRDDIR%%/sensors.rrd:temp1:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/temp2d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Temperature (degrees C)"
+	-t "CPU 1 temperature"
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 1:5
+	DEF:temp=%%RRDDIR%%/sensors.rrd:temp2:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/temp3d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Temperature (degrees C)"
+	-t "CPU 2 temperature"
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 1:5
+	DEF:temp=%%RRDDIR%%/sensors.rrd:temp3:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<H1>FANS</H1>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/fan1d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Fan speed (RPM)"
+	-t "Fan 1 speed"
+	-u 5000
+	--units-exponent 0
+	--alt-autoscale
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	DEF:temp=%%RRDDIR%%/sensors.rrd:fan1:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/fan2d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Fan speed (RPM)"
+	-t "Fan 2 speed"
+	-u 5000
+	--units-exponent 0
+	--alt-autoscale
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	DEF:temp=%%RRDDIR%%/sensors.rrd:fan2:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/fan3d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Fan speed (RPM)"
+	-t "Fan 3 speed"
+	-u 5000
+	--units-exponent 0
+	--alt-autoscale
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	DEF:temp=%%RRDDIR%%/sensors.rrd:fan3:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<H1>POWER SUPPLIES</H1>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in0d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Volts"
+	-t "Core 1 Voltage"
+	-l 1 -u 3 --rigid
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 0.2:1
+	DEF:temp=%%RRDDIR%%/sensors.rrd:in0:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in1d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Volts"
+	-t "Core 2 Voltage"
+	-l 1 -u 3 --rigid
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 0.2:1
+	DEF:temp=%%RRDDIR%%/sensors.rrd:in1:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in2d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Volts"
+	-t "+3.3 Volt Supply"
+	-l 2 -u 4 --rigid
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 0.2:1
+	DEF:temp=%%RRDDIR%%/sensors.rrd:in2:AVERAGE
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in3d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Volts"
+	-t "+5 Volt Supply"
+	-l 4 -u 6 --rigid
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 0.2:1
+	DEF:x=%%RRDDIR%%/sensors.rrd:in3:AVERAGE
+	CDEF:temp=1.68,x,*
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in4d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Volts"
+	-t "+12 Volt Supply"
+	-l 10 -u 14
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 0.5:1
+	DEF:x=%%RRDDIR%%/sensors.rrd:in4:AVERAGE
+	CDEF:temp=3.8,x,*
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in5d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Volts"
+	-t "-12 Volt Supply"
+	-l -14 -u -10
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 0.5:1
+	DEF:x=%%RRDDIR%%/sensors.rrd:in5:AVERAGE
+	CDEF:temp=-3.48,x,*
+	LINE2:temp#FF00FF>
+</P>
+
+<P><RRD::GRAPH %%APACHDIR%%/pix/in6d.png
+        --imginfo '<IMG SRC=pix/%s WIDTH=%lu HEIGHT=%lu >'
+	-a PNG
+	-h 200 -w 800
+	--lazy
+	-s -1days
+	-v "Volts"
+	-t "-5 Volt Supply"
+	-l -6 -u -4 --rigid
+	-x HOUR:1:HOUR:3:HOUR:3:0:'%b %d %H:00'
+	-y 0.2:1
+	DEF:x=%%RRDDIR%%/sensors.rrd:in6:AVERAGE
+	CDEF:temp=-1.5,x,*
+	LINE2:temp#FF00FF>
+</P>
+
+This page generated with data and scripts from
+<a href="http://www.lm-sensors.org/">the lm_sensors project</a>;
+the data are stored in a Round Robin Database and
+the graphs are generated by
+<a href="http://oss.oetiker.ch/rrdtool/">
+RRD</a>.
+
+</BODY>
+</HTML>
+
+
+
+
Index: /lm-sensors/tags/V3-0-0-RC2/prog/rrd/Makefile
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/rrd/Makefile	(revision 4372)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/rrd/Makefile	(revision 4372)
@@ -0,0 +1,55 @@
+#
+# Edit the following for your setup
+#
+USER=apache
+# CRONTAB not used
+#CRONTAB=/var/spool/cron/tabs/$(USER)
+RRDPATH=/usr/bin
+BINPATH=/usr/local/bin
+RRDDIR=/var/lib/sensors-rrd
+APACHE=/var/www/html
+APACHDIR=$(APACHE)/senspix
+MACH=`uname -n`
+SENSDEV=hwmon0
+SENSDIR=/sys/class/hwmon/$(SENSDEV)/device
+################################################
+# Everything below here should be fine
+#
+RRDB=$(RRDDIR)/sensors.rrd
+
+all: sens_day.cgi sens_week.cgi summ_week.cgi $(SENSDIR)
+
+%.cgi : %.in Makefile
+	sed -e "s#%%RRDPATH%%#$(RRDPATH)#g;s#%%APACHDIR%%#$(APACHDIR)#g;s#%%RRDDIR%%#$(RRDDIR)#g;s#%%MACH%%#$(MACH)#g" $< > $@
+
+$(RRDDIR) :
+	install -d -o $(USER) $(RRDDIR)
+
+$(RRDB) : $(RRDDIR)
+	./sens_create_rrd $(RRDB)
+	chown $(USER) $(RRDB)
+	
+$(SENSDIR) :
+	$(error error - sensor $(SENSDEV) not installed - check SENSDEV definition in Makefile)
+
+$(CRONTAB) :
+	$(error error - crontab for user $(USER) not present - check CRONTAB definition in Makefile)
+
+$(APACHE) :
+	$(error error - Web server directory $(APACHE) not present - check APACHE definition in Makefile)
+
+$(APACHDIR)/pix : $(APACHE)
+	install -d -o $(USER) -m 777 $(APACHDIR)/pix
+
+install: all $(RRDB) $(SENSDIR) $(CRONTAB) $(APACHDIR)/pix
+	install -m 755 sens_update_rrd $(BINPATH)
+	install -m 755 sens_week.cgi $(APACHDIR)
+	install -m 755 sens_day.cgi $(APACHDIR)
+	install -m 755 summ_week.cgi $(APACHDIR)
+#	grep sens_update_rrd $(CRONTAB) > /dev/null 2>&1 || echo '*/5 * * * *	/usr/local/bin/sens_update_rrd' $(RRDB) $(SENSDEV) >> $(CRONTAB)
+	@echo
+	@echo Note!!! You must manually install the following line in the crontab for user $(USER):
+	@echo '   */5 * * * *    ' /usr/local/bin/sens_update_rrd $(RRDB) $(SENSDEV)
+
+clean:
+	rm -f sens_day.cgi sens_week.cgi summ_week.cgi
Index: /lm-sensors/tags/V3-0-0-RC2/prog/rrd/README
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/rrd/README	(revision 4372)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/rrd/README	(revision 4372)
@@ -0,0 +1,101 @@
+OVERVIEW
+--------
+This directory contains shell and cgi scripts which maintain a
+database of sensor data and generate web pages containing
+graphs of sensor data.
+
+The RRD (Round Robin Database) package is REQUIRED.
+Get this package from
+         http://oss.oetiker.ch/rrdtool/
+
+A web server with CGI support is required.
+
+We have provided these scripts because the RRD package,
+while simple to build and install, is rather difficult
+to configure to store and display data.
+
+RRD, together with lm_sensors and these scripts, provide the
+following advantages:
+	- True round-robin (constant-size) database
+	- On-the-fly graph generation with CGI scripts
+	- Multiple data views using single database
+	- Automatic time stamping, interpolation of missing data,
+	  large data dropouts (during machine downtime) correctly
+	  shown on graphs
+
+If you are looking for something a little simpler,
+that does not require RRD, try ../tellerstats.
+
+The RRD scripts read /sys entries and do not use libsensors.
+Therefore the scale factors in /etc/sensors.conf are not used,
+and you may have to change the scale factors in the cgi scripts.
+
+
+WARNING!
+--------
+The 'make install' script tries to make it easy for you but
+makes a lot of assumptions about your cron and web setup.
+If you have any concerns, do NOT run make install, and
+install the items by hand instead.
+
+
+INSTALLATION INSTRUCTIONS
+-------------------------
+
+	- Make and install lm_sensors. Get it working (run 'sensors')
+	  before you try this!
+	- Get RRD, make and install it
+	- Edit the top of the Makefile. Do NOT skip this step.
+	  The defaults will probably not work for you.
+	  Here are the defaults:
+		Cron user
+			USER=httpd
+		Path to rrdtool and rrdcgi
+			RRDPATH=/usr/bin
+		Place to install sens_update_rrd script
+			BINPATH=/usr/local/bin
+		Place to store the database
+			RRDDIR=/var/lib/sensors-rrd
+		Place to put the cgi script and the graphs
+			APACHE=/usr/local/apache/htdocs
+			APACHDIR=$(APACHE)/senspix
+		The sensor device in your system
+		(isa recommended over i2c if both are available)
+			SENSDEV=hwmon0           (look in /sys/class/hwmon)
+	- make
+	- (as root) make install, which does the following.
+	  If you don't want it to do this, install by hand!!!
+		Creates a database
+		Installs the data gathering script
+		Installs the CGI script in your web server
+	- Manually add the following line to the crontab for
+	  the user specified above, which will call the data gathering
+	  script every 5 minutes (adjust paths as necessary)
+		*/5 * * * *	/usr/local/bin/sens_update_rrd /var/lib/sensors-rrd/sensors.rrd hwmon0
+	- Load http://localhost/senspix/sens_day.cgi in your web browser
+		to test
+
+
+TROUBLESHOOTING
+---------------
+	RRD problems: See the RRD documentation
+
+	Cron problems: check the cron logs, maybe your cron format
+		is different or you need to signal the cron daemon?
+
+	Unused sensors: remove appropriate sections from sens_*.cgi.in
+		and remake and install.
+
+	Sensor scaling factors incorrect (in3-in6): Edit lines in
+		sens_*.cgi.in that start
+		'CDEF:' to change the scale factor.
+
+	CGI problems: Check the apache logs. If CGI is not enabled for
+		the directory add a .htaccess file to the directory
+		including the line
+			Options ExecCGI 
+
+	Removing the "RRDTOOL / TOBI OETIKER" tag in RRD graphs:
+		Comment out the line 
+			gator(gif, (int) im->xgif-5, 5);
+		in src/rrd_graph.c in the RRD package.
Index: /lm-sensors/tags/V3-0-0-RC2/prog/detect/sensors-detect
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/detect/sensors-detect	(revision 4930)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/detect/sensors-detect	(revision 4930)
@@ -0,0 +1,5873 @@
+#!/usr/bin/perl -w
+
+#
+#    sensors-detect - Detect PCI bus and chips
+#    Copyright (C) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>
+#    Copyright (C) 2004 - 2007  Jean Delvare <khali@linux-fr.org>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# TODO: Better handling of chips with several addresses
+
+# A Perl wizard really ought to look upon this; the PCI and I2C stuff should
+# each be put in a separate file, using modules and packages. That is beyond
+# me.
+
+require 5.004;
+
+use strict;
+use Fcntl;
+use POSIX;
+use File::Basename;
+
+# We will call modprobe, which typically lives in either /sbin,
+# /usr/sbin or /usr/local/bin. So make sure these are all in the PATH.
+foreach ('/usr/sbin', '/usr/local/sbin', '/sbin') {
+	$ENV{PATH} = "$_:".$ENV{PATH}
+		unless $ENV{PATH} =~ m/(^|:)$_\/?(:|$)/;
+}
+
+#########################
+# CONSTANT DECLARATIONS #
+#########################
+
+use vars qw(@pci_adapters @chip_ids $i2c_addresses_to_scan @superio_ids
+            @cpu_ids $revision);
+
+$revision = '$Revision$ ($Date$)';
+$revision =~ s/\$\w+: (.*?) \$/$1/g;
+$revision =~ s/ \([^()]*\)//;
+
+# This is the list of SMBus or I2C adapters we recognize by their PCI
+# signature. This is an easy and fast way to determine which SMBus or I2C
+# adapters should be present.
+# Each entry must have a vendid (Vendor ID), devid (Device ID) and
+# procid (string as appears in /proc/pci; see linux/driver/pci,
+# either pci.c or oldproc.c). If no driver is written yet, set the 
+# driver (Driver Name) field to "to-be-written".
+# The match (Match Description) field should contain a regular expression
+# matching the adapter name as it would appear in /proc/bus/i2c or /sys.
+@pci_adapters = ( 
+     { 
+       vendid => 0x8086,
+       devid  => 0x7113,
+       procid => "Intel 82371AB PIIX4 ACPI",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x7603,
+       procid => "Intel 82372FB PIIX5 ACPI",
+       driver => "to-be-tested",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x719b,
+       procid => "Intel 82443MX Mobile",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x2413,
+       procid => "Intel 82801AA ICH",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x2423,
+       procid => "Intel 82801AB ICH0",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x2443,
+       procid => "Intel 82801BA ICH2",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x2483,
+       procid => "Intel 82801CA/CAM ICH3",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x24C3,
+       procid => "Intel 82801DB ICH4",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x24D3,
+       procid => "Intel 82801EB ICH5",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x25A4,
+       procid => "Intel 6300ESB",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x269B,
+       procid => "Intel Enterprise Southbridge - ESB2",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     },
+     {
+       vendid => 0x8086,
+       devid  => 0x266A,
+       procid => "Intel 82801FB ICH6",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x27DA,
+       procid => "Intel 82801G ICH7",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x283E,
+       procid => "Intel 82801H ICH8",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     }, 
+     { 
+       vendid => 0x8086,
+       devid  => 0x2930,
+       procid => "Intel ICH9",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     },
+     { 
+       vendid => 0x8086,
+       devid  => 0x5032,
+       procid => "Intel Tolapai",
+       driver => "i2c-i801",
+       match => qr/^SMBus I801 adapter at [0-9a-f]{4}/,
+     },  
+     { 
+       vendid => 0x1106,
+       devid  => 0x3040,
+       procid => "VIA Technologies VT82C586B Apollo ACPI",
+       driver => "i2c-via",
+       match => qr/^VIA i2c/,
+     } ,
+     { 
+       vendid => 0x1106,
+       devid  => 0x3050,
+       procid => "VIA Technologies VT82C596 Apollo ACPI",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     { 
+       vendid => 0x1106,
+       devid  => 0x3051,
+       procid => "VIA Technologies VT82C596B ACPI",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     { 
+       vendid => 0x1106,
+       devid  => 0x3057,
+       procid => "VIA Technologies VT82C686 Apollo ACPI",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     { 
+       vendid => 0x1106,
+       devid  => 0x3074,
+       procid => "VIA Technologies VT8233 VLink South Bridge",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     { 
+       vendid => 0x1106,
+       devid  => 0x3147,
+       procid => "VIA Technologies VT8233A South Bridge",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     { 
+       vendid => 0x1106,
+       devid  => 0x3177,
+       procid => "VIA Technologies VT8233A/8235 South Bridge",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     {
+       vendid => 0x1106,
+       devid  => 0x3227,
+       procid => "VIA Technologies VT8237 South Bridge",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     {
+       vendid => 0x1106,
+       devid  => 0x3337,
+       procid => "VIA Technologies VT8237A South Bridge",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     { 
+       vendid => 0x1106,
+       devid  => 0x8235,
+       procid => "VIA Technologies VT8231 South Bridge",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     { 
+       vendid => 0x1106,
+       devid  => 0x3287,
+       procid => "VIA Technologies VT8251 South Bridge",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     } ,
+     {
+       vendid => 0x1106,
+       devid  => 0x8324,
+       procid => "VIA Technologies CX700 South Bridge",
+       driver => "i2c-viapro",
+       match => qr/^SMBus V(IA|ia) Pro adapter at/,
+     },
+     {
+       vendid => 0x1039,
+       devid  => 0x5597,
+       procid => "Silicon Integrated Systems SIS5581/5582/5597/5598 (To be written - Do not use 5595 drivers)",
+       driver => "to-be-written",
+     } ,
+     {
+       vendid => 0x1039,
+       devid  => 0x5598,
+       procid => "Silicon Integrated Systems SIS5598 (To be written - Do not use 5595 drivers)",
+       driver => "to-be-written",
+     } ,
+     {
+       vendid => 0x1039,
+       devid  => 0x0540,
+       procid => "Silicon Integrated Systems SIS540 (To be written - Do not use 5595 drivers)",
+       driver => "to-be-written",
+     } ,
+     {
+       vendid => 0x1039,
+       devid  => 0x0630,
+       procid => "Silicon Integrated Systems SIS630",
+       driver => "i2c-sis630",
+       match => qr/^SMBus SIS630 adapter at [0-9a-f]{4}/,
+     } ,
+     {
+       vendid => 0x1039,
+       devid  => 0x0730,
+       procid => "Silicon Integrated Systems SIS730",
+       driver => "i2c-sis630",
+       match => qr/^SMBus SIS630 adapter at [0-9a-f]{4}/,
+     } ,
+#
+# Both Ali chips below have same PCI ID. Can't be helped. Only one should load.
+#
+     {
+       vendid => 0x10b9,
+       devid => 0x7101,
+       procid => "Acer Labs 1533/1543",
+       driver => "i2c-ali15x3",
+       match => qr/^SMBus ALI15X3 adapter at/,
+     },
+     {
+       vendid => 0x10b9,
+       devid => 0x7101,
+       procid => "Acer Labs 1535",
+       driver => "i2c-ali1535",
+       match => qr/^SMBus ALI1535 adapter at/,
+     },
+     {
+       vendid => 0x10b9,
+       devid => 0x1563,
+       procid => "Acer Labs 1563",
+       driver => "i2c-ali1563",
+       match => qr/^SMBus ALi 1563 Adapter @/,
+     },
+     { 
+       vendid => 0x106b,
+       devid  => 0x000e,
+       procid => "Apple Computer Inc. Hydra Mac I/O",
+       driver => "i2c-hydra",
+       match => qr/^Hydra i2c/,
+     },
+     { 
+       vendid => 0x1022,
+       devid  => 0x740b,
+       procid => "AMD-756 Athlon ACPI",
+       driver => "i2c-amd756",
+       match => qr/^SMBus AMD756 adapter at [0-9a-f]{4}/,
+     },
+     { 
+       vendid => 0x1022,
+       devid  => 0x7413,
+       procid => "AMD-766 Athlon ACPI",
+       driver => "i2c-amd756",
+       match => qr/^SMBus AMD766 adapter at [0-9a-f]{4}/,
+     },
+     { 
+       vendid => 0x1022,
+       devid  => 0x7443,
+       procid => "AMD-768 System Management",
+       driver => "i2c-amd756",
+       match => qr/^SMBus AMD768 adapter at [0-9a-f]{4}/,
+     },
+     { 
+       vendid => 0x1022,
+       devid  => 0x746b,
+       procid => "AMD-8111 ACPI",
+       driver => "i2c-amd756",
+       match => qr/^SMBus AMD8111 adapter at [0-9a-f]{4}/,
+     },
+     { 
+       vendid => 0x1022,
+       devid  => 0x746a,
+       procid => "AMD-8111 SMBus 2.0",
+       driver => "i2c-amd8111",
+       match => qr/^SMBus2 AMD8111 adapter at [0-9a-f]{4}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x0519,
+       procid => "MGA 2064W [Millennium]",
+       driver => "i2c-matroxfb",
+       match  => qr/^DDC:fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x051a,
+       procid => "MGA 1064SG [Mystique]",
+       driver => "i2c-matroxfb",
+       match  => qr/^DDC:fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x051b,
+       procid => "MGA 2164W [Millennium II]",
+       driver => "i2c-matroxfb",
+       match  => qr/^DDC:fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x051e,
+       procid => "MGA 1064SG [Mystique] AGP",
+       driver => "i2c-matroxfb",
+       match  => qr/^DDC:fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x051f,
+       procid => "MGA 2164W [Millennium II] AGP",
+       driver => "i2c-matroxfb",
+       match  => qr/^DDC:fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x1000,
+       procid => "MGA G100 [Productiva]",
+       driver => "i2c-matroxfb",
+       match  => qr/^DDC:fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x1001,
+       procid => "MGA G100 [Productiva] AGP",
+       driver => "i2c-matroxfb",
+       match  => qr/^DDC:fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x0520,
+       procid => "MGA G200",
+       driver => "i2c-matroxfb",
+       match  => qr/^DDC:fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x0521,
+       procid => "MGA G200 AGP",
+       driver => "i2c-matroxfb",
+       match  => qr/^DDC:fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x102b,
+       devid  => 0x0525,
+       procid => "MGA G400 AGP",
+       driver => "i2c-matroxfb",
+       match  => qr/^(DDC,MAVEN):fb[0-9]{1,2}/,
+     },
+     {
+       vendid => 0x121a,
+       devid  => 0x0005,
+       procid => "3Dfx Voodoo3",
+       driver => "i2c-voodoo3",
+       match  => qr/^(I2C|DDC) Voodoo3\/Banshee adapter/,
+     },
+     {
+       vendid => 0x121a,
+       devid  => 0x0003,
+       procid => "3Dfx Voodoo Banshee",
+       driver => "i2c-voodoo3",
+       match  => qr/^(I2C|DDC) Voodoo3\/Banshee adapter/,
+     },
+     { 
+       vendid => 0x8086,
+       devid  => 0x7121,
+       procid => "Intel 82810 GMCH",
+       driver => "i2c-i810",
+       match => qr/^I810/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x7123,
+       procid => "Intel 82810-DC100 GMCH",
+       driver => "i2c-i810",
+       match => qr/^I810/ ,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x7125,
+       procid => "Intel 82810E GMCH",
+       driver => "i2c-i810",
+       match => qr/^I810/,
+     } , 
+     { 
+       vendid => 0x8086,
+       devid  => 0x1132,
+       procid => "Intel 82815 GMCH",
+       driver => "i2c-i810",
+       match => qr/^I810/,
+     } , 
+     {
+       vendid => 0x8086,
+       devid  => 0x2562,
+       procid => "Intel 82845G GMCH",
+       driver => "i2c-i810",
+       match => qr/^I810/,
+     },
+     {
+       vendid => 0x10de,
+       devid  => 0x01b4,
+       procid => "nVidia nForce SMBus",
+       driver => "i2c-amd756",
+       match => qr/^SMBus nVidia nForce adapter at [0-9a-f]{4}/,
+     } , 
+     { 
+       vendid => 0x10de,
+       devid  => 0x0064,
+       procid => "nVidia Corporation nForce2 SMBus (MCP)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     }, 
+     {
+       vendid => 0x10de,
+       devid  => 0x0084,
+       procid => "nVidia Corporation nForce2 Ultra 400 SMBus (MCP)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     }, 
+     {
+       vendid => 0x10de,
+       devid  => 0x00D4,
+       procid => "nVidia Corporation nForce3 Pro150 SMBus (MCP)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     }, 
+     {
+       vendid => 0x10de,
+       devid  => 0x00E4,
+       procid => "nVidia Corporation nForce3 250Gb SMBus (MCP)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     }, 
+     {
+       vendid => 0x10de,
+       devid  => 0x0052,
+       procid => "nVidia Corporation nForce4 SMBus (MCP)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     }, 
+     {
+       vendid => 0x10de,
+       devid => 0x0034,
+       procid => "nVidia Corporation nForce4 SMBus (MCP-04)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     },
+     {
+       vendid => 0x10de,
+       devid => 0x0264,
+       procid => "nVidia Corporation nForce4 SMBus (MCP51)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     },
+     {
+       vendid => 0x10de,
+       devid => 0x0368,
+       procid => "nVidia Corporation nForce4 SMBus (MCP55)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     },
+     {
+       vendid => 0x10de,
+       devid => 0x03eb,
+       procid => "nVidia Corporation nForce4 SMBus (MCP61)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     },
+     {
+       vendid => 0x10de,
+       devid => 0x0446,
+       procid => "nVidia Corporation nForce4 SMBus (MCP65)",
+       driver => "i2c-nforce2",
+       match => qr/^SMBus nForce2 adapter at /,
+     },
+     {
+       vendid => 0x1166,
+       devid  => 0x0200,
+       procid => "ServerWorks OSB4 South Bridge",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     { 
+       vendid => 0x1055,
+       devid  => 0x9463,
+       procid => "SMSC Victory66 South Bridge",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     { 
+       vendid => 0x1166,
+       devid  => 0x0201,
+       procid => "ServerWorks CSB5 South Bridge",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     { 
+       vendid => 0x1166,
+       devid  => 0x0203,
+       procid => "ServerWorks CSB6 South Bridge",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     {
+       vendid => 0x1166,
+       devid  => 0x0205,
+       procid => "ServerWorks HT-1000 South Bridge",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     },
+     { 
+       vendid => 0x1283,
+       devid  => 0x8172,
+       procid => "ITE 8172G MIPS/SH4 Support Chip",
+       driver => "i2c-adap-ite",
+       match => qr/^ITE IIC adapter/,
+     } , 
+     { 
+       vendid => 0x5333,
+       devid  => 0x8A22,
+       procid => "S3 Savage 4",
+       driver => "i2c-savage4",
+       match => qr/^I2C Savage4 adapter/,
+     } , 
+     { 
+       vendid => 0x5333,
+       devid  => 0x9102,
+       procid => "S3 Savage 2000",
+       driver => "i2c-savage4",
+       match => qr/^I2C Savage4 adapter/,
+     } , 
+     { 
+       vendid => 0x5333,
+       devid  => 0x8A25,
+       procid => "S3 ProSavage PM",
+       driver => "i2c-prosavage",
+       match => qr/^ProSavage I2C bus at /,
+     } , 
+     { 
+       vendid => 0x5333,
+       devid  => 0x8D04,
+       procid => "S3 ProSavage8",
+       driver => "i2c-prosavage",
+       match => qr/^ProSavage I2C bus at /,
+     } , 
+     { 
+       vendid => 0x1002,
+       devid  => 0x4353,
+       procid => "ATI Technologies Inc ATI SMBus",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     { 
+       vendid => 0x1002,
+       devid  => 0x4363,
+       procid => "ATI Technologies Inc ATI SMBus",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     { 
+       vendid => 0x1002,
+       devid  => 0x4372,
+       procid => "ATI Technologies Inc IXP SB400 SMBus Controller",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     { 
+       vendid => 0x1002,
+       devid  => 0x4385,
+       procid => "ATI Technologies Inc SB600 SMBus",
+       driver => "i2c-piix4",
+       match => qr/^SMBus PIIX4 adapter at /,
+     } , 
+     {
+       vendid => 0x100B,
+       devid => 0x0500,
+       procid => "SCx200 Bridge",
+       driver => "scx200_acb",
+       match => qr/^(NatSemi SCx200 ACCESS\.bus|SCx200 ACB\d+) /,
+     },
+     {
+       vendid => 0x100B,
+       devid => 0x0510,
+       procid => "SC1100 Bridge",
+       driver => "scx200_acb",
+       match => qr/^(NatSemi SCx200 ACCESS\.bus|SCx200 ACB\d+) /,
+     },
+     {
+       vendid => 0x100B,
+       devid => 0x002B,
+       procid => "CS5535 ISA bridge",
+       driver => "scx200_acb",
+       match => qr/^CS5535 ACB\d+ /,
+     },
+     {
+       vendid => 0x1022,
+       devid => 0x2090,
+       procid => "CS5536 [Geode companion] ISA",
+       driver => "scx200_acb",
+       match => qr/^CS553[56] ACB\d+ /,
+     },
+);
+
+# The following entries used to appear directly in @pci_adapters.
+# Because of the tendency of SiS chipsets to have their real PCI
+# IDs obscured, we have to qualify these with a custom detection
+# routine before we add them to the @pci_adapters list.
+#
+use vars qw(@pci_adapters_sis5595 @pci_adapters_sis645 @pci_adapters_sis96x);
+@pci_adapters_sis5595 = (
+     {
+       vendid => 0x1039,
+       devid  => 0x0008,
+       procid => "Silicon Integrated Systems SIS5595",
+       driver => "i2c-sis5595",
+       match => qr/^SMBus SIS5595 adapter at [0-9a-f]{4}/,
+     } ,
+);
+
+@pci_adapters_sis645 = (
+     {
+       vendid => 0x1039,
+       devid  => 0x0008,
+       procid => "Silicon Integrated Systems SIS5595",
+       driver => "i2c-sis645",
+       match => qr/^SiS645 SMBus adapter at [0-9a-f]{4}/,
+     } ,
+     {
+       vendid => 0x1039,
+       devid  => 0x0016,
+       procid => "Silicon Integrated Systems SMBus Controller",
+       driver => "i2c-sis645",
+       match => qr/^SiS645 SMBus adapter at 0x[0-9a-f]{4}/,
+     } ,
+     {
+       vendid => 0x1039,
+       devid  => 0x0018,
+       procid => "Silicon Integrated Systems 85C503/5513 (LPC Bridge)",
+       driver => "i2c-sis645",
+       match => qr/^SiS645 SMBus adapter at 0x[0-9a-f]{4}/,
+     } ,
+);
+
+@pci_adapters_sis96x = (
+     {
+       vendid => 0x1039,
+       devid  => 0x0016,
+       procid => "Silicon Integrated Systems SMBus Controller",
+       driver => "i2c-sis96x",
+       match => qr/^SiS96x SMBus adapter at 0x[0-9a-f]{4}/,
+     } ,
+);
+
+# This is a list of all recognized chips. 
+# Each entry must have the following fields:
+#  name: The full chip name
+#  driver: The driver name (without .o extension). Put in exactly
+#      "to-be-written" if it is not yet available. Put in exactly
+#      "not-a-sensor" if it is not a hardware monitoring chip.
+#      Put in exactly "use-isa-instead" if no i2c driver will be written.
+#  i2c_addrs (optional): For I2C chips, the range of valid I2C addresses to
+#      probe. Recommend avoiding 0x69 because of clock chips.
+#  i2c_detect (optional): For I2C chips, the function to call to detect
+#      this chip. The function should take two parameters: an open file
+#      descriptor to access the bus, and the I2C address to probe.
+#  isa_addrs (optional): For ISA chips, the range of valid port addresses to
+#      probe.
+#  isa_detect (optional): For ISA chips, the function to call to detect
+#      this chip. The function should take one parameter: the ISA address
+#      to probe.
+#  alias_detect (optional): For chips which can be both on the ISA and the
+#      I2C bus, a function which detectes whether two entries are the same.
+#      The function should take three parameters: The ISA address, the
+#      I2C bus number, and the I2C address.
+@chip_ids = (
+     {
+       name => "Myson MTP008",
+       driver => "mtp008",
+       i2c_addrs => [0x2c..0x2e], 
+       i2c_detect => sub { mtp008_detect(@_); },
+     } ,
+     {
+       name => "National Semiconductor LM78",
+       driver => "lm78",
+       i2c_addrs => [0x20..0x2f], 
+       i2c_detect => sub { lm78_detect(0, @_); },
+       isa_addrs => [0x290],
+       isa_detect => sub { lm78_isa_detect(0, @_); },
+       alias_detect => sub { lm78_alias_detect(0, @_); },
+     } ,
+     {
+       name => "National Semiconductor LM78-J",
+       driver => "lm78",
+       i2c_addrs => [0x20..0x2f], 
+       i2c_detect => sub { lm78_detect(1, @_); },
+       isa_addrs => [0x290],
+       isa_detect => sub { lm78_isa_detect(1, @_); },
+       alias_detect => sub { lm78_alias_detect(1, @_); },
+     } ,
+     {
+       name => "National Semiconductor LM79",
+       driver => "lm78",
+       i2c_addrs => [0x20..0x2f], 
+       i2c_detect => sub { lm78_detect(2, @_); },
+       isa_addrs => [0x290],
+       isa_detect => sub { lm78_isa_detect(2, @_); },
+       alias_detect => sub { lm78_alias_detect(2, @_); },
+     } ,
+     {
+       name => "National Semiconductor LM75",
+       driver => "lm75",
+       i2c_addrs => [0x48..0x4f],
+       i2c_detect => sub { lm75_detect(0, @_); },
+     },
+     {
+       name => "Dallas Semiconductor DS75",
+       driver => "lm75",
+       i2c_addrs => [0x48..0x4f],
+       i2c_detect => sub { lm75_detect(1, @_); },
+     },
+     {
+       name => "National Semiconductor LM77",
+       driver => "lm77",
+       i2c_addrs => [0x48..0x4b],
+       i2c_detect => sub { lm77_detect(@_); },
+     },
+     {
+       name => "National Semiconductor LM80",
+       driver => "lm80",
+       i2c_addrs => [0x28..0x2f],
+       i2c_detect => sub { lm80_detect(@_); },
+     },
+     {
+       name => "National Semiconductor LM85 or LM96000",
+       driver => "lm85",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { lm85_detect(0x01, @_); },
+     },
+     {
+       name => "Analog Devices ADM1027, ADT7460 or ADT7463",
+       driver => "lm85",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { lm85_detect(0x41, @_); },
+     },
+     {
+       name => "SMSC EMC6D100, EMC6D101 or EMC6D102",
+       driver => "lm85",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { lm85_detect(0x5c, @_); },
+     },
+     {
+       name => "Analog Devices ADT7462",
+       driver => "to-be-written",
+       # The datasheet says addresses 0x5C and 0x58, but I guess these are
+       # left-aligned values
+       i2c_addrs => [0x2c, 0x2e],
+       i2c_detect => sub { adt7467_detect(2, @_); },
+     },
+     {
+       name => "Analog Devices ADT7466",
+       driver => "to-be-written",
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { adt7467_detect(3, @_); },
+     },
+     {
+       name => "Analog Devices ADT7467 or ADT7468",
+       driver => "to-be-written",
+       i2c_addrs => [0x2e],
+       i2c_detect => sub { adt7467_detect(0, @_); },
+     },
+     {
+       name => "Analog Devices ADT7470",
+       driver => "adt7470",
+       i2c_addrs => [0x2c, 0x2e, 0x2f],
+       i2c_detect => sub { adt7467_detect(4, @_); },
+     },
+     {
+       name => "Analog Devices ADT7473",
+       driver => "to-be-written",
+       i2c_addrs => [0x2e],
+       i2c_detect => sub { adt7473_detect(0, @_); },
+     },
+     {
+       name => "Analog Devices ADT7475",
+       driver => "to-be-written",
+       i2c_addrs => [0x2e],
+       i2c_detect => sub { adt7473_detect(1, @_); },
+     },
+     {
+       name => "Analog Devices ADT7476",
+       driver => "to-be-written",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { adt7467_detect(1, @_); },
+     },
+     {
+       name => "Andigilog aSC7511",
+       driver => "to-be-written",
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { andigilog_aSC7511_detect(0, @_); },
+     },
+     {
+       name => "Andigilog aSC7512",
+       driver => "to-be-written",
+       i2c_addrs => [0x58],
+       i2c_detect => sub { andigilog_detect(0, @_); },
+     },
+     {
+       name => "Andigilog aSC7611",
+       driver => "to-be-written",
+       i2c_addrs => [0x2c, 0x2d, 0x2e],
+       i2c_detect => sub { andigilog_detect(1, @_); },
+     },
+     {
+       name => "Andigilog aSC7621",
+       driver => "to-be-written",
+       i2c_addrs => [0x2c, 0x2d, 0x2e],
+       i2c_detect => sub { andigilog_detect(2, @_); },
+     },
+     {
+       name => "National Semiconductor LM87",
+       driver => "lm87",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { lm87_detect(@_); },
+     },
+     {
+       name => "National Semiconductor LM93",
+       driver => "lm93",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { lm93_detect(@_); },
+     },
+     {
+       name => "Winbond W83781D",
+       driver => "w83781d",
+       i2c_detect => sub { w83781d_detect(0, @_); },
+       i2c_addrs => [0x20..0x2f], 
+       isa_addrs => [0x290],
+       isa_detect => sub { w83781d_isa_detect(0, @_); },
+       alias_detect => sub { w83781d_alias_detect(0, @_); },
+     } ,
+     {
+       name => "Winbond W83782D",
+       driver => "w83781d",
+       i2c_addrs => [0x20..0x2f], 
+       i2c_detect => sub { w83781d_detect(1, @_); },
+       isa_addrs => [0x290],
+       isa_detect => sub { w83781d_isa_detect(1, @_); },
+       alias_detect => sub { w83781d_alias_detect(1, @_); },
+     } ,
+     {
+       name => "Winbond W83783S",
+       driver => "w83781d",
+       i2c_addrs => [0x2d],
+       i2c_detect => sub { w83781d_detect(2, @_); },
+     } ,
+     {
+       name => "Winbond W83792D",
+       driver => "w83792d",
+       i2c_addrs => [0x2c..0x2f],
+       i2c_detect => sub { w83781d_detect(8, @_); },
+     },
+     {
+       name => "Winbond W83793R/G",
+       driver => "w83793",
+       i2c_addrs => [0x2c..0x2f],
+       i2c_detect => sub { w83793_detect(0, @_); },
+     },
+     {
+       name => "Winbond W83791SD",
+       driver => "not-a-sensor",
+       i2c_addrs => [0x2c..0x2f],
+       i2c_detect => sub { w83791sd_detect(@_); },
+     },
+     {
+       name => "Winbond W83627HF",
+       driver => "use-isa-instead",
+       i2c_addrs => [0x28..0x2f],
+       i2c_detect => sub { w83781d_detect(3, @_); },
+     },
+     {
+       name => "Winbond W83627EHF",
+       driver => "use-isa-instead",
+       i2c_addrs => [0x28..0x2f], 
+       i2c_detect => sub { w83781d_detect(9, @_); },
+     },
+     {
+       name => "Winbond W83627DHG",
+       driver => "use-isa-instead",
+       i2c_addrs => [0x28..0x2f], 
+       i2c_detect => sub { w83781d_detect(10, @_); },
+     },
+     {
+       name => "Asus AS99127F (rev.1)",
+       driver => "w83781d",
+       i2c_addrs => [0x28..0x2f],
+       i2c_detect => sub { w83781d_detect(4, @_); },
+     } ,
+     {
+       name => "Asus AS99127F (rev.2)",
+       driver => "w83781d",
+       i2c_addrs => [0x28..0x2f],
+       i2c_detect => sub { w83781d_detect(5, @_); },
+     } ,
+     {
+       name => "Asus ASB100 Bach",
+       driver => "asb100",
+       i2c_addrs => [0x28..0x2f],
+       i2c_detect => sub { w83781d_detect(6, @_); },
+     } ,
+     {
+       name => "Asus ASM58 Mozart-2",
+       driver => "to-be-written",
+       i2c_addrs => [0x77],
+       i2c_detect => sub { mozart_detect(0, @_); },
+     } ,
+     {
+       name => "Asus AS2K129R Mozart-2",
+       driver => "to-be-written",
+       i2c_addrs => [0x77],
+       i2c_detect => sub { mozart_detect(1, @_); },
+     } ,
+     {
+       name => "Asus Mozart-2",
+       driver => "to-be-written",
+       i2c_addrs => [0x77],
+       i2c_detect => sub { mozart_detect(2, @_); },
+     } ,
+     {
+       name => "Winbond W83L784R/AR/G",
+       driver => "to-be-written",
+       i2c_addrs => [0x2d],
+       i2c_detect => sub { w83l784r_detect(0, @_); },
+     } ,
+     {
+       name => "Winbond W83L785R/G",
+       driver => "to-be-written",
+       i2c_addrs => [0x2d],
+       i2c_detect => sub { w83l784r_detect(1, @_); },
+     } ,
+     {
+       name => "Winbond W83L786NR/NG/R/G",
+       driver => "to-be-written",
+       i2c_addrs => [0x2e, 0x2f],
+       i2c_detect => sub { w83l784r_detect(2, @_); },
+     },
+     {
+       name => "Winbond W83L785TS-S",
+       driver => "w83l785ts",
+       i2c_addrs => [0x2e], 
+       i2c_detect => sub { w83l785ts_detect(0, @_); },
+     } ,
+     {
+       name => "Genesys Logic GL518SM Revision 0x00",
+       driver => "gl518sm",
+       i2c_addrs => [0x2c, 0x2d],
+       i2c_detect => sub { gl518sm_detect(0, @_); },
+     },
+     {
+       name => "Genesys Logic GL518SM Revision 0x80",
+       driver => "gl518sm",
+       i2c_addrs => [0x2c, 0x2d],
+       i2c_detect => sub { gl518sm_detect(1, @_); },
+     },
+     {
+       name => "Genesys Logic GL520SM",
+       driver => "gl520sm",
+       i2c_addrs => [0x2c, 0x2d],
+       i2c_detect => sub { gl520sm_detect(@_); },
+     },
+     {
+       name => "Genesys Logic GL525SM",
+       driver => "Unwritten (GL525SM)",
+       i2c_addrs => [0x2d],
+       i2c_detect => sub { gl525sm_detect(@_); },
+     },
+     {
+       name => "Analog Devices ADM9240",
+       driver => "adm9240",
+       i2c_addrs => [0x2c..0x2f],
+       i2c_detect => sub { adm9240_detect(0, @_); },
+     },
+     {
+       name => "Dallas Semiconductor DS1621",
+       driver => "ds1621",
+       i2c_addrs => [0x48..0x4f],
+       i2c_detect => sub { ds1621_detect(@_); },
+     } ,
+     {
+       name => "Dallas Semiconductor DS1780",
+       driver => "adm9240",
+       i2c_addrs => [0x2c..0x2f],
+       i2c_detect => sub { adm9240_detect(1, @_); },
+     },
+     {
+       name => "National Semiconductor LM81",
+       driver => "adm9240",
+       i2c_addrs => [0x2c..0x2f],
+       i2c_detect => sub { adm9240_detect(2, @_); },
+     },
+     {
+       name => "Analog Devices ADM1026",
+       driver => "adm1026",
+       i2c_addrs => [0x2c,0x2d,0x2e],
+       i2c_detect => sub { adm1026_detect(0, @_); },
+     },
+     {
+       name => "Analog Devices ADM1025",
+       driver => "adm1025",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { adm1025_detect(0, @_); },
+     },
+     {
+       name => "Philips NE1619",
+       driver => "adm1025",
+       i2c_addrs => [0x2c..0x2d],
+       i2c_detect => sub { adm1025_detect(1, @_); },
+     },
+     {
+       name => "Analog Devices ADM1021",
+       driver => "adm1021",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { adm1021_detect(0, @_); },
+     },
+     {
+       name => "Analog Devices ADM1021A/ADM1023",
+       driver => "adm1021",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { adm1021_detect(1, @_); },
+     },
+     {
+       name => "Maxim MAX1617",
+       driver => "adm1021",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { adm1021_detect(2, @_); },
+     },
+     {
+       name => "Maxim MAX1617A",
+       driver => "adm1021",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { adm1021_detect(3, @_); },
+     },
+     {
+       name => "Maxim MAX1668",
+       driver => "max1668",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { max1668_detect(0, @_); },
+     },
+     {
+       name => "Maxim MAX1805",
+       driver => "max1668",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { max1668_detect(1, @_); },
+     },
+     {
+       name => "Maxim MAX1989",
+       driver => "max1668",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { max1668_detect(2, @_); },
+     },
+     {
+       name => "Maxim MAX6650/MAX6651",
+       driver => "max6650",
+       i2c_addrs => [0x1b,0x1f,0x48,0x4b],
+       i2c_detect => sub { max6650_detect(0, @_); },
+     },
+     {
+       name => "Maxim MAX6655/MAX6656",
+       driver => "max6655",
+       i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e],
+       i2c_detect => sub { max6655_detect(0, @_); },
+     },
+     {
+       name => "TI THMC10",
+       driver => "adm1021",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { adm1021_detect(4, @_); },
+     },
+     {
+       name => "National Semiconductor LM84",
+       driver => "adm1021",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { adm1021_detect(5, @_); },
+     },
+     {
+       name => "Genesys Logic GL523SM",
+       driver => "adm1021",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { adm1021_detect(6, @_); },
+     },
+     {
+       name => "Onsemi MC1066",
+       driver => "adm1021",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { adm1021_detect(7, @_); },
+     },
+     {
+       name => "Maxim MAX1619",
+       driver => "max1619",
+       i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e],
+       i2c_detect => sub { max1619_detect(0, @_); },
+     },
+     {
+       name => "National Semiconductor LM82/LM83",
+       driver => "lm83",
+       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
+       i2c_detect => sub { lm83_detect(0, @_); },
+     },
+     {
+       name => "National Semiconductor LM90",
+       driver => "lm90",
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { lm90_detect(0, @_); },
+     },
+     {
+       name => "National Semiconductor LM89/LM99",
+       driver => "lm90",
+       i2c_addrs => [0x4c..0x4d],
+       i2c_detect => sub { lm90_detect(1, @_); },
+     },
+     {
+       name => "National Semiconductor LM86",
+       driver => "lm90",
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { lm90_detect(2, @_); },
+     },
+     {
+       name => "Analog Devices ADM1032",
+       driver => "lm90",
+       i2c_addrs => [0x4c..0x4d],
+       i2c_detect => sub { lm90_detect(3, @_); },
+     },
+     {
+       name => "Maxim MAX6657/MAX6658/MAX6659",
+       driver => "lm90",
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { lm90_detect(4, @_); },
+     },
+     {
+       name => "Maxim MAX6659",
+       driver => "lm90",
+       i2c_addrs => [0x4d..0x4e], # 0x4c is handled above
+       i2c_detect => sub { lm90_detect(4, @_); },
+     },
+     {
+       name => "Maxim MAX6648/MAX6692",
+       driver => "to-be-written",
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { lm90_detect(6, @_); },
+     },
+     {
+       name => "Maxim MAX6680/MAX6681",
+       driver => "lm90",
+       i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e],
+       i2c_detect => sub { lm90_detect(7, @_); },
+     },
+     {
+       name => "Winbond W83L771W/G",
+       driver => "lm90",
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { lm90_detect(8, @_); },
+     },
+     {
+       name => "National Semiconductor LM63",
+       driver => "lm63",
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { lm63_detect(1, @_); },
+     },
+     {
+       name => "Fintek F75363SG",
+       driver => "lm63", # Not yet
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { lm63_detect(2, @_); },
+     },
+     {
+       name => "National Semiconductor LM92",
+       driver => "lm92",
+       i2c_addrs => [0x48..0x4b],
+       i2c_detect => sub { lm92_detect(0, @_); },
+     },
+     {
+       name => "National Semiconductor LM76",
+       driver => "lm92",
+       i2c_addrs => [0x48..0x4b],
+       i2c_detect => sub { lm92_detect(1, @_); },
+     },
+     {
+       name => "Maxim MAX6633/MAX6634/MAX6635",
+       driver => "lm92",
+       i2c_addrs => [0x40..0x4f],
+       i2c_detect => sub { lm92_detect(2, @_); },
+     },
+     {
+       name => "Analog Devices ADT7461",
+       driver => "lm90",
+       i2c_addrs => [0x4c..0x4d],
+       i2c_detect => sub { lm90_detect(5, @_); },
+     },
+     {
+       name => "Analog Devices ADM1029",
+       driver => "adm1029",
+       i2c_addrs => [0x28..0x2f],
+       i2c_detect => sub { adm1029_detect(0, @_); },
+     },
+     {
+       name => "Analog Devices ADM1030",
+       driver => "adm1031",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { adm1031_detect(0, @_); },
+     },
+     {
+       name => "Analog Devices ADM1031",
+       driver => "adm1031",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { adm1031_detect(1, @_); },
+     },
+     {
+       name => "Analog Devices ADM1033",
+       driver => "to-be-written",
+       i2c_addrs => [0x50..0x53],
+       i2c_detect => sub { adm1034_detect(0, @_); },
+     },
+     {
+       name => "Analog Devices ADM1034",
+       driver => "to-be-written",
+       i2c_addrs => [0x50..0x53],
+       i2c_detect => sub { adm1034_detect(1, @_); },
+     },
+     {
+       name => "Analog Devices ADM1022",
+       driver => "thmc50",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { adm1022_detect(0, @_); },
+     },
+     {
+       name => "Texas Instruments THMC50",
+       driver => "thmc50",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { adm1022_detect(1, @_); },
+     },
+     {
+       name => "Analog Devices ADM1028",
+       driver => "thmc50",
+       i2c_addrs => [0x2e],
+       i2c_detect => sub { adm1022_detect(2, @_); },
+     },
+     {
+       name => "Silicon Integrated Systems SIS5595",
+       driver => "sis5595",
+       isa_addrs => [ 0 ],
+       isa_detect => sub { sis5595_pci_detect(); },
+     },
+     {
+       name => "VIA VT82C686 Integrated Sensors",
+       driver => "via686a",
+       isa_addrs => [ 0 ],
+       isa_detect => sub { via686a_pci_detect(); },
+     },
+     {
+       name => "VIA VT8231 Integrated Sensors",
+       driver => "vt8231",
+       isa_addrs => [ 0 ],
+       isa_detect => sub { via8231_pci_detect(); },
+     },
+     {
+       name => "VIA VT1211 (I2C)",
+       driver => "use-isa-instead",
+       i2c_addrs => [0x2d],
+       i2c_detect => sub { vt1211_i2c_detect(0, @_); },
+     },
+     {
+       name => "ITE IT8712F",
+       driver => "it87",
+       i2c_addrs => [0x28..0x2f],
+       i2c_detect => sub { ite_detect(0, @_); },
+     },
+     {
+       name => "ITE IT8201R/IT8203R/IT8206R/IT8266R",
+       driver => "not-a-sensor",
+       i2c_addrs => [0x4e],
+       i2c_detect => sub { ite_overclock_detect(@_); },
+     },
+     {
+       name => "SPD EEPROM",
+       driver => "not-a-sensor",
+       # Can also live at 0x54-0x57, but we don't care: we only check
+       # for SPD and EDID EEPROMs because some hardware monitoring chips
+       # can live at 0x50-0x53.
+       i2c_addrs => [0x50..0x53],
+       i2c_detect => sub { eeprom_detect(@_); },
+     },
+     {
+       name => "EDID EEPROM",
+       driver => "not-a-sensor",
+       i2c_addrs => [0x50..0x53],
+       i2c_detect => sub { ddcmonitor_detect(@_); },
+     },
+     {
+       name => "FSC Poseidon I",
+       driver => "fscpos",
+       i2c_addrs => [0x73],
+       i2c_detect => sub { fscpeg_detect(@_); },
+     },
+     {
+       name => "FSC Poseidon II",
+       driver => "to-be-written",
+       i2c_addrs => [0x73],
+       i2c_detect => sub { fscpos_detect(@_); },
+     },
+     {
+       name => "FSC Scylla",
+       driver => "fscscy",
+       i2c_addrs => [0x73],
+       i2c_detect => sub { fscscy_detect(@_); },
+     },
+     {
+       name => "FSC Hermes",
+       driver => "fscher",
+       i2c_addrs => [0x73],
+       i2c_detect => sub { fscher_detect(@_); },
+     },
+     {
+       name => "FSC Heimdal",
+       driver => "to-be-written",
+       i2c_addrs => [0x73],
+       i2c_detect => sub { fschmd_detect(@_); },
+     },
+     {
+       name => "ALi M5879",
+       driver => "to-be-written",
+       i2c_addrs => [0x2c..0x2d],
+       i2c_detect => sub { m5879_detect(@_); },
+     },
+     {
+       name => "SMSC LPC47M15x/192/292/997",
+       driver => "smsc47m192",
+       i2c_addrs => [0x2c..0x2d],
+       i2c_detect => sub { smsc47m192_detect(@_); },
+     },
+     {
+       name => "SMSC DME1737",
+       driver => "dme1737",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { dme1737_detect(@_); },
+     },
+     {
+       name => "Fintek F75111R/RG/N (GPIO)",
+       driver => "not-a-sensor",
+       i2c_addrs => [0x4e], # 0x37 not probed
+       i2c_detect => sub { fintek_detect(1, @_); },
+     },
+     {
+       name => "Fintek F75121R/F75122R/RG (VID+GPIO)",
+       driver => "to-be-written",
+       i2c_addrs => [0x4e], # 0x37 not probed
+       i2c_detect => sub { fintek_detect(2, @_); },
+     },
+     {
+       name => "Fintek F75373S/SG",
+       driver => "to-be-written",
+       i2c_addrs => [0x2d..0x2e],
+       i2c_detect => sub { fintek_detect(3, @_); },
+     },
+     {
+       name => "Fintek F75375S/SP",
+       driver => "to-be-written",
+       i2c_addrs => [0x2d..0x2e],
+       i2c_detect => sub { fintek_detect(4, @_); },
+     },
+     {
+       name => "Fintek F75387SG/RG",
+       driver => "to-be-written",
+       i2c_addrs => [0x2d..0x2e],
+       i2c_detect => sub { fintek_detect(5, @_); },
+     },
+     {
+       name => "Fintek F75383S/M",
+       driver => "to-be-written",
+       i2c_addrs => [0x4c],
+       i2c_detect => sub { fintek_detect(6, @_); },
+     },
+     {
+       name => "Fintek F75384S/M",
+       driver => "to-be-written",
+       i2c_addrs => [0x4d],
+       i2c_detect => sub { fintek_detect(6, @_); },
+     },
+     {
+       name => "Fintek custom power control IC",
+       driver => "to-be-written",
+       i2c_addrs => [0x2f],
+       i2c_detect => sub { fintek_detect(7, @_); },
+     },
+     {
+       name => "Philips Semiconductors PCA9540",
+       driver => "pca9540",
+       i2c_addrs => [0x70],
+       i2c_detect => sub { pca9540_detect(@_); },
+     },
+     {
+       name => "Smart Battery",
+       driver => "smartbatt",
+       i2c_addrs => [0x0b],
+       i2c_detect => sub { smartbatt_detect(@_); },
+     },
+);
+
+# Special case chip information goes here and would be included in
+# the chip_special_cases routine below
+use vars qw(@chip_kern24_ids @chip_kern26_ids);
+@chip_kern24_ids = (
+     {
+       name => "Analog Devices ADM1024",
+       driver => "adm1024",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { adm1024_detect(0, @_); },
+     },
+     {
+       name => "Winbond W83791D",
+       driver => "w83781d",
+       i2c_addrs => [0x2c..0x2f],
+       i2c_detect => sub { w83781d_detect(7, @_); },
+     },
+     {
+       name => "IPMI BMC KCS",
+       driver => "bmcsensors",
+       isa_addrs => [0x0ca0],
+       isa_detect => sub { ipmi_kcs_detect(@_); },
+     },
+     {
+       name => "IPMI BMC SMIC",
+       driver => "bmcsensors",
+       isa_addrs => [0x0ca8],
+       isa_detect => sub { ipmi_smic_detect(@_); },
+     },
+);
+
+@chip_kern26_ids = (
+     {
+       name => "Analog Devices ADM1024",
+       driver => "lm87",
+       i2c_addrs => [0x2c..0x2e],
+       i2c_detect => sub { adm1024_detect(0, @_); },
+     },
+     {
+       name => "Winbond W83791D",
+       driver => "w83791d",
+       i2c_addrs => [0x2c..0x2f],
+       i2c_detect => sub { w83781d_detect(7, @_); },
+     },
+     {
+       name => "IPMI BMC KCS",
+       driver => "ipmisensors",
+       isa_addrs => [0x0ca0],
+       isa_detect => sub { ipmi_kcs_detect(@_); },
+     },
+     {
+       name => "IPMI BMC SMIC",
+       driver => "ipmisensors",
+       isa_addrs => [0x0ca8],
+       isa_detect => sub { ipmi_smic_detect(@_); },
+     },
+);
+
+# This is a list of all recognized superio chips. 
+# Each entry must have the following fields:
+#  name: The full chip name
+#  driver: The driver name (without .o extension). Put in
+#      "to-be-written" if it is not yet available.
+#      Put in "not-a-sensor" if the chip doesn't have hardware monitoring
+#      capabilities (listing such chips here removes the need of manual
+#      lookup when people report them).
+#      Put in exactly "via-smbus-only" if this is a Super-I/O chip whose
+#      hardware monitoring registers can only be accessed via the SMBus.
+#  devid: The device ID(s) we have to match (base device)
+#  devid_mask (optional): Bitmask to apply before checking the device ID
+#  logdev: The logical device containing the sensors
+#  alias_detect (optional): For chips which can be both on the ISA and the
+#      I2C bus, a function which detectes whether two entries are the same.
+#      The function should take three parameters: The ISA address, the
+#      I2C bus number, and the I2C address.
+# Entries are grouped by family. Each family entry has the following fields:
+#  family: The family name
+#  guess (optional): Typical logical device address. This lets us do
+#      generic probing if we fail to recognize the chip.
+#  enter: The password sequence to write to the address register
+#  chips: Array of chips
+# The order of families matters, because we stop as soon as one family
+# succeeds. So we have to list families with shorter password sequences
+# first.
+@superio_ids = (
+  {
+    family => "National Semiconductor",
+    enter =>
+    {
+      0x2e => [],
+      0x4e => [],
+    },
+    chips =>
+    [
+      {
+	name => "Nat. Semi. PC8374L Super IO Sensors",
+	driver => "to-be-written",
+	devid => 0xf1,
+	logdev => 0x08,
+      },
+      {
+	name => "Nat. Semi. PC87351 Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0xe2,
+	logdev => 0x08,
+      },
+      {
+	name => "Nat. Semi. PC87360 Super IO Fan Sensors",
+	driver => "pc87360",
+	devid => 0xe1,
+	logdev => 0x09,
+      },
+      {
+	name => "Nat. Semi. PC87363 Super IO Fan Sensors",
+	driver => "pc87360",
+	devid => 0xe8,
+	logdev => 0x09,
+      },
+      {
+	name => "Nat. Semi. PC87364 Super IO Fan Sensors",
+	driver => "pc87360",
+	devid => 0xe4,
+	logdev => 0x09,
+      },
+      {
+	name => "Nat. Semi. PC87365 Super IO Fan Sensors",
+	driver => "pc87360",
+	devid => 0xe5,
+	logdev => 0x09,
+      },
+      {
+	name => "Nat. Semi. PC87365 Super IO Voltage Sensors",
+	driver => "pc87360",
+	devid => 0xe5,
+	logdev => 0x0d,
+      },
+      {
+	name => "Nat. Semi. PC87365 Super IO Thermal Sensors",
+	driver => "pc87360",
+	devid => 0xe5,
+	logdev => 0x0e,
+      },
+      {
+	name => "Nat. Semi. PC87366 Super IO Fan Sensors",
+	driver => "pc87360",
+	devid => 0xe9,
+	logdev => 0x09,
+      },
+      {
+	name => "Nat. Semi. PC87366 Super IO Voltage Sensors",
+	driver => "pc87360",
+	devid => 0xe9,
+	logdev => 0x0d,
+      },
+      {
+	name => "Nat. Semi. PC87366 Super IO Thermal Sensors",
+	driver => "pc87360",
+	devid => 0xe9,
+	logdev => 0x0e,
+      },
+      {
+	name => "Nat. Semi. PC87372 Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0xf0,
+	logdev => 0x09,
+      },
+      {
+	name => "Nat. Semi. PC87373 Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0xf3,
+	logdev => 0x09,
+      },
+      {
+	name => "Nat. Semi. PC87591 Super IO",
+	driver => "to-be-written",
+	devid => 0xec,
+	logdev => 0x0f,
+      },
+      {
+	name => "Nat. Semi. PC87371 Super IO",
+	driver => "not-a-sensor",
+	devid => 0xd0,
+      },
+      {
+	name => "Nat. Semi. PC97371 Super IO",
+	driver => "not-a-sensor",
+	devid => 0xdf,
+      },
+      {
+	name => "Nat. Semi. PC8739x Super IO",
+	driver => "not-a-sensor",
+	devid => 0xea,
+      },
+      {
+	name => "Nat. Semi. PC8741x Super IO",
+	driver => "not-a-sensor",
+	devid => 0xee,
+      },
+      {
+	name => "Nat. Semi. PC87427 Super IO Fan Sensors",
+	driver => "pc87427",
+	devid => 0xf2,
+	logdev => 0x09,
+      },
+      {
+	name => "Nat. Semi. PC87427 Super IO Health Sensors",
+	driver => "to-be-written",
+	devid => 0xf2,
+	logdev => 0x14,
+      },
+    ],
+  },
+  {
+    family => "SMSC",
+    enter =>
+    {
+      0x2e => [0x55],
+      0x4e => [0x55],
+    },
+    chips =>
+    [
+      {
+	name => "SMSC DME1737 Super IO",
+	# Hardware monitoring features are accessed on the SMBus
+	driver => "via-smbus-only",
+	devid => 0x78,
+      },
+      {
+	name => "SMSC DME1737 Super IO",
+	# The DME1737 shows up twice in this list because it can return either
+	# 0x78 or 0x77 as its device ID.
+	# Hardware monitoring features are accessed on the SMBus
+	driver => "via-smbus-only",
+	devid => 0x77,
+      },
+      {
+	name => "SMSC FDC37B72x Super IO",
+	driver => "not-a-sensor",
+	devid => 0x4c,
+      },
+      {
+	name => "SMSC FDC37B78x Super IO",
+	driver => "not-a-sensor",
+	devid => 0x44,
+      },
+      {
+	name => "SMSC FDC37C672 Super IO",
+	driver => "not-a-sensor",
+	devid => 0x40,
+      },
+      {
+	name => "SMSC FDC37M707 Super IO",
+	driver => "not-a-sensor",
+	devid => 0x42,
+      },
+      {
+	name => "SMSC FDC37M81x Super IO",
+	driver => "not-a-sensor",
+	devid => 0x4d,
+      },
+      {
+	name => "SMSC LPC47B27x Super IO Fan Sensors",
+	driver => "smsc47m1",
+	devid => 0x51,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47B34x Super IO",
+	driver => "not-a-sensor",
+	devid => 0x56,
+      },
+      {
+	name => "SMSC LPC47B357 Super IO",
+	# no datasheet
+	devid => 0x5d,
+      },
+      {
+	name => "SMSC LPC47B37x Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0x52,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47B397-NC Super IO",
+	driver => "smsc47b397",
+	devid => 0x6f,
+	logdev => 0x08,
+      },
+      {
+	name => "SMSC LPC47M10x/112/13x Super IO Fan Sensors",
+	driver => "smsc47m1",
+	devid => 0x59,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47M14x Super IO Fan Sensors",
+	driver => "smsc47m1",
+	devid => 0x5f,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47M15x/192/997 Super IO Fan Sensors",
+	driver => "smsc47m1",
+	devid => 0x60,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47M172 Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0x14,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47M182 Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0x74,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47M292 Super IO Fan Sensors",
+	driver => "smsc47m1",
+	devid => 0x6b,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47M584-NC Super IO",
+	# No datasheet
+	devid => 0x76,
+      },
+      {
+	name => "SMSC LPC47N252 Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0x0e,
+	logdev => 0x09,
+      },
+      {
+	name => "SMSC LPC47S42x Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0x57,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47S45x Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0x62,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC LPC47U33x Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0x54,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC SCH3112 Super IO",
+	driver => "dme1737",
+	devid => 0x7c,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC SCH3114 Super IO",
+	driver => "dme1737",
+	devid => 0x7d,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC SCH3116 Super IO",
+	driver => "dme1737",
+	devid => 0x7f,
+	logdev => 0x0a,
+      },
+      {
+	name => "SMSC SCH4307 Super IO Fan Sensors",
+	driver => "to-be-written",
+	devid => 0x90,
+	logdev => 0x08,
+      },
+      {
+	name => "SMSC SCH5307-NS Super IO",
+	driver => "smsc47b397",
+	devid => 0x81,
+	logdev => 0x08,
+      },
+      {
+	name => "SMSC SCH5317 Super IO",
+	driver => "smsc47b397",
+	devid => 0x85,
+	logdev => 0x08,
+      },
+      {
+	name => "SMSC SCH5504-NS Super IO",
+	# No datasheet
+	driver => "not-a-sensor",
+	devid => 0x79,
+      },
+    ],
+    # Non-standard SMSC detection callback and chip list. These chips differ
+    # from the standard ones listed above in that the device ID register 
+    # address is 0x0d instead of 0x20 (as specified by the ISA PNP spec).
+    ns_detect => \&smsc_ns_detect_superio,
+    ns_chips =>
+    [
+      {
+	name => "SMSC FDC37C665 Super IO",
+	driver => "not-a-sensor",
+	devid => 0x65,
+      },
+      {
+	name => "SMSC FDC37C666 Super IO",
+	driver => "not-a-sensor",
+	devid => 0x66,
+      },
+      {
+	name => "SMSC FDC37C669 Super IO",
+	driver => "not-a-sensor",
+	devid => 0x03,
+      },
+      {
+	name => "SMSC FDC37N769 Super IO",
+	driver => "not-a-sensor",
+	devid => 0x28,
+      },
+      {
+	name => "SMSC LPC47N227 Super IO",
+	driver => "not-a-sensor",
+	devid => 0x5a,
+      },
+    ],
+  },
+  {
+    family => "VIA/Winbond/Fintek",
+    guess => 0x290,
+    enter =>
+    {
+      0x2e => [0x87, 0x87],
+      0x4e => [0x87, 0x87],
+    },
+    chips =>
+    [
+      {
+	name => "VIA VT1211 Super IO Sensors",
+	driver => "vt1211",
+	devid => 0x3c,
+	logdev => 0x0b,
+	alias_detect => sub { vt1211_alias_detect(0, @_); },
+      },
+      {
+	name => "Winbond W83627HF/F/HG/G Super IO Sensors",
+	driver => "w83627hf",
+	devid => 0x52,
+	logdev => 0x0b,
+	alias_detect => sub { w83781d_alias_detect(3, @_); },
+      },
+      {
+	name => "Winbond W83627THF/THG Super IO Sensors",
+	driver => "w83627hf",
+	devid => 0x82,
+	logdev => 0x0b,
+      },
+      {
+	name => "Winbond W83637HF/HG Super IO Sensors",
+	driver => "w83627hf",
+	devid => 0x70,
+	logdev => 0x0b,
+      },
+      {
+	name => "Winbond W83687THF Super IO Sensors",
+	driver => "w83627hf",
+	devid => 0x85,
+	logdev => 0x0b,
+      },
+      {
+	name => "Winbond W83697HF/F/HG Super IO Sensors",
+	driver => "w83627hf",
+	devid => 0x60,
+	logdev => 0x0b,
+      },
+      {
+	name => "Winbond W83697SF/UF/UG Super IO PWM",
+	driver => "to-be-written",
+	devid => 0x68,
+	logdev => 0x0b,
+      },
+      {
+	name => "Winbond W83627EHF/EF/EHG/EG Super IO Sensors",
+	driver => "w83627ehf",
+	# W83627EHF datasheet says 0x886x but 0x8853 was seen, thus the
+	# broader mask. W83627EHG was seen with ID 0x8863.
+	devid => 0x8840,
+	devid_mask => 0xFFC0,
+	logdev => 0x0b,
+	alias_detect => sub { w83781d_alias_detect(9, @_); },
+      },
+      {
+	name => "Winbond W83627DHG Super IO Sensors",
+	driver => "w83627ehf",
+	devid => 0xA020,
+	devid_mask => 0xFFF0,
+	logdev => 0x0b,
+	alias_detect => sub { w83781d_alias_detect(10, @_); },
+      },
+      {
+	name => "Winbond W83L517D Super IO",
+	driver => "not-a-sensor",
+	devid => 0x61,
+      },
+      {
+	name => "Fintek F71805F/FG Super IO Sensors",
+	driver => "f71805f",
+	devid => 0x0406,
+	logdev => 0x04,
+      },
+      {
+	name => "Fintek F71862FG Super IO Sensors",
+	driver => "to-be-written",
+	devid => 0x0601,
+	logdev => 0x04,
+      },
+      {
+	name => "Fintek F71806FG/F71872FG Super IO Sensors",
+	driver => "f71805f",
+	devid => 0x0341,
+	logdev => 0x04,
+      },
+      {
+	name => "Fintek F71882FG/F71883FG Super IO Sensors",
+	driver => "f71882fg",
+	devid => 0x0541,
+	logdev => 0x04,
+      },
+      {
+	name => "Fintek F81218D Super IO",
+	driver => "not-a-sensor",
+	devid => 0x0206,
+      },
+      {
+	# Shouldn't be in this family, but seems to be still.
+	name => "ITE IT8708F Super IO",
+	driver => "not-a-sensor",
+	devid => 0x8708,
+      },
+    ],
+  },
+  {
+    family => "ITE",
+    guess => 0x290,
+    enter =>
+    {
+      0x2e => [0x87, 0x01, 0x55, 0x55],
+      0x4e => [0x87, 0x01, 0x55, 0xaa],
+    },
+    chips =>
+    [
+      {
+	name => "ITE IT8702F Super IO Sensors",
+	driver => "to-be-written",
+	devid => 0x8702,
+	logdev => 0x04,
+      },
+      {
+	name => "ITE IT8705F Super IO Sensors",
+	driver => "it87",
+	devid => 0x8705,
+	logdev => 0x04,
+      },
+      {
+	name => "ITE IT8712F Super IO Sensors",
+	driver => "it87",
+	devid => 0x8712,
+	logdev => 0x04,
+	alias_detect => sub { ite_alias_detect(0, @_); },
+      },
+      {
+	name => "ITE IT8716F Super IO Sensors",
+	driver => "it87",
+	devid => 0x8716,
+	logdev => 0x04,
+      },
+      {
+	name => "ITE IT8718F Super IO Sensors",
+	driver => "it87",
+	devid => 0x8718,
+	logdev => 0x04,
+      },
+      {
+	name => "ITE IT8726F Super IO Sensors",
+	driver => "it87",
+	devid => 0x8726,
+	logdev => 0x04,
+      },
+    ],
+  },
+);
+
+# Drivers for CPU embedded sensors
+# Each entry must have the following fields:
+#  name: The CPU family name
+#  driver: The driver name. Put "to-be-written" if no driver is available.
+#  detect: Detection callback function. No parameter will be passed to
+#          this function, it must use global lists of PCI devices, CPU,
+#          etc. It must return a confidence value, undef if no supported
+#          CPU is found.
+@cpu_ids = (
+  {
+    name => "AMD K8 thermal sensors",
+    driver => "k8temp",
+    detect => sub { k8temp_pci_detect(); },
+  },
+  {
+    name => "AMD K10 thermal sensors",
+    driver => "to-be-written",
+    detect => sub { k10temp_pci_detect(); },
+  },
+  {
+    name => "Intel Core family thermal sensor",
+    driver => "coretemp",
+    detect => sub { coretemp_detect(); },
+  },
+  {
+    name => "Intel AMB FB-DIMM thermal sensor",
+    driver => "to-be-written",
+    detect => sub { intel_amb_detect(); },
+  },
+);
+
+#######################
+# AUXILIARY FUNCTIONS #
+#######################
+
+sub swap_bytes
+{
+  return (($_[0] & 0xff00) >> 8) + (($_[0] & 0x00ff) << 8)
+}
+
+# $_[0] is the sought value
+# @_[1..] is the list to seek in
+# Returns: 0 on failure, 1 if found.
+# Note: Every use of this sub probably indicates the use of the wrong
+#       datastructure
+sub contains
+{
+  my $sought = shift;
+  foreach (@_) {
+    return 1 if $sought eq $_;
+  }
+  return 0;
+}
+
+sub parse_not_to_scan
+{
+  my ($min,$max,$to_parse) = @_;
+  my @ranges = split /\s*,\s*/, $to_parse;
+  my @res;
+  my $range;
+  foreach $range (@ranges) {
+    my ($start,$end) = split /\s*-s*/, $range;
+    $start = oct $start if $start =~ /^0/;
+    if (defined $end) {
+      $end = oct $end if $end =~ /^0/;
+      $start = $min if $start < $min;
+      $end = $max if $end > $max;
+      push @res, ($start+0..$end+0);
+    } else {
+      push @res, $start+0 if $start >= $min and $start <= $max;
+    }
+  }
+  return sort { $a <=> $b } @res;
+}
+
+# @_[0]: Reference to list 1
+# @_[1]: Reference to list 2
+# Result: 0 if they have no elements in common, 1 if they have
+# Elements must be numeric.
+sub any_list_match
+{
+  my ($list1,$list2) = @_;
+  my ($el1,$el2);
+  foreach $el1 (@$list1) {
+    foreach $el2 (@$list2) {
+      return 1 if $el1 == $el2;
+    }
+  }
+  return 0;
+}
+
+###################
+# I/O port access #
+###################
+
+sub initialize_ioports
+{
+  sysopen (IOPORTS, "/dev/port", O_RDWR)
+    or die "/dev/port: $!\n";
+  binmode IOPORTS;
+}
+
+sub close_ioports
+{
+  close (IOPORTS)
+    or print "Warning: $!\n";
+}
+
+# $_[0]: port to read
+# Returns: -1 on failure, read value on success.
+sub inb
+{
+  my ($res,$nrchars);
+  sysseek IOPORTS, $_[0], 0 or return -1;
+  $nrchars = sysread IOPORTS, $res, 1;
+  return -1 if not defined $nrchars or $nrchars != 1;
+  $res = unpack "C",$res ;
+  return $res;
+}
+
+# $_[0]: port to write
+# $_[1]: value to write
+# Returns: -1 on failure, 0 on success.
+sub outb
+{
+  my $towrite = pack "C", $_[1];
+  sysseek IOPORTS, $_[0], 0 or return -1;
+  my $nrchars = syswrite IOPORTS, $towrite, 1;
+  return -1 if not defined $nrchars or $nrchars != 1;
+  return 0;
+}
+
+# $_[0]: Address register
+# $_[1]: Data register
+# $_[2]: Register to read
+# Returns: read value
+sub isa_read_byte
+{
+  outb $_[0],$_[2];
+  return inb $_[1];
+}
+
+# $_[0]: Address register
+# $_[1]: Data register
+# $_[2]: Register to write
+# $_[3}: Value to write
+# Returns: nothing
+sub isa_write_byte
+{
+  outb $_[0],$_[2];
+  outb $_[1],$_[3];
+}
+
+#################
+# AUTODETECTION #
+#################
+
+use vars qw($modules_conf $dev_i2c $sysfs_root);
+
+sub initialize_conf
+{
+  my $use_devfs = 0;
+  open(local *INPUTFILE, "/proc/mounts") or die "Can't access /proc/mounts!";
+  local $_;
+  while (<INPUTFILE>) {
+    if (m@^\w+ /dev devfs @) {
+      $use_devfs = 1;
+      $dev_i2c = '/dev/i2c/';
+    }
+    if (m@^\S+ (/\w+) sysfs @) {
+      $sysfs_root = $1;
+    }
+  }
+  close INPUTFILE;
+
+  my $use_udev = 0;
+  if (open(*INPUTFILE, '/etc/udev/udev.conf')) {
+    while (<INPUTFILE>) {
+      if (m/^\s*udev_db\s*=\s*\"([^"]*)\"/ || m/^\s*udev_db\s*=\s*(\S+)/) {
+        if (-e $1) {
+          $use_udev = 1;
+          $dev_i2c = '/dev/i2c-';
+        }
+        last;
+      }
+    }
+    close INPUTFILE;
+  }
+  
+  if (!$use_udev) {
+    # Try some known default udev db locations, just in case
+    if (-e '/dev/.udev.tdb' || -e '/dev/.udev'
+     || -e '/dev/.udevdb') {
+      $use_udev = 1;
+      $dev_i2c = '/dev/i2c-';
+    }
+  }
+
+  if (kernel_version_at_least(2, 6, 0)) {
+    $modules_conf = '/etc/modprobe.conf';
+  } else {
+    $modules_conf = '/etc/modules.conf';
+  }
+
+  if (!($use_devfs || $use_udev)) {
+    if (! -c '/dev/i2c-0' && -x '/sbin/MAKEDEV') {
+      system("/sbin/MAKEDEV i2c");
+    }
+    if (! -c '/dev/i2c-0' && -x '/dev/MAKEDEV') {
+      system("/dev/MAKEDEV i2c");
+    }
+    if (-c '/dev/i2c-0') {
+      $dev_i2c = '/dev/i2c-';
+    } else { # default
+      print "No i2c device files found.\n";
+      exit -1;
+    }
+  }
+}
+
+# [0] -> VERSION
+# [1] -> PATCHLEVEL
+# [2] -> SUBLEVEL
+# [3] -> EXTRAVERSION
+#
+use vars qw(@kernel_version);
+
+sub initialize_kernel_version
+{
+  `uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/;
+  @kernel_version = ($1, $2, $3, $4);
+}
+
+sub kernel_version_at_least
+{
+  my ($vers, $plvl, $slvl) = @_;
+  return 1 if ($kernel_version[0]  > $vers ||
+                ($kernel_version[0] == $vers && 
+                  ($kernel_version[1]  > $plvl || 
+                    ($kernel_version[1] == $plvl && 
+                      ($kernel_version[2] >= $slvl)))));
+  return 0;
+}
+
+# @cpu is a list of reference to hashes, one hash per CPU.
+# Each entry has the following keys: vendor_id, cpu family, model,
+# model name and stepping, directly taken from /proc/cpuinfo.
+use vars qw(@cpu);
+
+sub initialize_cpu_list
+{
+  open(local *INPUTFILE, "/proc/cpuinfo") or die "Can't access /proc/cpuinfo!";
+  local $_;
+  my $entry;
+
+  while (<INPUTFILE>) {
+    if (m/^processor\s*:\s*(\d+)/) {
+      push @cpu, $entry if scalar keys(%{$entry}); # Previous entry
+      $entry = {}; # New entry
+      next;
+    }
+    if (m/^(vendor_id|cpu family|model|model name|stepping)\s*:\s*(.+)$/) {
+      my $k = $1;
+      my $v = $2;
+      $v =~ s/\s+/ /g;	# Merge multiple spaces
+      $v =~ s/ $//;	# Trim trailing space
+      $entry->{$k} = $v;
+      next;
+    }
+  }
+  push @cpu, $entry if scalar keys(%{$entry}); # Last entry
+  close INPUTFILE;
+}
+
+# @i2c_adapters is a list of references to hashes, one hash per I2C/SMBus
+# adapter present on the system. Each entry has the following keys: name
+# (directly taken from either /proc/bus/i2c or /sys/class/i2c-adapter) and
+# driver.
+use vars qw(@i2c_adapters);
+
+sub initialize_i2c_adapters_list
+{
+  my $entry;
+  local $_;
+
+  if (defined $sysfs_root) {
+    my $class_dir = "${sysfs_root}/class/i2c-adapter";
+    opendir(local *ADAPTERS, $class_dir) or return;
+
+    while (defined($_ = readdir(ADAPTERS))) {
+      next unless m/^i2c-(\d+)$/;
+      $entry = {}; # New entry
+      $entry->{'name'} = sysfs_device_attribute("${class_dir}/i2c-$1", "name")
+                      || sysfs_device_attribute("${class_dir}/i2c-$1/device", "name");
+      next if $entry->{'name'} eq "ISA main adapter";
+      $entry->{'driver'} = find_adapter_driver($entry->{'name'});
+      $i2c_adapters[$1] = $entry;
+    }
+    closedir(ADAPTERS);
+  } else {
+    open(local *INPUTFILE, "/proc/bus/i2c") or return;
+
+    while (<INPUTFILE>) {
+      my ($nr, $type, $name) = /^i2c-(\d+)\s+(\S+)\s+(.*?) *(\t|$)/;
+      next if ($type eq "dummy" || $type eq "isa");
+      $entry = {}; # New entry
+      $entry->{'name'} = $name;
+      $entry->{'driver'} = find_adapter_driver($name);
+      $i2c_adapters[$nr] = $entry;
+    }
+    close(INPUTFILE);
+  }
+}
+
+###########
+# MODULES #
+###########
+
+use vars qw(%modules_list %modules_supported);
+
+sub initialize_modules_list
+{
+  open(local *INPUTFILE, "/proc/modules") or return;
+  local $_;
+  while (<INPUTFILE>) {
+    tr/_/-/;
+    $modules_list{$1} = 1 if m/^(\S*)/;
+  }
+}
+
+sub initialize_modules_supported
+{
+  foreach my $chip (@chip_ids) {
+    $modules_supported{$chip->{driver}}++;
+  }
+}
+
+#################
+# SYSFS HELPERS #
+#################
+
+# From a sysfs device path, return the driver name, or undef
+sub sysfs_device_driver($)
+{
+  my $device = shift;
+  
+  my $link = readlink("$device/driver");
+  return unless defined $link;
+  return basename($link);
+}
+
+# From a sysfs device path and an attribute name, return the attribute
+# value, or undef
+sub sysfs_device_attribute($$)
+{
+  my ($device, $attr) = @_;
+  my $value;
+
+  open(local *FILE, "$device/$attr") or return;
+  return unless defined($value = <FILE>);
+  close(FILE);
+
+  chomp($value);
+  return $value;
+}
+
+##############
+# PCI ACCESS #
+##############
+
+use vars qw(%pci_list);
+
+# This function returns a list of hashes. Each hash has some PCI information:
+# 'domain', 'bus', 'slot' and 'func' uniquely identify a PCI device in a
+# computer; 'vendid' and 'devid' uniquely identify a type of device.
+# 'class' lets us spot unknown SMBus adapters.
+# This function is used when sysfs is available (Linux 2.6).
+sub read_sys_dev_pci($)
+{
+  my $devices = shift;
+  my ($dev, @pci_list);
+
+  opendir(local *DEVICES, "$devices")
+    or die "$devices: $!";
+
+  while (defined($dev = readdir(DEVICES))) {
+    my %record;
+    next unless $dev =~
+      m/^(?:([\da-f]+):)?([\da-f]+):([\da-f]+)\.([\da-f]+)$/;
+
+    $record{domain} = hex $1;
+    $record{bus} = hex $2;
+    $record{slot} = hex $3;
+    $record{func} = hex $4;
+
+    $record{vendid} = oct sysfs_device_attribute("$devices/$dev", "vendor");
+    $record{devid} = oct sysfs_device_attribute("$devices/$dev", "device");
+    $record{class} = (oct sysfs_device_attribute("$devices/$dev", "class"))
+                     >> 8;
+
+    push @pci_list, \%record;
+  }
+
+  return \@pci_list;
+}
+
+# This function returns a list of hashes. Each hash has some PCI information:
+# 'bus', 'slot' and 'func' uniquely identify a PCI device in a computer;
+# 'vendid' and 'devid' uniquely identify a type of device.
+# This function is used when sysfs is not available (Linux 2.4).
+sub read_proc_dev_pci
+{
+  my ($dfn, $vend, @pci_list);
+  open(local *INPUTFILE, "/proc/bus/pci/devices")
+    or die "/proc/bus/pci/devices: $!";
+  local $_;
+  while (<INPUTFILE>) {
+    my %record;
+    ($dfn, $vend) = map { hex } (split) [0..1];
+    $record{bus} = $dfn >> 8;
+    $record{slot} = ($dfn & 0xf8) >> 3;
+    $record{func} = $dfn & 0x07;
+    $record{vendid} = $vend >> 16;
+    $record{devid} = $vend & 0xffff;
+    
+    push @pci_list, \%record;
+  }
+  return \@pci_list;
+}
+
+sub initialize_proc_pci
+{
+  my $pci_list;
+
+  if (defined $sysfs_root) {
+    $pci_list = read_sys_dev_pci("$sysfs_root/bus/pci/devices");
+  } else {
+    $pci_list = read_proc_dev_pci();
+  }
+
+  # Note that we lose duplicate devices at this point, but we don't
+  # really care. What matters to us is which unique devices are present,
+  # not how many of each.
+  %pci_list = map {
+    sprintf("%04x:%04x", $_->{vendid}, $_->{devid}) => $_
+  } @{$pci_list};
+}
+
+#####################
+# ADAPTER DETECTION #
+#####################
+
+sub adapter_pci_detection_sis_96x
+{
+  my $driver="";
+
+  # first, determine which driver if any...
+  if (kernel_version_at_least(2,6,0)) {
+    if (exists $pci_list{"1039:0016"}) {
+      $driver = "i2c-sis96x";
+    } elsif (exists $pci_list{"1039:0008"}) {
+      $driver = "i2c-sis5595";
+    }
+  } elsif (kernel_version_at_least(2,4,0)) {
+    if (exists $pci_list{"1039:0008"}) {
+      if ((exists $pci_list{"1039:0645"}) ||
+          (exists $pci_list{"1039:0646"}) ||
+          (exists $pci_list{"1039:0648"}) ||
+          (exists $pci_list{"1039:0650"}) ||
+          (exists $pci_list{"1039:0651"}) ||
+          (exists $pci_list{"1039:0655"}) ||
+          (exists $pci_list{"1039:0661"}) ||
+          (exists $pci_list{"1039:0735"}) ||
+          (exists $pci_list{"1039:0745"}) ||
+          (exists $pci_list{"1039:0746"})) {
+        $driver = "i2c-sis645";
+      } else {
+        $driver = "i2c-sis5595";
+      }
+    } elsif ((exists $pci_list{"1039:0016"}) ||
+             (exists $pci_list{"1039:0018"})) {
+      $driver = "i2c-sis645";
+    }
+  }
+
+  # then, add the appropriate entries to @pci_adapters
+  if ($driver eq "i2c-sis5595") {
+    push @pci_adapters, @pci_adapters_sis5595;
+  } elsif ($driver eq "i2c-sis645") {
+    push @pci_adapters, @pci_adapters_sis645;
+  } elsif ($driver eq "i2c-sis96x") {
+    push @pci_adapters, @pci_adapters_sis96x;
+  }
+}
+
+# Build and return a PCI device's bus ID
+sub pci_busid($)
+{
+  my $device = shift;
+  my $busid;
+
+  $busid = sprintf("\%02x:\%02x.\%x",
+                   $device->{bus}, $device->{slot}, $device->{func});
+  $busid = sprintf("\%04x:", $device->{domain}) . $busid
+    if defined $device->{domain};
+
+  return $busid;
+}
+
+sub adapter_pci_detection
+{
+  my ($key, $device, $try, @res, %smbus);
+  print "Probing for PCI bus adapters...\n";
+
+  # Custom detection routine for some SiS chipsets
+  adapter_pci_detection_sis_96x();
+
+  # Build a list of detected SMBus devices
+  foreach $key (keys %pci_list) {
+    $device = $pci_list{$key};
+    $smbus{$key}++
+      if exists $device->{class} && $device->{class} == 0x0c05; # SMBus
+  }
+
+  # Loop over the known I2C/SMBus adapters
+  foreach $try (@pci_adapters) {
+    $key = sprintf("%04x:%04x", $try->{vendid}, $try->{devid});
+    if (exists $pci_list{$key}) {
+        $device = $pci_list{$key};
+        printf "Use driver `\%s' for device \%s: \%s\n",
+               $try->{driver}, pci_busid($device), $try->{procid};
+        if ($try->{driver} eq "to-be-tested") {
+          print "\nWe are currently looking for testers for this adapter!\n".
+                "Please check http://www.lm-sensors.org/wiki/Devices\n".
+                "and/or contact us if you want to help.\n\n";
+          print "Continue... ";
+          <STDIN>;
+          print "\n";
+        }
+        push @res,$try->{driver};
+
+        # Delete from detected SMBus device list
+        delete $smbus{$key};
+    }
+  }
+
+  # Now see if there are unknown SMBus devices left
+  foreach $key (keys %smbus) {
+    $device = $pci_list{$key};
+    printf "Found unknown SMBus adapter \%04x:\%04x at \%s.\n",
+           $device->{vendid}, $device->{devid}, pci_busid($device);
+  }
+  
+  if (! @res) {
+    print "Sorry, no known PCI bus adapters found.\n";
+  }
+  return @res;
+}
+
+# $_[0]: Adapter description as found in /proc/bus/i2c or sysfs
+sub find_adapter_driver
+{
+  my $adapter;
+  for $adapter (@pci_adapters) {
+    return $adapter->{driver}
+      if (exists $adapter->{match} && $_[0] =~ $adapter->{match});
+  }
+  return "UNKNOWN";
+}
+
+#############################
+# I2C AND SMBUS /DEV ACCESS #
+#############################
+
+# This should really go into a separate module/package.
+
+# These are copied from <linux/i2c-dev.h>
+
+use constant IOCTL_I2C_SLAVE    => 0x0703;
+use constant IOCTL_I2C_FUNCS    => 0x0705;
+use constant IOCTL_I2C_SMBUS    => 0x0720;
+
+use constant SMBUS_READ         => 1;
+use constant SMBUS_WRITE        => 0;
+
+use constant SMBUS_QUICK        => 0;
+use constant SMBUS_BYTE         => 1;
+use constant SMBUS_BYTE_DATA    => 2;
+use constant SMBUS_WORD_DATA    => 3;
+
+use constant I2C_FUNC_SMBUS_QUICK	=> 0x00010000;
+use constant I2C_FUNC_SMBUS_READ_BYTE	=> 0x00020000;
+
+# Get the i2c adapter's functionalities
+# $_[0]: Reference to an opened filehandle
+# Returns: -1 on failure, functionality bitfield on success.
+sub i2c_get_funcs($)
+{
+  my $file = shift;
+  my $funcs = pack "L", 0; # Allocate space
+
+  ioctl $file, IOCTL_I2C_FUNCS, $funcs or return -1;
+  $funcs = unpack "L", $funcs;
+
+  return $funcs;
+}
+
+# Select the device to communicate with through its address.
+# $_[0]: Reference to an opened filehandle
+# $_[1]: Address to select
+# Returns: 0 on failure, 1 on success.
+sub i2c_set_slave_addr
+{
+  my ($file,$addr) = @_;
+  $addr += 0; # Make sure it's a number not a string
+  ioctl $file, IOCTL_I2C_SLAVE, $addr or return 0;
+  return 1;
+}
+
+# i2c_smbus_access is based upon the corresponding C function (see 
+# <linux/i2c-dev.h>). You should not need to call this directly.
+# Exact calling conventions are intricate; read i2c-dev.c if you really need
+# to know.
+# $_[0]: Reference to an opened filehandle
+# $_[1]: SMBUS_READ for reading, SMBUS_WRITE for writing
+# $_[2]: Command (usually register number)
+# $_[3]: Transaction kind (SMBUS_BYTE, SMBUS_BYTE_DATA, etc.)
+# $_[4]: Reference to an array used for input/output of data
+# Returns: 0 on failure, 1 on success.
+# Note that we need to get back to Integer boundaries through the 'x2'
+# in the pack. This is very compiler-dependent; I wish there was some other 
+# way to do this.
+sub i2c_smbus_access
+{
+  my ($file,$read_write,$command,$size,$data) = @_;
+  my $data_array = pack "C32", @$data;
+  my $ioctl_data = pack "C2x2Ip", ($read_write,$command,$size,$data_array);
+  ioctl $file, IOCTL_I2C_SMBUS, $ioctl_data or return 0;
+  @{$_[4]} = unpack "C32",$data_array;
+  return 1;
+}
+
+# $_[0]: Reference to an opened filehandle
+# $_[1]: Either 0 or 1
+# Returns: -1 on failure, the 0 on success.
+sub i2c_smbus_write_quick
+{
+  my ($file,$value) = @_;
+  my @data;
+  i2c_smbus_access $file, $value, 0, SMBUS_QUICK, \@data
+         or return -1;
+  return 0;
+}
+
+# $_[0]: Reference to an opened filehandle
+# Returns: -1 on failure, the read byte on success.
+sub i2c_smbus_read_byte
+{
+  my ($file) = @_;
+  my @data;
+  i2c_smbus_access $file, SMBUS_READ, 0, SMBUS_BYTE, \@data
+         or return -1;
+  return $data[0];
+}
+
+# $_[0]: Reference to an opened filehandle
+# $_[1]: Command byte (usually register number)
+# Returns: -1 on failure, the read byte on success.
+sub i2c_smbus_read_byte_data
+{
+  my ($file,$command) = @_;
+  my @data;
+  i2c_smbus_access $file, SMBUS_READ, $command, SMBUS_BYTE_DATA, \@data
+         or return -1;
+  return $data[0];
+}
+  
+# $_[0]: Reference to an opened filehandle
+# $_[1]: Command byte (usually register number)
+# Returns: -1 on failure, the read word on success.
+# Note: some devices use the wrong endiannes; use swap_bytes to correct for 
+# this.
+sub i2c_smbus_read_word_data
+{
+  my ($file,$command) = @_;
+  my @data;
+  i2c_smbus_access $file, SMBUS_READ, $command, SMBUS_WORD_DATA, \@data
+         or return -1;
+  return $data[0] + 256 * $data[1];
+}
+
+# $_[0]: Reference to an opened filehandle
+# $_[1]: Address
+# $_[2]: Functionalities of this i2c adapter
+# Returns: 1 on successful probing, 0 else.
+# This function is meant to prevent AT24RF08 corruption and write-only
+# chips locks. This is done by choosing the best probing method depending
+# on the address range.
+sub i2c_probe($$$)
+{
+  my ($file, $addr, $funcs) = @_;
+  my $data = [];
+  if (($addr >= 0x50 && $addr <= 0x5F)
+   || ($addr >= 0x30 && $addr <= 0x37)) {
+    # This covers all EEPROMs we know of, including page protection addresses.
+    # Note that some page protection addresses will not reveal themselves with
+    # this, because they ack on write only, but this is probably better since
+    # some EEPROMs write-protect themselves permanently on almost any write to
+    # their page protection address.
+    return 0 unless ($funcs & I2C_FUNC_SMBUS_READ_BYTE);
+    return i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE, $data);
+  } else {
+    return 0 unless ($funcs & I2C_FUNC_SMBUS_QUICK);
+    return i2c_smbus_access($file, SMBUS_WRITE, 0, SMBUS_QUICK, $data);
+  }
+}
+
+####################
+# ADAPTER SCANNING #
+####################
+
+use vars qw(@chips_detected);
+
+# We will build a complicated structure @chips_detected here, being:
+# A list of
+#  references to hashes
+#    with field 'driver', being a string with the driver name for this chip;
+#    with field 'detected'
+#      being a reference to a list of
+#        references to hashes of type 'detect_data';
+#    with field 'misdetected'
+#      being a reference to a list of
+#        references to hashes of type 'detect_data'
+
+# Type detect_data:
+# A hash
+#   with field 'i2c_adap' containing an adapter string as appearing
+#        in /proc/bus/i2c (if this is an I2C detection)
+#  with field 'i2c_devnr', contianing the /dev/i2c-* number of this
+#       adapter (if this is an I2C detection)
+#  with field 'i2c_driver', containing the driver name for this adapter
+#       (if this is an I2C detection)
+#  with field 'i2c_addr', containing the I2C address of the detection;
+#       (if this is an I2C detection)
+#  with field 'i2c_sub_addrs', containing a reference to a list of
+#       other I2C addresses (if this is an I2C detection)
+#  with field 'isa_addr' containing the ISA address this chip is on 
+#       (if this is an ISA detection)
+#  with field 'conf', containing the confidence level of this detection
+#  with field 'chipname', containing the chip name
+
+# This adds a detection to the above structure. We do no alias detection
+# here; so you should do ISA detections *after* all I2C detections.
+# Not all possibilities of i2c_addr and i2c_sub_addrs are exhausted.
+# In all normal cases, it should be all right.
+# $_[0]: chip driver
+# $_[1]: reference to data hash
+# Returns: Nothing
+sub add_i2c_to_chips_detected
+{
+  my ($chipdriver,$datahash) = @_;
+  my ($i,$new_detected_ref,$new_misdetected_ref,$detected_ref,$misdetected_ref,
+      $main_entry,$detected_entry,$put_in_detected,@hash_addrs,@entry_addrs,
+      $do_not_add);
+
+  # First determine where the hash has to be added.
+  for ($i = 0; $i < @chips_detected; $i++) {
+    last if ($chips_detected[$i]->{driver} eq $chipdriver);
+  }
+  if ($i == @chips_detected) {
+    push @chips_detected, { driver => $chipdriver,
+                            detected => [],
+                            misdetected => [] };
+  }
+  $new_detected_ref = $chips_detected[$i]->{detected};
+  $new_misdetected_ref = $chips_detected[$i]->{misdetected};
+
+  # Find out whether our new entry should go into the detected or the
+  # misdetected list. We compare all i2c addresses; if at least one matches,
+  # but our conf value is lower, we assume this is a misdetect.
+  @hash_addrs = ($datahash->{i2c_addr});
+  push @hash_addrs, @{$datahash->{i2c_sub_addrs}}
+       if exists $datahash->{i2c_sub_addrs};
+  $put_in_detected = 1;
+  $do_not_add = 0;
+  FIND_LOOP:
+  foreach $main_entry (@chips_detected) {
+    foreach $detected_entry (@{$main_entry->{detected}}) {
+      @entry_addrs = ($detected_entry->{i2c_addr});
+      push @entry_addrs, @{$detected_entry->{i2c_sub_addrs}}
+               if exists $detected_entry->{i2c_sub_addrs};
+      if ($detected_entry->{i2c_devnr} == $datahash->{i2c_devnr} and
+          any_list_match \@entry_addrs, \@hash_addrs) {
+        if ($detected_entry->{conf} >= $datahash->{conf}) {
+          $put_in_detected = 0;
+        }
+        if ($chipdriver eq $main_entry->{driver}) {
+          $do_not_add = 1;
+        }
+        last FIND_LOOP;
+      }
+    }
+  }
+
+  if ($put_in_detected) {
+    # Here, we move all entries from detected to misdetected which
+    # match at least in one main or sub address. This may not be the
+    # best idea to do, as it may remove detections without replacing
+    # them with second-best ones. Too bad.
+    # (Khali 2003-09-13) If the driver is the same, the "misdetected"
+    # entry is simply deleted; failing to do so cause the configuration
+    # lines generated later to look very confusing (the driver will
+    # be told to ignore valid addresses).
+    @hash_addrs = ($datahash->{i2c_addr});
+    push @hash_addrs, @{$datahash->{i2c_sub_addrs}} 
+         if exists $datahash->{i2c_sub_addrs};
+    foreach $main_entry (@chips_detected) {
+      $detected_ref = $main_entry->{detected};
+      $misdetected_ref = $main_entry->{misdetected};
+      for ($i = @$detected_ref-1; $i >=0; $i--) {
+        @entry_addrs = ($detected_ref->[$i]->{i2c_addr});
+        push @entry_addrs, @{$detected_ref->[$i]->{i2c_sub_addrs}}
+             if exists $detected_ref->[$i]->{i2c_sub_addrs};
+        if ($detected_ref->[$i]->{i2c_devnr} == $datahash->{i2c_devnr} and
+            any_list_match \@entry_addrs, \@hash_addrs) {
+          push @$misdetected_ref,$detected_ref->[$i]
+            unless $chipdriver eq $main_entry->{driver};
+          splice @$detected_ref, $i, 1;
+        }
+      }
+    }
+
+    # Now add the new entry to detected
+    push @$new_detected_ref, $datahash;
+  } else {
+    # No hard work here 
+    push @$new_misdetected_ref, $datahash
+      unless $do_not_add;
+  }
+}
+
+# This adds a detection to the above structure. We also do alias detection
+# here; so you should do ISA detections *after* all I2C detections.
+# $_[0]: alias detection function
+# $_[1]: chip driver
+# $_[2]: reference to data hash
+# Returns: 0 if it is not an alias, datahash reference if it is.
+sub add_isa_to_chips_detected
+{
+  my ($alias_detect,$chipdriver,$datahash) = @_;
+  my ($i,$new_detected_ref,$new_misdetected_ref,$detected_ref,$misdetected_ref,
+      $main_entry,$isalias);
+
+  # First determine where the hash has to be added.
+  $isalias=0;
+  for ($i = 0; $i < @chips_detected; $i++) {
+    last if ($chips_detected[$i]->{driver} eq $chipdriver);
+  }
+  if ($i == @chips_detected) {
+    push @chips_detected, { driver => $chipdriver,
+                            detected => [],
+                            misdetected => [] };
+  }
+  $new_detected_ref = $chips_detected[$i]->{detected};
+  $new_misdetected_ref = $chips_detected[$i]->{misdetected};
+
+  # Now, we are looking for aliases. An alias can only be the same chiptype.
+  # If an alias is found in the misdetected list, we add the new information
+  # and terminate this function. If it is found in the detected list, we
+  # still have to check whether another chip has claimed this ISA address.
+  # So we remove the old entry from the detected list and put it in datahash.
+
+  # Misdetected alias detection:
+  for ($i = 0; $i < @$new_misdetected_ref; $i++) {
+    if (exists $new_misdetected_ref->[$i]->{i2c_addr} and
+        not exists $new_misdetected_ref->[$i]->{isa_addr} and
+        defined $alias_detect and
+        $new_misdetected_ref->[$i]->{chipname} eq $datahash->{chipname}) {
+      open(local *FILE, "$dev_i2c$new_misdetected_ref->[$i]->{i2c_devnr}") or
+        print("Can't open $dev_i2c$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"),
+        next;
+      binmode FILE;
+      i2c_set_slave_addr \*FILE,$new_misdetected_ref->[$i]->{i2c_addr} or
+           print("Can't set I2C address for ",
+                 "$dev_i2c$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"),
+           next;
+      if (&$alias_detect ($datahash->{isa_addr},\*FILE,
+                          $new_misdetected_ref->[$i]->{i2c_addr})) {
+        $new_misdetected_ref->[$i]->{isa_addr} = $datahash->{isa_addr};
+        return $new_misdetected_ref->[$i]; 
+      }
+    }
+  }
+
+  # Detected alias detection:
+  for ($i = 0; $i < @$new_detected_ref; $i++) {
+    if (exists $new_detected_ref->[$i]->{i2c_addr} and
+        not exists $new_detected_ref->[$i]->{isa_addr} and
+        defined $alias_detect and
+        $new_detected_ref->[$i]->{chipname} eq $datahash->{chipname}) {
+      open(local *FILE, "$dev_i2c$new_detected_ref->[$i]->{i2c_devnr}") or
+        print("Can't open $dev_i2c$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
+        next;
+      binmode FILE;
+      i2c_set_slave_addr \*FILE,$new_detected_ref->[$i]->{i2c_addr} or
+           print("Can't set I2C address for ",
+                 "$dev_i2c$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
+           next;
+      if (&$alias_detect ($datahash->{isa_addr},\*FILE,
+                          $new_detected_ref->[$i]->{i2c_addr})) {
+        $new_detected_ref->[$i]->{isa_addr} = $datahash->{isa_addr};
+        ($datahash) = splice (@$new_detected_ref, $i, 1);
+        $isalias=1;
+        last;
+      }
+    }
+  }
+
+
+  # Find out whether our new entry should go into the detected or the
+  # misdetected list. We only compare main isa_addr here, of course.
+  # (Khali 2004-05-12) If the driver is the same, the "misdetected"
+  # entry is simply deleted; same we do for I2C chips.
+  foreach $main_entry (@chips_detected) {
+    $detected_ref = $main_entry->{detected};
+    $misdetected_ref = $main_entry->{misdetected};
+    for ($i = 0; $i < @{$main_entry->{detected}}; $i++) {
+      if (exists $detected_ref->[$i]->{isa_addr} and
+          exists $datahash->{isa_addr} and
+          $detected_ref->[$i]->{isa_addr} == $datahash->{isa_addr}) {
+        if ($detected_ref->[$i]->{conf} >= $datahash->{conf}) {
+          push @$new_misdetected_ref, $datahash
+            unless $main_entry->{driver} eq $chipdriver;
+        } else {
+          push @$misdetected_ref,$detected_ref->[$i]
+            unless $main_entry->{driver} eq $chipdriver;
+          splice @$detected_ref, $i,1;
+          push @$new_detected_ref, $datahash;
+        }
+        if ($isalias) {
+          return $datahash;
+        } else {
+          return 0;
+        }
+      }
+    }
+  }
+
+  # Not found? OK, put it in the detected list
+  push @$new_detected_ref, $datahash;
+  if ($isalias) {
+    return $datahash;
+  } else {
+    return 0;
+  }
+}
+
+# From the list of known I2C/SMBus devices, build a list of I2C addresses
+# which are worth probing. There's no point in probing an address for which
+# we don't know a single device, and probing some addresses has caused
+# random trouble in the past.
+sub i2c_addresses_to_scan()
+{
+  my @used;
+  my @addresses;
+  my $addr;
+
+  foreach my $chip (@chip_ids) {
+    next unless defined $chip->{'i2c_addrs'};
+    next if $chip->{'driver'} eq 'not-a-sensor';
+    foreach $addr (@{$chip->{'i2c_addrs'}}) {
+      $used[$addr]++;
+    }
+  }
+
+  for ($addr = 0x03; $addr <= 0x77; $addr++) {
+    push @addresses, $addr if $used[$addr];
+  }
+  return \@addresses;
+}
+
+# $_[0]: The number of the adapter to scan
+# $_[1]: The name of the adapter, as appearing in /proc/bus/i2c
+# $_[2]: The driver of the adapter
+# @_[3]: Addresses not to scan (array reference)
+sub scan_adapter
+{
+  my ($adapter_nr, $adapter_name, $adapter_driver, $not_to_scan) = @_;
+  my ($funcs, $chip, $addr, $conf, @chips, $new_hash, $other_addr);
+
+  # As we modify it, we need a copy
+  my @not_to_scan = @$not_to_scan;
+
+  open(local *FILE, "$dev_i2c$adapter_nr") or 
+    (print "Can't open $dev_i2c$adapter_nr\n"), return;
+  binmode FILE;
+
+  # Can we probe this adapter?
+  $funcs = i2c_get_funcs(\*FILE);
+  if ($funcs < 0) {
+    print "Adapter failed to provide its functionalities, skipping.\n";
+    return;
+  }
+  if (!($funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
+    print "Adapter cannot be probed, skipping.\n";
+    return;
+  }
+  if (~$funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE)) {
+    print "Adapter doesn't support all probing functions.\n",
+          "Some addresses won't be probed.\n";
+  }
+
+  # Now scan each address in turn
+  foreach $addr (@{$i2c_addresses_to_scan}) {
+    # As the not_to_scan list is sorted, we can check it fast
+    if (@not_to_scan and $not_to_scan[0] == $addr) {
+      shift @not_to_scan;
+      next;
+    }
+
+    if (!i2c_set_slave_addr(\*FILE, $addr)) {
+      # If the address is busy, in Linux 2.6 we can find out which driver
+      # is using it, and we assume it is the right one. In Linux 2.4 we
+      # just give up and warn the user.
+      my ($device, $driver);
+      if (defined($sysfs_root)) {
+        $device = sprintf("$sysfs_root/bus/i2c/devices/\%d-\%04x",
+                             $adapter_nr, $addr);
+        $driver = sysfs_device_driver($device);
+      }
+      if (defined($driver)) {
+        $new_hash = {
+          conf => 6, # Arbitrary confidence
+          i2c_addr => $addr,
+          chipname => sysfs_device_attribute($device, "name") || "unknown",
+          i2c_adap => $adapter_name,
+          i2c_driver => $adapter_driver,
+          i2c_devnr => $adapter_nr,
+        };
+
+        printf "Client found at address 0x\%02x\n", $addr;
+        printf "Handled by driver `\%s' (already loaded), chip type `\%s'\n",
+               $driver, $new_hash->{chipname};
+
+        # Only add it to the list if this is something we would have
+        # detected, else we end up with random i2c chip drivers listed
+        # (for example media/video drivers.)
+        if (exists $modules_supported{$driver}) {
+          add_i2c_to_chips_detected($driver, $new_hash);
+        } else {
+          print "    (note: this is probably NOT a sensor chip!)\n";
+        }    
+      } else {
+        printf("Client at address 0x%02x can not be probed - ".
+               "unload all client drivers first!\n", $addr);
+      }
+      next;
+    }
+
+    next unless i2c_probe(\*FILE, $addr, $funcs);
+    printf "Client found at address 0x%02x\n",$addr;
+
+    $| = 1;
+    foreach $chip (@chip_ids) {
+      if (exists $chip->{i2c_addrs} and contains $addr, @{$chip->{i2c_addrs}}) {
+        printf("\%-60s", sprintf("Probing for `\%s'... ", $chip->{name}));
+        if (($conf,@chips) = &{$chip->{i2c_detect}} (\*FILE ,$addr)) {
+          if ($chip->{driver} eq "not-a-sensor") {
+            print "Yes\n",
+                  "    (confidence $conf, not a hardware monitoring chip";
+          } else {
+            print "Success!\n",
+                  "    (confidence $conf, driver `$chip->{driver}'";
+          }
+          if (@chips) {
+            print ", other addresses:";
+            @chips = sort @chips;
+            foreach $other_addr (@chips) {
+              printf(" 0x%02x",$other_addr);
+            }
+          }
+          printf ")\n";
+
+          next if ($chip->{driver} eq "not-a-sensor"
+                || $chip->{driver} eq "use-isa-instead");
+
+          $new_hash = { conf => $conf,
+                        i2c_addr => $addr,
+                        chipname => $chip->{name},
+                        i2c_adap => $adapter_name,
+                        i2c_driver => $adapter_driver,
+                        i2c_devnr => $adapter_nr,
+                      };
+          if (@chips) {
+            my @chips_copy = @chips;
+            $new_hash->{i2c_sub_addrs} = \@chips_copy;
+          }
+          add_i2c_to_chips_detected $chip->{driver}, $new_hash;
+        } else {
+          print "No\n";
+        }
+      }
+    }
+    $| = 0;
+  }
+}
+
+sub scan_isa_bus
+{
+  my ($chip,$addr,$conf);
+  $| = 1;
+  foreach $chip (@chip_ids) {
+    next if not exists $chip->{isa_addrs} or not exists $chip->{isa_detect};
+    foreach $addr (@{$chip->{isa_addrs}}) {
+      printf("\%-60s", sprintf("Probing for `\%s'\%s... ", $chip->{name},
+                               $addr ? sprintf(" at 0x\%x", $addr) : ''));
+      $conf = &{$chip->{isa_detect}} ($addr);
+      print("No\n"), next if not defined $conf;
+      print "Success!\n";
+      printf "    (confidence %d, driver `%s')\n", $conf, $chip->{driver};
+      my $new_hash = { conf => $conf,
+                       isa_addr => $addr,
+                       chipname => $chip->{name}
+                     };
+      $new_hash = add_isa_to_chips_detected $chip->{alias_detect},$chip->{driver},
+                                            $new_hash;
+      if ($new_hash) {
+        printf "    Alias of the chip on I2C bus `%s', address 0x%04x\n",
+                        $new_hash->{i2c_adap},$new_hash->{i2c_addr};
+      }
+    }
+  }
+  $| = 0;
+}
+
+use vars qw(%superio);
+
+# The following are taken from the PNP ISA spec (so it's supposed
+# to be common to all Super I/O chips):
+#  devidreg: The device ID register(s)
+#  logdevreg: The logical device register
+#  actreg: The activation register within the logical device
+#  actmask: The activation bit in the activation register
+#  basereg: The I/O base register within the logical device
+%superio = (
+  devidreg => 0x20,
+  logdevreg => 0x07,
+  actreg => 0x30,
+  actmask => 0x01,
+  basereg => 0x60,
+);
+
+sub exit_superio
+{
+  my ($addrreg, $datareg) = @_;
+
+  # Some chips (SMSC, Winbond) want this
+  outb($addrreg, 0xaa);
+
+  # Return to "Wait For Key" state (PNP-ISA spec)
+  outb($addrreg, 0x02);
+  outb($datareg, 0x02);
+}
+
+# Guess if an unknown Super-I/O chip has sensors
+sub guess_superio_ld($$$)
+{
+  my ($addrreg, $datareg, $typical_addr) = @_;
+  my ($oldldn, $ldn, $addr);
+
+  # Save logical device number
+  outb($addrreg, $superio{logdevreg});
+  $oldldn = inb($datareg);
+
+  for ($ldn = 0; $ldn < 16; $ldn++) {
+    # Select logical device
+    outb($addrreg, $superio{logdevreg});
+    outb($datareg, $ldn);
+
+    # Read base I/O address
+    outb($addrreg, $superio{basereg});
+    $addr = inb($datareg) << 8;
+    outb($addrreg, $superio{basereg} + 1);
+    $addr |= inb($datareg);
+    next unless ($addr & 0xfff8) == $typical_addr;
+
+    printf "    (logical device \%X has address 0x\%x, could be sensors)\n",
+           $ldn, $addr;
+    last;
+  }
+
+  # Be nice, restore original logical device
+  outb($addrreg, $superio{logdevreg});
+  outb($datareg, $oldldn);
+}
+
+sub probe_superio($$$)
+{
+  my ($addrreg, $datareg, $chip) = @_;
+  my ($val, $addr);
+
+  printf "\%-60s",  "Found `$chip->{name}'";
+
+  # Does it have hardware monitoring capabilities?
+  if (!exists $chip->{driver}) {
+    print "\n    (no information available)\n";
+    return;
+  }
+  if ($chip->{driver} eq "not-a-sensor") {
+    print "\n    (no hardware monitoring capabilities)\n";
+    return;
+  }
+  if ($chip->{driver} eq "via-smbus-only") {
+    print "\n    (hardware monitoring capabilities accessible via SMBus only)\n";
+    return;
+  }
+
+  # Switch to the sensor logical device
+  outb($addrreg, $superio{logdevreg});
+  outb($datareg, $chip->{logdev});
+
+  # Check the activation register
+  outb($addrreg, $superio{actreg});
+  $val = inb($datareg);
+  if (!($val & $superio{actmask})) {
+    print "\n    (but not activated)\n";
+    return;
+  }
+
+  # Get the IO base register
+  outb($addrreg, $superio{basereg});
+  $addr = inb($datareg);
+  outb($addrreg, $superio{basereg} + 1);
+  $addr = ($addr << 8) | inb($datareg);
+  if ($addr == 0) {
+    print "\n    (but no address specified)\n";
+    return;
+  }
+  print "Success!\n";
+  printf "    (address 0x\%x, driver `%s')\n", $addr, $chip->{driver};
+  my $new_hash = { conf => 9,
+                   isa_addr => $addr,
+                   chipname => $chip->{name}
+                 };
+  add_isa_to_chips_detected $chip->{alias_detect},$chip->{driver},
+                                        $new_hash;
+}
+
+# Detection routine for non-standard SMSC Super I/O chips
+# $_[0]: Super I/O LPC config/index port
+# $_[1]: Super I/O LPC data port
+# $_[2]: Reference to array of non-standard chips
+# Return values: 1 if non-standard chip found, 0 otherwise
+sub smsc_ns_detect_superio
+{
+    my ($addrreg, $datareg, $ns_chips) = @_;
+    my ($val, $chip);
+
+    # read alternate device ID register
+    outb($addrreg, 0x0d);
+    $val = inb($datareg);
+    if ($val == 0x00 || $val == 0xff) {
+	return 0;
+    }
+
+    print "Yes\n";
+
+    foreach $chip (@{$ns_chips}) {
+	if ($chip->{devid} == $val) {
+	    probe_superio($addrreg, $datareg, $chip);
+	    return 1;
+	}
+    }
+
+    printf("Found unknown non-standard chip with ID 0x%02x\n", $val);
+    return 1;
+}
+
+sub scan_superio
+{
+  my ($addrreg, $datareg) = @_;
+  my ($val, $found);
+
+  printf("Probing for Super-I/O at 0x\%x/0x\%x\n", $addrreg, $datareg);
+
+  $| = 1;
+# reset state to avoid false positives
+  exit_superio($addrreg, $datareg);
+  FAMILY: 
+  foreach my $family (@superio_ids) {
+    printf("\%-60s", "Trying family `$family->{family}'... ");
+# write the password
+    foreach $val (@{$family->{enter}->{$addrreg}}) {
+      outb($addrreg, $val);
+    }
+# call the non-standard detection routine first if it exists
+    if (defined($family->{ns_detect}) && 
+        &{$family->{ns_detect}}($addrreg, $datareg, $family->{ns_chips})) {
+      exit_superio($addrreg, $datareg);
+      last FAMILY;
+    }
+# did it work?
+    outb($addrreg, $superio{devidreg});
+    $val = inb($datareg);
+    outb($addrreg, $superio{devidreg} + 1);
+    $val = ($val << 8) | inb($datareg);
+    if ($val == 0x0000 || $val == 0xffff) {
+      print "No\n";
+      next FAMILY;
+    }
+    print "Yes\n";
+
+    $found = 0;
+    foreach my $chip (@{$family->{chips}}) {
+      if (($chip->{devid} > 0xff && ($val & ($chip->{devid_mask} || 0xffff)) == $chip->{devid})
+       || ($chip->{devid} <= 0xff && ($val >> 8) == $chip->{devid})) {
+        probe_superio($addrreg, $datareg, $chip);
+        $found++;
+      }
+    }
+
+    if (!$found) {
+      printf("Found unknown chip with ID 0x%04x\n", $val);
+      # Guess if a logical device could correspond to sensors
+      guess_superio_ld($addrreg, $datareg, $family->{guess})
+        if defined $family->{guess};
+    }
+
+    exit_superio($addrreg, $datareg);
+    last FAMILY;
+  }
+  $| = 0;
+}
+
+
+sub scan_cpu($)
+{
+  my $entry = shift;
+  my $confidence;
+
+  printf("\%-60s", "$entry->{name}... ");
+  if (defined ($confidence = $entry->{detect}())) {
+    print "Success!\n";
+    printf "    (driver `%s')\n", $entry->{driver};
+    my $new_hash = {
+      conf => $confidence,
+      chipname => $entry->{name},
+    };
+    add_isa_to_chips_detected(undef, $entry->{driver}, $new_hash);
+  } else {
+    print "No\n";
+  }
+}
+
+
+##################
+# CHIP DETECTION #
+##################
+
+# This routine allows you to select which chips are optionally added to the
+# chip detection list. The most common use is to allow for different chip
+# detection/drivers based on different linux kernels
+# This routine follows the pattern of the SiS adapter special cases
+sub chip_special_cases
+{
+	# Based on the kernel, add the appropriate chip structure to the
+	# chip_ids detection list
+	if (kernel_version_at_least(2, 6, 0)) {
+		push @chip_ids, @chip_kern26_ids;
+	} else {
+		push @chip_ids, @chip_kern24_ids;
+	}
+}
+
+# Each function returns a confidence value. The higher this value, the more
+# sure we are about this chip. A Winbond W83781D, for example, will be
+# detected as a LM78 too; but as the Winbond detection has a higher confidence 
+# factor, you should identify it as a Winbond.
+
+# Each function returns a list. The first element is the confidence value;
+# Each element after it is an SMBus address. In this way, we can detect 
+# chips with several SMBus addresses. The SMBus address for which the
+# function was called is never returned.
+
+# If there are devices which get confused if they are only read from, then
+# this program will surely confuse them. But we guarantee never to write to
+# any of these devices.
+
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (7) if detected.
+# Registers used: 0x58
+sub mtp008_detect
+{
+  my ($file,$addr) = @_;
+  return if (i2c_smbus_read_byte_data($file,0x58)) != 0xac;
+  return (8);
+}
+  
+# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, (6) if detected.
+# Registers used:
+#   0x40: Configuration
+#   0x48: Full I2C Address
+#   0x49: Device ID
+sub lm78_detect
+{
+  my $reg;
+  my ($chip,$file,$addr) = @_;
+  return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
+  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
+  $reg = i2c_smbus_read_byte_data($file,0x49);
+  return unless ($chip == 0 and ($reg == 0x00 or $reg == 0x20)) or
+                    ($chip == 1 and $reg == 0x40) or
+                    ($chip == 2 and ($reg & 0xfe) == 0xc0);
+  return (6);
+}
+
+# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
+# $_[1]: Address
+# Returns: undef if not detected, 6 if detected.
+# Note: Only address 0x290 is scanned at this moment.
+sub lm78_isa_detect
+{
+  my ($chip,$addr) = @_ ;
+  my $val = inb ($addr + 1);
+  return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or 
+            inb ($addr + 7) != $val;
+
+  $val = inb($addr + 5);
+  outb($addr + 5, ~$val & 0x7f);
+  if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) {
+    outb($addr+5,$val);
+    return;
+  }
+  my $readproc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
+  return unless (&$readproc(0x40) & 0x80) == 0x00;
+  my $reg = &$readproc(0x49);
+  return unless ($chip == 0 and ($reg == 0x00 or $reg == 0x20)) or
+                ($chip == 1 and $reg == 0x40) or
+                ($chip == 2 and ($reg & 0xfe) == 0xc0);
+
+  # Explicitly prevent misdetection of Winbond chips
+  $reg = &$readproc(0x4f);
+  return if $reg == 0xa3 || $reg == 0x5c;
+
+  # Explicitly prevent misdetection of ITE chips
+  $reg = &$readproc(0x58);
+  return if $reg == 0x90;
+
+  return 6;
+}
+
+
+# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
+# $_[1]: ISA address
+# $_[2]: I2C file handle
+# $_[3]: I2C address
+sub lm78_alias_detect
+{
+  my ($chip,$isa_addr,$file,$i2c_addr) = @_;
+  my $i;
+  my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
+  return 0 unless &$readproc(0x48) == $i2c_addr;
+  for ($i = 0x2b; $i <= 0x3d; $i ++) {
+    return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
+  }
+  return 1;
+}
+
+# $_[0]: Chip to detect (0 = LM75, 1 = DS75)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address (unused)
+# Returns: undef if not detected, 3 or 6 if detected;
+#   6 means that the temperatures make sense;
+#   3 means that the temperatures look strange;
+# Registers used:
+#   0x00: Temperature
+#   0x01: Configuration
+#   0x02: Hysteresis
+#   0x03: Overtemperature Shutdown
+#   0x04-0x07: No registers
+# The first detection step is based on the fact that the LM75 has only
+# four registers, and cycles addresses over 8-byte boundaries. We use the
+# 0x04-0x07 addresses (unused) to improve the reliability. These are not
+# real registers and will always return the last returned value. This isn't
+# documented.
+# Note that register 0x00 may change, so we can't use the modulo trick on it.
+# The DS75 is a bit different, it doesn't cycle over 8-byte boundaries, and
+# all register addresses from 0x04 to 0x0f behave like 0x04-0x07 do for
+# the LM75.
+sub lm75_detect
+{
+  my $i;
+  my ($chip, $file, $addr) = @_;
+  my $cur = i2c_smbus_read_word_data($file,0x00);
+  my $conf = i2c_smbus_read_byte_data($file,0x01);
+
+  my $hyst = i2c_smbus_read_word_data($file,0x02);
+  my $maxreg = $chip == 1 ? 0x0f : 0x07;
+  for $i (0x04 .. $maxreg) {
+    return if i2c_smbus_read_word_data($file, $i) != $hyst;
+  }
+
+  my $os = i2c_smbus_read_word_data($file,0x03);
+  for $i (0x04 .. $maxreg) {
+    return if i2c_smbus_read_word_data($file, $i) != $os;
+  }
+
+  if ($chip == 0) {
+    for ($i = 8; $i <= 248; $i += 40) {
+      return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf
+             or i2c_smbus_read_word_data($file, $i + 0x02) != $hyst
+             or i2c_smbus_read_word_data($file, $i + 0x03) != $os;
+    }
+  }
+
+  # All registers hold the same value, obviously a misdetection
+  return if $conf == ($cur & 0xff) and $cur == $hyst
+    and $cur == $os;
+
+  $cur = swap_bytes($cur);
+  $hyst = swap_bytes($hyst);
+  $os = swap_bytes($os);
+  # Unused bits
+  return if $chip == 0 and ($conf & 0xe0);
+  return if $chip == 1 and ($conf & 0x80);
+
+  $cur = $cur >> 8;
+  $hyst = $hyst >> 8;
+  $os = $os >> 8;
+  # Most probable value ranges
+  return 6 if $cur <= 100 and ($hyst >= 10 && $hyst <= 125)
+    and ($os >= 20 && $os <= 127) and $hyst < $os;
+  return 3;
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, 3 or 6 if detected;
+#   6 means that the temperatures make sense;
+#   3 means that the temperatures look strange;
+# Registers used:
+#   0x00: Temperature
+#   0x01: Configuration
+#   0x02: Hysteresis
+#   0x03: Overtemperature Shutdown
+#   0x04: Low limit
+#   0x05: High limit
+#   0x04-0x07: No registers
+# The first detection step is based on the fact that the LM77 has only
+# six registers, and cycles addresses over 8-byte boundaries. We use the
+# 0x06-0x07 addresses (unused) to improve the reliability. These are not
+# real registers and will always return the last returned value. This isn't
+# documented.
+# Note that register 0x00 may change, so we can't use the modulo trick on it.
+sub lm77_detect
+{
+  my $i;
+  my ($file,$addr) = @_;
+  my $cur = i2c_smbus_read_word_data($file,0x00);
+  my $conf = i2c_smbus_read_byte_data($file,0x01);
+  my $hyst = i2c_smbus_read_word_data($file,0x02);
+  my $os = i2c_smbus_read_word_data($file,0x03);
+
+  my $low = i2c_smbus_read_word_data($file,0x04);
+  return if i2c_smbus_read_word_data($file,0x06) != $low;
+  return if i2c_smbus_read_word_data($file,0x07) != $low;
+
+  my $high = i2c_smbus_read_word_data($file,0x05);
+  return if i2c_smbus_read_word_data($file,0x06) != $high;
+  return if i2c_smbus_read_word_data($file,0x07) != $high;
+
+  for ($i = 8; $i <= 248; $i += 40) {
+    return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf;
+    return if i2c_smbus_read_word_data($file, $i + 0x02) != $hyst;
+    return if i2c_smbus_read_word_data($file, $i + 0x03) != $os;
+    return if i2c_smbus_read_word_data($file, $i + 0x04) != $low;
+    return if i2c_smbus_read_word_data($file, $i + 0x05) != $high;
+  }
+
+  # All registers hold the same value, obviously a misdetection
+  return if $conf == ($cur & 0xff) and $cur == $hyst
+    and $cur == $os and $cur == $low and $cur == $high;
+
+  $cur = swap_bytes($cur);
+  $os = swap_bytes($os);
+  $hyst = swap_bytes($hyst);
+  $low = swap_bytes($low);
+  $high = swap_bytes($high);
+  # Unused bits
+  return if ($conf & 0xe0)
+    or (($cur >> 12) != 0 && ($cur >> 12) != 0xf)
+    or (($hyst >> 12) != 0 && ($hyst >> 12) != 0xf)
+    or (($os >> 12) != 0 && ($os >> 12) != 0xf)
+    or (($low >> 12) != 0 && ($low >> 12) != 0xf)
+    or (($high >> 12) != 0 && ($high >> 12) != 0xf);
+
+  $cur /= 16;
+  $hyst /= 16;
+  $os /= 16;
+  $high /= 16;
+  $low /= 16;
+
+  # Most probable value ranges
+  return 6 if $cur <= 100 and $hyst <= 40
+    and ($os >= 20 && $os <= 127) and ($high >= 20 && $high <= 127);
+  return 3;
+}
+
+# $_[0]: Chip to detect (0 = LM92, 1 = LM76, 2 = MAX6633/MAX6634/MAX6635)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 2 or 4 if detected;
+# Registers used:
+#   0x01: Configuration (National Semiconductor only)
+#   0x02: Hysteresis
+#   0x03: Critical Temp
+#   0x04: Low Limit
+#   0x05: High Limit
+#   0x07: Manufacturer ID (LM92 only)
+# One detection step is based on the fact that the LM92 and clones have a
+# limited number of registers, which cycle modulo 16 address values.
+# Note that register 0x00 may change, so we can't use the modulo trick on it.
+sub lm92_detect
+{
+  my ($chip, $file, $addr) = @_;
+
+  my $conf = i2c_smbus_read_byte_data($file, 0x01);
+  my $hyst = i2c_smbus_read_word_data($file, 0x02);
+  my $crit = i2c_smbus_read_word_data($file, 0x03);
+  my $low = i2c_smbus_read_word_data($file, 0x04);
+  my $high = i2c_smbus_read_word_data($file, 0x05);
+
+  return if $conf == 0 and $hyst == 0 and $crit == 0
+        and $low == 0 and $high == 0;
+
+  return if $chip == 0
+        and i2c_smbus_read_word_data($file, 0x07) != 0x0180;
+  
+  return if ($chip == 0 || $chip == 1)
+        and ($conf & 0xE0);
+
+  for (my $i = 0; $i < 8; $i++) {
+    return if i2c_smbus_read_byte_data($file, $i*16+0x01) != $conf;
+    return if i2c_smbus_read_word_data($file, $i*16+0x02) != $hyst;
+    return if i2c_smbus_read_word_data($file, $i*16+0x03) != $crit;
+    return if i2c_smbus_read_word_data($file, $i*16+0x04) != $low;
+    return if i2c_smbus_read_word_data($file, $i*16+0x05) != $high;
+  }
+  
+  foreach my $temp ($hyst, $crit, $low, $high) {
+    return if $chip == 2 and ($temp & 0x7F00);
+    return if $chip != 2 and ($temp & 0x0700);
+  }
+
+  return 4 if $chip == 0;
+  return 2;
+}
+  
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, 3 if detected
+# Registers used:
+#   0xAA: Temperature
+#   0xA1: High limit
+#   0xA2: Low limit
+#   0xAC: Configuration
+# Detection is weak. We check if bit 4 (NVB) is clear, because it is
+# unlikely to be set (would mean that EEPROM is currently being accessed).
+# Temperature checkings will hopefully prevent LM75 or other chips from
+# being detected as a DS1621.
+sub ds1621_detect
+{
+  my $i;
+  my ($file,$addr) = @_;
+  my $temp = i2c_smbus_read_word_data($file,0xAA);
+  my $high = i2c_smbus_read_word_data($file,0xA1);
+  my $low = i2c_smbus_read_word_data($file,0xA2);
+  return if ($temp | $high | $low) & 0x7F00;
+  my $conf = i2c_smbus_read_byte_data($file,0xAC);
+  return if ($temp == 0 && $high == 0 && $low == 0 && $conf == 0);
+  return 3 if ($conf & 0x10) == 0x00;
+  return;
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, 1 to 3 if detected.
+# Registers used:
+#   0x00: Configuration register
+#   0x02: Interrupt state register
+#   0x2a-0x3d: Limits registers
+# This one is easily misdetected since it doesn't provide identification
+# registers. So we have to use some tricks:
+#   - 6-bit addressing, so limits readings modulo 0x40 should be unchanged
+#   - positive temperature limits
+#   - limits order correctness
+# Hopefully this should limit the rate of false positives, without increasing
+# the rate of false negatives.
+# Thanks to Lennard Klein for testing on a non-LM80 chip, which was
+# previously misdetected, and isn't anymore. For reference, it scored
+# a final confidence of 0, and changing from strict limit comparisons
+# to loose comparisons did not change the score.
+sub lm80_detect
+{
+  my ($i,$reg);
+  my ($file,$addr) = @_;
+
+  return if (i2c_smbus_read_byte_data($file,0x00) & 0x80) != 0;
+  return if (i2c_smbus_read_byte_data($file,0x02) & 0xc0) != 0;
+
+  for ($i = 0x2a; $i <= 0x3d; $i++) {
+    $reg = i2c_smbus_read_byte_data($file,$i);
+    return if i2c_smbus_read_byte_data($file,$i+0x40) != $reg;
+    return if i2c_smbus_read_byte_data($file,$i+0x80) != $reg;
+    return if i2c_smbus_read_byte_data($file,$i+0xc0) != $reg;
+  }
+  
+  # Refine a bit by checking wether limits are in the correct order
+  # (min<max for voltages, hyst<max for temperature). Since it is still
+  # possible that the chip is an LM80 with limits not properly set,
+  # a few "errors" are tolerated.
+  my $confidence = 0;
+  for ($i = 0x2a; $i <= 0x3a; $i++) {
+    $confidence++
+      if i2c_smbus_read_byte_data($file,$i) < i2c_smbus_read_byte_data($file,$i+1);
+  }
+  # hot temp<OS temp
+  $confidence++
+    if i2c_smbus_read_byte_data($file,0x38) < i2c_smbus_read_byte_data($file,0x3a);
+
+  # Negative temperature limits are unlikely.
+  for ($i = 0x3a; $i <= 0x3d; $i++) {
+    $confidence++ if (i2c_smbus_read_byte_data($file,$i) & 0x80) == 0;
+  }
+
+  # $confidence is between 0 and 14
+  $confidence = ($confidence >> 1) - 4;
+  # $confidence is now between -4 and 3
+
+  return unless $confidence > 0;
+
+  return $confidence;
+}
+
+# $_[0]: Chip to detect
+#   (0 = LM82/LM83)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 4 to 8 if detected.
+# Registers used:
+#   0x02: Status 1
+#   0x03: Configuration
+#   0x04: Company ID of LM84
+#   0x35: Status 2
+#   0xfe: Manufacturer ID
+#   0xff: Chip ID / die revision
+# We can use the LM84 Company ID register because the LM83 and the LM82 are
+# compatible with the LM84.
+# The LM83 chip ID is missing from the datasheet and was contributed by
+# Magnus Forsstrom: 0x03.
+# At least some revisions of the LM82 seem to be repackaged LM83, so they
+# have the same chip ID, and temp2/temp4 will be stuck in "OPEN" state.
+# For this reason, we don't even try to distinguish between both chips.
+# Thanks to Ben Gardner for reporting.
+sub lm83_detect
+{
+  my ($chip, $file) = @_;
+  return if i2c_smbus_read_byte_data($file,0xfe) != 0x01;
+  my $chipid = i2c_smbus_read_byte_data($file,0xff);
+  return if $chipid != 0x01 && $chipid != 0x03;
+
+  my $confidence = 4;
+  $confidence++
+    if (i2c_smbus_read_byte_data($file,0x02) & 0xa8) == 0x00;
+  $confidence++
+    if (i2c_smbus_read_byte_data($file,0x03) & 0x41) == 0x00;
+  $confidence++
+    if i2c_smbus_read_byte_data($file,0x04) == 0x00;
+  $confidence++
+    if (i2c_smbus_read_byte_data($file,0x35) & 0x48) == 0x00;
+
+  return $confidence;
+}
+
+# $_[0]: Chip to detect
+#   (0 = LM90, 1=LM89/LM99, 2=LM86, 3=ADM1032, 4=MAX6657/MAX6658/MAX6659,
+#    5 = ADT7461, 6 = MAX6648/MAX6692, 7 = MAX6680/MAX6681,
+#    8 = W83L771W/G)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 4, 6 or 8 if detected.
+#   The Maxim chips MAX6657, MAX6658 and MAX6659 have a low confidence
+#   value (4) because they don't have a die revision register.
+# Registers used:
+#   0x03: Configuration
+#   0x04: Conversion rate
+#   0xfe: Manufacturer ID
+#   0xff: Chip ID / die revision
+sub lm90_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $mid = i2c_smbus_read_byte_data($file, 0xfe);
+  my $cid = i2c_smbus_read_byte_data($file, 0xff);
+  my $conf = i2c_smbus_read_byte_data($file, 0x03);
+  my $rate = i2c_smbus_read_byte_data($file, 0x04);
+
+  if ($chip == 0) {
+    return if ($conf & 0x2a) != 0;
+    return if $rate > 0x09;
+    return if $mid != 0x01;     # National Semiconductor
+    return 8 if $cid == 0x21;   # LM90
+    return 6 if ($cid & 0x0f) == 0x20;
+  }
+  if ($chip == 1) {
+    return if ($conf & 0x2a) != 0;
+    return if $rate > 0x09;
+    return if $mid != 0x01;     # National Semiconductor
+    return 8 if $addr == 0x4c and $cid == 0x31; # LM89/LM99
+    return 8 if $addr == 0x4d and $cid == 0x34; # LM89-1/LM99-1
+    return 6 if ($cid & 0x0f) == 0x30;
+  }
+  if ($chip == 2) {
+    return if ($conf & 0x2a) != 0;
+    return if $rate > 0x09;
+    return if $mid != 0x01;     # National Semiconductor
+    return 8 if $cid == 0x11;   # LM86
+    return 6 if ($cid & 0xf0) == 0x10;
+  }
+  if ($chip == 3) {
+    return if ($conf & 0x3f) != 0;
+    return if $rate > 0x0a;
+    return if $mid != 0x41;     # Analog Devices
+    return 8 if ($cid & 0xf0) == 0x40; # ADM1032
+  }
+  if ($chip == 4) {
+    return if ($conf & 0x1f) != ($mid & 0x0f); # No low nibble,
+                                               # returns previous low nibble
+    return if $rate > 0x09;
+    return if $mid != 0x4d;     # Maxim
+    return if $cid != 0x4d;     # No register, returns previous value
+    return 4;
+  }
+  if ($chip == 5) {
+    return if ($conf & 0x1b) != 0;
+    return if $rate > 0x0a;
+    return if $mid != 0x41;     # Analog Devices
+    return 8 if $cid == 0x61;   # ADT7461
+  }
+  if ($chip == 6) {
+    return if ($conf & 0x3f) != 0;
+    return if $rate > 0x07;
+    return if $mid != 0x4d;     # Maxim
+    return if $cid != 0x59;     # MAX6648/MAX6692
+    return 8;
+  }    
+  if ($chip == 7) {
+    return if ($conf & 0x03) != 0;
+    return if $rate > 0x07;
+    return if $mid != 0x4d;     # Maxim
+    return if $cid != 0x01;     # MAX6680/MAX6681
+    return 6;
+  }
+  if ($chip == 8) {
+    return if ($conf & 0x2a) != 0;
+    return if $rate > 0x09;
+    return if $mid != 0x5c;     # Winbond
+    return if $cid != 0x00;     # W83L771W/G
+    return 6;
+  }
+  return;
+}
+
+# $_[0]: Chip to detect
+#   (1 = LM63, 2 = F75363SG)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address (unused)
+# Returns: undef if not detected, 8 if detected.
+# Registers used:
+#   0xfe: Manufacturer ID
+#   0xff: Chip ID / die revision
+#   0x03: Configuration (two or three unused bits)
+#   0x16: Alert mask (two or three unused bits)
+#   0x03-0x0e: Mirrored registers (five pairs)
+sub lm63_detect
+{
+  my ($chip, $file, $addr) = @_;
+
+  my $mid = i2c_smbus_read_byte_data($file, 0xfe);
+  my $cid = i2c_smbus_read_byte_data($file, 0xff);
+  my $conf = i2c_smbus_read_byte_data($file, 0x03);
+  my $mask = i2c_smbus_read_byte_data($file, 0x16);
+
+  if ($chip == 1) {
+    return if $mid != 0x01    # National Semiconductor
+           || $cid != 0x41;   # LM63
+    return if ($conf & 0x18) != 0x00
+           || ($mask & 0xa4) != 0xa4;
+  } elsif ($chip == 2) {
+    return if $mid != 0x23    # Fintek
+           || $cid != 0x20;   # F75363SG
+    return if ($conf & 0x1a) != 0x00
+           || ($mask & 0x84) != 0x00;  
+  }
+
+  # For compatibility with the LM86, some registers are mirrored
+  # to alternative locations
+  return if $conf != i2c_smbus_read_byte_data($file, 0x09);
+  foreach my $i (0x04, 0x05, 0x07, 0x08) {
+    return if i2c_smbus_read_byte_data($file, $i)
+           != i2c_smbus_read_byte_data($file, $i+6);
+  }
+
+  return 8;
+}
+
+# $_[0]: Chip to detect
+#   (0 = ADM1029)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address (unused)
+# Returns: undef if not detected, 6 if detected.
+# Registers used:
+#   0x02, 0x03: Fan support
+#   0x06: Temperature support
+#   0x07, 0x08, 0x09: Fan config
+#   0x0d: Manufacturer ID
+#   0x0e: Chip ID / die revision
+sub adm1029_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $mid = i2c_smbus_read_byte_data($file, 0x0d);
+  my $cid = i2c_smbus_read_byte_data($file, 0x0e);
+  my $cfg;
+
+  if ($chip == 0) {
+    return unless $mid == 0x41;             # Analog Devices
+    return unless ($cid & 0xF0) == 0x00;    # ADM1029
+
+    # Extra check on unused bits
+    $cfg = i2c_smbus_read_byte_data($file, 0x02);
+    return unless $cfg == 0x03;
+    $cfg = i2c_smbus_read_byte_data($file, 0x06);
+    return unless ($cfg & 0xF9) == 0x01;
+    foreach my $reg (0x03, 0x07, 0x08, 0x09) {
+      $cfg = i2c_smbus_read_byte_data($file, $reg);
+      return unless ($cfg & 0xFC) == 0x00;
+    }
+
+    return 7;
+  }
+  return;
+}
+
+# $_[0]: Chip to detect
+#   (0 = ADM1030, 1=ADM1031)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 3 to 7 (ADM1031) or 9 (ADM1030)
+#          if detected.
+# Registers used:
+#   0x01: Config 2
+#   0x03: Status 2
+#   0x0d, 0x0e, 0x0f: Temperature offsets
+#   0x22: Fan speed config
+#   0x3d: Chip ID
+#   0x3e: Manufacturer ID
+#   0x3f: Die revision
+sub adm1031_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $mid = i2c_smbus_read_byte_data($file, 0x3e);
+  my $cid = i2c_smbus_read_byte_data($file, 0x3d);
+  my $drev = i2c_smbus_read_byte_data($file, 0x3f);
+  my $conf2 = i2c_smbus_read_byte_data($file, 0x01);
+  my $stat2 = i2c_smbus_read_byte_data($file, 0x03);
+  my $fsc = i2c_smbus_read_byte_data($file, 0x22);
+  my $lto = i2c_smbus_read_byte_data($file, 0x0d);
+  my $r1to = i2c_smbus_read_byte_data($file, 0x0e);
+  my $r2to = i2c_smbus_read_byte_data($file, 0x0f);
+  my $confidence = 3;
+
+  if ($chip == 0) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x30;     # ADM1030
+    $confidence++ if ($drev & 0x70) == 0x00;
+    $confidence++ if ($conf2 & 0x4A) == 0x00;
+    $confidence++ if ($stat2 & 0x3F) == 0x00;
+    $confidence++ if ($fsc & 0xF0) == 0x00;
+    $confidence++ if ($lto & 0x70) == 0x00;
+    $confidence++ if ($r1to & 0x70) == 0x00;
+    return $confidence;
+  }
+  if ($chip == 1) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x31;     # ADM1031
+    $confidence++ if ($drev & 0x70) == 0x00;
+    $confidence++ if ($lto & 0x70) == 0x00;
+    $confidence++ if ($r1to & 0x70) == 0x00;
+    $confidence++ if ($r2to & 0x70) == 0x00;
+    return $confidence;
+  }
+  return;
+}
+
+# $_[0]: Chip to detect
+#   (0 = ADM1033, 1 = ADM1034)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address (unused)
+# Returns: undef if not detected, 4 or 6 if detected.
+# Registers used:
+#   0x3d: Chip ID
+#   0x3e: Manufacturer ID
+#   0x3f: Die revision
+sub adm1034_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $mid = i2c_smbus_read_byte_data($file, 0x3e);
+  my $cid = i2c_smbus_read_byte_data($file, 0x3d);
+  my $drev = i2c_smbus_read_byte_data($file, 0x3f);
+
+  if ($chip == 0) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x33;     # ADM1033
+    return if ($drev & 0xf8) != 0x00;
+    return 6 if $drev == 0x02;
+    return 4;
+  }
+  if ($chip == 1) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x34;     # ADM1034
+    return if ($drev & 0xf8) != 0x00;
+    return 6 if $drev == 0x02;
+    return 4;
+  }
+  return
+}
+
+# $_[0]: Chip to detect
+#   (0 = ADT7467/ADT7468, 1 = ADT7476, 2 = ADT7462, 3 = ADT7466,
+#    4 = ADT7470)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 5 or 7 if detected.
+# Registers used:
+#   0x3d: Chip ID
+#   0x3e: Manufacturer ID
+#   0x3f: Die revision
+sub adt7467_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $mid = i2c_smbus_read_byte_data($file, 0x3e);
+  my $cid = i2c_smbus_read_byte_data($file, 0x3d);
+  my $drev = i2c_smbus_read_byte_data($file, 0x3f);
+
+  if ($chip == 0) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x68;     # ADT7467
+    return if ($drev & 0xf0) != 0x70;
+    return 7 if ($drev == 0x71 || $drev == 0x72);
+    return 5;
+  }
+  if ($chip == 1) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x76;     # ADT7476
+    return if ($drev & 0xf0) != 0x60;
+    return 7 if ($drev == 0x69);
+    return 5;
+  }
+  if ($chip == 2) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x62;     # ADT7462
+    return if ($drev & 0xf0) != 0x00;
+    return 7 if ($drev == 0x04);
+    return 5;
+  }
+  if ($chip == 3) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x66;     # ADT7466
+    return if ($drev & 0xf0) != 0x00;
+    return 7 if ($drev == 0x02);
+    return 5;
+  }
+  if ($chip == 4) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x70;     # ADT7470
+    return if ($drev & 0xf0) != 0x00;
+    return 7 if ($drev == 0x00);
+    return 5;
+  }
+  return
+}
+
+# $_[0]: Chip to detect
+#   (0 = ADT7473, 1 = ADT7475)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address (unused)
+# Returns: undef if not detected, 5 if detected.
+# Registers used:
+#   0x3d: Chip ID
+#   0x3e: Manufacturer ID
+sub adt7473_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $mid = i2c_smbus_read_byte_data($file, 0x3e);
+  my $cid = i2c_smbus_read_byte_data($file, 0x3d);
+
+  if ($chip == 0) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x73;     # ADT7473
+    return 5;
+  }
+  if ($chip == 1) {
+    return if $mid != 0x41;     # Analog Devices
+    return if $cid != 0x75;     # ADT7475
+    return 5;
+  }
+  return
+}
+
+# $_[0]: Chip to detect
+#   (0 = aSC7512, 1 = aSC7611, 2 = aSC7621)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address (unused)
+# Returns: undef if not detected, 1 if detected.
+# Registers used:
+#   0x3e: Manufacturer ID (0x61)
+#   0x3f: Version
+
+sub andigilog_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $mid = i2c_smbus_read_byte_data($file, 0x3e);
+  my $cid = i2c_smbus_read_byte_data($file, 0x3f);
+
+  return if ($mid != 0x61);
+
+  if ($chip == 0) {
+    return if $cid != 0x62;
+    return 5;
+  }
+
+  if ($chip == 1) {
+    return if $cid != 0x69;
+    return 5;
+  }
+
+  if ($chip == 2) {
+    return if $cid != 0x6C;
+    return 5;
+  }
+
+  return;
+}
+
+# $_[0]: Chip to detect
+#   (0 = aSC7511)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address (unused)
+# Returns: undef if not detected, 1 if detected.
+# Registers used:
+#   0xfe: Manufacturer ID
+#   0xff: Die Code
+sub andigilog_aSC7511_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $mid = i2c_smbus_read_byte_data($file, 0xfe);
+  my $die = i2c_smbus_read_byte_data($file, 0xff);
+
+  if ($chip == 0) {
+    return if $mid != 0x61;     # Andigilog
+    if ($die == 0x0) {
+        return 3;
+    } else {
+        return 1;
+    }
+  }
+  return;
+}
+
+# $_[0]: Vendor to check for
+#   (0x01 = National Semi, 0x41 = Analog Dev, 0x5c = SMSC)
+# $_[1]: A reference to the file descriptor to access this chip.
+# #_[2]: Base address.
+# Returns: undef if not detected, (7) or (8) if detected.
+# Registers used: 0x3e == Vendor register.
+#                 0x3d == Device ID register (Analog Devices only).
+#		  0x3f == Version/Stepping register.
+# Constants used: 0x01 == National Semiconductor Vendor Id.
+#                 0x41 == Analog Devices Vendor Id.
+#                 0x5c == SMSC Vendor Id.
+#		  0x60 == Version number. The lower 4 stepping
+#			  bits are masked and ignored.
+sub lm85_detect
+{
+  my ($vendor,$file,$addr) = @_;
+  return if (i2c_smbus_read_byte_data($file,0x3e)) != $vendor ;
+  return if (i2c_smbus_read_byte_data($file,0x3f) & 0xf0) != 0x60;
+
+  if ($vendor == 0x41) # Analog Devices
+  {
+    return if i2c_smbus_read_byte_data($file, 0x3d) != 0x27;
+    return (8);
+  }
+
+  return (7);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (7) if detected.
+# Registers used: 0x3E, 0x3F
+#        Assume lower 2 bits of reg 0x3F are for revisions.
+sub lm87_detect
+{
+  my ($file,$addr) = @_;
+  return if (i2c_smbus_read_byte_data($file,0x3e)) != 0x02;
+  return if (i2c_smbus_read_byte_data($file,0x3f) & 0xfc) != 0x04;
+  return (7);
+}
+  
+# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 2 = W83783S,
+#                        3 = W83627HF, 4 = AS99127F (rev.1),
+#                        5 = AS99127F (rev.2), 6 = ASB100, 7 = W83791D,
+#                        8 = W83792D, 9 = W83627EHF 10 = W83627DHG)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, (8,addr1,addr2) if detected, but only
+#          if the LM75 chip emulation is enabled.
+# Registers used:
+#   0x48: Full I2C Address
+#   0x4a: I2C addresses of emulated LM75 chips
+#   0x4e: Vendor ID byte selection, and bank selection
+#   0x4f: Vendor ID
+#   0x58: Device ID (only when in bank 0)
+# Note: Fails if the W8378xD is not in bank 0!
+# Note: Detection overrules a previous LM78 detection
+# Note: Asus chips do not have their I2C address at register 0x48?
+#       AS99127F rev.1 and ASB100 have 0x00, confirmation wanted for
+#       AS99127F rev.2.
+sub w83781d_detect
+{
+  my ($reg1,$reg2,@res);
+  my ($chip,$file,$addr) = @_;
+
+  return unless (i2c_smbus_read_byte_data($file,0x48) == $addr)
+    or ($chip >= 4 && $chip <= 6);
+
+  $reg1 = i2c_smbus_read_byte_data($file,0x4e);
+  $reg2 = i2c_smbus_read_byte_data($file,0x4f);
+  if ($chip == 4) { # Asus AS99127F (rev.1)
+    return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xc3) or 
+                  (($reg1 & 0x80) == 0x80 and $reg2 == 0x12);
+  } elsif ($chip == 6) { # Asus ASB100
+    return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0x94) or 
+                  (($reg1 & 0x80) == 0x80 and $reg2 == 0x06);
+  } else { # Winbond and Asus AS99127F (rev.2)
+    return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or 
+                  (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
+  }
+
+  return unless ($reg1 & 0x07) == 0x00;
+
+  $reg1 = i2c_smbus_read_byte_data($file,0x58);
+  return if $chip == 0 and ($reg1 != 0x10 && $reg1 != 0x11);
+  return if $chip == 1 and  $reg1 != 0x30;
+  return if $chip == 2 and  $reg1 != 0x40;
+  return if $chip == 3 and  $reg1 != 0x21;
+  return if $chip == 4 and  $reg1 != 0x31;
+  return if $chip == 5 and  $reg1 != 0x31;
+  return if $chip == 6 and  $reg1 != 0x31;
+  return if $chip == 7 and  $reg1 != 0x71;
+  return if $chip == 8 and  $reg1 != 0x7a;
+  return if $chip == 9 and  $reg1 != 0xa1;
+  return if $chip == 10 and  $reg1 != 0xa2;
+  $reg1 = i2c_smbus_read_byte_data($file,0x4a);
+  # Default address is 0x2d
+  @res = ($addr != 0x2d) ? (7) : (8);
+  return @res if $chip == 9; # No subclients
+  push @res, ($reg1 & 0x07) + 0x48 unless $reg1 & 0x08;
+  push @res, (($reg1 & 0x70) >> 4) + 0x48 unless ($reg1 & 0x80 or $chip == 2);
+  return @res;
+}
+  
+# $_[0]: Chip to detect (0 = W83793)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected
+#          6 if detected and bank different from 0
+#          (8,addr1,addr2) if detected, band is 0 and LM75 chip emulation
+#          is enabled
+# Registers used:
+#   0x0b: Full I2C Address
+#   0x0c: I2C addresses of emulated LM75 chips
+#   0x00: Vendor ID byte selection, and bank selection(Bank 0,1,2)
+#   0x0d: Vendor ID(Bank 0,1,2)
+#   0x0e: Device ID(Bank 0,1,2)
+sub w83793_detect
+{
+  my ($bank, $reg, @res);
+  my ($chip, $file, $addr) = @_;
+
+  $bank = i2c_smbus_read_byte_data($file, 0x00);
+  $reg = i2c_smbus_read_byte_data($file, 0x0d);
+
+  return unless (($bank & 0x80) == 0x00 and $reg == 0xa3) or 
+                (($bank & 0x80) == 0x80 and $reg == 0x5c);
+
+  $reg = i2c_smbus_read_byte_data($file, 0x0e);
+  return if $chip == 0 and $reg != 0x7b;
+
+# If bank 0 is selected, we can do more checks
+  return 6 unless ($bank & 0x07) == 0;
+  $reg = i2c_smbus_read_byte_data($file, 0x0b);
+  return unless ($reg == ($addr << 1));
+
+  $reg = i2c_smbus_read_byte_data($file, 0x0c);
+  @res = (8);
+  push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08;
+  push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80;
+  return @res;
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, 3 if detected
+# Registers used:
+#   0x48: Full I2C Address
+#   0x4e: Vendor ID byte selection
+#   0x4f: Vendor ID
+#   0x58: Device ID
+# Note that the datasheet was useless and this detection routine
+# is based on dumps we received from users. Also, the W83781SD is *NOT*
+# a hardware monitoring chip as far as we know, but we still want to
+# detect it so that people won't keep reporting it as an unknown chip
+# we should investigate about.
+sub w83791sd_detect
+{
+  my ($file, $addr) = @_;
+  my ($reg1, $reg2);
+
+  return unless (i2c_smbus_read_byte_data($file, 0x48) == $addr);
+
+  $reg1 = i2c_smbus_read_byte_data($file, 0x4e);
+  $reg2 = i2c_smbus_read_byte_data($file, 0x4f);
+  return unless (!($reg1 & 0x80) && $reg2 == 0xa3)
+             || (($reg1 & 0x80) && $reg2 == 0x5c);
+
+  $reg1 = i2c_smbus_read_byte_data($file, 0x58);
+  return unless $reg1 == 0x72;
+
+  return 3;
+}
+
+# $_[0]: Chip to detect (0 = ASM58, 1 = AS2K129R, 2 = ???)
+# $_[1]: A reference to the file descriptor to access this chip
+# $_[2]: Address (unused)
+# Returns: undef if not detected, 5 if detected
+# Registers used:
+#   0x4e: Vendor ID high byte
+#   0x4f: Vendor ID low byte
+#   0x58: Device ID
+# Note: The values were given by Alex van Kaam, we don't have datasheets
+#       to confirm.
+sub mozart_detect
+{
+  my ($vid,$dev);
+  my ($chip,$file,$addr) = @_;
+
+  $vid = (i2c_smbus_read_byte_data($file,0x4e) << 8)
+       +  i2c_smbus_read_byte_data($file,0x4f);
+  $dev = i2c_smbus_read_byte_data($file,0x58);
+
+  return if ($chip == 0) and ($dev != 0x56 || $vid != 0x9436);
+  return if ($chip == 1) and ($dev != 0x56 || $vid != 0x9406);
+  return if ($chip == 2) and ($dev != 0x10 || $vid != 0x5ca3);
+
+  return 5;
+}
+
+# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 3 = W83627HF,
+#                        9 = W83627EHF 10 = W83627DHG)
+# $_[1]: ISA address
+# $_[2]: I2C file handle
+# $_[3]: I2C address
+sub w83781d_alias_detect
+{
+  my ($chip,$isa_addr,$file,$i2c_addr) = @_;
+  my $i;
+  my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
+  return 0 unless &$readproc(0x48) == $i2c_addr;
+  for ($i = 0x2b; $i <= 0x3d; $i ++) {
+    return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
+  }
+  return 1;
+}
+
+# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D)
+# $_[1]: Address
+# Returns: undef if not detected, (8) if detected.
+sub w83781d_isa_detect
+{
+  my ($chip,$addr) = @_ ;
+  my ($reg1,$reg2);
+  my $val = inb ($addr + 1);
+  return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
+            inb ($addr + 7) != $val;
+
+  $val = inb($addr + 5);
+  outb($addr+5, ~$val & 0x7f);
+  if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) {
+    outb($addr+5,$val);
+    return;
+  }
+
+  my $read_proc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
+  $reg1 = &$read_proc(0x4e);
+  $reg2 = &$read_proc(0x4f);
+  return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or 
+                (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
+  return unless ($reg1 & 0x07) == 0x00;
+  $reg1 = &$read_proc(0x58);
+  return if $chip == 0 and  ($reg1 & 0xfe) != 0x10;
+  return if $chip == 1 and  ($reg1 & 0xfe) != 0x30;
+
+  return 8;
+}
+
+# $_[0]: Chip to detect (0 = Revision 0x00, 1 = Revision 0x80)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, (6) if detected.
+# Registers used:
+#   0x00: Device ID
+#   0x01: Revision ID
+#   0x03: Configuration 
+# Mediocre detection
+sub gl518sm_detect
+{
+  my $reg;
+  my ($chip,$file,$addr) = @_;
+  return unless i2c_smbus_read_byte_data($file,0x00) == 0x80;
+  return unless (i2c_smbus_read_byte_data($file,0x03) & 0x80) == 0x00;
+  $reg = i2c_smbus_read_byte_data($file,0x01);
+  return unless ($chip == 0 and $reg == 0x00) or
+                ($chip == 1 and $reg == 0x80);
+  return (6);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (5) if detected.
+# Registers used:
+#   0x00: Device ID
+#   0x01: Revision ID
+#   0x03: Configuration 
+# Mediocre detection
+sub gl520sm_detect
+{
+  my ($file,$addr) = @_;
+  return unless i2c_smbus_read_byte_data($file,0x00) == 0x20;
+  return unless (i2c_smbus_read_byte_data($file,0x03) & 0x80) == 0x00;
+  # The line below must be better checked before I dare to use it.
+  # return unless i2c_smbus_read_byte_data($file,0x01) == 0x00;
+  return (5);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (5) if detected.
+# Registers used:
+#   0x00: Device ID
+# Mediocre detection
+sub gl525sm_detect
+{
+  my ($file,$addr) = @_;
+  return unless i2c_smbus_read_byte_data($file,0x00) == 0x25;
+  return (5);
+}
+
+# $_[0]: Chip to detect (0 = ADM9240, 1 = DS1780, 2 = LM81)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, (7) if detected.
+# Registers used:
+#   0x3e: Company ID
+#   0x40: Configuration
+#   0x48: Full I2C Address
+# Note: Detection overrules a previous LM78 detection
+sub adm9240_detect
+{
+  my $reg;
+  my ($chip, $file,$addr) = @_;
+  $reg = i2c_smbus_read_byte_data($file,0x3e);
+  return unless ($chip == 0 and $reg == 0x23) or
+                ($chip == 1 and $reg == 0xda) or
+                ($chip == 2 and $reg == 0x01);
+  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
+  return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
+  
+  return (7);
+}
+
+# $_[0]: Chip to detect (0 = ADM1022, 1 = THMC50, 2 = ADM1028)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, (8) if detected.
+# Registers used:
+#   0x3e: Company ID
+#   0x3f: Revision
+#   0x40: Configuration
+# Note: Detection overrules a previous LM78 or ADM9240 detection
+sub adm1022_detect
+{
+  my $reg;
+  my ($chip, $file,$addr) = @_;
+  $reg = i2c_smbus_read_byte_data($file,0x3e);
+  return unless ($chip == 0 and $reg == 0x41) or
+                ($chip == 1 and $reg == 0x49) or
+                ($chip == 2 and $reg == 0x41);
+  $reg = i2c_smbus_read_byte_data($file,0x40);
+  return if ($reg & 0x10);			# Soft Reset always reads 0
+  return if ($chip != 0 and ($reg & 0x80));	# Reserved on THMC50 and ADM1028
+  $reg = i2c_smbus_read_byte_data($file, 0x3f) & 0xf0;
+  return unless ($chip == 0 and $reg == 0xc0) or
+                ($chip == 1 and $reg == 0xc0) or
+                ($chip == 2 and $reg == 0xd0);
+  return (8);
+}
+
+# $_[0]: Chip to detect (0 = ADM1025, 1 = NE1619)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, (8) if detected.
+# Registers used:
+#   0x3e: Company ID
+#   0x3f: Revision
+#   0x40: Configuration
+#   0x41: Status 1
+#   0x42: Status 2
+# Note: Detection overrules a previous LM78 or ADM9240 detection
+sub adm1025_detect
+{
+  my $reg;
+  my ($chip, $file,$addr) = @_;
+
+  $reg = i2c_smbus_read_byte_data($file,0x3e);
+  return if ($chip == 0) and ($reg != 0x41);
+  return if ($chip == 1) and ($reg != 0xA1);
+
+  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
+  return unless (i2c_smbus_read_byte_data($file,0x41) & 0xC0) == 0x00;
+  return unless (i2c_smbus_read_byte_data($file,0x42) & 0xBC) == 0x00;
+  return unless (i2c_smbus_read_byte_data($file,0x3f) & 0xf0) == 0x20;
+
+  return (8);
+}
+
+# $_[0]: Chip to detect (0 = ADM1026)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, (8) if detected.
+# Registers used:
+#   0x16: Company ID
+#   0x17: Revision
+sub adm1026_detect
+{
+  my $reg;
+  my ($chip, $file,$addr) = @_;
+  $reg = i2c_smbus_read_byte_data($file,0x16);
+  return unless ($reg == 0x41);
+  return unless (i2c_smbus_read_byte_data($file,0x17) & 0xf0) == 0x40;
+  return (8);
+}
+
+# $_[0]: Chip to detect (0 = ADM1024)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, (8) if detected.
+# Registers used:
+#   0x3e: Company ID
+#   0x3f: Revision
+#   0x40: Configuration
+sub adm1024_detect
+{
+  my $reg;
+  my ($chip, $file,$addr) = @_;
+  $reg = i2c_smbus_read_byte_data($file,0x3e);
+  return unless ($reg == 0x41);
+  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
+  return unless (i2c_smbus_read_byte_data($file,0x3f) & 0xf0) == 0x10;
+  return (8);
+}
+
+# $_[0]: Chip to detect
+#   (0 = ADM1021, 1 = ADM1021A/ADM1023, 2 = MAX1617, 3 = MAX1617A, 4 = THMC10,
+#    5 = LM84, 6 = GL523, 7 = MC1066)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 3 if simply detected, 5 if detected and
+#          manufacturer ID matches, 7 if detected and manufacturer ID and
+#          revision match
+# Registers used:
+#   0x04: Company ID (LM84 only)
+#   0xfe: Company ID (all but LM84 and MAX1617)
+#   0xff: Revision (ADM1021, ADM1021A/ADM1023 and MAX1617A)
+#   0x02: Status
+#   0x03: Configuration
+#   0x04: Conversion rate
+#   0x00-0x01, 0x05-0x08: Temperatures (MAX1617 and LM84)
+# Note: Especially the MAX1617 has very bad detection; we give it a low 
+# confidence value.
+sub adm1021_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $man_id = i2c_smbus_read_byte_data($file, 0xfe);
+  my $rev = i2c_smbus_read_byte_data($file, 0xff);
+  my $conf = i2c_smbus_read_byte_data($file, 0x03);
+  my $status = i2c_smbus_read_byte_data($file, 0x02);
+  my $convrate = i2c_smbus_read_byte_data($file, 0x04);
+
+  # Check manufacturer IDs and product revisions when available
+  return if $chip == 0 and $man_id != 0x41 ||
+                          ($rev & 0xf0) != 0x00;
+  return if $chip == 1 and $man_id != 0x41 ||
+                          ($rev & 0xf0) != 0x30;
+  return if $chip == 3 and $man_id != 0x4d ||
+                           $rev != 0x01;
+  return if $chip == 4 and $man_id != 0x49;
+  return if $chip == 5 and $convrate != 0x00;
+  return if $chip == 6 and $man_id != 0x23;
+  return if $chip == 7 and $man_id != 0x54;
+
+  # Check unused bits
+  if ($chip == 5) # LM84
+  {
+    return if ($status & 0xab) != 0;
+    return if ($conf & 0x7f) != 0;
+  }
+  else
+  {
+    return if ($status & 0x03) != 0;
+    return if ($conf & 0x3f) != 0;
+    return if ($convrate & 0xf8) != 0;
+  }
+
+  # Extra checks for MAX1617 and LM84, since those are often misdetected
+  # We verify several assertions (6 for the MAX1617, 4 for the LM84) and
+  # discard the chip if any fail. Note that these checks are not done
+  # by the adm1021 driver.
+  if ($chip == 2 || $chip == 5)
+  {
+    my $lte = i2c_smbus_read_byte_data($file, 0x00);
+    my $rte = i2c_smbus_read_byte_data($file, 0x01);
+    my $lhi = i2c_smbus_read_byte_data($file, 0x05);
+    my $rhi = i2c_smbus_read_byte_data($file, 0x07);
+    my $llo = i2c_smbus_read_byte_data($file, 0x06);
+    my $rlo = i2c_smbus_read_byte_data($file, 0x08);
+
+    # If all registers hold the same value, it has to be a misdetection
+    return if $lte == $rte and $lte == $lhi and $lte == $rhi
+           and $lte == $llo and $lte == $rlo;
+
+    # Negative temperatures
+    return if ($lte & 0x80) or ($rte & 0x80);
+    # Negative high limits
+    return if ($lhi & 0x80) or ($rhi & 0x80);
+    # Low limits over high limits
+    if ($chip != 5) # LM84 doesn't have low limits
+    {
+      $llo-=256 if ($llo & 0x80);
+      $rlo-=256 if ($rlo & 0x80);
+      return if ($llo > $lhi) or ($rlo > $rhi);
+    }
+  }
+
+  return 3 if ($chip == 2) or ($chip == 5);
+  return 7 if $chip <= 3;
+  return 5;
+}
+
+# $_[0]: Chip to detect
+#   (0 = MAX1668, 1 = MAX1805, 2 = MAX1989)
+# $_[1]: A reference to the file descriptor to access this chip.
+#        We may assume an i2c_set_slave_addr was already done.
+# $_[2]: Address
+# Returns: undef if not detected, 7 if detected
+# Registers used:
+#   0xfe: Company ID
+#   0xff: Device ID
+sub max1668_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $man_id = i2c_smbus_read_byte_data($file, 0xfe);
+  my $dev_id = i2c_smbus_read_byte_data($file, 0xff);
+
+  return if $man_id != 0x4d;
+  return if $chip == 0 and $dev_id != 0x03;
+  return if $chip == 1 and $dev_id != 0x05;
+  return if $chip == 2 and $dev_id != 0x0b;
+
+  return 7;
+}
+
+# $_[0]: Chip to detect
+#   (0 = MAX1619)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 7 if detected
+# Registers used:
+#   0xfe: Company ID
+#   0xff: Device ID
+#   0x02: Status
+#   0x03: Configuration
+#   0x04: Conversion rate
+sub max1619_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $man_id = i2c_smbus_read_byte_data($file, 0xfe);
+  my $dev_id = i2c_smbus_read_byte_data($file, 0xff);
+  my $conf = i2c_smbus_read_byte_data($file, 0x03);
+  my $status = i2c_smbus_read_byte_data($file, 0x02);
+  my $convrate = i2c_smbus_read_byte_data($file, 0x04);
+
+  return if $man_id != 0x4D
+    or $dev_id != 0x04
+    or ($conf & 0x03)
+    or ($status & 0x61)
+    or $convrate >= 8;
+
+  return 7;
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address (unused)
+# Returns: undef if not detected, 6 if detected.
+# Registers used:
+#   0x28: User ID
+#   0x29: User ID2
+#   0x2A: Version ID
+
+sub ite_overclock_detect
+{
+  my ($file, $addr) = @_;
+
+  my $uid1 = i2c_smbus_read_byte_data($file, 0x28);
+  my $uid2 = i2c_smbus_read_byte_data($file, 0x29);
+  return if $uid1 != 0x83
+         || $uid2 != 0x12;
+
+  return 6;
+}
+
+# $_[0]: Chip to detect (0 = IT8712F)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 7 or 8 if detected (tops LM78).
+# Registers used:
+#   0x00: Configuration
+#   0x48: Full I2C Address
+#   0x58: Mfr ID
+#   0x5b: Device ID (not on IT8705)
+sub ite_detect
+{
+  my $reg;
+  my ($chip,$file,$addr) = @_;
+  return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
+  return unless (i2c_smbus_read_byte_data($file, 0x00) & 0x90) == 0x10;
+  return unless i2c_smbus_read_byte_data($file,0x58) == 0x90;
+  return if $chip == 0 and i2c_smbus_read_byte_data($file,0x5b) != 0x12;
+  return (7 + ($addr == 0x2d));
+}
+
+
+# $_[0]: Chip to detect (0 = IT8712F)
+# $_[1]: ISA address
+# $_[2]: I2C file handle
+# $_[3]: I2C address
+sub ite_alias_detect
+{
+  my ($chip,$isa_addr,$file,$i2c_addr) = @_;
+  my $i;
+  my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
+  return 0 unless &$readproc(0x48) == $i2c_addr;
+  for ($i = 0x30; $i <= 0x45; $i++) {
+    return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
+  }
+  return 1;
+}
+
+# $_[0]: A reference to the file descriptor to access this chip
+# $_[1]: Address
+# Returns: 8 for a memory eeprom
+# Registers used:
+#   0-63: SPD Data and Checksum
+sub eeprom_detect
+{
+  my ($file, $addr) = @_;
+  my $checksum = 0;
+
+  # Check the checksum for validity (works for most DIMMs and RIMMs)
+  for (my $i = 0; $i <= 62; $i++) {
+    $checksum += i2c_smbus_read_byte_data($file, $i);
+  }
+  $checksum &= 255;
+
+  return 8
+    if $checksum == i2c_smbus_read_byte_data($file, 63);
+
+  return;
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, 8 if detected.
+# Registers used:
+#   0x00..0x07: DDC signature
+sub ddcmonitor_detect
+{
+  my ($file,$addr) = @_;
+
+  return unless
+    i2c_smbus_read_byte_data($file,0x00) == 0x00 and
+    i2c_smbus_read_byte_data($file,0x01) == 0xFF and
+    i2c_smbus_read_byte_data($file,0x02) == 0xFF and
+    i2c_smbus_read_byte_data($file,0x03) == 0xFF and
+    i2c_smbus_read_byte_data($file,0x04) == 0xFF and
+    i2c_smbus_read_byte_data($file,0x05) == 0xFF and
+    i2c_smbus_read_byte_data($file,0x06) == 0xFF and
+    i2c_smbus_read_byte_data($file,0x07) == 0x00;
+
+  return 8;
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (8) if detected.
+# Registers used:
+#   0x00-0x02: Identification ('P','E','G' -> Pegasus ? :-) aka Poseidon I
+sub fscpeg_detect
+{
+  my ($file,$addr) = @_;
+  # check the first 3 registers
+  if (i2c_smbus_read_byte_data($file,0x00) != 0x50) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x01) != 0x45) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x02) != 0x47) {
+  	return;
+  }
+  return (8);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (8) if detected.
+# Registers used:
+#   0x00-0x02: Identification 'P','O','S' -> Poseideon II
+sub fscpos_detect
+{
+  my ($file,$addr) = @_;
+  # check the first 3 registers
+  if (i2c_smbus_read_byte_data($file,0x00) != 0x50) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x01) != 0x4F) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x02) != 0x53) {
+  	return;
+  }
+  return (8);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (8) if detected.
+# Registers used:
+#   0x00-0x02: Identification ('S','C','Y')
+sub fscscy_detect
+{
+  my ($file,$addr) = @_;
+  # check the first 3 registers
+  if (i2c_smbus_read_byte_data($file,0x00) != 0x53) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x01) != 0x43) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x02) != 0x59) {
+  	return;
+  }
+  return (8);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (8) if detected.
+# Registers used:
+#   0x00-0x02: Identification ('H','E','R')
+sub fscher_detect
+{
+  my ($file,$addr) = @_;
+  # check the first 3 registers
+  if (i2c_smbus_read_byte_data($file,0x00) != 0x48) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x01) != 0x45) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x02) != 0x52) {
+  	return;
+  }
+  return (8);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (8) if detected.
+# Registers used:
+#   0x00-0x02: Identification ('H','M','D')
+sub fschmd_detect
+{
+  my ($file,$addr) = @_;
+  # check the first 3 registers
+  if (i2c_smbus_read_byte_data($file,0x00) != 0x48) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x01) != 0x4D) {
+  	return;
+  }
+  if (i2c_smbus_read_byte_data($file,0x02) != 0x44) {
+  	return;
+  }
+  return (8);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address (unused)
+# Returns: undef if not detected, 5 if detected.
+# Registers used:
+#   0x3E: Manufacturer ID
+#   0x3F: Version/Stepping
+sub lm93_detect
+{
+  my $file = shift;
+  return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x01
+            and i2c_smbus_read_byte_data($file, 0x3F) == 0x73;
+  return 5;
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, (7) if detected.
+# Registers used:
+#   0x3F: Revision ID
+#   0x48: Address
+#   0x4A, 0x4B, 0x4F, 0x57, 0x58: Reserved bits.
+# We do not use 0x49's reserved bits on purpose. The register is named
+# "VID4/Device ID" so it is doubtful bits 7-1 are really unused.
+sub m5879_detect
+{
+  my ($file, $addr) = @_;
+
+  return
+    unless i2c_smbus_read_byte_data($file, 0x3F) == 0x01;
+  
+  return
+    unless i2c_smbus_read_byte_data($file, 0x48) == $addr;
+  
+  return
+    unless (i2c_smbus_read_byte_data($file, 0x4A) & 0x06) == 0
+       and (i2c_smbus_read_byte_data($file, 0x4B) & 0xFC) == 0
+       and (i2c_smbus_read_byte_data($file, 0x4F) & 0xFC) == 0
+       and (i2c_smbus_read_byte_data($file, 0x57) & 0xFE) == 0
+       and (i2c_smbus_read_byte_data($file, 0x58) & 0xEF) == 0;
+
+  return (7);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, 5 or 6 if detected.
+# Registers used:
+#   0x3E: Manufacturer ID
+#   0x3F: Version/Stepping
+#   0x47: VID (3 reserved bits)
+#   0x49: VID4 (7 reserved bits)
+sub smsc47m192_detect
+{
+  my ($file, $addr) = @_;
+  return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x55
+           and (i2c_smbus_read_byte_data($file, 0x3F) & 0xF0) == 0x20
+           and (i2c_smbus_read_byte_data($file, 0x47) & 0x70) == 0x00
+           and (i2c_smbus_read_byte_data($file, 0x49) & 0xFE) == 0x80;
+  return ($addr == 0x2d ? 6 : 5);
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, 5 or 6 if detected.
+# Registers used:
+#   0x3E: Manufacturer ID
+#   0x3F: Version/Stepping
+#   0x73: Read-only test register (4 test bits)
+#   0x8A: Read-only test register (7 test bits)
+sub dme1737_detect
+{
+  my ($file, $addr) = @_;
+  return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x5c
+           and (i2c_smbus_read_byte_data($file, 0x3F) & 0xF8) == 0x88
+           and (i2c_smbus_read_byte_data($file, 0x73) & 0x0F) == 0x09
+           and (i2c_smbus_read_byte_data($file, 0x8A) & 0x7F) == 0x4D;
+  return ($addr == 0x2e ? 6 : 5);
+}
+
+# $_[0]: Chip to detect
+#   (1 = F75111R/RG/N, 2 = F75121R/F75122R/RG, 3 = F75373S/SG,
+#    4 = F75375S/SP, 5 = F75387SG/RG, 6 = F75383M/S/F75384M/S,
+#    7 = custom power control IC)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address (unused)
+# Returns: undef if not detected, 7 if detected.
+# Registers used:
+#   0x5A-0x5B: Chip ID
+#   0x5D-0x5E: Vendor ID
+sub fintek_detect
+{
+  my ($chip, $file, $addr) = @_;
+  my $chipid = (i2c_smbus_read_byte_data($file, 0x5A) << 8)
+             | i2c_smbus_read_byte_data($file, 0x5B);
+  my $vendid = (i2c_smbus_read_byte_data($file, 0x5D) << 8)
+             | i2c_smbus_read_byte_data($file, 0x5E);
+
+  return unless $vendid == 0x1934; # Fintek ID
+
+  if ($chip == 1) { # F75111R/RG/N
+    return unless $chipid == 0x0300;
+  } elsif ($chip == 2) { # F75121R/F75122R/RG
+    return unless $chipid == 0x0301;
+  } elsif ($chip == 3) { # F75373S/SG
+    return unless $chipid == 0x0204;
+  } elsif ($chip == 4) { # F75375S/SP
+    return unless $chipid == 0x0306;
+  } elsif ($chip == 5) { # F75387SG/RG
+    return unless $chipid == 0x0410;
+  } elsif ($chip == 6) { # F75383M/S/F75384M/S
+    # The datasheet has 0x0303, but Fintek say 0x0413 is also possible
+    return unless $chipid == 0x0303 || $chipid == 0x0413;
+  } elsif ($chip == 7) { # custom power control IC
+    return unless $chipid == 0x0302;
+  }
+
+  return 7;
+}
+
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: undef if not detected, 1 if detected
+# Detection is rather difficult, since the PCA9540 has a single register.
+# Fortunately, no other device is known to live at this address.
+sub pca9540_detect
+{
+	my ($file, $addr) = @_;
+	my $reg = i2c_smbus_read_byte($file);
+
+	return if ($reg & 0xfa);
+	return if $reg != i2c_smbus_read_byte($file);
+	return if $reg != i2c_smbus_read_byte($file);
+	return if $reg != i2c_smbus_read_byte($file);
+
+	return 1;
+}
+
+# This checks for non-FFFF values for temperature, voltage, and current.
+# The address (0x0b) is specified by the SMBus standard so it's likely
+# that this really is a smart battery.
+# $_[0]: A reference to the file descriptor to access this chip.
+# $_[1]: Address
+# Returns: 5
+sub smartbatt_detect
+{
+  my ($file,$addr) = @_;
+  # check some registers
+  if (i2c_smbus_read_word_data($file,0x08) == 0xffff) {
+  	return;
+  }
+  if (i2c_smbus_read_word_data($file,0x09) == 0xffff) {
+  	return;
+  }
+  if (i2c_smbus_read_word_data($file,0x0a) == 0xffff) {
+  	return;
+  }
+  return (5);
+}
+
+# Returns: 4
+# These are simple detectors that only look for a register at the
+# standard location. No writes are performed.
+# For KCS, use the STATUS register. For SMIC, use the FLAGS register.
+sub ipmi_kcs_detect
+{
+  return if inb (0x0ca3) == 0xff;
+  return (4);
+}
+
+sub ipmi_smic_detect
+{
+  return if inb (0x0cab) == 0xff;
+  return (4);
+}
+
+# $_[0]: Chip to detect (0 = W83L784R/AR/G, 1 = W83L785R/G,
+#                        2 = W83L786NR/NG/R/G)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 6 or 8 if detected
+# Registers used:
+#   0x40: Configuration
+#   0x4a: Full I2C Address (W83L784R only)
+#   0x4b: I2C addresses of emulated LM75 chips (W83L784R only)
+#   0x4c: Winbond Vendor ID (Low Byte)
+#   0x4d: Winbond Vendor ID (High Byte)
+#   0x4e: Chip ID
+sub w83l784r_detect
+{
+  my ($reg,@res);
+  my ($chip,$file,$addr) = @_;
+
+  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
+  return if $chip == 0
+    and i2c_smbus_read_byte_data($file,0x4a) != $addr;
+  return unless i2c_smbus_read_byte_data($file,0x4c) == 0xa3;
+  return unless i2c_smbus_read_byte_data($file,0x4d) == 0x5c;
+
+  $reg = i2c_smbus_read_byte_data($file, 0x4e);
+  return if $chip == 0 and $reg != 0x50;
+  return if $chip == 1 and $reg != 0x60;
+  return if $chip == 2 and $reg != 0x80;
+
+  return 6 if $chip != 0; # No subclients
+  
+  @res = (8);
+  $reg = i2c_smbus_read_byte_data($file, 0x4b);
+  push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08 ;
+  push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80;
+  return @res;
+}
+
+# $_[0]: Chip to detect (0 = W83L785TS-S)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 8 if detected
+# Registers used:
+#   0x4C-4E: Mfr and Chip ID
+sub w83l785ts_detect
+{
+  my ($chip,$file,$addr) = @_;
+  return unless i2c_smbus_read_byte_data($file,0x4c) == 0xa3;
+  return unless i2c_smbus_read_byte_data($file,0x4d) == 0x5c;
+  return unless i2c_smbus_read_byte_data($file,0x4e) == 0x70;
+  return (8);
+}
+
+# $_[0]: Chip to detect. Always zero for now, but available for future use
+#        if somebody finds a way to distinguish MAX6650 and MAX6651.
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+# Returns: undef if not detected, 4 if detected.
+#
+# The max6650 has no device ID register. However, a few registers have
+# spare bits, which are documented as being always zero on read. We read
+# all of these registers check the spare bits. Any non-zero means this
+# is not a max6650/1.
+#
+# The always zero bits are: 
+#   configuration byte register (0x02) - top 2 bits 
+#   gpio status register (0x14) - top 3 bits
+#   alarm enable register (0x08) - top 3 bits
+#   alarm status register (0x0A) - top 3 bits
+#   tachometer count time register (0x16) - top 6 bits
+# Additionally, not all values are possible for lower 3 bits of
+# the configuration register.
+sub max6650_detect
+{
+  my ($chip, $file) = @_;
+
+  my $conf = i2c_smbus_read_byte_data($file,0x02);
+  
+  return if i2c_smbus_read_byte_data($file,0x16) & 0xFC;
+  return if i2c_smbus_read_byte_data($file,0x0A) & 0xE0;
+  return if i2c_smbus_read_byte_data($file,0x08) & 0xE0;
+  return if i2c_smbus_read_byte_data($file,0x14) & 0xE0;
+  return if ($conf & 0xC0) or ($conf & 0x07) > 4;
+
+  return 4;
+}
+
+# $_[0]: Chip to detect. Always zero.
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address.
+#
+# Returns: undef if not detected, 6 if detected.
+sub max6655_detect
+{
+  my ($chip, $file, $addr) = @_;
+
+  # checking RDID (Device ID)
+  return unless i2c_smbus_read_byte_data($file, 0xfe) == 0x0a;
+  # checking RDRV (Manufacturer ID)
+  return unless i2c_smbus_read_byte_data($file, 0xff) == 0x4d;
+  # checking unused bits (conversion rate, extended temperature)
+  return unless i2c_smbus_read_byte_data($file, 0x04) & 0xf8;
+  return unless i2c_smbus_read_byte_data($file, 0x10) & 0x1f;
+  return unless i2c_smbus_read_byte_data($file, 0x11) & 0x1f;
+  return unless i2c_smbus_read_byte_data($file, 0x12) & 0x1f;
+
+  return 6;
+}
+
+# $_[0]: Chip to detect (0 = VT1211)
+# $_[1]: A reference to the file descriptor to access this chip.
+# $_[2]: Address
+#
+# This isn't very good detection.
+# Verify the i2c address, and the stepping ID (which is 0xb0 on
+# my chip but could be different for others...
+#
+sub vt1211_i2c_detect
+{
+  my ($chip,$file,$addr) = @_;
+  return unless (i2c_smbus_read_byte_data($file,0x48) & 0x7f) == $addr;
+  return unless i2c_smbus_read_byte_data($file,0x3f) == 0xb0;
+  return 2;
+}
+
+# $_[0]: Chip to detect (0 = VT1211)
+# $_[1]: ISA address
+# $_[2]: I2C file handle
+# $_[3]: I2C address
+sub vt1211_alias_detect
+{
+  my ($chip,$isa_addr,$file,$i2c_addr) = @_;
+  my $i;
+  return 0 unless (inb($isa_addr + 0x48) & 0x7f) == $i2c_addr;
+  return 0 unless (i2c_smbus_read_byte_data($file,0x48) & 0x7f) == $i2c_addr;
+  for ($i = 0x2b; $i <= 0x3d; $i ++) {
+    return 0 unless inb($isa_addr + $i) == i2c_smbus_read_byte_data($file,$i);
+  }
+  return 1;
+}
+
+
+######################
+# PCI CHIP DETECTION #
+######################
+
+# Returns: undef if not detected, (7) or (9) if detected.
+# The address is encoded in PCI space. We could decode it and print it.
+# For Linux 2.4 we should probably check for invalid matches (SiS645).
+sub sis5595_pci_detect
+{
+	return unless exists $pci_list{'1039:0008'};
+	return (kernel_version_at_least(2, 6, 0) ? 9 : 7);
+}
+
+# Returns: undef if not detected, (9) if detected.
+# The address is encoded in PCI space. We could decode it and print it.
+sub via686a_pci_detect
+{
+	return unless exists $pci_list{'1106:3057'};
+	return 9;
+}
+
+# Returns: undef if not detected, (9) if detected.
+# The address is encoded in PCI space. We could decode it and print it.
+sub via8231_pci_detect
+{
+	return unless exists $pci_list{'1106:8235'};
+	return 9;
+}
+
+# Returns: undef if not detected, (9) if detected.
+sub k8temp_pci_detect
+{
+	return unless exists $pci_list{'1022:1103'};
+	return 9;
+}
+
+sub k10temp_pci_detect
+{
+	return unless exists $pci_list{'1022:1203'};
+	return 9;
+}
+
+# Returns: undef if not detected, (9) if detected.
+# the device 0xa620 should not be visible on host PCI bus, gateway
+# must be used
+sub intel_amb_detect
+{
+	if ((exists $pci_list{'8086:a620'}) ||
+	   (exists $pci_list{'8086:25f0'})) {
+		return 9;
+	}
+	return;
+}
+
+# Returns: undef if not detected, (9) if detected.
+sub coretemp_detect
+{
+	my $probecpu;
+	foreach $probecpu (@cpu) {
+		if ($probecpu->{'vendor_id'} eq 'GenuineIntel' && 
+				$probecpu->{'cpu family'} == 6 &&
+				($probecpu->{'model'} == 14 ||
+				 $probecpu->{'model'} == 15)) {
+			return 9;
+		}
+	}
+	return;
+}
+
+################
+# MAIN PROGRAM #
+################
+
+# $_[0]: reference to a list of chip hashes
+sub print_chips_report 
+{
+  my ($listref) = @_;
+  my $data;
+  
+  foreach $data (@$listref) {
+    my $is_i2c = exists $data->{i2c_addr};
+    my $is_isa = exists $data->{isa_addr};
+    print "  * ";
+    if ($is_i2c) {
+      printf "Bus `%s'\n", $data->{i2c_adap};
+      printf "    Busdriver `%s', I2C address 0x%02x", 
+             $data->{i2c_driver}, $data->{i2c_addr};
+      if (exists $data->{i2c_sub_addrs}) {
+        print " (and";
+        my $sub_addr;
+        foreach $sub_addr (@{$data->{i2c_sub_addrs}}) {
+          printf " 0x%02x",$sub_addr;
+        }
+        print ")"
+      }
+      print "\n    ";
+    }
+    if ($is_isa) {
+      print "ISA bus";
+      if ($data->{isa_addr}) {
+        printf ", address 0x%x", $data->{isa_addr};
+      }
+      print " (Busdriver `i2c-isa')"
+        unless kernel_version_at_least(2, 6, 18);
+      print "\n    ";
+    }
+    printf "Chip `%s' (confidence: %d)\n",
+           $data->{chipname},  $data->{conf};
+  }
+}
+
+# $_[0]: 1 if ISA bus is prefered, 0 for SMBus
+# We build here an array adapters, indexed on the number the adapter has
+# at this moment (we assume only loaded adapters are interesting at all;
+# everything that got scanned also got loaded). Each entry is a reference
+# to a hash containing:
+#  driver: Name of the adapter driver
+#  nr_now: Number of the bus now
+#  nr_later: Number of the bus when the modprobes are done (not included if the
+#        driver should not be loaded)
+# A second array, called 
+sub generate_modprobes
+{
+  my ($prefer_isa) = @_;
+
+  my ($chip,$detection,$nr,$i,@optionlist,@probelist,$driver,$isa,$adap);
+  my $ipmi = 0;
+  my $modprobes = "";
+  my $configfile;
+
+  # Collect all adapters used
+  $nr = 0;
+  $isa = 0;
+  foreach $chip (@chips_detected) {
+    foreach $detection (@{$chip->{detected}}) {
+      # If there is more than one bus detected by a driver, they are
+      # still all added. So we number them in the correct order
+      if (exists $detection->{i2c_driver} and
+          not exists $i2c_adapters[$detection->{i2c_devnr}]->{nr_later} and 
+          not (exists $detection->{isa_addr} and $prefer_isa)) {
+         foreach $adap (@i2c_adapters) {
+           next unless exists $adap->{driver};
+           $adap->{nr_later} = $nr++ if $adap->{driver} eq $detection->{i2c_driver};
+         }
+      }
+      if (exists $detection->{isa_addr} and
+          not (exists $detection->{i2c_driver} and not $prefer_isa)) {
+           $isa=1;
+      }
+      if ($chip->{driver} eq "bmcsensors" || 
+          $chip->{driver} eq "ipmisensors") {
+           $ipmi = 1;
+      }
+    }
+  }
+
+  $modprobes .= "# I2C adapter drivers\n" if $nr;
+  for ($i = 0; $i < $nr; $i++) {
+    foreach $adap (@i2c_adapters) {
+      next unless exists $adap->{nr_later} and $adap->{nr_later} == $i;
+      if ($adap->{driver} eq "UNKNOWN") {
+        $modprobes .= "# modprobe unknown adapter ".$adap->{name}."\n";
+      } elsif ($adap->{driver} eq "DISABLED") {
+        $modprobes .= "# modprobe disabled adapter ".$adap->{name}."\n";
+      } elsif ($adap->{driver} eq "to-be-written") {
+        $modprobes .= "# no driver available for adapter ".$adap->{name}."\n";
+      } else {
+        $modprobes .= "modprobe $adap->{driver}\n"
+          unless $modprobes =~ /modprobe $adap->{driver}\n/;
+      }
+      last;
+    }
+  }
+  # i2c-isa is loaded automatically (as a dependency) since 2.6.14,
+  # and will soon be gone.
+  $modprobes .= "modprobe i2c-isa\n" if ($isa && !kernel_version_at_least(2, 6, 18));
+  if ($ipmi) {
+    $modprobes .= "# You must also install and load the IPMI modules\n";
+    if (kernel_version_at_least(2, 6, 0)) {
+      $modprobes .= "modprobe ipmi-si\n";
+    } else {
+      $modprobes .= "modprobe i2c-ipmi\n";
+    }
+  }
+
+  # Now determine the chip probe lines
+  $modprobes .= "# Chip drivers\n";
+  foreach $chip (@chips_detected) {
+    next if not @{$chip->{detected}};
+    if ($chip->{driver} eq "to-be-written") {
+      $modprobes .= "# no driver for $chip->{detected}[0]{chipname} yet\n";
+    } else {
+       # need the * for 2.4 kernels, won't necessarily be an exact match
+       open(local *INPUTFILE, "modprobe -l $chip->{driver}\\* 2>/dev/null |");
+       local $_;
+       my $modulefound = 0;
+       while (<INPUTFILE>) {
+         if(m@/@) {
+           $modulefound = 1;
+           last;
+         }
+       }
+       close INPUTFILE;
+       #check return value from modprobe in case modprobe -l isn't supported
+       if((($? >> 8) == 0) && ! $modulefound) {
+         $modprobes .= "# Warning: the required module $chip->{driver} is not currently installed\n".
+                       "# on your system. For status of 2.6 kernel ports check\n".
+                       "# http://www.lm-sensors.org/wiki/Devices. If driver is built\n".
+                       "# into the kernel, or unavailable, comment out the following line.\n";
+       }
+       $modprobes .= "modprobe $chip->{driver}\n";
+    }
+
+    # Handle misdetects
+    foreach $detection (@{$chip->{misdetected}}) {
+      push @optionlist, $i2c_adapters[$detection->{i2c_devnr}]->{nr_later},
+                       $detection->{i2c_addr}
+           if exists $detection->{i2c_addr} and
+              exists $i2c_adapters[$detection->{i2c_devnr}]->{nr_later};
+      push @optionlist, -1, $detection->{isa_addr}
+           if exists $detection->{isa_addr} and $isa;
+    }
+
+    # Handle aliases
+    foreach $detection (@{$chip->{detected}}) {
+      if (exists $detection->{i2c_driver} and 
+          exists $detection->{isa_addr} and
+          exists $i2c_adapters[$detection->{i2c_devnr}]->{nr_later} and
+          $isa) {
+        if ($prefer_isa) {
+          push @optionlist, $i2c_adapters[$detection->{i2c_devnr}]->{nr_later},
+                           $detection->{i2c_addr};
+        } else {
+          push @optionlist, -1, $detection->{isa_addr}
+        }
+      }
+    }
+
+    next if not (@probelist or @optionlist);
+    $configfile = "# hwmon module options\n" unless defined $configfile;
+    $configfile .= "options $chip->{driver}";
+    $configfile .= sprintf " ignore=%d,0x%02x",shift @optionlist, 
+                                               shift @optionlist
+                  if @optionlist;
+    $configfile .= sprintf ",%d,0x%02x",shift @optionlist, shift @optionlist
+                  while @optionlist;
+    $configfile .= sprintf " probe=%d,0x%02x",shift @probelist,
+                                              shift @probelist
+                  if @probelist;
+    $configfile .= sprintf ",%d,0x%02x",shift @probelist, shift @probelist
+                  while @probelist;
+    $configfile .= "\n";
+  }
+
+  return ($modprobes,$configfile);
+  
+}
+
+sub main
+{
+  my (@adapters,$res,$did_adapter_detection,$adapter);
+
+  # We won't go very far if not root
+  unless ($> == 0) {
+    print "You need to be root to run this script.\n";
+    exit -1;
+  }
+
+  initialize_kernel_version();
+  initialize_conf;
+  initialize_proc_pci;
+  initialize_modules_list;
+  initialize_modules_supported;
+  initialize_cpu_list();
+
+  print "# sensors-detect revision $revision\n\n";
+
+  print "This program will help you determine which kernel modules you need\n",
+        "to load to use lm_sensors most effectively. It is generally safe\n",
+        "and recommended to accept the default answers to all questions,\n",
+        "unless you know what you're doing.\n";
+  print "You need to have i2c and lm_sensors installed before running this\n",
+        "program.\n"
+    unless kernel_version_at_least(2, 6, 0);
+  print "\n";
+
+  print "We can start with probing for (PCI) I2C or SMBus adapters.\n";
+  print "Do you want to probe now? (YES/no): ";
+  @adapters = adapter_pci_detection 
+                        if ($did_adapter_detection = not <STDIN> =~ /\s*[Nn]/);
+  print "\n";
+
+  if (not $did_adapter_detection) {
+    print "As you skipped adapter detection, we will only scan already loaded\n".
+          "adapter modules.\n";
+  } else {
+    print "We will now try to load each adapter module in turn.\n";
+    foreach $adapter (@adapters) {
+      next if $adapter eq "DISABLED";
+      next if $adapter eq "to-be-tested";
+      if (exists($modules_list{$adapter})) {
+        print "Module `$adapter' already loaded.\n";
+      } else {
+        print "Load `$adapter' (say NO if built into your kernel)? (YES/no): ";
+        unless (<STDIN> =~ /^\s*[Nn]/) {
+          if (system ("modprobe", $adapter)) {
+            print "Loading failed... skipping.\n";
+          } else {
+            print "Module loaded successfully.\n";
+          }
+        }
+      }
+    }
+  }
+
+  print "If you have undetectable or unsupported adapters, you can have them\n".
+        "scanned by manually loading the modules before running this script.\n\n";
+  initialize_i2c_adapters_list();
+
+  if (!exists($modules_list{"i2c-dev"})
+   && !(defined $sysfs_root && -e "$sysfs_root/class/i2c-dev")) {
+    print "To continue, we need module `i2c-dev' to be loaded.\n";
+    print "If it is built-in into your kernel, you can safely skip this.\n"
+      unless kernel_version_at_least(2, 6, 0);
+    print "Do you want to load `i2c-dev' now? (YES/no): ";
+    if (<STDIN> =~ /^\s*n/i) {
+      print "Well, you will know best.\n";
+    } elsif (system "modprobe", "i2c-dev") {
+      print "Loading failed, expect problems later on.\n";
+    } else {
+      print "Module loaded successfully.\n";
+    }
+    print "\n";
+  }
+
+  # Before looking for chips, make sure any special case chips are
+  # added to the chip_ids list
+  chip_special_cases();
+  $i2c_addresses_to_scan = i2c_addresses_to_scan();
+
+  print "We are now going to do the I2C/SMBus adapter probings. Some chips may\n",
+        "be double detected; we choose the one with the highest confidence\n",
+        "value in that case.\n",
+        "If you found that the adapter hung after probing a certain address,\n",
+        "you can specify that address to remain unprobed.\n";
+
+  my ($inp,@not_to_scan,$inp2);
+  for (my $dev_nr = 0; $dev_nr < @i2c_adapters; $dev_nr++) {
+    next unless exists $i2c_adapters[$dev_nr];
+    my $adap = $i2c_adapters[$dev_nr]->{'name'};
+    print "\n";
+    print "Next adapter: $adap (i2c-$dev_nr)\n";
+    print "Do you want to scan it? (YES/no/selectively): ";
+    
+    $inp = <STDIN>;
+    if ($inp =~ /^\s*[Ss]/) {
+      print "Please enter one or more addresses not to scan. Separate them ",
+            "with comma's.\n",
+            "You can specify a range by using dashes. Addresses may be ",
+            "decimal (like 54)\n",
+            "or hexadecimal (like 0x33).\n",
+            "Addresses: ";
+      $inp2 = <STDIN>;
+      chop $inp2;
+      @not_to_scan = parse_not_to_scan 0,0x7f,$inp2;
+    }
+    scan_adapter $dev_nr, $adap, $i2c_adapters[$dev_nr]->{'driver'},
+                 \@not_to_scan   unless $inp =~ /^\s*[Nn]/;
+  }
+  print "\n";
+
+  print "Some chips are also accessible through the ISA I/O ports. We have to\n".
+        "write to arbitrary I/O ports to probe them. This is usually safe though.\n".
+        "Yes, you do have ISA I/O ports even if you do not have any ISA slots!\n";
+  print "Do you want to scan the ISA I/O ports? (YES/no): ";
+  unless (<STDIN> =~ /^\s*n/i) {
+    initialize_ioports();
+    scan_isa_bus();
+    close_ioports();
+  }
+  print "\n";
+
+  print "Some Super I/O chips may also contain sensors. We have to write to\n".
+        "standard I/O ports to probe them. This is usually safe.\n";
+  print "Do you want to scan for Super I/O sensors? (YES/no): ";
+  unless (<STDIN> =~ /^\s*n/i) {
+    initialize_ioports();
+    scan_superio(0x2e, 0x2f);
+    scan_superio(0x4e, 0x4f);
+    close_ioports();
+  }
+  print "\n";
+
+  print "Some CPUs or memory controllers may also contain embedded sensors.\n";
+  print "Do you want to scan for them? (YES/no): ";
+  unless (<STDIN> =~ /^\s*n/i) {
+    $| = 1;
+    foreach my $entry (@cpu_ids) {
+      scan_cpu($entry);
+    }
+    $| = 0;
+  }
+  print "\n";
+
+  if(! @chips_detected) {
+    print "Sorry, no sensors were detected.\n",
+          "Either your sensors are not supported, or they are connected to an\n",
+          "I2C or SMBus adapter that is not supported. See doc/FAQ,\n",
+          "doc/lm_sensors-FAQ.html or http://www.lm-sensors.org/wiki/FAQ\n",
+          "(FAQ #4.24.3) for further information.\n",
+          "If you find out what chips are on your board, check\n",
+          "http://www.lm-sensors.org/wiki/Devices for driver status.\n";
+    exit;
+  }
+
+  print "Now follows a summary of the probes I have just done.\n".
+        "Just press ENTER to continue: ";
+  <STDIN>;
+
+  my ($chip,$data);
+  foreach $chip (@chips_detected) {
+    print "\nDriver `$chip->{driver}' ";
+    if (@{$chip->{detected}}) {
+      if (@{$chip->{misdetected}}) {
+        print "(should be inserted but causes problems):\n";
+      } else {
+        print "(should be inserted):\n";
+      }
+    } else {
+      if (@{$chip->{misdetected}}) {
+        print "(may not be inserted):\n";
+      } else {
+        print "(should not be inserted, but is harmless):\n";
+      }
+    }
+    if (@{$chip->{detected}}) {
+      print "  Detects correctly:\n";
+      print_chips_report $chip->{detected};
+    }
+    if (@{$chip->{misdetected}}) {
+      print "  Misdetects:\n";
+      print_chips_report $chip->{misdetected};
+    }
+  }
+  print "\n";
+
+  print "I will now generate the commands needed to load the required modules.\n".
+        "Just press ENTER to continue: ";
+  <STDIN>;
+     
+  print "\n";
+  my ($modprobes, $configfile) = generate_modprobes 1;	# 1 == prefer ISA
+  if (defined $configfile) {
+    print "To make the sensors modules behave correctly, add these lines to\n".
+          "$modules_conf:\n\n";
+    print "#----cut here----\n".
+          $configfile.
+          "#----cut here----\n\n";
+  }
+
+  print "To load everything that is needed, add this to some /etc/rc* file:\n\n";
+  print "#----cut here----\n".
+        $modprobes.
+        "# sleep 2 # optional\n".
+        (-e '/usr/bin/sensors' ?
+          "/usr/bin/sensors -s # recommended\n" :
+          "/usr/local/bin/sensors -s # recommended\n") .
+        "#----cut here----\n\n";
+
+  print "If you have some drivers built into your kernel, the list above will\n".
+        "contain too many modules. Skip the appropriate ones! You really\n".
+        "should try these commands right now to make sure everything is\n".
+        "working properly. Monitoring programs won't work until the needed\n".
+        "modules are loaded.\n\n";
+  
+  my $have_sysconfig = -d '/etc/sysconfig';
+  printf "Do you want to \%s /etc/sysconfig/lm_sensors? (\%s): ",
+         (-e '/etc/sysconfig/lm_sensors' ? 'overwrite' : 'generate'),
+         ($have_sysconfig ? 'YES/no' : 'yes/NO');
+  $_ = <STDIN>;
+  if (($have_sysconfig and not m/^\s*n/i) or m/^\s*y/i) {
+    unless ($have_sysconfig) {
+      mkdir '/etc/sysconfig', 0777
+        or die "Sorry, can't create /etc/sysconfig ($!)";
+    }
+    open(local *SYSCONFIG, ">/etc/sysconfig/lm_sensors")
+      or die "Sorry, can't create /etc/sysconfig/lm_sensors ($!)";
+    print SYSCONFIG <<'EOT';
+#    /etc/sysconfig/lm_sensors - Defines modules loaded by
+#                                /etc/init.d/lm_sensors
+#    Copyright (c) 1998 - 2001  Frodo Looijaard <frodol@dds.nl>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#
+# See also the lm_sensors homepage at:
+#     http://www.lm-sensors.org/
+#
+# This file is used by /etc/init.d/lm_sensors and defines the modules to
+# be loaded/unloaded. This file is sourced into /etc/init.d/lm_sensors.
+#
+# The format of this file is a shell script that simply defines the modules
+# in order as normal variables with the special names:
+#    MODULE_0, MODULE_1, MODULE_2, etc.
+#
+# List the modules that are to be loaded for your system
+#
+EOT
+    print SYSCONFIG
+      "# Generated by sensors-detect on " . scalar localtime() . "\n";
+    my @modules = grep /^modprobe /, split "\n", $modprobes;
+    my $i = 0;
+    my $sysconfig = "";
+    foreach (@modules) {
+      s/^modprobe //;
+      $sysconfig .= "MODULE_$i=$_\n";
+      $i++;
+    }
+    print SYSCONFIG $sysconfig;
+
+    print "Copy prog/init/lm_sensors.init to /etc/init.d/lm_sensors\n".
+          "for initialization at boot time.\n"
+      unless -f "/etc/init.d/lm_sensors";
+  }
+}
+
+main;
Index: /lm-sensors/tags/V3-0-0-RC2/prog/detect/sensors-detect-stat.pl
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/detect/sensors-detect-stat.pl	(revision 2373)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/detect/sensors-detect-stat.pl	(revision 2373)
@@ -0,0 +1,88 @@
+#!/usr/bin/perl -wT
+
+# sensors-detect-stat.pl
+# Statistical analysis of sensors-detect i2c addresses scanner
+# Part of the lm_sensors project
+# Copyright (C) 2003-2004  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+use strict;
+use vars qw(%histo $chips $file);
+
+# Where is sensors-detect?
+# Use first argument, else try default locations.
+if (defined($ARGV[0]))
+{
+	$file = $ARGV[0];
+}
+elsif (-r '/usr/local/sbin/sensors-detect')
+{
+	$file = '/usr/local/sbin/sensors-detect';
+}
+elsif (-r '/usr/sbin/sensors-detect')
+{
+	$file = '/usr/sbin/sensors-detect';
+}
+else
+{
+	print "Usage: $0 /path/to/sensors-detect\n";
+	exit 1;
+}
+
+# Can we read that file?
+if (! -r $file)
+{
+	print "Couldn't open $file for reading.\n";
+	exit 2;
+}
+
+# Get the data.
+open (SD, $file) || die;
+while (<SD>)
+{
+	# The regular expression may seem a little bit complex, but we wouldn't
+	# want to exec malicious code.
+	next unless m/^\s*i2c_addrs\s*=>\s*(\[( *0x[\dA-Fa-f]{2}( *\.\. *0x[\dA-Fa-f]{2})? *,?)+\])\s*,/;
+	my $addresses = eval $1 || die "Failed to eval \"$1\"";
+	$chips++;
+	foreach my $a (@{$addresses})
+	{
+		$histo{$a}++;
+	}
+}
+close SD;
+
+# Print the data.
+printf "$file knows \%d chips and scans \%d addresses.\n\n",
+	$chips, scalar keys %histo;
+print "     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n";
+for (my $i=0; $i<128; $i+=16)
+{
+	printf '%02x:', $i;
+	for (my $j=0; $j<16; $j++)
+	{
+		my $valid = ($i+$j >= 0x04 && $i+$j <= 0x77);
+		if (defined $histo{$i+$j})
+		{
+			printf '%s%02d', ($valid?' ':'!'), $histo{$i+$j};
+		}
+		else
+		{
+			printf ' %s', ($valid?'--':'  ');
+		}
+	}
+	print "\n";
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/detect/sensors-detect.8
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/detect/sensors-detect.8	(revision 4699)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/detect/sensors-detect.8	(revision 4699)
@@ -0,0 +1,22 @@
+.TH SENSORS-DETECT 8 "March 2004" "lm-sensors 3"
+.SH NAME
+sensors-detect \- detect hardware monitoring chips
+
+.SH SYNOPSIS
+.B sensors-detect
+
+.SH DESCRIPTION
+sensors-detect is an interactive program that will walk you through the
+process of scanning your system for various hardware monitoring chips,
+or sensors, supported by libsensors(3), or more generally by the lm_sensors
+tool suite.
+
+.SH SEE ALSO
+sensors(1), libsensors(3), i2cdetect(8)
+
+.SH AUTHOR
+Frodo Looijaard and the lm_sensors group
+http://www.lm-sensors.org/
+This manual page was written by Joey Hess <joey@debian.org>, for
+the Debian GNU/Linux system. It was then reviewed by the lm_sensors team and
+is now part of the lm_sensors source distribution.
Index: /lm-sensors/tags/V3-0-0-RC2/prog/detect/Module.mk
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/detect/Module.mk	(revision 4480)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/detect/Module.mk	(revision 4480)
@@ -0,0 +1,48 @@
+#  Module.mk - Makefile for a Linux module for reading sensor data.
+#  Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Note that MODULE_DIR (the directory in which this file resides) is a
+# 'simply expanded variable'. That means that its value is substituted
+# verbatim in the rules, until it is redefined. 
+MODULE_DIR := prog/detect
+PROGDETECTDIR := $(MODULE_DIR)
+
+PROGDETECTMAN8DIR := $(MANDIR)/man8
+PROGDETECTMAN8FILES := $(MODULE_DIR)/sensors-detect.8
+
+# Regrettably, even 'simply expanded variables' will not put their currently
+# defined value verbatim into the command-list of rules...
+PROGDETECTSBININSTALL := $(MODULE_DIR)/sensors-detect
+
+REMOVEDETECTBIN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(SBINDIR)/%,$(PROGDETECTSBININSTALL))
+REMOVEDETECTMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGDETECTMAN8DIR)/%,$(PROGDETECTMAN8FILES))
+
+all-prog-detect:
+user :: all-prog-detect
+
+install-prog-detect: all-prog-detect
+	$(MKDIR) $(DESTDIR)$(SBINDIR) $(DESTDIR)$(PROGDETECTMAN8DIR)
+	$(INSTALL) -m 755 $(PROGDETECTSBININSTALL) $(DESTDIR)$(SBINDIR)
+	$(INSTALL) -m 644 $(PROGDETECTMAN8FILES) $(DESTDIR)$(PROGDETECTMAN8DIR)
+user_install :: install-prog-detect
+
+user_uninstall::
+	$(RM) $(REMOVEDETECTBIN)
+	$(RM) $(REMOVEDETECTMAN)
+
+clean-prog-detect:
+clean :: clean-prog-detect
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensors/main.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensors/main.c	(revision 4902)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensors/main.c	(revision 4902)
@@ -0,0 +1,342 @@
+/*
+    main.c - Part of sensors, a user-space program for hardware monitoring
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include <locale.h>
+#include <langinfo.h>
+
+#ifndef __UCLIBC__
+#include <iconv.h>
+#define HAVE_ICONV
+#endif
+
+#include "lib/sensors.h"
+#include "lib/error.h"
+#include "main.h"
+#include "chips.h"
+#include "version.h"
+
+#define PROGRAM			"sensors"
+#define VERSION			LM_VERSION
+#define DEFAULT_CONFIG_FILE	ETCDIR "/sensors.conf"
+
+static int do_sets, do_raw, hide_adapter;
+
+int fahrenheit;
+char degstr[5]; /* store the correct string to print degrees */
+
+static void print_short_help(void)
+{
+	printf("Try `%s -h' for more information\n", PROGRAM);
+}
+
+static void print_long_help(void)
+{
+	printf("Usage: %s [OPTION]... [CHIP]...\n", PROGRAM);
+	printf("  -c, --config-file     Specify a config file (default: %s)\n",
+	       DEFAULT_CONFIG_FILE);
+	puts("  -h, --help            Display this help text\n"
+	     "  -s, --set             Execute `set' statements (root only)\n"
+	     "  -f, --fahrenheit      Show temperatures in degrees fahrenheit\n"
+	     "  -A, --no-adapter      Do not show adapter for each chip\n"
+	     "      --bus-list        Generate bus statements for sensors.conf\n"
+	     "  -u                    Raw output (debugging only)\n"
+	     "  -v, --version         Display the program version\n"
+	     "\n"
+	     "Use `-' after `-c' to read the config file from stdin.\n"
+	     "If no chips are specified, all chip info will be printed.\n"
+	     "Example chip names:\n"
+	     "\tlm78-i2c-0-2d\t*-i2c-0-2d\n"
+	     "\tlm78-i2c-0-*\t*-i2c-0-*\n"
+	     "\tlm78-i2c-*-2d\t*-i2c-*-2d\n"
+	     "\tlm78-i2c-*-*\t*-i2c-*-*\n"
+	     "\tlm78-isa-0290\t*-isa-0290\n"
+	     "\tlm78-isa-*\t*-isa-*\n"
+	     "\tlm78-*");
+}
+
+static void print_version(void)
+{
+	printf("%s version %s with libsensors version %s\n", PROGRAM, VERSION,
+	       libsensors_version);
+}
+
+/* Return 0 on success, and an exit error code otherwise */
+static int read_config_file(const char *config_file_name)
+{
+	FILE *config_file;
+	int err;
+
+	if (!strcmp(config_file_name, "-"))
+		config_file = stdin;
+	else
+		config_file = fopen(config_file_name, "r");
+
+	if (!config_file) {
+		fprintf(stderr, "Could not open config file\n");
+		perror(config_file_name);
+		return 1;
+	}
+
+	err = sensors_init(config_file);
+	if (err) {
+		fprintf(stderr, "sensors_init: %s\n", sensors_strerror(err));
+		return 1;
+	}
+
+	if (fclose(config_file) == EOF)
+		perror(config_file_name);
+
+	return 0;
+}
+
+static void set_degstr(void)
+{
+	const char *deg_default_text[2] = { " C", " F" };
+
+#ifdef HAVE_ICONV
+	/* Size hardcoded for better performance.
+	   Don't forget to count the trailing \0! */
+	size_t deg_latin1_size = 3;
+	char *deg_latin1_text[2] = { "\260C", "\260F" };
+	size_t nconv;
+	size_t degstr_size = sizeof(degstr);
+	char *degstr_ptr = degstr;
+
+	iconv_t cd = iconv_open(nl_langinfo(CODESET), "ISO-8859-1");
+	if (cd != (iconv_t) -1) {
+		nconv = iconv(cd, &(deg_latin1_text[fahrenheit]),
+			      &deg_latin1_size, &degstr_ptr, &degstr_size);
+		iconv_close(cd);
+
+		if (nconv != (size_t) -1)
+			return;
+	}
+#endif /* HAVE_ICONV */
+
+	/* There was an error during the conversion, use the default text */
+	strcpy(degstr, deg_default_text[fahrenheit]);
+}
+
+static const char *sprintf_chip_name(const sensors_chip_name *name)
+{
+#define BUF_SIZE 200
+	static char buf[BUF_SIZE];
+
+	if (sensors_snprintf_chip_name(buf, BUF_SIZE, name) < 0)
+		return NULL;
+	return buf;
+}
+
+static void do_a_print(const sensors_chip_name *name)
+{
+	printf("%s\n", sprintf_chip_name(name));
+	if (!hide_adapter) {
+		const char *adap = sensors_get_adapter_name(&name->bus);
+		if (adap)
+			printf("Adapter: %s\n", adap);
+		else
+			fprintf(stderr, "Can't get adapter name\n");
+	}
+	if (do_raw)
+		print_chip_raw(name);
+	else
+		print_chip(name);
+	printf("\n");
+}
+
+/* returns 1 on error */
+static int do_a_set(const sensors_chip_name *name)
+{
+	int res;
+
+	if ((res = sensors_do_chip_sets(name))) {
+		if (res == -SENSORS_ERR_KERNEL) {
+			fprintf(stderr, "%s: %s;\n",
+				sprintf_chip_name(name),
+				sensors_strerror(res));
+			fprintf(stderr, "Run as root?\n");
+			return 1;
+		} else if (res == -SENSORS_ERR_ACCESS_W) {
+			fprintf(stderr,
+				"%s: At least one \"set\" statement failed\n",
+				sprintf_chip_name(name));
+		} else {
+			fprintf(stderr, "%s: %s\n", sprintf_chip_name(name),
+				sensors_strerror(res));
+		}
+	}
+	return 0;
+}
+
+/* returns number of chips found */
+static int do_the_real_work(const sensors_chip_name *match, int *error)
+{
+	const sensors_chip_name *chip;
+	int chip_nr;
+	int cnt = 0;
+
+	chip_nr = 0;
+	while ((chip = sensors_get_detected_chips(match, &chip_nr))) {
+		if (do_sets) {
+			if (do_a_set(chip))
+				*error = 1;
+		} else
+			do_a_print(chip);
+		cnt++;
+	}
+	return cnt;
+}
+
+/* List the buses in a format suitable for sensors.conf. We only list
+   bus types for which bus statements are actually useful and supported.
+   Known bug: i2c buses with number >= 32 or 64 could be listed several
+   times. Very unlikely to ever happen, though. */
+static void print_bus_list(void)
+{
+	const sensors_chip_name *chip;
+	int chip_nr;
+	unsigned long seen_i2c = 0;
+
+	chip_nr = 0;
+	while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
+		switch (chip->bus.type) {
+		case SENSORS_BUS_TYPE_I2C:
+			if (chip->bus.nr < (int)sizeof(unsigned long) * 8) {
+				if (seen_i2c & (1 << chip->bus.nr))
+					break;
+				seen_i2c |= 1 << chip->bus.nr;
+			}
+			printf("bus \"i2c-%d\" \"%s\"\n", chip->bus.nr,
+			       sensors_get_adapter_name(&chip->bus));
+			break;
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	int c, res, i, error, do_bus_list;
+	const char *config_file_name = DEFAULT_CONFIG_FILE;
+
+	struct option long_opts[] =  {
+		{ "help", no_argument, NULL, 'h' },
+		{ "set", no_argument, NULL, 's' },
+		{ "version", no_argument, NULL, 'v'},
+		{ "fahrenheit", no_argument, NULL, 'f' },
+		{ "no-adapter", no_argument, NULL, 'A' },
+		{ "config-file", required_argument, NULL, 'c' },
+		{ "bus-list", no_argument, NULL, 'B' },
+		{ 0, 0, 0, 0 }
+	};
+
+	setlocale(LC_CTYPE, "");
+
+	do_raw = 0;
+	do_sets = 0;
+	do_bus_list = 0;
+	hide_adapter = 0;
+	while (1) {
+		c = getopt_long(argc, argv, "hsvfAc:u", long_opts, NULL);
+		if (c == EOF)
+			break;
+		switch(c) {
+		case ':':
+		case '?':
+			print_short_help();
+			exit(1);
+		case 'h':
+			print_long_help();
+			exit(0);
+		case 'v':
+			print_version();
+			exit(0);
+		case 'c':
+			config_file_name = optarg;
+			break;
+		case 's':
+			do_sets = 1;
+			break;
+		case 'f':
+			fahrenheit = 1;
+			break;
+		case 'A':
+			hide_adapter = 1;
+			break;
+		case 'u':
+			do_raw = 1;
+			break;
+		case 'B':
+			do_bus_list = 1;
+			break;
+		default:
+			fprintf(stderr,
+				"Internal error while parsing options!\n");
+			exit(1);
+		}
+	}
+
+	res = read_config_file(config_file_name);
+	if (res)
+		exit(res);
+
+	/* build the degrees string */
+	set_degstr();
+
+	if (do_bus_list) {
+		print_bus_list();
+	} else if (optind == argc) { /* No chip name on command line */
+		if (!do_the_real_work(NULL, &error)) {
+			fprintf(stderr,
+				"No sensors found!\n"
+				"Make sure you loaded all the kernel drivers you need.\n"
+				"Try sensors-detect to find out which these are.\n");
+			error = 1;
+		}
+	} else {
+		int cnt = 0;
+		sensors_chip_name chip;
+
+		for (i = optind; i < argc; i++) {
+			if (sensors_parse_chip_name(argv[i], &chip)) {
+				fprintf(stderr,
+					"Parse error in chip name `%s'\n",
+					argv[i]);
+				print_short_help();
+				error = 1;
+				goto exit;
+			}
+			cnt += do_the_real_work(&chip, &error);
+		}
+
+		if (!cnt) {
+			fprintf(stderr, "Specified sensor(s) not found!\n");
+			error = 1;
+		}
+	}
+
+exit:
+	sensors_cleanup();
+	exit(res);
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensors/chips.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensors/chips.c	(revision 4910)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensors/chips.c	(revision 4910)
@@ -0,0 +1,472 @@
+/*
+    chips.c - Part of sensors, a user-space program for hardware monitoring
+    Copyright (C) 1998-2003  Frodo Looijaard <frodol@dds.nl> and
+                             Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Copyright (C) 2007       Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "main.h"
+#include "chips.h"
+#include "lib/sensors.h"
+#include "lib/error.h"
+
+void print_chip_raw(const sensors_chip_name *name)
+{
+	int a, b, err;
+	const sensors_feature *feature;
+	const sensors_subfeature *sub;
+	char *label;
+	double val;
+
+	a = 0;
+	while ((feature = sensors_get_features(name, &a))) {
+		if (!(label = sensors_get_label(name, feature))) {
+			fprintf(stderr, "ERROR: Can't get label of feature "
+				"%s!\n", feature->name);
+			continue;
+		}
+		printf("%s:\n", label);
+		free(label);
+
+		b = 0;
+		while ((sub = sensors_get_all_subfeatures(name, feature, &b))) {
+			if (sub->flags & SENSORS_MODE_R) {
+				if ((err = sensors_get_value(name, sub->number,
+							     &val)))
+					fprintf(stderr, "ERROR: Can't get "
+						"value of subfeature %s: %s\n",
+						sub->name,
+						sensors_strerror(err));
+				else
+					printf("  %s: %.2f\n", sub->name, val);
+			} else
+				printf("(%s)\n", label);
+		}
+	}
+}
+
+static inline double deg_ctof(double cel)
+{
+	return cel * (9.0F / 5.0F) + 32.0F;
+}
+
+static void print_label(const char *label, int space)
+{
+	int len = strlen(label)+1;
+	printf("%s:%*s", label, space - len, "");
+}
+
+static double get_value(const sensors_chip_name *name,
+			const sensors_subfeature *sub)
+{
+	double val;
+	int err;
+
+	err = sensors_get_value(name, sub->number, &val);
+	if (err) {
+		fprintf(stderr, "ERROR: Can't get value of subfeature %s: %s\n",
+			sub->name, sensors_strerror(err));
+		val = 0;
+	}
+	return val;
+}
+
+static int get_label_size(const sensors_chip_name *name)
+{
+	int i;
+	const sensors_feature *iter;
+	char *label;
+	unsigned int max_size = 11;	/* 11 as minumum label width */
+
+	i = 0;
+	while ((iter = sensors_get_features(name, &i))) {
+		if ((label = sensors_get_label(name, iter)) &&
+		    strlen(label) > max_size)
+			max_size = strlen(label);
+		free(label);
+	}
+	return max_size + 1;
+}
+
+static void print_temp_limits(double limit1, double limit2,
+			      const char *name1, const char *name2, int alarm)
+{
+	if (fahrenheit) {
+		limit1 = deg_ctof(limit1);
+		limit2 = deg_ctof(limit2);
+        }
+
+	if (name2) {
+		printf("(%-4s = %+5.1f%s, %-4s = %+5.1f%s)  ",
+		       name1, limit1, degstr,
+		       name2, limit2, degstr);
+	} else if (name1) {
+		printf("(%-4s = %+5.1f%s)                  ",
+		       name1, limit1, degstr);
+	} else {
+		printf("                                  ");
+	}
+
+	if (alarm)
+		printf("ALARM  ");
+}
+
+static void print_chip_temp(const sensors_chip_name *name,
+			    const sensors_feature *feature,
+			    int label_size)
+{
+	const sensors_subfeature *sf, *sfmin, *sfmax, *sfcrit, *sfhyst;
+	double val, limit1, limit2;
+	const char *s1, *s2;
+	int alarm, crit_displayed = 0;
+	char *label;
+
+	if (!(label = sensors_get_label(name, feature))) {
+		fprintf(stderr, "ERROR: Can't get label of feature %s!\n",
+			feature->name);
+		return;
+	}
+	print_label(label, label_size);
+	free(label);
+
+	sf = sensors_get_subfeature(name, feature,
+				    SENSORS_SUBFEATURE_TEMP_ALARM);
+	alarm = sf && get_value(name, sf);
+
+	sfmin = sensors_get_subfeature(name, feature,
+				       SENSORS_SUBFEATURE_TEMP_MIN);
+	sfmax = sensors_get_subfeature(name, feature,
+				       SENSORS_SUBFEATURE_TEMP_MAX);
+	sfcrit = sensors_get_subfeature(name, feature,
+					SENSORS_SUBFEATURE_TEMP_CRIT);
+	if (sfmax) {
+		sf = sensors_get_subfeature(name, feature,
+					SENSORS_SUBFEATURE_TEMP_MAX_ALARM);
+		if (sf && get_value(name, sf))
+			alarm |= 1;
+
+     		if (sfmin) {
+			limit1 = get_value(name, sfmin);
+			s1 = "low";
+			limit2 = get_value(name, sfmax);
+			s2 = "high";
+
+			sf = sensors_get_subfeature(name, feature,
+					SENSORS_SUBFEATURE_TEMP_MIN_ALARM);
+			if (sf && get_value(name, sf))
+				alarm |= 1;
+		} else {
+			limit1 = get_value(name, sfmax);
+			s1 = "high";
+
+			sfhyst = sensors_get_subfeature(name, feature,
+					SENSORS_SUBFEATURE_TEMP_MAX_HYST);
+			if (sfhyst) {
+				limit2 = get_value(name, sfhyst);
+				s2 = "hyst";
+			} else if (sfcrit) {
+				limit2 = get_value(name, sfcrit);
+				s2 = "crit";
+
+				sf = sensors_get_subfeature(name, feature,
+					SENSORS_SUBFEATURE_TEMP_CRIT_ALARM);
+				if (sf && get_value(name, sf))
+					alarm |= 1;
+				crit_displayed = 1;
+			} else {
+				limit2 = 0;
+				s2 = NULL;
+			}
+		}
+	} else if (sfcrit) {
+		limit1 = get_value(name, sfcrit);
+		s1 = "crit";
+
+		sfhyst = sensors_get_subfeature(name, feature,
+					SENSORS_SUBFEATURE_TEMP_CRIT_HYST);
+		if (sfhyst) {
+			limit2 = get_value(name, sfhyst);
+			s2 = "hyst";
+		} else {
+			limit2 = 0;
+			s2 = NULL;
+		}
+
+		sf = sensors_get_subfeature(name, feature,
+					SENSORS_SUBFEATURE_TEMP_CRIT_ALARM);
+		if (sf && get_value(name, sf))
+			alarm |= 1;
+		crit_displayed = 1;
+	} else {
+		limit1 = limit2 = 0;
+		s1 = s2 = NULL;
+	}
+
+
+	sf = sensors_get_subfeature(name, feature,
+				    SENSORS_SUBFEATURE_TEMP_FAULT);
+	if (sf && get_value(name, sf)) {
+		printf("   FAULT  ");
+	} else {
+		sf = sensors_get_subfeature(name, feature,
+					    SENSORS_SUBFEATURE_TEMP_INPUT);
+		if (sf) {
+			val = get_value(name, sf);
+			if (fahrenheit)
+				val = deg_ctof(val);
+			printf("%+6.1f%s  ", val, degstr);
+		} else
+			printf("     N/A  ");
+	}
+	print_temp_limits(limit1, limit2, s1, s2, alarm);
+
+	if (!crit_displayed && sfcrit) {
+		limit1 = get_value(name, sfcrit);
+		s1 = "crit";
+
+		sfhyst = sensors_get_subfeature(name, feature,
+					SENSORS_SUBFEATURE_TEMP_CRIT_HYST);
+		if (sfhyst) {
+			limit2 = get_value(name, sfhyst);
+			s2 = "hyst";
+		} else {
+			limit2 = 0;
+			s2 = NULL;
+		}
+
+		sf = sensors_get_subfeature(name, feature,
+					SENSORS_SUBFEATURE_TEMP_CRIT_ALARM);
+		alarm = sf && get_value(name, sf);
+
+		printf("\n%*s", label_size + 10, "");
+		print_temp_limits(limit1, limit2, s1, s2, alarm);
+	}
+
+	/* print out temperature sensor info */
+	sf = sensors_get_subfeature(name, feature,
+				    SENSORS_SUBFEATURE_TEMP_TYPE);
+	if (sf) {
+		int sens = (int)get_value(name, sf);
+
+		/* older kernels / drivers sometimes report a beta value for
+		   thermistors */
+		if (sens > 1000)
+			sens = 4;
+
+		printf("sensor = %s", sens == 0 ? "disabled" :
+		       sens == 1 ? "diode" :
+		       sens == 2 ? "transistor" :
+		       sens == 3 ? "thermal diode" :
+		       sens == 4 ? "thermistor" :
+		       sens == 5 ? "AMD AMDSI" :
+		       sens == 6 ? "Intel PECI" : "unknown");
+	}
+	printf("\n");
+}
+
+static void print_chip_in(const sensors_chip_name *name,
+			  const sensors_feature *feature,
+			  int label_size)
+{
+	const sensors_subfeature *sf, *sfmin, *sfmax;
+	double val, alarm_max, alarm_min;
+	char *label;
+
+	if (!(label = sensors_get_label(name, feature))) {
+		fprintf(stderr, "ERROR: Can't get label of feature %s!\n",
+			feature->name);
+		return;
+	}
+	print_label(label, label_size);
+	free(label);
+
+	sf = sensors_get_subfeature(name, feature,
+				    SENSORS_SUBFEATURE_IN_INPUT);
+	val = sf ? get_value(name, sf) : 0;
+	printf("%+6.2f V", val);
+
+	sfmin = sensors_get_subfeature(name, feature,
+				       SENSORS_SUBFEATURE_IN_MIN);
+	sfmax = sensors_get_subfeature(name, feature,
+				       SENSORS_SUBFEATURE_IN_MAX);
+	if (sfmin && sfmax)
+		printf("  (min = %+6.2f V, max = %+6.2f V)",
+		       get_value(name, sfmin),
+		       get_value(name, sfmax));
+	else if (sfmin)
+		printf("  (min = %+6.2f V)",
+		       get_value(name, sfmin));
+	else if (sfmax)
+		printf("  (max = %+6.2f V)",
+		       get_value(name, sfmax));
+
+	sf = sensors_get_subfeature(name, feature,
+				    SENSORS_SUBFEATURE_IN_ALARM);
+	sfmin = sensors_get_subfeature(name, feature,
+				       SENSORS_SUBFEATURE_IN_MIN_ALARM);
+	sfmax = sensors_get_subfeature(name, feature,
+				       SENSORS_SUBFEATURE_IN_MAX_ALARM);
+	if (sfmin || sfmax) {
+		alarm_max = sfmax ? get_value(name, sfmax) : 0;
+		alarm_min = sfmin ? get_value(name, sfmin) : 0;
+
+		if (alarm_min || alarm_max) {
+			printf(" ALARM (");
+
+			if (alarm_min)
+				printf("MIN");
+			if (alarm_max)
+				printf("%sMAX", (alarm_min) ? ", " : "");
+
+			printf(")");
+		}
+	} else if (sf) {
+		printf("   %s",
+		       get_value(name, sf) ? "ALARM" : "");
+	}
+
+	printf("\n");
+}
+
+static void print_chip_fan(const sensors_chip_name *name,
+			   const sensors_feature *feature,
+			   int label_size)
+{
+	const sensors_subfeature *sf, *sfmin, *sfdiv;
+	char *label;
+
+	if (!(label = sensors_get_label(name, feature))) {
+		fprintf(stderr, "ERROR: Can't get label of feature %s!\n",
+			feature->name);
+		return;
+	}
+	print_label(label, label_size);
+	free(label);
+
+	sf = sensors_get_subfeature(name, feature,
+				    SENSORS_SUBFEATURE_FAN_FAULT);
+	if (sf && get_value(name, sf))
+		printf("   FAULT");
+	else {
+		sf = sensors_get_subfeature(name, feature,
+					    SENSORS_SUBFEATURE_FAN_INPUT);
+		if (sf)
+			printf("%4.0f RPM", get_value(name, sf));
+		else
+			printf("     N/A");
+	}
+
+	sfmin = sensors_get_subfeature(name, feature,
+				       SENSORS_SUBFEATURE_FAN_MIN);
+	sfdiv = sensors_get_subfeature(name, feature,
+				       SENSORS_SUBFEATURE_FAN_DIV);
+	if (sfmin && sfdiv)
+		printf("  (min = %4.0f RPM, div = %1.0f)",
+		       get_value(name, sfmin),
+		       get_value(name, sfdiv));
+	else if (sfmin)
+		printf("  (min = %4.0f RPM)",
+		       get_value(name, sfmin));
+	else if (sfdiv)
+		printf("  (div = %1.0f)",
+		       get_value(name, sfdiv));
+
+	sf = sensors_get_subfeature(name, feature,
+				    SENSORS_SUBFEATURE_FAN_ALARM);
+	if (sf && get_value(name, sf)) {
+		printf("  ALARM");
+	}
+
+	printf("\n");
+}
+
+static void print_chip_vid(const sensors_chip_name *name,
+			   const sensors_feature *feature,
+			   int label_size)
+{
+	char *label;
+	const sensors_subfeature *subfeature;
+	double vid;
+
+	subfeature = sensors_get_subfeature(name, feature,
+					    SENSORS_SUBFEATURE_VID);
+	if (!subfeature)
+		return;
+
+	if ((label = sensors_get_label(name, feature))
+	 && !sensors_get_value(name, subfeature->number, &vid)) {
+		print_label(label, label_size);
+		printf("%+6.3f V\n", vid);
+	}
+	free(label);
+}
+
+static void print_chip_beep_enable(const sensors_chip_name *name,
+				   const sensors_feature *feature,
+				   int label_size)
+{
+	char *label;
+	const sensors_subfeature *subfeature;
+	double beep_enable;
+
+	subfeature = sensors_get_subfeature(name, feature,
+					    SENSORS_SUBFEATURE_BEEP_ENABLE);
+	if (!subfeature)
+		return;
+
+	if ((label = sensors_get_label(name, feature))
+	 && !sensors_get_value(name, subfeature->number, &beep_enable)) {
+		print_label(label, label_size);
+		printf("%s\n", beep_enable ? "enabled" : "disabled");
+	}
+	free(label);
+}
+
+void print_chip(const sensors_chip_name *name)
+{
+	const sensors_feature *feature;
+	int i, label_size;
+
+	label_size = get_label_size(name);
+
+	i = 0;
+	while ((feature = sensors_get_features(name, &i))) {
+		switch (feature->type) {
+		case SENSORS_FEATURE_TEMP:
+			print_chip_temp(name, feature, label_size);
+			break;
+		case SENSORS_FEATURE_IN:
+			print_chip_in(name, feature, label_size);
+			break;
+		case SENSORS_FEATURE_FAN:
+			print_chip_fan(name, feature, label_size);
+			break;
+		case SENSORS_FEATURE_VID:
+			print_chip_vid(name, feature, label_size);
+			break;
+		case SENSORS_FEATURE_BEEP_ENABLE:
+			print_chip_beep_enable(name, feature, label_size);
+			break;
+		default:
+			continue;
+		}
+	}
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensors/main.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensors/main.h	(revision 4713)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensors/main.h	(revision 4713)
@@ -0,0 +1,26 @@
+/*
+    main.h - Part of sensors, a user-space program for hardware monitoring
+    Copyright (C) 2007       Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef PROG_SENSORS_MAIN_H
+#define PROG_SENSORS_MAIN_H
+
+extern int fahrenheit;
+extern char degstr[5];
+
+#endif /* PROG_SENSORS_MAIN_H */
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensors/Module.mk
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensors/Module.mk	(revision 4710)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensors/Module.mk	(revision 4710)
@@ -0,0 +1,60 @@
+#  Module.mk - Makefile for a Linux module for reading sensor data.
+#  Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Note that MODULE_DIR (the directory in which this file resides) is a
+# 'simply expanded variable'. That means that its value is substituted
+# verbatim in the rules, until it is redefined. 
+MODULE_DIR := prog/sensors
+PROGSENSORSDIR := $(MODULE_DIR)
+
+PROGSENSORSMAN1DIR := $(MANDIR)/man1
+PROGSENSORSMAN1FILES := $(MODULE_DIR)/sensors.1
+
+# Regrettably, even 'simply expanded variables' will not put their currently
+# defined value verbatim into the command-list of rules...
+PROGSENSORSTARGETS := $(MODULE_DIR)/sensors3
+PROGSENSORSSOURCES := $(MODULE_DIR)/main.c $(MODULE_DIR)/chips.c
+
+# Include all dependency files. We use '.rd' to indicate this will create
+# executables.
+INCLUDEFILES += $(PROGSENSORSSOURCES:.c=.rd)
+
+REMOVESENSORSBIN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(BINDIR)/%,$(PROGSENSORSTARGETS))
+REMOVESENSORSMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGSENSORSMAN1DIR)/%,$(PROGSENSORSMAN1FILES))
+
+LIBICONV := $(shell if /sbin/ldconfig -p | grep -q libiconv\\.so ; then echo \-liconv; else echo; fi)
+
+$(PROGSENSORSTARGETS): $(PROGSENSORSSOURCES:.c=.ro) lib/$(LIBSHBASENAME)
+	$(CC) $(EXLDFLAGS) -o $@ $(PROGSENSORSSOURCES:.c=.ro) $(LIBICONV) -Llib -lsensors
+
+all-prog-sensors: $(PROGSENSORSTARGETS)
+user :: all-prog-sensors
+
+install-prog-sensors: all-prog-sensors
+	$(MKDIR) $(DESTDIR)$(BINDIR) $(DESTDIR)$(PROGSENSORSMAN1DIR)
+	$(INSTALL) -m 755 $(PROGSENSORSTARGETS) $(DESTDIR)$(BINDIR)
+	$(INSTALL) -m 644 $(PROGSENSORSMAN1FILES) $(DESTDIR)$(PROGSENSORSMAN1DIR)
+user_install :: install-prog-sensors
+
+user_uninstall::
+	$(RM) $(REMOVESENSORSBIN)
+	$(RM) $(REMOVESENSORSMAN)
+
+clean-prog-sensors:
+	$(RM) $(PROGSENSORSDIR)/*.rd $(PROGSENSORSDIR)/*.ro 
+	$(RM) $(PROGSENSORSTARGETS)
+clean :: clean-prog-sensors
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensors/sensors.1
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensors/sensors.1	(revision 4781)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensors/sensors.1	(revision 4781)
@@ -0,0 +1,91 @@
+.\" Copyright 1999 Frodo Looijaard <frodol@dds.nl>
+.\" Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+.\" sensors is distributed under the GPL
+.\"
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one
+.\" 
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date.  The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein.  The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\" 
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\"
+.TH sensors 1  "September 2007" "lm-sensors 3" "Linux User's Manual"
+.SH NAME
+sensors \- print sensors information
+.SH SYNOPSIS
+.B sensors [
+.I options
+.B ] [
+.I chips
+.B ]
+.br
+.B sensors -s [
+.I chips
+.B ]
+.br
+.B sensors --bus-list
+
+.SH DESCRIPTION
+.B sensors
+is used to show the current readings of all sensor chips.
+.br
+.B sensors -s
+is used to set all limits as specified in the configuration file.
+.br
+.B sensors --bus-list
+is used to generate bus statements suitable for the configuration file.
+
+.SH OPTIONS
+.IP "-c config-file"
+Specify a configuration file. If no file is specified, `/etc/sensors.conf'
+is used. Use `-c /dev/null' to temporarily disable this default configuration
+file.
+.IP -h
+Print a help text and exit.
+.IP -s
+Evaluate all `set' statements in the configuration file and exit. You must
+be `root' to do this. If this parameter is not specified, no `set' statement
+is evaluated.
+.IP -A
+Do not show the adapter for each chip.
+.IP -u
+Raw output. This mode is only meant for debugging.
+.IP -v
+Print the program version and exit.
+.IP -f
+Print the temperatures in degrees Fahrenheit instead of Celsius.
+.IP --bus-list
+Generate bus statements suitable for using in sensors.conf. Such bus statements
+are only needed if you have several chips sharing the same address on different
+buses of the same type. As bus numbers are usually not guaranteed to be stable
+over reboots, these statements let you refer to each bus by its name rather
+than numbers.
+.SH FILES
+.I /etc/sensors.conf
+.RS
+The system wide configuration file. See
+.BR sensors.conf (5)
+for further details.
+.RE
+
+.SH SEE ALSO
+sensors.conf(5)
+
+.SH AUTHOR
+Frodo Looijaard and the lm_sensors group
+http://www.lm-sensors.org/
+
+
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensors/chips.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensors/chips.h	(revision 4902)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensors/chips.h	(revision 4902)
@@ -0,0 +1,29 @@
+/*
+    chips.h - Part of sensors, a user-space program for hardware monitoring
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2007        Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef PROG_SENSORS_CHIPS_H
+#define PROG_SENSORS_CHIPS_H
+
+#include "lib/sensors.h"
+
+void print_chip_raw(const sensors_chip_name *name);
+void print_chip(const sensors_chip_name *name);
+
+#endif /* def PROG_SENSORS_CHIPS_H */
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sensord.8
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sensord.8	(revision 4919)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sensord.8	(revision 4919)
@@ -0,0 +1,384 @@
+.\" Copyright 1999-2002 Merlin Hughes <merlin@merlin.org>
+.\" sensord is distributed under the GPL
+.\"
+.\" Permission is granted to make and distribute verbatim copies of this
+.\" manual provided the copyright notice and this permission notice are
+.\" preserved on all copies.
+.\"
+.\" Permission is granted to copy and distribute modified versions of this
+.\" manual under the conditions for verbatim copying, provided that the
+.\" entire resulting derived work is distributed under the terms of a
+.\" permission notice identical to this one
+.\" 
+.\" Since the Linux kernel and libraries are constantly changing, this
+.\" manual page may be incorrect or out-of-date.  The author(s) assume no
+.\" responsibility for errors or omissions, or for damages resulting from
+.\" the use of the information contained herein.  The author(s) may not
+.\" have taken the same level of care in the production of this manual,
+.\" which is licensed free of charge, as they might when working
+.\" professionally.
+.\" 
+.\" Formatted or processed versions of this manual, if unaccompanied by
+.\" the source, must acknowledge the copyright and authors of this work.
+.\"
+.TH sensord 8  "October 2007" "lm-sensors 3" "Linux System Administration"
+.SH NAME
+sensord \- Sensor information logging daemon.
+.SH SYNOPSIS
+.B sensord [
+.I options
+.B ] [
+.I chips
+.B ]
+
+.SH DESCRIPTION
+.B Sensord
+is a daemon that can be used to periodically log sensor readings from
+hardware health-monitoring chips to
+.BR syslog (3)
+or a round-robin database (RRD)
+and to alert when a sensor alarm is signalled; for example, if a
+fan fails, a temperature limit is exceeded, etc.
+
+.SH OPTIONS
+.IP "-i, --interval time"
+Specify the interval between scanning for sensor alarms; the default is to
+scan every minute.
+
+The time should be specified as a raw integer (seconds) or with a suffix
+`s' for seconds, `m' for minutes or `h' for hours; for example, the
+default interval is `60' or `1m'.
+
+Specify an interval of zero to suppress scanning explicitly for alarms.
+.IP "-l, --log-interval time"
+Specify the interval between logging all sensor readings; the default is
+to log all readings every half hour.
+
+The time is specified as before; e.g., `30m'.
+
+Specify an interval of zero to suppress logging of regular sensor
+readings.
+.IP "-t, --rrd-interval time"
+Specify the interval between logging all sensor readings to a round-robin
+database; the default is to log all readings every five minutes
+.B if
+a round-robin database is configured.
+
+The time is specified as before; e.g., `5m'.
+.IP "-T, --rrd-no-average"
+Specify that the round-robin database should not be averaged.
+
+.IP "-r, --rrd-file file"
+Specify a round-robin database into which to log all sensor readings;
+e.g., `/var/log/sensord.rrd'. This database will be created if it does
+not exist. By default, no round-robin database is used.
+
+See the section
+.B ROUND ROBIN DATABASES
+below for more details.
+.IP "-c, --config-file file"
+Specify a
+.BR libsensors (3)
+configuration file. If no file is specified, the default configuration file
+is used.
+
+.IP "-p, --pid-file file"
+Specify what PID file to write; the default is to write the file
+`/var/run/sensord.pid'. You should always specify an absolute path
+here. The file is removed when the daemon exits.
+.IP "-f, --syslog-facility facility"
+Specify the
+.BR syslog (3)
+facility to use when logging sensor readings and alarms; the default is
+to use
+.IR local4 .
+
+Other possibile facilities include
+.IR local0
+through
+.IR local7 ,
+.IR daemon
+or
+.IR user .
+.IP "-g, --rrd-cgi directory"
+Prints out a sample
+.BR rrdcgi (1)
+CGI script that can be used to display graphs of recent sensor information
+in a Web page, and exits. You must specify the world-writable, Web-accessible
+directory where the graphs should be stored; the CGI script assumes that
+this will be accessed under the `/sensord/' directory on the Webserver. See
+the section
+.B ROUND ROBIN DATABASES
+below for more details.
+.IP "-a, --load-average"
+Include the load average in the RRD database. You should
+also specify this flag when you create the CGI script.
+.IP "-d, --debug"
+Prints a small amount of additional debugging information.
+.IP "-h, --help"
+Prints a help message and exits.
+.IP "-v, --version"
+Displays the program version and exits.
+.SH CHIPS
+To restrict the devices that are scanned by this daemon, you may
+optionally specify a list of chip names. By default, all available
+chips are scanned.
+
+A typical chip name would be `w83782d-*' (you may want to escape the
+`*' for your shell) which would scan any W83782D chips on any bus. See
+.BR sensors.conf (5)
+for more details. Another option is to simply not load the sensor
+modules for chips in which you have no interest.
+.SH SIGNALS
+Upon receipt of a SIGTERM (see
+.BR signal (7)
+for details) this daemon should gracefully shut down.
+.SH LOGGING
+All messages from this daemon are logged to
+.BR syslog (3)
+under the program name `sensord' and facility
+.IR local4 ,
+or whatever is specified on the command line.
+
+Regular sensor readings are logged at the level
+.IR info .
+Alarms are logged at the level
+.IR alert .
+Inconsequential status messages are logged at
+the minimum level,
+.IR debug ,
+when debugging is enabled.
+
+You can use an appropriate `/etc/syslog.conf'
+file to direct these messages in a useful manner. See
+.BR syslog.conf (5)
+for full details, however the following is a sample configuration:
+.IP
+.nf
+# Sample syslog.conf entries
+*.info;...;local4.none;local4.warn  /var/log/messages
+local4.info                        -/var/log/sensors
+local4.alert                        /dev/console
+local4.alert                        *
+.fi
+.PP
+The first line ensures that regular sensor readings do not clutter
+`/var/log/messages'; we first say `local4.none' to eliminate
+informational messages; then `local4.warn' to enable warnings and
+above. The second line says to log all regular sensor readings to
+`/var/log/sensors'; the leading hyphen `-' means that this file
+is not flushed after every message. The final two lines ensure
+that alarms are printed to the system console as well as
+to all connected users (in addition to `/var/log/messages' and
+`/var/log/sensors').
+.SH LOG ROTATION
+On a typical system with a good sensor chip, expect about 2KB per sensor
+reading in the log file. This works out at about 3MB per month. You
+should be rotating your syslog files anyway, but just to be sure you'll
+want to use something like
+.BR logrotate (8)
+or equivalent. You might, for example, want an entry in
+`/etc/logrotate.d/syslog' containing:
+.IP
+.nf
+# Sample logrotate.d entry
+/var/log/sensors {
+    postrotate
+        /usr/sbin/killall -HUP syslogd
+    endscript
+}
+.fi
+.PP
+Note, of course, that you want to restart
+.BR syslogd (8)
+and not
+.BR sensord (8)
+.
+.SH ALARMS
+Alarms generally indicate a critical condition; for example, a fan
+failure or an unacceptable temperature or voltage. However, some
+sensor chips do not support alarms, while others are incorrectly
+configured and may signal alarms incorrectly.
+
+Note that some drivers may lack support for alarm reporting
+even though the chips they support do have alarms. As of Linux 2.6.23,
+many drivers still don't report alarms in a format suitable for
+libsensors 3.
+
+.SH BEEPS
+If you see `(beep)' beside any sensor reading, that just means that
+your system is configured to issue an audio warning from the
+motherboard if an alarm is signalled on that sensor.
+.SH ROUND ROBIN DATABASES
+.BR Sensord (8)
+provides support for storing sensor readings in a round-robin
+database. This may be a useful alternative to the use of
+.BR syslog (3).
+
+Round-robin databases are
+constant-size databases that can be used to store, for example,
+a week's worth of sensor readings. Subsequent readings stored
+in the database will overwrite readings that are over a week
+old. This capability is extremely useful because it allows
+useful information to be stored in an easily-accessible
+manner for a useful length of time, without the burden of
+ever-growing log files.
+
+The
+.BR rrdtool (1)
+utility and its associated library provide the basic framework for
+the round-robin database beneath
+.BR sensord (8).
+In addition, the
+.BR rrdcgi (1)
+and
+.BR rrdgraph (1)
+utilities provide support for generating graphs of these data for
+display in a Web page.
+
+If you wish to use the default configuration of round-robin
+database, which holds one week of sensor readings at five-minute
+intervals, then simply start
+.BR sensord (8)
+and specify where you want the database stored. It will automatically
+be created and configured using these default parameters.
+
+If you wish readings to be stored for a longer period, or want multiple
+readings to be averaged into each database entry, then you must
+manually create and configure the database before starting
+.BR sensord (8).
+Consult the
+.BR rrdcreate (1)
+manual for details. Note that the database must match exactly the
+names and order of sensors read by
+.BR sensord (8).
+It is recommended that you create the default database and then use
+.BR rrdinfo (1)
+to obtain this information, and/or
+.BR rrdtune (1)
+to change it.
+
+After creating the round-robin database, you must then configure
+your Web server to display the sensor information. This assumes that
+you have a Web server preconfigured and functioning on your machine.
+.BR Sensord (8)
+provides a command-line option
+.BR --rrd-cgi
+to generate a basic CGI script to
+display these graphs; you can then customize this script as desired.
+Consult the
+.BR rrdcgi (1)
+manual for details. This CGI script requires a world-writable, Web-accessible
+directory into which to write the graphs that it generates.
+
+An example of how to set up Web-accessible graphs of recent sensor readings
+follows:
+.IP
+.nf
+sensord --log-interval 0 \\
+  --load-average \\
+  --rrd-file /var/log/sensord.rrd
+.fi
+.PP
+Here, we start
+.BR sensord (8)
+and configure it to store readings in a round-robin database; note
+that we disable logging of sensor readings to
+.BR syslog (3),
+and enable logging of the load average.
+.IP
+.nf
+mkdir /var/www/sensord
+chown www-data:staff /var/www/sensord
+chmod a=rwxs /var/www/sensord
+.fi
+.PP
+Here, we create a world-writable, Web-accessible directory in which
+graphs will be stored; we set the ownership and permissions on this
+directory appropriately. You will have to determine the location and
+ownership that is appropriate for your machine.
+.IP
+.nf
+sensord --load-average \\
+  --rrd-file /var/log/sensord.rrd \\
+  --rrd-cgi /var/www/sensord \\
+  > /usr/lib/cgi-bin/sensord.cgi
+chmod a+rx /usr/lib/cgi-bin/sensord.cgi
+.fi
+.PP
+Here, we create
+a CGI script that will display sensor readings from the database.
+You must specify the location of the round-robin database, the
+location of the directory where the images should be stored,
+and whether you want the load average displayed. The
+.BR --rrd-cgi
+command-line parameter causes
+.BR sensord (8)
+to display a suitable CGI script on
+.BR stdout
+and then to exit. You will need to write this script to the CGI
+bin directory of your Web server,
+and edit the script if the image directory you chose is not the
+`/sensord/' directory of your Web server.
+
+Finally, you should be able to view your sensor readings from
+the URL `http://localhost/cgi-bin/sensord.cgi'.
+.SH MODULES
+It is expected that all required sensor modules are loaded prior to
+this daemon being started. This can either be achieved with a system
+specific module loading scheme (e.g., listing the required modules
+in the file `/etc/modules' under Debian) or with explicit
+.BR modprobe (1)
+commands in an init script before loading the daemon.
+
+For example, a `sensord' initialization script might
+contain (among others) the following commands:
+.IP
+.nf
+# Sample init.d scriptlet
+echo -n "Loading AMD756 module: "
+modprobe i2c-amd756 || { echo Fail. ; exit 1 ; }
+echo OK.
+echo -n "Loading W83781D module: "
+modprobe w83781d || { echo Fail. ; exit 1 ; }
+echo OK.
+echo -n "Starting sensord: "
+daemon sensord
+...
+.fi
+.PP
+Ignore the platform-specific shell functions; the general idea
+should be fairly clear.
+.SH ERRORS
+Errors encountered by this daemon are logged to
+.BR syslogd (8)
+after which the daemon will exit.
+.SH BUGS
+Round-robin database support doesn't cope with
+multiple sensor chips having duplicate sensor labels.
+.SH FILES
+.I /etc/sensors.conf
+.RS
+The system-wide
+.BR libsensors (3)
+configuration file. See
+.BR sensors.conf (5)
+for further details.
+.RE
+.I /etc/syslog.conf
+.RS
+The system-wide
+.BR syslog (3)
+/
+.BR syslogd (8)
+configuration file. See
+.BR syslog.conf (5)
+for further details.
+.RE
+
+.SH SEE ALSO
+sensors.conf(5)
+.SH AUTHORS
+.B Sensord
+was written by Merlin Hughes <merlin@merlin.org>. Basics of round-robin
+databases were misappropriated from Mark D. Studebaker.
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sensord.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sensord.h	(revision 4918)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sensord.h	(revision 4918)
@@ -0,0 +1,102 @@
+/*
+ * sensord
+ *
+ * A daemon that periodically logs sensor information to syslog.
+ *
+ * Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "lib/sensors.h"
+
+extern void sensorLog (int priority, const char *fmt, ...);
+
+/* from args.c */
+
+extern int isDaemon;
+extern const char *sensorsCfgFile;
+extern const char *pidFile;
+extern const char *rrdFile;
+extern const char *cgiDir;
+extern int scanTime;
+extern int logTime;
+extern int rrdTime;
+extern int rrdNoAverage;
+extern int syslogFacility;
+extern int doScan;
+extern int doSet;
+extern int doCGI;
+extern int doLoad;
+extern int debug;
+extern sensors_chip_name chipNames[];
+extern int numChipNames;
+
+extern int parseArgs (int argc, char **argv);
+extern int parseChips (int argc, char **argv);
+
+/* from lib.c */
+
+extern int loadLib (const char *cfgPath);
+extern int reloadLib (const char *cfgPath);
+extern int unloadLib (void);
+
+/* from sense.c */
+
+extern int readChips (void);
+extern int scanChips (void);
+extern int setChips (void);
+extern int rrdChips (void);
+
+/* from rrd.c */
+
+extern char rrdBuff[];
+extern int rrdInit (void);
+extern int rrdUpdate (void);
+extern int rrdCGI (void);
+
+/* from chips.c */
+
+#define MAX_DATA 5
+
+typedef const char * (*FormatterFN) (const double values[], int alarm, int beep);
+
+typedef const char * (*RRDFN) (const double values[]);
+
+typedef enum {
+  DataType_voltage = 0,
+  DataType_rpm,
+  DataType_temperature,
+  DataType_other = -1
+} DataType;
+
+typedef struct {
+  FormatterFN format;
+  RRDFN rrd;
+  DataType type;
+  int alarmNumber;
+  int beepNumber;
+  const sensors_feature *feature;
+  int dataNumbers[MAX_DATA + 1];
+} FeatureDescriptor;
+
+typedef struct {
+  const sensors_chip_name *name;
+  FeatureDescriptor *features;
+} ChipDescriptor;
+
+extern ChipDescriptor * knownChips;
+extern int initKnownChips (void);
+extern void freeKnownChips (void);
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/chips.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/chips.c	(revision 4846)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/chips.c	(revision 4846)
@@ -0,0 +1,402 @@
+/*
+ * sensord
+ *
+ * A daemon that periodically logs sensor information to syslog.
+ *
+ * Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sensord.h"
+
+/* TODO: Temp in C/F */
+
+/** formatters **/
+
+static char buff[4096];
+
+static const char *
+fmtExtra
+(int alarm, int beep) {
+  if (alarm)
+    sprintf (buff + strlen (buff), " [ALARM]");
+  if (beep)
+    sprintf (buff + strlen (buff), " (beep)");
+  return buff;
+}
+
+static const char *
+fmtTemps_1
+(const double values[], int alarm, int beep) {
+  sprintf (buff, "%.1f C (limit = %.1f C, hysteresis = %.1f C)", values[0], values[1], values[2]);
+  return fmtExtra (alarm, beep);
+}
+
+static const char *
+fmtTemps_minmax_1
+(const double values[], int alarm, int beep) {
+ sprintf (buff, "%.1f C (min = %.1f C, max = %.1f C)", values[0], values[1], values[2]);
+ return fmtExtra (alarm, beep);
+}
+
+static const char *
+fmtTemp_only
+(const double values[], int alarm, int beep) {
+  sprintf (buff, "%.1f C", values[0]);
+  return fmtExtra (alarm, beep);
+}
+
+static const char *
+fmtVolt_2
+(const double values[], int alarm, int beep) {
+  sprintf (buff, "%+.2f V", values[0]);
+  return fmtExtra (alarm, beep);
+}
+
+static const char *
+fmtVolt_3
+(const double values[], int alarm, int beep) {
+  sprintf (buff, "%+.3f V", values[0]);
+  return fmtExtra (alarm, beep);
+}
+
+static const char *
+fmtVolts_2
+(const double values[], int alarm, int beep) {
+  sprintf (buff, "%+.2f V (min = %+.2f V, max = %+.2f V)", values[0], values[1], values[2]);
+  return fmtExtra (alarm, beep);
+}
+
+static const char *
+fmtFans_0
+(const double values[], int alarm, int beep) {
+  sprintf (buff, "%.0f RPM (min = %.0f RPM, div = %.0f)", values[0], values[1], values[2]);
+  return fmtExtra (alarm, beep);
+}
+
+static const char *
+fmtFans_nodiv_0
+(const double values[], int alarm, int beep) {
+  sprintf (buff, "%.0f RPM (min = %.0f RPM)", values[0], values[1]);
+  return fmtExtra (alarm, beep);
+}
+
+static const char *
+fmtFan_only
+(const double values[], int alarm, int beep) {
+  sprintf (buff, "%.0f RPM", values[0]);
+  return fmtExtra (alarm, beep);
+}
+
+static const char *
+fmtSoundAlarm
+(const double values[], int alarm, int beep) {
+  sprintf (buff, "Sound alarm %s", (values[0] < 0.5) ? "disabled" : "enabled");
+  return fmtExtra (alarm, beep);
+}
+
+static const char *
+rrdF0
+(const double values[]) {
+  sprintf (buff, "%.0f", values[0]);
+  return buff;
+}
+
+static const char *
+rrdF1
+(const double values[]) {
+  sprintf (buff, "%.1f", values[0]);
+  return buff;
+}
+
+static const char *
+rrdF2
+(const double values[]) {
+  sprintf (buff, "%.2f", values[0]);
+  return buff;
+}
+
+static const char *
+rrdF3
+(const double values[]) {
+  sprintf (buff, "%.3f", values[0]);
+  return buff;
+}
+
+static void fillChipVoltage (FeatureDescriptor *voltage,
+                             const sensors_chip_name *name,
+                             const sensors_feature *feature)
+{
+  const sensors_subfeature *sf, *sfmin, *sfmax;
+  int pos = 0;
+
+  voltage->rrd = rrdF2;
+  voltage->type = DataType_voltage;
+
+  sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_IN_INPUT);
+  if (sf)
+    voltage->dataNumbers[pos++] = sf->number;
+
+  sfmin = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_IN_MIN);
+  sfmax = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_IN_MAX);
+  if (sfmin && sfmax) {
+    voltage->format = fmtVolts_2;
+    voltage->dataNumbers[pos++] = sfmin->number;
+    voltage->dataNumbers[pos++] = sfmax->number;
+  } else {
+    voltage->format = fmtVolt_2;
+  }
+  
+  /* terminate the list */
+  voltage->dataNumbers[pos] = -1;
+
+  /* alarm if applicable */
+  if ((sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_IN_ALARM)) ||
+      (sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_IN_MIN_ALARM)) ||
+      (sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_IN_MAX_ALARM))) {
+    voltage->alarmNumber = sf->number;
+  } else {
+    voltage->alarmNumber = -1;
+  }
+  /* beep if applicable */
+  if ((sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_IN_BEEP))) {
+    voltage->beepNumber = sf->number;
+  } else {
+    voltage->beepNumber = -1;
+  }
+}
+
+static void fillChipTemperature (FeatureDescriptor *temperature,
+                                 const sensors_chip_name *name,
+                                 const sensors_feature *feature)
+{
+  const sensors_subfeature *sf, *sfmin, *sfmax, *sfhyst;
+  int pos = 0;
+
+  temperature->rrd = rrdF1;
+  temperature->type = DataType_temperature;
+
+  sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_TEMP_INPUT);
+  if (sf)
+    temperature->dataNumbers[pos++] = sf->number;
+
+  sfmin = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_TEMP_MIN);
+  sfmax = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_TEMP_MAX);
+  sfhyst = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_TEMP_MAX_HYST);
+  if (sfmin && sfmax) {
+    temperature->format = fmtTemps_minmax_1;
+    temperature->dataNumbers[pos++] = sfmin->number;
+    temperature->dataNumbers[pos++] = sfmax->number;
+  } else if (sfmax && sfhyst) {
+    temperature->format = fmtTemps_1;
+    temperature->dataNumbers[pos++] = sfmax->number;
+    temperature->dataNumbers[pos++] = sfhyst->number;
+  } else {
+    temperature->format = fmtTemp_only;
+  }
+  
+  /* terminate the list */
+  temperature->dataNumbers[pos] = -1;
+
+  /* alarm if applicable */
+  if ((sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_TEMP_ALARM)) ||
+      (sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_TEMP_MAX_ALARM))) {
+    temperature->alarmNumber = sf->number;
+  } else {
+    temperature->alarmNumber = -1;
+  }
+  /* beep if applicable */
+  if ((sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_TEMP_BEEP))) {
+    temperature->beepNumber = sf->number;
+  } else {
+    temperature->beepNumber = -1;
+  }
+}
+
+static void fillChipFan (FeatureDescriptor *fan,
+                         const sensors_chip_name *name,
+                         const sensors_feature *feature)
+{
+  const sensors_subfeature *sf, *sfmin, *sfdiv;
+  int pos = 0;
+
+  fan->rrd = rrdF0;
+  fan->type = DataType_rpm;
+
+  sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_FAN_INPUT);
+  if (sf)
+    fan->dataNumbers[pos++] = sf->number;
+
+  sfmin = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_FAN_MIN);
+  if (sfmin) {
+    fan->dataNumbers[pos++] = sfmin->number;
+    sfdiv = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_FAN_DIV);
+    if (sfdiv) {
+      fan->format = fmtFans_0;
+      fan->dataNumbers[pos++] = sfdiv->number;
+    } else {
+      fan->format = fmtFans_nodiv_0;
+    }
+  } else {
+      fan->format = fmtFan_only;
+  }
+  
+  /* terminate the list */
+  fan->dataNumbers[pos] = -1;
+
+  /* alarm if applicable */
+  sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_FAN_ALARM);
+  if (sf) {
+    fan->alarmNumber = sf->number;
+  } else {
+    fan->alarmNumber = -1;
+  }
+  /* beep if applicable */
+  sf = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_FAN_BEEP);
+  if (sf) {
+    fan->beepNumber = sf->number;
+  } else {
+    fan->beepNumber = -1;
+  }
+}
+
+static void fillChipVid (FeatureDescriptor *vid,
+                         const sensors_chip_name *name,
+                         const sensors_feature *feature)
+{
+  const sensors_subfeature *sub;
+
+  sub = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_VID);
+  if (!sub)
+    return;
+
+  vid->format = fmtVolt_3;
+  vid->rrd = rrdF3;
+  vid->type = DataType_voltage;
+  vid->alarmNumber = -1;
+  vid->beepNumber = -1;
+  vid->dataNumbers[0] = sub->number;
+  vid->dataNumbers[1] = -1;
+}
+
+static void fillChipBeepEnable (FeatureDescriptor *beepen,
+                                const sensors_chip_name *name,
+                                const sensors_feature *feature)
+{
+  const sensors_subfeature *sub;
+
+  sub = sensors_get_subfeature(name, feature, SENSORS_SUBFEATURE_BEEP_ENABLE);
+  if (!sub)
+    return;
+
+  beepen->format = fmtSoundAlarm;
+  beepen->rrd = rrdF0;
+  beepen->type = DataType_other;
+  beepen->alarmNumber = -1;
+  beepen->beepNumber = -1;
+  beepen->dataNumbers[0] = sub->number;
+  beepen->dataNumbers[1] = -1;
+}
+
+static
+FeatureDescriptor * generateChipFeatures (const sensors_chip_name *chip)
+{
+	int nr, count = 1;
+	const sensors_feature *sensor;
+	FeatureDescriptor *features;
+
+	/* How many main features do we have? */
+	nr = 0;
+	while ((sensor = sensors_get_features(chip, &nr)))
+		count++;
+
+	/* Allocate the memory we need */
+	features = calloc(count, sizeof(FeatureDescriptor));
+	if (!features)
+		return NULL;
+
+	/* Fill in the data structures */
+	count = 0;
+	nr = 0;
+	while ((sensor = sensors_get_features(chip, &nr))) {
+		switch (sensor->type) {
+		case SENSORS_FEATURE_TEMP:
+			fillChipTemperature(&features[count], chip, sensor);
+			break;
+		case SENSORS_FEATURE_IN:
+			fillChipVoltage(&features[count], chip, sensor);
+			break;
+		case SENSORS_FEATURE_FAN:
+			fillChipFan(&features[count], chip, sensor);
+			break;
+		case SENSORS_FEATURE_VID:
+			fillChipVid(&features[count], chip, sensor);
+			break;
+		case SENSORS_FEATURE_BEEP_ENABLE:
+			fillChipBeepEnable(&features[count], chip, sensor);
+			break;
+		default:
+			continue;
+		}
+
+		features[count].feature = sensor;
+		count++;
+	}
+
+	return features;
+}
+
+ChipDescriptor * knownChips;
+
+int initKnownChips (void)
+{
+  int nr, count = 1;
+  const sensors_chip_name *name;
+
+  /* How many chips do we have? */
+  nr = 0;
+  while ((name = sensors_get_detected_chips(NULL, &nr)))
+    count++;
+
+  /* Allocate the memory we need */
+  knownChips = calloc(count, sizeof(ChipDescriptor));
+  if (!knownChips)
+    return 1;
+
+  /* Fill in the data structures */
+  count = 0;
+  nr = 0;
+  while ((name = sensors_get_detected_chips(NULL, &nr))) {
+    knownChips[count].name = name;
+    if ((knownChips[count].features = generateChipFeatures(name)))
+      count++;
+  }
+
+  return 0;
+}
+
+void freeKnownChips (void)
+{
+  int index0;
+
+  for (index0 = 0; knownChips[index0].features; index0++)
+    free (knownChips[index0].features);
+  free (knownChips);
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/lib.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/lib.c	(revision 4918)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/lib.c	(revision 4918)
@@ -0,0 +1,103 @@
+/*
+ * sensord
+ *
+ * A daemon that periodically logs sensor information to syslog.
+ *
+ * Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "sensord.h"
+#include "lib/error.h"
+
+static time_t cfgLastModified;
+
+static int
+loadConfig
+(const char *cfgPath, int reload) {
+  struct stat stats;
+  FILE *cfg = NULL;
+  int ret = 0;
+
+  if (!strcmp (cfgPath, "-")) {
+    if (!reload) {
+      if ((ret = sensors_init (stdin))) {
+        sensorLog (LOG_ERR, "Error loading sensors configuration file <stdin>: %s",
+                   sensors_strerror (ret));
+        ret = 12;
+      }
+    }
+  } else if (stat (cfgPath, &stats) < 0) {
+    sensorLog (LOG_ERR, "Error stating sensors configuration file: %s", cfgPath);
+    ret = 10;
+  } else if (!reload || (difftime (stats.st_mtime, cfgLastModified) > 0.0)) {
+    if (reload) {
+      sensorLog (LOG_INFO, "configuration reloading");
+      sensors_cleanup ();
+    }
+    if (!(cfg = fopen (cfgPath, "r"))) {
+      sensorLog (LOG_ERR, "Error opening sensors configuration file: %s", cfgPath);
+      ret = 11;
+    } else if ((ret = sensors_init (cfg))) {
+      sensorLog (LOG_ERR, "Error loading sensors configuration file %s: %s",
+                 cfgPath, sensors_strerror (ret));
+      ret = 11;
+    } else {
+      cfgLastModified = stats.st_mtime;
+    }
+    if (cfg)
+      fclose (cfg);
+  }
+
+  return ret;
+}
+
+int
+loadLib
+(const char *cfgPath) {
+  int ret;
+  ret = loadConfig (cfgPath, 0);
+  if (!ret)
+    ret = initKnownChips ();
+  return ret;
+}
+
+int
+reloadLib
+(const char *cfgPath) {
+  int ret;
+  freeKnownChips ();
+  ret = loadConfig (cfgPath, 1);
+  if (!ret)
+    ret = initKnownChips ();
+  return ret;
+}
+
+int
+unloadLib
+(void) {
+  freeKnownChips ();
+  sensors_cleanup ();
+  return 0;  
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/rrd.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/rrd.c	(revision 4849)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/rrd.c	(revision 4849)
@@ -0,0 +1,436 @@
+/*
+ * sensord
+ *
+ * A daemon that periodically logs sensor information to syslog.
+ *
+ * Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * RRD is the Round Robin Database
+ * 
+ * Get this package from:
+ *   http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/
+ *
+ * For compilation you need the development libraries;
+ * for execution you need the runtime libraries; for
+ * Web-based graph access you need the binary rrdtool.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <getopt.h>
+#include <rrd.h>
+
+#include "sensord.h"
+#include "lib/error.h"
+
+#define DO_READ 0
+#define DO_SCAN 1
+#define DO_SET 2
+#define DO_RRD 3
+
+/* one integer */
+#define STEP_BUFF 64
+/* RRA:AVERAGE:0.5:1:12345 */
+#define RRA_BUFF 256
+/* weak: max sensors for RRD .. TODO: fix */
+#define MAX_RRD_SENSORS 256
+/* weak: max raw label length .. TODO: fix */
+#define RAW_LABEL_LENGTH 32
+/* DS:label:GAUGE:900:U:U | :3000 .. TODO: fix */
+#define RRD_BUFF 64
+
+char rrdBuff[MAX_RRD_SENSORS * RRD_BUFF + 1];
+static char rrdLabels[MAX_RRD_SENSORS][RAW_LABEL_LENGTH + 1];
+
+#define LOADAVG "loadavg"
+#define LOAD_AVERAGE "Load Average"
+
+typedef int (*FeatureFN) (void *data, const char *rawLabel, const char *label, const FeatureDescriptor *feature);
+
+static char
+rrdNextChar
+(char c) {
+  if (c == '9') {
+    return 'A';
+  } else if (c == 'Z') {
+    return 'a';
+  } else if (c == 'z') {
+    return 0;
+  } else {
+    return c + 1;
+  }
+}
+
+static void
+rrdCheckLabel
+(const char *rawLabel, int index0) {
+  char *buffer = rrdLabels[index0];
+  int i, j, okay;
+  
+  i = 0;
+  while ((i < RAW_LABEL_LENGTH) && rawLabel[i]) { /* contrain raw label to [A-Za-z0-9_] */
+    char c = rawLabel[i];
+    if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) || (c == '_')) {
+      buffer[i] = c;
+    } else {
+      buffer[i] = '_';
+    }
+    ++ i;
+  }
+  buffer[i] = '\0';
+
+  j = 0;
+  okay = (i > 0);
+  while (okay && (j < index0)) /* locate duplicates */
+    okay = strcmp (rrdLabels[j ++], buffer);
+
+  while (!okay) { /* uniquify duplicate labels with _? or _?? */
+    if (!buffer[i]) {
+      if (i > RAW_LABEL_LENGTH - 3)
+        i = RAW_LABEL_LENGTH - 3;
+      buffer[i] = '_';
+      buffer[i + 1] = '0';
+      buffer[i + 2] = '\0';
+    } else if (!buffer[i + 2]) {
+      if (!(buffer[i + 1] = rrdNextChar (buffer[i + 1]))) {
+        buffer[i + 1] = '0';
+        buffer[i + 2] = '0';
+        buffer[i + 3] = '\0';
+      }
+    } else {
+      if (!(buffer[i + 2] = rrdNextChar (buffer[i + 2]))) {
+        buffer[i + 1] = rrdNextChar (buffer[i + 1]);
+        buffer[i + 2] = '0';
+      }
+    }
+    j = 0;
+    okay = 1;
+    while (okay && (j < index0))
+      okay = strcmp (rrdLabels[j ++], buffer);
+  }
+}
+
+static int
+applyToFeatures
+(FeatureFN fn, void *data) {
+  const sensors_chip_name *chip;
+  int i = 0, j, ret = 0, num = 0;
+
+  for (j = 0; (ret == 0) && (j < numChipNames); ++ j) {
+    while ((ret == 0) && ((chip = sensors_get_detected_chips (&chipNames[j], &i)) != NULL)) {
+      int index0, chipindex = -1;
+      for (index0 = 0; knownChips[index0].features; ++ index0)
+        /* Trick: we compare addresses here. We know it works because both
+           pointers were returned by sensors_get_detected_chips(), so they
+           refer to libsensors internal structures, which do not move. */
+        if (knownChips[index0].name == chip) {
+          chipindex = index0;
+          break;
+        }
+      if (chipindex >= 0) {
+        const ChipDescriptor *descriptor = &knownChips[chipindex];
+        const FeatureDescriptor *features = descriptor->features;
+
+        for (index0 = 0; (ret == 0) && (num < MAX_RRD_SENSORS) && features[index0].format; ++ index0) {
+          const FeatureDescriptor *feature = features + index0;
+          const char *rawLabel = features->feature->name;
+          char *label = NULL;
+
+          if (!(label = sensors_get_label (chip, features->feature))) {
+            sensorLog (LOG_ERR, "Error getting sensor label: %s/%s", chip->prefix, rawLabel);
+            ret = -1;
+          } else  {
+            rrdCheckLabel (rawLabel, num);
+            ret = fn (data, rrdLabels[num], label, feature);
+            ++ num;
+          }
+          if (label)
+            free (label);
+        }
+      }
+    }
+  }
+
+  return ret;
+}
+
+struct ds {
+  int num;
+  const char **argv;
+};
+
+static int
+rrdGetSensors_DS
+(void *_data, const char *rawLabel, const char *label, const FeatureDescriptor *feature) {
+  (void) label; /* no warning */
+  if (!feature || feature->rrd) {
+    struct ds *data = (struct ds *) _data;
+    char *ptr = rrdBuff + data->num * RRD_BUFF;
+    const char *min, *max;
+    data->argv[data->num ++] = ptr;
+    switch (feature ? feature->type : DataType_other) { /* arbitrary sanity limits */
+      case DataType_voltage:
+        min="-25";
+        max="25";
+        break;
+      case DataType_rpm:
+        min = "0";
+        max = "12000";
+        break;
+      case DataType_temperature:
+        min = "0";
+        max = "250";
+        break;
+      default:
+        min = max = "U";
+        break;
+    }
+    sprintf (ptr, "DS:%s:GAUGE:%d:%s:%s", rawLabel, /* number of seconds downtime during which average be used instead of unknown */ 5 * rrdTime, min, max);
+  }
+  return 0;
+}
+
+static int
+rrdGetSensors
+(const char **argv) {
+  int ret = 0;
+  struct ds data = { 0, argv};
+  ret = applyToFeatures (rrdGetSensors_DS, &data);
+  if (!ret && doLoad)
+    ret = rrdGetSensors_DS (&data, LOADAVG, LOAD_AVERAGE, NULL);
+  return ret ? -1 : data.num;
+}
+
+int
+rrdInit
+(void) {
+  int ret = 0;
+  struct stat tmp;
+  
+  sensorLog (LOG_DEBUG, "sensor RRD init"); 
+  if (stat (rrdFile, &tmp)) {
+    if (errno == ENOENT) {
+      char stepBuff[STEP_BUFF], rraBuff[RRA_BUFF];
+      int argc = 4, num;
+      const char *argv[6 + MAX_RRD_SENSORS] = {
+        "sensord", rrdFile, "-s", stepBuff
+      };
+      
+      sensorLog (LOG_INFO, "creating round robin database");
+      num = rrdGetSensors (argv + argc);
+      if (num == 0) {
+        sensorLog (LOG_ERR, "Error creating RRD: %s: %s", rrdFile, "No sensors detected");
+        ret = 2;
+      } else if (num < 0) {
+        ret = -num;
+      } else {
+        sprintf (stepBuff, "%d", rrdTime);
+        sprintf (rraBuff, "RRA:%s:%f:%d:%d", rrdNoAverage?"LAST":"AVERAGE", 0.5 /* fraction of non-unknown samples needed per entry */, 1 /* samples per entry */, 7 * 24 * 60 * 60 / rrdTime /* 1 week */);
+        argc += num;
+        argv[argc ++] = rraBuff;
+        argv[argc] = NULL;
+        optind = 1;
+        opterr = 0;
+        optopt = '?';
+        optarg = NULL;
+        if ((ret = rrd_create (argc, (char **) /* WEAK */ argv))) {
+          sensorLog (LOG_ERR, "Error creating RRD file: %s: %s", rrdFile, rrd_get_error ());
+        }
+      }
+    } else {
+      sensorLog (LOG_ERR, "Error stat()ing RRD: %s: %s", rrdFile, strerror (errno));
+      ret = 1;
+    }
+  }
+  sensorLog (LOG_DEBUG, "sensor RRD inited"); 
+  
+  return ret;
+}
+
+#define RRDCGI "/usr/bin/rrdcgi"
+#define WWWDIR "/sensord"
+
+struct gr {
+  DataType type;
+  const char *h2;
+  const char *image;
+  const char *title;
+  const char *axisTitle;
+  const char *axisDefn;
+  const char *options;
+  int loadAvg;
+};
+
+static int
+rrdCGI_DEF
+(void *_data, const char *rawLabel, const char *label, const FeatureDescriptor *feature) {
+  struct gr *data = (struct gr *) _data;
+  (void) label; /* no warning */
+  if (!feature || (feature->rrd && (feature->type == data->type)))
+    printf ("\n\tDEF:%s=%s:%s:AVERAGE", rawLabel, rrdFile, rawLabel);
+  return 0;
+}
+
+static int
+rrdCGI_LINE
+(void *_data, const char *rawLabel, const char *label, const FeatureDescriptor *feature) {
+  struct gr *data = (struct gr *) _data;
+  if (!feature || (feature->rrd && (feature->type == data->type)))
+    printf ("\n\tLINE2:%s#%.6x:\"%s\"", rawLabel, (int) random () & 0xffffff, label);
+  return 0;
+}
+
+static struct gr graphs[] = {
+  {
+    DataType_temperature,
+    "Daily Temperature Summary",
+    "daily-temperature",
+    "Temperature",
+    "Temperature (C)",
+    "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00",
+    "-s -1d -l 0",
+    1
+  }, {
+    DataType_rpm,
+    "Daily Fan Speed Summary",
+    "daily-rpm",
+    "Fan Speed",
+    "Speed (RPM)",
+    "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00",
+    "-s -1d -l 0",
+    0
+  }, {
+    DataType_voltage,
+    "Daily Voltage Summary",
+    "daily-voltage",
+    "Power Supply",
+    "Voltage (V)",
+    "HOUR:1:HOUR:3:HOUR:3:0:%b %d %H:00",
+    "-s -1d --alt-autoscale",
+    0
+  }, {
+    DataType_temperature,
+    "Weekly Temperature Summary",
+    "weekly-temperature",
+    "Temperature",
+    "Temperature (C)",
+    "HOUR:6:DAY:1:DAY:1:86400:%a %b %d",
+    "-s -1w -l 0",
+    1
+  }, {
+    DataType_rpm,
+    "Weekly Fan Speed Summary",
+    "weekly-rpm",
+    "Fan Speed",
+    "Speed (RPM)",
+    "HOUR:6:DAY:1:DAY:1:86400:%a %b %d",
+    "-s -1w -l 0",
+    0
+  }, {
+    DataType_voltage,
+    "Weekly Voltage Summary",
+    "weekly-voltage",
+    "Power Supply",
+    "Voltage (V)",
+    "HOUR:6:DAY:1:DAY:1:86400:%a %b %d",
+    "-s -1w --alt-autoscale",
+    0
+  }, {
+    DataType_other,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    0
+  }  
+};
+
+int
+rrdUpdate
+(void) {
+  int ret = rrdChips ();
+  if (!ret && doLoad) {
+    FILE *loadavg;
+    if (!(loadavg = fopen ("/proc/loadavg", "r"))) {
+      sensorLog (LOG_ERR, "Error opening `/proc/loadavg': %s", strerror (errno));
+      ret = 1;
+    } else {
+      float value;
+      if (fscanf (loadavg, "%f", &value) != 1) {
+        sensorLog (LOG_ERR, "Error reading load average");
+        ret = 2;
+      } else {
+        sprintf (rrdBuff + strlen (rrdBuff), ":%f", value);
+      }
+      fclose (loadavg);
+    }
+  }
+  if (!ret) {
+    const char *argv[] = {
+      "sensord", rrdFile, rrdBuff, NULL
+    };
+    optind = 1;
+    opterr = 0;
+    optopt = '?';
+    optarg = NULL;
+    if ((ret = rrd_update (3, (char **) /* WEAK */ argv))) {
+      sensorLog (LOG_ERR, "Error updating RRD file: %s: %s", rrdFile, rrd_get_error ());
+    }
+  }
+  sensorLog (LOG_DEBUG, "sensor rrd updated"); 
+  
+  return ret;
+}
+
+int
+rrdCGI
+(void) {
+  int ret = 0;
+  struct gr *graph = graphs;
+
+  printf ("#!" RRDCGI "\n\n<HTML>\n<HEAD>\n<TITLE>sensord</TITLE>\n</HEAD>\n<BODY>\n<H1>sensord</H1>\n");
+  while (graph->type != DataType_other) {
+    printf ("<H2>%s</H2>\n", graph->h2);
+    printf ("<P>\n<RRD::GRAPH %s/%s.png\n\t--imginfo '<IMG SRC=" WWWDIR "/%%s WIDTH=%%lu HEIGHT=%%lu>'\n\t-a PNG\n\t-h 200 -w 800\n", cgiDir, graph->image);
+    printf ("\t--lazy\n\t-v '%s'\n\t-t '%s'\n\t-x '%s'\n\t%s", graph->axisTitle, graph->title, graph->axisDefn, graph->options);
+    if (!ret)
+      ret = applyToFeatures (rrdCGI_DEF, graph);
+    if (!ret && doLoad && graph->loadAvg)
+      ret = rrdCGI_DEF (graph, LOADAVG, LOAD_AVERAGE, NULL);
+    if (!ret)
+      ret = applyToFeatures (rrdCGI_LINE, graph);
+    if (!ret && doLoad && graph->loadAvg)
+      ret = rrdCGI_LINE (graph, LOADAVG, LOAD_AVERAGE, NULL);
+    printf (">\n</P>\n");
+    ++ graph;
+  }
+  printf ("<p>\n<small><b>sensord</b> by <a href=\"mailto:merlin@merlin.org\">Merlin Hughes</a>, all credit to the <a href=\"http://www.lm-sensors.org/\">lm_sensors</a> crew.</small>\n</p>\n");
+  printf ("</BODY>\n</HTML>\n");
+  
+  return ret;
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/Module.mk
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/Module.mk	(revision 2604)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/Module.mk	(revision 2604)
@@ -0,0 +1,62 @@
+#  Module.mk - Makefile for a Linux module for reading sensor data.
+#  Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# The round robin database (RRD) development headers and libraries are
+# REQUIRED. Get this package from:
+#   http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/
+
+# Note that MODULE_DIR (the directory in which this file resides) is a
+# 'simply expanded variable'. That means that its value is substituted
+# verbatim in the rules, until it is redefined. 
+MODULE_DIR := prog/sensord
+PROGSENSORDDIR := $(MODULE_DIR)
+
+PROGSENSORDMAN8DIR := $(MANDIR)/man8
+PROGSENSORDMAN8FILES := $(MODULE_DIR)/sensord.8
+
+# Regrettably, even 'simply expanded variables' will not put their currently
+# defined value verbatim into the command-list of rules...
+PROGSENSORDTARGETS := $(MODULE_DIR)/sensord
+PROGSENSORDSOURCES := $(MODULE_DIR)/args.c $(MODULE_DIR)/chips.c $(MODULE_DIR)/lib.c $(MODULE_DIR)/rrd.c $(MODULE_DIR)/sense.c $(MODULE_DIR)/sensord.c
+
+# Include all dependency files. We use '.rd' to indicate this will create
+# executables.
+INCLUDEFILES += $(PROGSENSORDSOURCES:.c=.rd)
+
+REMOVESENSORDBIN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(SBINDIR)/%,$(PROGSENSORDTARGETS))
+REMOVESENSORDMAN := $(patsubst $(MODULE_DIR)/%,$(DESTDIR)$(PROGSENSORDMAN8DIR)/%,$(PROGSENSORDMAN8FILES))
+
+$(PROGSENSORDTARGETS): $(PROGSENSORDSOURCES:.c=.ro) lib/$(LIBSHBASENAME)
+	$(CC) $(EXLDFLAGS) -o $@ $(PROGSENSORDSOURCES:.c=.ro) -Llib -lsensors -lrrd
+
+all-prog-sensord: $(PROGSENSORDTARGETS)
+user :: all-prog-sensord
+
+install-prog-sensord: all-prog-sensord
+	$(MKDIR) $(DESTDIR)$(SBINDIR) $(DESTDIR)$(PROGSENSORDMAN8DIR)
+	$(INSTALL) -m 755 $(PROGSENSORDTARGETS) $(DESTDIR)$(SBINDIR)
+	$(INSTALL) -m 644 $(PROGSENSORDMAN8FILES) $(DESTDIR)$(PROGSENSORDMAN8DIR)
+user_install :: install-prog-sensord
+
+user_uninstall::
+	$(RM) $(REMOVESENSORDBIN)
+	$(RM) $(REMOVESENSORDMAN)
+
+clean-prog-sensord:
+	$(RM) $(PROGSENSORDDIR)/*.rd $(PROGSENSORDDIR)/*.ro 
+	$(RM) $(PROGSENSORDTARGETS)
+clean :: clean-prog-sensord
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/README
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/README	(revision 1955)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/README	(revision 1955)
@@ -0,0 +1,9 @@
+Daemon that periodically logs sensor readings to syslog or a round-robin
+database, and warns of sensor alarms.
+
+Compile this program by making lm_sensors with the following argument:
+  make PROG_EXTRA:=sensord
+
+The RRD (Round Robin Database) development headers and libraries are
+REQUIRED. Get this package from:
+  http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/args.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/args.c	(revision 4918)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/args.c	(revision 4918)
@@ -0,0 +1,308 @@
+/*
+ * sensord
+ *
+ * A daemon that periodically logs sensor information to syslog.
+ *
+ * Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <syslog.h>
+
+#include "sensord.h"
+#include "lib/error.h"
+#include "version.h"
+
+#define DEFAULT_CONFIG_FILE	ETCDIR "/sensors.conf"
+
+#define MAX_CHIP_NAMES 32
+
+int isDaemon = 0;
+const char *sensorsCfgFile = DEFAULT_CONFIG_FILE;
+const char *pidFile = "/var/run/sensord.pid";
+const char *rrdFile = NULL;
+const char *cgiDir = NULL;
+int scanTime = 60;
+int logTime = 30 * 60;
+int rrdTime = 5 * 60;
+int rrdNoAverage = 0;
+int syslogFacility = LOG_LOCAL4;
+int doScan = 0;
+int doSet = 0;
+int doCGI = 0;
+int doLoad = 0;
+int debug = 0;
+sensors_chip_name chipNames[MAX_CHIP_NAMES];
+int numChipNames = 0;
+
+static int
+parseTime
+(char *arg) {
+  char *end;
+  int value = strtoul (arg, &end, 10);
+  if ((end > arg) && (*end == 's')) {
+    ++ end;
+  } else if ((end > arg) && (*end == 'm')) {
+    value *= 60;
+    ++ end;
+  } else if ((end > arg) && (*end == 'h')) {
+    value *= 60 * 60;
+    ++ end;
+  }
+  if ((end == arg) || *end) {
+    fprintf (stderr, "Error parsing time value `%s'.\n", arg);
+    return -1;
+  }
+  return value;
+}
+
+static struct {
+  const char *name;
+  int id;
+} facilities[] = {
+  { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 },
+  { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 },
+  { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 },
+  { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 },
+  { "daemon", LOG_DAEMON }, { "user", LOG_USER },
+  { NULL, 0 }
+};
+
+static int
+parseFacility
+(char *arg) {
+  int i = 0;
+  while (facilities[i].name && strcasecmp (arg, facilities[i].name))
+    ++ i;
+  if (!facilities[i].name) {
+    fprintf (stderr, "Error parsing facility value `%s'.\n", arg);
+    return -1;
+  }
+  return facilities[i].id;
+}
+
+static const char *daemonSyntax =
+  "  -i, --interval <time>     -- interval between scanning alarms (default 60s)\n"
+  "  -l, --log-interval <time> -- interval between logging sensors (default 30m)\n"
+  "  -t, --rrd-interval <time> -- interval between updating RRD file (default 5m)\n"
+  "  -T, --rrd-no-average      -- switch RRD in non-average mode\n"
+  "  -r, --rrd-file <file>     -- RRD file (default <none>)\n"
+  "  -c, --config-file <file>  -- configuration file (default " DEFAULT_CONFIG_FILE ")\n"
+  "  -p, --pid-file <file>     -- PID file (default /var/run/sensord.pid)\n"
+  "  -f, --syslog-facility <f> -- syslog facility to use (default local4)\n"
+  "  -g, --rrd-cgi <img-dir>   -- output an RRD CGI script and exit\n"
+  "  -a, --load-average        -- include load average in RRD file\n"
+  "  -d, --debug               -- display some debug information\n"
+  "  -v, --version             -- display version and exit\n"
+  "  -h, --help                -- display help and exit\n"
+  "\n"
+  "Specify a value of 0 for any interval to disable that operation;\n"
+  "for example, specify --log-interval 0 to only scan for alarms."
+  "\n"
+  "Specify the filename `-' to read the config file from stdin.\n"
+  "\n"
+  "If no chips are specified, all chip info will be printed.\n"
+  "\n"
+  "If unspecified, no RRD (round robin database) is used. If specified and the\n"
+  "file does not exist, it will be created. For RRD updates to be successful,\n"
+  "the RRD file configuration must EXACTLY match the sensors that are used. If\n"
+  "your configuration changes, delete the old RRD file and restart sensord.\n";
+
+static const char *appSyntax =
+  "  -a, --alarm-scan          -- only scan for alarms\n"
+  "  -s, --set                 -- execute set statements (root only)\n"
+  "  -r, --rrd-file <file>     -- only update RRD file\n"
+  "  -c, --config-file <file>  -- configuration file (default " DEFAULT_CONFIG_FILE ")\n"
+  "  -d, --debug               -- display some debug information\n"
+  "  -v, --version             -- display version and exit\n"
+  "  -h, --help                -- display help and exit\n"
+  "\n"
+  "Specify the filename `-' to read the config file from stdin.\n"
+  "\n"
+  "If no chips are specified, all chip info will be printed.\n";
+
+static const char *daemonShortOptions = "i:l:t:Tf:r:c:p:advhg:";
+
+static const struct option daemonLongOptions[] = {
+  { "interval", required_argument, NULL, 'i' },
+  { "log-interval", required_argument, NULL, 'l' },
+  { "rrd-interval", required_argument, NULL, 't' },
+  { "rrd-no-average", no_argument, NULL, 'T' },
+  { "syslog-facility", required_argument, NULL, 'f' },
+  { "rrd-file", required_argument, NULL, 'r' },
+  { "config-file", required_argument, NULL, 'c' },
+  { "pid-file", required_argument, NULL, 'p' },
+  { "rrd-cgi", required_argument, NULL, 'g' },
+  { "load-average", no_argument, NULL, 'a' },
+  { "debug", no_argument, NULL, 'd' },
+  { "version", no_argument, NULL, 'v' },
+  { "help", no_argument, NULL, 'h' },
+  { NULL, 0, NULL, 0 }
+};
+
+static const char *appShortOptions = "asr:c:dvh";
+
+static const struct option appLongOptions[] = {
+  { "alarm-scan", no_argument, NULL, 'a' },
+  { "set", no_argument, NULL, 's' },
+  { "rrd-file", required_argument, NULL, 'r' },
+  { "config-file", required_argument, NULL, 'c' },
+  { "debug", no_argument, NULL, 'd' },
+  { "version", no_argument, NULL, 'v' },
+  { "help", no_argument, NULL, 'h' },
+  { NULL, 0, NULL, 0 }
+};
+
+int
+parseArgs
+(int argc, char **argv) {
+  int c;
+  const char *shortOptions;
+  const struct option *longOptions;
+
+  isDaemon = (argv[0][strlen (argv[0]) - 1] == 'd');
+  shortOptions = isDaemon ? daemonShortOptions : appShortOptions;
+  longOptions = isDaemon ? daemonLongOptions : appLongOptions;
+
+  while ((c = getopt_long (argc, argv, shortOptions, longOptions, NULL)) != EOF) {
+    switch(c) {
+      case 'i':
+        if ((scanTime = parseTime (optarg)) < 0)
+          return -1;
+        break;
+      case 'l':
+        if ((logTime = parseTime (optarg)) < 0)
+          return -1;
+        break;
+      case 't':
+        if ((rrdTime = parseTime (optarg)) < 0)
+          return -1;
+        break;
+      case 'T':
+        rrdNoAverage = 1;
+        break;
+      case 'f':
+        if ((syslogFacility = parseFacility (optarg)) < 0)
+          return -1;
+        break;
+      case 'a':
+        if (isDaemon)
+          doLoad = 1;
+        else
+          doScan = 1;
+        break;
+      case 's':
+        doSet = 1;
+        break;
+      case 'c':
+        sensorsCfgFile = optarg;
+        break;
+      case 'p':
+        pidFile = optarg;
+        break;
+      case 'r':
+        rrdFile = optarg;
+        break;
+      case 'd':
+        debug = 1;
+        break;
+      case 'g':
+        doCGI = 1;
+        cgiDir = optarg;
+        break;
+      case 'v':
+        printf ("sensord version %s\n", LM_VERSION);
+        exit (EXIT_SUCCESS);
+        break;
+      case 'h':
+        printf ("Syntax: %s {options} {chips}\n%s", argv[0], isDaemon ? daemonSyntax : appSyntax);
+        exit (EXIT_SUCCESS);
+        break;
+      case ':':
+      case '?':
+        printf ("Try `%s --help' for more information.\n", argv[0]);
+        return -1;
+        break;
+      default:
+        fprintf (stderr, "Internal error while parsing options.\n");
+        return -1;
+        break;
+    }
+  }
+
+  if (doScan && doSet) {
+    fprintf (stderr, "Error: Incompatible --set and --alarm-scan.\n");
+    return -1;
+  }
+  
+  if (rrdFile && doSet) {
+    fprintf (stderr, "Error: Incompatible --set and --rrd-file.\n");
+    return -1;
+  }
+  
+  if (doScan && rrdFile) {
+    fprintf (stderr, "Error: Incompatible --rrd-file and --alarm-scan.\n");
+    return -1;
+  }
+
+  if (doCGI && !rrdFile) {
+    fprintf (stderr, "Error: Incompatible --rrd-cgi without --rrd-file.\n");
+    return -1;
+  }
+  
+  if (rrdFile && !rrdTime) {
+    fprintf (stderr, "Error: Incompatible --rrd-file without --rrd-interval.\n");
+    return -1;
+  }
+  
+  if (!logTime && !scanTime && !rrdFile) {
+    fprintf (stderr, "Error: No logging, alarm or RRD scanning.\n");
+    return -1;
+  }
+
+  return 0;
+}
+
+int
+parseChips
+(int argc, char **argv) {
+  if (optind == argc) {
+    chipNames[0].prefix = SENSORS_CHIP_NAME_PREFIX_ANY;
+    chipNames[0].bus.type = SENSORS_BUS_TYPE_ANY;
+    chipNames[0].bus.nr = SENSORS_BUS_NR_ANY;
+    chipNames[0].addr = SENSORS_CHIP_NAME_ADDR_ANY;
+    numChipNames = 1;
+  } else {
+    int i, n = argc - optind, err;
+    if (n > MAX_CHIP_NAMES) {
+      fprintf (stderr, "Too many chip names.\n");
+      return -1;
+    }
+    for (i = 0; i < n; ++ i) {
+      char *arg = argv[optind + i];
+      if ((err = sensors_parse_chip_name (arg, chipNames + i))) {
+        fprintf (stderr, "Invalid chip name `%s': %s\n", arg, sensors_strerror (err));
+        return -1;
+      }
+    }
+    numChipNames = n;
+  }
+  return 0;
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sense.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sense.c	(revision 4834)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sense.c	(revision 4834)
@@ -0,0 +1,233 @@
+/*
+ * sensord
+ *
+ * A daemon that periodically logs sensor information to syslog.
+ *
+ * Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "sensord.h"
+#include "lib/error.h"
+
+#define DO_READ 0
+#define DO_SCAN 1
+#define DO_SET 2
+#define DO_RRD 3
+
+static const char *
+chipName
+(const sensors_chip_name *chip) {
+  static char buffer[256];
+  if (sensors_snprintf_chip_name(buffer, 256, chip) < 0)
+    return NULL;
+  return buffer;
+}
+
+static int
+idChip
+(const sensors_chip_name *chip) {
+  const char *adapter;
+
+  sensorLog (LOG_INFO, "Chip: %s", chipName (chip));
+  adapter = sensors_get_adapter_name (&chip->bus);
+  if (adapter)
+    sensorLog (LOG_INFO, "Adapter: %s", adapter);
+  
+  return 0;
+}
+
+static int
+doKnownChip
+(const sensors_chip_name *chip, const ChipDescriptor *descriptor, int action) {
+  const FeatureDescriptor *features = descriptor->features;
+  int index0, subindex;
+  int ret = 0;
+  double tmp;
+
+  if (action == DO_READ)
+    ret = idChip (chip);
+  for (index0 = 0; (ret == 0) && features[index0].format; ++ index0) {
+    const FeatureDescriptor *feature = features + index0;
+    int alarm, beep;
+    char *label = NULL;
+
+    if (!(label = sensors_get_label (chip, feature->feature))) {
+      sensorLog (LOG_ERR, "Error getting sensor label: %s/%s", chip->prefix, feature->feature->name);
+      ret = 22;
+    } else {
+      double values[MAX_DATA];
+
+      alarm = 0;
+      if (!ret && feature->alarmNumber != -1) {
+        if ((ret = sensors_get_value (chip, feature->alarmNumber, &tmp))) {
+          sensorLog (LOG_ERR, "Error getting sensor data: %s/#%d: %s", chip->prefix, feature->alarmNumber, sensors_strerror (ret));
+          ret = 20;
+        } else {
+          alarm = (int) (tmp + 0.5);
+        }
+      }
+      if ((action == DO_SCAN) && !alarm)
+        continue;
+
+      beep = 0;
+      if (!ret && feature->beepNumber != -1) {
+        if ((ret = sensors_get_value (chip, feature->beepNumber, &tmp))) {
+          sensorLog (LOG_ERR, "Error getting sensor data: %s/#%d: %s", chip->prefix, feature->beepNumber, sensors_strerror (ret));
+          ret = 21;
+        } else {
+          beep = (int) (tmp + 0.5);
+        }
+      }
+
+      for (subindex = 0; !ret && (feature->dataNumbers[subindex] >= 0); ++ subindex) {
+        if ((ret = sensors_get_value (chip, feature->dataNumbers[subindex], values + subindex))) {
+          sensorLog (LOG_ERR, "Error getting sensor data: %s/#%d: %s", chip->prefix, feature->dataNumbers[subindex], sensors_strerror (ret));
+          ret = 23;
+        }
+      }
+      if (ret == 0) {
+        if (action == DO_RRD) { // arse = "N:"
+          if (feature->rrd) {
+            const char *rrded = feature->rrd (values);
+            strcat (strcat (rrdBuff, ":"), rrded ? rrded : "U");
+          }
+        } else {
+          const char *formatted = feature->format (values, alarm, beep);
+          if (formatted) {
+            if (action == DO_READ) {
+              sensorLog (LOG_INFO, "  %s: %s", label, formatted);
+            } else {
+              sensorLog (LOG_ALERT, "Sensor alarm: Chip %s: %s: %s", chipName (chip), label, formatted);
+            }
+          }
+        }
+      }
+    }
+    if (label)
+      free (label);
+  }
+  return ret;
+}
+
+static int
+setChip
+(const sensors_chip_name *chip) {
+  int ret = 0;
+  if ((ret = idChip (chip))) {
+    sensorLog (LOG_ERR, "Error identifying chip: %s", chip->prefix);
+  } else if ((ret = sensors_do_chip_sets (chip))) {
+    sensorLog (LOG_ERR, "Error performing chip sets: %s: %s", chip->prefix, sensors_strerror (ret));
+    ret = 50;
+  } else {
+    sensorLog (LOG_INFO, "Set.");
+  }
+  return ret;
+}
+
+static int
+doChip
+(const sensors_chip_name *chip, int action) {
+  int ret = 0;
+  if (action == DO_SET) {
+    ret = setChip (chip);
+  } else {
+    int index0, chipindex = -1;
+    for (index0 = 0; knownChips[index0].features; ++ index0)
+      /* Trick: we compare addresses here. We know it works because both
+         pointers were returned by sensors_get_detected_chips(), so they
+         refer to libsensors internal structures, which do not move. */
+      if (knownChips[index0].name == chip) {
+        chipindex = index0;
+        break;
+      }
+    if (chipindex >= 0)
+      ret = doKnownChip (chip, &knownChips[chipindex], action);
+  }
+  return ret;
+}
+
+static int
+doChips
+(int action) {
+  const sensors_chip_name *chip;
+  int i = 0, j, ret = 0;
+
+  for (j = 0; (ret == 0) && (j < numChipNames); ++ j) {
+    while ((ret == 0) && ((chip = sensors_get_detected_chips (&chipNames[j], &i)) != NULL)) {
+      ret = doChip (chip, action);
+    }
+  }
+
+  return ret;
+}
+
+int
+readChips
+(void) {
+  int ret = 0;
+
+  sensorLog (LOG_DEBUG, "sensor read started");
+  ret = doChips (DO_READ);
+  sensorLog (LOG_DEBUG, "sensor read finished");
+
+  return ret;
+}
+
+int
+scanChips
+(void) {
+  int ret = 0;
+
+  sensorLog (LOG_DEBUG, "sensor sweep started"); /* only logged in debug mode */
+  ret = doChips (DO_SCAN);
+  sensorLog (LOG_DEBUG, "sensor sweep finished");
+
+  return ret;
+}
+
+int
+setChips
+(void) {
+  int ret = 0;
+
+  sensorLog (LOG_DEBUG, "sensor set started");
+  ret = doChips (DO_SET);
+  sensorLog (LOG_DEBUG, "sensor set finished");
+
+  return ret;
+}
+
+/* TODO: loadavg entry */
+
+int
+rrdChips
+(void) {
+  int ret = 0;
+
+  strcpy (rrdBuff, "N");
+
+  sensorLog (LOG_DEBUG, "sensor rrd started"); 
+  ret = doChips (DO_RRD);
+  sensorLog (LOG_DEBUG, "sensor rrd finished");
+
+  return ret;
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sensord.c
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sensord.c	(revision 4918)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/sensord/sensord.c	(revision 4918)
@@ -0,0 +1,231 @@
+/*
+ * sensord
+ *
+ * A daemon that periodically logs sensor information to syslog.
+ *
+ * Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sensord.h"
+
+static int logOpened = 0;
+
+static volatile sig_atomic_t done = 0;
+
+#define LOG_BUFFER 4096
+
+#include <stdarg.h>
+
+void
+sensorLog
+(int priority, const char *fmt, ...) {
+  static char buffer[1 + LOG_BUFFER];
+  va_list ap;
+  va_start (ap, fmt);
+  vsnprintf (buffer, LOG_BUFFER, fmt, ap);
+  buffer[LOG_BUFFER] = '\0';
+  va_end (ap);
+  if (debug || (priority < LOG_DEBUG)) {
+    if (logOpened) {
+      syslog (priority, "%s", buffer);
+    } else {
+      fprintf (stderr, "%s\n", buffer);
+      fflush (stderr);
+    }
+  }
+}
+
+static void
+signalHandler
+(int sig) {
+  signal (sig, signalHandler);
+  switch (sig) {
+    case SIGTERM:
+      done = 1;
+      break;
+  }
+}
+
+static int
+sensord
+(void) {
+  int ret = 0;
+  int scanValue = 0, logValue = 0;
+  /*
+   * First RRD update at next RRD timeslot to prevent failures due
+   * one timeslot updated twice on restart for example.
+   */
+  int rrdValue = rrdTime - time(NULL) % rrdTime;
+
+  sensorLog (LOG_INFO, "sensord started");
+
+  while (!done && (ret == 0)) {
+    if (ret == 0)
+      ret = reloadLib (sensorsCfgFile);
+    if ((ret == 0) && scanTime) { /* should I scan on the read cycle? */
+      ret = scanChips ();
+      if (scanValue <= 0)
+        scanValue += scanTime;
+    }
+    if ((ret == 0) && logTime && (logValue <= 0)) {
+      ret = readChips ();
+      logValue += logTime;
+    }
+    if ((ret == 0) && rrdTime && rrdFile && (rrdValue <= 0)) {
+      ret = rrdUpdate ();
+      /*
+       * The amount of time to wait is computed using the same method as
+       * in RRD instead of simply adding the interval.
+       */
+      rrdValue = rrdTime - time(NULL) % rrdTime;
+    }
+    if (!done && (ret == 0)) {
+      int a = logTime ? logValue : INT_MAX;
+      int b = scanTime ? scanValue : INT_MAX;
+      int c = (rrdTime && rrdFile) ? rrdValue : INT_MAX;
+      int sleepTime = (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c);
+      sleep (sleepTime);
+      scanValue -= sleepTime;
+      logValue -= sleepTime;
+      rrdValue -= sleepTime;
+    }
+  }
+
+  if (ret)
+    sensorLog (LOG_INFO, "sensord failed (%d)", ret);
+  else
+    sensorLog (LOG_INFO, "sensord stopped");
+
+  return ret;
+}
+
+static void
+openLog
+(void) {
+  openlog ("sensord", 0, syslogFacility);
+  logOpened = 1; 
+}
+
+static void
+daemonize
+(void) {
+  int pid;
+  struct stat fileStat;
+  FILE *file;
+
+  if (chdir ("/") < 0) {
+    perror ("chdir()");
+    exit (EXIT_FAILURE);
+  }
+
+  if (!(stat (pidFile, &fileStat)) &&
+      ((!S_ISREG (fileStat.st_mode)) || (fileStat.st_size > 11))) {
+    fprintf (stderr, "Error: PID file `%s' already exists and looks suspicious.\n", pidFile);
+    exit (EXIT_FAILURE);
+  }
+ 
+  if (!(file = fopen (pidFile, "w"))) {
+    fprintf (stderr, "fopen(\"%s\"): %s\n", pidFile, strerror (errno));
+    exit (EXIT_FAILURE);
+  }
+  
+  /* I should use sigaction but... */
+  if (signal (SIGTERM, signalHandler) == SIG_ERR) {
+    perror ("signal(SIGTERM)");
+    exit (EXIT_FAILURE);
+  }
+
+  if ((pid = fork ()) == -1) {
+    perror ("fork()");
+    exit (EXIT_FAILURE);
+  } else if (pid != 0) {
+    fprintf (file, "%d\n", pid);
+    fclose (file);
+    unloadLib ();
+    exit (EXIT_SUCCESS);
+  }
+
+  if (setsid () < 0) {
+    perror ("setsid()");
+    exit (EXIT_FAILURE);
+  }
+
+  fclose (file);
+  close (STDIN_FILENO);
+  close (STDOUT_FILENO);
+  close (STDERR_FILENO);
+}
+
+static void 
+undaemonize
+(void) {
+  unlink (pidFile);
+  closelog ();
+}
+
+int
+main
+(int argc, char **argv) {
+  int ret = 0;
+  
+  if (parseArgs (argc, argv) ||
+      parseChips (argc, argv))
+    exit (EXIT_FAILURE);
+  
+  if (loadLib (sensorsCfgFile))
+    exit (EXIT_FAILURE);
+
+  if (isDaemon)
+    openLog ();
+  if (rrdFile)
+    ret = rrdInit ();
+  
+  if (ret) {
+  } else if (doCGI) {
+    ret = rrdCGI ();
+  } else if (isDaemon) {
+    daemonize ();
+    ret = sensord ();
+    undaemonize ();
+  } else {
+    if (doSet)
+      ret = setChips ();
+    else if (doScan)
+      ret = scanChips ();
+    else if (rrdFile)
+      ret = rrdUpdate ();
+    else
+      ret = readChips ();
+  }
+  
+  if (unloadLib ())
+    exit (EXIT_FAILURE);
+  
+  return ret;
+}
Index: /lm-sensors/tags/V3-0-0-RC2/prog/maxilife/sysinfo.sh
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/maxilife/sysinfo.sh	(revision 791)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/maxilife/sysinfo.sh	(revision 791)
@@ -0,0 +1,26 @@
+#! /bin/sh
+
+lnxvers="`uname -s` `uname -r`"
+#host="`hostname -s`"
+host="`hostname`"
+blink="o"
+
+writelcd=/home/rdm/src/lm_sensors-2.5.0/prog/maxilife/writelcd.sh
+
+$writelcd "$host" 3
+
+i=0
+while true; do
+   $writelcd "$lnxvers $blink" 2
+   if [ $[i == 5] = 1 ]; then
+      $writelcd "`awk '{ printf("%s %s %s", $1, $2, $3) }' < /proc/loadavg`" 4
+      i=0
+   fi
+   if [ $blink = "o" ]; then
+      blink=O
+   else
+      blink=o
+   fi
+   sleep 1
+   i=$[i+1]
+done
Index: /lm-sensors/tags/V3-0-0-RC2/prog/maxilife/writelcd.sh
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/prog/maxilife/writelcd.sh	(revision 791)
+++ /lm-sensors/tags/V3-0-0-RC2/prog/maxilife/writelcd.sh	(revision 791)
@@ -0,0 +1,26 @@
+#! /bin/sh
+
+usage() {
+   echo "usage: $0 <string> <line>"
+   echo "       <string> must be <= 16 characters"
+   echo "       <line> lcd line number, between 1..4"
+}
+
+if [ $# != 2 ]; then
+   usage
+   exit 1
+fi
+
+str=$1
+line=$2
+
+if [ $[line < 1 || line > 4] = 1 ]; then
+   usage
+   exit 1
+fi
+
+sysctl=/proc/sys/dev/sensors/maxilife-nba-i2c-0-14/lcd
+
+printf "%-16.16s" "$str" | od -A n -l > $sysctl$line
+
+exit 0
Index: /lm-sensors/tags/V3-0-0-RC2/CHANGES
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/CHANGES	(revision 4936)
+++ /lm-sensors/tags/V3-0-0-RC2/CHANGES	(revision 4936)
@@ -0,0 +1,22 @@
+lm-sensors CHANGES file
+-----------------------
+
+3.0.0-rc2 (2007-10-10)
+  useful_addresses.html: Moved to the wiki
+  Makefile: Add sensors-conf-convert to make install
+  libsensors: Notify the caller when writing a value fails
+              Differentiate between different read error types
+              Report I/O errors as such
+  sensord: Log the error code on failure
+           Drop the configuration file search path mechanism (#2259)
+           Manual page update
+  sensors: Fix spurious critical temperature alarm
+           Print error messages to stderr
+           Make error messages more helpful and consistent
+           Better handling of the fault flags
+  sensors-conf-convert: Add a short help text
+  sensors-detect: Fix SMSC SCH311x detection
+                  Add AMD K10 CPU sensor detection 
+
+3.0.0-rc1 (2007-09-25)
+  Initial release
Index: /lm-sensors/tags/V3-0-0-RC2/COPYING
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/COPYING	(revision 4483)
+++ /lm-sensors/tags/V3-0-0-RC2/COPYING	(revision 4483)
@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Index: /lm-sensors/tags/V3-0-0-RC2/etc/sensors.conf.eg
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/etc/sensors.conf.eg	(revision 4934)
+++ /lm-sensors/tags/V3-0-0-RC2/etc/sensors.conf.eg	(revision 4934)
@@ -0,0 +1,2449 @@
+# Sensors configuration file used by 'libsensors'
+#------------------------------------------------
+#
+##########################################################################
+#                                                                        #
+#    PLEASE READ THIS HELPFUL HINT!!!                                    #
+#                                                                        #
+#       The 'set' lines (generally for min and max values)               #
+#       do not take effect until you run 'sensors -s' as root !!!        #
+#       We suggest you put 'sensors -s' in a /etc/rc.d/... file          #
+#       to be run at boot time after the modules are inserted !!!        #
+#                                                                        #
+##########################################################################
+#
+#
+# OVERVIEW
+# --------
+# This configuration file will be used by all userspace applications
+# linked to libsensors. It is NOT used by the lm_sensors drivers directly.
+#
+# This config file consists of two parts: the heavily commented LM78
+# example, and the real parts. Search for '####' if you want to skip
+# to the real stuff.
+#
+# Hash marks introduce comments, which continue until the end of a line.
+#
+# Identifiers consisting of only digits and letters can be used
+# unquoted; other identifiers must be quoted. Escape characters within
+# quotes operate like those in C.
+#
+#
+# CHIP LINES
+# ----------
+# A 'chip' line specifies what the following 'label', 'compute', 'set' and
+# 'ignore' lines refer to. In this case, until the
+# next 'chip' line, everything refers to all lm78 and lm79
+# chips. Other examples are *-isa-* for everything on the ISA bus, and
+# lm78-i2c-*-4e for all lm78 chips on address 0x4e of any I2C bus.
+#
+# If more chip statements match a specific chip, they are all considered.
+# Later lines overrule earlier lines, so if you set the in0 label for
+# lm78-* to "This", and later on the in0 label for lm78-isa-* to "That",
+# "That" is used for LM78 chips on the ISA bus, and "This" for LM78
+# chips on a non-ISA bus.
+#
+#	chip "lm78-*" "lm79-*"
+#
+#
+# FEATURE NAMES
+# -------------
+# Feature names are used in 'label', 'compute', 'set', and 'ignore' lines.
+# Example feature names are 'in0', 'temp2', 'in3_min', and 'temp3_over'.
+# These features are defined for each chip in lib/chips.c.
+#
+# Undefined features will be silently ignored in 'label' and 'compute' lines.
+# Undefined features in 'set' lines will result in 'Unknown feature name'
+# when running 'sensors -s'.
+#
+# Unfortunately, feature names starting with a number must be in
+# double quotes or you get "parse error, expecting 'NAME'".
+#
+#
+# LABEL LINES
+# -----------
+# A label line describes what a certain feature stands for on your
+# mainboard. Programs can retrieve these names and display them.
+# If no label is specified for a certain feature, the default name
+# (ie. 'fan1' for fan1) is used.
+#
+# These are as advised in the LM78 and LM79 data sheets, and used on most
+# boards we have seen.
+#
+#  	label in0 "VCore 1"
+#  	label in1 "VCore 2"
+#  	label in2 "+3.3V"
+#  	label in3 "+5V"
+#  	label in4 "+12V"
+#  	label in5 "-12V"
+#  	label in6 "-5V"
+#
+#
+# COMPUTE LINES
+# -------------
+# A compute line describes how to scale a certain feature. There are
+# two expressions in it: the first describes how the driver value must
+# be translated to a user value, the second how a user value must be
+# translated to a driver value. '@' is the value to operate on. You may
+# refer to other readable features (like 'cpu0_vid * 1.05').
+#
+# The following operators are valid: + - * / ( ) ^ `
+# ^ is e**x and ` is ln(x)
+#
+# Where it makes sense, compute lines are inherited by subfeatures.
+# For example, the compute line for 'in0' is automatically applied to
+# 'in0_min' and 'in0_max' as well.
+#
+#
+# VOLTAGE COMPUTATION DETAILS
+# ---------------------------
+# Most voltage sensors in sensor chips have a range of 0 to 4.096 Volts.
+# This is generally sufficient for the 3.3 and CPU (2.5V, for example)
+# supply voltages, so the sensor chip reading is the actual voltage.
+#
+# Other supply voltages must be scaled with an external resistor network.
+# The chip driver generally reports the 'raw' value 0 - 4.09 V, and the
+# userspace application must convert this raw value to an actual voltage.
+# The 'compute' lines provide this facility.
+#
+# Unfortunately the resistor values vary among motherboard types.
+# Therefore you may have to adjust the computations in this file
+# to match your motherboard.
+#
+# For positive voltages (in3, in4), two resistors are used, with the following
+# formula (R1,R2: resistor values, Vs: read voltage, Vin: pin voltage)
+#	R1 = R2 * (Vs/Vin - 1)
+# For negative voltages (in5, in6) two resistors are used, with the following
+# formula (Rin,Rf: resistor values, Vs: read voltage, Vin: pin voltage)
+#	Rin = (Vs * Rf) / Vin
+#
+# Note: Some chips use a different formula, see it87 section for example.
+#
+# Here are the official LM78 and LM79 data sheet values.
+# 	      Vs     R1,Rin   R2,Rf    Vin
+# 	in3   +5.0      6.8    10     +2.98
+# 	in4  +12.0     30      10     +3.00
+# 	in5  -12.0    240      60     +3.00
+# 	in6   -5.0    100      60     +3.00
+#
+# These would lead to these declarations:
+# 	compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+# 	compute in4 ((30/10)+1)*@  ,  @/((30/10)+1)
+# 	compute in5 -(240/60)*@    ,  -@/(240/60)
+# 	compute in6 -(100/60)*@    ,  -@/(100/60)
+#
+# On almost any mainboard we have seen, the Winbond compute values lead to
+# much better results, though.
+#
+# 	      Vs     R1,Rin   R2,Rf    Vin
+# 	in4  +12.0     28      10     +3.15
+# 	in5  -12.0    210      60.4   +3.45
+# 	in6   -5.0     90.9    60.4   +3.33
+#
+# These leads to these declarations:
+#  	compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+#  	compute in4 ((28/10)+1)*@  ,  @/((28/10)+1)
+#  	compute in5 -(210/60.4)*@  ,  -@/(210/60.4)
+#  	compute in6 -(90.9/60.4)*@ ,  -@/(90.9/60.4)
+#
+# NOTE: On many motherboards, the -5V and -12V sensors are not connected.
+# Add ignore lines so these readings will not be displayed. For example:
+#	ignore in5
+#	ignore in6
+#
+#
+# TEMPERATURE COMPUTATION EXAMPLES
+# --------------------------------
+# There are two common ways to adjust temperature readings.
+# One is to adjust by a constant. The other is to change the
+# temperature sensor type.
+#
+# Add 5 degrees to temperature sensor 1:
+#	compute temp1 @+5,@-5
+#
+# Sensor type adjustments (certain chips only):
+#	set temp1_type 1    # PII/Celeron Diode
+#	set temp1_type 2    # 3904 transistor
+#	set temp1_type 3    # thermal diode
+#	set temp1_type 4    # thermistor
+#	set temp1_type 5    # AMD AMDSI
+#	set temp1_type 6    # Intel PECI
+#
+# Often, a temperature sensor is disconnected; disable it with an ignore line:
+#	ignore temp3
+#
+#
+# SET LINES
+# ---------
+# Set statements set things like limits. Complete expressions can be
+# used. Not everything can sensibly be set: setting 'in0', for example,
+# is impossible! These settings are put through the compute translations;
+# so if we specify '12.8' for in6, '3.2' will actually be written!
+#
+# Important note: In the 'sensors' program, these only take effect
+# after running 'sensors -s'!!!
+#
+# Here are some examples:
+#
+#	set in0_max cpu0_vid*1.05
+#	set in0_min cpu0_vid*0.95
+#	set temp1_max 40
+#	set temp1_max_hyst 37
+#
+# Think of tempx_max as 'alarm set' and tempx_max_hyst as 'alarm clear'
+# thresholds. In most cases the 'max' value should be higher than
+# the 'max_hyst' value by several degrees.
+#
+# All the set statements from this file are commented out by default.
+# The reason is that the proper limits are highly system-dependent,
+# and writing improper limits may have all sorts of weird effects,
+# from beeping to CPU throttling to instant reboot. If you want to
+# actually set the limits, remove the comment marks.
+#
+#
+# IGNORE LINES
+# ------------
+# Ignore statements tell certain features are not wanted. As with compute
+# statements, 'ignore in0' would also invalidate 'in0_max' and 'in0_min'.
+# 'ignore' does not disable anything in the actual sensor chip; it
+# simply prevents the user program from accessing that data.
+#
+#	ignore in0
+#
+#
+# STATEMENT ORDER
+# ---------------
+# Statements can go in any order, EXCEPT that some statements depend
+# on others. Dependencies could be either in the library or the driver.
+# A 'compute' statement must go before a 'set' statement
+# for the same feature or else the 'set' won't be computed correctly.
+# This is a library dependency.
+# A 'set fan1_div' statement must go before a 'set fan1_min' statement,
+# because the driver uses the divisor in calculating the minimum.
+#
+#
+# BUS LINES
+# ---------
+# There is one other feature: the 'bus' statement. An example is below.
+#
+#	bus "i2c-0" "SMBus PIIX4 adapter at e800"
+#
+# If we refer from now on to 'i2c-0' in 'chip' lines, this will run-time
+# be matched to this bus. So even if the PIIX4 is called 'i2c-5' at that
+# moment, because five other adapters were detected first, 'i2c-0' in
+# the config file would always only match this physical bus. In the above
+# config file, this feature is not needed; but the next lines would
+# only affect the LM75 chips on the PIIX4 adapter:
+#
+#	chip "lm75-i2c-0-*"
+#
+# You can use "sensors --bus-list" to generate bus lines for your system.
+#
+#
+# BEEPS
+# -----
+# Some chips support alarms with beep warnings. When an alarm is triggered
+# you can be warned by a beeping signal through your computer speaker. It
+# is possible to enable beeps for all alarms on a chip using the following
+# line:
+#
+# 	set beep_enable 1
+#
+# or disable them using:
+#
+# 	set beep_enable 0
+#
+#
+##########################################################################
+#### Here begins the real configuration file
+
+
+chip "lm78-*" "lm79-*" "w83781d-*"
+
+# These are as advised in the LM78 and LM79 data sheets, and used on almost
+# any mainboard we have seen.
+
+    label in0 "VCore 1"
+    label in1 "VCore 2"
+    label in2 "+3.3V"
+    label in3 "+5V"
+    label in4 "+12V"
+    label in5 "-12V"
+    label in6 "-5V"
+
+# For positive voltages (in3, in4), two resistors are used, with the following
+# formula (R1,R2: resistor values, Vs: read voltage, Vin: pin voltage)
+#   R1 = R2 * (Vs/Vin - 1)
+# For negative voltages (in5, in6) two resistors are used, with the following
+# formula (Rin,Rf: resistor values, Vs: read voltage, Vin: pin voltage)
+#   Rin = (Vs * Rf) / Vin
+#
+# Here are the official LM78 and LM79 data sheet values.
+#       Vs     R1,Rin   R2,Rf    Vin
+# in3   +5.0      6.8    10     +2.98
+# in4  +12.0     30      10     +3.00
+# in5  -12.0    240      60     +3.00
+# in6   -5.0    100      60     +3.00
+#
+# These would lead to these declarations:
+# compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+# compute in4 ((30/10)+1)*@  ,  @/((30/10)+1)
+# compute in5 -(240/60)*@    ,  -@/(240/60)
+# compute in6 -(100/60)*@    ,  -@/(100/60)
+#
+# On almost any mainboard we have seen, the Winbond compute values lead to
+# much better results, though.
+#
+#       Vs     R1,Rin   R2,Rf    Vin
+# in4  +12.0     28      10     +3.15
+# in5  -12.0    210      60.4   +3.45
+# in6   -5.0     90.9    60.4   +3.33
+#
+# These leads to these declarations:
+
+    compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+    compute in4 ((28/10)+1)*@  ,  @/((28/10)+1)
+    compute in5 -(210/60.4)*@  ,  -@/(210/60.4)
+    compute in6 -(90.9/60.4)*@ ,  -@/(90.9/60.4)
+
+# Here, we assume the VID readings are valid, and we use a max. 5% deviation
+
+#    set in0_min cpu0_vid*0.95
+#    set in0_max cpu0_vid*1.05
+#    set in1_min cpu0_vid*0.95
+#    set in1_max cpu0_vid*1.05
+#    set in2_min 3.3 * 0.95
+#    set in2_max 3.3 * 1.05
+#    set in3_min 5.0 * 0.95
+#    set in3_max 5.0 * 1.05
+#    set in4_min 12 * 0.95
+#    set in4_max 12 * 1.05
+#    set in5_min -12 * 0.95
+#    set in5_max -12 * 1.05
+#    set in6_min -5 * 0.95
+#    set in6_max -5 * 1.05
+
+# Examples for lm78, lm79 temperature limits
+#    set temp1_max      40
+#    set temp1_max_hyst 37
+
+# Examples for w83781d temperature limits
+#    set temp1_max      40
+#    set temp1_max_hyst 37
+#    set temp2_max      52
+#    set temp2_max_hyst 47
+#    set temp3_max      52
+#    set temp3_max_hyst 47
+
+# Examples of fan low speed limits
+#    set fan1_min 3000
+#    set fan2_min 3000
+#    set fan3_min 3000
+
+# Ignore fans you don't actually have
+#    ignore fan1
+#    ignore fan2
+#    ignore fan3
+
+# In case a lm78 is used together with a lm75, the lm78 temp sensor will
+# generally show the M/B temperature while the lm75 temp sensor will show
+# the CPU temperature.
+#    label temp1 "M/B Temp"
+
+# Uncomment the following line to enable beeps for all alarms on this chip
+#    set beep_enable 1
+
+
+
+chip "lm75-*"
+
+# Most boards don't need scaling. Following is for the Asus TX97-E.
+#   compute temp1 @*2.0, @/2.0
+
+# Examples for temperature limits
+#    set temp1_max      70
+#    set temp1_max_hyst 65
+
+# In case a lm75 is used together with a lm78, the lm78 temp sensor will
+# generally show the M/B temperature while the lm75 temp sensor will show
+# the CPU temperature.
+#    label temp1 "CPU Temp"
+
+
+chip "sis5595-*"
+
+    label in0 "VCore 1"
+    label in1 "VCore 2"
+    label in2 "+3.3V"
+    label in3 "+5V"
+    label in4 "+12V"
+
+    compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+    compute in4 ((28/10)+1)*@  ,  @/((28/10)+1)
+
+#    set in0_min 2.0 * 0.95
+#    set in0_max 2.0 * 1.05
+#    set in1_min 2.0 * 0.95
+#    set in1_max 2.0 * 1.05
+#    set in2_min 3.3 * 0.95
+#    set in2_max 3.3 * 1.05
+#    set in3_min 5.0 * 0.95
+#    set in3_max 5.0 * 1.05
+#    set in4_min 12 * 0.95
+#    set in4_max 12 * 1.05
+
+#
+# SiS5595 temperature calculation
+# The driver currently includes a calculation due to the wide
+# variation in thermistor types on SiS5595 motherboards.
+# The driver currently has a calculation of t = (.83x + 52.12).
+# One user reports the correct formula of t = (.345x - 12).
+# So you want to put a compute line in sensors.conf that has
+# the inverse of the driver formula, and put your formula on top of it.
+# The inverse of the driver formula is x = (1.20t - 62.77)
+# So the final formula is newt = (.345(1.20t - 62.77)) - 12).
+# Put this in the sensors.conf file as
+# compute temp1 ((.345 * ((1.20 * @) - 62.77)) - 12), ...
+# where ... is the inverse function I leave to you.
+#
+# Look in your 'Vendor.ini' file to see which one is present
+# on your motherboard. Look for the line like:
+#	[Temp1]
+#	     ThermistorType     = NTC-10KC15-1608-1P
+# Fix up a 'compute' line to match your thermistor type.
+# Warning. You still don't have enough information to do this.
+#	     ThermistorType     = NTC-10KC15-1608-1P (10K at 25C; Beta = 3435)
+#   compute temp1 ((X * ((1.20 * @) - 62.77)) - Y), ...
+#	     ThermistorType     = NTC-103KC15-1608-1P  (??)
+#   compute temp1 ((X * ((1.20 * @) - 62.77)) - Y), ...
+#	     ThermistorType     = NTC-103AT-2 (10K at 25C; Beta = 3435)
+#   compute temp1 ((X * ((1.20 * @) - 62.77)) - Y), ...
+#	     ThermistorType     = NTC-103JT   (10K at 25C; Beta = 3435)
+#   compute temp1 ((X * ((1.20 * @) - 62.77)) - Y), ...
+
+# examples for sis5595 temperature limits;
+#    set temp1_max      40
+#    set temp1_max_hyst 37
+
+
+chip "w83782d-*" "w83627hf-*"
+
+# Same as above for w83781d except that in5 and in6 are computed differently.
+# Rather than an internal inverting op amp, the 82d/83s use standard positive
+# inputs and the negative voltages are level shifted by a 3.6V reference.
+# The math is convoluted, so we hope that your motherboard
+# uses the recommended resistor values.
+
+    label in0 "VCore 1"
+    label in1 "VCore 2"
+    label in2 "+3.3V"
+    label in3 "+5V"
+    label in4 "+12V"
+    label in5 "-12V"
+    label in6 "-5V"
+    label in7 "V5SB"
+    label in8 "VBat"
+
+# Abit BP6 motherboard has a few differences. VCore1 and VCore2 are the core
+# voltages of the two processors. Vtt is memory bus termination resistors
+# voltage.
+#    label in1 "Vtt"
+#    label in8 "VCore2"
+
+    compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+    compute in4 ((28/10)+1)*@  ,  @/((28/10)+1)
+    compute in5 (5.14 * @) - 14.91  ,  (@ + 14.91) / 5.14
+    compute in6 (3.14 * @) -  7.71  ,  (@ +  7.71) / 3.14
+    compute in7 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+
+# set limits to  5% for the critical voltages
+# set limits to 10% for the non-critical voltages
+# set limits to 20% for the battery voltage
+
+#    set in0_min cpu0_vid*0.95
+#    set in0_max cpu0_vid*1.05
+#    set in1_min cpu0_vid*0.95
+#    set in1_max cpu0_vid*1.05
+#    set in2_min 3.3 * 0.95
+#    set in2_max 3.3 * 1.05
+#    set in3_min 5.0 * 0.95
+#    set in3_max 5.0 * 1.05
+#    set in4_min 12 * 0.90
+#    set in4_max 12 * 1.10
+#    set in5_max -12 * 0.90
+#    set in5_min -12 * 1.10
+#    set in6_max -5 * 0.95
+#    set in6_min -5 * 1.05
+#    set in7_min 5 * 0.95
+#    set in7_max 5 * 1.05
+#    set in8_min 3.0 * 0.80
+#    set in8_max 3.0 * 1.20
+
+# set up sensor types (thermistor is default)
+# 1 = PII/Celeron Diode; 2 = 3904 transistor;
+# 3435 = thermistor with Beta = 3435
+# If temperature changes very little, try 1 or 2.
+#   set temp1_type 1
+#   set temp2_type 2
+#   set temp3_type 3435
+
+# examples for temperature limits
+#    set temp1_max      40
+#    set temp1_max_hyst 37
+#    set temp2_max      52
+#    set temp2_max_hyst 47
+#    set temp3_max      52
+#    set temp3_max_hyst 47
+
+
+chip "w83783s-*"
+
+# Same as above for w83781d except that in5 and in6 are computed differently.
+# Rather than an internal inverting op amp, the 82d/83s use standard positive
+# inputs and the negative voltages are level shifted by a 3.6V reference.
+# The math is convoluted, so we hope that your motherboard
+# uses the recommended resistor values.
+
+    label in0 "VCore 1"
+    label in2 "+3.3V"
+    label in3 "+5V"
+    label in4 "+12V"
+    label in5 "-12V"
+    label in6 "-5V"
+
+    compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+    compute in4 ((28/10)+1)*@  ,  @/((28/10)+1)
+    compute in5 (5.14 * @) - 14.91  ,  (@ + 14.91) / 5.14
+    compute in6 (3.14 * @) -  7.71  ,  (@ +  7.71) / 3.14
+
+# set limits to  5% for the critical voltages
+# set limits to 10% for the non-critical voltages
+# set limits to 20% for the battery voltage
+
+#   set in0_min cpu0_vid*0.95
+#   set in0_max cpu0_vid*1.05
+#   set in2_min 3.3 * 0.95
+#   set in2_max 3.3 * 1.05
+#   set in3_min 5.0 * 0.95
+#   set in3_max 5.0 * 1.05
+#   set in4_min 12 * 0.90
+#   set in4_max 12 * 1.10
+#   set in5_max -12 * 0.90
+#   set in5_min -12 * 1.10
+#   set in6_max -5 * 0.95
+#   set in6_min -5 * 1.05
+
+# set up sensor types (thermistor is default)
+# 1 = PII/Celeron Diode; 2 = 3904 transistor;
+# 3435 = thermistor with Beta = 3435
+# If temperature changes very little, try 1 or 2.
+#   set temp1_type 1
+#   set temp2_type 2
+
+# examples for temperature limits
+#    set temp1_max      40
+#    set temp1_max_hyst 37
+#    set temp2_max      52
+#    set temp2_max_hyst 47
+
+
+chip "w83697hf-*"
+
+# Same as above for w83781d except that in5 and in6 are computed differently.
+# Rather than an internal inverting op amp, the 82d/83s use standard positive
+# inputs and the negative voltages are level shifted by a 3.6V reference.
+# The math is convoluted, so we hope that your motherboard
+# uses the recommended resistor values.
+
+# no in1 on this chip.
+
+    label in0 "VCore"
+    label in2 "+3.3V"
+    label in3 "+5V"
+    label in4 "+12V"
+    label in5 "-12V"
+    label in6 "-5V"
+    label in7 "V5SB"
+    label in8 "VBat"
+
+# Tyan Trinity S2495 KT400 has a few differences. Thanks to Eric Schumann
+# for proving this information. Same is true for Epox 8K3A and 8KHA+.
+# Thanks to Thomas Schorpp for additional feedback.
+#    label in2 "VAgp"
+#    label in5 "+3.3V" # aka. Vio
+#    label in6 "Vdimm"
+#    label in7 "VBat"
+#    label in8 "V5SB"
+#
+# You'll also want to comment out the in5 and in6 compute lines right below,
+# and rename compute in7 to compute in8.
+
+    compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+    compute in4 ((28/10)+1)*@  ,  @/((28/10)+1)
+    compute in5 (5.14 * @) - 14.91  ,  (@ + 14.91) / 5.14
+    compute in6 (3.14 * @) -  7.71  ,  (@ +  7.71) / 3.14
+    compute in7 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+
+# 697HF does not have VID inputs so you MUST set your core
+# voltage limits below. Currently set for 1.8V core.
+#               vvv
+
+#   set in0_min 1.8 * 0.95
+#   set in0_max 1.8 * 1.05
+
+#   set in2_min 3.3 * 0.95
+#   set in2_max 3.3 * 1.05
+#   set in3_min 5.0 * 0.95
+#   set in3_max 5.0 * 1.05
+#   set in4_min 12 * 0.90
+#   set in4_max 12 * 1.10
+#   set in5_max -12 * 0.90
+#   set in5_min -12 * 1.10
+#   set in6_max -5 * 0.95
+#   set in6_min -5 * 1.05
+#   set in7_min 5 * 0.95
+#   set in7_max 5 * 1.05
+#   set in8_min 3.0 * 0.80
+#   set in8_max 3.0 * 1.20
+
+# And for Tyan Trinity S2495 KT400 and Epox 8K3A and 8KHA+:
+#    set in2_min 1.5 * 0.95
+#    set in2_max 1.5 * 1.05
+#    set in5_min 3.3 * 0.95
+#    set in5_max 3.3 * 1.05
+#    set in6_min 2.5 * 0.95 # 2.6 on Epox
+#    set in6_max 2.5 * 1.05 # 2.6 on Epox
+#    set in7_min 3.0 * 0.90
+#    set in7_max 3.0 * 1.10
+#    set in8_min 5 * 0.90
+#    set in8_max 5 * 1.10
+
+# set up sensor types (thermistor is default)
+# 1 = PII/Celeron Diode; 2 = 3904 transistor;
+# 3435 = thermistor with Beta = 3435
+# If temperature changes very little, try 1 or 2.
+#   set temp1_type 1
+#   set temp2_type 2
+#   set temp3_type 3435
+
+# examples for temperature limits
+#    set temp1_max      40
+#    set temp1_max_hyst 37
+#    set temp2_max      52
+#    set temp2_max_hyst 47
+
+
+chip "w83627thf-*" "w83637hf-*"
+
+# Rather than an internal inverting op amp, the 627thf uses standard positive
+# inputs and the negative voltages are level shifted by a 3.6V reference
+# (same as 82d/83s).
+# The math is convoluted, so we hope that your motherboard
+# uses the recommended resistor values.
+# Note that in1 (+12V) is the usual in4, and in4 (-12V) is the usual in5.
+# Data sheet is obviously wrong for in4, the usual formula should work.
+# No in5 nor in6.
+
+    label in0 "VCore"
+    label in1 "+12V"
+    label in2 "+3.3V"
+    label in3 "+5V"
+    label in4 "-12V"
+    label in7 "V5SB"
+    label in8 "VBat"
+
+# Mori Hiroyuki reported to need this (P4P800)
+#   compute in0 @/2, @*2
+
+    compute in1 ((28/10)+1)*@, @/((28/10)+1)
+    compute in3 ((34/51)+1)*@, @/((34/51)+1)
+    compute in4 (5.14*@)-14.91, (@+14.91)/5.14
+    compute in7 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+
+# set limits to  5% for the critical voltages
+# set limits to 10% for the non-critical voltages
+# set limits to 20% for the battery voltage
+# if your vid is wrong, you'll need to adjust in0_min and in0_max
+
+#   set in0_min cpu0_vid * 0.95
+#   set in0_max cpu0_vid * 1.05
+#   set in1_min 12 * 0.90
+#   set in1_max 12 * 1.10
+#   set in2_min 3.3 * 0.95
+#   set in2_max 3.3 * 1.05
+#   set in3_min 5.0 * 0.95
+#   set in3_max 5.0 * 1.05
+#   set in4_min -12 * 1.10
+#   set in4_max -12 * 0.90
+#   set in7_min 5 * 0.95
+#   set in7_max 5 * 1.05
+#   set in8_min 3.0 * 0.80
+#   set in8_max 3.0 * 1.20
+
+# set up sensor types (thermistor is default)
+# 1 = PII/Celeron Diode; 2 = 3904 transistor;
+# 3435 = thermistor with Beta = 3435
+# If temperature changes very little, try 1 or 2.
+#   set temp1_type 1
+#   set temp2_type 2
+#   set temp3_type 3435
+
+    label temp1 "M/B Temp"
+    label temp2 "CPU Temp"
+#   ignore temp3
+
+# examples for temperature limits
+#    set temp1_max      40
+#    set temp1_max_hyst 37
+#    set temp2_max      52
+#    set temp2_max_hyst 47
+#    set temp3_max      52
+#    set temp3_max_hyst 47
+
+#   ignore fan1
+    label fan2 "CPU Fan"
+#   ignore fan3
+
+
+# Here are configurations for Winbond W83792AD/D chip.
+chip "w83792d-*"
+
+    label in0 "VCoreA"
+    label in1 "VCoreB"
+    label in2 "VIN0"
+    label in3 "VIN1"
+    label in4 "VIN2"
+    label in5 "VIN3"
+    label in6 "5VCC"
+    label in7 "5VSB"
+    label in8 "VBAT"
+    label fan1 "Fan1"
+    label fan2 "Fan2"
+    label fan3 "Fan3"
+    label fan4 "Fan4"
+    label fan5 "Fan5"
+    label fan6 "Fan6"
+    label fan7 "Fan7"
+    label temp1 "Temp1"
+    label temp2 "Temp2"
+    label temp3 "Temp3"
+
+#    set in0_min 1.4
+#    set in0_max 1.6
+#    set in1_min 1.4
+#    set in1_max 1.6
+#    set in2_min 3.2
+#    set in2_max 3.4
+#    set in3_min 3.1
+#    set in3_max 3.3
+#    set in4_min 1.4
+#    set in4_max 1.5
+#    set in5_min 2.6
+#    set in5_max 2.65
+#    set in6_min 5 * 0.95
+#    set in6_max 5 * 1.05
+#    set in7_min 5 * 0.95
+#    set in7_max 5 * 1.05
+#    set in8_min 3 * 0.95
+#    set in8_max 3 * 1.05
+
+# fan1 adjustments examples
+
+#   set fan1_div 4
+#   set fan1_min 1500
+
+# temp2 limits examples
+
+#    set temp2_max      42
+#    set temp2_max_hyst 37
+
+# ignore examples
+
+#    ignore fan7
+#    ignore temp3
+
+
+# Here are configurations for Winbond W83793 chip.
+chip "w83793-*"
+
+    label in0 "VCoreA"
+    label in1 "VCoreB"
+    label in2 "Vtt"
+    label in5 "+3.3V"
+    label in6 "+12V"
+    label in7 "+5V"
+    label in8 "5VSB"
+    label in9 "VBAT"
+
+    compute in6 12*@ ,  @/12
+
+    label temp1 "CPU1 Temp"
+    label temp2 "CPU2 Temp"
+
+# fan1 adjustments examples
+
+#   set fan1_min 1500
+
+# temp2 limits examples
+
+#   set temp2_max       45
+#   set temp2_max_hyst  40
+
+# ignore examples
+
+#    ignore fan7
+#    ignore temp3
+
+
+chip "as99127f-*"
+
+# Asus won't release a datasheet so this is guesswork.
+# Thanks to Guntram Blohm, Jack, Ed Harrison, Artur Gawryszczak,
+# Victor G. Marimon and others for their feedback.
+
+# Dual power plane
+    label in0 "VCore 1"
+    label in1 "VCore 2"
+# Single power plane (A7V133, A7M266, CUV4X)
+#   label in0 "VCore"
+#   ignore in1
+
+    label in2 "+3.3V"
+    label in3 "+5V"
+    label in4 "+12V"
+# These last two may not make sense on all motherboards.
+    label in5 "-12V"
+    label in6 "-5V"
+
+    compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+    compute in4 ((28/10)+1)*@  ,  @/((28/10)+1)
+# AS99127F rev.1 (same as w83781d)
+    compute in5 -(240/60.4)*@ ,  -@/(240/60.4)
+    compute in6 -(90.9/60.4)*@ ,  -@/(90.9/60.4)
+# AS99127F rev.2 (same as w83782d)
+#   compute in5 (5.14 * @) - 14.91 , (@ + 14.91) / 5.14
+#   compute in6 (3.14 * @) -  7.71 , (@ +  7.71) / 3.14
+
+# Depending on your motherboard, you may have to use any of two formulae
+# for temp2. Quoting Artur Gawryszczak (edited to reflect subsequent fixes
+# to the driver):
+# "I guess, that the formula "(@*15/43)+25, (@-25)*43/15" is correct
+# for those Asus motherboards, which get CPU temperature from internal
+# thermal diode (Pentium Coppermine, and above), while no formula is needed
+# for Athlon/Duron boards, which use a thermistor in the socket."
+# An alternative formula was then found and reported by Victor G. Marimon.
+
+# Asus A7V133, Asus A7M266
+#   No compute line is needed
+# Asus CUV4X, Asus A7V8X
+#   compute temp2 (@*15/43)+25, (@-25)*43/15
+# Asus CUSL2, Asus CUV266-DLS, Asus TUSL2-C
+#   compute temp2 (@*30/43)+25, (@-25)*43/30
+
+# See comments above if temp3 looks bad. What works for temp2 is likely
+# to work for temp3 for dual-CPU boards, such as the CUV4X-D.
+
+# Most Asus boards have temperatures settled like that:
+    label temp1 "M/B Temp"
+    label temp2 "CPU Temp"
+# However, some boards have them swapped (A7N8X Deluxe rev.2,
+# A7N8X-E Deluxe rev.2, CUV4X):
+#   label temp1 "CPU Temp"
+#   label temp2 "M/B Temp"
+
+# Most boards have no temp3 by default, except for dual-CPU boards.
+#   label temp3 "CPU 2 Temp"
+#   ignore temp3
+
+# set limits to  5% for the critical voltages
+# set limits to 10% for the non-critical voltages
+# set limits to 20% for the battery voltage
+
+#    set in0_min cpu0_vid*0.95
+#    set in0_max cpu0_vid*1.05
+#    set in1_min cpu0_vid*0.95
+#    set in1_max cpu0_vid*1.05
+#    set in2_min 3.3 * 0.95
+#    set in2_max 3.3 * 1.05
+#    set in3_min 5.0 * 0.95
+#    set in3_max 5.0 * 1.05
+#    set in4_min 12 * 0.90
+#    set in4_max 12 * 1.10
+#    set in5_min -12 * 0.90
+#    set in5_max -12 * 1.10
+#    set in6_min -5 * 0.95
+#    set in6_max -5 * 1.05
+
+# examples for temperature limits
+#    set temp1_max      40
+#    set temp1_max_hyst 37
+#    set temp2_max      52
+#    set temp2_max_hyst 47
+#    set temp3_max      52
+#    set temp3_max_hyst 47
+
+
+chip "gl518sm-*"
+
+# IMPORTANT: in0, in1, and in2 values (+5, +3, and +12) CANNOT be read
+#
+# Factors and labels taken from GL518SM datasheet, they seem to give
+# reasonable values with EISCA connected Fan78
+
+  label in0 "+5V"
+  label in1 "+3.3V"
+  label in2 "+12V"
+  label in3 "Vcore"
+
+# in2 depends on external resistors (4,7k and 15k assumed here)
+# in1 and in3 require no scaling
+
+  compute in2 (197/47)*@  ,  @/(197/47)
+
+#  set in0_min 4.8
+#  set in0_max 5.2
+#  set in1_min 3.20
+#  set in1_max 3.40
+#  set in2_min 11.0
+#  set in2_max 13.0
+#  set in3_min 2.10
+#  set in3_max 2.30
+#  set fan2_min 0
+
+
+chip "gl520sm-*"
+
+# Factors and labels taken from GL520SM datasheet
+
+# The GL520SM has two application modes. In mode 1 it has two thermistor
+# inputs, in mode 2 it has only one and an extra (negative) voltage input.
+# The mode is supposed to be set properly by your BIOS so you should not
+# need to change it. Note that you have either temp2 or in4, not both.
+
+  label in0 "+5V"
+  label in1 "+3.3V"
+  label in2 "+12V"
+  label in3 "Vcore"
+  label in4 "-12V"
+
+# in1 and in3 require no scaling
+# in2 depends on external resistors (4,7k and 15k assumed)
+
+# in4 = ((R1+R2)/R2)*@ - (R1/R2)*vdd
+#
+#       -12 --| R1 |---t---| R2 |-- +5
+#                      |
+#                    vin4
+#
+
+  compute in2 (197/47)*@  ,  @/(197/47)
+  compute in4 (5*@)-(4*in0) , (@+4*in0)/5
+
+#  set in0_min 4.8
+#  set in0_max 5.2
+#  set in1_min 3.20
+#  set in1_max 3.40
+#  set in2_min 11.0
+#  set in2_max 13.0
+#  set in3_min 2.10
+#  set in3_max 2.30
+
+
+chip "lm80-*"
+
+# The values below should be correct if you own a qdi BX (brilliant1)
+# mainboard. Many thanks go to Peter T. Breuer for helping us figure
+# out how to handle the LM80.
+
+# For positive voltages (in0..in4), two resistors are used, with the following
+# formula (R1,R2: resistor values, Vs: read voltage, Vin: pin voltage)
+#   R1 = R2 * (Vs/Vin - 1)
+# For negative voltages (in5, in6) two resistors are used, with the following
+# formula (R3,R4: resistor values, Vs: read voltage, Vin: pin voltage,
+# V5: +5V)
+#   R3 = R4 * (Vs - Vin) / (Vin - V5)
+
+# Here are the official LM80 data sheet values.
+#       Vs      R1,R3   R2,R4    Vin
+#       +2.5V    23.7    75     +1.9
+#       +3.3V    22.1    30     +1.9
+#       +5.0     24      14.7   +1.9
+#      +12.0    160      30.1   +1.9
+#      -12.0    160      35.7   +1.9
+#       -5.0     36      16.2   +1.9
+
+# Now curiously enough, VCore is connected with (unknown) resistors, which
+# translate a +2.8V to +1.9V. So we use that in the computations below.
+
+    label in0 "+5V"
+    label in1 "VTT"
+    label in2 "+3.3V"
+    label in3 "+Vcore"
+    label in4 "+12V"
+    label in5 "-12V"
+    label in6 "-5V"
+
+    compute in0 (24/14.7 + 1) * @ ,       @ / (24/14.7 + 1)
+    compute in2 (22.1/30 + 1) * @ ,       @ / (22.1/30 + 1)
+    compute in3 (2.8/1.9) * @,            @ * 1.9/2.8
+    compute in4 (160/30.1 + 1) * @,       @ / (160/30.1 + 1)
+    compute in5 (160/35.7)*(@ - in0) + @, (@ + in0 * 160/35.7)/ (1 + 160/35.7)
+    compute in6 (36/16.2)*(@ - in0) + @,  (@ + in0 * 36/16.2) / (1 + 36/16.2)
+
+#    set in0_min 5 * 0.95
+#    set in0_max 5 * 1.05
+# What is your VTT? It is probably not this value...
+#    set in1_min 2*0.95
+#    set in1_max 2*1.05
+#    set in2_min 3.3 * 0.95
+#    set in2_max 3.3 * 1.05
+# What is your VCore? It is probably not this value...
+#    set in3_min 1.9 * 0.95
+#    set in3_max 1.9 * 1.05
+#    set in4_min 12 * 0.95
+#    set in4_max 12 * 1.05
+#    set in5_min -12 * 1.05
+#    set in5_max -12 * 0.95
+#    set in6_min -5 * 1.05
+#    set in6_max -5 * 0.95
+
+# All 4 of these limits apply to the single temperature sensor.
+# "crit" may or may not do anything on your motherboard but it should
+#  be set higher than the "max" thresholds.
+#    set temp1_max_hyst   45
+#    set temp1_max        52
+#    set temp1_crit_hyst  57
+#    set temp1_crit       62
+
+
+chip "via686a-*"
+
+# VIA is very specific about the voltage sensor inputs, and our labels
+# reflect what they say.  Unfortunately, they are not at all specific about
+# how to convert any of the register values to real units.  Fortunately,
+# Jonathan Yew and Alex van Kaam came through with some data for temp
+# conversion and formulae for voltage conversion. However, the conversions
+# should be regarded as our best guess - YMMV.
+
+# On the Tyan S1598, the 2.5V sensor reads 0 and is not displayed in the BIOS.
+# Linas Vepstas reports that this sensor shows nothing of
+# interest on the Abit KA7 (Athlon), and is also not displayed in the BIOS.
+# Likewise, Johannes Drechsel-Burkhard reports that this
+# sensor is unavailable in the BIOS of his MSI K7T Pro (Thunderbird).  So,
+# if you have one of these boards you may want to uncomment the 'ignore in1'
+# line below.
+
+    label in0 "CPU core"
+    label in1 "+2.5V"
+    #ignore in1
+    label in2 "I/O"
+    label in3 "+5V"
+    label in4 "+12V"
+
+    label fan1  "CPU Fan"
+    label fan2  "P/S Fan"
+
+# VIA suggests that temp3 is an internal temp sensor for the 686a.  However,
+# on the Tyan S1598 as well as the Abit KA7 (Athalon), the absolute values
+# of the readings from that sensor are not valid.  The readings do seem to
+# correlate with temp changes, but the conversion factor may be quite
+# different from temp1 & temp2 (as noted above, VIA has not provided
+# conversion info).  So, you may wish to 'ignore temp3'.
+
+# Johannes Drechsel-Burkhard notes that on his MSI K7T Pro,
+# temp1 is the CPU temp and temp2 is the SYS temp. Hugo van der Merwe notes
+# the same for his Gigabyte GA-7DXC, Olivier Martin for his Gigabyte
+# GA-7ZM and Patrick Thomson for his Chaintech CT-5ATA.
+# Thomas Anglmaier notes: on Epox EP-7kxa temp2 is CPU and temp1 is SYS.
+
+    label temp1 "SYS Temp"
+    label temp2 "CPU Temp"
+    label temp3 "SBr Temp"
+    #ignore temp3
+
+# Set your CPU core limits here if the BIOS did not.
+
+    #set in0_min 1.70 * 0.95
+    #set in0_max 1.70 * 1.05
+
+# Other voltage values are standard so we can enforce the limits.
+
+#    set in1_min 2.5 * 0.95
+#    set in1_max 2.5 * 1.05
+#    set in2_min 3.3 * 0.95
+#    set in2_max 3.3 * 1.05
+#    set in3_min 5 * 0.9
+#    set in3_max 5 * 1.1
+#    set in4_min 12 * 0.9
+#    set in4_max 12 * 1.1
+
+# Set your temp limits here.  Remember, 'tempX_max' is the temp at which an
+# alarm is triggered, and 'tempX_max_hyst' is the temp at which an alarm turns off.
+# Setting tempX_max_hyst to a few degrees below the corresponding tempX_max
+# prevents an oscillation between alarm on and off states.  This kind of
+# oscillation is known as hyteresis, thus the name.  (You typically get the
+# most serious and troublesome hysteresis when a sensor triggers something to
+# reduce the temp, thus creating a negative feedback loop.  Even without that,
+# we would still get some oscillation when the temp hovers around the limit
+# due to noise.)
+
+#    set temp1_max_hyst 40
+#    set temp1_max      45
+#    set temp2_max_hyst 55
+#    set temp2_max      60
+#    set temp3_max_hyst 60
+#    set temp3_max      65
+
+# You could set your fan limits too, but the defaults should be fine.
+
+    #set fan1_min 5000
+    #set fan2_min 5000
+
+
+chip "adm1025-*" "ne1619-*"
+
+# The ADM1025 has integrated scaling resistors, rather
+# than external resistors common to most sensor devices.
+# These apply to the 6 voltage inputs in0-in5 (+2.5V, VCore,
+# +3.3V, +5V, +12V, VCC). As the scaling is fixed inside
+# the chip for these inputs, it is fairly certain that the
+# motherboard connections match these labels, and that the
+# driver computations are correct. Therefore they do not need to
+# be overridden here.
+
+    label in0 "+2.5V"
+    label in1 "VCore"
+    label in2 "+3.3V"
+    label in3 "+5V"
+    label in4 "+12V"
+    label in5 "VCC"
+
+# Tolerate a 5% deviance for CPU power-supply
+#    set in1_min cpu0_vid * 0.95
+#    set in1_max cpu0_vid * 1.05
+# Tolerate a 10% deviance for other voltages
+#    set in0_min 2.5 * 0.90
+#    set in0_max 2.5 * 1.10
+#    set in2_min 3.3 * 0.90
+#    set in2_max 3.3 * 1.10
+#    set in3_min 5.0 * 0.90
+#    set in3_max 5.0 * 1.10
+#    set in4_min 12 * 0.90
+#    set in4_max 12 * 1.10
+#    set in5_min 3.3 * 0.90
+#    set in5_max 3.3 * 1.10
+
+# Depending on how your chipset is hardwired, you may or may not have
+# +12V readings (will show as 0.0V if you don't have it).
+#   ignore in4
+
+# VCC is the power-supply voltage of the ADM1025 chipset, generally
+# redundant with +3.3V so you may want to hide it.
+#   ignore in5
+
+# Temperatures
+    label temp1 "CPU Temp"
+    label temp2 "M/B Temp"
+#    set temp1_min 10
+#    set temp1_max 60
+#    set temp2_min 10
+#    set temp2_max 45
+
+
+chip "lm87-*" "adm1024-*"
+#
+# The LM87 has integrated scaling resistors, rather
+# than external resistors common to most sensor devices.
+# These apply to the first 6 voltage inputs in0-in5
+# (+2.5, Vccp1, +3.3, +5, 12, +Vccp2). As the scaling is fixed inside
+# the chip for these inputs, it is fairly certain that the
+# motherboard connections match these labels, and that the
+# driver computations are correct. Therefore they do not need to
+# be overridden here.
+
+   label in0  "+2.5V"
+   label in1  "VCore"
+   label in2  "+3.3V"
+   label in3  "+5V"
+   label in4  "+12V"
+#   label in5  "VCore2"
+
+   label fan1 "CPU Fan"
+#   label fan2 "Case Fan"
+   label temp1 "M/B Temp"
+   label temp2 "CPU Temp"
+#   label temp3 "AUX Temp"
+
+#   set in1_min  cpu0_vid * 0.95
+#   set in1_max  cpu0_vid * 1.05
+#   set in2_min  3.3 * 0.92
+#   set in2_max  3.3 * 1.08
+#   set in3_min    5 * 0.92
+#   set in3_max    5 * 1.08
+#   set in4_min   12 * 0.90
+#   set in4_max   12 * 1.10
+
+# These ones are mutually exclusive with temp3. If you have temp3,
+# comment out these lines as they will trigger errors on "sensors -s".
+#   set in0_min  2.5 * 0.92
+#   set in0_max  2.5 * 1.08
+#   set in5_min  cpu0_vid * 0.95
+#   set in5_max  cpu0_vid * 1.05
+
+# Increase fan clock dividers if your fans read 0 RPM while you know
+# they are connected and running.
+#   set fan1_div 4
+#   set fan2_div 4
+
+#   set fan1_min 3000
+#   set fan2_min 3000
+
+#   set temp1_min   5
+#   set temp1_max  65
+#   set temp2_min   5
+#   set temp2_max  70
+
+# Uncomment if you actually have temp3 (which means you don't have 2.5V
+# nor Vccp2, as they are mutually exclusive).
+#   set temp3_min   5
+#   set temp3_max  70
+
+# LM87 AIN1 and AIN2 Section
+# -12 and -5 may be reversed on your board, this is
+# just a guess, the datasheet gives no guidance.
+#   label in6 "-12V"
+#   label in7 "-5V"
+#   compute in6 (7.50 * @) - 21.45  ,  (@ + 21.45) / 7.50
+#   compute in7 (4.05 * @) - 10.07  ,  (@ + 10.07) / 4.05
+#   set in6_min -12 * 0.95
+#   set in7_min -5 * 0.95
+#   set in6_max -12 * 1.05
+#   set in7_max -5 * 1.05
+
+
+chip "it87-*" "it8712-*"
+
+# The values below have been tested on Asus CUSI, CUM motherboards.
+
+# Voltage monitors as advised in the It8705 data sheet
+
+    label in0 "VCore 1"
+    label in1 "VCore 2"
+    label in2 "+3.3V"
+    label in3 "+5V"
+    label in4 "+12V"
+    label in5 "-12V"
+    label in6 "-5V"
+    label in7 "Stdby"
+    label in8 "VBat"
+
+# Incubus Saturnus reports that the IT87 chip on Asus A7V8X-X seems
+# to report the VCORE voltage approximately 0.05V higher than the board's
+# BIOS does. Although it doesn't make much sense physically, uncommenting
+# the next line should bring the readings in line with the BIOS' ones in
+# this case.
+# compute in0 -0.05+@ , @+0.05
+
+# If 3.3V reads around 1.65V, uncomment the following line:
+#    compute in2   2*@ , @/2
+
+    compute in3 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+# A number of Gigabyte boards (GA-8IPE1000Pro, GA-8KNXP, GA-7N400-L) use
+# a different resistor combination for +5V:
+#    compute in3 ((10/10)+1)*@ ,  @/((10/10)+1)
+
+    compute in4 ((30/10) +1)*@  , @/((30/10) +1)
+# For this family of chips the negative voltage equation is different from
+# the lm78.  The chip uses two external resistor for scaling but one is
+# tied to a positive reference voltage.  See ITE8705/12 datasheet (SIS950
+# data sheet is wrong)
+# Vs = (1 + Rin/Rf) * Vin - (Rin/Rf) * Vref.
+# Vref = 4.096 volts, Vin is voltage measured, Vs is actual voltage.
+
+# The next two are negative voltages (-12 and -5).
+# The following formulas must be used. Unfortunately the datasheet
+# does not give recommendations for Rin, Rf, but we can back into
+# them based on a nominal +2V input to the chip, together with a 4.096V Vref.
+# Formula:
+#    actual V = (Vmeasured * (1 + Rin/Rf)) - (Vref * (Rin/Rf))
+#    For -12V input use Rin/Rf = 6.68
+#    For -5V input use Rin/Rf = 3.33
+# Then you can convert the forumula to a standard form like:
+    compute in5 (7.67 * @) - 27.36  ,  (@ + 27.36) / 7.67
+    compute in6 (4.33 * @) - 13.64  ,  (@ + 13.64) / 4.33
+#
+# this much simpler version is reported to work for a
+# Elite Group K7S5A board
+#
+#   compute in5 -(36/10)*@, -@/(36/10)
+#   compute in6 -(56/10)*@, -@/(56/10)
+#
+    compute in7 ((6.8/10)+1)*@ ,  @/((6.8/10)+1)
+
+#    set in0_min 1.5 * 0.95
+#    set in0_max 1.5 * 1.05
+#    set in1_min 2.4
+#    set in1_max 2.6
+#    set in2_min 3.3 * 0.95
+#    set in2_max 3.3 * 1.05
+#    set in3_min 5.0 * 0.95
+#    set in3_max 5.0 * 1.05
+#    set in4_min 12 * 0.95
+#    set in4_max 12 * 1.05
+#    set in5_max -12 * 0.95
+#    set in5_min -12 * 1.05
+#    set in6_max -5 * 0.95
+#    set in6_min -5 * 1.05
+#    set in7_min 5 * 0.95
+#    set in7_max 5 * 1.05
+    #the chip does not support in8 min/max
+
+# Temperature
+#
+# Important - if your temperature readings are completely whacky
+# you probably need to change the sensor type.
+# Adujst and uncomment the appropriate lines below.
+#
+# 2 = thermistor; 3 = thermal diode; 0 = unused
+#   set temp1_type 3
+#   set temp2_type 3
+#   set temp3_type 3
+# If a given sensor isn't used, you will probably want to ignore it
+# (see ignore statement right below).
+
+    label temp1       "M/B Temp"
+#    set   temp1_max   40
+#    set   temp1_min   15
+    label temp2       "CPU Temp"
+#    set   temp2_max   45
+#    set   temp2_min   15
+#   ignore temp3
+    label temp3       "Temp3"
+#    set   temp3_max   45
+#    set   temp3_min   15
+
+# The A7V8X-X has temperatures inverted, and needs a conversion for
+# CPU temp. Thanks to Preben Randhol for the formula.
+#   label temp1       "CPU Temp"
+#   label temp2       "M/B Temp"
+#   compute temp1     (-15.096+1.4893*@), (@+15.096)/1.4893
+
+# The A7V600 also has temperatures inverted, and needs a different
+# conversion for CPU temp. Thanks to Dariusz Jaszkowski for the formula.
+#   label temp1       "CPU Temp"
+#   label temp2       "M/B Temp"
+#   compute temp1     (@+128)/3, (3*@-128)
+
+# Fans
+#   set fan1_min 0
+#   set fan2_min 3000
+#   ignore fan3
+#   set fan3_min 3000
+
+
+chip "it8716-*"
+
+# Voltages
+
+    label  in0  "VCore"
+    label  in1  "VDDR"
+    label  in2  "+3.3V"    # VCC3
+    label  in3  "+5V"      # VCC
+    label  in4  "+12V"
+#   label  in5  "-12V"
+#   label  in6  "-5V"
+    label  in7  "5VSB"     # VCCH
+    label  in8  "VBat"
+
+    compute in3  ((6.8/10)+1)*@ , @/((6.8/10)+1)
+    compute in4  ((30/10)+1)*@  , @/((30/10)+1)
+#   compute in5  (1+232/56)*@ - 4.096*232/56 , (@ + 4.096*232/56)/(1+232/56)
+#   compute in6  (1+120/56)*@ - 4.096*120/56 , (@ + 4.096*120/56)/(1+120/56)
+    compute in7  ((6.8/10)+1)*@ , @/((6.8/10)+1)
+
+# If vid (nominal CPU voltage) isn't correct, hardcode the correct value
+# instead.
+#    set in0_min  cpu0_vid * 0.95
+#    set in0_max  cpu0_vid * 1.05
+#    set in1_min  1.8 * 0.95
+#    set in1_max  1.8 * 1.05
+#    set in2_min  3.3 * 0.95
+#    set in2_max  3.3 * 1.05
+#    set in3_min    5 * 0.95
+#    set in3_max    5 * 1.05
+#    set in4_min   12 * 0.95
+#    set in4_max   12 * 1.05
+#    set in5_max  -12 * 0.95
+#    set in5_min  -12 * 1.05
+#    set in6_max   -5 * 0.95
+#    set in6_min   -5 * 1.05
+#    set in7_min    5 * 0.95
+#    set in7_max    5 * 1.05
+# The chip does not support in8 min/max
+
+# Temperatures
+
+# If you are lucky, the BIOS has set the proper sensor types for you.
+# If your temperature readings are completely whacky you probably
+# need to change the sensor types. Adujst and uncomment the
+# appropriate lines below.
+#
+# 2 = thermistor; 3 = thermal diode; 0 = unused
+#   set temp1_type  3
+#   set temp2_type  3
+#   set temp3_type  3
+
+# If a given sensor isn't used, you will probably want to ignore it
+# as well (see ignore statement right below).
+# The CPU sensor can be any of temp1, temp2 or temp3 - it's motherboard
+# dependent. Same for the motherboard temperature.
+
+#   label  temp1  "CPU Temp"
+#   label  temp2  "M/B Temp"
+#   ignore temp3
+
+#   set temp1_max  60
+#   set temp1_min  10
+#   set temp2_max  50
+#   set temp2_min  10
+
+# Fans
+
+# The CPU fan can be any of fan1, fan2 or fan3 - it's motherboard
+# dependent. Same for the case fan.
+
+#   label  fan1 "CPU Fan"
+#   label  fan2 "Case Fan"
+#   ignore fan3
+
+#   set fan1_min 2000
+#   set fan2_min 2000
+
+
+chip "fscpos-*"
+# Fujitsu-Siemens Poseidon chip
+
+# Temperature
+
+    label temp1       "Temp1/CPU"
+    label temp2       "Temp2/MB"
+    label temp3       "Temp3/AUX"
+
+# Fans
+
+    label fan1        "Fan1"
+    label fan2        "Fan2"
+    label fan3        "Fan3"
+
+# Voltage
+
+    label in0         "+12V"
+    label in1         "+5V"
+    label in2         "Battery"
+
+
+chip "fscscy-*"
+# Fujitsu-Siemens Scylla chip
+
+# Temperature
+
+    label temp1       "Temp1/CPU0"
+    label temp2       "Temp2/CPU1"
+    label temp3       "Temp3/MB"
+    label temp4       "Temp4/AUX"
+
+# Fans
+
+    label  fan1       "Fan1/CPU0"
+    label  fan2       "Fan2/CPU0"
+    label  fan3       "Fan3"
+    label  fan4       "Fan4"
+    label  fan5       "Fan5"
+    label  fan6       "Fan6"
+
+# Voltage
+
+    label in0         "+12V"
+    label in1         "+5V"
+    label in2         "+3.3V"
+
+
+chip "fscher-*"
+# Fujitsu-Siemens Hermes chip
+
+# Temperature
+    label temp1       "Temp1/CPU"
+    label temp2       "Temp2/MB"
+    label temp3       "Temp3/AUX"
+
+# Fans
+    label fan1        "Fan1/PS"
+    label fan2        "Fan2/CPU"
+    label fan3        "Fan3/AUX"
+
+# Voltage
+    label in0         "+12V"
+    label in1         "+5V"
+    label in2         "Battery"
+
+# Compute Voltages using mainboard dependant MRO-values
+# (see the fscher driver documentation in the kernel tree)
+#                           M    R             O               O                  M    R
+    compute in0       (@ * (49 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (49 * 33)
+    compute in1       (@ * (20 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (20 * 33)
+    compute in2       (@ * (10 * 33) / 255) + (0 / 100), (@ - (0 / 100)) * 255 / (10 * 33)
+
+
+chip "pcf8591-*"
+#
+#    values for the Philips PCF8591 chip
+#
+# Analog inputs
+
+# You may discard ch2 and ch3 if you don't use them (depends on the input
+# configuration)
+#  ignore in2
+#  ignore in3
+
+   label  in0         "Chan. 0"
+   label  in1         "Chan. 1"
+   label  in2         "Chan. 2"
+   label  in3         "Chan. 3"
+
+# The driver assumes Vref = 2.56V and Agnd = 0V. If it doesn't match
+# your hardware, you have to use compute lines. The example below is
+# correct for Vref = 5.0V and Agnd = 0V.
+#  compute in0 (@ * 500 / 256), (@ * 256 / 500)
+#  compute in1 (@ * 500 / 256), (@ * 256 / 500)
+#  compute in2 (@ * 500 / 256), (@ * 256 / 500)
+#  compute in3 (@ * 500 / 256), (@ * 256 / 500)
+
+
+chip "adm1021-*" "adm1023-*" "max1617-*" "max1617a-*" "thmc10-*" "lm84-*" "gl523sm-*" "mc1066-*"
+
+   label temp1 		"Board Temp"
+   label temp2		"CPU Temp"
+#   set temp1_min	40
+#   set temp1_max	70
+#   set temp2_min	40
+#   set temp2_max	70
+
+chip "lm83-*"
+
+   label temp1 "M/B Temp"
+   label temp2 "D1 Temp"
+   label temp3 "CPU Temp"
+   label temp4 "D3 Temp"
+
+# ignore D1 and/or D3 readings if not used
+#   ignore temp2
+#   ignore temp4
+
+# change high limits to fit your needs
+#   set temp1_max 55
+#   set temp2_max 60
+#   set temp3_max 65
+#   set temp4_max 60
+
+# change critical limit to fit your needs
+# only one limit for all four temperatures
+# should be higher than each of the high limits above
+#   set temp3_crit 85
+
+
+chip "max1619-*"
+
+   label temp1 "M/B Temp"
+   label temp2 "CPU Temp"
+
+# change high and low limits to fit your needs
+#   set temp2_min   10
+#   set temp2_max   100
+
+# change critical limit and hysteresis to fit your needs
+#   set temp2_crit       50
+#   set temp2_crit_hyst  40
+
+
+chip "lm90-*" "adm1032-*" "lm86-*" "max6657-*" "adt7461-*" "max6680-*"
+
+   label temp1 "M/B Temp"
+   label temp2 "CPU Temp"
+   label temp1_crit "M/B Crit"
+   label temp2_crit "CPU Crit"
+
+# change high and low limits to fit your needs
+#   set temp1_min 10
+#   set temp1_max 55
+#   set temp2_min 10
+#   set temp2_max 66
+
+# change critical limits to fit your needs
+# should be higher than the corresponding high limit above
+#   set temp1_crit 75
+#   set temp2_crit 85
+
+# change the hysteresis values (to critical limits) to fit your needs
+# note #1: hyst2 will be automatically set with the same delta
+# note #2: the internal register, which stores a single, relative value
+# for both channels, cannot hold values greater than 31, so the delta
+# between critical temperatures and respective absolute hysteresis can
+# never exceed this value
+#   set temp1_crit_hyst 70
+
+chip "lm99-*"
+
+   label temp1 "G/C Temp"
+   label temp2 "GPU Temp"
+   label temp1_crit "G/C Crit"
+   label temp2_crit "GPU Crit"
+
+# note #1: only the LM99 needs this; for a LM89, comment the compute line
+# out
+# note #2: there is no way for us to differentiate between a LM89 and a
+# LM99; you have to know what you have; LM99 are frequently found on
+# graphics cards, most notably nVidia ones
+   compute temp2 @+16, @-16
+
+# change high and low limits to fit your needs
+#   set temp1_min  10
+#   set temp1_max  90
+#   set temp2_min  10
+#   set temp2_max 100
+
+# change critical limits to fit your needs
+# should be higher than the corresponding high limit above
+#   set temp1_crit 100
+#   set temp2_crit 110
+
+# change the hysteresis values (to critical limits) to fit your needs
+# note #1: hyst2 will be automatically set with the same delta
+# note #2: the internal register, which stores a single, relative value
+# for both channels, cannot hold values greater than 31, so the delta
+# between critical temperatures and respective absolute hysteresis can
+# never exceed this value
+#   set temp1_crit_hyst 105
+
+
+chip "lm63-*"
+
+   label temp1       "M/B Temp"
+   label temp2       "CPU Temp"
+   label temp2_crit  "CPU Crit"
+   label fan1        "CPU Fan"
+
+# Change limits to fit your needs. Note that temp2_crit is read-only.
+#   set temp1_max        50
+#   set temp2_min        10
+#   set temp2_max        70
+#   set temp2_crit_hyst  75
+#   set fan1_min         2000
+
+
+chip "vt1211-*"
+
+    label in0 "+3.3V"
+    label in1 "+2.5V"
+    label in2 "VCore"
+    label in3 "+5V"
+    label in4 "+12V"
+    label in5 "+3.3V"
+
+    label temp1 "CPU Temp"
+    label temp2 "Int Temp"
+
+    label fan1 "Case Fan"
+    label fan2 "CPU Fan"
+
+# All voltage calculations have the form
+#    compute inX  @ * (1 + R1 / R2), @ / (1 + R1 / R2)
+#
+# The following are the resistor values as recommended by VIA
+#	Voltage		R1	R2
+#	-------		----	----
+#	VCore	 	-	-	(no scaling)
+#	 3.3		6.8k	10k
+#	 2.5		2k	10k
+#	 5.0		14k	10k
+#	12.0		47k	10k
+#
+# The VT1211 internal 3.3V (in5) is scaled by the driver and doesn't
+# need to be adjusted here. VCore doesn't need scaling at all.
+
+    compute in0  @ * (1 + 6.8 / 10),  @ / (1 + 6.8 / 10)
+    compute in1  @ * (1 +   2 / 10),  @ / (1 +   2 / 10)
+    compute in3  @ * (1 +  14 / 10),  @ / (1 +  14 / 10)
+    compute in4  @ * (1 +  47 / 10),  @ / (1 +  47 / 10)
+
+#   set in0_min 3.3 * 0.95
+#   set in0_max 3.3 * 1.05
+#   set in1_min 2.5 * 0.95
+#   set in1_max 2.5 * 1.05
+# If your vid is wrong, hardcode the CPU voltage (e.g. 1.4)
+#   set in2_min cpu0_vid * 0.97
+#   set in2_max cpu0_vid * 1.03
+#   set in3_min 5.0 * 0.95
+#   set in3_max 5.0 * 1.05
+#   set in4_min 12.0 * 0.90
+#   set in4_max 12.0 * 1.10
+    set in5_min 3.3 * 0.95
+    set in5_max 3.3 * 1.05
+
+# The temperature calculations are of the form
+#    compute tempX  (@ - Offset) / Gain, (@ * Gain) + Offset
+#
+# The following are the gain and offset values as recommended by VIA
+#	Diode Type	Gain	Offset
+#	----------	----	------
+# 	Intel CPU	0.9528	88.638
+#			0.9686	65.000	*)
+#	VIA C3 Ezra	0.9528	83.869
+#	VIA C3 Ezra-T	0.9528	73.869
+#
+# *) These are the values from the previous sensors.conf. I don't know
+# where they came from or how they got derived.
+#
+# The VT1211 internal temperature (temp2) is scaled by the driver
+# and doesn't need to be adjusted here.
+
+    compute temp1  (@ - 73.869) / 0.9528,  (@ * 0.9528) + 73.869
+
+# The thermistor calculations are of the form
+#    compute tempX  1 / (1 / 298.15 - (` Vmax / @ - 1)) / B) - 273.15, \
+#                   Vmax / (1 + (^ (B / 298.15 - B / (273.15 + @))))
+#
+# B is the thermistor beta value, Vmax is the reference voltage, '^' is the
+# exp() operator and '`' is the ln() operator.
+# Given B = 3435 and Vmax = 2.2V and assuming that the thermistor forms a
+# resistor divider with a resistor equal to the thermistor's nominal value at
+# 25 degrees C, the following compute lines can be used:
+
+    compute temp3  1 / (1 / 298.15 - (` (2.2 / @ - 1)) / 3435) - 273.15, \
+                   2.2 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
+    compute temp4  1 / (1 / 298.15 - (` (2.2 / @ - 1)) / 3435) - 273.15, \
+                   2.2 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
+    compute temp5  1 / (1 / 298.15 - (` (2.2 / @ - 1)) / 3435) - 273.15, \
+                   2.2 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
+    compute temp6  1 / (1 / 298.15 - (` (2.2 / @ - 1)) / 3435) - 273.15, \
+                   2.2 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
+    compute temp7  1 / (1 / 298.15 - (` (2.2 / @ - 1)) / 3435) - 273.15, \
+                   2.2 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
+
+#    set temp1_max_hyst 80
+#    set temp1_max      85
+#    set temp2_max_hyst 60
+#    set temp2_max      65
+#    set temp3_max_hyst 60
+#    set temp3_max      65
+#    set temp4_max_hyst 40
+#    set temp4_max      45
+
+#    set fan1_min 3000
+#    set fan2_min 3000
+
+chip "vt8231-*"
+
+    label in1 "+2.5V"
+    label in2 "VCore"
+    label in3 "+5V"
+    label in4 "+12V"
+    label in5 "+3.3V"
+
+    label temp1 "CPU Temp"
+    label temp2 "M/B Temp"
+
+# Here are the resistor values as recommended by VIA:
+#   Voltage			R1	R2
+#   VCore			no scaling
+#    2.5			2k	10k
+#    3.5 (3.3V ext.)		6.8k	10k
+#    5.0			14k	10k
+#   12.0			47k	10k
+
+#   compute in0  @ * (1 + 6.8 / 10),  @ / (1 + 6.8 / 10)
+    compute in1  @ * (1 +   2 / 10),  @ / (1 +   2 / 10)
+    compute in3  @ * (1 +  14 / 10),  @ / (1 +  14 / 10)
+    compute in4  @ * (1 +  47 / 10),  @ / (1 +  47 / 10)
+# in5 is scaled internally so scaling is done by the driver.
+
+#   set in0_min 2.5 * 0.95
+#   set in0_max 2.5 * 1.05
+#   set in1_min 2.5 * 0.95
+#   set in1_max 2.5 * 1.05
+# Replace "2.0" with your nominal CPU voltage for in2.
+#   set in2_min 2.0 * 0.95
+#   set in2_max 2.0 * 1.05
+#   set in3_min 5.0 * 0.95
+#   set in3_max 5.0 * 1.05
+#   set in4_min 12.0 * 0.95
+#   set in4_max 12.0 * 1.05
+#   set in5_min 3.3 * 0.95
+#   set in5_max 3.3 * 1.05
+
+# For Intel CPU:
+    compute temp1  (@ - 65) / 0.9686,  (@ * 0.9686) + 65
+
+# For VIA EPIA CPU (provided by Roger Lucas):
+#   compute temp1  (@ - 45) / 0.7809,  (@ * 0.7809) + 45
+
+# Thermistor calculations
+# 3435 is the thermistor beta, 2.2 is the reference voltage.
+# '^' is the e**x operator; '`' is the ln(x) operator
+# This assumes that the thermistor forms a resistor divider with a resistor
+# equal to its nominal value at 25 degrees C.
+
+    compute temp2  1 / (1 / 298.15 - (` (2.2 / @ - 1)) / 3435) - 273.15, \
+                   2.2 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
+    compute temp3  1 / (1 / 298.15 - (` (2.2 / @ - 1)) / 3435) - 273.15, \
+                   2.2 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
+
+#    set temp1_max_hyst 60
+#    set temp1_max      65
+#    set temp2_max_hyst 40
+#    set temp2_max      45
+
+#    set fan1_min 3000
+#    set fan2_min 3000
+
+
+chip "smsc47m1-*"
+
+# SMSC LPC47M10x, LPC47M13x, LPC47M14x and LPC47B27x chips
+
+#    set fan1_min 3000
+#    set fan2_min 3000
+
+chip "smsc47m192-*"
+
+# Temperature and voltage input from SMSC LPC47M192 and LPC47M997 chips
+# This example works on a Gigabyte K8U motherboard
+# Voltages are scaled internally, no computations needed
+
+    label in0 "+2.5V"
+#    set in0_min  2.5 * 0.95
+#    set in0_max  2.5 * 1.05
+
+    label in1 "VCore"
+#    set in1_min  cpu0_vid * 0.95
+#    set in1_max  cpu0_vid * 1.05
+
+    label in2 "+3.3V"
+#    set in2_min  3.3 * 0.95
+#    set in2_max  3.3 * 1.05
+
+    label in3 "+5V"
+#    set in3_min  5.0 * 0.95
+#    set in3_max  5.0 * 1.05
+
+    label in4 "+12V"
+#    set in4_min  12.0 * 0.95
+#    set in4_max  12.0 * 1.05
+
+    label in5 "VCC"
+#    set in5_min  3.3 * 0.95
+#    set in5_max  3.3 * 1.05
+
+    label in6 "+1.5V"
+#    set in6_min  1.5 * 0.95
+#    set in6_max  1.5 * 1.05
+#   ignore in6
+
+    label in7 "+1.8V"
+#    set in7_min  1.8 * 0.95
+#    set in7_max  1.8 * 1.05
+#   Haven't yet heard from any board that has 1.8V connected, so
+#   this might be more appropriate:
+#   ignore in7
+
+    label temp1 "Chip Temp"
+#    set temp1_min   0
+#    set temp1_max   60
+
+    label temp2 "CPU Temp"
+#    set temp2_min   0
+#    set temp2_max   60
+
+    label temp3 "Sys Temp"
+#    set temp3_min   0
+#    set temp3_max   60
+
+#
+# This example was tested vs. Asus P4S333
+#
+chip "asb100-*"
+
+    label in0 "VCore 1"
+    #set in0_min cpu0_vid * 0.95
+    #set in0_max cpu0_vid * 1.05
+
+    label in1 "VCore 2"
+    ignore in1
+    #set in1_min cpu0_vid * 0.95
+    #set in1_max cpu0_vid * 1.05
+
+    label in2 "+3.3V"
+    #set in2_min 3.3 * 0.95
+    #set in2_max 3.3 * 1.05
+
+    label in3 "+5V"
+    compute in3 1.68 * @ ,  @ / 1.68
+    #set in3_min 5.0 * 0.95
+    #set in3_max 5.0 * 1.05
+
+    label in4 "+12V"
+    compute in4 3.8 * @ , @ / 3.8
+    #set in4_min 12  * 0.90
+    #set in4_max 12  * 1.10
+
+    label in5 "-12V (reserved)"
+    #ignore in5
+    compute in5 -@ * 3.97 ,  -@ / 3.97
+    #set in5_max -12 * 0.90
+    #set in5_min -12 * 1.10
+
+    label in6 "-5V (reserved)"
+    #ignore in6
+    compute in6 -@ * 1.666 , -@ / 1.666
+    #set in6_max -5  * 0.95
+    #set in6_min -5  * 1.05
+
+    label temp1 "M/B Temp"
+    #set temp1_max      45
+    #set temp1_max_hyst 40
+
+    label temp2 "CPU Temp (Intel)"
+    #ignore temp2
+    #set temp2_max      60
+    #set temp2_max_hyst 50
+
+    # PWRTMP connector on P4S333, for external sensor
+    label temp3 "Power Temp"
+    #ignore temp3
+    #set temp3_max      45
+    #set temp3_max_hyst 40
+
+
+    # Used for Athlon diode, ignore for P4S333
+    label temp4 "CPU Temp (AMD)"
+    #set temp4_max      60
+    #set temp4_max_hyst 50
+    #ignore temp4
+
+    label fan1 "CPU Fan"
+    #set fan1_div 4
+    #set fan1_min 2000
+
+    label fan2 "Chassis Fan"
+    #set fan2_div 2
+    #set fan2_min 4000
+
+    label fan3 "Power Fan"
+    #set fan3_div 2
+    #set fan3_min 4000
+
+#
+# Sample configuration for the Intel S845WD1-E
+# courtesy of Marcus Schopen
+#
+chip "lm85c-*" "adm1027-*" "adt7463-*" "lm85-*" "lm85b-*"
+
+# Voltage inputs
+# Depending on the hardware setup, the ADT7463 may not have in4.
+   label in0   "V1.5"      # AGP on Intel S845WD1-E
+   label in1   "VCore"
+   label in2   "V3.3"
+   label in3   "V5"
+   label in4   "V12"
+
+# Temperature inputs
+   label temp1  "CPU Temp"
+   label temp2  "Board Temp"
+   label temp3  "Remote Temp"
+
+# Fan inputs
+   label fan1   "CPU_Fan"
+#   label fan2   "Fan2"
+#   label fan3   "Fan3"
+#   label fan4   "Fan4"
+
+# Voltage scaling is done on-chip.  No 'compute' directive
+# should be necessary.  If in0 has external scaling set
+# it here.
+
+#   compute in0  @ * 2.5,   @ / 2.5
+
+# Adjust fans speeds for actual pulses per rev
+#   compute fan1  @ * 2,  @ / 2    # 1 pulse per rev
+#   compute fan2  @ / 2,  @ * 2    # 4 pulse per rev
+
+# Ignore fans you (or your motherboard) don't have
+#   ignore fan2
+#   ignore fan3
+#   ignore fan4
+
+# Set voltage limits
+#   set in0_min  1.5 * 0.95
+#   set in0_max  1.5 * 1.05
+#   set in1_min  cpu0_vid * 0.95
+#   set in1_max  cpu0_vid * 1.05
+#   set in2_min  3.3 * 0.95
+#   set in2_max  3.3 * 1.05
+#   set in3_min  5.0 * 0.95
+#   set in3_max  5.0 * 1.05
+#   set in4_min   12 * 0.95
+#   set in4_max   12 * 1.05
+
+# Set Fan limits
+#   set fan1_min 4000
+
+# Set Temp Limits
+#   set temp1_min 10
+#   set temp1_max 50
+#   set temp2_min 10
+#   set temp2_max 35
+#   set temp3_min 10
+#   set temp3_max 35
+
+chip "pc87366-*"
+
+# Voltage inputs
+
+   label in7   "Vsb"
+   label in8   "Vdd"
+   label in9   "Vbat"
+   label in10  "AVdd"
+
+   compute in7   @*2, @/2
+   compute in8   @*2, @/2
+   compute in10  @*2, @/2
+
+# These are the operating conditions as recommended by National
+# Semiconductor
+   set in7_min   3.0
+   set in7_max   3.6
+   set in8_min   3.0
+   set in8_max   3.6
+#   set in9_min   2.4
+#   set in9_max   3.6
+   set in10_min  3.0
+   set in10_max  3.6
+
+# Temperature inputs
+
+   label temp1       "CPU0 Temp"
+   label temp1_crit  "CPU0 Crit"
+   label temp2       "CPU1 Temp"
+   label temp2_crit  "CPU1 Crit"
+   label temp3       "S-IO Temp"
+   label temp3_crit  "S-IO Crit"
+
+#   set temp1_min    0
+#   set temp1_max   70
+#   set temp1_crit  85
+#   set temp2_min    0
+#   set temp2_max   70
+#   set temp2_crit  85
+#   set temp3_min    0
+#   set temp3_max   70
+#   set temp3_crit  85
+
+# Thermistors
+# On some systems, thermistors are used instead of thermal diodes.
+# Note that these are the same pins used differently, so you really
+# can't have them all on a given system.
+#   ignore temp1
+#   ignore temp2
+   ignore temp4
+   ignore temp5
+   ignore temp6
+
+# 3435 is the thermistor beta.
+# This assumes that the thermistor forms a resistor divider with a resistor
+# equal to its nominal value at 25 degres Celsius. If not, change the values.
+# We also assume that you have a working in10 (which is forcibly enabled by
+# default). If not, use 3.3 instead, but you lose accuracy.
+
+   compute temp4  3435 / (` (1 / (1 - @ / in10) - 1) + 3435 / 298.15) - 273.15, \
+                  in10 * (1 - 1 / (1 + (^ (3435 / (273.15 + @) - 3435 / 298.15))))
+   compute temp5  3435 / (` (1 / (1 - @ / in10) - 1) + 3435 / 298.15) - 273.15, \
+                  in10 * (1 - 1 / (1 + (^ (3435 / (273.15 + @) - 3435 / 298.15))))
+   compute temp6  3435 / (` (1 / (1 - @ / in10) - 1) + 3435 / 298.15) - 273.15, \
+                  in10 * (1 - 1 / (1 + (^ (3435 / (273.15 + @) - 3435 / 298.15))))
+
+#   set temp4_min    0
+#   set temp4_max   70
+#   set temp4_crit  85
+#   set temp5_min    0
+#   set temp5_max   70
+#   set temp5_crit  85
+#   set temp6_min    0
+#   set temp6_max   70
+#   set temp6_crit  85
+
+# Fan inputs
+
+# Ignore fans you don't have
+#   ignore fan2
+#   ignore fan3
+
+#   set fan1_min 2000
+#   set fan2_min 2000
+#   set fan3_min 2000
+
+
+chip "adm1030-*"
+
+   label temp1 "SYS Temp"
+   label temp2 "CPU Temp"
+   label temp1_crit "SYS Crit"
+   label temp2_crit "CPU Crit"
+
+#   set temp1_max  60
+#   set temp2_max  70
+#   set temp1_crit 85
+#   set temp2_crit 85
+
+   label fan1 "CPU Fan"
+
+#   set fan1_min 2000
+
+
+chip "adm1031-*"
+
+   label temp1 "SYS Temp"
+   label temp2 "CPU Temp"
+   label temp3 "AUX Temp"
+   label temp1_crit "SYS Crit"
+   label temp2_crit "CPU Crit"
+   label temp3_crit "AUX Crit"
+
+#   set temp1_max  60
+#   set temp2_max  70
+#   set temp3_max  70
+#   set temp1_crit 85
+#   set temp2_crit 85
+#   set temp3_crit 85
+
+   label fan1 "CPU Fan"
+   label fan2 "Case Fan"
+
+#   set fan1_min 2000
+#   set fan2_min 2000
+
+
+chip "w83l785ts-*"
+
+   label temp1 "CPU Diode"
+
+chip "lm92-*"
+
+   label temp1 "CPU Temp"
+
+# Change limits as you see fit
+#   set temp1_min 14
+#   set temp1_max 60
+#   set temp1_crit 72
+# Hysteresis is computed from critical limit
+# The same relative hysteresis is used for all of low, high
+# and critical limits.
+#   set temp1_crit_hyst 70
+
+
+# Winbond W83627EHF configuration originally contributed by Leon Moonen
+# This is for an Asus P5P800, voltages for A8V-E SE.
+chip "w83627ehf-*" "w83627dhg-*"
+
+    label in0 "VCore"
+    label in2 "AVCC"
+    label in3 "3VCC"
+    label in7 "VSB"
+    label in8 "VBAT"
+
+# +12V is in1 and +5V is in6 as recommended by datasheet
+    compute in1 @*(1+(56/10)),  @/(1+(56/10))
+    compute in6 @*(1+(22/10)),  @/(1+(22/10))
+#    set in1_min   12.0*0.9
+#    set in1_max   12.0*1.1
+#    set in6_min   5.0*0.95
+#    set in6_max   5.0*1.05
+
+# Set the 3.3V
+#    set in2_min   3.3*0.95
+#    set in2_max   3.3*1.05
+#    set in3_min   3.3*0.95
+#    set in3_max   3.3*1.05
+#    set in7_min   3.3*0.95
+#    set in7_max   3.3*1.05
+#    set in8_min   3.3*0.95
+#    set in8_max   3.3*1.05
+
+# Fans
+   label fan1      "Case Fan"
+   label fan2      "CPU Fan"
+   label fan3      "Aux Fan"
+#  ignore fan3
+#  ignore fan4
+#  set fan1_min    1200
+#  set fan2_min    1700
+
+# Temperatures
+   label temp1     "Sys Temp"
+   label temp2     "CPU Temp"
+   label temp3     "AUX Temp"
+
+#  ignore temp3
+#  set temp1_max       45
+#  set temp1_max_hyst  40
+#  set temp2_max       45
+#  set temp2_max_hyst  40
+
+
+# Fintek F71805F/FG configuration
+# This is the recommended wiring and resistor values from the F71805F/FG
+# datasheet. Your motherboard manufacturer may or may not have followed
+# these.
+chip "f71805f-*"
+# Voltages
+   label in0 "+3.3V"
+   label in1 "Vtt1.2V"
+   label in2 "Vram"
+   label in3 "Vchip"
+   label in4 "+5V"
+   label in5 "+12V"
+   label in6 "Vcc1.5V"
+   label in7 "Vcore"
+   label in8 "5VSB"
+
+   # in0 is scaled internally
+   compute in2  @*(1+100/100), @/(1+100/100)
+   compute in3  @*(1+100/47),  @/(1+100/47)
+   compute in4  @*(1+200/47),  @/(1+200/47)
+   compute in5  @*(1+200/20),  @/(1+200/20)
+   compute in8  @*(1+200/47),  @/(1+200/47)
+
+   # in0 is the chip's own VCC.
+   set in0_min  3.0
+   set in0_max  3.6
+
+   #set in1_min  1.2 * 0.95
+   #set in1_max  1.2 * 1.05
+   #set in2_min  2.5 * 0.95
+   #set in2_max  2.6 * 1.05
+   #set in3_min  3.3 * 0.95
+   #set in3_max  3.3 * 1.05
+   #set in4_min  5.0 * 0.95
+   #set in4_max  5.0 * 1.05
+   #set in5_min 12.0 * 0.95
+   #set in5_max 12.0 * 1.05
+   #set in6_min  1.5 * 0.95
+   #set in6_max  1.5 * 1.05
+   # in7 nominal value depends on the CPU model
+   #set in7_min  1.4 * 0.95
+   #set in7_max  1.4 * 1.05
+   #set in8_min  5.0 * 0.95
+   #set in8_max  5.0 * 1.05
+
+# Fans
+   label fan1 "CPU Fan"
+   label fan2 "Sys Fan"
+   label fan3 "Aux Fan"
+
+   #set fan1_min 2100
+   #set fan2_min 1400
+   #set fan3_min 1400
+
+# Temperatures
+   label temp1 "CPU Temp"
+   label temp2 "Sys Temp"
+   label temp3 "Aux Temp"
+
+   #set temp1_max       60
+   #set temp1_max_hyst  58
+   #set temp2_max       50
+   #set temp2_max_hyst  48
+   #set temp3_max       50
+   #set temp3_max_hyst  48
+
+
+# Abit Uguru sensor part configuration.
+# The Abit Uguru is relativly straight forward to configure.
+# label statements:
+# The voltage (in) temp and fan sensors are usualy in the same order as listed
+# in the BIOS, but not always!
+# compute statements:
+# The temp and fan sensors don't need any compute statements. Most voltage
+# inputs are directly connected to the IC and thus don't need an compute line
+# because the 0-3494 mV voltage given by the kernel driver is correct. The sen-
+# sors for higher voltages however are connect through a divider and measure
+# ranges of: 0-4361mV, 0-6248mV or 0-14510mV. Thus the measured voltages must
+# be multiplied by resp. 1.248, 1.788 or 4.153. 3.3 volt sources use the 1.248
+# mutiplier, 5 volt the 1.788 and 12 volt the 4.153.
+# set statements:
+# The Abit BIOS sets reasonable treshholds and allows changing them, thus
+# set statements may be ommited. The abituguru kernel driver does support
+# them if you want to add them.
+#
+# The configuration below is for the Kv8Pro and AV8 this is the default as this
+# driver is developed and tested on a Kv8Pro.
+# Configurations for many other Abit boards can be found at:
+# http://www.lm-sensors.org/trac/wiki/Configurations/Abit
+# If your motherboard isn't listed there and you create a configuration for it
+# please add it there.
+
+chip "abituguru-*"
+
+   label in0 "CPU Core Voltage"
+   label in1 "DDR Voltage"
+   label in2 "DDR VTT Voltage"
+   label in3 "NB Voltage"
+   label in4 "SB Voltage"
+   label in5 "HyperTransport Voltage"
+   label in6 "AGP VDDQ Voltage"
+   label in7 "ATX +5V"
+   compute in7 @*1.788 , @/1.788
+   label in8 "ATX +3.3V"
+   compute in8 @*1.248 , @/1.248
+   label in9 "Standby Voltage (+5V)"
+   compute in9 @*1.788 , @/1.788
+   label in10 "3VDual Voltage"
+   compute in10 @*1.248 , @/1.248
+
+   label temp1 "CPU Temperature"
+   label temp2 "SYS Temperature"
+   label temp3 "PWM Temperature"
+   ignore temp4
+   ignore temp5
+   ignore temp6
+   ignore temp7
+
+   label fan1 "CPU FAN Speed"
+   label fan2 "NB FAN Speed"
+   label fan3 "SYS FAN Speed"
+   label fan4 "AUX1 FAN Speed"
+   label fan5 "AUX2 FAN Speed"
+   ignore fan6
+
+chip "k8temp-*"
+
+   label temp1 "Core0 Temp"
+   label temp2 "Core0 Temp"
+   label temp3 "Core1 Temp"
+   label temp4 "Core1 Temp"
+
+
+#
+# Sample configuration for the SMSC DME1737 and ASUS A8000
+#
+chip "dme1737-*"
+
+# Voltage inputs
+   label in0   "V5stby"
+   label in1   "Vccp"
+   label in2   "V3.3"
+   label in3   "V5"
+   label in4   "V12"
+   label in5   "V3.3stby"
+   label in6   "Vbat"
+
+# Temperature inputs
+   label temp1   "RD1 Temp"
+   label temp2   "Int Temp"
+   label temp3   "CPU Temp"
+
+# Fan inputs
+   label fan1   "CPU_Fan"
+   label fan2   "Fan2"
+   label fan3   "Fan3"
+   label fan4   "Fan4"
+   label fan5   "Fan5"
+   label fan6   "Fan6"
+
+# Set voltage limits
+#   set in0_min   5.0 * 0.95
+#   set in0_max   5.0 * 1.05
+#   set in1_min   1.4 * 0.95
+#   set in1_max   1.4 * 1.05
+#   set in2_min   3.3 * 0.95
+#   set in2_max   3.3 * 1.05
+#   set in3_min   5.0 * 0.95
+#   set in3_max   5.0 * 1.05
+#   set in4_min  12.0 * 0.95
+#   set in4_max  12.0 * 1.05
+#   set in5_min   3.3 * 0.95
+#   set in5_max   3.3 * 1.05
+#   set in6_min   3.0 * 0.95
+#   set in6_max   3.0 * 1.05
+
+# Set Temp Limits
+#   set temp1_min 10
+#   set temp1_max 75
+#   set temp2_min 10
+#   set temp2_max 75
+#   set temp3_min 10
+#   set temp3_max 75
+
+# Set Fan limits
+#   set fan1_min 1000
+#   set fan2_min 1000
+#   set fan3_min 1000
+#   set fan4_min 1000
+#   set fan5_min 1000
+#   set fan6_min 1000
+
+
+#
+# sample configuration for the Fintek f71882fg and f71883fg
+#
+# The configuration below is for the Epox EP-9U1697 GLI board, which has a
+# Fintek f71883fg relabeled as Epox ep1308, this is the default config as this
+# driver is developed and tested on an Epox EP-9U1697 GLI board.
+#
+# Premade configurations for other boards can be found at:
+# http://www.lm-sensors.org/trac/wiki/Configurations/
+# If your motherboard isn't listed there and you create a configuration for it
+# please add it there.
+#
+chip "f71882fg-*"
+
+# Temperature
+    label temp1       "CPU"
+    label temp2       "System"
+    ignore temp3
+
+# Fans
+    label fan1        "CPU"
+    label fan2        "System"
+    label fan3        "Power"
+    label fan4        "Aux"
+
+# Voltage
+    label in0         "3.3V"
+    label in1         "Vcore"
+    label in2         "Vdimm"
+    label in3         "Vchip"
+    label in4         "+5V"
+    label in5         "12V"
+    label in6         "5VSB"
+    label in7         "3VSB"
+    label in8         "Battery"
+
+# never change the in0, in7 and in8 compute, these are hardwired in the chip!
+    compute in0       (@ * 2), (@ / 2)
+    compute in2       (@ * 2), (@ / 2)
+    compute in3       (@ * 2), (@ / 2)
+    compute in4       (@ * 5.25), (@ / 5.25)
+    compute in5       (@ * 12.83), (@ / 12.83)
+    compute in6       (@ * 5.25), (@ / 5.25)
+    compute in7       (@ * 2), (@ / 2)
+    compute in8       (@ * 2), (@ / 2)
+
+
+chip "adm1022-*" "thmc50-*"
+
+   label temp1 "M/B Temp"
+   # Single CPU setup
+   label temp2 "CPU Temp"
+
+   # Dual CPU setup (ADM1022 only)
+   #label temp2 "CPU0 Temp"
+   #label temp3 "CPU1 Temp"
Index: /lm-sensors/tags/V3-0-0-RC2/etc/Module.mk
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/etc/Module.mk	(revision 4893)
+++ /lm-sensors/tags/V3-0-0-RC2/etc/Module.mk	(revision 4893)
@@ -0,0 +1,44 @@
+#  Module.mk - Makefile for a Linux module for reading sensor data.
+#  Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Note that MODULE_DIR (the directory in which this file resides) is a
+# 'simply expanded variable'. That means that its value is substituted
+# verbatim in the rules, until it is redefined. 
+MODULE_DIR := etc
+
+ETCTARGET := $(MODULE_DIR)/sensors.conf.eg
+ETCINSTALL := $(ETCDIR)/sensors.conf
+
+
+# No all rule
+
+install-etc:
+	$(MKDIR) $(DESTDIR)$(ETCDIR)
+	if [ ! -e $(DESTDIR)$(ETCINSTALL) ] ; then \
+	  $(INSTALL) -m 644 $(ETCTARGET) $(DESTDIR)$(ETCINSTALL); \
+	fi
+	$(MKDIR) $(DESTDIR)$(BINDIR)
+	$(INSTALL) -m 755 $(MODULE_DIR)/sensors-conf-convert $(DESTDIR)$(BINDIR)
+
+user_install :: install-etc
+
+uninstall-etc:
+	$(RM) $(DESTDIR)$(BINDIR)/sensors-conf-convert
+
+user_uninstall :: uninstall-etc
+
+# No clean rule
Index: /lm-sensors/tags/V3-0-0-RC2/etc/sensors-conf-convert
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/etc/sensors-conf-convert	(revision 4935)
+++ /lm-sensors/tags/V3-0-0-RC2/etc/sensors-conf-convert	(revision 4935)
@@ -0,0 +1,482 @@
+#!/usr/bin/perl -w -pi.old
+
+# Convert a sensors.conf file from the old (Linux 2.4, lm-sensors 2)
+# symbol names to the new (Linux 2.6, lm-sensors 3) symbol names.
+#
+# Copyright (C) 2007  Jean Delvare <khali@linux-fr.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# Implemented conversions:
+# * The "algorithm name" part of bus statements is removed.
+# * Bus statements for the ISA bus are removed.
+# * Chip names containing dashes are removed.
+# * Label, ignore, set and compute statements referencing features
+#   which are not part of the new interface are removed.
+# * Label, ignore, set and compute statements referencing features
+#   which have been renamed are updated. This includes both general
+#   feature name changes and chip-specific feature name changes.
+#
+# Note that we have to look at the commented out lines too, so that
+# the user doesn't have a bad surprise when uncommenting them.
+
+use strict;
+use vars qw($debug $chip %trans @delete %chip_trans %chip_delete);
+
+BEGIN
+{
+	$debug = 0;
+
+	%trans = (
+		qr/\bvid\b/			=> sub { "cpu0_vid" },
+		qr/\bremote_temp\b/		=> sub { "temp2" },
+		qr/\bremote_temp_hyst\b/	=> sub { "temp2_max_hyst" },
+		qr/\bremote_temp_low\b/		=> sub { "temp2_min" },
+		qr/\bremote_temp_over\b/	=> sub { "temp2_max" },
+		qr/\btemp\b/			=> sub { "temp1" },
+		qr/\btemp_hyst\b/		=> sub { "temp1_max_hyst" },
+		qr/\btemp_low\b/		=> sub { "temp1_min" },
+		qr/\btemp_over\b/		=> sub { "temp1_max" },
+		qr/\btemp_high\b/		=> sub { "temp1_max" },
+		qr/\btemp_crit\b/		=> sub { "temp1_crit" },
+
+		qr/\bvin(\d+)_max\b/		=> sub { "in$1_max" },
+		qr/\bvin(\d+)_min\b/		=> sub { "in$1_min" },
+		qr/\bvin(\d+)\b/		=> sub { "in$1" },
+		qr/\btemp(\d+)_over\b/		=> sub { "temp$1_max" },
+		qr/\btemp(\d+)_hyst\b/		=> sub { "temp$1_max_hyst" },
+		qr/\btemp(\d+)_high\b/		=> sub { "temp$1_max" },
+		qr/\btemp(\d+)_low\b/		=> sub { "temp$1_min" },
+		qr/\bsensor(\d+)\b/		=> sub { "temp$1_type" },
+	);
+
+	@delete = (
+		qr/\balarms\b/,
+		qr/\bbeeps\b/,
+		qr/\bpwm\d*\b/,
+		qr/\bpwm\d+_enable\b/,
+		qr/\b(in|temp|fan)\d+_(state|status)\b/,
+		qr/\banalog_out\b/,
+		qr/\balarms_(in|temp|fan)\b/,
+	);
+
+	%chip_trans = (
+		"gl518sm" => {
+			qr/\bvdd\b/			=> sub { "in0" },
+			qr/\bvdd_min\b/			=> sub { "in0_min" },
+			qr/\bvdd_max\b/			=> sub { "in0_max" },
+		},
+		"gl520sm" => {
+			qr/\bvdd\b/			=> sub { "in0" },
+			qr/\bvdd_min\b/			=> sub { "in0_min" },
+			qr/\bvdd_max\b/			=> sub { "in0_max" },
+		},
+		"lm80" => {
+			qr/\btemp_hot_hyst\b/		=> sub { "temp1_max_hyst" },
+			qr/\btemp_hot_max\b/		=> sub { "temp1_max" },
+			qr/\btemp_os_hyst\b/		=> sub { "temp1_crit_hyst" },
+			qr/\btemp_os_max\b/		=> sub { "temp1_crit" },
+		},
+		"lm83" => {
+			qr/\btcrit\b/			=> sub { "temp3_crit" },
+		},
+		"lm90" => {
+			qr/\btcrit(\d)\b/		=> sub { "temp$1_crit" },
+			qr/\bhyst(\d)\b/		=> sub { "temp$1_crit_hyst" },
+		},
+		"adm1032" => {
+			qr/\btcrit(\d)\b/		=> sub { "temp$1_crit" },
+			qr/\bhyst(\d)\b/		=> sub { "temp$1_crit_hyst" },
+		},
+		"lm86" => {
+			qr/\btcrit(\d)\b/		=> sub { "temp$1_crit" },
+			qr/\bhyst(\d)\b/		=> sub { "temp$1_crit_hyst" },
+		},
+		"lm99" => {
+			qr/\btcrit(\d)\b/		=> sub { "temp$1_crit" },
+			qr/\bhyst(\d)\b/		=> sub { "temp$1_crit_hyst" },
+		},
+		"adt7461" => {
+			qr/\btcrit(\d)\b/		=> sub { "temp$1_crit" },
+			qr/\bhyst(\d)\b/		=> sub { "temp$1_crit_hyst" },
+		},
+		"max6657" => {
+			qr/\btcrit(\d)\b/		=> sub { "temp$1_crit" },
+			qr/\bhyst(\d)\b/		=> sub { "temp$1_crit_hyst" },
+		},
+		"max6680" => {
+			qr/\btcrit(\d)\b/		=> sub { "temp$1_crit" },
+			qr/\bhyst(\d)\b/		=> sub { "temp$1_crit_hyst" },
+		},
+		"lm93" => {
+			qr/\bvid([12])\b/			=> sub { "cpu".($1-1)."_vid" },
+		},
+		"adm9240" => {
+			qr/"2\.5V(|_min|_max)"/		=> sub { "in0$1" },
+			qr/\bVccp1(|_min|_max)\b/	=> sub { "in1$1" },
+			qr/"3\.3V(|_min|_max)"/		=> sub { "in2$1" },
+			qr/"5V(|_min|_max)"/		=> sub { "in3$1" },
+			qr/"12V(|_min|_max)"/		=> sub { "in4$1" },
+			qr/\bVccp2(|_min|_max)\b/	=> sub { "in5$1" },
+		},
+		"lm81" => {
+			qr/"2\.5V(|_min|_max)"/		=> sub { "in0$1" },
+			qr/\bVccp1(|_min|_max)\b/	=> sub { "in1$1" },
+			qr/"3\.3V(|_min|_max)"/		=> sub { "in2$1" },
+			qr/"5V(|_min|_max)"/		=> sub { "in3$1" },
+			qr/"12V(|_min|_max)"/		=> sub { "in4$1" },
+			qr/\bVccp2(|_min|_max)\b/	=> sub { "in5$1" },
+		},
+		"ds1780" => {
+			qr/"2\.5V(|_min|_max)"/		=> sub { "in0$1" },
+			qr/\bVccp1(|_min|_max)\b/	=> sub { "in1$1" },
+			qr/"3\.3V(|_min|_max)"/		=> sub { "in2$1" },
+			qr/"5V(|_min|_max)"/		=> sub { "in3$1" },
+			qr/"12V(|_min|_max)"/		=> sub { "in4$1" },
+			qr/\bVccp2(|_min|_max)\b/	=> sub { "in5$1" },
+		},
+		"adm1024" => {
+			qr/"2\.5V(|_min|_max)"/		=> sub { "in0$1" },
+			qr/\bVccp1(|_min|_max)\b/	=> sub { "in1$1" },
+			qr/"3\.3V(|_min|_max)"/		=> sub { "in2$1" },
+			qr/"5V(|_min|_max)"/		=> sub { "in3$1" },
+			qr/"12V(|_min|_max)"/		=> sub { "in4$1" },
+			qr/\bVccp2(|_min|_max)\b/	=> sub { "in5$1" },
+			qr/\btemp_hyst\b/		=> sub { "temp1_min" },
+			qr/\btemp(\d)\b/		=> sub { "temp".($1+1) },
+			qr/\btemp(\d)_hyst\b/		=> sub { "temp".($1+1)."_min" },
+			qr/\btemp(\d)_over\b/		=> sub { "temp".($1+1)."_max" },
+		},
+		"maxilife" => {
+			qr/\bvid(\d)(|_min|_max)\b/	=> sub { "in".($1-1).$2 },
+		},
+		"thmc50" => {
+			qr/\btemp_hyst\b/		=> sub { "temp1_min" },
+			qr/\bremote_temp_hyst\b/	=> sub { "temp2_min" },
+			qr/\bremote_temp2\b/		=> sub { "temp3" },
+			qr/\bremote_temp2_hyst\b/	=> sub { "temp3_min" },
+			qr/\bremote_temp2_over\b/	=> sub { "temp3_max" },
+		},
+		"adm1022" => {
+			qr/\btemp_hyst\b/		=> sub { "temp1_min" },
+			qr/\bremote_temp_hyst\b/	=> sub { "temp2_min" },
+			qr/\bremote_temp2\b/		=> sub { "temp3" },
+			qr/\bremote_temp2_hyst\b/	=> sub { "temp3_min" },
+			qr/\bremote_temp2_over\b/	=> sub { "temp3_max" },
+		},
+		"adm1026" => {
+			qr/\bfan(\d)(|_div|_min)\b/	=> sub { "fan".($1+1).$2 },
+			qr/\btemp(\d)_therm\b/		=> sub { "temp$1_crit" },
+		},
+		"via686a" => {
+			qr/"2\.0V"/			=> sub { "in0" },
+			qr/"2\.5V"/			=> sub { "in1" },
+			qr/"3\.3V"/			=> sub { "in2" },
+			qr/"5\.0V"/			=> sub { "in3" },
+			qr/"12V"/			=> sub { "in4" },
+		},
+		"lm87" => {
+			qr/"2\.5V(|_min|_max)"/		=> sub { "in0$1" },
+			qr/\bVccp1(|_min|_max)\b/	=> sub { "in1$1" },
+			qr/"3\.3V(|_min|_max)"/		=> sub { "in2$1" },
+			qr/"5V(|_min|_max)"/		=> sub { "in3$1" },
+			qr/"12V(|_min|_max)"/		=> sub { "in4$1" },
+			qr/\bVccp2(|_min|_max)\b/	=> sub { "in5$1" },
+			qr/\bAIN1(|_min|_max)\b/	=> sub { "in6$1" },
+			qr/\bAIN2(|_min|_max)\b/	=> sub { "in7$1" },
+			qr/\bCPU_Temp\b/		=> sub { "temp2" },
+		},
+		"fscpos" => {
+			qr/\bvolt12\b/			=> sub { "in0" },
+			qr/\bvolt5\b/			=> sub { "in1" },
+			qr/\bvoltbatt\b/		=> sub { "in2" },
+		},
+		"fscscy" => {
+			qr/\bvolt12\b/			=> sub { "in0" },
+			qr/\bvolt5\b/			=> sub { "in1" },
+			qr/\bvoltbatt\b/		=> sub { "in2" },
+		},
+		"pcf8591" => {
+			qr/\bch(\d)\b/			=> sub { "in$1" },
+		},
+		"smsc47m192" => {
+			qr/\btemp(\d)_input_fault\b/	=> sub { "temp$1_fault" },
+		},
+		"lm92" => {
+			qr/\btemp_hyst\b/		=> sub { "temp1_crit_hyst" },
+		},
+		"max1619" => {
+			qr/\btemp2_hyst\b/		=> sub { "temp2_crit_hyst" },
+		},
+		"lm78" => {
+			qr/\bin([56])_(min|max)\b/	=> sub { "in$1_".($2 eq "max" ? "min" : "max") },
+		},
+		"lm79" => {
+			qr/\bin([56])_(min|max)\b/	=> sub { "in$1_".($2 eq "max" ? "min" : "max") },
+		},
+		"w83781d" => {
+			qr/\bin([56])_(min|max)\b/	=> sub { "in$1_".($2 eq "max" ? "min" : "max") },
+		},
+		"as99127f" => {
+			qr/\bin([56])_(min|max)\b/	=> sub { "in$1_".($2 eq "max" ? "min" : "max") },
+		},
+	);
+
+	%chip_delete = (
+		"adm1021" => [
+			qr/\bdie_code\b/,
+		],
+		"lm84" => [
+			qr/\bdie_code\b/,
+		],
+		"gl523" => [
+			qr/\bdie_code\b/,
+		],
+		"thmc10" => [
+			qr/\bdie_code\b/,
+		],
+		"gl518sm" => [
+			qr/\bfan1_off\b/,
+			qr/\bfan1_off_pin\b/,
+			qr/\biterate\b/,
+		],
+		"gl520sm" => [
+			qr/\bfan1_off\b/,
+			qr/\btwo_temps\b/,
+		],
+		"w83792d" => [
+			qr/\bchassis\b/,
+		],
+		"w83793" => [
+			qr/\bchassis\b/,
+		],
+		"maxilife" => [
+			qr/\bpll(|_min|_max)\b/,
+		],
+		"thmc50" => [
+			qr/\banalog output\b/,
+			qr/\binterrupts\b/,
+			qr/\binterrupt mask\b/,
+			qr/\bdie_code\b/,
+		],
+		"adm1022" => [
+			qr/\banalog output\b/,
+			qr/\binterrupts\b/,
+			qr/\binterrupt mask\b/,
+			qr/\bdie_code\b/,
+		],
+		"adm1026" => [
+			qr/\balarm_mask\b/,
+			qr/\bgpio\b/,
+			qr/\bgpio_mask\b/,
+			qr/\bafc_pwm\b/,
+			qr/\bafc_analog_out\b/,
+			qr/\btemp\d_tmin\b/,
+		],
+		"lm85" => [
+			qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/,
+			qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/,
+			qr/\bfan\d_(tach_mode|ppr)\b/,
+		],
+		"lm85b" => [
+			qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/,
+			qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/,
+			qr/\bfan\d_(tach_mode|ppr)\b/,
+		],
+		"lm85c" => [
+			qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/,
+			qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/,
+			qr/\bfan\d_(tach_mode|ppr)\b/,
+		],
+		"emc6d100" => [
+			qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/,
+			qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/,
+			qr/\bfan\d_(tach_mode|ppr)\b/,
+		],
+		"emc6d102" => [
+			qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/,
+			qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/,
+			qr/\bfan\d_(tach_mode|ppr)\b/,
+		],
+		"adm1027" => [
+			qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/,
+			qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/,
+			qr/\bfan\d_(tach_mode|ppr)\b/,
+		],
+		"adt7473" => [
+			qr/\bpwm\d_(spinup|min|freq|min_ctl|zone|spinup_ctl)\b/,
+			qr/\bzone\d_(limit|hyst|range|critical|smooth)\b/,
+			qr/\bfan\d_(tach_mode|ppr)\b/,
+		],
+		"fscpos" => [
+			qr/\brev\b/,
+			qr/\bevent\b/,
+			qr/\bcontrol\b/,
+			qr/\bfan\d_ripple\b/,
+			qr/\bwdog_(preset|state|control)\b/,
+		],
+		"fscscy" => [
+			qr/\brev\b/,
+			qr/\bevent\b/,
+			qr/\bcontrol\b/,
+			qr/\btemp\d_lim\b/,
+			qr/\bfan\d_ripple\b/,
+			qr/\bwdog_(preset|state|control)\b/,
+		],
+		"fscher" => [
+			qr/\brev\b/,
+			qr/\bevent\b/,
+			qr/\bcontrol\b/,
+			qr/\bfan\d_ripple\b/,
+			qr/\bwdog_(preset|state|control)\b/,
+		],
+		"pcf8591" => [
+			qr/\bain_conf\b/,
+			qr/\baout_enable\b/,
+			qr/\baout\b/,
+		],
+		"vt1211" => [
+			qr/\bconfig\b/,
+		],
+		"vt8231" => [
+			qr/\bconfig\b/,
+		],
+		"max6650" => [
+			qr/\bspeed\b/,
+		],
+		"max6651" => [
+			qr/\bspeed\b/,
+		],
+		"applesmc" => [
+			qr/\bfan\d_(max|safe)\b/,
+		],
+	);
+
+	if (defined $ARGV[0] && ($ARGV[0] eq '-h' || $ARGV[0] eq '--help')) {
+		print "Convert sensors.conf from lm-sensors 2 format to lm-sensors 3 format\n",
+		      "Typical usage: sensors-conf-convert /etc/sensors.conf\n";
+		exit 0;
+	}
+}
+
+if ($. == 1) {
+	print "# Converted by sensors-conf-convert on ".localtime()."\n";
+}
+
+sub substitute_line($$)
+{
+	my ($chip, $line) = @_;
+
+	# First the chip-specific ones
+	if ($chip && exists $chip_trans{$chip}) {
+		foreach my $t (keys %{$chip_trans{$chip}}) {
+			$line =~ s/$t/$chip_trans{$chip}->{$t}->()/ge;
+		}
+	}
+
+	# Then the general substitutions
+	foreach my $t (keys %trans) {
+		# Kudos to the nice folks in #perl on freenode :)
+		$line =~ s/$t/$trans{$t}->()/ge;
+	}
+
+	return $line;
+}
+
+sub delete_line($)
+{
+	my $feature = shift;
+
+	# First the general deletions
+	foreach my $t (@delete) {
+		return 1 if $feature =~ m/$t/;
+	}
+
+	# Then the chip-specific ones
+	if ($chip && exists $chip_delete{$chip}) {
+		foreach my $t (@{$chip_delete{$chip}}) {
+			return 1 if $feature =~ m/$t/;
+		}
+	}
+
+	return 0;
+}
+
+if (m/^# Converted by sensors-conf-convert/) {
+	print STDERR "WARNING: Converting an already converted file!\n";
+	print STDERR "         Result will be incorrect for some chip types.\n";
+}
+
+# Bus statements
+if (m/^([\s#]*bus\s+"?i2c-\d+"?\s+"([^"]+)")\s+"[^"]*"/) {
+	print STDERR "Processing bus statement: $2\n" if $debug;
+
+	if ($2 eq "ISA main adapter") {
+		$_ = '';	# Drop entirely 
+	} else {
+		$_ = "$1\n";	# Drop algorithm name
+	}
+}
+
+# Chip statements
+elsif (m/^[\s#]*chip\s+"([\w\d*-]+)"/) {
+	# We only remember the first chip name, assuming that all chips
+	# in a given "chip" statement need the same specific processing
+	$chip = $1;
+	$chip =~ s/-.*//;
+	undef $chip if $chip eq "*";
+
+	# Remove dashes from chip names, as this is no longer allowed
+	s/(\s+"lm78-)j-/$1/g;
+	s/(\s+"maxilife-)(cg|co|as|nba)-/$1/g;
+	# Simplify possible duplicates
+	s/("lm78-\*")(\s+"lm78-\*")+/$1/g;
+	s/("maxilife-\*")(\s+"maxilife-\*")+/$1/g;
+
+	# "*" is no longer a valid chip name
+	s/"\*"/"\*-\*"/g;
+
+	print STDERR "Processing chip section: $chip\n" if $chip and $debug;
+}
+
+# Drop references to lm78-j
+elsif (m/^\s*#+.*lm78-?j/i) {
+	s/(lm78), lm78-?j/$1/gi;
+	s/(lm78)-?j/$1/gi;
+}
+
+# Drop references to vrm
+elsif (m/^[\s#]*set\s+vrm\s/i
+    || m/^\s*#+\s*adjust this if your vid is wrong/i
+    || m/^\s*#+\s*Also, one should set vrm prior to using vid in any formula/) {
+	$_ = '';
+}
+
+# Drop references to pwm
+elsif (m/^\s*#+\s*PWM Output/i) {
+	$_ = '';
+}
+
+# Feature name substitution
+elsif (m/^[\s#]*(?:label|ignore|set|compute)\s+(\S+)\s/) {
+	if (delete_line($1)) {
+		# Delete references to features that are now gone
+		$_ = '';
+	} else {
+		# Substitute feature names
+		$_ = substitute_line($chip, $_);
+	}
+}
Index: /lm-sensors/tags/V3-0-0-RC2/version.h
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/version.h	(revision 4936)
+++ /lm-sensors/tags/V3-0-0-RC2/version.h	(revision 4936)
@@ -0,0 +1,1 @@
+#define LM_VERSION "3.0.0-rc2"
Index: /lm-sensors/tags/V3-0-0-RC2/CONTRIBUTORS
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/CONTRIBUTORS	(revision 4864)
+++ /lm-sensors/tags/V3-0-0-RC2/CONTRIBUTORS	(revision 4864)
@@ -0,0 +1,15 @@
+Here is a list of the main contributors to lm-sensors version 3.
+
+* Frodo Looijaard
+  Original author of libsensors, sensors and isadump.
+* Merlin Hughes
+  Original author of sensord.
+* Bob Schlaermann
+  Dynamic chip feature detection (a.k.a. generic chip support) in
+  libsensors and sensors.
+* Mark M. Hoffman
+  Many improvements to the libsensors configuration file scanner.
+* Jean Delvare
+  New libsensors API, and migration of sensors and sensord thereto.
+  Many optimizations in libsensors and sensors.
+  Configuration file converter.
Index: /lm-sensors/tags/V3-0-0-RC2/Makefile
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/Makefile	(revision 4877)
+++ /lm-sensors/tags/V3-0-0-RC2/Makefile	(revision 4877)
@@ -0,0 +1,267 @@
+#  Makefile - Makefile for a Linux module for reading sensor data.
+#  Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Everything you may want to change is in the top of this file. Usually, you
+# can just use the defaults, fortunately.
+
+# You need a full complement of GNU utilities to run this Makefile
+# successfully; most notably, you need GNU make, flex (>= 2.5.1)
+# and bison.
+
+# Uncomment the second line if you are a developer. This will enable many
+# additional warnings at compile-time
+#WARN := 0
+WARN := 1
+
+# Uncomment the second line if you want to get (loads of) debug information
+# at run-time.
+# Not recommended, unless you are actually debugging the code
+DEBUG := 0
+#DEBUG := 1
+
+# If you want to install at some other place then at from which you will run
+# everything, set DESTDIR to the extra prefix.
+DESTDIR :=
+
+# This is the prefix that will be used for almost all directories below.
+PREFIX := /usr/local
+
+# Your C compiler
+CC := gcc
+
+# This is the directory where sensors.conf will be installed, if no other
+# configuration file is found
+ETCDIR := /etc
+
+# You should not need to change this. It is the directory into which the
+# library files (both static and shared) will be installed.
+LIBDIR := $(PREFIX)/lib
+
+EXLDFLAGS := -Wl,-rpath,$(LIBDIR)
+
+# You should not need to change this. It is the directory into which the
+# executable program files will be installed. BINDIR for programs that are
+# also useful for normal users, SBINDIR for programs that can only be run
+# by the superuser.
+# Note that not all programs in this package are really installed;
+# some are just examples. You can always install them by hand, of
+# course.
+BINDIR := $(PREFIX)/bin
+SBINDIR := $(PREFIX)/sbin
+
+# You should not need to change this. It is the basic directory into which
+# include files will be installed. The actual directory will be 
+# $(INCLUDEDIR)/sensors for library include files.
+INCLUDEDIR := $(PREFIX)/include
+LIBINCLUDEDIR := $(INCLUDEDIR)/sensors
+
+# You should not need to change this. It is the base directory under which the
+# manual pages will be installed.
+MANDIR := $(PREFIX)/man
+
+MACHINE := $(shell uname -m)
+
+# Extra non-default programs to build; e.g., sensord
+# PROG_EXTRA := sensord
+
+# Set these to add preprocessor or compiler flags, or use
+# environment variables
+# CFLAGS :=
+# CPPFLAGS :=
+
+##################################################
+# Below this, nothing should need to be changed. #
+##################################################
+
+# Note that this is a monolithic Makefile; it calls no sub-Makefiles,
+# but instead, it compiles everything right from here. Yes, there are
+# some distinct advantages to this; see the following paper for more info:
+#   http://www.tip.net.au/~millerp/rmch/recu-make-cons-harm.html
+# Note that is still uses Makefile fragments in sub-directories; these
+# are called 'Module.mk'.
+
+# Within each Module.mk, rules and dependencies can be added to targets
+# all, install and clean. Use double colons instead of single ones
+# to do this. 
+
+# The subdirectories we need to build things in 
+SRCDIRS :=
+SRCDIRS += lib prog/detect prog/dump prog/pwm \
+           prog/sensors ${PROG_EXTRA:%=prog/%} etc
+SRCDIRS += lib/test
+
+# Some often-used commands with default options
+MKDIR := mkdir -p
+RMDIR := rmdir
+RM := rm -f
+BISON := bison
+FLEX := flex
+AR := ar
+INSTALL := install
+LN := ln -sf
+GREP := grep
+AWK := awk
+SED := sed
+
+# Determine the default compiler flags
+# Set CFLAGS or CPPFLAGS above to add your own flags to all.
+# ALLCPPFLAGS/ALLCFLAGS are common flags, plus any user-specified overrides from the environment or make command line.
+# PROGCPPFLAGS/PROGCFLAGS is to create regular object files (which are linked into executables).
+# ARCPPFLAGS/ARCFLAGS are used to create archive object files (static libraries).
+# LIBCPPFLAGS/LIBCFLAGS are for shared library objects.
+ALL_CPPFLAGS := -I.
+ALL_CFLAGS := -Wall
+
+ifeq ($(DEBUG),1)
+ALL_CPPFLAGS += -DDEBUG
+ALL_CFLAGS += -O -g
+else
+ALL_CFLAGS += -O2
+endif
+
+ifeq ($(WARN),1)
+ALL_CFLAGS += -Wstrict-prototypes -Wshadow -Wpointer-arith -Wcast-qual \
+            -Wcast-align -Wwrite-strings -Wnested-externs -Winline -W \
+            -Wmissing-prototypes -Wundef
+endif
+
+ALL_CPPFLAGS += $(CPPFLAGS)
+ALL_CFLAGS += $(CFLAGS)
+
+PROGCPPFLAGS := -DETCDIR="\"$(ETCDIR)\"" $(ALL_CPPFLAGS)
+PROGCFLAGS := $(ALL_CFLAGS)
+ARCPPFLAGS := $(ALL_CPPFLAGS)
+ARCFLAGS := $(ALL_CFLAGS)
+LIBCPPFLAGS := $(ALL_CPPFLAGS)
+LIBCFLAGS := -fpic -D_REENTRANT $(ALL_CFLAGS)
+
+.PHONY: all user clean install user_install uninstall user_uninstall
+
+# Make all the default rule
+all::
+
+# Include all makefiles for sub-modules
+INCLUDEFILES := 
+include $(patsubst %,%/Module.mk,$(SRCDIRS))
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),uninstall)
+ifneq ($(MAKECMDGOALS),user_uninstall)
+ifneq ($(MAKECMDGOALS),help)
+include $(INCLUDEFILES)
+endif
+endif
+endif
+endif
+
+# Man pages
+MANPAGES := $(LIBMAN3FILES) $(LIBMAN5FILES) $(PROGDETECTMAN8FILES) $(PROGDUMPMAN8FILES) \
+            $(PROGSENSORSMAN1FILES) $(PROGPWMMAN8FILES) prog/sensord/sensord.8
+
+user ::
+user_install::
+	@echo "*** Important notes:"
+	@echo "***  * The libsensors configuration file ($(ETCDIR)/sensors.conf) is never"
+	@echo "***    overwritten by our installation process, so that you won't lose"
+	@echo "***    your personal settings in that file. You still can get our latest"
+	@echo "***    default config file in etc/sensors.conf.eg and manually copy it to"
+	@echo "***    $(ETCDIR)/sensors.conf if you want. You will then want to edit it"
+	@echo "***    to fit your needs again."
+	@echo "***  * The format of $(ETCDIR)/sensors.conf changed with lm-sensors 3.0.0."
+	@echo "***    If you have a custom configuration file using the old format, you"
+	@echo "***    can convert it using the sensors-conf-convert script. Otherwise just"
+	@echo "***    overwrite your old configuration file with the new default one."
+all :: user
+install :: all user_install
+
+clean::
+	$(RM) lm_sensors-* lex.backup
+
+user_uninstall::
+
+uninstall :: user_uninstall
+
+help:
+	@echo 'Make targets are:'
+	@echo '  all (default): build library and userspace programs'
+	@echo '  install: install library and userspace programs'
+	@echo '  uninstall: uninstall library and userspace programs'
+	@echo '  clean: cleanup'
+
+# Generate html man pages to be copied to the lm_sensors website.
+# This uses the man2html from here
+# http://ftp.math.utah.edu/pub/sgml/
+# which works directly from the nroff source
+manhtml:
+	$(MKDIR) html
+	cp $(MANPAGES) html
+	cd html ; \
+	export LOGNAME=sensors ; \
+	export HOSTNAME=www.lm-sensors.org ; \
+	man2html *.[1-8] ; \
+	$(RM) *.[1-8]
+
+# Here, we define all implicit rules we want to use.
+
+.SUFFIXES:
+
+# We need to create dependency files. Tricky. The sed rule puts dir/file.d and
+# dir/file.c in front of the dependency file rule.
+
+
+# .ro files are used for programs (as opposed to modules)
+%.ro: %.c
+	$(CC) $(PROGCPPFLAGS) $(PROGCFLAGS) -c $< -o $@
+
+%.rd: %.c
+	$(CC) -M -MG $(PROGCPPFLAGS) $(PROGCFLAGS) $< | \
+	$(SED) -e 's@^\(.*\)\.o:@$*.rd $*.ro: Makefile '`dirname $*.rd`/Module.mk' @' > $@
+
+
+%: %.ro
+	$(CC) $(EXLDFLAGS) -o $@ $^
+
+
+# .ao files are used for static archives
+%.ao: %.c
+	$(CC) $(ARCPPFLAGS) $(ARCFLAGS) -c $< -o $@
+
+%.ad: %.c
+	$(CC) -M -MG $(ARCPPFLAGS) $(ARCFLAGS) $< | \
+	$(SED) -e 's@^\(.*\)\.o:@$*.ad $*.ao: Makefile '`dirname $*.ad`/Module.mk' @' > $@
+
+
+# .lo files are used for shared libraries
+%.lo: %.c
+	$(CC) $(LIBCPPFLAGS) $(LIBCFLAGS) -c $< -o $@
+
+%.ld: %.c
+	$(CC) -M -MG $(LIBCPPFLAGS) $(LIBCFLAGS) $< | \
+	$(SED) -e 's@^\(.*\)\.o:@$*.ld $*.lo: Makefile '`dirname $*.ld`/Module.mk' @' > $@
+
+
+# Flex and Bison
+%c: %y
+	$(BISON) -p sensors_yy -d $< -o $@
+
+ifeq ($(DEBUG),1)
+FLEX_FLAGS := -Psensors_yy -t -b -Cfe -8
+else
+FLEX_FLAGS := -Psensors_yy -t -Cfe -8
+endif
+
+%.c: %.l
+	$(FLEX) $(FLEX_FLAGS) $< > $@
Index: /lm-sensors/tags/V3-0-0-RC2/README
===================================================================
--- /lm-sensors/tags/V3-0-0-RC2/README	(revision 4931)
+++ /lm-sensors/tags/V3-0-0-RC2/README	(revision 4931)
@@ -0,0 +1,108 @@
+OVERVIEW OF THE LM-SENSORS PACKAGE
+==================================
+
+The lm-sensors package, version 3, provides user-space support for the
+hardware monitoring drivers in Linux 2.6.5 and later. For older kernel
+versions, you have to use lm-sensors version 2.
+
+The directories within this package:
+
+* doc
+  Documentation.
+* etc
+  A sample configuration file for libsensors, and a script to convert
+  lm-sensors version 2 configuration files to work with version 3.
+* lib
+  The user-space sensors support library code (libsensors).
+* prog
+  Several supporting programs. The most important ones are:
+  - sensors-detect: A program for detecting installed hardware and
+    recommending specific modules to load.
+  - sensors: A console tool to report sensor readings and set new
+    sensor limits.
+  - sensord: A daemon to watch sensor values and log problems. It
+    includes RRD support.
+
+
+INSTALLING LM-SENSORS
+---------------------
+
+See the INSTALL file.
+
+
+HARDWARE SUPPORT
+----------------
+
+To find out what hardware you have, just run 'sensors-detect' as root.
+
+Most modern mainboards incorporate some form of hardware monitoring chips.
+These chips read things like chip temperatures, fan rotation speeds and
+voltage levels. There are quite a few different chips which can be used by
+mainboard builders for approximately the same results.
+
+Laptops, on the other hand, rarely expose any hardware monitoring
+chip. They often have some BIOS and/or ACPI magic to get the CPU
+temperature value, but that's about it. For such laptops, the lm-sensors
+package is of no use (sensors-detect will not find anything), and you have
+to use acpi instead.
+
+This package doesn't contain chip-specific knowledge. It will support all
+the hardware monitoring chips your kernel has drivers for. In other words,
+if you find out that you have unsupported hardware (e.g. sensors-detect
+told you so) then it means that you need a more recent kernel, or you
+even need to wait for a new kernel driver to be written. Updating the
+lm-sensors package itself will not help.
+
+
+LIBSENSORS
+----------
+
+The kernel drivers communicate their information through the /sys
+interface. Because every motherboard is different, the drivers always
+advert the measurements at their pins. This means that the values they
+report are not always immediately relevant to you. They have to be
+labelled properly, and sometimes they must be scaled to correspond to
+real-world values.
+
+libsensors is a (shared or static) library of access functions. It
+offers a simple-to-use interface for applications to access the sensor
+chip readings and configure them as you like. It has a configuration
+file where you can put all the motherboard-specific labels and
+conversion rules. That way, all applications do not need to duplicate
+the effort and can simply link with libsensors and work out of the box.
+
+
+APPLICATIONS
+------------
+
+This package contains an example console program that reports all current
+sensors values. This program is called 'sensors'. You can use it as a
+reference implementation for more intricate programs. It also contains a
+daemon watching for sensor values, logging alarms and feeding an RRD
+database with the sensor measurements.
+
+This package does not contain a nice graphical monitor. See
+http://www.lm-sensors.org/wiki/UsefulLinks for pointers to such programs.
+
+
+OTHER INFORMATION
+-----------------
+
+The developers of this package can be reached through a mailing-list
+(see http://www.lm-sensors.org/wiki/AuthorsAndContributors). Do not hesitate
+to mail us if you have questions, suggestions, problems, want to
+contribute, or just want to report it works for you. But please try to
+read the documentation and FAQ before you ask any questions! It's all
+under doc/.
+
+The latest version of this package can always be found at:
+http://www.lm-sensors.org/wiki/Download. Pre-release versions can be
+retrieved through anonymous SVN; see doc/svn for details.
+
+This package may be distributed according to the GNU General Public
+License (GPL), as included in the file COPYING.
+
+Note that libsensors falls under the GPL, not the LGPL.  In more human
+language, that means it is FORBIDDEN to link any application to the
+library, even to the shared version, if the application itself does not
+fall under the GPL.
