linux/drivers/hwmon/abituguru3.c
<<
>>
Prefs
   1/*
   2    abituguru3.c
   3
   4    Copyright (c) 2006-2008 Hans de Goede <j.w.r.degoede@hhs.nl>
   5    Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk>
   6
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 2 of the License, or
  10    (at your option) any later version.
  11
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16
  17    You should have received a copy of the GNU General Public License
  18    along with this program; if not, write to the Free Software
  19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20*/
  21/*
  22    This driver supports the sensor part of revision 3 of the custom Abit uGuru
  23    chip found on newer Abit uGuru motherboards. Note: because of lack of specs
  24    only reading the sensors and their settings is supported.
  25*/
  26#include <linux/module.h>
  27#include <linux/init.h>
  28#include <linux/slab.h>
  29#include <linux/jiffies.h>
  30#include <linux/mutex.h>
  31#include <linux/err.h>
  32#include <linux/delay.h>
  33#include <linux/platform_device.h>
  34#include <linux/hwmon.h>
  35#include <linux/hwmon-sysfs.h>
  36#include <linux/dmi.h>
  37#include <linux/io.h>
  38
  39/* uGuru3 bank addresses */
  40#define ABIT_UGURU3_SETTINGS_BANK               0x01
  41#define ABIT_UGURU3_SENSORS_BANK                0x08
  42#define ABIT_UGURU3_MISC_BANK                   0x09
  43#define ABIT_UGURU3_ALARMS_START                0x1E
  44#define ABIT_UGURU3_SETTINGS_START              0x24
  45#define ABIT_UGURU3_VALUES_START                0x80
  46#define ABIT_UGURU3_BOARD_ID                    0x0A
  47/* uGuru3 sensor bank flags */                       /* Alarm if: */
  48#define ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE      0x01 /*  temp over warn */
  49#define ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE      0x02 /*  volt over max */
  50#define ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE       0x04 /*  volt under min */
  51#define ABIT_UGURU3_TEMP_HIGH_ALARM_FLAG        0x10 /* temp is over warn */
  52#define ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG        0x20 /* volt is over max */
  53#define ABIT_UGURU3_VOLT_LOW_ALARM_FLAG         0x40 /* volt is under min */
  54#define ABIT_UGURU3_FAN_LOW_ALARM_ENABLE        0x01 /*   fan under min */
  55#define ABIT_UGURU3_BEEP_ENABLE                 0x08 /* beep if alarm */
  56#define ABIT_UGURU3_SHUTDOWN_ENABLE             0x80 /* shutdown if alarm */
  57/* sensor types */
  58#define ABIT_UGURU3_IN_SENSOR                   0
  59#define ABIT_UGURU3_TEMP_SENSOR                 1
  60#define ABIT_UGURU3_FAN_SENSOR                  2
  61
  62/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
  63   convert them to params. Determined by trial and error. I assume this is
  64   cpu-speed independent, since the ISA-bus and not the CPU should be the
  65   bottleneck. */
  66#define ABIT_UGURU3_WAIT_TIMEOUT                250
  67/* Normally the 0xAC at the end of synchronize() is reported after the
  68   first read, but sometimes not and we need to poll */
  69#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT         5
  70/* utility macros */
  71#define ABIT_UGURU3_NAME                        "abituguru3"
  72#define ABIT_UGURU3_DEBUG(format, arg...)       \
  73        if (verbose)                            \
  74                printk(KERN_DEBUG ABIT_UGURU3_NAME ": " format , ## arg)
  75
  76/* Macros to help calculate the sysfs_names array length */
  77#define ABIT_UGURU3_MAX_NO_SENSORS 26
  78/* sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
  79   in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0 */
  80#define ABIT_UGURU3_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11)
  81/* sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0,
  82   temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0,
  83   temp??_label\0 */
  84#define ABIT_UGURU3_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16 + 13)
  85/* sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0,
  86   fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0 */
  87#define ABIT_UGURU3_FAN_NAMES_LENGTH (12 + 10 + 12 + 19 + 11 + 15 + 12)
  88/* Worst case scenario 16 in sensors (longest names_length) and the rest
  89   temp sensors (second longest names_length). */
  90#define ABIT_UGURU3_SYSFS_NAMES_LENGTH (16 * ABIT_UGURU3_IN_NAMES_LENGTH + \
  91        (ABIT_UGURU3_MAX_NO_SENSORS - 16) * ABIT_UGURU3_TEMP_NAMES_LENGTH)
  92
  93/* All the macros below are named identical to the openguru2 program
  94   reverse engineered by Louis Kruger, hence the names might not be 100%
  95   logical. I could come up with better names, but I prefer keeping the names
  96   identical so that this driver can be compared with his work more easily. */
  97/* Two i/o-ports are used by uGuru */
  98#define ABIT_UGURU3_BASE                        0x00E0
  99#define ABIT_UGURU3_CMD                         0x00
 100#define ABIT_UGURU3_DATA                        0x04
 101#define ABIT_UGURU3_REGION_LENGTH               5
 102/* The wait_xxx functions return this on success and the last contents
 103   of the DATA register (0-255) on failure. */
 104#define ABIT_UGURU3_SUCCESS                     -1
 105/* uGuru status flags */
 106#define ABIT_UGURU3_STATUS_READY_FOR_READ       0x01
 107#define ABIT_UGURU3_STATUS_BUSY                 0x02
 108
 109
 110/* Structures */
 111struct abituguru3_sensor_info {
 112        const char* name;
 113        int port;
 114        int type;
 115        int multiplier;
 116        int divisor;
 117        int offset;
 118};
 119
 120/* Avoid use of flexible array members */
 121#define ABIT_UGURU3_MAX_DMI_NAMES 2
 122
 123struct abituguru3_motherboard_info {
 124        u16 id;
 125        const char *dmi_name[ABIT_UGURU3_MAX_DMI_NAMES + 1];
 126        /* + 1 -> end of sensors indicated by a sensor with name == NULL */
 127        struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1];
 128};
 129
 130/* For the Abit uGuru, we need to keep some data in memory.
 131   The structure is dynamically allocated, at the same time when a new
 132   abituguru3 device is allocated. */
 133struct abituguru3_data {
 134        struct device *hwmon_dev;       /* hwmon registered device */
 135        struct mutex update_lock;       /* protect access to data and uGuru */
 136        unsigned short addr;            /* uguru base address */
 137        char valid;                     /* !=0 if following fields are valid */
 138        unsigned long last_updated;     /* In jiffies */
 139
 140        /* For convenience the sysfs attr and their names are generated
 141           automatically. We have max 10 entries per sensor (for in sensors) */
 142        struct sensor_device_attribute_2 sysfs_attr[ABIT_UGURU3_MAX_NO_SENSORS
 143                * 10];
 144
 145        /* Buffer to store the dynamically generated sysfs names */
 146        char sysfs_names[ABIT_UGURU3_SYSFS_NAMES_LENGTH];
 147
 148        /* Pointer to the sensors info for the detected motherboard */
 149        const struct abituguru3_sensor_info *sensors;
 150
 151        /* The abituguru3 supports upto 48 sensors, and thus has registers
 152           sets for 48 sensors, for convienence reasons / simplicity of the
 153           code we always read and store all registers for all 48 sensors */
 154
 155        /* Alarms for all 48 sensors (1 bit per sensor) */
 156        u8 alarms[48/8];
 157
 158        /* Value of all 48 sensors */
 159        u8 value[48];
 160
 161        /* Settings of all 48 sensors, note in and temp sensors (the first 32
 162           sensors) have 3 bytes of settings, while fans only have 2 bytes,
 163           for convenience we use 3 bytes for all sensors */
 164        u8 settings[48][3];
 165};
 166
 167
 168/* Constants */
 169static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
 170        { 0x000C, { NULL } /* Unknown, need DMI string */, {
 171                { "CPU Core",            0, 0, 10, 1, 0 },
 172                { "DDR",                 1, 0, 10, 1, 0 },
 173                { "DDR VTT",             2, 0, 10, 1, 0 },
 174                { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
 175                { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
 176                { "MCH 2.5V",            5, 0, 20, 1, 0 },
 177                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 178                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 179                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 180                { "ATX +5V",             9, 0, 30, 1, 0 },
 181                { "+3.3V",              10, 0, 20, 1, 0 },
 182                { "5VSB",               11, 0, 30, 1, 0 },
 183                { "CPU",                24, 1, 1, 1, 0 },
 184                { "System",             25, 1, 1, 1, 0 },
 185                { "PWM",                26, 1, 1, 1, 0 },
 186                { "CPU Fan",            32, 2, 60, 1, 0 },
 187                { "NB Fan",             33, 2, 60, 1, 0 },
 188                { "SYS FAN",            34, 2, 60, 1, 0 },
 189                { "AUX1 Fan",           35, 2, 60, 1, 0 },
 190                { NULL, 0, 0, 0, 0, 0 } }
 191        },
 192        { 0x000D, { NULL } /* Abit AW8, need DMI string */, {
 193                { "CPU Core",            0, 0, 10, 1, 0 },
 194                { "DDR",                 1, 0, 10, 1, 0 },
 195                { "DDR VTT",             2, 0, 10, 1, 0 },
 196                { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
 197                { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
 198                { "MCH 2.5V",            5, 0, 20, 1, 0 },
 199                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 200                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 201                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 202                { "ATX +5V",             9, 0, 30, 1, 0 },
 203                { "+3.3V",              10, 0, 20, 1, 0 },
 204                { "5VSB",               11, 0, 30, 1, 0 },
 205                { "CPU",                24, 1, 1, 1, 0 },
 206                { "System",             25, 1, 1, 1, 0 },
 207                { "PWM1",               26, 1, 1, 1, 0 },
 208                { "PWM2",               27, 1, 1, 1, 0 },
 209                { "PWM3",               28, 1, 1, 1, 0 },
 210                { "PWM4",               29, 1, 1, 1, 0 },
 211                { "CPU Fan",            32, 2, 60, 1, 0 },
 212                { "NB Fan",             33, 2, 60, 1, 0 },
 213                { "SYS Fan",            34, 2, 60, 1, 0 },
 214                { "AUX1 Fan",           35, 2, 60, 1, 0 },
 215                { "AUX2 Fan",           36, 2, 60, 1, 0 },
 216                { "AUX3 Fan",           37, 2, 60, 1, 0 },
 217                { "AUX4 Fan",           38, 2, 60, 1, 0 },
 218                { "AUX5 Fan",           39, 2, 60, 1, 0 },
 219                { NULL, 0, 0, 0, 0, 0 } }
 220        },
 221        { 0x000E, { NULL } /* AL-8, need DMI string */, {
 222                { "CPU Core",            0, 0, 10, 1, 0 },
 223                { "DDR",                 1, 0, 10, 1, 0 },
 224                { "DDR VTT",             2, 0, 10, 1, 0 },
 225                { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
 226                { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
 227                { "MCH 2.5V",            5, 0, 20, 1, 0 },
 228                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 229                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 230                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 231                { "ATX +5V",             9, 0, 30, 1, 0 },
 232                { "+3.3V",              10, 0, 20, 1, 0 },
 233                { "5VSB",               11, 0, 30, 1, 0 },
 234                { "CPU",                24, 1, 1, 1, 0 },
 235                { "System",             25, 1, 1, 1, 0 },
 236                { "PWM",                26, 1, 1, 1, 0 },
 237                { "CPU Fan",            32, 2, 60, 1, 0 },
 238                { "NB Fan",             33, 2, 60, 1, 0 },
 239                { "SYS Fan",            34, 2, 60, 1, 0 },
 240                { NULL, 0, 0, 0, 0, 0 } }
 241        },
 242        { 0x000F, { NULL } /* Unknown, need DMI string */, {
 243
 244                { "CPU Core",            0, 0, 10, 1, 0 },
 245                { "DDR",                 1, 0, 10, 1, 0 },
 246                { "DDR VTT",             2, 0, 10, 1, 0 },
 247                { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
 248                { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
 249                { "MCH 2.5V",            5, 0, 20, 1, 0 },
 250                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 251                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 252                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 253                { "ATX +5V",             9, 0, 30, 1, 0 },
 254                { "+3.3V",              10, 0, 20, 1, 0 },
 255                { "5VSB",               11, 0, 30, 1, 0 },
 256                { "CPU",                24, 1, 1, 1, 0 },
 257                { "System",             25, 1, 1, 1, 0 },
 258                { "PWM",                26, 1, 1, 1, 0 },
 259                { "CPU Fan",            32, 2, 60, 1, 0 },
 260                { "NB Fan",             33, 2, 60, 1, 0 },
 261                { "SYS Fan",            34, 2, 60, 1, 0 },
 262                { NULL, 0, 0, 0, 0, 0 } }
 263        },
 264        { 0x0010, { NULL } /* Abit NI8 SLI GR, need DMI string */, {
 265                { "CPU Core",            0, 0, 10, 1, 0 },
 266                { "DDR",                 1, 0, 10, 1, 0 },
 267                { "DDR VTT",             2, 0, 10, 1, 0 },
 268                { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
 269                { "NB 1.4V",             4, 0, 10, 1, 0 },
 270                { "SB 1.5V",             6, 0, 10, 1, 0 },
 271                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 272                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 273                { "ATX +5V",             9, 0, 30, 1, 0 },
 274                { "+3.3V",              10, 0, 20, 1, 0 },
 275                { "5VSB",               11, 0, 30, 1, 0 },
 276                { "CPU",                24, 1, 1, 1, 0 },
 277                { "SYS",                25, 1, 1, 1, 0 },
 278                { "PWM",                26, 1, 1, 1, 0 },
 279                { "CPU Fan",            32, 2, 60, 1, 0 },
 280                { "NB Fan",             33, 2, 60, 1, 0 },
 281                { "SYS Fan",            34, 2, 60, 1, 0 },
 282                { "AUX1 Fan",           35, 2, 60, 1, 0 },
 283                { "OTES1 Fan",          36, 2, 60, 1, 0 },
 284                { NULL, 0, 0, 0, 0, 0 } }
 285        },
 286        { 0x0011, { "AT8 32X", NULL }, {
 287                { "CPU Core",            0, 0, 10, 1, 0 },
 288                { "DDR",                 1, 0, 20, 1, 0 },
 289                { "DDR VTT",             2, 0, 10, 1, 0 },
 290                { "CPU VDDA 2.5V",       6, 0, 20, 1, 0 },
 291                { "NB 1.8V",             4, 0, 10, 1, 0 },
 292                { "NB 1.8V Dual",        5, 0, 10, 1, 0 },
 293                { "HTV 1.2",             3, 0, 10, 1, 0 },
 294                { "PCIE 1.2V",          12, 0, 10, 1, 0 },
 295                { "NB 1.2V",            13, 0, 10, 1, 0 },
 296                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 297                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 298                { "ATX +5V",             9, 0, 30, 1, 0 },
 299                { "+3.3V",              10, 0, 20, 1, 0 },
 300                { "5VSB",               11, 0, 30, 1, 0 },
 301                { "CPU",                24, 1, 1, 1, 0 },
 302                { "NB",                 25, 1, 1, 1, 0 },
 303                { "System",             26, 1, 1, 1, 0 },
 304                { "PWM",                27, 1, 1, 1, 0 },
 305                { "CPU Fan",            32, 2, 60, 1, 0 },
 306                { "NB Fan",             33, 2, 60, 1, 0 },
 307                { "SYS Fan",            34, 2, 60, 1, 0 },
 308                { "AUX1 Fan",           35, 2, 60, 1, 0 },
 309                { "AUX2 Fan",           36, 2, 60, 1, 0 },
 310                { "AUX3 Fan",           37, 2, 60, 1, 0 },
 311                { NULL, 0, 0, 0, 0, 0 } }
 312        },
 313        { 0x0012, { NULL } /* Abit AN8 32X, need DMI string */, {
 314                { "CPU Core",            0, 0, 10, 1, 0 },
 315                { "DDR",                 1, 0, 20, 1, 0 },
 316                { "DDR VTT",             2, 0, 10, 1, 0 },
 317                { "HyperTransport",      3, 0, 10, 1, 0 },
 318                { "CPU VDDA 2.5V",       5, 0, 20, 1, 0 },
 319                { "NB",                  4, 0, 10, 1, 0 },
 320                { "SB",                  6, 0, 10, 1, 0 },
 321                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 322                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 323                { "ATX +5V",             9, 0, 30, 1, 0 },
 324                { "+3.3V",              10, 0, 20, 1, 0 },
 325                { "5VSB",               11, 0, 30, 1, 0 },
 326                { "CPU",                24, 1, 1, 1, 0 },
 327                { "SYS",                25, 1, 1, 1, 0 },
 328                { "PWM",                26, 1, 1, 1, 0 },
 329                { "CPU Fan",            32, 2, 60, 1, 0 },
 330                { "NB Fan",             33, 2, 60, 1, 0 },
 331                { "SYS Fan",            34, 2, 60, 1, 0 },
 332                { "AUX1 Fan",           36, 2, 60, 1, 0 },
 333                { NULL, 0, 0, 0, 0, 0 } }
 334        },
 335        { 0x0013, { NULL } /* Abit AW8D, need DMI string */, {
 336                { "CPU Core",            0, 0, 10, 1, 0 },
 337                { "DDR",                 1, 0, 10, 1, 0 },
 338                { "DDR VTT",             2, 0, 10, 1, 0 },
 339                { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
 340                { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
 341                { "MCH 2.5V",            5, 0, 20, 1, 0 },
 342                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 343                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 344                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 345                { "ATX +5V",             9, 0, 30, 1, 0 },
 346                { "+3.3V",              10, 0, 20, 1, 0 },
 347                { "5VSB",               11, 0, 30, 1, 0 },
 348                { "CPU",                24, 1, 1, 1, 0 },
 349                { "System",             25, 1, 1, 1, 0 },
 350                { "PWM1",               26, 1, 1, 1, 0 },
 351                { "PWM2",               27, 1, 1, 1, 0 },
 352                { "PWM3",               28, 1, 1, 1, 0 },
 353                { "PWM4",               29, 1, 1, 1, 0 },
 354                { "CPU Fan",            32, 2, 60, 1, 0 },
 355                { "NB Fan",             33, 2, 60, 1, 0 },
 356                { "SYS Fan",            34, 2, 60, 1, 0 },
 357                { "AUX1 Fan",           35, 2, 60, 1, 0 },
 358                { "AUX2 Fan",           36, 2, 60, 1, 0 },
 359                { "AUX3 Fan",           37, 2, 60, 1, 0 },
 360                { "AUX4 Fan",           38, 2, 60, 1, 0 },
 361                { "AUX5 Fan",           39, 2, 60, 1, 0 },
 362                { NULL, 0, 0, 0, 0, 0 } }
 363        },
 364        { 0x0014, { "AB9", "AB9 Pro", NULL }, {
 365                { "CPU Core",            0, 0, 10, 1, 0 },
 366                { "DDR",                 1, 0, 10, 1, 0 },
 367                { "DDR VTT",             2, 0, 10, 1, 0 },
 368                { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
 369                { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
 370                { "MCH 2.5V",            5, 0, 20, 1, 0 },
 371                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 372                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 373                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 374                { "ATX +5V",             9, 0, 30, 1, 0 },
 375                { "+3.3V",              10, 0, 20, 1, 0 },
 376                { "5VSB",               11, 0, 30, 1, 0 },
 377                { "CPU",                24, 1, 1, 1, 0 },
 378                { "System",             25, 1, 1, 1, 0 },
 379                { "PWM",                26, 1, 1, 1, 0 },
 380                { "CPU Fan",            32, 2, 60, 1, 0 },
 381                { "NB Fan",             33, 2, 60, 1, 0 },
 382                { "SYS Fan",            34, 2, 60, 1, 0 },
 383                { NULL, 0, 0, 0, 0, 0 } }
 384        },
 385        { 0x0015, { NULL } /* Unknown, need DMI string */, {
 386                { "CPU Core",            0, 0, 10, 1, 0 },
 387                { "DDR",                 1, 0, 20, 1, 0 },
 388                { "DDR VTT",             2, 0, 10, 1, 0 },
 389                { "HyperTransport",      3, 0, 10, 1, 0 },
 390                { "CPU VDDA 2.5V",       5, 0, 20, 1, 0 },
 391                { "NB",                  4, 0, 10, 1, 0 },
 392                { "SB",                  6, 0, 10, 1, 0 },
 393                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 394                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 395                { "ATX +5V",             9, 0, 30, 1, 0 },
 396                { "+3.3V",              10, 0, 20, 1, 0 },
 397                { "5VSB",               11, 0, 30, 1, 0 },
 398                { "CPU",                24, 1, 1, 1, 0 },
 399                { "SYS",                25, 1, 1, 1, 0 },
 400                { "PWM",                26, 1, 1, 1, 0 },
 401                { "CPU Fan",            32, 2, 60, 1, 0 },
 402                { "NB Fan",             33, 2, 60, 1, 0 },
 403                { "SYS Fan",            34, 2, 60, 1, 0 },
 404                { "AUX1 Fan",           33, 2, 60, 1, 0 },
 405                { "AUX2 Fan",           35, 2, 60, 1, 0 },
 406                { "AUX3 Fan",           36, 2, 60, 1, 0 },
 407                { NULL, 0, 0, 0, 0, 0 } }
 408        },
 409        { 0x0016, { "AW9D-MAX", NULL }, {
 410                { "CPU Core",            0, 0, 10, 1, 0 },
 411                { "DDR2",                1, 0, 20, 1, 0 },
 412                { "DDR2 VTT",            2, 0, 10, 1, 0 },
 413                { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
 414                { "MCH & PCIE 1.5V",     4, 0, 10, 1, 0 },
 415                { "MCH 2.5V",            5, 0, 20, 1, 0 },
 416                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 417                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 418                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 419                { "ATX +5V",             9, 0, 30, 1, 0 },
 420                { "+3.3V",              10, 0, 20, 1, 0 },
 421                { "5VSB",               11, 0, 30, 1, 0 },
 422                { "CPU",                24, 1, 1, 1, 0 },
 423                { "System",             25, 1, 1, 1, 0 },
 424                { "PWM1",               26, 1, 1, 1, 0 },
 425                { "PWM2",               27, 1, 1, 1, 0 },
 426                { "PWM3",               28, 1, 1, 1, 0 },
 427                { "PWM4",               29, 1, 1, 1, 0 },
 428                { "CPU Fan",            32, 2, 60, 1, 0 },
 429                { "NB Fan",             33, 2, 60, 1, 0 },
 430                { "SYS Fan",            34, 2, 60, 1, 0 },
 431                { "AUX1 Fan",           35, 2, 60, 1, 0 },
 432                { "AUX2 Fan",           36, 2, 60, 1, 0 },
 433                { "AUX3 Fan",           37, 2, 60, 1, 0 },
 434                { "OTES1 Fan",          38, 2, 60, 1, 0 },
 435                { NULL, 0, 0, 0, 0, 0 } }
 436        },
 437        { 0x0017, { NULL } /* Unknown, need DMI string */, {
 438                { "CPU Core",            0, 0, 10, 1, 0 },
 439                { "DDR2",                1, 0, 20, 1, 0 },
 440                { "DDR2 VTT",            2, 0, 10, 1, 0 },
 441                { "HyperTransport",      3, 0, 10, 1, 0 },
 442                { "CPU VDDA 2.5V",       6, 0, 20, 1, 0 },
 443                { "NB 1.8V",             4, 0, 10, 1, 0 },
 444                { "NB 1.2V ",           13, 0, 10, 1, 0 },
 445                { "SB 1.2V",             5, 0, 10, 1, 0 },
 446                { "PCIE 1.2V",          12, 0, 10, 1, 0 },
 447                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 448                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 449                { "ATX +5V",             9, 0, 30, 1, 0 },
 450                { "ATX +3.3V",          10, 0, 20, 1, 0 },
 451                { "ATX 5VSB",           11, 0, 30, 1, 0 },
 452                { "CPU",                24, 1, 1, 1, 0 },
 453                { "System",             26, 1, 1, 1, 0 },
 454                { "PWM",                27, 1, 1, 1, 0 },
 455                { "CPU FAN",            32, 2, 60, 1, 0 },
 456                { "SYS FAN",            34, 2, 60, 1, 0 },
 457                { "AUX1 FAN",           35, 2, 60, 1, 0 },
 458                { "AUX2 FAN",           36, 2, 60, 1, 0 },
 459                { "AUX3 FAN",           37, 2, 60, 1, 0 },
 460                { NULL, 0, 0, 0, 0, 0 } }
 461        },
 462        { 0x0018, { "AB9 QuadGT", NULL }, {
 463                { "CPU Core",            0, 0, 10, 1, 0 },
 464                { "DDR2",                1, 0, 20, 1, 0 },
 465                { "DDR2 VTT",            2, 0, 10, 1, 0 },
 466                { "CPU VTT",             3, 0, 10, 1, 0 },
 467                { "MCH 1.25V",           4, 0, 10, 1, 0 },
 468                { "ICHIO 1.5V",          5, 0, 10, 1, 0 },
 469                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 470                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 471                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 472                { "ATX +5V",             9, 0, 30, 1, 0 },
 473                { "+3.3V",              10, 0, 20, 1, 0 },
 474                { "5VSB",               11, 0, 30, 1, 0 },
 475                { "CPU",                24, 1, 1, 1, 0 },
 476                { "System",             25, 1, 1, 1, 0 },
 477                { "PWM Phase1",         26, 1, 1, 1, 0 },
 478                { "PWM Phase2",         27, 1, 1, 1, 0 },
 479                { "PWM Phase3",         28, 1, 1, 1, 0 },
 480                { "PWM Phase4",         29, 1, 1, 1, 0 },
 481                { "PWM Phase5",         30, 1, 1, 1, 0 },
 482                { "CPU Fan",            32, 2, 60, 1, 0 },
 483                { "SYS Fan",            34, 2, 60, 1, 0 },
 484                { "AUX1 Fan",           33, 2, 60, 1, 0 },
 485                { "AUX2 Fan",           35, 2, 60, 1, 0 },
 486                { "AUX3 Fan",           36, 2, 60, 1, 0 },
 487                { NULL, 0, 0, 0, 0, 0 } }
 488        },
 489        { 0x0019, { "IN9 32X MAX", NULL }, {
 490                { "CPU Core",            7, 0, 10, 1, 0 },
 491                { "DDR2",               13, 0, 20, 1, 0 },
 492                { "DDR2 VTT",           14, 0, 10, 1, 0 },
 493                { "CPU VTT",             3, 0, 20, 1, 0 },
 494                { "NB 1.2V",             4, 0, 10, 1, 0 },
 495                { "SB 1.5V",             6, 0, 10, 1, 0 },
 496                { "HyperTransport",      5, 0, 10, 1, 0 },
 497                { "ATX +12V (24-Pin)",  12, 0, 60, 1, 0 },
 498                { "ATX +12V (4-pin)",    8, 0, 60, 1, 0 },
 499                { "ATX +5V",             9, 0, 30, 1, 0 },
 500                { "ATX +3.3V",          10, 0, 20, 1, 0 },
 501                { "ATX 5VSB",           11, 0, 30, 1, 0 },
 502                { "CPU",                24, 1, 1, 1, 0 },
 503                { "System",             25, 1, 1, 1, 0 },
 504                { "PWM Phase1",         26, 1, 1, 1, 0 },
 505                { "PWM Phase2",         27, 1, 1, 1, 0 },
 506                { "PWM Phase3",         28, 1, 1, 1, 0 },
 507                { "PWM Phase4",         29, 1, 1, 1, 0 },
 508                { "PWM Phase5",         30, 1, 1, 1, 0 },
 509                { "CPU FAN",            32, 2, 60, 1, 0 },
 510                { "SYS FAN",            34, 2, 60, 1, 0 },
 511                { "AUX1 FAN",           33, 2, 60, 1, 0 },
 512                { "AUX2 FAN",           35, 2, 60, 1, 0 },
 513                { "AUX3 FAN",           36, 2, 60, 1, 0 },
 514                { NULL, 0, 0, 0, 0, 0 } }
 515        },
 516        { 0x001A, { "IP35 Pro", "IP35 Pro XE", NULL }, {
 517                { "CPU Core",            0, 0, 10, 1, 0 },
 518                { "DDR2",                1, 0, 20, 1, 0 },
 519                { "DDR2 VTT",            2, 0, 10, 1, 0 },
 520                { "CPU VTT 1.2V",        3, 0, 10, 1, 0 },
 521                { "MCH 1.25V",           4, 0, 10, 1, 0 },
 522                { "ICHIO 1.5V",          5, 0, 10, 1, 0 },
 523                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 524                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 525                { "ATX +12V (8-pin)",    8, 0, 60, 1, 0 },
 526                { "ATX +5V",             9, 0, 30, 1, 0 },
 527                { "+3.3V",              10, 0, 20, 1, 0 },
 528                { "5VSB",               11, 0, 30, 1, 0 },
 529                { "CPU",                24, 1, 1, 1, 0 },
 530                { "System",             25, 1, 1, 1, 0 },
 531                { "PWM",                26, 1, 1, 1, 0 },
 532                { "PWM Phase2",         27, 1, 1, 1, 0 },
 533                { "PWM Phase3",         28, 1, 1, 1, 0 },
 534                { "PWM Phase4",         29, 1, 1, 1, 0 },
 535                { "PWM Phase5",         30, 1, 1, 1, 0 },
 536                { "CPU Fan",            32, 2, 60, 1, 0 },
 537                { "SYS Fan",            34, 2, 60, 1, 0 },
 538                { "AUX1 Fan",           33, 2, 60, 1, 0 },
 539                { "AUX2 Fan",           35, 2, 60, 1, 0 },
 540                { "AUX3 Fan",           36, 2, 60, 1, 0 },
 541                { "AUX4 Fan",           37, 2, 60, 1, 0 },
 542                { NULL, 0, 0, 0, 0, 0 } }
 543        },
 544        { 0x001B, { NULL } /* Unknown, need DMI string */, {
 545                { "CPU Core",            0, 0, 10, 1, 0 },
 546                { "DDR3",                1, 0, 20, 1, 0 },
 547                { "DDR3 VTT",            2, 0, 10, 1, 0 },
 548                { "CPU VTT",             3, 0, 10, 1, 0 },
 549                { "MCH 1.25V",           4, 0, 10, 1, 0 },
 550                { "ICHIO 1.5V",          5, 0, 10, 1, 0 },
 551                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 552                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 553                { "ATX +12V (8-pin)",    8, 0, 60, 1, 0 },
 554                { "ATX +5V",             9, 0, 30, 1, 0 },
 555                { "+3.3V",              10, 0, 20, 1, 0 },
 556                { "5VSB",               11, 0, 30, 1, 0 },
 557                { "CPU",                24, 1, 1, 1, 0 },
 558                { "System",             25, 1, 1, 1, 0 },
 559                { "PWM Phase1",         26, 1, 1, 1, 0 },
 560                { "PWM Phase2",         27, 1, 1, 1, 0 },
 561                { "PWM Phase3",         28, 1, 1, 1, 0 },
 562                { "PWM Phase4",         29, 1, 1, 1, 0 },
 563                { "PWM Phase5",         30, 1, 1, 1, 0 },
 564                { "CPU Fan",            32, 2, 60, 1, 0 },
 565                { "SYS Fan",            34, 2, 60, 1, 0 },
 566                { "AUX1 Fan",           33, 2, 60, 1, 0 },
 567                { "AUX2 Fan",           35, 2, 60, 1, 0 },
 568                { "AUX3 Fan",           36, 2, 60, 1, 0 },
 569                { NULL, 0, 0, 0, 0, 0 } }
 570        },
 571        { 0x001C, { "IX38 QuadGT", NULL }, {
 572                { "CPU Core",            0, 0, 10, 1, 0 },
 573                { "DDR2",                1, 0, 20, 1, 0 },
 574                { "DDR2 VTT",            2, 0, 10, 1, 0 },
 575                { "CPU VTT",             3, 0, 10, 1, 0 },
 576                { "MCH 1.25V",           4, 0, 10, 1, 0 },
 577                { "ICHIO 1.5V",          5, 0, 10, 1, 0 },
 578                { "ICH 1.05V",           6, 0, 10, 1, 0 },
 579                { "ATX +12V (24-Pin)",   7, 0, 60, 1, 0 },
 580                { "ATX +12V (8-pin)",    8, 0, 60, 1, 0 },
 581                { "ATX +5V",             9, 0, 30, 1, 0 },
 582                { "+3.3V",              10, 0, 20, 1, 0 },
 583                { "5VSB",               11, 0, 30, 1, 0 },
 584                { "CPU",                24, 1, 1, 1, 0 },
 585                { "System",             25, 1, 1, 1, 0 },
 586                { "PWM Phase1",         26, 1, 1, 1, 0 },
 587                { "PWM Phase2",         27, 1, 1, 1, 0 },
 588                { "PWM Phase3",         28, 1, 1, 1, 0 },
 589                { "PWM Phase4",         29, 1, 1, 1, 0 },
 590                { "PWM Phase5",         30, 1, 1, 1, 0 },
 591                { "CPU Fan",            32, 2, 60, 1, 0 },
 592                { "SYS Fan",            34, 2, 60, 1, 0 },
 593                { "AUX1 Fan",           33, 2, 60, 1, 0 },
 594                { "AUX2 Fan",           35, 2, 60, 1, 0 },
 595                { "AUX3 Fan",           36, 2, 60, 1, 0 },
 596                { NULL, 0, 0, 0, 0, 0 } }
 597        },
 598        { 0x0000, { NULL }, { { NULL, 0, 0, 0, 0, 0 } } }
 599};
 600
 601
 602/* Insmod parameters */
 603static int force;
 604module_param(force, bool, 0);
 605MODULE_PARM_DESC(force, "Set to one to force detection.");
 606/* Default verbose is 1, since this driver is still in the testing phase */
 607static int verbose = 1;
 608module_param(verbose, bool, 0644);
 609MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
 610
 611
 612/* wait while the uguru is busy (usually after a write) */
 613static int abituguru3_wait_while_busy(struct abituguru3_data *data)
 614{
 615        u8 x;
 616        int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
 617
 618        while ((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
 619                        ABIT_UGURU3_STATUS_BUSY) {
 620                timeout--;
 621                if (timeout == 0)
 622                        return x;
 623                /* sleep a bit before our last try, to give the uGuru3 one
 624                   last chance to respond. */
 625                if (timeout == 1)
 626                        msleep(1);
 627        }
 628        return ABIT_UGURU3_SUCCESS;
 629}
 630
 631/* wait till uguru is ready to be read */
 632static int abituguru3_wait_for_read(struct abituguru3_data *data)
 633{
 634        u8 x;
 635        int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
 636
 637        while (!((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
 638                        ABIT_UGURU3_STATUS_READY_FOR_READ)) {
 639                timeout--;
 640                if (timeout == 0)
 641                        return x;
 642                /* sleep a bit before our last try, to give the uGuru3 one
 643                   last chance to respond. */
 644                if (timeout == 1)
 645                        msleep(1);
 646        }
 647        return ABIT_UGURU3_SUCCESS;
 648}
 649
 650/* This synchronizes us with the uGuru3's protocol state machine, this
 651   must be done before each command. */
 652static int abituguru3_synchronize(struct abituguru3_data *data)
 653{
 654        int x, timeout = ABIT_UGURU3_SYNCHRONIZE_TIMEOUT;
 655
 656        if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
 657                ABIT_UGURU3_DEBUG("synchronize timeout during initial busy "
 658                        "wait, status: 0x%02x\n", x);
 659                return -EIO;
 660        }
 661
 662        outb(0x20, data->addr + ABIT_UGURU3_DATA);
 663        if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
 664                ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x20, "
 665                        "status: 0x%02x\n", x);
 666                return -EIO;
 667        }
 668
 669        outb(0x10, data->addr + ABIT_UGURU3_CMD);
 670        if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
 671                ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x10, "
 672                        "status: 0x%02x\n", x);
 673                return -EIO;
 674        }
 675
 676        outb(0x00, data->addr + ABIT_UGURU3_CMD);
 677        if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
 678                ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x00, "
 679                        "status: 0x%02x\n", x);
 680                return -EIO;
 681        }
 682
 683        if ((x = abituguru3_wait_for_read(data)) != ABIT_UGURU3_SUCCESS) {
 684                ABIT_UGURU3_DEBUG("synchronize timeout waiting for read, "
 685                        "status: 0x%02x\n", x);
 686                return -EIO;
 687        }
 688
 689        while ((x = inb(data->addr + ABIT_UGURU3_CMD)) != 0xAC) {
 690                timeout--;
 691                if (timeout == 0) {
 692                        ABIT_UGURU3_DEBUG("synchronize timeout cmd does not "
 693                                "hold 0xAC after synchronize, cmd: 0x%02x\n",
 694                                x);
 695                        return -EIO;
 696                }
 697                msleep(1);
 698        }
 699        return 0;
 700}
 701
 702/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
 703   result in buf */
 704static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
 705        u8 count, u8 *buf)
 706{
 707        int i, x;
 708
 709        if ((x = abituguru3_synchronize(data)))
 710                return x;
 711
 712        outb(0x1A, data->addr + ABIT_UGURU3_DATA);
 713        if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
 714                ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
 715                        "sending 0x1A, status: 0x%02x\n", (unsigned int)bank,
 716                        (unsigned int)offset, x);
 717                return -EIO;
 718        }
 719
 720        outb(bank, data->addr + ABIT_UGURU3_CMD);
 721        if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
 722                ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
 723                        "sending the bank, status: 0x%02x\n",
 724                        (unsigned int)bank, (unsigned int)offset, x);
 725                return -EIO;
 726        }
 727
 728        outb(offset, data->addr + ABIT_UGURU3_CMD);
 729        if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
 730                ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
 731                        "sending the offset, status: 0x%02x\n",
 732                        (unsigned int)bank, (unsigned int)offset, x);
 733                return -EIO;
 734        }
 735
 736        outb(count, data->addr + ABIT_UGURU3_CMD);
 737        if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
 738                ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
 739                        "sending the count, status: 0x%02x\n",
 740                        (unsigned int)bank, (unsigned int)offset, x);
 741                return -EIO;
 742        }
 743
 744        for (i = 0; i < count; i++) {
 745                if ((x = abituguru3_wait_for_read(data)) !=
 746                                ABIT_UGURU3_SUCCESS) {
 747                        ABIT_UGURU3_DEBUG("timeout reading byte %d from "
 748                                "0x%02x:0x%02x, status: 0x%02x\n", i,
 749                                (unsigned int)bank, (unsigned int)offset, x);
 750                        break;
 751                }
 752                buf[i] = inb(data->addr + ABIT_UGURU3_CMD);
 753        }
 754        return i;
 755}
 756
 757/* Sensor settings are stored 1 byte per offset with the bytes
 758   placed add consecutive offsets. */
 759static int abituguru3_read_increment_offset(struct abituguru3_data *data,
 760                                            u8 bank, u8 offset, u8 count,
 761                                            u8 *buf, int offset_count)
 762{
 763        int i, x;
 764
 765        for (i = 0; i < offset_count; i++)
 766                if ((x = abituguru3_read(data, bank, offset + i, count,
 767                                buf + i * count)) != count) {
 768                        if (x < 0)
 769                                return x;
 770                        return i * count + x;
 771                }
 772
 773        return i * count;
 774}
 775
 776/* Following are the sysfs callback functions. These functions expect:
 777   sensor_device_attribute_2->index:   index into the data->sensors array
 778   sensor_device_attribute_2->nr:      register offset, bitmask or NA. */
 779static struct abituguru3_data *abituguru3_update_device(struct device *dev);
 780
 781static ssize_t show_value(struct device *dev,
 782        struct device_attribute *devattr, char *buf)
 783{
 784        int value;
 785        struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
 786        struct abituguru3_data *data = abituguru3_update_device(dev);
 787        const struct abituguru3_sensor_info *sensor;
 788
 789        if (!data)
 790                return -EIO;
 791
 792        sensor = &data->sensors[attr->index];
 793
 794        /* are we reading a setting, or is this a normal read? */
 795        if (attr->nr)
 796                value = data->settings[sensor->port][attr->nr];
 797        else
 798                value = data->value[sensor->port];
 799
 800        /* convert the value */
 801        value = (value * sensor->multiplier) / sensor->divisor +
 802                sensor->offset;
 803
 804        /* alternatively we could update the sensors settings struct for this,
 805           but then its contents would differ from the windows sw ini files */
 806        if (sensor->type == ABIT_UGURU3_TEMP_SENSOR)
 807                value *= 1000;
 808
 809        return sprintf(buf, "%d\n", value);
 810}
 811
 812static ssize_t show_alarm(struct device *dev,
 813        struct device_attribute *devattr, char *buf)
 814{
 815        int port;
 816        struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
 817        struct abituguru3_data *data = abituguru3_update_device(dev);
 818
 819        if (!data)
 820                return -EIO;
 821
 822        port = data->sensors[attr->index].port;
 823
 824        /* See if the alarm bit for this sensor is set and if a bitmask is
 825           given in attr->nr also check if the alarm matches the type of alarm
 826           we're looking for (for volt it can be either low or high). The type
 827           is stored in a few readonly bits in the settings of the sensor. */
 828        if ((data->alarms[port / 8] & (0x01 << (port % 8))) &&
 829                        (!attr->nr || (data->settings[port][0] & attr->nr)))
 830                return sprintf(buf, "1\n");
 831        else
 832                return sprintf(buf, "0\n");
 833}
 834
 835static ssize_t show_mask(struct device *dev,
 836        struct device_attribute *devattr, char *buf)
 837{
 838        struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
 839        struct abituguru3_data *data = dev_get_drvdata(dev);
 840
 841        if (data->settings[data->sensors[attr->index].port][0] & attr->nr)
 842                return sprintf(buf, "1\n");
 843        else
 844                return sprintf(buf, "0\n");
 845}
 846
 847static ssize_t show_label(struct device *dev,
 848        struct device_attribute *devattr, char *buf)
 849{
 850        struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
 851        struct abituguru3_data *data = dev_get_drvdata(dev);
 852
 853        return sprintf(buf, "%s\n", data->sensors[attr->index].name);
 854}
 855
 856static ssize_t show_name(struct device *dev,
 857        struct device_attribute *devattr, char *buf)
 858{
 859        return sprintf(buf, "%s\n", ABIT_UGURU3_NAME);
 860}
 861
 862/* Sysfs attr templates, the real entries are generated automatically. */
 863static const
 864struct sensor_device_attribute_2 abituguru3_sysfs_templ[3][10] = { {
 865        SENSOR_ATTR_2(in%d_input, 0444, show_value, NULL, 0, 0),
 866        SENSOR_ATTR_2(in%d_min, 0444, show_value, NULL, 1, 0),
 867        SENSOR_ATTR_2(in%d_max, 0444, show_value, NULL, 2, 0),
 868        SENSOR_ATTR_2(in%d_min_alarm, 0444, show_alarm, NULL,
 869                ABIT_UGURU3_VOLT_LOW_ALARM_FLAG, 0),
 870        SENSOR_ATTR_2(in%d_max_alarm, 0444, show_alarm, NULL,
 871                ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG, 0),
 872        SENSOR_ATTR_2(in%d_beep, 0444, show_mask, NULL,
 873                ABIT_UGURU3_BEEP_ENABLE, 0),
 874        SENSOR_ATTR_2(in%d_shutdown, 0444, show_mask, NULL,
 875                ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
 876        SENSOR_ATTR_2(in%d_min_alarm_enable, 0444, show_mask, NULL,
 877                ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE, 0),
 878        SENSOR_ATTR_2(in%d_max_alarm_enable, 0444, show_mask, NULL,
 879                ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE, 0),
 880        SENSOR_ATTR_2(in%d_label, 0444, show_label, NULL, 0, 0)
 881        }, {
 882        SENSOR_ATTR_2(temp%d_input, 0444, show_value, NULL, 0, 0),
 883        SENSOR_ATTR_2(temp%d_max, 0444, show_value, NULL, 1, 0),
 884        SENSOR_ATTR_2(temp%d_crit, 0444, show_value, NULL, 2, 0),
 885        SENSOR_ATTR_2(temp%d_alarm, 0444, show_alarm, NULL, 0, 0),
 886        SENSOR_ATTR_2(temp%d_beep, 0444, show_mask, NULL,
 887                ABIT_UGURU3_BEEP_ENABLE, 0),
 888        SENSOR_ATTR_2(temp%d_shutdown, 0444, show_mask, NULL,
 889                ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
 890        SENSOR_ATTR_2(temp%d_alarm_enable, 0444, show_mask, NULL,
 891                ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE, 0),
 892        SENSOR_ATTR_2(temp%d_label, 0444, show_label, NULL, 0, 0)
 893        }, {
 894        SENSOR_ATTR_2(fan%d_input, 0444, show_value, NULL, 0, 0),
 895        SENSOR_ATTR_2(fan%d_min, 0444, show_value, NULL, 1, 0),
 896        SENSOR_ATTR_2(fan%d_alarm, 0444, show_alarm, NULL, 0, 0),
 897        SENSOR_ATTR_2(fan%d_beep, 0444, show_mask, NULL,
 898                ABIT_UGURU3_BEEP_ENABLE, 0),
 899        SENSOR_ATTR_2(fan%d_shutdown, 0444, show_mask, NULL,
 900                ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
 901        SENSOR_ATTR_2(fan%d_alarm_enable, 0444, show_mask, NULL,
 902                ABIT_UGURU3_FAN_LOW_ALARM_ENABLE, 0),
 903        SENSOR_ATTR_2(fan%d_label, 0444, show_label, NULL, 0, 0)
 904} };
 905
 906static struct sensor_device_attribute_2 abituguru3_sysfs_attr[] = {
 907        SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
 908};
 909
 910static int __devinit abituguru3_probe(struct platform_device *pdev)
 911{
 912        const int no_sysfs_attr[3] = { 10, 8, 7 };
 913        int sensor_index[3] = { 0, 1, 1 };
 914        struct abituguru3_data *data;
 915        int i, j, type, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
 916        char *sysfs_filename;
 917        u8 buf[2];
 918        u16 id;
 919
 920        if (!(data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL)))
 921                return -ENOMEM;
 922
 923        data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
 924        mutex_init(&data->update_lock);
 925        platform_set_drvdata(pdev, data);
 926
 927        /* Read the motherboard ID */
 928        if ((i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK,
 929                        ABIT_UGURU3_BOARD_ID, 2, buf)) != 2) {
 930                goto abituguru3_probe_error;
 931        }
 932
 933        /* Completely read the uGuru to see if one really is there */
 934        if (!abituguru3_update_device(&pdev->dev))
 935                goto abituguru3_probe_error;
 936
 937        /* lookup the ID in our motherboard table */
 938        id = ((u16)buf[0] << 8) | (u16)buf[1];
 939        for (i = 0; abituguru3_motherboards[i].id; i++)
 940                if (abituguru3_motherboards[i].id == id)
 941                        break;
 942        if (!abituguru3_motherboards[i].id) {
 943                printk(KERN_ERR ABIT_UGURU3_NAME ": error unknown motherboard "
 944                        "ID: %04X. Please report this to the abituguru3 "
 945                        "maintainer (see MAINTAINERS)\n", (unsigned int)id);
 946                goto abituguru3_probe_error;
 947        }
 948        data->sensors = abituguru3_motherboards[i].sensors;
 949
 950        printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard "
 951                "ID: %04X\n", (unsigned int)id);
 952
 953        /* Fill the sysfs attr array */
 954        sysfs_attr_i = 0;
 955        sysfs_filename = data->sysfs_names;
 956        sysfs_names_free = ABIT_UGURU3_SYSFS_NAMES_LENGTH;
 957        for (i = 0; data->sensors[i].name; i++) {
 958                /* Fail safe check, this should never happen! */
 959                if (i >= ABIT_UGURU3_MAX_NO_SENSORS) {
 960                        printk(KERN_ERR ABIT_UGURU3_NAME
 961                                ": Fatal error motherboard has more sensors "
 962                                "then ABIT_UGURU3_MAX_NO_SENSORS. This should "
 963                                "never happen please report to the abituguru3 "
 964                                "maintainer (see MAINTAINERS)\n");
 965                        res = -ENAMETOOLONG;
 966                        goto abituguru3_probe_error;
 967                }
 968                type = data->sensors[i].type;
 969                for (j = 0; j < no_sysfs_attr[type]; j++) {
 970                        used = snprintf(sysfs_filename, sysfs_names_free,
 971                                abituguru3_sysfs_templ[type][j].dev_attr.attr.
 972                                name, sensor_index[type]) + 1;
 973                        data->sysfs_attr[sysfs_attr_i] =
 974                                abituguru3_sysfs_templ[type][j];
 975                        data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
 976                                sysfs_filename;
 977                        data->sysfs_attr[sysfs_attr_i].index = i;
 978                        sysfs_filename += used;
 979                        sysfs_names_free -= used;
 980                        sysfs_attr_i++;
 981                }
 982                sensor_index[type]++;
 983        }
 984        /* Fail safe check, this should never happen! */
 985        if (sysfs_names_free < 0) {
 986                printk(KERN_ERR ABIT_UGURU3_NAME
 987                        ": Fatal error ran out of space for sysfs attr names. "
 988                        "This should never happen please report to the "
 989                        "abituguru3 maintainer (see MAINTAINERS)\n");
 990                res = -ENAMETOOLONG;
 991                goto abituguru3_probe_error;
 992        }
 993
 994        /* Register sysfs hooks */
 995        for (i = 0; i < sysfs_attr_i; i++)
 996                if (device_create_file(&pdev->dev,
 997                                &data->sysfs_attr[i].dev_attr))
 998                        goto abituguru3_probe_error;
 999        for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
1000                if (device_create_file(&pdev->dev,
1001                                &abituguru3_sysfs_attr[i].dev_attr))
1002                        goto abituguru3_probe_error;
1003
1004        data->hwmon_dev = hwmon_device_register(&pdev->dev);
1005        if (IS_ERR(data->hwmon_dev)) {
1006                res = PTR_ERR(data->hwmon_dev);
1007                goto abituguru3_probe_error;
1008        }
1009
1010        return 0; /* success */
1011
1012abituguru3_probe_error:
1013        for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
1014                device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
1015        for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
1016                device_remove_file(&pdev->dev,
1017                        &abituguru3_sysfs_attr[i].dev_attr);
1018        kfree(data);
1019        return res;
1020}
1021
1022static int __devexit abituguru3_remove(struct platform_device *pdev)
1023{
1024        int i;
1025        struct abituguru3_data *data = platform_get_drvdata(pdev);
1026
1027        platform_set_drvdata(pdev, NULL);
1028        hwmon_device_unregister(data->hwmon_dev);
1029        for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
1030                device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
1031        for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
1032                device_remove_file(&pdev->dev,
1033                        &abituguru3_sysfs_attr[i].dev_attr);
1034        kfree(data);
1035
1036        return 0;
1037}
1038
1039static struct abituguru3_data *abituguru3_update_device(struct device *dev)
1040{
1041        int i;
1042        struct abituguru3_data *data = dev_get_drvdata(dev);
1043
1044        mutex_lock(&data->update_lock);
1045        if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
1046                /* Clear data->valid while updating */
1047                data->valid = 0;
1048                /* Read alarms */
1049                if (abituguru3_read_increment_offset(data,
1050                                ABIT_UGURU3_SETTINGS_BANK,
1051                                ABIT_UGURU3_ALARMS_START,
1052                                1, data->alarms, 48/8) != (48/8))
1053                        goto LEAVE_UPDATE;
1054                /* Read in and temp sensors (3 byte settings / sensor) */
1055                for (i = 0; i < 32; i++) {
1056                        if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
1057                                        ABIT_UGURU3_VALUES_START + i,
1058                                        1, &data->value[i]) != 1)
1059                                goto LEAVE_UPDATE;
1060                        if (abituguru3_read_increment_offset(data,
1061                                        ABIT_UGURU3_SETTINGS_BANK,
1062                                        ABIT_UGURU3_SETTINGS_START + i * 3,
1063                                        1,
1064                                        data->settings[i], 3) != 3)
1065                                goto LEAVE_UPDATE;
1066                }
1067                /* Read temp sensors (2 byte settings / sensor) */
1068                for (i = 0; i < 16; i++) {
1069                        if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
1070                                        ABIT_UGURU3_VALUES_START + 32 + i,
1071                                        1, &data->value[32 + i]) != 1)
1072                                goto LEAVE_UPDATE;
1073                        if (abituguru3_read_increment_offset(data,
1074                                        ABIT_UGURU3_SETTINGS_BANK,
1075                                        ABIT_UGURU3_SETTINGS_START + 32 * 3 +
1076                                                i * 2, 1,
1077                                        data->settings[32 + i], 2) != 2)
1078                                goto LEAVE_UPDATE;
1079                }
1080                data->last_updated = jiffies;
1081                data->valid = 1;
1082        }
1083LEAVE_UPDATE:
1084        mutex_unlock(&data->update_lock);
1085        if (data->valid)
1086                return data;
1087        else
1088                return NULL;
1089}
1090
1091#ifdef CONFIG_PM
1092static int abituguru3_suspend(struct platform_device *pdev, pm_message_t state)
1093{
1094        struct abituguru3_data *data = platform_get_drvdata(pdev);
1095        /* make sure all communications with the uguru3 are done and no new
1096           ones are started */
1097        mutex_lock(&data->update_lock);
1098        return 0;
1099}
1100
1101static int abituguru3_resume(struct platform_device *pdev)
1102{
1103        struct abituguru3_data *data = platform_get_drvdata(pdev);
1104        mutex_unlock(&data->update_lock);
1105        return 0;
1106}
1107#else
1108#define abituguru3_suspend      NULL
1109#define abituguru3_resume       NULL
1110#endif /* CONFIG_PM */
1111
1112static struct platform_driver abituguru3_driver = {
1113        .driver = {
1114                .owner  = THIS_MODULE,
1115                .name   = ABIT_UGURU3_NAME,
1116        },
1117        .probe  = abituguru3_probe,
1118        .remove = __devexit_p(abituguru3_remove),
1119        .suspend = abituguru3_suspend,
1120        .resume = abituguru3_resume
1121};
1122
1123#ifdef CONFIG_DMI
1124
1125static int __init abituguru3_dmi_detect(void)
1126{
1127        const char *board_vendor, *board_name;
1128        int i, err = (force) ? 1 : -ENODEV;
1129        const char *const *dmi_name;
1130        size_t sublen;
1131
1132        board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
1133        if (!board_vendor || strcmp(board_vendor, "http://www.abit.com.tw/"))
1134                return err;
1135
1136        board_name = dmi_get_system_info(DMI_BOARD_NAME);
1137        if (!board_name)
1138                return err;
1139
1140        /* At the moment, we don't care about the part of the vendor
1141         * DMI string contained in brackets. Truncate the string at
1142         * the first occurrence of a bracket. Trim any trailing space
1143         * from the substring.
1144         */
1145        sublen = strcspn(board_name, "(");
1146        while (sublen > 0 && board_name[sublen - 1] == ' ')
1147                sublen--;
1148
1149        for (i = 0; abituguru3_motherboards[i].id; i++) {
1150                dmi_name = abituguru3_motherboards[i].dmi_name;
1151                for ( ; *dmi_name; dmi_name++) {
1152                        if (strlen(*dmi_name) != sublen)
1153                                continue;
1154                        if (!strncasecmp(board_name, *dmi_name, sublen))
1155                                return 0;
1156                }
1157        }
1158
1159        /* No match found */
1160        return 1;
1161}
1162
1163#else /* !CONFIG_DMI */
1164
1165static inline int abituguru3_dmi_detect(void)
1166{
1167        return 1;
1168}
1169
1170#endif /* CONFIG_DMI */
1171
1172/* FIXME: Manual detection should die eventually; we need to collect stable
1173 *        DMI model names first before we can rely entirely on CONFIG_DMI.
1174 */
1175
1176static int __init abituguru3_detect(void)
1177{
1178        /* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
1179           0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
1180           or 0x55 at CMD instead, why is unknown. */
1181        u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
1182        u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
1183        if (((data_val == 0x00) || (data_val == 0x08)) &&
1184                        ((cmd_val == 0xAC) || (cmd_val == 0x05) ||
1185                         (cmd_val == 0x55)))
1186                return 0;
1187
1188        ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = "
1189                "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
1190
1191        if (force) {
1192                printk(KERN_INFO ABIT_UGURU3_NAME ": Assuming Abit uGuru3 is "
1193                                "present because of \"force\" parameter\n");
1194                return 0;
1195        }
1196
1197        /* No uGuru3 found */
1198        return -ENODEV;
1199}
1200
1201static struct platform_device *abituguru3_pdev;
1202
1203static int __init abituguru3_init(void)
1204{
1205        struct resource res = { .flags = IORESOURCE_IO };
1206        int err;
1207
1208        /* Attempt DMI detection first */
1209        err = abituguru3_dmi_detect();
1210        if (err < 0)
1211                return err;
1212
1213        /* Fall back to manual detection if there was no exact
1214         * board name match, or force was specified.
1215         */
1216        if (err > 0) {
1217                err = abituguru3_detect();
1218                if (err)
1219                        return err;
1220
1221#ifdef CONFIG_DMI
1222                printk(KERN_WARNING ABIT_UGURU3_NAME ": this motherboard was "
1223                        "not detected using DMI. Please send the output of "
1224                        "\"dmidecode\" to the abituguru3 maintainer "
1225                        "(see MAINTAINERS)\n");
1226#endif
1227        }
1228
1229        err = platform_driver_register(&abituguru3_driver);
1230        if (err)
1231                goto exit;
1232
1233        abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME,
1234                                                ABIT_UGURU3_BASE);
1235        if (!abituguru3_pdev) {
1236                printk(KERN_ERR ABIT_UGURU3_NAME
1237                        ": Device allocation failed\n");
1238                err = -ENOMEM;
1239                goto exit_driver_unregister;
1240        }
1241
1242        res.start = ABIT_UGURU3_BASE;
1243        res.end = ABIT_UGURU3_BASE + ABIT_UGURU3_REGION_LENGTH - 1;
1244        res.name = ABIT_UGURU3_NAME;
1245
1246        err = platform_device_add_resources(abituguru3_pdev, &res, 1);
1247        if (err) {
1248                printk(KERN_ERR ABIT_UGURU3_NAME
1249                        ": Device resource addition failed (%d)\n", err);
1250                goto exit_device_put;
1251        }
1252
1253        err = platform_device_add(abituguru3_pdev);
1254        if (err) {
1255                printk(KERN_ERR ABIT_UGURU3_NAME
1256                        ": Device addition failed (%d)\n", err);
1257                goto exit_device_put;
1258        }
1259
1260        return 0;
1261
1262exit_device_put:
1263        platform_device_put(abituguru3_pdev);
1264exit_driver_unregister:
1265        platform_driver_unregister(&abituguru3_driver);
1266exit:
1267        return err;
1268}
1269
1270static void __exit abituguru3_exit(void)
1271{
1272        platform_device_unregister(abituguru3_pdev);
1273        platform_driver_unregister(&abituguru3_driver);
1274}
1275
1276MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
1277MODULE_DESCRIPTION("Abit uGuru3 Sensor device");
1278MODULE_LICENSE("GPL");
1279
1280module_init(abituguru3_init);
1281module_exit(abituguru3_exit);
1282