]> err.no Git - linux-2.6/commitdiff
[PATCH] abituguru: New hardware monitoring driver
authorHans de Goede <j.w.r.degoede@hhs.nl>
Sun, 4 Jun 2006 18:22:24 +0000 (20:22 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 22 Jun 2006 18:10:34 +0000 (11:10 -0700)
New hardware monitoring driver for the Abit uGuru

Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Documentation/hwmon/abituguru [new file with mode: 0644]
Documentation/hwmon/abituguru-datasheet [new file with mode: 0644]
MAINTAINERS
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c [new file with mode: 0644]

diff --git a/Documentation/hwmon/abituguru b/Documentation/hwmon/abituguru
new file mode 100644 (file)
index 0000000..69cdb52
--- /dev/null
@@ -0,0 +1,59 @@
+Kernel driver abituguru
+=======================
+
+Supported chips:
+  * Abit uGuru (Hardware Monitor part only)
+    Prefix: 'abituguru'
+    Addresses scanned: ISA 0x0E0
+    Datasheet: Not available, this driver is based on reverse engineering.
+       A "Datasheet" has been written based on the reverse engineering it
+       should be available in the same dir as this file under the name
+       abituguru-datasheet.
+
+Authors:
+       Hans de Goede <j.w.r.degoede@hhs.nl>,
+       (Initial reverse engineering done by Olle Sandberg
+        <ollebull@gmail.com>)
+
+
+Module Parameters
+-----------------
+
+* force: bool          Force detection. Note this parameter only causes the
+                       detection to be skipped, if the uGuru can't be read
+                       the module initialization (insmod) will still fail.
+* fan_sensors: int     Tell the driver how many fan speed sensors there are
+                       on your motherboard. Default: 0 (autodetect).
+* pwms: int            Tell the driver how many fan speed controls (fan
+                       pwms) your motherboard has. Default: 0 (autodetect).
+* verbose: int         How verbose should the driver be? (0-3):
+                          0 normal output
+                          1 + verbose error reporting
+                          2 + sensors type probing info\n"
+                          3 + retryable error reporting
+                       Default: 2 (the driver is still in the testing phase)
+
+Notice if you need any of the first three options above please insmod the
+driver with verbose set to 3 and mail me <j.w.r.degoede@hhs.nl> the output of:
+dmesg | grep abituguru
+
+
+Description
+-----------
+
+This driver supports the hardware monitoring features of the Abit uGuru chip
+found on Abit uGuru featuring motherboards (most modern Abit motherboards).
+
+The uGuru chip in reality is a Winbond W83L950D in disguise (despite Abit
+claiming it is "a new microprocessor designed by the ABIT Engineers").
+Unfortunatly this doesn't help since the W83L950D is a generic
+microcontroller with a custom Abit application running on it.
+
+Despite Abit not releasing any information regarding the uGuru, Olle
+Sandberg <ollebull@gmail.com> has managed to reverse engineer the sensor part
+of the uGuru. Without his work this driver would not have been possible.
+
+Known Issues
+------------
+
+The voltage and frequency control parts of the Abit uGuru are not supported.
diff --git a/Documentation/hwmon/abituguru-datasheet b/Documentation/hwmon/abituguru-datasheet
new file mode 100644 (file)
index 0000000..aef5a9b
--- /dev/null
@@ -0,0 +1,312 @@
+uGuru datasheet
+===============
+
+First of all, what I know about uGuru is no fact based on any help, hints or
+datasheet from Abit. The data I have got on uGuru have I assembled through
+my weak knowledge in "backwards engineering".
+And just for the record, you may have noticed uGuru isn't a chip developed by
+Abit, as they claim it to be. It's realy just an microprocessor (uC) created by
+Winbond (W83L950D). And no, reading the manual for this specific uC or
+mailing  Windbond for help won't give any usefull data about uGuru, as it is
+the program inside the uC that is responding to calls.
+
+Olle Sandberg <ollebull@gmail.com>, 2005-05-25
+
+
+Original version by Olle Sandberg who did the heavy lifting of the initial
+reverse engineering. This version has been almost fully rewritten for clarity
+and extended with write support and info on more databanks, the write support
+is once again reverse engineered by Olle the additional databanks have been
+reverse engineered by me. I would like to express my thanks to Olle, this
+document and the Linux driver could not have been written without his efforts.
+
+Note: because of the lack of specs only the sensors part of the uGuru is
+described here and not the CPU / RAM / etc voltage & frequency control.
+
+Hans de Goede <j.w.r.degoede@hhs.nl>, 28-01-2006
+
+
+Detection
+=========
+
+As far as known the uGuru is always placed at and using the (ISA) I/O-ports
+0xE0 and 0xE4, so we don't have to scan any port-range, just check what the two
+ports are holding for detection. We will refer to 0xE0 as CMD (command-port)
+and 0xE4 as DATA because Abit refers to them with these names.
+
+If DATA holds 0x00 or 0x08 and CMD holds 0x00 or 0xAC an uGuru could be
+present. We have to check for two different values at data-port, because
+after a reboot uGuru will hold 0x00 here, but if the driver is removed and
+later on attached again data-port will hold 0x08, more about this later.
+
+After wider testing of the Linux kernel driver some variants of the uGuru have
+turned up which will hold 0x00 instead of 0xAC at the CMD port, thus we also
+have to test CMD for two different values. On these uGuru's DATA will initally
+hold 0x09 and will only hold 0x08 after reading CMD first, so CMD must be read
+first!
+
+To be really sure an uGuru is present a test read of one or more register
+sets should be done.
+
+
+Reading / Writing
+=================
+
+Addressing
+----------
+
+The uGuru has a number of different addressing levels. The first addressing
+level we will call banks. A bank holds data for one or more sensors. The data
+in a bank for a sensor is one or more bytes large.
+
+The number of bytes is fixed for a given bank, you should always read or write
+that many bytes, reading / writing more will fail, the results when writing
+less then the number of bytes for a given bank are undetermined.
+
+See below for all known bank addresses, numbers of sensors in that bank,
+number of bytes data per sensor and contents/meaning of those bytes.
+
+Although both this document and the kernel driver have kept the sensor
+terminoligy for the addressing within a bank this is not 100% correct, in
+bank 0x24 for example the addressing within the bank selects a PWM output not
+a sensor.
+
+Notice that some banks have both a read and a write address this is how the
+uGuru determines if a read from or a write to the bank is taking place, thus
+when reading you should always use the read address and when writing the
+write address. The write address is always one (1) more then the read address.
+
+
+uGuru ready
+-----------
+
+Before you can read from or write to the uGuru you must first put the uGuru
+in "ready" mode.
+
+To put the uGuru in ready mode first write 0x00 to DATA and then wait for DATA
+to hold 0x09, DATA should read 0x09 within 250 read cycles.
+
+Next CMD _must_ be read and should hold 0xAC, usually CMD will hold 0xAC the
+first read but sometimes it takes a while before CMD holds 0xAC and thus it
+has to be read a number of times (max 50).
+
+After reading CMD, DATA should hold 0x08 which means that the uGuru is ready
+for input. As above DATA will usually hold 0x08 the first read but not always.
+This step can be skipped, but it is undetermined what happens if the uGuru has
+not yet reported 0x08 at DATA and you proceed with writing a bank address.
+
+
+Sending bank and sensor addresses to the uGuru
+----------------------------------------------
+
+First the uGuru must be in "ready" mode as described above, DATA should hold
+0x08 indicating that the uGuru wants input, in this case the bank address.
+
+Next write the bank address to DATA. After the bank address has been written
+wait for to DATA to hold 0x08 again indicating that it wants / is ready for
+more input (max 250 reads).
+
+Once DATA holds 0x08 again write the sensor address to CMD.
+
+
+Reading
+-------
+
+First send the bank and sensor addresses as described above.
+Then for each byte of data you want to read wait for DATA to hold 0x01
+which indicates that the uGuru is ready to be read (max 250 reads) and once
+DATA holds 0x01 read the byte from CMD.
+
+Once all bytes have been read data will hold 0x09, but there is no reason to
+test for this. Notice that the number of bytes is bank address dependent see
+above and below.
+
+After completing a successfull read it is advised to put the uGuru back in
+ready mode, so that it is ready for the next read / write cycle. This way
+if your program / driver is unloaded and later loaded again the detection
+algorithm described above will still work.
+
+
+
+Writing
+-------
+
+First send the bank and sensor addresses as described above.
+Then for each byte of data you want to write wait for DATA to hold 0x00
+which indicates that the uGuru is ready to be written (max 250 reads) and
+once DATA holds 0x00 write the byte to CMD.
+
+Once all bytes have been written wait for DATA to hold 0x01 (max 250 reads)
+don't ask why this is the way it is.
+
+Once DATA holds 0x01 read CMD it should hold 0xAC now.
+
+After completing a successfull write it is advised to put the uGuru back in
+ready mode, so that it is ready for the next read / write cycle. This way
+if your program / driver is unloaded and later loaded again the detection
+algorithm described above will still work.
+
+
+Gotchas
+-------
+
+After wider testing of the Linux kernel driver some variants of the uGuru have
+turned up which do not hold 0x08 at DATA within 250 reads after writing the
+bank address. With these versions this happens quite frequent, using larger
+timeouts doesn't help, they just go offline for a second or 2, doing some
+internal callibration or whatever. Your code should be prepared to handle
+this and in case of no response in this specific case just goto sleep for a
+while and then retry.
+
+
+Address Map
+===========
+
+Bank 0x20 Alarms (R)
+--------------------
+This bank contains 0 sensors, iow the sensor address is ignored (but must be
+written) just use 0. Bank 0x20 contains 3 bytes:
+
+Byte 0:
+This byte holds the alarm flags for sensor 0-7 of Sensor Bank1, with bit 0
+corresponding to sensor 0, 1 to 1, etc.
+
+Byte 1:
+This byte holds the alarm flags for sensor 8-15 of Sensor Bank1, with bit 0
+corresponding to sensor 8, 1 to 9, etc.
+
+Byte 2:
+This byte holds the alarm flags for sensor 0-5 of Sensor Bank2, with bit 0
+corresponding to sensor 0, 1 to 1, etc.
+
+
+Bank 0x21 Sensor Bank1 Values / Readings (R)
+--------------------------------------------
+This bank contains 16 sensors, for each sensor it contains 1 byte.
+So far the following sensors are known to be available on all motherboards:
+Sensor  0 CPU temp
+Sensor  1 SYS temp
+Sensor  3 CPU core volt
+Sensor  4 DDR volt
+Sensor 10 DDR Vtt volt
+Sensor 15 PWM temp
+
+Byte 0:
+This byte holds the reading from the sensor. Sensors in Bank1 can be both
+volt and temp sensors, this is motherboard specific. The uGuru however does
+seem to know (be programmed with) what kindoff sensor is attached see Sensor
+Bank1 Settings description.
+
+Volt sensors use a linear scale, a reading 0 corresponds with 0 volt and a
+reading of 255 with 3494 mV. The sensors for higher voltages however are
+connected through a division circuit. The currently known division circuits
+in use result in ranges of: 0-4361mV, 0-6248mV or 0-14510mV. 3.3 volt sources
+use the 0-4361mV range, 5 volt the 0-6248mV and 12 volt the 0-14510mV .
+
+Temp sensors also use a linear scale, a reading of 0 corresponds with 0 degree
+Celsius and a reading of 255 with a reading of 255 degrees Celsius.
+
+
+Bank 0x22 Sensor Bank1 Settings (R)
+Bank 0x23 Sensor Bank1 Settings (W)
+-----------------------------------
+
+This bank contains 16 sensors, for each sensor it contains 3 bytes. Each
+set of 3 bytes contains the settings for the sensor with the same sensor
+address in Bank 0x21 .
+
+Byte 0:
+Alarm behaviour for the selected sensor. A 1 enables the described behaviour.
+Bit 0: Give an alarm if measured temp is over the warning threshold    (RW) *
+Bit 1: Give an alarm if measured volt is over the max threshold                (RW) **
+Bit 2: Give an alarm if measured volt is under the min threshold       (RW) **
+Bit 3: Beep if alarm                                                   (RW)
+Bit 4: 1 if alarm cause measured temp is over the warning threshold    (R)
+Bit 5: 1 if alarm cause measured volt is over the max threshold                (R)
+Bit 6: 1 if alarm cause measured volt is under the min threshold       (R)
+Bit 7: Volt sensor: Shutdown if alarm persist for more then 4 seconds  (RW)
+       Temp sensor: Shutdown if temp is over the shutdown threshold    (RW)
+
+*  This bit is only honored/used by the uGuru if a temp sensor is connected
+** This bit is only honored/used by the uGuru if a volt sensor is connected
+Note with some trickery this can be used to find out what kinda sensor is
+detected see the Linux kernel driver for an example with many comments on
+how todo this.
+
+Byte 1:
+Temp sensor: warning threshold  (scale as bank 0x21)
+Volt sensor: min threshold      (scale as bank 0x21)
+
+Byte 2:
+Temp sensor: shutdown threshold (scale as bank 0x21)
+Volt sensor: max threshold      (scale as bank 0x21)
+
+
+Bank 0x24 PWM outputs for FAN's (R)
+Bank 0x25 PWM outputs for FAN's (W)
+-----------------------------------
+
+This bank contains 3 "sensors", for each sensor it contains 5 bytes.
+Sensor 0 usually controls the CPU fan
+Sensor 1 usually controls the NB (or chipset for single chip) fan
+Sensor 2 usually controls the System fan
+
+Byte 0:
+Flag 0x80 to enable control, Fan runs at 100% when disabled.
+low nibble (temp)sensor address at bank 0x21 used for control.
+
+Byte 1:
+0-255 = 0-12v (linear), specify voltage at which fan will rotate when under
+low threshold temp (specified in byte 3)
+
+Byte 2:
+0-255 = 0-12v (linear), specify voltage at which fan will rotate when above
+high threshold temp (specified in byte 4)
+
+Byte 3:
+Low threshold temp  (scale as bank 0x21)
+
+byte 4:
+High threshold temp (scale as bank 0x21)
+
+
+Bank 0x26 Sensors Bank2 Values / Readings (R)
+---------------------------------------------
+
+This bank contains 6 sensors (AFAIK), for each sensor it contains 1 byte.
+So far the following sensors are known to be available on all motherboards:
+Sensor 0: CPU fan speed
+Sensor 1: NB (or chipset for single chip) fan speed
+Sensor 2: SYS fan speed
+
+Byte 0:
+This byte holds the reading from the sensor. 0-255 = 0-15300 (linear)
+
+
+Bank 0x27 Sensors Bank2 Settings (R)
+Bank 0x28 Sensors Bank2 Settings (W)
+------------------------------------
+
+This bank contains 6 sensors (AFAIK), for each sensor it contains 2 bytes.
+
+Byte 0:
+Alarm behaviour for the selected sensor. A 1 enables the described behaviour.
+Bit 0: Give an alarm if measured rpm is under the min threshold        (RW)
+Bit 3: Beep if alarm                                           (RW)
+Bit 7: Shutdown if alarm persist for more then 4 seconds       (RW)
+
+Byte 1:
+min threshold (scale as bank 0x26)
+
+
+Warning for the adventerous
+===========================
+
+A word of caution to those who want to experiment and see if they can figure
+the voltage / clock programming out, I tried reading and only reading banks
+0-0x30 with the reading code used for the sensor banks (0x20-0x28) and this
+resulted in a _permanent_ reprogramming of the voltages, luckily I had the
+sensors part configured so that it would shutdown my system on any out of spec
+voltages which proprably safed my computer (after a reboot I managed to
+immediatly enter the bios and reload the defaults). This probably means that
+the read/write cycle for the non sensor part is different from the sensor part.
index 58d181d050c4cdb9f16f42b7eb487ad30a2588c3..7e3a38eeccbfa83238d56672faa8b60f0d148656 100644 (file)
@@ -181,6 +181,12 @@ M: bcrl@kvack.org
 L:     linux-aio@kvack.org
 S:     Supported
 
+ABIT UGURU HARDWARE MONITOR DRIVER
+P:     Hans de Goede
+M:     j.w.r.degoede@hhs.nl
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+
 ACENIC DRIVER
 P:     Jes Sorensen
 M:     jes@trained-monkey.org
index 164760df1233371a636976777fc72768ae3b31e0..6fb93d63bd8c0b29b2685549813d980c34955da4 100644 (file)
@@ -27,6 +27,18 @@ config HWMON_VID
        tristate
        default n
 
+config SENSORS_ABITUGURU
+       tristate "Abit uGuru"
+       depends on HWMON && EXPERIMENTAL
+       help
+         If you say yes here you get support for the Abit uGuru chips
+         sensor part. The voltage and frequency control parts of the Abit
+         uGuru are not supported. The Abit uGuru chip can be found on Abit
+         uGuru featuring motherboards (most modern Abit motherboards).
+
+         This driver can also be built as a module.  If so, the module
+         will be called abituguru.
+
 config SENSORS_ADM1021
        tristate "Analog Devices ADM1021 and compatibles"
        depends on HWMON && I2C
index db72b1415e7f05c1b009abb5837e505ce7289d2e..5092999deb7b5c40a30984404cbf2b8a89e45fc4 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_SENSORS_W83792D) += w83792d.o
 obj-$(CONFIG_SENSORS_W83781D)  += w83781d.o
 obj-$(CONFIG_SENSORS_W83791D)  += w83791d.o
 
