mirror of
https://github.com/lm-sensors/lm-sensors.git
synced 2026-10-29 12:50:43 +00:00
initial checkin IPMI/BMC support
git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@1593 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
1 parent
051f0f0bc9
commit
7bcd435c4c
5 files changed
+1176
No files matched your search
@@ -25,6 +25,9 @@ KERNELBUSSESDIR := $(MODULE_DIR)
|
||||
# defined value verbatim into the command-list of rules...
|
||||
# These targets are NOT included in 'mkpatch' ...
|
||||
KERNELBUSSESTARGETS :=
|
||||
ifeq ($(shell if grep -q '^CONFIG_IPMI_HANDLER=' $(LINUX)/.config; then echo 1; fi),1)
|
||||
KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-ipmi.o
|
||||
endif
|
||||
KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-sis630.o
|
||||
KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-sis645.o
|
||||
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
i2c-bmc.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
This implements an
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ipmi.h>
|
||||
#include "version.h"
|
||||
|
||||
|
||||
static void bmc_inc_use(struct i2c_adapter *adapter);
|
||||
static void bmc_dec_use(struct i2c_adapter *adapter);
|
||||
static u32 bmc_func(struct i2c_adapter *adapter);
|
||||
|
||||
#ifdef MODULE
|
||||
static
|
||||
#else
|
||||
extern
|
||||
#endif
|
||||
int __init i2c_bmc_init(void);
|
||||
static int __init bmc_cleanup(void);
|
||||
|
||||
#ifdef MODULE
|
||||
extern int init_module(void);
|
||||
extern int cleanup_module(void);
|
||||
#endif /* MODULE */
|
||||
|
||||
/* I2C Data */
|
||||
/* This is the actual algorithm we define */
|
||||
static struct i2c_algorithm bmc_algorithm = {
|
||||
/* name */ "IPMI algorithm",
|
||||
/* id */ I2C_ALGO_IPMI,
|
||||
/* master_xfer */ NULL,
|
||||
/* smbus_access */ NULL,
|
||||
/* slave_send */ NULL,
|
||||
/* slave_rcv */ NULL,
|
||||
/* algo_control */ NULL,
|
||||
/* functionality */ &bmc_func,
|
||||
};
|
||||
|
||||
static struct i2c_adapter bmc_adapter = {
|
||||
/* name */ "IPMI adapter",
|
||||
/* id */ I2C_ALGO_IPMI | I2C_HW_IPMI,
|
||||
/* algorithm */ &bmc_algorithm,
|
||||
/* algo_data */ NULL,
|
||||
/* inc_use */ &bmc_inc_use,
|
||||
/* dec_use */ &bmc_dec_use,
|
||||
/* data */ NULL,
|
||||
/* Other fields not initialized */
|
||||
};
|
||||
|
||||
/* IPMI Data */
|
||||
static ipmi_user_t i2c_bmc_user;
|
||||
static ipmi_user_t i2c_ipmi_user;
|
||||
static unsigned char ipmi_version_major;
|
||||
static unsigned char ipmi_version_minor;
|
||||
static const char msgdata[IPMI_MAX_ADDR_SIZE]; /* ?? */
|
||||
static struct ipmi_addr address = {
|
||||
IPMI_SYSTEM_INTERFACE_ADDR_TYPE,
|
||||
IPMI_BMC_CHANNEL,
|
||||
NULL
|
||||
}; /* send address */
|
||||
static struct ipmi_msg message; /* send message */
|
||||
static long msgid; /* message ID */
|
||||
static int interfaces;
|
||||
static int (*rcv_callback)(struct i2c_client *client,unsigned int cmd, void *arg);
|
||||
|
||||
/* Used in bmc_init/cleanup */
|
||||
/*
|
||||
static int __initdata bmc_initialized;
|
||||
*/
|
||||
|
||||
void bmc_inc_use(struct i2c_adapter *adapter)
|
||||
{
|
||||
#ifdef MODULE
|
||||
MOD_INC_USE_COUNT;
|
||||
#endif
|
||||
}
|
||||
|
||||
void bmc_dec_use(struct i2c_adapter *adapter)
|
||||
{
|
||||
#ifdef MODULE
|
||||
MOD_DEC_USE_COUNT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We can't do a thing... */
|
||||
static u32 bmc_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------*/
|
||||
|
||||
void bmc_i2c_send_message(int id, struct ipmi_msg * msg)
|
||||
{
|
||||
ipmi_request(i2c_bmc_user, &address, id, msg, 0);
|
||||
}
|
||||
|
||||
void bmcclient_i2c_send_message(struct i2c_client *client, int id, struct ipmi_msg * msg)
|
||||
{
|
||||
id = (id & 0xffff) | 0x10000;
|
||||
rcv_callback = client->driver->command;
|
||||
bmc_i2c_send_message(id, msg);
|
||||
}
|
||||
|
||||
|
||||
static void ipmi_i2c_msg_handler(struct ipmi_recv_msg *msg,
|
||||
void *handler_data)
|
||||
{
|
||||
int rcvid = msg->msgid & 0xffff;
|
||||
int client = (msg->msgid >> 16) & 0xf;
|
||||
|
||||
if (msg->msg.data[0] != 0) {
|
||||
printk(KERN_ERR "IPMI BMC response: Error 0x%x on cmd 0x%x\n",
|
||||
msg->msg.data[0],
|
||||
msg->msg.cmd);
|
||||
} else {
|
||||
/*
|
||||
printk(KERN_INFO "IPMI BMC response: No error on cmd 0x%x\n",
|
||||
msg->msg.cmd);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
if(client == 1 && rcv_callback != NULL)
|
||||
(*rcv_callback)(NULL, client, msg);
|
||||
else
|
||||
ipmi_free_recv_msg(msg);
|
||||
}
|
||||
|
||||
static struct ipmi_user_hndl ipmi_hndlrs =
|
||||
{
|
||||
.ipmi_recv_hndl = ipmi_i2c_msg_handler,
|
||||
};
|
||||
|
||||
/* callback for each BMC found */
|
||||
static void ipmi_register_bmc(int ipmi_intf)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rv = -EBUSY;
|
||||
|
||||
if(interfaces > 0) { /* 1 max for now */
|
||||
printk(KERN_INFO
|
||||
"i2c-bmc.o: Additional IPMI interface %d not supported\n",
|
||||
ipmi_intf);
|
||||
return;
|
||||
}
|
||||
|
||||
rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &i2c_bmc_user);
|
||||
if (rv < 0) {
|
||||
printk(KERN_ERR "i2c-bmc.o: Unable to register with ipmi\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ipmi_get_version(i2c_bmc_user,
|
||||
&ipmi_version_major,
|
||||
&ipmi_version_minor);
|
||||
|
||||
if ((rv = i2c_add_adapter(&bmc_adapter))) {
|
||||
printk(KERN_ERR "i2c-bmc.o: Adapter registration failed, "
|
||||
"module i2c-bmc.o is not inserted\n.");
|
||||
return;
|
||||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
"i2c-bmc.o: Registered IPMI interface %d with version %d.%d\n",
|
||||
ipmi_intf, ipmi_version_major, ipmi_version_minor);
|
||||
interfaces++;
|
||||
}
|
||||
|
||||
|
||||
static void ipmi_new_smi(int if_num)
|
||||
{
|
||||
ipmi_register_bmc(if_num);
|
||||
}
|
||||
|
||||
static void ipmi_smi_gone(int if_num)
|
||||
{
|
||||
/* TBD */
|
||||
}
|
||||
|
||||
static struct ipmi_smi_watcher smi_watcher =
|
||||
{
|
||||
.new_smi = ipmi_new_smi,
|
||||
.smi_gone = ipmi_smi_gone
|
||||
};
|
||||
|
||||
int __init i2c_bmc_init(void)
|
||||
{
|
||||
int rv;
|
||||
|
||||
printk(KERN_INFO "i2c-bmc.o version %s (%s)\n", LM_VERSION, LM_DATE);
|
||||
|
||||
rv = ipmi_smi_watcher_register(&smi_watcher);
|
||||
if (rv) {
|
||||
printk(KERN_WARNING
|
||||
"ipmi_watchdog: can't register smi watcher\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "i2c-bmc.o: BMC access for i2c modules initialized.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init bmc_cleanup(void)
|
||||
{
|
||||
ipmi_smi_watcher_unregister(&smi_watcher);
|
||||
if (interfaces >= 1) {
|
||||
i2c_del_adapter(&bmc_adapter);
|
||||
ipmi_destroy_user(i2c_bmc_user);
|
||||
interfaces--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
EXPORT_SYMBOL(bmcclient_i2c_send_message);
|
||||
|
||||
MODULE_AUTHOR("M. D. Studebaker <mdsxyz123@yahoo.com>");
|
||||
MODULE_DESCRIPTION("BMC bus access through i2c");
|
||||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
return i2c_bmc_init();
|
||||
}
|
||||
|
||||
int cleanup_module(void)
|
||||
{
|
||||
return bmc_cleanup();
|
||||
}
|
||||
|
||||
#endif /* MODULE */
|
||||
@@ -25,6 +25,9 @@ KERNELCHIPSDIR := $(MODULE_DIR)
|
||||
# defined value verbatim into the command-list of rules...
|
||||
# These targets are NOT included in 'mkpatch' ...
|
||||
KERNELCHIPSTARGETS :=
|
||||
ifeq ($(shell if grep -q '^CONFIG_IPMI_HANDLER=' $(LINUX)/.config; then echo 1; fi),1)
|
||||
KERNELCHIPSTARGETS += $(MODULE_DIR)/bmcsensors.o
|
||||
endif
|
||||
KERNELCHIPSTARGETS += $(MODULE_DIR)/smartbatt.o
|
||||
KERNELCHIPSTARGETS += $(MODULE_DIR)/smbus-arp.o
|
||||
KERNELCHIPSTARGETS += $(MODULE_DIR)/vt8231.o
|
||||
|
||||
@@ -0,0 +1,905 @@
|
||||
/*
|
||||
bmcsensors.c - Part of lm_sensors, Linux kernel modules
|
||||
for hardware monitoring
|
||||
|
||||
Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/ipmi.h>
|
||||
#include "version.h"
|
||||
#include "sensors.h"
|
||||
#include <linux/init.h>
|
||||
|
||||
static unsigned short normal_i2c[] = { SENSORS_I2C_END };
|
||||
static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
|
||||
static unsigned int normal_isa[] = { 0, SENSORS_ISA_END };
|
||||
static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
|
||||
|
||||
SENSORS_INSMOD_1(bmcsensors);
|
||||
|
||||
#ifdef MODULE
|
||||
extern int init_module(void);
|
||||
extern int cleanup_module(void);
|
||||
#endif /* MODULE */
|
||||
|
||||
struct bmcsensors_data {
|
||||
struct semaphore lock;
|
||||
int sysctl_id;
|
||||
|
||||
struct semaphore update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
u8 alarms;
|
||||
};
|
||||
|
||||
#ifdef MODULE
|
||||
static
|
||||
#else
|
||||
extern
|
||||
#endif
|
||||
int __init sensors_bmcsensors_init(void);
|
||||
static int __init bmcsensors_cleanup(void);
|
||||
|
||||
static int bmcsensors_attach_adapter(struct i2c_adapter *adapter);
|
||||
static int bmcsensors_detect(struct i2c_adapter *adapter, int address,
|
||||
unsigned short flags, int kind);
|
||||
static int bmcsensors_detach_client(struct i2c_client *client);
|
||||
static int bmcsensors_command(struct i2c_client *client, unsigned int cmd,
|
||||
void *arg);
|
||||
static void bmcsensors_inc_use(struct i2c_client *client);
|
||||
static void bmcsensors_dec_use(struct i2c_client *client);
|
||||
|
||||
static void bmcsensors_update_client(struct i2c_client *client);
|
||||
static void bmcsensors_init_client(struct i2c_client *client);
|
||||
static int bmcsensors_find(int *address);
|
||||
|
||||
|
||||
static void bmcsensors_all(struct i2c_client *client, int operation,
|
||||
int ctl_name, int *nrels_mag, long *results);
|
||||
static void bmcsensors_alarms(struct i2c_client *client, int operation,
|
||||
int ctl_name, int *nrels_mag, long *results);
|
||||
static void bmcsensors_fan_div(struct i2c_client *client, int operation,
|
||||
int ctl_name, int *nrels_mag, long *results);
|
||||
static void bmcsensors_pwm(struct i2c_client *client, int operation,
|
||||
int ctl_name, int *nrels_mag, long *results);
|
||||
void bmcsensors_get_sdr(u16 resid, u16 record, u8 offset);
|
||||
void bmcsensors_get_reading(struct i2c_client *client, int i);
|
||||
|
||||
static int bmcsensors_id = 0;
|
||||
|
||||
static struct i2c_driver bmcsensors_driver = {
|
||||
/* name */ "BMC Sensors driver",
|
||||
/* id */ I2C_DRIVERID_BMCSENSORS,
|
||||
/* flags */ I2C_DF_NOTIFY,
|
||||
/* attach_adapter */ &bmcsensors_attach_adapter,
|
||||
/* detach_client */ &bmcsensors_detach_client,
|
||||
/* command */ &bmcsensors_command,
|
||||
/* inc_use */ &bmcsensors_inc_use,
|
||||
/* dec_use */ &bmcsensors_dec_use
|
||||
};
|
||||
|
||||
static struct bmcsensors_data bmc_data;
|
||||
struct i2c_client bmc_client = {
|
||||
"BMC Sensors",
|
||||
1, /* fake should be 0 */
|
||||
0,
|
||||
0,
|
||||
NULL, /* adapter */
|
||||
&bmcsensors_driver,
|
||||
& bmc_data,
|
||||
0
|
||||
};
|
||||
|
||||
static bmcsensors_initialized;
|
||||
|
||||
|
||||
#define MAX_SDR_ENTRIES 50
|
||||
#define SDR_LIMITS 13
|
||||
#define SDR_MAX_ID_LENGTH 16
|
||||
#define SDR_MAX_UNPACKED_ID_LENGTH ((SDR_MAX_ID_LENGTH * 4 / 3) + 2)
|
||||
struct sdrdata {
|
||||
/* reverse lookup from sysctl */
|
||||
int sysctl;
|
||||
/* retrieved from SDR, not expected to change */
|
||||
u8 stype;
|
||||
u8 number;
|
||||
u8 linear;
|
||||
s16 m;
|
||||
s16 b;
|
||||
u8 k;
|
||||
u8 limits[SDR_LIMITS];
|
||||
u8 string_type;
|
||||
u8 id_length;
|
||||
u8 id[SDR_MAX_ID_LENGTH];
|
||||
/* retrieved from reading */
|
||||
u8 reading;
|
||||
u8 status;
|
||||
u8 thresholds;
|
||||
};
|
||||
static struct sdrdata sdrd[MAX_SDR_ENTRIES];
|
||||
static int sdrd_count;
|
||||
|
||||
#define MAX_PROC_ENTRIES (MAX_SDR_ENTRIES + 5)
|
||||
#define MAX_PROCNAME_SIZE 8
|
||||
static ctl_table *bmcsensors_dir_table;
|
||||
static char *bmcsensors_proc_name_pool;
|
||||
|
||||
#define IPMI_SDR_SIZE 67
|
||||
static int ipmi_sdr_partial_size = IPMI_SDR_SIZE;
|
||||
static struct ipmi_msg tx_message; /* send message */
|
||||
static unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH + 50];
|
||||
static unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH + 50]; /* sloppy */
|
||||
int rx_msg_data_offset;
|
||||
static long msgid; /* message ID */
|
||||
static u16 resid;
|
||||
|
||||
enum states {STATE_INIT, STATE_RESERVE, STATE_SDR, STATE_SDRPARTIAL, STATE_READING, STATE_DONE};
|
||||
int state;
|
||||
static int receive_counter;
|
||||
|
||||
|
||||
/* IPMI Message defs */
|
||||
/* Network Function Codes */
|
||||
#define IPMI_NETFN_SENSOR 0x04
|
||||
#define IPMI_NETFN_STORAGE 0x0A
|
||||
/* Commands */
|
||||
#define IPMI_RESERVE_SDR 0x22
|
||||
#define IPMI_GET_SDR 0x23
|
||||
#define IPMI_GET_SENSOR_STATE_READING 0x2D
|
||||
|
||||
/* SDR defs */
|
||||
#define STYPE_TEMP 0x01
|
||||
#define STYPE_VOLT 0x02
|
||||
#define STYPE_CURR 0x03
|
||||
#define STYPE_FAN 0x04
|
||||
|
||||
/* get rid of this ***************/
|
||||
#define STYPE_MAX 0x29 /* the last sensor type we are interested in */
|
||||
static u8 bmcs_count[STYPE_MAX + 1] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
static const u8 bmcs_max[STYPE_MAX + 1] = {
|
||||
0, 10, 10, 10, 10, 0, 0, 0}; /* more zeros*/
|
||||
|
||||
/************************************/
|
||||
|
||||
|
||||
/* unpack based on string type, convert to normal, null terminate */
|
||||
static void ipmi_sprintf(u8 * to, u8 * from, u8 type, u8 length)
|
||||
{
|
||||
static const u8 *bcdplus = "0123456789 -.:,_";
|
||||
int i;
|
||||
|
||||
switch (type) {
|
||||
case 0: /* unicode */
|
||||
for(i = 0; i < length; i++)
|
||||
*to++ = *from++ & 0x7f;
|
||||
*to = 0;
|
||||
break;
|
||||
case 1: /* BCD Plus */
|
||||
for(i = 0; i < length; i++)
|
||||
*to++ = bcdplus[*from++ & 0x0f];
|
||||
*to = 0;
|
||||
break;
|
||||
case 2: /* packed ascii */ /* if not a mult. of 3 this will run over */
|
||||
for(i = 0; i < length; i += 3) {
|
||||
*to++ = *from & 0x3f;
|
||||
*to++ = *from++ >> 6 | ((*from & 0xf) << 2);
|
||||
*to++ = *from++ >> 4 | ((*from & 0x3) << 4);
|
||||
*to++ = (*from++ >> 2) & 0x3f;
|
||||
}
|
||||
*to = 0;
|
||||
break;
|
||||
case 3: /* normal */
|
||||
if(length > 1)
|
||||
memcpy(to, from, length);
|
||||
to[length] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* After we have received all the SDR entries and picked out the ones
|
||||
we are interested in, build a table of the /proc entries and register.
|
||||
*/
|
||||
static void bmcsensors_build_proc_table()
|
||||
{
|
||||
int i;
|
||||
int temps = 0, volts = 0, currs = 0, fans = 0;
|
||||
u8 id[SDR_MAX_UNPACKED_ID_LENGTH];
|
||||
|
||||
if(!(bmcsensors_dir_table = kmalloc((sdrd_count + 1) * sizeof(struct ctl_table), GFP_KERNEL))) {
|
||||
printk(KERN_ERR "bmcsensors.o: no memory\n");
|
||||
return; /* do more than this */ /* ^^ add 1 or more for alarms, etc. */
|
||||
}
|
||||
if(!(bmcsensors_proc_name_pool = kmalloc((sdrd_count + 0) * MAX_PROCNAME_SIZE, GFP_KERNEL))) {
|
||||
kfree(bmcsensors_dir_table);
|
||||
printk(KERN_ERR "bmcsensors.o: no memory\n");
|
||||
return; /* do more than this */ /* ^^ add 1 or more for alarms, etc. */
|
||||
}
|
||||
|
||||
for(i = 0; i < sdrd_count; i++) {
|
||||
bmcsensors_dir_table[i].procname = bmcsensors_proc_name_pool + (i * MAX_PROCNAME_SIZE);
|
||||
bmcsensors_dir_table[i].data = NULL;
|
||||
bmcsensors_dir_table[i].maxlen = 0;
|
||||
bmcsensors_dir_table[i].mode = 0644;
|
||||
bmcsensors_dir_table[i].child = NULL;
|
||||
bmcsensors_dir_table[i].proc_handler = &i2c_proc_real;
|
||||
bmcsensors_dir_table[i].strategy = &i2c_sysctl_real;
|
||||
bmcsensors_dir_table[i].de = NULL;
|
||||
|
||||
switch(sdrd[i].stype) {
|
||||
case(STYPE_TEMP) :
|
||||
bmcsensors_dir_table[i].ctl_name = BMCSENSORS_SYSCTL_TEMP1 + temps;
|
||||
sprintf((char *)bmcsensors_dir_table[i].procname, "temp%d", ++temps);
|
||||
bmcsensors_dir_table[i].extra1 = &bmcsensors_all;
|
||||
break;
|
||||
case(STYPE_VOLT) :
|
||||
bmcsensors_dir_table[i].ctl_name = BMCSENSORS_SYSCTL_IN1 + volts;
|
||||
sprintf((char *)bmcsensors_dir_table[i].procname, "in%d", ++volts);
|
||||
bmcsensors_dir_table[i].extra1 = &bmcsensors_all;
|
||||
break;
|
||||
case(STYPE_CURR) :
|
||||
bmcsensors_dir_table[i].ctl_name = BMCSENSORS_SYSCTL_CURR1 + currs;
|
||||
sprintf((char *)bmcsensors_dir_table[i].procname, "curr%d", ++currs);
|
||||
bmcsensors_dir_table[i].extra1 = &bmcsensors_all;
|
||||
break;
|
||||
case(STYPE_FAN) :
|
||||
bmcsensors_dir_table[i].ctl_name = BMCSENSORS_SYSCTL_FAN1 + fans;
|
||||
sprintf((char *)bmcsensors_dir_table[i].procname, "fan%d", ++fans);
|
||||
bmcsensors_dir_table[i].extra1 = &bmcsensors_all;
|
||||
break;
|
||||
default: /* ?? */
|
||||
printk(KERN_INFO "bmcsensors.o: unk stype\n");
|
||||
continue;
|
||||
}
|
||||
sdrd[i].sysctl = bmcsensors_dir_table[i].ctl_name;
|
||||
if(sdrd[i].linear != 0) {
|
||||
printk(KERN_INFO "bmcsensors.o: sensor %d: (type 0x%x) nonlinear function 0x%.2x unsupported\n",
|
||||
i, sdrd[i].stype, sdrd[i].linear);
|
||||
}
|
||||
ipmi_sprintf(id, sdrd[i].id, sdrd[i].string_type, sdrd[i].id_length);
|
||||
printk(KERN_INFO "bmcsensors.o: registering sensor %d: '%s' (type 0x%x) as %s "
|
||||
"(m=%d; b=%d; k1=%d; k2=%d)\n",
|
||||
i, id, sdrd[i].stype, bmcsensors_dir_table[i].procname,
|
||||
sdrd[i].m, sdrd[i].b,sdrd[i].k & 0xf, sdrd[i].k >> 4);
|
||||
}
|
||||
bmcsensors_dir_table[sdrd_count].ctl_name = 0;
|
||||
|
||||
if ((i = i2c_register_entry(&bmc_client, "bmc",
|
||||
bmcsensors_dir_table,
|
||||
THIS_MODULE)) < 0) {
|
||||
printk(KERN_INFO "bmcsensors.o: i2c registration failed.\n");
|
||||
kfree(bmcsensors_dir_table);
|
||||
kfree(bmcsensors_proc_name_pool);
|
||||
return;
|
||||
}
|
||||
bmcsensors_initialized = 3;
|
||||
bmc_data.sysctl_id = i;
|
||||
|
||||
bmcsensors_init_client(&bmc_client);
|
||||
printk(KERN_INFO "bmcsensors.o: registered %d temp, %d volt, %d current, %d fan sensors\n",
|
||||
temps, volts, currs, fans);
|
||||
bmcsensors_update_client(&bmc_client);
|
||||
}
|
||||
|
||||
|
||||
/* Process a sensor reading response */
|
||||
static int bmcsensors_rcv_reading_msg(struct ipmi_msg *msg)
|
||||
{
|
||||
if(receive_counter >= sdrd_count) {
|
||||
/* shouldn't happen */
|
||||
receive_counter = 0;
|
||||
return STATE_DONE;
|
||||
}
|
||||
sdrd[receive_counter].reading = msg->data[1];
|
||||
sdrd[receive_counter].status = msg->data[2];
|
||||
sdrd[receive_counter].thresholds = msg->data[3];
|
||||
#ifdef DEBUG
|
||||
printk(KERN_DEBUG "bmcsensors.o: sensor %d (type %d) reading %d\n",
|
||||
receive_counter, sdrd[receive_counter].stype, msg->data[1]);
|
||||
#endif
|
||||
if(++receive_counter >= sdrd_count) {
|
||||
receive_counter = 0;
|
||||
return STATE_DONE;
|
||||
}
|
||||
bmcsensors_get_reading(&bmc_client, receive_counter); /* don't really need to pass client */
|
||||
return STATE_READING;
|
||||
}
|
||||
|
||||
/* Process a SDR response */
|
||||
static int bmcsensors_rcv_sdr_msg(struct ipmi_msg *msg, int state)
|
||||
{
|
||||
u16 record, nextrecord;
|
||||
int version, type, length, owner, lun, number, entity, instance, init;
|
||||
int capab, stype, code;
|
||||
int id_length;
|
||||
int i;
|
||||
int rstate = STATE_SDR;
|
||||
struct ipmi_msg txmsg;
|
||||
unsigned char * data;
|
||||
|
||||
|
||||
if(msg->data[0] != 0) {
|
||||
/* cut request in half and try again */
|
||||
ipmi_sdr_partial_size /= 2;
|
||||
if(ipmi_sdr_partial_size < 8) {
|
||||
printk(KERN_INFO "bmcsensors.o: IPMI buffers too small, giving up\n");
|
||||
return STATE_DONE;
|
||||
}
|
||||
printk(KERN_INFO "bmcsensors.o: Reducing SDR request size to %d\n", ipmi_sdr_partial_size);
|
||||
bmcsensors_get_sdr(resid, 0, 0);
|
||||
return STATE_SDR;
|
||||
}
|
||||
if(ipmi_sdr_partial_size < IPMI_SDR_SIZE) {
|
||||
if(rx_msg_data_offset == 0) {
|
||||
memcpy(rx_msg_data, msg->data, ipmi_sdr_partial_size + 3);
|
||||
rx_msg_data_offset = ipmi_sdr_partial_size + 3;
|
||||
} else {
|
||||
memcpy(rx_msg_data + rx_msg_data_offset, msg->data + 3, ipmi_sdr_partial_size);
|
||||
rx_msg_data_offset += ipmi_sdr_partial_size;
|
||||
}
|
||||
if(rx_msg_data_offset > IPMI_SDR_SIZE + 3) {
|
||||
/* got last chunk */
|
||||
rx_msg_data_offset = 0;
|
||||
data = rx_msg_data;
|
||||
} else {
|
||||
/* get more */
|
||||
record = (rx_msg_data[4] << 8) | rx_msg_data[3];
|
||||
bmcsensors_get_sdr(resid, record, rx_msg_data_offset - 3);
|
||||
return STATE_SDR;
|
||||
}
|
||||
} else {
|
||||
data = msg->data; /* got it in one chunk */
|
||||
}
|
||||
|
||||
nextrecord = (data[2] << 8) | data[1];
|
||||
version = data[5];
|
||||
type = data[6];
|
||||
if(type == 1 || type == 2) { /* known SDR type */
|
||||
owner = data[8];
|
||||
lun = data[9];
|
||||
entity = data[11];
|
||||
init = data[13];
|
||||
capab = data[14];
|
||||
stype = data[15];
|
||||
|
||||
if(stype <= STYPE_MAX) { /* known sensor type */
|
||||
if(bmcs_count[stype] >= bmcs_max[stype]) {
|
||||
if(bmcs_max[stype] > 0) {
|
||||
printk(KERN_INFO "bmcsensors.o: Limit of %d exceeded for sensor type 0x%x\n", bmcs_max[stype], stype);
|
||||
#ifdef DEBUG
|
||||
} else {
|
||||
printk(KERN_INFO "bmcsensors.o: Ignoring unsupported sensor type 0x%x\n", stype);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if(sdrd_count >= MAX_SDR_ENTRIES) {
|
||||
printk(KERN_INFO "bmcsensors.o: Limit of %d exceeded for total sensors\n", MAX_SDR_ENTRIES);
|
||||
} else {
|
||||
/* add SDR database entry */
|
||||
sdrd[sdrd_count].stype = stype;
|
||||
sdrd[sdrd_count].number = data[10];
|
||||
if(type == 1) {
|
||||
sdrd[sdrd_count].linear = data[26] & 0x7f;
|
||||
sdrd[sdrd_count].m = data[27];
|
||||
sdrd[sdrd_count].m |= ((u16) (data[28] & 0xc0)) << 2;
|
||||
if(sdrd[sdrd_count].m & 0x0200)
|
||||
sdrd[sdrd_count].m |= 0xfc00; /* sign extend */
|
||||
sdrd[sdrd_count].b = data[29];
|
||||
sdrd[sdrd_count].b |= ((u16) (data[30] & 0xc0)) << 2;
|
||||
if(sdrd[sdrd_count].b & 0x0200)
|
||||
sdrd[sdrd_count].b |= 0xfc00; /* sign extend */
|
||||
sdrd[sdrd_count].k = data[32];
|
||||
for(i = 0; i < SDR_LIMITS; i++)
|
||||
sdrd[sdrd_count].limits[i] = data[34 + i];
|
||||
sdrd[sdrd_count].string_type = data[50] >> 6;
|
||||
id_length = data[50] & 0x1f;
|
||||
if(id_length > 0)
|
||||
memcpy(sdrd[sdrd_count].id, &data[51], id_length);
|
||||
sdrd[sdrd_count].id_length = id_length;
|
||||
} else {
|
||||
sdrd[sdrd_count].m = 1;
|
||||
sdrd[sdrd_count].b = 0;
|
||||
sdrd[sdrd_count].k = 0;
|
||||
sdrd[sdrd_count].string_type = data[34] >> 6;
|
||||
id_length = data[34] & 0x1f;
|
||||
if(id_length > 0)
|
||||
memcpy(sdrd[sdrd_count].id, &data[35], id_length);
|
||||
sdrd[sdrd_count].id_length = id_length;
|
||||
}
|
||||
bmcs_count[stype]++;
|
||||
sdrd_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
} else {
|
||||
printk(KERN_INFO "bmcsensors.o: Ignoring sensor type 0x%x\n", stype);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
printk(KERN_INFO "bmcsensors.o: STATE_SDR: record = 0x%x; version = 0x%x, type = 0x%x; length=0x%x\n",
|
||||
record, version, type, length);
|
||||
printk(KERN_INFO "bmcsensors.o: STATE_SDR: owner = 0x%x; lun = 0x%x, number = 0x%x; entity=0x%x\n",
|
||||
owner, lun, number, entity);
|
||||
printk(KERN_INFO "bmcsensors.o: STATE_SDR: instance = 0x%x; init = 0x%x, capab = 0x%x; stype=0x%x\n",
|
||||
instance, init, capab, stype);
|
||||
printk(KERN_INFO "bmcsensors.o: STATE_SDR: code = 0x%x\n",
|
||||
code);
|
||||
printk(KERN_INFO "bmcsensors.o: STATE_SDR: next = 0x%x\n", nextrecord);
|
||||
} else {
|
||||
printk(KERN_INFO "bmcsensors.o: unknown STATE_SDR type 0x%x\n", type);
|
||||
*/
|
||||
}
|
||||
|
||||
if(nextrecord == 0xFFFF) {
|
||||
rstate = STATE_READING;
|
||||
if(sdrd_count == 0) {
|
||||
printk(KERN_INFO "bmcsensors.o: No recognized sensors found.\n");
|
||||
} else {
|
||||
printk(KERN_INFO "bmcsensors.o: found %d temp, %d volt, %d current, %d fan sensors\n",
|
||||
bmcs_count[1], bmcs_count[2], bmcs_count[3], bmcs_count[4]);
|
||||
bmcsensors_build_proc_table();
|
||||
}
|
||||
} else {
|
||||
bmcsensors_get_sdr(resid, nextrecord, 0);
|
||||
}
|
||||
return rstate;
|
||||
}
|
||||
|
||||
/* Process incoming messages based on internal state */
|
||||
static void bmcsensors_rcv_msg(struct ipmi_msg *msg)
|
||||
{
|
||||
|
||||
switch(state) {
|
||||
case STATE_INIT:
|
||||
case STATE_RESERVE:
|
||||
resid = (msg->data[2] << 8) || msg->data[1];
|
||||
bmcsensors_get_sdr(resid, 0, 0);
|
||||
state = STATE_SDR;
|
||||
break;
|
||||
|
||||
case STATE_SDR:
|
||||
case STATE_SDRPARTIAL:
|
||||
state = bmcsensors_rcv_sdr_msg(msg, state);
|
||||
break;
|
||||
|
||||
|
||||
case STATE_READING:
|
||||
state = bmcsensors_rcv_reading_msg(msg);
|
||||
break;
|
||||
|
||||
case STATE_DONE:
|
||||
break;
|
||||
|
||||
default:
|
||||
state = STATE_INIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Incoming message handler */
|
||||
static void bmcsensors_msg_handler(struct ipmi_recv_msg *msg,
|
||||
void * handler_data)
|
||||
{
|
||||
if (msg->msg.data[0] != 0 && msg->msg.data[0] != 0xca) {
|
||||
printk(KERN_ERR "BMCsensors response: Error %x on cmd %x; state = %d; probably fatal.\n",
|
||||
msg->msg.data[0], msg->msg.cmd, state);
|
||||
} else {
|
||||
bmcsensors_rcv_msg(&(msg->msg));
|
||||
}
|
||||
ipmi_free_recv_msg(msg);
|
||||
}
|
||||
|
||||
/************** Message Sending **************/
|
||||
|
||||
/* Send an IPMI message */
|
||||
static void bmcsensors_send_message(struct ipmi_msg * msg)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printk(KERN_INFO "bmcsensors.o: Send BMC msg, cmd: 0x%x\n",
|
||||
msg->cmd);
|
||||
#endif
|
||||
bmcclient_i2c_send_message(&bmc_client, msgid++, msg);
|
||||
|
||||
}
|
||||
|
||||
/* Compose and send a "reserve SDR" message */
|
||||
void bmcsensors_reserve_sdr(void)
|
||||
{
|
||||
tx_message.netfn = IPMI_NETFN_STORAGE;
|
||||
tx_message.cmd = IPMI_RESERVE_SDR;
|
||||
tx_message.data_len = 0;
|
||||
tx_message.data = NULL;
|
||||
bmcsensors_send_message(&tx_message);
|
||||
}
|
||||
|
||||
/* Componse and send a "get SDR" message */
|
||||
void bmcsensors_get_sdr(u16 resid, u16 record, u8 offset)
|
||||
{
|
||||
tx_message.netfn = IPMI_NETFN_STORAGE;
|
||||
tx_message.cmd = IPMI_GET_SDR;
|
||||
tx_message.data_len = 6;
|
||||
tx_message.data = tx_msg_data;
|
||||
tx_msg_data[0] = resid & 0xff;
|
||||
tx_msg_data[1] = resid >> 8;
|
||||
tx_msg_data[2] = record & 0xff;
|
||||
tx_msg_data[3] = record >> 8;
|
||||
tx_msg_data[4] = offset;
|
||||
tx_msg_data[5] = ipmi_sdr_partial_size;
|
||||
bmcsensors_send_message(&tx_message);
|
||||
}
|
||||
|
||||
/* Compose and send a "get sensor reading" message */
|
||||
void bmcsensors_get_reading(struct i2c_client *client, int i)
|
||||
{
|
||||
tx_message.netfn = IPMI_NETFN_SENSOR;
|
||||
tx_message.cmd = IPMI_GET_SENSOR_STATE_READING;
|
||||
tx_message.data_len = 1;
|
||||
tx_message.data = tx_msg_data;
|
||||
tx_msg_data[0] = sdrd[i].number;
|
||||
bmcsensors_send_message(&tx_message);
|
||||
}
|
||||
|
||||
/**************** Initialization ****************/
|
||||
|
||||
int bmcsensors_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
/*
|
||||
not really i2c or isa so i2c_detect not required
|
||||
*/
|
||||
printk(KERN_INFO "bmcsensors.o: in bmcsensors_detect() for ID %x\n",
|
||||
adapter->algo->id);
|
||||
|
||||
if(adapter->algo->id != I2C_ALGO_IPMI) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(bmcsensors_initialized >= 2) {
|
||||
printk(KERN_INFO "bmcsensors.o: limit of 1\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bmcsensors_detect(adapter, 0, 0, 0);
|
||||
}
|
||||
|
||||
int bmcsensors_detect(struct i2c_adapter *adapter, int address,
|
||||
unsigned short flags, int kind)
|
||||
{
|
||||
int err, i;
|
||||
|
||||
bmc_client.id = 0;
|
||||
bmc_client.adapter = adapter;
|
||||
bmc_data.valid = 0;
|
||||
/*
|
||||
init_MUTEX(bmc_data.update_lock);
|
||||
*/
|
||||
|
||||
if ((err = i2c_attach_client(&bmc_client))) {
|
||||
printk(KERN_ERR "attach client error in bmcsensors_detect()\n");
|
||||
return err;
|
||||
}
|
||||
bmcsensors_initialized = 2;
|
||||
|
||||
/* initialize some key data */
|
||||
state = STATE_INIT;
|
||||
sdrd_count = 0;
|
||||
receive_counter = 0;
|
||||
rx_msg_data_offset = 0;
|
||||
ipmi_sdr_partial_size = IPMI_SDR_SIZE;
|
||||
for(i = 0; i <= STYPE_MAX; i++)
|
||||
bmcs_count[i] = 0;
|
||||
|
||||
/* send our first message, which kicks things off */
|
||||
bmcsensors_reserve_sdr();
|
||||
/* don't call i2c_register_entry until we scan the SDR's */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bmcsensors_detach_client(struct i2c_client *client)
|
||||
{
|
||||
int err;
|
||||
|
||||
if(bmcsensors_initialized >= 3) {
|
||||
kfree(bmcsensors_dir_table);
|
||||
kfree(bmcsensors_proc_name_pool);
|
||||
i2c_deregister_entry(((struct bmcsensors_data *) (client->data))->
|
||||
sysctl_id);
|
||||
}
|
||||
|
||||
if ((err = i2c_detach_client(client))) {
|
||||
/*
|
||||
printk
|
||||
("bmcsensors.o: Client deregistration failed, client not detached.\n");
|
||||
*/
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bmcsensors_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
||||
{
|
||||
bmcsensors_msg_handler((struct ipmi_recv_msg *) arg, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bmcsensors_inc_use(struct i2c_client *client)
|
||||
{
|
||||
#ifdef MODULE
|
||||
MOD_INC_USE_COUNT;
|
||||
#endif
|
||||
}
|
||||
|
||||
void bmcsensors_dec_use(struct i2c_client *client)
|
||||
{
|
||||
#ifdef MODULE
|
||||
MOD_DEC_USE_COUNT;
|
||||
#endif
|
||||
}
|
||||
|
||||
void bmcsensors_init_client(struct i2c_client *client)
|
||||
{
|
||||
/*******************************************/
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void bmcsensors_update_client(struct i2c_client *client)
|
||||
{
|
||||
struct bmcsensors_data *data = client->data;
|
||||
int i;
|
||||
|
||||
/*
|
||||
down(&data->update_lock);
|
||||
*/
|
||||
|
||||
if ((jiffies - data->last_updated > 3 * HZ) ||
|
||||
(jiffies < data->last_updated) || !data->valid) {
|
||||
/* don't start an update cycle if one already in progress */
|
||||
if(state != STATE_READING) {
|
||||
state = STATE_READING;
|
||||
printk(KERN_DEBUG "bmcsensors.o: Starting update\n");
|
||||
bmcsensors_get_reading(client, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
up(&data->update_lock);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/************* /proc callback helper functions *********/
|
||||
|
||||
/* need better way to map from sysctl to sdrd record number */
|
||||
int find_sdrd(int sysctl)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sdrd_count; i++)
|
||||
if(sdrd[i].sysctl == sysctl)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* IPMI V1.5 Section 30 */
|
||||
static const int exps[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000};
|
||||
|
||||
static int decplaces(i)
|
||||
{
|
||||
u8 k2;
|
||||
|
||||
k2 = sdrd[i].k >> 4;
|
||||
if(k2 < 8)
|
||||
return 0;
|
||||
else
|
||||
return 16 - k2;
|
||||
}
|
||||
|
||||
static long convert_reading(i)
|
||||
{
|
||||
u8 k1, k2;
|
||||
long r;
|
||||
|
||||
k1 = sdrd[i].k & 0x0f;
|
||||
k2 = sdrd[i].k >> 4;
|
||||
|
||||
r = sdrd[i].reading * sdrd[i].m;
|
||||
if(k1 < 8)
|
||||
r += sdrd[i].b * exps[k1];
|
||||
else
|
||||
r += sdrd[i].b / exps[16 - k1];
|
||||
if(k2 < 8)
|
||||
r *= exps[k2];
|
||||
/*
|
||||
taken care of by nrels_mag
|
||||
else
|
||||
r /= exps[16 - k2];
|
||||
*/
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/************** /proc callbacks *****************/
|
||||
|
||||
void bmcsensors_all(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results)
|
||||
{
|
||||
int i;
|
||||
struct bmcsensors_data *data = client->data;
|
||||
int nr = ctl_name - BMCSENSORS_SYSCTL_TEMP1 + 1;
|
||||
|
||||
if((i = find_sdrd(ctl_name)) < 0) {
|
||||
*nrels_mag = 0;
|
||||
return;
|
||||
}
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = decplaces(i);
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
bmcsensors_update_client(client);
|
||||
results[0] = convert_reading(i);
|
||||
*nrels_mag = 1;
|
||||
} else if (operation == SENSORS_PROC_REAL_WRITE) {
|
||||
if (*nrels_mag >= 1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bmcsensors_alarms(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results)
|
||||
{
|
||||
struct bmcsensors_data *data = client->data;
|
||||
#if 0
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = 0;
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
bmcsensors_update_client(client);
|
||||
results[0] = data->alarms;
|
||||
*nrels_mag = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void bmcsensors_fan_div(struct i2c_client *client, int operation,
|
||||
int ctl_name, int *nrels_mag, long *results)
|
||||
{
|
||||
struct bmcsensors_data *data = client->data;
|
||||
int old;
|
||||
|
||||
#if 0
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = 0;
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
bmcsensors_update_client(client);
|
||||
results[0] = DIV_FROM_REG(data->fan_div[0]);
|
||||
results[1] = DIV_FROM_REG(data->fan_div[1]);
|
||||
*nrels_mag = 2;
|
||||
} else if (operation == SENSORS_PROC_REAL_WRITE) {
|
||||
old = bmcsensors_read_value(client, BMCSENSORS_REG_FANDIV);
|
||||
if (*nrels_mag >= 2) {
|
||||
data->fan_div[1] = DIV_TO_REG(results[1]);
|
||||
old = (old & 0x3f) | (data->fan_div[1] << 6);
|
||||
}
|
||||
if (*nrels_mag >= 1) {
|
||||
data->fan_div[0] = DIV_TO_REG(results[0]);
|
||||
old = (old & 0xcf) | (data->fan_div[0] << 4);
|
||||
bmcsensors_write_value(client, BMCSENSORS_REG_FANDIV, old);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void bmcsensors_pwm(struct i2c_client *client, int operation, int ctl_name,
|
||||
int *nrels_mag, long *results)
|
||||
{
|
||||
struct bmcsensors_data *data = client->data;
|
||||
#if 0
|
||||
int nr = 1 + ctl_name - BMCSENSORS_SYSCTL_PWM1;
|
||||
|
||||
if (operation == SENSORS_PROC_REAL_INFO)
|
||||
*nrels_mag = 0;
|
||||
else if (operation == SENSORS_PROC_REAL_READ) {
|
||||
bmcsensors_update_client(client);
|
||||
results[0] = PWM_FROM_REG(data->pwm[nr - 1]);
|
||||
results[1] = data->pwm[nr - 1] >> 7;
|
||||
*nrels_mag = 2;
|
||||
} else if (operation == SENSORS_PROC_REAL_WRITE) {
|
||||
if (*nrels_mag >= 1) {
|
||||
data->pwm[nr - 1] &= 0x80;
|
||||
data->pwm[nr - 1] |= PWM_TO_REG(results[0]);
|
||||
if (*nrels_mag >= 2) {
|
||||
if(results[1] && (!(data->pwm[nr-1] & 0x80))) {
|
||||
/* output PWM */
|
||||
bmcsensors_write_value(client,
|
||||
BMCSENSORS_REG_PPIN(nr), 0x04);
|
||||
data->pwm[nr - 1] |= 0x80;
|
||||
}
|
||||
}
|
||||
bmcsensors_write_value(client, BMCSENSORS_REG_PWM(nr),
|
||||
data->pwm[nr - 1]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int __init sensors_bmcsensors_init(void)
|
||||
{
|
||||
int res, addr;
|
||||
|
||||
printk(KERN_INFO "bmcsensors.o version %s (%s)\n", LM_VERSION, LM_DATE);
|
||||
bmcsensors_initialized = 0;
|
||||
|
||||
if ((res = i2c_add_driver(&bmcsensors_driver))) {
|
||||
printk(KERN_ERR
|
||||
"bmcsensors.o: Driver registration failed, module not inserted.\n");
|
||||
bmcsensors_cleanup();
|
||||
return res;
|
||||
}
|
||||
bmcsensors_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init bmcsensors_cleanup(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (bmcsensors_initialized >= 1) {
|
||||
if ((res = i2c_del_driver(&bmcsensors_driver))) {
|
||||
printk(KERN_WARNING
|
||||
"bmcsensors.o: Driver deregistration failed, module not removed.\n");
|
||||
return res;
|
||||
}
|
||||
bmcsensors_initialized--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_NO_SYMBOLS;
|
||||
|
||||
#ifdef MODULE
|
||||
|
||||
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||
MODULE_DESCRIPTION("IPMI BMC sensors");
|
||||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
return sensors_bmcsensors_init();
|
||||
}
|
||||
|
||||
int cleanup_module(void)
|
||||
{
|
||||
return bmcsensors_cleanup();
|
||||
}
|
||||
|
||||
#endif /* MODULE */
|
||||
@@ -683,5 +683,11 @@
|
||||
#define SMARTBATT_SYSCTL_ALARMS 1005
|
||||
#define SMARTBATT_SYSCTL_CHARGE 1006
|
||||
|
||||
#define BMCSENSORS_SYSCTL_IN1 1000
|
||||
#define BMCSENSORS_SYSCTL_TEMP1 1100
|
||||
#define BMCSENSORS_SYSCTL_CURR1 1200
|
||||
#define BMCSENSORS_SYSCTL_FAN1 1300
|
||||
#define BMCSENSORS_SYSCTL_ALARMS 5000
|
||||
|
||||
|
||||
#endif /* def SENSORS_SENSORS_H */
|
||||
Reference in new issue
Block a user