Commit f2b84bbc authored by Hans de Goede's avatar Hans de Goede Committed by Greg Kroah-Hartman

[PATCH] abituguru: New hardware monitoring driver

New hardware monitoring driver for the Abit uGuru
Signed-off-by: default avatarHans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent bed73082
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.
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.
...@@ -181,6 +181,12 @@ M: bcrl@kvack.org ...@@ -181,6 +181,12 @@ M: bcrl@kvack.org
L: linux-aio@kvack.org L: linux-aio@kvack.org
S: Supported 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 ACENIC DRIVER
P: Jes Sorensen P: Jes Sorensen
M: jes@trained-monkey.org M: jes@trained-monkey.org
......
...@@ -27,6 +27,18 @@ config HWMON_VID ...@@ -27,6 +27,18 @@ config HWMON_VID
tristate tristate
default n 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 config SENSORS_ADM1021
tristate "Analog Devices ADM1021 and compatibles" tristate "Analog Devices ADM1021 and compatibles"
depends on HWMON && I2C depends on HWMON && I2C
......
...@@ -12,6 +12,7 @@ obj-$(CONFIG_SENSORS_W83792D) += w83792d.o ...@@ -12,6 +12,7 @@ obj-$(CONFIG_SENSORS_W83792D) += w83792d.o
obj-$(CONFIG_SENSORS_W83781D) += w83781d.o obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_W83791D) += w83791d.o obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
......
/*
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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment