mirror of
https://github.com/lm-sensors/lm-sensors.git
synced 2026-10-31 13:10:30 +00:00
(Phil) Added Fons Rademakers' <Fons.Rademakers@cern.ch> MaxiLife driver.
I've reviewed and applied the patch, but I would like some others to review these commits too, to be safe. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@327 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
1 parent
0900fb64bf
commit
1ac215f6a1
9 files changed
+1172
-1
No files matched your search
@@ -322,3 +322,52 @@ chip "lm80-*"
|
||||
set in5_max -12 * 1.05
|
||||
set in6_min -5 * 0.95
|
||||
set in6_max -5 * 1.05
|
||||
|
||||
|
||||
chip "maxilife-cg-*" "maxilife-co-*" "maxilife-as-*"
|
||||
|
||||
label fan1 "HDD Fan"
|
||||
label fan2 "PCI Fan"
|
||||
label fan3 "CPU Fan"
|
||||
|
||||
label temp2 "PCI Temp"
|
||||
label temp4 "HDD Temp"
|
||||
label temp5 "CPU Temp"
|
||||
|
||||
label vid1 "V+12"
|
||||
|
||||
# vid1 need to be scaled by 6.337 other voltages
|
||||
# require no scaling
|
||||
|
||||
compute vid1 6.337*@ , @/6.337
|
||||
|
||||
|
||||
chip "maxilife-cg-*"
|
||||
|
||||
# invalid temp1
|
||||
label temp3 "BX Temp"
|
||||
|
||||
label vid2 "Vcpu1"
|
||||
label vid3 "Vcpu2"
|
||||
# invalid vid4
|
||||
|
||||
|
||||
chip "maxilife-co-*"
|
||||
|
||||
label temp1 "CPU 1 Temp"
|
||||
label temp3 "CPU 2 Temp"
|
||||
|
||||
label vid2 "Vcpu1"
|
||||
label vid3 "Vcpu2"
|
||||
label vid4 "VcacheL2"
|
||||
|
||||
|
||||
chip "maxilife-as-*"
|
||||
|
||||
# invalid temp1
|
||||
# invalid temp3
|
||||
|
||||
label vid2 "Vcpu"
|
||||
# invalid vid3
|
||||
# invalid vid4
|
||||
|
||||
@@ -27,7 +27,7 @@ KERNELCHIPSTARGETS := $(MODULE_DIR)/adm1021.o $(MODULE_DIR)/adm9240.o \
|
||||
$(MODULE_DIR)/lm75.o $(MODULE_DIR)/lm78.o \
|
||||
$(MODULE_DIR)/lm80.o $(MODULE_DIR)/ltc1710.o \
|
||||
$(MODULE_DIR)/w83781d.o $(MODULE_DIR)/sis5595.o \
|
||||
$(MODULE_DIR)/icspll.o
|
||||
$(MODULE_DIR)/icspll.o $(MODULE_DIR)/maxilife.o
|
||||
|
||||
# Include all dependency files
|
||||
INCLUDEFILES += $(KERNELCHIPSTARGETS:.o=.d)
|
||||
|
||||
@@ -0,0 +1,747 @@
|
||||
/*
|
||||
maxilife.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 1999 Fons Rademakers <Fons.Rademakers@cern.ch>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* The is the driver for the HP MaxiLife Health monitoring system
|
||||
as used in the line of HP Kayak Workstation PC's.
|
||||
|
||||
The driver supports the following MaxiLife firmware versions:
|
||||
|
||||
0) HP KAYAK XU/XAs (Dual Pentium II Slot 1, Deschutes/Klamath)
|
||||
1) HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz)
|
||||
2) HP KAYAK XA (Pentium II Slot 1, monoprocessor)
|
||||
|
||||
Currently firmware auto detection is not implemented. To use the
|
||||
driver load it with the correct option for you Kayak. For example:
|
||||
|
||||
insmod maxilife.o maxi_version=0 | 1 | 2
|
||||
|
||||
maxi_version=0 is the default
|
||||
*/
|
||||
|
||||
static const char *version = "1.00 25/2/99 Fons Rademakers";
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/malloc.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/types.h>
|
||||
#include "smbus.h"
|
||||
#include "version.h"
|
||||
#include "sensors.h"
|
||||
#include "i2c.h"
|
||||
#include "compat.h"
|
||||
|
||||
|
||||
/*#define AUTODETECT /* try to autodetect MaxiLife version */
|
||||
#define NOWRITE /* don't allow writing to MaxiLife registers */
|
||||
|
||||
|
||||
/* The MaxiLife registers */
|
||||
#define MAXI_REG_TEMP(nr) (0x60 + (nr))
|
||||
|
||||
#define MAXI_REG_FAN(nr) (0x65 + (nr))
|
||||
#define MAXI_REG_FAN_MIN(nr) ((nr)==0 ? 0xb3 : (nr)==1 ? 0xb3 : 0xab)
|
||||
#define MAXI_REG_FAN_MINAS(nr) ((nr)==0 ? 0xb3 : (nr)==1 ? 0xab : 0xb3)
|
||||
#define MAXI_REG_FAN_SPEED(nr) ((nr)==0 ? 0xe4 : (nr)==1 ? 0xe5 : 0xe9)
|
||||
|
||||
#define MAXI_REG_PLL 0xb9
|
||||
#define MAXI_REG_PLL_MIN 0xba
|
||||
#define MAXI_REG_PLL_MAX 0xbb
|
||||
|
||||
#define MAXI_REG_VID(nr) ((nr)==0 ? 0xd1 : (nr)==1 ? 0xd9 : \
|
||||
(nr)==2 ? 0xd4 : 0xc5)
|
||||
#define MAXI_REG_VID_MIN(nr) MAXI_REG_VID(nr)+1
|
||||
#define MAXI_REG_VID_MAX(nr) MAXI_REG_VID(nr)+2
|
||||
|
||||
#define MAXI_REG_DIAG_RT1 0x2c
|
||||
#define MAXI_REG_DIAG_RT2 0x2d
|
||||
|
||||
#define MAXI_REG_BIOS_CTRL 0x2a
|
||||
#define MAXI_REG_LED_STATE 0x96
|
||||
|
||||
/* Conversions */
|
||||
/* 0xfe: fan off, 0xff: stopped (alarm) */
|
||||
/* 19531 / val * 60 == 1171860 / val */
|
||||
#define FAN_FROM_REG(val) ((val)==0xfe ? -1 : (val)==0xff ? 0 : \
|
||||
(1171860 / (val)))
|
||||
#define FAN_TO_REG(val) (1171860 / (val))
|
||||
|
||||
#define TEMP_FROM_REG(val) ((val) * 5)
|
||||
#define TEMP_TO_REG(val) ((val) / 5)
|
||||
#define PLL_FROM_REG(val) (((val) * 1000) / 32)
|
||||
#define PLL_TO_REG(val) (((val) * 32) / 1000)
|
||||
#define VID_FROM_REG(val) ((val) ? (((val) * 27390) / 256) + 3208 : 0)
|
||||
#define VID_TO_REG(val) ((((val) - 3208) * 256) / 27390)
|
||||
#define ALARMS_FROM_REG(val) (val)
|
||||
|
||||
|
||||
|
||||
#ifdef MODULE
|
||||
extern int init_module(void);
|
||||
extern int cleanup_module(void);
|
||||
#endif /* MODULE */
|
||||
|
||||
/* The following product codenames apply:
|
||||
Cristal/Geronimo: HP KAYAK XU/XAs
|
||||
(Dual Pentium II Slot 1, Deschutes/Klamath)
|
||||
Cognac: HP KAYAK XU (Dual Xeon [Slot 2] 400/450 Mhz)
|
||||
Ashaki: HP KAYAK XA (Pentium II Slot 1, monoprocessor) */
|
||||
|
||||
enum maxi_type { cristal, cognac, ashaki };
|
||||
|
||||
/* For each registered MaxiLife controller, we need to keep some data in
|
||||
memory. That data is pointed to by maxi_list[NR]->data. The structure
|
||||
itself is dynamically allocated, at the same time when a new MaxiLife
|
||||
client is allocated. We assume MaxiLife will only be present on the
|
||||
SMBus and not on the ISA bus. */
|
||||
struct maxi_data {
|
||||
struct semaphore lock;
|
||||
int sysctl_id;
|
||||
enum maxi_type type;
|
||||
|
||||
struct semaphore update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
u8 fan[3]; /* Register value */
|
||||
u8 fan_min[3]; /* Register value */
|
||||
u8 fan_speed[3]; /* Register value */
|
||||
u8 fan_div[3]; /* Static value */
|
||||
u8 temp[5]; /* Register value */
|
||||
u8 temp_max[5]; /* Static value */
|
||||
u8 temp_hyst[5]; /* Static value */
|
||||
u8 pll; /* Register value */
|
||||
u8 pll_min; /* Register value */
|
||||
u8 pll_max; /* register value */
|
||||
u8 vid[4]; /* Register value */
|
||||
u8 vid_min[4]; /* Register value */
|
||||
u8 vid_max[4]; /* Register value */
|
||||
u16 alarms; /* Register encoding, combined */
|
||||
};
|
||||
|
||||
|
||||
static int maxi_init(void);
|
||||
static int maxi_cleanup(void);
|
||||
|
||||
static int maxi_attach_adapter(struct i2c_adapter *adapter);
|
||||
static int maxi_detect_smbus(struct i2c_adapter *adapter);
|
||||
static int maxi_detach_client(struct i2c_client *client);
|
||||
static int maxi_detach_smbus(struct i2c_client *client);
|
||||
static int maxi_new_client(struct i2c_adapter *adapter,
|
||||
struct i2c_client *new_client);
|
||||
static void maxi_remove_client(struct i2c_client *client);
|
||||
static int maxi_command(struct i2c_client *client, unsigned int cmd,
|
||||
void *arg);
|
||||
static void maxi_inc_use (struct i2c_client *client);
|
||||
static void maxi_dec_use (struct i2c_client *client);
|
||||
|
||||
static int maxi_read_value(struct i2c_client *client, u8 register);
|
||||
static int maxi_write_value(struct i2c_client *client, u8 register, u8 value);
|
||||
static void maxi_update_client(struct i2c_client *client);
|
||||
static void maxi_init_client(struct i2c_client *client);
|
||||
|
||||
static void maxi_fan(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results);
|
||||
static void maxi_temp(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results);
|
||||
static void maxi_pll(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results);
|
||||
static void maxi_vid(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results);
|
||||
static void maxi_alarms(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results);
|
||||
|
||||
|
||||
/* I choose here for semi-static MaxiLife allocation. Complete dynamic
|
||||
allocation could also be used; the code needed for this would probably
|
||||
take more memory than the datastructure takes now. */
|
||||
#define MAX_MAXI_NR 4
|
||||
static struct i2c_client *maxi_list[MAX_MAXI_NR];
|
||||
|
||||
/* The driver. I choose to use type i2c_driver, as at is identical to
|
||||
the smbus_driver. */
|
||||
static struct i2c_driver maxi_driver = {
|
||||
/* name */ "HP MaxiLife driver",
|
||||
/* id */ I2C_DRIVERID_MAXILIFE,
|
||||
/* flags */ DF_NOTIFY,
|
||||
/* attach_adapter */ &maxi_attach_adapter,
|
||||
/* detach_client */ &maxi_detach_client,
|
||||
/* command */ &maxi_command,
|
||||
/* inc_use */ &maxi_inc_use,
|
||||
/* dec_use */ &maxi_dec_use
|
||||
};
|
||||
|
||||
/* Used by maxi_init/cleanup */
|
||||
static int maxi_initialized = 0;
|
||||
|
||||
/* Default firmware version. Use module option "maxi_version"
|
||||
to set desired version. Auto detect is not yet working */
|
||||
static int maxi_version = cristal;
|
||||
|
||||
/* The /proc/sys entries */
|
||||
/* These files are created for each detected MaxiLife processor.
|
||||
This is just a template; though at first sight, you might think we
|
||||
could use a statically allocated list, we need some way to get back
|
||||
to the parent - which is done through one of the 'extra' fields
|
||||
which are initialized when a new copy is allocated. */
|
||||
static ctl_table maxi_dir_table_template[] = {
|
||||
{ MAXI_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_fan },
|
||||
{ MAXI_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_fan },
|
||||
{ MAXI_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_fan },
|
||||
{ MAXI_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_temp },
|
||||
{ MAXI_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_temp },
|
||||
{ MAXI_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_temp },
|
||||
{ MAXI_SYSCTL_TEMP4, "temp4", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_temp },
|
||||
{ MAXI_SYSCTL_TEMP5, "temp5", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_temp },
|
||||
{ MAXI_SYSCTL_PLL, "pll", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_pll },
|
||||
{ MAXI_SYSCTL_VID1, "vid1", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_vid },
|
||||
{ MAXI_SYSCTL_VID2, "vid2", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_vid },
|
||||
{ MAXI_SYSCTL_VID3, "vid3", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_vid },
|
||||
{ MAXI_SYSCTL_VID4, "vid4", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_vid },
|
||||
{ MAXI_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real,
|
||||
&sensors_sysctl_real, NULL, &maxi_alarms },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* This function is called when:
|
||||
- maxi_driver is inserted (when this module is loaded), for each
|
||||
available adapter
|
||||
- when a new adapter is inserted (and maxi_driver is still present) */
|
||||
int maxi_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
return maxi_detect_smbus(adapter);
|
||||
}
|
||||
|
||||
/* This function is called whenever a client should be removed:
|
||||
- maxi_driver is removed (when this module is unloaded)
|
||||
- when an adapter is removed which has a maxi client (and maxi_driver
|
||||
is still present). */
|
||||
int maxi_detach_client(struct i2c_client *client)
|
||||
{
|
||||
return maxi_detach_smbus(client);
|
||||
}
|
||||
|
||||
int maxi_detect_smbus(struct i2c_adapter *adapter)
|
||||
{
|
||||
u8 biosctl;
|
||||
int address, err;
|
||||
struct i2c_client *new_client;
|
||||
enum maxi_type type;
|
||||
const char *type_name, *client_name;
|
||||
|
||||
/* OK, this is no detection. I know. It will do for now, though. */
|
||||
err = 0;
|
||||
for (address = 0x10; (! err) && (address <= 0x14); address++) {
|
||||
|
||||
/* Later on, we will keep a list of registered addresses for each
|
||||
adapter, and check whether they are used here */
|
||||
|
||||
if (smbus_read_byte_data(adapter, address, MAXI_REG_LED_STATE) < 0)
|
||||
continue;
|
||||
|
||||
#ifdef AUTODETECT
|
||||
/* The right way to get the platform info is to read the firmware
|
||||
revision from serial EEPROM (addr=0x54), at offset 0x0045.
|
||||
This is a string as:
|
||||
"CG 00.04" -> Cristal [XU] / Geronimo [XAs]
|
||||
"CO 00.03" -> Cognac [XU]
|
||||
"AS 00.01" -> Ashaki [XA] */
|
||||
biosctl = smbus_read_byte_data(adapter, address, MAXI_REG_BIOS_CTRL);
|
||||
smbus_write_byte_data(adapter, address, MAXI_REG_BIOS_CTRL, biosctl|4);
|
||||
err = eeprom_read_byte_data(adapter, 0x54, 0x45);
|
||||
smbus_write_byte_data(adapter, address, MAXI_REG_BIOS_CTRL, biosctl);
|
||||
#endif
|
||||
|
||||
if (maxi_version == cristal) {
|
||||
type = cristal;
|
||||
type_name = "maxilife-cg";
|
||||
client_name = "HP MaxiLife Rev CG 00.04";
|
||||
printk("maxilife: HP KAYAK XU/XAs (Dual Pentium II Slot 1)\n");
|
||||
} else if (maxi_version == cognac) {
|
||||
type = cognac;
|
||||
type_name = "maxilife-co";
|
||||
client_name = "HP MaxiLife Rev CO 00.03";
|
||||
printk("maxilife: HP KAYAK XU (Dual Xeon Slot 2 400/450 Mhz)\n");
|
||||
} else if (maxi_version == ashaki) {
|
||||
type = ashaki;
|
||||
type_name = "maxilife-as";
|
||||
client_name = "HP MaxiLife Rev AS 00.01";
|
||||
printk("maxilife: HP KAYAK XA (Pentium II Slot 1, monoprocessor)\n");
|
||||
} else {
|
||||
#if AUTODETECT
|
||||
printk("maxilife: Warning: probed non-maxilife chip?!? (%x)\n", err);
|
||||
#else
|
||||
printk("maxilife: Error: specified wrong maxi_version (%d)\n",
|
||||
maxi_version);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Allocate space for a new client structure. To counter memory
|
||||
fragmentation somewhat, we only do one kmalloc. */
|
||||
if (! (new_client = kmalloc(sizeof(struct i2c_client) +
|
||||
sizeof(struct maxi_data),
|
||||
GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fill the new client structure with data */
|
||||
new_client->data = (struct maxi_data *) (new_client + 1);
|
||||
new_client->addr = address;
|
||||
strcpy(new_client->name, client_name);
|
||||
((struct maxi_data *) (new_client->data))->type = type;
|
||||
if ((err = maxi_new_client(adapter, new_client)))
|
||||
goto ERROR2;
|
||||
|
||||
/* Tell i2c-core a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
goto ERROR3;
|
||||
|
||||
/* Register a new directory entry with module sensors */
|
||||
if ((err = sensors_register_entry(new_client, type_name,
|
||||
maxi_dir_table_template)) < 0)
|
||||
goto ERROR4;
|
||||
((struct maxi_data *) (new_client->data))->sysctl_id = err;
|
||||
err = 0;
|
||||
|
||||
/* Initialize the MaxiLife chip */
|
||||
maxi_init_client(new_client);
|
||||
continue;
|
||||
|
||||
/* OK, this is not exactly good programming practice, usually.
|
||||
But it is very code-efficient in this case. */
|
||||
ERROR4:
|
||||
i2c_detach_client(new_client);
|
||||
ERROR3:
|
||||
maxi_remove_client((struct i2c_client *) new_client);
|
||||
ERROR2:
|
||||
kfree(new_client);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int maxi_detach_smbus(struct i2c_client *client)
|
||||
{
|
||||
int err,i;
|
||||
for (i = 0; i < MAX_MAXI_NR; i++)
|
||||
if (client == maxi_list[i])
|
||||
break;
|
||||
if ((i == MAX_MAXI_NR)) {
|
||||
printk("maxilife: Client to detach not found.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
sensors_deregister_entry(((struct maxi_data *)(client->data))->sysctl_id);
|
||||
|
||||
if ((err = i2c_detach_client(client))) {
|
||||
printk("maxilife: Client deregistration failed, client not detached.\n");
|
||||
return err;
|
||||
}
|
||||
maxi_remove_client(client);
|
||||
kfree(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find a free slot, and initialize most of the fields */
|
||||
int maxi_new_client(struct i2c_adapter *adapter,
|
||||
struct i2c_client *new_client)
|
||||
{
|
||||
int i;
|
||||
struct maxi_data *data;
|
||||
|
||||
/* First, seek out an empty slot */
|
||||
for (i = 0; i < MAX_MAXI_NR; i++)
|
||||
if (!maxi_list[i])
|
||||
break;
|
||||
if (i == MAX_MAXI_NR) {
|
||||
printk("maxilife: No empty slots left, recompile and heighten "
|
||||
"MAX_MAXI_NR!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
maxi_list[i] = new_client;
|
||||
new_client->id = i;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &maxi_driver;
|
||||
data = new_client->data;
|
||||
data->valid = 0;
|
||||
data->lock = MUTEX;
|
||||
data->update_lock = MUTEX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Inverse of maxi_new_client */
|
||||
void maxi_remove_client(struct i2c_client *client)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_MAXI_NR; i++)
|
||||
if (client == maxi_list[i])
|
||||
maxi_list[i] = NULL;
|
||||
}
|
||||
|
||||
/* No commands defined yet */
|
||||
int maxi_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Nothing here yet */
|
||||
void maxi_inc_use (struct i2c_client *client)
|
||||
{
|
||||
#ifdef MODULE
|
||||
MOD_INC_USE_COUNT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Nothing here yet */
|
||||
void maxi_dec_use (struct i2c_client *client)
|
||||
{
|
||||
#ifdef MODULE
|
||||
MOD_DEC_USE_COUNT;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Read byte from specified register. */
|
||||
int maxi_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return smbus_read_byte_data(client->adapter, client->addr, reg);
|
||||
}
|
||||
|
||||
/* Write byte to specified register. */
|
||||
int maxi_write_value(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
return smbus_write_byte_data(client->adapter, client->addr, reg, value);
|
||||
}
|
||||
|
||||
/* Called when we have found a new MaxiLife. It should set limits, etc. */
|
||||
void maxi_init_client(struct i2c_client *client)
|
||||
{
|
||||
/* start with default settings */
|
||||
}
|
||||
|
||||
void maxi_update_client(struct i2c_client *client)
|
||||
{
|
||||
struct maxi_data *data = client->data;
|
||||
int i;
|
||||
|
||||
down(&data->update_lock);
|
||||
|
||||
if ((jiffies - data->last_updated > HZ+HZ/2 ) ||
|
||||
(jiffies < data->last_updated) || !data->valid) {
|
||||
|
||||
#ifdef DEBUG
|
||||
printk("maxilife: Starting MaxiLife update\n");
|
||||
#endif
|
||||
for (i = 0; i < 5; i++)
|
||||
data->temp[i] = maxi_read_value(client, MAXI_REG_TEMP(i));
|
||||
switch (data->type) {
|
||||
case cristal:
|
||||
data->temp[0] = 0; /* not valid */
|
||||
data->temp_max[0] = 0;
|
||||
data->temp_hyst[0] = 0;
|
||||
data->temp_max[1] = 110; /* max PCI slot temp */
|
||||
data->temp_hyst[1] = 100;
|
||||
data->temp_max[2] = 120; /* max BX chipset temp */
|
||||
data->temp_hyst[2] = 110;
|
||||
data->temp_max[3] = 100; /* max HDD temp */
|
||||
data->temp_hyst[3] = 90;
|
||||
data->temp_max[4] = 120; /* max CPU temp */
|
||||
data->temp_hyst[4] = 110;
|
||||
break;
|
||||
|
||||
case cognac:
|
||||
data->temp_max[0] = 120; /* max CPU1 temp */
|
||||
data->temp_hyst[0] = 110;
|
||||
data->temp_max[1] = 110; /* max PCI slot temp */
|
||||
data->temp_hyst[1] = 100;
|
||||
data->temp_max[2] = 120; /* max CPU2 temp */
|
||||
data->temp_hyst[2] = 110;
|
||||
data->temp_max[3] = 100; /* max HDD temp */
|
||||
data->temp_hyst[3] = 90;
|
||||
data->temp_max[4] = 120; /* max reference CPU temp */
|
||||
data->temp_hyst[4] = 110;
|
||||
break;
|
||||
|
||||
case ashaki:
|
||||
data->temp[0] = 0; /* not valid */
|
||||
data->temp_max[0] = 0;
|
||||
data->temp_hyst[0] = 0;
|
||||
data->temp_max[1] = 110; /* max PCI slot temp */
|
||||
data->temp_hyst[1] = 100;
|
||||
data->temp[2] = 0; /* not valid */
|
||||
data->temp_max[2] = 0;
|
||||
data->temp_hyst[2] = 0;
|
||||
data->temp_max[3] = 100; /* max HDD temp */
|
||||
data->temp_hyst[3] = 90;
|
||||
data->temp_max[4] = 120; /* max CPU temp */
|
||||
data->temp_hyst[4] = 110;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("maxilife: Unknown MaxiLife chip\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
data->fan[i] = maxi_read_value(client, MAXI_REG_FAN(i));
|
||||
data->fan_speed[i] = maxi_read_value(client, MAXI_REG_FAN_SPEED(i));
|
||||
data->fan_div[i] = 4;
|
||||
if (data->type == ashaki)
|
||||
data->fan_min[i] = maxi_read_value(client, MAXI_REG_FAN_MINAS(i));
|
||||
else
|
||||
data->fan_min[i] = maxi_read_value(client, MAXI_REG_FAN_MIN(i));
|
||||
}
|
||||
|
||||
data->pll = maxi_read_value(client, MAXI_REG_PLL);
|
||||
data->pll_min = maxi_read_value(client, MAXI_REG_PLL_MIN);
|
||||
data->pll_max = maxi_read_value(client, MAXI_REG_PLL_MAX);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
data->vid[i] = maxi_read_value(client, MAXI_REG_VID(i));
|
||||
data->vid_min[i] = maxi_read_value(client, MAXI_REG_VID_MIN(i));
|
||||
data->vid_max[i] = maxi_read_value(client, MAXI_REG_VID_MAX(i));
|
||||
}
|
||||
switch (data->type) {
|
||||
case cristal:
|
||||
data->vid[3] = 0; /* no voltage cache L2 */
|
||||
data->vid_min[3] = 0;
|
||||
data->vid_max[3] = 0;
|
||||
break;
|
||||
|
||||
case cognac:
|
||||
break;
|
||||
|
||||
case ashaki:
|
||||
data->vid[1] = 0; /* no voltage CPU 2 */
|
||||
data->vid_min[1] = 0;
|
||||
data->vid_max[1] = 0;
|
||||
data->vid[3] = 0; /* no voltage cache L2 */
|
||||
data->vid_min[3] = 0;
|
||||
data->vid_max[3] = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("maxilife: Unknown MaxiLife chip\n");
|
||||
}
|
||||
|
||||
data->alarms = maxi_read_value(client, MAXI_REG_DIAG_RT1) +
|
||||
(maxi_read_value(client, MAXI_REG_DIAG_RT2) << 8);
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
up(&data->update_lock);
|
||||
}
|
||||
|
||||
/* The next few functions are the call-back functions of the /proc/sys and
|
||||
sysctl files. Which function is used is defined in the ctl_table in
|
||||
the extra1 field.
|
||||
Each function must return the magnitude (power of 10 to divide the data
|
||||
with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
|
||||
put a maximum of *nrels elements in results reflecting the data of this
|
||||
file, and set *nrels to the number it actually put in it, if operation==
|
||||
SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
|
||||
results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
|
||||
Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
|
||||
large enough (by checking the incoming value of *nrels). This is not very
|
||||
good practice, but as long as you put less than about 5 values in results,
|
||||
you can assume it is large enough. */
|
||||
void maxi_fan(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results)
|
||||
{
|
||||
struct maxi_data *data = client->data;
|
||||
int nr = ctl_name - MAXI_SYSCTL_FAN1 + 1;
|
||||
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = 0;
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
maxi_update_client(client);
|
||||
results[0] = FAN_FROM_REG(data->fan_min[nr-1]);
|
||||
results[1] = data->fan_div[nr-1];
|
||||
results[2] = FAN_FROM_REG(data->fan[nr-1]);
|
||||
*nrels_mag = 3;
|
||||
} else if (operation == SENSORS_PROC_REAL_WRITE) {
|
||||
#ifndef NOWRITE
|
||||
if (*nrels_mag >= 1) {
|
||||
data->fan_min[nr-1] = FAN_TO_REG(results[0]);
|
||||
maxi_write_value(client, MAXI_REG_FAN_MIN(nr), data->fan_min[nr-1]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void maxi_temp(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results)
|
||||
{
|
||||
struct maxi_data *data = client->data;
|
||||
int nr = ctl_name - MAXI_SYSCTL_TEMP1 + 1;
|
||||
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = 1;
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
maxi_update_client(client);
|
||||
results[0] = TEMP_FROM_REG(data->temp_max[nr-1]);
|
||||
results[1] = TEMP_FROM_REG(data->temp_hyst[nr-1]);
|
||||
results[2] = TEMP_FROM_REG(data->temp[nr-1]);
|
||||
*nrels_mag = 3;
|
||||
} else if (operation == SENSORS_PROC_REAL_WRITE) {
|
||||
/* temperature range can not be changed */
|
||||
}
|
||||
}
|
||||
|
||||
void maxi_pll(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results)
|
||||
{
|
||||
struct maxi_data *data = client->data;
|
||||
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = 2;
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
maxi_update_client(client);
|
||||
results[0] = PLL_FROM_REG(data->pll_min);
|
||||
results[1] = PLL_FROM_REG(data->pll_max);
|
||||
results[2] = PLL_FROM_REG(data->pll);
|
||||
*nrels_mag = 3;
|
||||
} else if (operation == SENSORS_PROC_REAL_WRITE) {
|
||||
#ifndef NOWRITE
|
||||
if (*nrels_mag >= 1) {
|
||||
data->pll_min = PLL_TO_REG(results[0]);
|
||||
maxi_write_value(client, MAXI_REG_PLL_MIN, data->pll_min);
|
||||
}
|
||||
if (*nrels_mag >= 2) {
|
||||
data->pll_max = PLL_TO_REG(results[1]);
|
||||
maxi_write_value(client, MAXI_REG_PLL_MAX, data->pll_max);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void maxi_vid(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results)
|
||||
{
|
||||
struct maxi_data *data = client->data;
|
||||
int nr = ctl_name - MAXI_SYSCTL_VID1 + 1;
|
||||
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = 4;
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
maxi_update_client(client);
|
||||
results[0] = VID_FROM_REG(data->vid_min[nr-1]);
|
||||
results[1] = VID_FROM_REG(data->vid_max[nr-1]);
|
||||
results[2] = VID_FROM_REG(data->vid[nr-1]);
|
||||
*nrels_mag = 3;
|
||||
} else if (operation == SENSORS_PROC_REAL_WRITE) {
|
||||
#ifndef NOWRITE
|
||||
if (*nrels_mag >= 1) {
|
||||
data->vid_min[nr-1] = VID_TO_REG(results[0]);
|
||||
maxi_write_value(client, MAXI_REG_VID_MIN(nr), data->vid_min[nr-1]);
|
||||
}
|
||||
if (*nrels_mag >= 2) {
|
||||
data->vid_max[nr-1] = VID_TO_REG(results[1]);
|
||||
maxi_write_value(client, MAXI_REG_VID_MAX(nr), data->vid_max[nr-1]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void maxi_alarms(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results)
|
||||
{
|
||||
struct maxi_data *data = client->data;
|
||||
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = 0;
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
maxi_update_client(client);
|
||||
results[0] = ALARMS_FROM_REG(data->alarms);
|
||||
*nrels_mag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int maxi_init(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
printk("maxilife: Version %s (lm_sensors %s (%s))\n", version,
|
||||
LM_VERSION, LM_DATE);
|
||||
maxi_initialized = 0;
|
||||
|
||||
if ((res = i2c_add_driver(&maxi_driver))) {
|
||||
printk("maxilife: Driver registration failed, module not inserted.\n");
|
||||
maxi_cleanup();
|
||||
return res;
|
||||
}
|
||||
maxi_initialized++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int maxi_cleanup(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (maxi_initialized >= 1) {
|
||||
if ((res = i2c_del_driver(&maxi_driver))) {
|
||||
printk("maxilife: Driver deregistration failed, module not removed.\n");
|
||||
return res;
|
||||
}
|
||||
maxi_initialized--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef MODULE
|
||||
|
||||
MODULE_AUTHOR("Fons Rademakers <Fons.Rademakers@cern.ch>");
|
||||
MODULE_DESCRIPTION("HP MaxiLife driver");
|
||||
MODULE_PARM(maxi_version, "i");
|
||||
MODULE_PARM_DESC(maxi_version, "MaxiLife firmware version");
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
return maxi_init();
|
||||
}
|
||||
|
||||
int cleanup_module(void)
|
||||
{
|
||||
return maxi_cleanup();
|
||||
}
|
||||
|
||||
#endif /* MODULE */
|
||||
|
||||
|
||||
@@ -285,6 +285,7 @@ extern int sensors_detect(struct i2c_adapter *adapter,
|
||||
#define I2C_DRIVERID_LTC1710 1010
|
||||
#define I2C_DRIVERID_SIS5595 1011
|
||||
#define I2C_DRIVERID_ICSPLL 1012
|
||||
#define I2C_DRIVERID_MAXILIFE 1012
|
||||
|
||||
/* Sysctl IDs */
|
||||
#ifdef DEV_HWMON
|
||||
@@ -452,5 +453,33 @@ struct sensors_chips_data {
|
||||
#define LM80_ALARM_BTI 0x0200
|
||||
#define LM80_ALARM_INT_IN 0x0080
|
||||
|
||||
#define MAXI_SYSCTL_FAN1 1101 /* Rotations/min */
|
||||
#define MAXI_SYSCTL_FAN2 1102 /* Rotations/min */
|
||||
#define MAXI_SYSCTL_FAN3 1103 /* Rotations/min */
|
||||
#define MAXI_SYSCTL_TEMP1 1201 /* Degrees Celcius */
|
||||
#define MAXI_SYSCTL_TEMP2 1202 /* Degrees Celcius */
|
||||
#define MAXI_SYSCTL_TEMP3 1203 /* Degrees Celcius */
|
||||
#define MAXI_SYSCTL_TEMP4 1204 /* Degrees Celcius */
|
||||
#define MAXI_SYSCTL_TEMP5 1205 /* Degrees Celcius */
|
||||
#define MAXI_SYSCTL_PLL 1301 /* MHz */
|
||||
#define MAXI_SYSCTL_VID1 1401 /* Volts / 6.337 */
|
||||
#define MAXI_SYSCTL_VID2 1402 /* Volts */
|
||||
#define MAXI_SYSCTL_VID3 1403 /* Volts */
|
||||
#define MAXI_SYSCTL_VID4 1404 /* Volts */
|
||||
#define MAXI_SYSCTL_ALARMS 2001 /* Bitvector (see below) */
|
||||
|
||||
#define MAXI_ALARM_VID4 0x0001
|
||||
#define MAXI_ALARM_TEMP2 0x0002
|
||||
#define MAXI_ALARM_VID1 0x0004
|
||||
#define MAXI_ALARM_VID2 0x0008
|
||||
#define MAXI_ALARM_VID3 0x0010
|
||||
#define MAXI_ALARM_PLL 0x0080
|
||||
#define MAXI_ALARM_TEMP4 0x0100
|
||||
#define MAXI_ALARM_TEMP5 0x0200
|
||||
#define MAXI_ALARM_FAN1 0x1000
|
||||
#define MAXI_ALARM_FAN2 0x2000
|
||||
#define MAXI_ALARM_FAN3 0x4000
|
||||
|
||||
|
||||
#define ICSPLL_SYSCTL1 1000
|
||||
#endif /* def SENSORS_SENSORS_H */
|
||||
+98
@@ -1077,6 +1077,101 @@ static sensors_chip_feature sis5595_features[] =
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static sensors_chip_feature maxi_features[] =
|
||||
{
|
||||
{ SENSORS_MAXI_FAN1, "fan1", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_FAN1, VALUE(3), 0 },
|
||||
{ SENSORS_MAXI_FAN2, "fan2", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_FAN2, VALUE(3), 0 },
|
||||
{ SENSORS_MAXI_FAN3, "fan3", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_FAN3, VALUE(3), 0 },
|
||||
{ SENSORS_MAXI_FAN1_MIN, "fan1_min", SENSORS_MAXI_FAN1, SENSORS_MAXI_FAN1,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_FAN1, VALUE(1), 0 },
|
||||
{ SENSORS_MAXI_FAN2_MIN, "fan2_min", SENSORS_MAXI_FAN2, SENSORS_MAXI_FAN2,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_FAN2, VALUE(1), 0 },
|
||||
{ SENSORS_MAXI_FAN3_MIN, "fan3_min", SENSORS_MAXI_FAN3, SENSORS_MAXI_FAN3,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_FAN3, VALUE(1), 0 },
|
||||
{ SENSORS_MAXI_FAN1_DIV, "fan1_div", SENSORS_MAXI_FAN1, SENSORS_MAXI_FAN1,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_FAN1, VALUE(2), 0 },
|
||||
{ SENSORS_MAXI_FAN2_DIV, "fan2_div", SENSORS_MAXI_FAN2, SENSORS_MAXI_FAN2,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_FAN2, VALUE(2), 0 },
|
||||
{ SENSORS_MAXI_FAN3_DIV, "fan3_div", SENSORS_MAXI_FAN3, SENSORS_MAXI_FAN3,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_FAN3, VALUE(2), 0 },
|
||||
{ SENSORS_MAXI_TEMP1, "temp1", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_TEMP1, VALUE(3), 1 },
|
||||
{ SENSORS_MAXI_TEMP2, "temp2", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_TEMP2, VALUE(3), 1 },
|
||||
{ SENSORS_MAXI_TEMP3, "temp3", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_TEMP3, VALUE(3), 1 },
|
||||
{ SENSORS_MAXI_TEMP4, "temp4", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_TEMP4, VALUE(3), 1 },
|
||||
{ SENSORS_MAXI_TEMP5, "temp5", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_TEMP5, VALUE(3), 1 },
|
||||
{ SENSORS_MAXI_TEMP1_MAX, "temp1_max", SENSORS_MAXI_TEMP1,
|
||||
SENSORS_MAXI_TEMP1, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP1, VALUE(1), 1 },
|
||||
{ SENSORS_MAXI_TEMP2_MAX, "temp2_max", SENSORS_MAXI_TEMP2,
|
||||
SENSORS_MAXI_TEMP2, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP2, VALUE(1), 1 },
|
||||
{ SENSORS_MAXI_TEMP3_MAX, "temp3_max", SENSORS_MAXI_TEMP3,
|
||||
SENSORS_MAXI_TEMP3, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP3, VALUE(1), 1 },
|
||||
{ SENSORS_MAXI_TEMP4_MAX, "temp4_max", SENSORS_MAXI_TEMP4,
|
||||
SENSORS_MAXI_TEMP4, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP4, VALUE(1), 1 },
|
||||
{ SENSORS_MAXI_TEMP5_MAX, "temp5_max", SENSORS_MAXI_TEMP5,
|
||||
SENSORS_MAXI_TEMP5, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP5, VALUE(1), 1 },
|
||||
{ SENSORS_MAXI_TEMP1_HYST, "temp1_hyst", SENSORS_MAXI_TEMP1,
|
||||
SENSORS_MAXI_TEMP1, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP1, VALUE(2), 1 },
|
||||
{ SENSORS_MAXI_TEMP2_HYST, "temp2_hyst", SENSORS_MAXI_TEMP2,
|
||||
SENSORS_MAXI_TEMP2, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP2, VALUE(2), 1 },
|
||||
{ SENSORS_MAXI_TEMP3_HYST, "temp3_hyst", SENSORS_MAXI_TEMP3,
|
||||
SENSORS_MAXI_TEMP3, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP3, VALUE(2), 1 },
|
||||
{ SENSORS_MAXI_TEMP4_HYST, "temp4_hyst", SENSORS_MAXI_TEMP4,
|
||||
SENSORS_MAXI_TEMP4, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP4, VALUE(2), 1 },
|
||||
{ SENSORS_MAXI_TEMP5_HYST, "temp5_hyst", SENSORS_MAXI_TEMP5,
|
||||
SENSORS_MAXI_TEMP5, SENSORS_MODE_R,
|
||||
MAXI_SYSCTL_TEMP5, VALUE(2), 1 },
|
||||
{ SENSORS_MAXI_PLL, "pll", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_PLL, VALUE(3), 2 },
|
||||
{ SENSORS_MAXI_PLL_MIN, "pll_min", SENSORS_MAXI_PLL, SENSORS_MAXI_PLL,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_PLL, VALUE(1), 2 },
|
||||
{ SENSORS_MAXI_PLL_MAX, "pll_max", SENSORS_MAXI_PLL, SENSORS_MAXI_PLL,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_PLL, VALUE(2), 2 },
|
||||
{ SENSORS_MAXI_VID1, "vid1", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_VID1, VALUE(3), 4 },
|
||||
{ SENSORS_MAXI_VID2, "vid2", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_VID2, VALUE(3), 4 },
|
||||
{ SENSORS_MAXI_VID3, "vid3", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_VID3, VALUE(3), 4 },
|
||||
{ SENSORS_MAXI_VID4, "vid4", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_VID4, VALUE(3), 4 },
|
||||
{ SENSORS_MAXI_VID1_MIN, "vid1_min", SENSORS_MAXI_VID1, SENSORS_MAXI_VID1,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_VID1, VALUE(1), 4 },
|
||||
{ SENSORS_MAXI_VID2_MIN, "vid2_min", SENSORS_MAXI_VID2, SENSORS_MAXI_VID2,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_VID2, VALUE(1), 4 },
|
||||
{ SENSORS_MAXI_VID3_MIN, "vid3_min", SENSORS_MAXI_VID3, SENSORS_MAXI_VID3,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_VID3, VALUE(1), 4 },
|
||||
{ SENSORS_MAXI_VID4_MIN, "vid4_min", SENSORS_MAXI_VID4, SENSORS_MAXI_VID4,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_VID4, VALUE(1), 4 },
|
||||
{ SENSORS_MAXI_VID1_MAX, "vid1_max", SENSORS_MAXI_VID1, SENSORS_MAXI_VID1,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_VID1, VALUE(2), 4 },
|
||||
{ SENSORS_MAXI_VID2_MAX, "vid2_max", SENSORS_MAXI_VID2, SENSORS_MAXI_VID2,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_VID2, VALUE(2), 4 },
|
||||
{ SENSORS_MAXI_VID3_MAX, "vid3_max", SENSORS_MAXI_VID3, SENSORS_MAXI_VID3,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_VID3, VALUE(2), 4 },
|
||||
{ SENSORS_MAXI_VID4_MAX, "vid4_max", SENSORS_MAXI_VID4, SENSORS_MAXI_VID4,
|
||||
SENSORS_MODE_RW, MAXI_SYSCTL_VID4, VALUE(2), 4 },
|
||||
{ SENSORS_MAXI_ALARMS, "alarms", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
|
||||
SENSORS_MODE_R, MAXI_SYSCTL_ALARMS, VALUE(1), 0 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
sensors_chip_features sensors_chip_features_list[] =
|
||||
{
|
||||
{ SENSORS_LM78_PREFIX, lm78_features },
|
||||
@@ -1092,6 +1187,9 @@ sensors_chip_features sensors_chip_features_list[] =
|
||||
{ SENSORS_ADM9240_PREFIX, adm9240_features },
|
||||
{ SENSORS_ADM1021_PREFIX, adm1021_features },
|
||||
{ SENSORS_SIS5595_PREFIX, sis5595_features },
|
||||
{ SENSORS_MAXI_CG_PREFIX, maxi_features },
|
||||
{ SENSORS_MAXI_CO_PREFIX, maxi_features },
|
||||
{ SENSORS_MAXI_AS_PREFIX, maxi_features },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
+48
@@ -505,4 +505,52 @@
|
||||
#define SENSORS_SIS5595_FAN3_DIV 73 /* R (yes, really! */
|
||||
#define SENSORS_SIS5595_ALARMS 81 /* R */
|
||||
|
||||
|
||||
/* HP MaxiLife chips */
|
||||
|
||||
#define SENSORS_MAXI_CG_PREFIX "maxilife-cg"
|
||||
#define SENSORS_MAXI_CO_PREFIX "maxilife-co"
|
||||
#define SENSORS_MAXI_AS_PREFIX "maxilife-as"
|
||||
|
||||
#define SENSORS_MAXI_FAN1 1 /* R */
|
||||
#define SENSORS_MAXI_FAN2 2 /* R */
|
||||
#define SENSORS_MAXI_FAN3 3 /* R */
|
||||
#define SENSORS_MAXI_FAN1_MIN 11 /* RW */
|
||||
#define SENSORS_MAXI_FAN2_MIN 12 /* RW */
|
||||
#define SENSORS_MAXI_FAN3_MIN 13 /* RW */
|
||||
#define SENSORS_MAXI_FAN1_DIV 14 /* R */
|
||||
#define SENSORS_MAXI_FAN2_DIV 15 /* R */
|
||||
#define SENSORS_MAXI_FAN3_DIV 16 /* R */
|
||||
#define SENSORS_MAXI_TEMP1 21 /* R */
|
||||
#define SENSORS_MAXI_TEMP2 22 /* R */
|
||||
#define SENSORS_MAXI_TEMP3 23 /* R */
|
||||
#define SENSORS_MAXI_TEMP4 24 /* R */
|
||||
#define SENSORS_MAXI_TEMP5 25 /* R */
|
||||
#define SENSORS_MAXI_TEMP1_MAX 31 /* R */
|
||||
#define SENSORS_MAXI_TEMP2_MAX 32 /* R */
|
||||
#define SENSORS_MAXI_TEMP3_MAX 33 /* R */
|
||||
#define SENSORS_MAXI_TEMP4_MAX 34 /* R */
|
||||
#define SENSORS_MAXI_TEMP5_MAX 35 /* R */
|
||||
#define SENSORS_MAXI_TEMP1_HYST 41 /* R */
|
||||
#define SENSORS_MAXI_TEMP2_HYST 42 /* R */
|
||||
#define SENSORS_MAXI_TEMP3_HYST 43 /* R */
|
||||
#define SENSORS_MAXI_TEMP4_HYST 44 /* R */
|
||||
#define SENSORS_MAXI_TEMP5_HYST 45 /* R */
|
||||
#define SENSORS_MAXI_PLL 51 /* R */
|
||||
#define SENSORS_MAXI_PLL_MIN 52 /* RW */
|
||||
#define SENSORS_MAXI_PLL_MAX 53 /* RW */
|
||||
#define SENSORS_MAXI_VID1 61 /* R */
|
||||
#define SENSORS_MAXI_VID2 62 /* R */
|
||||
#define SENSORS_MAXI_VID3 63 /* R */
|
||||
#define SENSORS_MAXI_VID4 64 /* R */
|
||||
#define SENSORS_MAXI_VID1_MIN 71 /* RW */
|
||||
#define SENSORS_MAXI_VID2_MIN 72 /* RW */
|
||||
#define SENSORS_MAXI_VID3_MIN 73 /* RW */
|
||||
#define SENSORS_MAXI_VID4_MIN 74 /* RW */
|
||||
#define SENSORS_MAXI_VID1_MAX 81 /* RW */
|
||||
#define SENSORS_MAXI_VID2_MAX 82 /* RW */
|
||||
#define SENSORS_MAXI_VID3_MAX 83 /* RW */
|
||||
#define SENSORS_MAXI_VID4_MAX 84 /* RW */
|
||||
#define SENSORS_MAXI_ALARMS 91 /* R */
|
||||
|
||||
#endif /* def LIB_SENSORS_CHIPS_H */
|
||||
@@ -752,3 +752,198 @@ void print_w83781d(const sensors_chip_name *name)
|
||||
printf("ERROR: Can't get BEEP data!\n");
|
||||
free_the_label(&label);
|
||||
}
|
||||
|
||||
void print_maxilife(const sensors_chip_name *name)
|
||||
{
|
||||
char *label = NULL;
|
||||
double cur, min, max;
|
||||
int alarms;
|
||||
|
||||
if (!sensors_get_feature(*name, SENSORS_MAXI_ALARMS, &cur))
|
||||
alarms = cur + 0.5;
|
||||
else {
|
||||
printf("ERROR: Can't get alarm data!\n");
|
||||
alarms = 0;
|
||||
}
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_TEMP1, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP1, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP1_MAX, &max) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP1_HYST, &min)) {
|
||||
if (cur || max || min) {
|
||||
print_label(label, 12);
|
||||
printf("%+3.1f C (limit = %+3.1f C, hysteresis = %+3.1f C)\n",
|
||||
cur, max, min);
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get TEMP1 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_TEMP2, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP2, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP2_MAX, &max) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP2_HYST, &min)) {
|
||||
if (cur || max || min) {
|
||||
print_label(label, 12);
|
||||
printf("%+3.1f C (limit = %+3.1f C, hysteresis = %+3.1f C) %s\n",
|
||||
cur, max, min, alarms&MAXI_ALARM_TEMP2 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get TEMP2 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_TEMP3, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP3, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP3_MAX, &max) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP3_HYST, &min)) {
|
||||
if (cur || max || min) {
|
||||
print_label(label, 12);
|
||||
printf("%+3.1f C (limit = %+3.1f C, hysteresis = %+3.1f C)\n",
|
||||
cur, max, min);
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get TEMP3 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_TEMP4, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP4, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP4_MAX, &max) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP4_HYST, &min)) {
|
||||
if (cur || max || min) {
|
||||
print_label(label, 12);
|
||||
printf("%+3.1f C (limit = %+3.1f C, hysteresis = %+3.1f C) %s\n",
|
||||
cur, max, min, alarms&MAXI_ALARM_TEMP4 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get TEMP4 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_TEMP5, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP5, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP5_MAX, &max) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_TEMP5_HYST, &min)) {
|
||||
if (cur || max || min) {
|
||||
print_label(label, 12);
|
||||
printf("%+3.1f C (limit = %+3.1f C, hysteresis = %+3.1f C) %s\n",
|
||||
cur, max, min, alarms&MAXI_ALARM_TEMP5 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get TEMP5 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_FAN1, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_FAN1, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_FAN1_MIN, &min) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_FAN1_DIV, &max)) {
|
||||
if (cur || min || max) {
|
||||
print_label(label, 12);
|
||||
if (cur < 0)
|
||||
printf(" OFF (min = %4.0f RPM, div = %1.0f) %s\n",
|
||||
min/max, max, alarms&MAXI_ALARM_FAN1 ? "ALARM" : "");
|
||||
else
|
||||
printf("%5.0f RPM (min = %4.0f RPM, div = %1.0f) %s\n",
|
||||
cur/max, min/max, max, alarms&MAXI_ALARM_FAN1 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get FAN1 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_FAN2, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_FAN2, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_FAN2_MIN, &min) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_FAN2_DIV, &max)) {
|
||||
if (cur || min || max) {
|
||||
print_label(label, 12);
|
||||
if (cur < 0)
|
||||
printf(" OFF (min = %4.0f RPM, div = %1.0f) %s\n",
|
||||
min/max, max, alarms&MAXI_ALARM_FAN2 ? "ALARM" : "");
|
||||
else
|
||||
printf("%5.0f RPM (min = %4.0f RPM, div = %1.0f) %s\n",
|
||||
cur/max, min/max, max, alarms&MAXI_ALARM_FAN2 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get FAN2 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_FAN3, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_FAN3, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_FAN3_MIN, &min) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_FAN3_DIV, &max)) {
|
||||
if (cur || min || max) {
|
||||
print_label(label, 12);
|
||||
if (cur < 0)
|
||||
printf(" OFF (min = %4.0f RPM, div = %1.0f) %s\n",
|
||||
min/max, max, alarms&MAXI_ALARM_FAN3 ? "ALARM" : "");
|
||||
else
|
||||
printf("%5.0f RPM (min = %4.0f RPM, div = %1.0f) %s\n",
|
||||
cur/max, min/max, max, alarms&MAXI_ALARM_FAN3 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get FAN3 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_PLL, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_PLL, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_PLL_MIN, &min) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_PLL_MAX, &max)) {
|
||||
if (cur || min || max) {
|
||||
print_label(label, 12);
|
||||
printf("%4.2f MHz (min = %4.2f MHz, max = %4.2f MHz) %s\n",
|
||||
cur, min, max, alarms&MAXI_ALARM_PLL ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get PLL data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_VID1, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID1, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID1_MIN, &min) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID1_MAX, &max)) {
|
||||
if (cur || min || max) {
|
||||
print_label(label, 12);
|
||||
printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
|
||||
cur, min, max, alarms&MAXI_ALARM_VID1 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get VID1 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_VID2, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID2, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID2_MIN, &min) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID2_MAX, &max)) {
|
||||
if (cur || min || max) {
|
||||
print_label(label, 12);
|
||||
printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
|
||||
cur, min, max, alarms&MAXI_ALARM_VID2 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get VID2 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_VID3, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID3, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID3_MIN, &min) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID3_MAX, &max)) {
|
||||
if (cur || min || max) {
|
||||
print_label(label, 12);
|
||||
printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
|
||||
cur, min, max, alarms&MAXI_ALARM_VID3 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get VID3 data!\n");
|
||||
free_the_label(&label);
|
||||
|
||||
if (!sensors_get_label(*name, SENSORS_MAXI_VID4, &label) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID4, &cur) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID4_MIN, &min) &&
|
||||
!sensors_get_feature(*name, SENSORS_MAXI_VID4_MAX, &max)) {
|
||||
if (cur || min || max) {
|
||||
print_label(label, 12);
|
||||
printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
|
||||
cur, min, max, alarms&MAXI_ALARM_VID4 ? "ALARM" : "");
|
||||
}
|
||||
} else
|
||||
printf("ERROR: Can't get VID4 data!\n");
|
||||
free_the_label(&label);
|
||||
}
|
||||
@@ -29,5 +29,6 @@ extern void print_lm78(const sensors_chip_name *name);
|
||||
extern void print_gl518(const sensors_chip_name *name);
|
||||
extern void print_lm80(const sensors_chip_name *name);
|
||||
extern void print_w83781d(const sensors_chip_name *name);
|
||||
extern void print_maxilife(const sensors_chip_name *name);
|
||||
|
||||
#endif /* def PROG_SENSORS_CHIPS_H */
|
||||
@@ -258,6 +258,10 @@ void do_a_print(sensors_chip_name name)
|
||||
(!strcmp(name.prefix,"w83782d")) ||
|
||||
(!strcmp(name.prefix,"w83783s")))
|
||||
print_w83781d(&name);
|
||||
else if (!strcmp(name.prefix,"maxilife-cg") ||
|
||||
!strcmp(name.prefix,"maxilife-co") ||
|
||||
!strcmp(name.prefix,"maxilife-as"))
|
||||
print_maxilife(&name);
|
||||
else
|
||||
print_unknown_chip(&name);
|
||||
printf("\n");
|
||||
|
||||
Reference in new issue
Block a user