+obj-$(CONFIG_SENSORS_ABITUGURU)        += abituguru.o
 obj-$(CONFIG_SENSORS_ADM1021)  += adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)  += adm1025.o
 obj-$(CONFIG_SENSORS_ADM1026)  += adm1026.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
new file mode 100644 (file)
index 0000000..bf2cb0a
--- /dev/null
@@ -0,0 +1,1391 @@
+/*
+    abituguru.c Copyright (c) 2005-2006 Hans de Goede <j.w.r.degoede@hhs.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.
+*/
+/*
+    This driver supports the sensor part of the custom Abit uGuru chip found
+    on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM /
+    etc voltage & frequency control is not supported!
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/io.h>
+
+/* Banks */
+#define ABIT_UGURU_ALARM_BANK                  0x20 /* 1x 3 bytes */
+#define ABIT_UGURU_SENSOR_BANK1                        0x21 /* 16x volt and temp */
+#define ABIT_UGURU_FAN_PWM                     0x24 /* 3x 5 bytes */
+#define ABIT_UGURU_SENSOR_BANK2                        0x26 /* fans */
+/* max nr of sensors in bank2, currently mb's with max 6 fans are known */
+#define ABIT_UGURU_MAX_BANK2_SENSORS           6
+/* max nr of pwm outputs, currently mb's with max 5 pwm outputs are known */
+#define ABIT_UGURU_MAX_PWMS                    5
+/* uGuru sensor bank 1 flags */                             /* Alarm if: */
+#define ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE      0x01 /*  temp over warn */
+#define ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE      0x02 /*  volt over max */
+#define ABIT_UGURU_VOLT_LOW_ALARM_ENABLE       0x04 /*  volt under min */
+#define ABIT_UGURU_TEMP_HIGH_ALARM_FLAG                0x10 /* temp is over warn */
+#define ABIT_UGURU_VOLT_HIGH_ALARM_FLAG                0x20 /* volt is over max */
+#define ABIT_UGURU_VOLT_LOW_ALARM_FLAG         0x40 /* volt is under min */
+/* uGuru sensor bank 2 flags */                             /* Alarm if: */
+#define ABIT_UGURU_FAN_LOW_ALARM_ENABLE                0x01 /*   fan under min */
+/* uGuru sensor bank common flags */
+#define ABIT_UGURU_BEEP_ENABLE                 0x08 /* beep if alarm */
+#define ABIT_UGURU_SHUTDOWN_ENABLE             0x80 /* shutdown if alarm */
+/* uGuru fan PWM (speed control) flags */
+#define ABIT_UGURU_FAN_PWM_ENABLE              0x80 /* enable speed control */
+/* Values used for conversion */
+#define ABIT_UGURU_FAN_MAX                     15300 /* RPM */
+/* Bank1 sensor types */
+#define ABIT_UGURU_IN_SENSOR                   0
+#define ABIT_UGURU_TEMP_SENSOR                 1
+#define ABIT_UGURU_NC                          2
+/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
+   convert them to params. */
+/* 250 was determined by trial and error, 200 works most of the time, but not
+   always. I assume this is cpu-speed independent, since the ISA-bus and not
+   the CPU should be the bottleneck. Note that 250 sometimes is still not
+   enough (only reported on AN7 mb) this is handled by a higher layer. */
+#define ABIT_UGURU_WAIT_TIMEOUT                        250
+/* Normally all expected status in abituguru_ready, are reported after the
+   first read, but sometimes not and we need to poll, 5 polls was not enough
+   50 sofar is. */
+#define ABIT_UGURU_READY_TIMEOUT               50
+/* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */
+#define ABIT_UGURU_MAX_RETRIES                 3
+#define ABIT_UGURU_RETRY_DELAY                 (HZ/5)
+/* Maximum 2 timeouts in abituguru_update_device, iow 3 in a row is a error */
+#define ABIT_UGURU_MAX_TIMEOUTS                        2
+
+/* All the variables below are named identical to the oguru and oguru2 programs
+   reverse engineered by Olle Sandberg, hence the names might not be 100%
+   logical. I could come up with better names, but I prefer keeping the names
+   identical so that this driver can be compared with his work more easily. */
+/* Two i/o-ports are used by uGuru */
+#define ABIT_UGURU_BASE                                0x00E0
+/* Used to tell uGuru what to read and to read the actual data */
+#define ABIT_UGURU_CMD                         0x00
+/* Mostly used to check if uGuru is busy */
+#define ABIT_UGURU_DATA                                0x04
+#define ABIT_UGURU_REGION_LENGTH               5
+/* uGuru status' */
+#define ABIT_UGURU_STATUS_WRITE                        0x00 /* Ready to be written */
+#define ABIT_UGURU_STATUS_READ                 0x01 /* Ready to be read */
+#define ABIT_UGURU_STATUS_INPUT                        0x08 /* More input */
+#define ABIT_UGURU_STATUS_READY                        0x09 /* Ready to be written */
+/* utility macros */
+#define ABIT_UGURU_NAME                                "abituguru"
+#define ABIT_UGURU_DEBUG(level, format, arg...)                                \
+       if (level <= verbose)                                           \
+               printk(KERN_DEBUG ABIT_UGURU_NAME ": "  format , ## arg)
+
+/* Constants */
+/* in (Volt) sensors go up to 3494 mV, temp to 255000 millidegrees Celsius */
+static const int abituguru_bank1_max_value[2] = { 3494, 255000 };
+/* Min / Max allowed values for sensor2 (fan) alarm threshold, these values
+   correspond to 300-3000 RPM */
+static const u8 abituguru_bank2_min_threshold = 5;
+static const u8 abituguru_bank2_max_threshold = 50;
+/* Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4
+   are temperature trip points. */
+static const int abituguru_pwm_settings_multiplier[5] = { 0, 1, 1, 1000, 1000 };
+/* Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a
+   special case the minium allowed pwm% setting for this is 30% (77) on
+   some MB's this special case is handled in the code! */
+static const u8 abituguru_pwm_min[5] = { 0, 170, 170, 25, 25 };
+static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 };
+
+
+/* Insmod parameters */
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to force detection.");
+static int fan_sensors;
+module_param(fan_sensors, int, 0);
+MODULE_PARM_DESC(fan_sensors, "Number of fan sensors on the uGuru "
+       "(0 = autodetect)");
+static int pwms;
+module_param(pwms, int, 0);
+MODULE_PARM_DESC(pwms, "Number of PWMs on the uGuru "
+       "(0 = autodetect)");
+
+/* Default verbose is 2, since this driver is still in the testing phase */
+static int verbose = 2;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n"
+       "   0 normal output\n"
+       "   1 + verbose error reporting\n"
+       "   2 + sensors type probing info\n"
+       "   3 + retryable error reporting");
+
+
+/* For the Abit uGuru, we need to keep some data in memory.
+   The structure is dynamically allocated, at the same time when a new
+   abituguru device is allocated. */
+struct abituguru_data {
+       struct class_device *class_dev; /* hwmon registered device */
+       struct mutex update_lock;       /* protect access to data and uGuru */
+       unsigned long last_updated;     /* In jiffies */
+       unsigned short addr;            /* uguru base address */
+       char uguru_ready;               /* is the uguru in ready state? */
+       unsigned char update_timeouts;  /* number of update timeouts since last
+                                          successful update */
+
+       /* The sysfs attr and their names are generated automatically, for bank1
+          we cannot use a predefined array because we don't know beforehand
+          of a sensor is a volt or a temp sensor, for bank2 and the pwms its
+          easier todo things the same way.  For in sensors we have 9 (temp 7)
+          sysfs entries per sensor, for bank2 and pwms 6. */
+       struct sensor_device_attribute_2 sysfs_attr[16 * 9 +
+               ABIT_UGURU_MAX_BANK2_SENSORS * 6 + ABIT_UGURU_MAX_PWMS * 6];
+       /* Buffer to store the dynamically generated sysfs names, we need 2120
+          bytes for bank1 (worst case scenario of 16 in sensors), 444 bytes
+          for fan1-6 and 738 bytes for pwm1-6 + some room to spare in case I
+          miscounted :) */
+       char bank1_names[3400];
+
+       /* Bank 1 data */
+       u8 bank1_sensors[2];    /* number of [0] in, [1] temp sensors */
+       u8 bank1_address[2][16];/* addresses of [0] in, [1] temp sensors */
+       u8 bank1_value[16];
+       /* This array holds 16 x 3 entries for all the bank 1 sensor settings
+          (flags, min, max for voltage / flags, warn, shutdown for temp). */
+       u8 bank1_settings[16][3];
+       /* Maximum value for each sensor used for scaling in mV/millidegrees
+          Celsius. */
+       int bank1_max_value[16];
+
+       /* Bank 2 data, ABIT_UGURU_MAX_BANK2_SENSORS entries for bank2 */
+       u8 bank2_sensors; /* actual number of bank2 sensors found */
+       u8 bank2_value[ABIT_UGURU_MAX_BANK2_SENSORS];
+       u8 bank2_settings[ABIT_UGURU_MAX_BANK2_SENSORS][2]; /* flags, min */
+
+       /* Alarms 2 bytes for bank1, 1 byte for bank2 */
+       u8 alarms[3];
+
+       /* Fan PWM (speed control) 5 bytes per PWM */
+       u8 pwms; /* actual number of pwms found */
+       u8 pwm_settings[ABIT_UGURU_MAX_PWMS][5];
+};
+
+/* wait till the uguru is in the specified state */
+static int abituguru_wait(struct abituguru_data *data, u8 state)
+{
+       int timeout = ABIT_UGURU_WAIT_TIMEOUT;
+
+       while (inb_p(data->addr + ABIT_UGURU_DATA) != state) {
+               timeout--;
+               if (timeout == 0)
+                       return -EBUSY;
+       }
+       return 0;
+}
+
+/* Put the uguru in ready for input state */
+static int abituguru_ready(struct abituguru_data *data)
+{
+       int timeout = ABIT_UGURU_READY_TIMEOUT;
+
+       if (data->uguru_ready)
+               return 0;
+
+       /* Reset? / Prepare for next read/write cycle */
+       outb(0x00, data->addr + ABIT_UGURU_DATA);
+
+       /* Wait till the uguru is ready */
+       if (abituguru_wait(data, ABIT_UGURU_STATUS_READY)) {
+               ABIT_UGURU_DEBUG(1,
+                       "timeout exceeded waiting for ready state\n");
+               return -EIO;
+       }
+
+       /* Cmd port MUST be read now and should contain 0xAC */
+       while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
+               timeout--;
+               if (timeout == 0) {
+                       ABIT_UGURU_DEBUG(1,
+                          "CMD reg does not hold 0xAC after ready command\n");
+                       return -EIO;
+               }
+       }
+
+       /* After this the ABIT_UGURU_DATA port should contain
+          ABIT_UGURU_STATUS_INPUT */
+       timeout = ABIT_UGURU_READY_TIMEOUT;
+       while (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) {
+               timeout--;
+               if (timeout == 0) {
+                       ABIT_UGURU_DEBUG(1,
+                               "state != more input after ready command\n");
+                       return -EIO;
+               }
+       }
+
+       data->uguru_ready = 1;
+       return 0;
+}
+
+/* Send the bank and then sensor address to the uGuru for the next read/write
+   cycle. This function gets called as the first part of a read/write by
+   abituguru_read and abituguru_write. This function should never be
+   called by any other function. */
+static int abituguru_send_address(struct abituguru_data *data,
+       u8 bank_addr, u8 sensor_addr, int retries)
+{
+       /* assume the caller does error handling itself if it has not requested
+          any retries, and thus be quiet. */
+       int report_errors = retries;
+
+       for (;;) {
+               /* Make sure the uguru is ready and then send the bank address,
+                  after this the uguru is no longer "ready". */
+               if (abituguru_ready(data) != 0)
+                       return -EIO;
+               outb(bank_addr, data->addr + ABIT_UGURU_DATA);
+               data->uguru_ready = 0;
+
+               /* Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again
+                  and send the sensor addr */
+               if (abituguru_wait(data, ABIT_UGURU_STATUS_INPUT)) {
+                       if (retries) {
+                               ABIT_UGURU_DEBUG(3, "timeout exceeded "
+                                       "waiting for more input state, %d "
+                                       "tries remaining\n", retries);
+                               set_current_state(TASK_UNINTERRUPTIBLE);
+                               schedule_timeout(ABIT_UGURU_RETRY_DELAY);
+                               retries--;
+                               continue;
+                       }
+                       if (report_errors)
+                               ABIT_UGURU_DEBUG(1, "timeout exceeded "
+                                       "waiting for more input state "
+                                       "(bank: %d)\n", (int)bank_addr);
+                       return -EBUSY;
+               }
+               outb(sensor_addr, data->addr + ABIT_UGURU_CMD);
+               return 0;
+       }
+}
+
+/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
+   result in buf, retry the send address part of the read retries times. */
+static int abituguru_read(struct abituguru_data *data,
+       u8 bank_addr, u8 sensor_addr, u8 *buf, int count, int retries)
+{
+       int i;
+
+       /* Send the address */
+       i = abituguru_send_address(data, bank_addr, sensor_addr, retries);
+       if (i)
+               return i;
+
+       /* And read the data */
+       for (i = 0; i < count; i++) {
+               if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
+                       ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for "
+                               "read state (bank: %d, sensor: %d)\n",
+                               (int)bank_addr, (int)sensor_addr);
+                       break;
+               }
+               buf[i] = inb(data->addr + ABIT_UGURU_CMD);
+       }
+
+       /* Last put the chip back in ready state */
+       abituguru_ready(data);
+
+       return i;
+}
+
+/* Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send
+   address part of the write is always retried ABIT_UGURU_MAX_RETRIES times. */
+static int abituguru_write(struct abituguru_data *data,
+       u8 bank_addr, u8 sensor_addr, u8 *buf, int count)
+{
+       int i;
+
+       /* Send the address */
+       i = abituguru_send_address(data, bank_addr, sensor_addr,
+               ABIT_UGURU_MAX_RETRIES);
+       if (i)
+               return i;
+
+       /* And write the data */
+       for (i = 0; i < count; i++) {
+               if (abituguru_wait(data, ABIT_UGURU_STATUS_WRITE)) {
+                       ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for "
+                               "write state (bank: %d, sensor: %d)\n",
+                               (int)bank_addr, (int)sensor_addr);
+                       break;
+               }
+               outb(buf[i], data->addr + ABIT_UGURU_CMD);
+       }
+
+       /* Now we need to wait till the chip is ready to be read again,
+          don't ask why */
+       if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
+               ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state "
+                       "after write (bank: %d, sensor: %d)\n", (int)bank_addr,
+                       (int)sensor_addr);
+               return -EIO;
+       }
+
+       /* Cmd port MUST be read now and should contain 0xAC */
+       if (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
+               ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after write "
+                       "(bank: %d, sensor: %d)\n", (int)bank_addr,
+                       (int)sensor_addr);
+               return -EIO;
+       }
+
+       /* Last put the chip back in ready state */
+       abituguru_ready(data);
+
+       return i;
+}
+
+/* Detect sensor type. Temp and Volt sensors are enabled with
+   different masks and will ignore enable masks not meant for them.
+   This enables us to test what kind of sensor we're dealing with.
+   By setting the alarm thresholds so that we will always get an
+   alarm for sensor type X and then enabling the sensor as sensor type
+   X, if we then get an alarm it is a sensor of type X. */
+static int __devinit
+abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
+                                  u8 sensor_addr)
+{
+       u8 val, buf[3];
+       int ret = ABIT_UGURU_NC;
+
+       /* First read the sensor and the current settings */
+       if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, sensor_addr, &val,
+                       1, ABIT_UGURU_MAX_RETRIES) != 1)
+               return -EIO;
+
+       /* Test val is sane / usable for sensor type detection. */
+       if ((val < 10u) || (val > 240u)) {
+               printk(KERN_WARNING ABIT_UGURU_NAME
+                       ": bank1-sensor: %d reading (%d) too close to limits, "
+                       "unable to determine sensor type, skipping sensor\n",
+                       (int)sensor_addr, (int)val);
+               /* assume no sensor is there for sensors for which we can't
+                  determine the sensor type because their reading is too close
+                  to their limits, this usually means no sensor is there. */
+               return ABIT_UGURU_NC;
+       }
+
+       ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
+       /* Volt sensor test, enable volt low alarm, set min value ridicously
+          high. If its a volt sensor this should always give us an alarm. */
+       buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
+       buf[1] = 245;
+       buf[2] = 250;
+       if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+                       buf, 3) != 3)
+               return -EIO;
+       /* Now we need 20 ms to give the uguru time to read the sensors
+          and raise a voltage alarm */
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(HZ/50);
+       /* Check for alarm and check the alarm is a volt low alarm. */
+       if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
+                       ABIT_UGURU_MAX_RETRIES) != 3)
+               return -EIO;
+       if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
+               if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
+                               sensor_addr, buf, 3,
+                               ABIT_UGURU_MAX_RETRIES) != 3)
+                       return -EIO;
+               if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
+                       /* Restore original settings */
+                       if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
+                                       sensor_addr,
+                                       data->bank1_settings[sensor_addr],
+                                       3) != 3)
+                               return -EIO;
+                       ABIT_UGURU_DEBUG(2, "  found volt sensor\n");
+                       return ABIT_UGURU_IN_SENSOR;
+               } else
+                       ABIT_UGURU_DEBUG(2, "  alarm raised during volt "
+                               "sensor test, but volt low flag not set\n");
+       } else
+               ABIT_UGURU_DEBUG(2, "  alarm not raised during volt sensor "
+                       "test\n");
+
+       /* Temp sensor test, enable sensor as a temp sensor, set beep value
+          ridicously low (but not too low, otherwise uguru ignores it).
+          If its a temp sensor this should always give us an alarm. */
+       buf[0] = ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE;
+       buf[1] = 5;
+       buf[2] = 10;
+       if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+                       buf, 3) != 3)
+               return -EIO;
+       /* Now we need 50 ms to give the uguru time to read the sensors
+          and raise a temp alarm */
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout(HZ/20);
+       /* Check for alarm and check the alarm is a temp high alarm. */
+       if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
+                       ABIT_UGURU_MAX_RETRIES) != 3)
+               return -EIO;
+       if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
+               if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
+                               sensor_addr, buf, 3,
+                               ABIT_UGURU_MAX_RETRIES) != 3)
+                       return -EIO;
+               if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) {
+                       ret = ABIT_UGURU_TEMP_SENSOR;
+                       ABIT_UGURU_DEBUG(2, "  found temp sensor\n");
+               } else
+                       ABIT_UGURU_DEBUG(2, "  alarm raised during temp "
+                               "sensor test, but temp high flag not set\n");
+       } else
+               ABIT_UGURU_DEBUG(2, "  alarm not raised during temp sensor "
+                       "test\n");
+
+       /* Restore original settings */
+       if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
+                       data->bank1_settings[sensor_addr], 3) != 3)
+               return -EIO;
+
+       return ret;
+}
+
+/* These functions try to find out how many sensors there are in bank2 and how
+   many pwms there are. The purpose of this is to make sure that we don't give
+   the user the possibility to change settings for non-existent sensors / pwm.
+   The uGuru will happily read / write whatever memory happens to be after the
+   memory storing the PWM settings when reading/writing to a PWM which is not
+   there. Notice even if we detect a PWM which doesn't exist we normally won't
+   write to it, unless the user tries to change the settings.
+
+   Although the uGuru allows reading (settings) from non existing bank2
+   sensors, my version of the uGuru does seem to stop writing to them, the
+   write function above aborts in this case with:
+   "CMD reg does not hold 0xAC after write"
+
+   Notice these 2 tests are non destructive iow read-only tests, otherwise
+   they would defeat their purpose. Although for the bank2_sensors detection a
+   read/write test would be feasible because of the reaction above, I've
+   however opted to stay on the safe side. */
+static void __devinit
+abituguru_detect_no_bank2_sensors(struct abituguru_data *data)
+{
+       int i;
+
+       if (fan_sensors) {
+               data->bank2_sensors = fan_sensors;
+               ABIT_UGURU_DEBUG(2, "assuming %d fan sensors because of "
+                       "\"fan_sensors\" module param\n",
+                       (int)data->bank2_sensors);
+               return;
+       }
+
+       ABIT_UGURU_DEBUG(2, "detecting number of fan sensors\n");
+       for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
+               /* 0x89 are the known used bits:
+                  -0x80 enable shutdown
+                  -0x08 enable beep
+                  -0x01 enable alarm
+                  All other bits should be 0, but on some motherboards
+                  0x40 (bit 6) is also high, at least for fan1 */
+               if ((!i && (data->bank2_settings[i][0] & ~0xC9)) ||
+                    (i && (data->bank2_settings[i][0] & ~0x89))) {
+                       ABIT_UGURU_DEBUG(2, "  bank2 sensor %d does not seem "
+                               "to be a fan sensor: settings[0] = %02X\n",
+                               i, (unsigned int)data->bank2_settings[i][0]);
+                       break;
+               }
+
+               /* check if the threshold is within the allowed range */
+               if (data->bank2_settings[i][1] <
+                               abituguru_bank2_min_threshold) {
+                       ABIT_UGURU_DEBUG(2, "  bank2 sensor %d does not seem "
+                               "to be a fan sensor: the threshold (%d) is "
+                               "below the minimum (%d)\n", i,
+                               (int)data->bank2_settings[i][1],
+                               (int)abituguru_bank2_min_threshold);
+                       break;
+               }
+               if (data->bank2_settings[i][1] >
+                               abituguru_bank2_max_threshold) {
+                       ABIT_UGURU_DEBUG(2, "  bank2 sensor %d does not seem "
+                               "to be a fan sensor: the threshold (%d) is "
+                               "above the maximum (%d)\n", i,
+                               (int)data->bank2_settings[i][1],
+                               (int)abituguru_bank2_max_threshold);
+                       break;
+               }
+       }
+
+       data->bank2_sensors = i;
+       ABIT_UGURU_DEBUG(2, " found: %d fan sensors\n",
+               (int)data->bank2_sensors);
+}
+
+static void __devinit
+abituguru_detect_no_pwms(struct abituguru_data *data)
+{
+       int i, j;
+
+       if (pwms) {
+               data->pwms = pwms;
+               ABIT_UGURU_DEBUG(2, "assuming %d PWM outputs because of "
+                       "\"pwms\" module param\n", (int)data->pwms);
+               return;
+       }
+
+       ABIT_UGURU_DEBUG(2, "detecting number of PWM outputs\n");
+       for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
+               /* 0x80 is the enable bit and the low
+                  nibble is which temp sensor to use,
+                  the other bits should be 0 */
+               if (data->pwm_settings[i][0] & ~0x8F) {
+                       ABIT_UGURU_DEBUG(2, "  pwm channel %d does not seem "
+                               "to be a pwm channel: settings[0] = %02X\n",
+                               i, (unsigned int)data->pwm_settings[i][0]);
+                       break;
+               }
+
+               /* the low nibble must correspond to one of the temp sensors
+                  we've found */
+               for (j = 0; j < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR];
+                               j++) {
+                       if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][j] ==
+                                       (data->pwm_settings[i][0] & 0x0F))
+                               break;
+               }
+               if (j == data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) {
+                       ABIT_UGURU_DEBUG(2, "  pwm channel %d does not seem "
+                               "to be a pwm channel: %d is not a valid temp "
+                               "sensor address\n", i,
+                               data->pwm_settings[i][0] & 0x0F);
+                       break;
+               }
+
+               /* check if all other settings are within the allowed range */
+               for (j = 1; j < 5; j++) {
+                       u8 min;
+                       /* special case pwm1 min pwm% */
+                       if ((i == 0) && ((j == 1) || (j == 2)))
+                               min = 77;
+                       else
+                               min = abituguru_pwm_min[j];
+                       if (data->pwm_settings[i][j] < min) {
+                               ABIT_UGURU_DEBUG(2, "  pwm channel %d does "
+                                       "not seem to be a pwm channel: "
+                                       "setting %d (%d) is below the minimum "
+                                       "value (%d)\n", i, j,
+                                       (int)data->pwm_settings[i][j],
+                                       (int)min);
+                               goto abituguru_detect_no_pwms_exit;
+                       }
+                       if (data->pwm_settings[i][j] > abituguru_pwm_max[j]) {
+                               ABIT_UGURU_DEBUG(2, "  pwm channel %d does "
+                                       "not seem to be a pwm channel: "
+                                       "setting %d (%d) is above the maximum "
+                                       "value (%d)\n", i, j,
+                                       (int)data->pwm_settings[i][j],
+                                       (int)abituguru_pwm_max[j]);
+                               goto abituguru_detect_no_pwms_exit;
+                       }
+               }
+
+               /* check that min temp < max temp and min pwm < max pwm */
+               if (data->pwm_settings[i][1] >= data->pwm_settings[i][2]) {
+                       ABIT_UGURU_DEBUG(2, "  pwm channel %d does not seem "
+                               "to be a pwm channel: min pwm (%d) >= "
+                               "max pwm (%d)\n", i,
+                               (int)data->pwm_settings[i][1],
+                               (int)data->pwm_settings[i][2]);
+                       break;
+               }
+               if (data->pwm_settings[i][3] >= data->pwm_settings[i][4]) {
+                       ABIT_UGURU_DEBUG(2, "  pwm channel %d does not seem "
+                               "to be a pwm channel: min temp (%d) >= "
+                               "max temp (%d)\n", i,
+                               (int)data->pwm_settings[i][3],
+                               (int)data->pwm_settings[i][4]);
+                       break;
+               }
+       }
+
+abituguru_detect_no_pwms_exit:
+       data->pwms = i;
+       ABIT_UGURU_DEBUG(2, " found: %d PWM outputs\n", (int)data->pwms);
+}
+
+/* Following are the sysfs callback functions. These functions expect:
+   sensor_device_attribute_2->index:   sensor address/offset in the bank
+   sensor_device_attribute_2->nr:      register offset, bitmask or NA. */
+static struct abituguru_data *abituguru_update_device(struct device *dev);
+
+static ssize_t show_bank1_value(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = abituguru_update_device(dev);
+       if (!data)
+               return -EIO;
+       return sprintf(buf, "%d\n", (data->bank1_value[attr->index] *
+               data->bank1_max_value[attr->index] + 128) / 255);
+}
+
+static ssize_t show_bank1_setting(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n",
+               (data->bank1_settings[attr->index][attr->nr] *
+               data->bank1_max_value[attr->index] + 128) / 255);
+}
+
+static ssize_t show_bank2_value(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = abituguru_update_device(dev);
+       if (!data)
+               return -EIO;
+       return sprintf(buf, "%d\n", (data->bank2_value[attr->index] *
+               ABIT_UGURU_FAN_MAX + 128) / 255);
+}
+
+static ssize_t show_bank2_setting(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n",
+               (data->bank2_settings[attr->index][attr->nr] *
+               ABIT_UGURU_FAN_MAX + 128) / 255);
+}
+
+static ssize_t store_bank1_setting(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       u8 val = (simple_strtoul(buf, NULL, 10) * 255 +
+               data->bank1_max_value[attr->index]/2) /
+               data->bank1_max_value[attr->index];
+       ssize_t ret = count;
+
+       mutex_lock(&data->update_lock);
+       if (data->bank1_settings[attr->index][attr->nr] != val) {
+               u8 orig_val = data->bank1_settings[attr->index][attr->nr];
+               data->bank1_settings[attr->index][attr->nr] = val;
+               if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
+                               attr->index, data->bank1_settings[attr->index],
+                               3) <= attr->nr) {
+                       data->bank1_settings[attr->index][attr->nr] = orig_val;
+                       ret = -EIO;
+               }
+       }
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static ssize_t store_bank2_setting(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       u8 val = (simple_strtoul(buf, NULL, 10)*255 + ABIT_UGURU_FAN_MAX/2) /
+               ABIT_UGURU_FAN_MAX;
+       ssize_t ret = count;
+
+       /* this check can be done before taking the lock */
+       if ((val < abituguru_bank2_min_threshold) ||
+                       (val > abituguru_bank2_max_threshold))
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       if (data->bank2_settings[attr->index][attr->nr] != val) {
+               u8 orig_val = data->bank2_settings[attr->index][attr->nr];
+               data->bank2_settings[attr->index][attr->nr] = val;
+               if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK2 + 2,
+                               attr->index, data->bank2_settings[attr->index],
+                               2) <= attr->nr) {
+                       data->bank2_settings[attr->index][attr->nr] = orig_val;
+                       ret = -EIO;
+               }
+       }
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static ssize_t show_bank1_alarm(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = abituguru_update_device(dev);
+       if (!data)
+               return -EIO;
+       /* See if the alarm bit for this sensor is set, and if the
+          alarm matches the type of alarm we're looking for (for volt
+          it can be either low or high). The type is stored in a few
+          readonly bits in the settings part of the relevant sensor.
+          The bitmask of the type is passed to us in attr->nr. */
+       if ((data->alarms[attr->index / 8] & (0x01 << (attr->index % 8))) &&
+                       (data->bank1_settings[attr->index][0] & attr->nr))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_bank2_alarm(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = abituguru_update_device(dev);
+       if (!data)
+               return -EIO;
+       if (data->alarms[2] & (0x01 << attr->index))
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_bank1_mask(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       if (data->bank1_settings[attr->index][0] & attr->nr)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t show_bank2_mask(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       if (data->bank2_settings[attr->index][0] & attr->nr)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t store_bank1_mask(struct device *dev,
+       struct device_attribute *devattr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       int mask = simple_strtoul(buf, NULL, 10);
+       ssize_t ret = count;
+       u8 orig_val;
+
+       mutex_lock(&data->update_lock);
+       orig_val = data->bank1_settings[attr->index][0];
+
+       if (mask)
+               data->bank1_settings[attr->index][0] |= attr->nr;
+       else
+               data->bank1_settings[attr->index][0] &= ~attr->nr;
+
+       if ((data->bank1_settings[attr->index][0] != orig_val) &&
+                       (abituguru_write(data,
+                       ABIT_UGURU_SENSOR_BANK1 + 2, attr->index,
+                       data->bank1_settings[attr->index], 3) < 1)) {
+               data->bank1_settings[attr->index][0] = orig_val;
+               ret = -EIO;
+       }
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static ssize_t store_bank2_mask(struct device *dev,
+       struct device_attribute *devattr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       int mask = simple_strtoul(buf, NULL, 10);
+       ssize_t ret = count;
+       u8 orig_val;
+
+       mutex_lock(&data->update_lock);
+       orig_val = data->bank2_settings[attr->index][0];
+
+       if (mask)
+               data->bank2_settings[attr->index][0] |= attr->nr;
+       else
+               data->bank2_settings[attr->index][0] &= ~attr->nr;
+
+       if ((data->bank2_settings[attr->index][0] != orig_val) &&
+                       (abituguru_write(data,
+                       ABIT_UGURU_SENSOR_BANK2 + 2, attr->index,
+                       data->bank2_settings[attr->index], 2) < 1)) {
+               data->bank2_settings[attr->index][0] = orig_val;
+               ret = -EIO;
+       }
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+/* Fan PWM (speed control) */
+static ssize_t show_pwm_setting(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", data->pwm_settings[attr->index][attr->nr] *
+               abituguru_pwm_settings_multiplier[attr->nr]);
+}
+
+static ssize_t store_pwm_setting(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       u8 min, val = (simple_strtoul(buf, NULL, 10) +
+               abituguru_pwm_settings_multiplier[attr->nr]/2) /
+               abituguru_pwm_settings_multiplier[attr->nr];
+       ssize_t ret = count;
+
+       /* special case pwm1 min pwm% */
+       if ((attr->index == 0) && ((attr->nr == 1) || (attr->nr == 2)))
+               min = 77;
+       else
+               min = abituguru_pwm_min[attr->nr];
+
+       /* this check can be done before taking the lock */
+       if ((val < min) || (val > abituguru_pwm_max[attr->nr]))
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       /* this check needs to be done after taking the lock */
+       if ((attr->nr & 1) &&
+                       (val >= data->pwm_settings[attr->index][attr->nr + 1]))
+               ret = -EINVAL;
+       else if (!(attr->nr & 1) &&
+                       (val <= data->pwm_settings[attr->index][attr->nr - 1]))
+               ret = -EINVAL;
+       else if (data->pwm_settings[attr->index][attr->nr] != val) {
+               u8 orig_val = data->pwm_settings[attr->index][attr->nr];
+               data->pwm_settings[attr->index][attr->nr] = val;
+               if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
+                               attr->index, data->pwm_settings[attr->index],
+                               5) <= attr->nr) {
+                       data->pwm_settings[attr->index][attr->nr] =
+                               orig_val;
+                       ret = -EIO;
+               }
+       }
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static ssize_t show_pwm_sensor(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       int i;
+       /* We need to walk to the temp sensor addresses to find what
+          the userspace id of the configured temp sensor is. */
+       for (i = 0; i < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; i++)
+               if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][i] ==
+                               (data->pwm_settings[attr->index][0] & 0x0F))
+                       return sprintf(buf, "%d\n", i+1);
+
+       return -ENXIO;
+}
+
+static ssize_t store_pwm_sensor(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       unsigned long val = simple_strtoul(buf, NULL, 10) - 1;
+       ssize_t ret = count;
+
+       mutex_lock(&data->update_lock);
+       if (val < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) {
+               u8 orig_val = data->pwm_settings[attr->index][0];
+               u8 address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val];
+               data->pwm_settings[attr->index][0] &= 0xF0;
+               data->pwm_settings[attr->index][0] |= address;
+               if (data->pwm_settings[attr->index][0] != orig_val) {
+                       if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
+                                       attr->index,
+                                       data->pwm_settings[attr->index],
+                                       5) < 1) {
+                               data->pwm_settings[attr->index][0] = orig_val;
+                               ret = -EIO;
+                       }
+               }
+       }
+       else
+               ret = -EINVAL;
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       int res = 0;
+       if (data->pwm_settings[attr->index][0] & ABIT_UGURU_FAN_PWM_ENABLE)
+               res = 2;
+       return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       u8 orig_val, user_val = simple_strtoul(buf, NULL, 10);
+       ssize_t ret = count;
+
+       mutex_lock(&data->update_lock);
+       orig_val = data->pwm_settings[attr->index][0];
+       switch (user_val) {
+               case 0:
+                       data->pwm_settings[attr->index][0] &=
+                               ~ABIT_UGURU_FAN_PWM_ENABLE;
+                       break;
+               case 2:
+                       data->pwm_settings[attr->index][0] |=
+                               ABIT_UGURU_FAN_PWM_ENABLE;
+                       break;
+               default:
+                       ret = -EINVAL;
+       }
+       if ((data->pwm_settings[attr->index][0] != orig_val) &&
+                       (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1,
+                       attr->index, data->pwm_settings[attr->index],
+                       5) < 1)) {
+               data->pwm_settings[attr->index][0] = orig_val;
+               ret = -EIO;
+       }
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static ssize_t show_name(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       return sprintf(buf, "%s\n", ABIT_UGURU_NAME);
+}
+
+/* Sysfs attr templates, the real entries are generated automatically. */
+static const
+struct sensor_device_attribute_2 abituguru_sysfs_bank1_templ[2][9] = {
+       {
+       SENSOR_ATTR_2(in%d_input, 0444, show_bank1_value, NULL, 0, 0),
+       SENSOR_ATTR_2(in%d_min, 0644, show_bank1_setting,
+               store_bank1_setting, 1, 0),
+       SENSOR_ATTR_2(in%d_min_alarm, 0444, show_bank1_alarm, NULL,
+               ABIT_UGURU_VOLT_LOW_ALARM_FLAG, 0),
+       SENSOR_ATTR_2(in%d_max, 0644, show_bank1_setting,
+               store_bank1_setting, 2, 0),
+       SENSOR_ATTR_2(in%d_max_alarm, 0444, show_bank1_alarm, NULL,
+               ABIT_UGURU_VOLT_HIGH_ALARM_FLAG, 0),
+       SENSOR_ATTR_2(in%d_beep, 0644, show_bank1_mask,
+               store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0),
+       SENSOR_ATTR_2(in%d_shutdown, 0644, show_bank1_mask,
+               store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
+       SENSOR_ATTR_2(in%d_min_alarm_enable, 0644, show_bank1_mask,
+               store_bank1_mask, ABIT_UGURU_VOLT_LOW_ALARM_ENABLE, 0),
+       SENSOR_ATTR_2(in%d_max_alarm_enable, 0644, show_bank1_mask,
+               store_bank1_mask, ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE, 0),
+       }, {
+       SENSOR_ATTR_2(temp%d_input, 0444, show_bank1_value, NULL, 0, 0),
+       SENSOR_ATTR_2(temp%d_alarm, 0444, show_bank1_alarm, NULL,
+               ABIT_UGURU_TEMP_HIGH_ALARM_FLAG, 0),
+       SENSOR_ATTR_2(temp%d_max, 0644, show_bank1_setting,
+               store_bank1_setting, 1, 0),
+       SENSOR_ATTR_2(temp%d_crit, 0644, show_bank1_setting,
+               store_bank1_setting, 2, 0),
+       SENSOR_ATTR_2(temp%d_beep, 0644, show_bank1_mask,
+               store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0),
+       SENSOR_ATTR_2(temp%d_shutdown, 0644, show_bank1_mask,
+               store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
+       SENSOR_ATTR_2(temp%d_alarm_enable, 0644, show_bank1_mask,
+               store_bank1_mask, ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE, 0),
+       }
+};
+
+static const struct sensor_device_attribute_2 abituguru_sysfs_fan_templ[6] = {
+       SENSOR_ATTR_2(fan%d_input, 0444, show_bank2_value, NULL, 0, 0),
+       SENSOR_ATTR_2(fan%d_alarm, 0444, show_bank2_alarm, NULL, 0, 0),
+       SENSOR_ATTR_2(fan%d_min, 0644, show_bank2_setting,
+               store_bank2_setting, 1, 0),
+       SENSOR_ATTR_2(fan%d_beep, 0644, show_bank2_mask,
+               store_bank2_mask, ABIT_UGURU_BEEP_ENABLE, 0),
+       SENSOR_ATTR_2(fan%d_shutdown, 0644, show_bank2_mask,
+               store_bank2_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0),
+       SENSOR_ATTR_2(fan%d_alarm_enable, 0644, show_bank2_mask,
+               store_bank2_mask, ABIT_UGURU_FAN_LOW_ALARM_ENABLE, 0),
+};
+
+static const struct sensor_device_attribute_2 abituguru_sysfs_pwm_templ[6] = {
+       SENSOR_ATTR_2(pwm%d_enable, 0644, show_pwm_enable,
+               store_pwm_enable, 0, 0),
+       SENSOR_ATTR_2(pwm%d_auto_channels_temp, 0644, show_pwm_sensor,
+               store_pwm_sensor, 0, 0),
+       SENSOR_ATTR_2(pwm%d_auto_point1_pwm, 0644, show_pwm_setting,
+               store_pwm_setting, 1, 0),
+       SENSOR_ATTR_2(pwm%d_auto_point2_pwm, 0644, show_pwm_setting,
+               store_pwm_setting, 2, 0),
+       SENSOR_ATTR_2(pwm%d_auto_point1_temp, 0644, show_pwm_setting,
+               store_pwm_setting, 3, 0),
+       SENSOR_ATTR_2(pwm%d_auto_point2_temp, 0644, show_pwm_setting,
+               store_pwm_setting, 4, 0),
+};
+
+static const struct sensor_device_attribute_2 abituguru_sysfs_attr[] = {
+       SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
+};
+
+static int __devinit abituguru_probe(struct platform_device *pdev)
+{
+       struct abituguru_data *data;
+       int i, j, res;
+       char *sysfs_filename;
+       int sysfs_attr_i = 0;
+
+       /* El weirdo probe order, to keep the sysfs order identical to the
+          BIOS and window-appliction listing order. */
+       const u8 probe_order[16] = { 0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E,
+               0x02, 0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
+
+       if (!(data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL)))
+               return -ENOMEM;
+
+       data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+       mutex_init(&data->update_lock);
+       platform_set_drvdata(pdev, data);
+
+       /* See if the uGuru is ready */
+       if (inb_p(data->addr + ABIT_UGURU_DATA) == ABIT_UGURU_STATUS_INPUT)
+               data->uguru_ready = 1;
+
+       /* Completely read the uGuru this has 2 purposes:
+          - testread / see if one really is there.
+          - make an in memory copy of all the uguru settings for future use. */
+       if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
+                       data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3) {
+               kfree(data);
+               return -ENODEV;
+       }
+
+       for (i = 0; i < 16; i++) {
+               if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, i,
+                               &data->bank1_value[i], 1,
+                               ABIT_UGURU_MAX_RETRIES) != 1) {
+                       kfree(data);
+                       return -ENODEV;
+               }
+               if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1+1, i,
+                               data->bank1_settings[i], 3,
+                               ABIT_UGURU_MAX_RETRIES) != 3) {
+                       kfree(data);
+                       return -ENODEV;
+               }
+       }
+       /* Note: We don't know how many bank2 sensors / pwms there really are,
+          but in order to "detect" this we need to read the maximum amount
+          anyways. If we read sensors/pwms not there we'll just read crap
+          this can't hurt. We need the detection because we don't want
+          unwanted writes, which will hurt! */
+       for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) {
+               if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i,
+                               &data->bank2_value[i], 1,
+                               ABIT_UGURU_MAX_RETRIES) != 1) {
+                       kfree(data);
+                       return -ENODEV;
+               }
+               if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2+1, i,
+                               data->bank2_settings[i], 2,
+                               ABIT_UGURU_MAX_RETRIES) != 2) {
+                       kfree(data);
+                       return -ENODEV;
+               }
+       }
+       for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) {
+               if (abituguru_read(data, ABIT_UGURU_FAN_PWM, i,
+                               data->pwm_settings[i], 5,
+                               ABIT_UGURU_MAX_RETRIES) != 5) {
+                       kfree(data);
+                       return -ENODEV;
+               }
+       }
+       data->last_updated = jiffies;
+
+       /* Detect sensor types and fill the sysfs attr for bank1 */
+       sysfs_filename = data->bank1_names;
+       for (i = 0; i < 16; i++) {
+               res = abituguru_detect_bank1_sensor_type(data, probe_order[i]);
+               if (res < 0) {
+                       kfree(data);
+                       return -ENODEV;
+               }
+               if (res == ABIT_UGURU_NC)
+                       continue;
+
+               for (j = 0; j < (res ? 7 : 9); j++) {
+                       const char *name_templ = abituguru_sysfs_bank1_templ[
+                               res][j].dev_attr.attr.name;
+                       data->sysfs_attr[sysfs_attr_i] =
+                               abituguru_sysfs_bank1_templ[res][j];
+                       data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+                               sysfs_filename;
+                       sysfs_filename += sprintf(sysfs_filename, name_templ,
+                               data->bank1_sensors[res] + res) + 1;
+                       data->sysfs_attr[sysfs_attr_i].index = probe_order[i];
+                       sysfs_attr_i++;
+               }
+               data->bank1_max_value[probe_order[i]] =
+                       abituguru_bank1_max_value[res];
+               data->bank1_address[res][data->bank1_sensors[res]] =
+                       probe_order[i];
+               data->bank1_sensors[res]++;
+       }
+       /* Detect number of sensors and fill the sysfs attr for bank2 (fans) */
+       abituguru_detect_no_bank2_sensors(data);
+       for (i = 0; i < data->bank2_sensors; i++) {
+               for (j = 0; j < 6; j++) {
+                       const char *name_templ = abituguru_sysfs_fan_templ[j].
+                               dev_attr.attr.name;
+                       data->sysfs_attr[sysfs_attr_i] =
+                               abituguru_sysfs_fan_templ[j];
+                       data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+                               sysfs_filename;
+                       sysfs_filename += sprintf(sysfs_filename, name_templ,
+                               i + 1) + 1;
+                       data->sysfs_attr[sysfs_attr_i].index = i;
+                       sysfs_attr_i++;
+               }
+       }
+       /* Detect number of sensors and fill the sysfs attr for pwms */
+       abituguru_detect_no_pwms(data);
+       for (i = 0; i < data->pwms; i++) {
+               for (j = 0; j < 6; j++) {
+                       const char *name_templ = abituguru_sysfs_pwm_templ[j].
+                               dev_attr.attr.name;
+                       data->sysfs_attr[sysfs_attr_i] =
+                               abituguru_sysfs_pwm_templ[j];
+                       data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+                               sysfs_filename;
+                       sysfs_filename += sprintf(sysfs_filename, name_templ,
+                               i + 1) + 1;
+                       data->sysfs_attr[sysfs_attr_i].index = i;
+                       sysfs_attr_i++;
+               }
+       }
+       /* Last add any "generic" entries to sysfs */
+       for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) {
+               data->sysfs_attr[sysfs_attr_i] = abituguru_sysfs_attr[i];
+               sysfs_attr_i++;
+       }
+       printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n");
+
+       /* Register sysfs hooks */
+       data->class_dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(data->class_dev)) {
+               kfree(data);
+               return PTR_ERR(data->class_dev);
+       }
+       for (i = 0; i < sysfs_attr_i; i++)
+               device_create_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+
+       return 0;
+}
+
+static int __devexit abituguru_remove(struct platform_device *pdev)
+{
+       struct abituguru_data *data = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       hwmon_device_unregister(data->class_dev);
+       kfree(data);
+
+       return 0;
+}
+
+static struct abituguru_data *abituguru_update_device(struct device *dev)
+{
+       int i, err;
+       struct abituguru_data *data = dev_get_drvdata(dev);
+       /* fake a complete successful read if no update necessary. */
+       char success = 1;
+
+       mutex_lock(&data->update_lock);
+       if (time_after(jiffies, data->last_updated + HZ)) {
+               success = 0;
+               if ((err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0,
+                               data->alarms, 3, 0)) != 3)
+                       goto LEAVE_UPDATE;
+               for (i = 0; i < 16; i++) {
+                       if ((err = abituguru_read(data,
+                                       ABIT_UGURU_SENSOR_BANK1, i,
+                                       &data->bank1_value[i], 1, 0)) != 1)
+                               goto LEAVE_UPDATE;
+                       if ((err = abituguru_read(data,
+                                       ABIT_UGURU_SENSOR_BANK1 + 1, i,
+                                       data->bank1_settings[i], 3, 0)) != 3)
+                               goto LEAVE_UPDATE;
+               }
+               for (i = 0; i < data->bank2_sensors; i++)
+                       if ((err = abituguru_read(data,
+                                       ABIT_UGURU_SENSOR_BANK2, i,
+                                       &data->bank2_value[i], 1, 0)) != 1)
+                               goto LEAVE_UPDATE;
+               /* success! */
+               success = 1;
+               data->update_timeouts = 0;
+LEAVE_UPDATE:
+               /* handle timeout condition */
+               if (err == -EBUSY) {
+                       /* No overflow please */
+                       if (data->update_timeouts < 255u)
+                               data->update_timeouts++;
+                       if (data->update_timeouts <= ABIT_UGURU_MAX_TIMEOUTS) {
+                               ABIT_UGURU_DEBUG(3, "timeout exceeded, will "
+                                       "try again next update\n");
+                               /* Just a timeout, fake a successful read */
+                               success = 1;
+                       } else
+                               ABIT_UGURU_DEBUG(1, "timeout exceeded %d "
+                                       "times waiting for more input state\n",
+                                       (int)data->update_timeouts);
+               }
+               /* On success set last_updated */
+               if (success)
+                       data->last_updated = jiffies;
+       }
+       mutex_unlock(&data->update_lock);
+
+       if (success)
+               return data;
+       else
+               return NULL;
+}
+
+static struct platform_driver abituguru_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = ABIT_UGURU_NAME,
+       },
+       .probe  = abituguru_probe,
+       .remove = __devexit_p(abituguru_remove),
+};
+
+static int __init abituguru_detect(void)
+{
+       /* See if there is an uguru there. After a reboot uGuru will hold 0x00
+          at DATA and 0xAC, when this driver has already been loaded once
+          DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either
+          scenario but some will hold 0x00.
+          Some uGuru's initally hold 0x09 at DATA and will only hold 0x08
+          after reading CMD first, so CMD must be read first! */
+       u8 cmd_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_CMD);
+       u8 data_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_DATA);
+       if (((data_val == 0x00) || (data_val == 0x08)) &&
+           ((cmd_val == 0x00) || (cmd_val == 0xAC)))
+               return ABIT_UGURU_BASE;
+
+       ABIT_UGURU_DEBUG(2, "no Abit uGuru found, data = 0x%02X, cmd = "
+               "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
+
+       if (force) {
+               printk(KERN_INFO ABIT_UGURU_NAME ": Assuming Abit uGuru is "
+                               "present because of \"force\" parameter\n");
+               return ABIT_UGURU_BASE;
+       }
+
+       /* No uGuru found */
+       return -ENODEV;
+}
+
+static struct platform_device *abituguru_pdev;
+
+static int __init abituguru_init(void)
+{
+       int address, err;
+       struct resource res = { .flags = IORESOURCE_IO };
+
+       address = abituguru_detect();
+       if (address < 0)
+               return address;
+
+       err = platform_driver_register(&abituguru_driver);
+       if (err)
+               goto exit;
+
+       abituguru_pdev = platform_device_alloc(ABIT_UGURU_NAME, address);
+       if (!abituguru_pdev) {
+               printk(KERN_ERR ABIT_UGURU_NAME
+                       ": Device allocation failed\n");
+               err = -ENOMEM;
+               goto exit_driver_unregister;
+       }
+
+       res.start = address;
+       res.end = address + ABIT_UGURU_REGION_LENGTH - 1;
+       res.name = ABIT_UGURU_NAME;
+
+       err = platform_device_add_resources(abituguru_pdev, &res, 1);
+       if (err) {
+               printk(KERN_ERR ABIT_UGURU_NAME
+                       ": Device resource addition failed (%d)\n", err);
+               goto exit_device_put;
+       }
+
+       err = platform_device_add(abituguru_pdev);
+       if (err) {
+               printk(KERN_ERR ABIT_UGURU_NAME
+                       ": Device addition failed (%d)\n", err);
+               goto exit_device_put;
+       }
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(abituguru_pdev);
+exit_driver_unregister:
+       platform_driver_unregister(&abituguru_driver);
+exit:
+       return err;
+}
+
+static void __exit abituguru_exit(void)
+{
+       platform_device_unregister(abituguru_pdev);
+       platform_driver_unregister(&abituguru_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("Abit uGuru Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(abituguru_init);
+module_exit(abituguru_exit);