diff --git a/src/Module.mk b/src/Module.mk deleted file mode 100644 index c03259b9..00000000 --- a/src/Module.mk +++ /dev/null @@ -1,51 +0,0 @@ -# Module.mk - Makefile for a Linux module for reading sensor data. -# Copyright (c) 1998 Frodo Looijaard -# -# 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. - -# Note that MODULE_DIR (the directory in which this file resides) is a -# 'simply expanded variable'. That means that its value is substituted -# verbatim in the rules, until it is redefined. -MODULE_DIR := src - -# Regrettably, even 'simply expanded variables' will not put their currently -# defined value verbatim into the command-list of rules... -SRCTARGETS := $(MODULE_DIR)/smbus.o $(MODULE_DIR)/piix4.o $(MODULE_DIR)/isa.o \ - $(MODULE_DIR)/lm78.o $(MODULE_DIR)/sensors.o \ - $(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/lm75.o \ - $(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/gl518sm.o \ - $(MODULE_DIR)/eeprom.o $(MODULE_DIR)/w83781d.o \ - $(MODULE_DIR)/lm80.o $(MODULE_DIR)/adm1021.o \ - $(MODULE_DIR)/adm9240.o $(MODULE_DIR)/ltc1710.o \ - $(MODULE_DIR)/i2c-dev.o - -SRCHEADERFILES := $(MODULE_DIR)/sensors.h $(MODULE_DIR)/isa.h \ - $(MODULE_DIR)/smbus.h $(MODULE_DIR)/i2c-dev.h - -# Include all dependency files -INCLUDEFILES += $(SRCTARGETS:.o=.d) - -all-src: $(SRCTARGETS) -all :: all-src - -install-src: all-src - $(MKDIR) $(MODDIR) $(SYSINCLUDEDIR) - $(INSTALL) -o root -g root -m 644 $(SRCTARGETS) $(MODDIR) - $(INSTALL) -o root -g root -m 644 $(SRCHEADERFILES) $(SYSINCLUDEDIR) -install :: install-src - -clean-src: - $(RM) $(SRCTARGETS) $(SRCTARGETS:.o=.d) -clean :: clean-src diff --git a/src/adm1021.c b/src/adm1021.c deleted file mode 100644 index f16c2d29..00000000 --- a/src/adm1021.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - adm1021.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard and - Philip Edelbrock - - 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 -#include -#include "smbus.h" -#include "sensors.h" -#include "i2c.h" -#include "version.h" - -/* adm1021 constants specified below */ - -/* The adm1021 registers */ -/* Read-only */ -#define adm1021_REG_TEMP 0x00 -#define adm1021_REG_REMOTE_TEMP 0x01 -#define adm1021_REG_STATUS 0x02 -#define adm1021_REG_DEVICE_ID 0x0FE /* should always read 0x41 */ -#define adm1021_REG_DIE_CODE 0x0FF -/* These use different addresses for reading/writing */ -#define adm1021_REG_CONFIG_R 0x03 -#define adm1021_REG_CONFIG_W 0x09 -#define adm1021_REG_CONV_RATE_R 0x04 -#define adm1021_REG_CONV_RATE_W 0x0A -#define adm1021_REG_TOS_R 0x05 -#define adm1021_REG_TOS_W 0x0B -#define adm1021_REG_REMOTE_TOS_R 0x07 -#define adm1021_REG_REMOTE_TOS_W 0x0D -#define adm1021_REG_THYST_R 0x06 -#define adm1021_REG_THYST_W 0x0C -#define adm1021_REG_REMOTE_THYST_R 0x08 -#define adm1021_REG_REMOTE_THYST_W 0x0E -/* write-only */ -#define adm1021_REG_ONESHOT 0x0F - - -/* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) -#define TEMP_TO_REG(val) (val < 0 ? val+256 : val) - -/* Initial values */ - -/* Note: Eventhough I left the low and high limits named os and hyst, -they don't quite work like a thermostat the way the LM75 does. I.e., -a lower temp than THYST actuall triggers an alarm instead of -clearing it. Weird, ey? --Phil */ -#define adm1021_INIT_TOS 60 -#define adm1021_INIT_THYST 20 -#define adm1021_INIT_REMOTE_TOS 60 -#define adm1021_INIT_REMOTE_THYST 20 - -/* Each client has this additional data */ -struct adm1021_data { - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 temp,temp_os,temp_hyst; /* Register values */ - u8 remote_temp,remote_temp_os,remote_temp_hyst,status,die_code; -}; - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static int adm1021_init(void); -static int adm1021_cleanup(void); -static int adm1021_attach_adapter(struct i2c_adapter *adapter); -static int adm1021_detach_client(struct i2c_client *client); -static int adm1021_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void adm1021_inc_use (struct i2c_client *client); -static void adm1021_dec_use (struct i2c_client *client); -static u16 swap_bytes(u16 val); -static int adm1021_read_value(struct i2c_client *client, u8 reg); -static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value); -static void adm1021_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm1021_remote_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm1021_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm1021_die_code(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm1021_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver adm1021_driver = { - /* name */ "adm1021 sensor chip driver", - /* id */ I2C_DRIVERID_ADM1021, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &adm1021_attach_adapter, - /* detach_client */ &adm1021_detach_client, - /* command */ &adm1021_command, - /* inc_use */ &adm1021_inc_use, - /* dec_use */ &adm1021_dec_use -}; - -/* These files are created for each detected adm1021. 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 adm1021_dir_table_template[] = { - { ADM1021_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm1021_temp }, - {ADM1021_SYSCTL_REMOTE_TEMP, "remote_temp", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm1021_remote_temp }, - {ADM1021_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm1021_die_code }, - {ADM1021_SYSCTL_STATUS, "status", NULL, 0, 0444, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm1021_status }, - { 0 } -}; - -/* Used by init/cleanup */ -static int adm1021_initialized = 0; - -/* I choose here for semi-static 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_adm1021_NR 9 -static struct i2c_client *adm1021_list[MAX_adm1021_NR]; - - -int adm1021_attach_adapter(struct i2c_adapter *adapter) -{ - int address,err,i; - struct i2c_client *new_client; - struct adm1021_data *data; - - err = 0; - - /* OK, this is no detection. I know. It will do for now, though. */ - - /* Set err only if a global error would make registering other clients - impossible too (like out-of-memory). */ - for (address = 0x18; (! err) && (address <= 0x54); address ++) { - /* Legal addresses: 0x18,19,20, 29,30,31, 52,53,54 - (Notice the two jumps) */ - if (address==0x21) { address=0x28; continue;} - if (address==0x32) { address=0x51; continue;} - /* Later on, we will keep a list of registered addresses for each - adapter, and check whether they are used here */ - - /* Verify device is 1021 by checked special DEVICE_ID - register (I wish all SMBus chips had this..) */ - if (smbus_read_byte_data(adapter,address,adm1021_REG_DEVICE_ID) != 0x41){ - continue; - } else { - printk("dm1021.o: Device found and passed detection.\n"); - } - /* continue; */ - - /* Allocate space for a new client structure */ - if (! (new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct adm1021_data), - GFP_KERNEL))) { - err = -ENOMEM; - continue; - } - - /* Find a place in our global list */ - for (i = 0; i < MAX_adm1021_NR; i++) - if (! adm1021_list[i]) - break; - if (i == MAX_adm1021_NR) { - err = -ENOMEM; - printk("adm1021.o: No empty slots left, recompile and heighten " - "MAX_adm1021_NR!\n"); - goto ERROR1; - } - adm1021_list[i] = new_client; - - /* Fill the new client structure with data */ - data = (struct adm1021_data *) (new_client + 1); - new_client->data = data; - new_client->id = i; - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1021_driver; - strcpy(new_client->name,"adm1021 chip"); - data->valid = 0; - data->update_lock = MUTEX; - - /* Tell i2c-core a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Register a new directory entry with module sensors */ - if ((err = sensors_register_entry(new_client,"adm1021", - adm1021_dir_table_template)) < 0) - goto ERROR3; - data->sysctl_id = err; - err = 0; - - /* Initialize the adm1021 chip */ - adm1021_write_value(new_client,adm1021_REG_TOS_W, - TEMP_TO_REG(adm1021_INIT_TOS)); - adm1021_write_value(new_client,adm1021_REG_THYST_W, - TEMP_TO_REG(adm1021_INIT_THYST)); - adm1021_write_value(new_client,adm1021_REG_REMOTE_TOS_W, - TEMP_TO_REG(adm1021_INIT_REMOTE_TOS)); - adm1021_write_value(new_client,adm1021_REG_REMOTE_THYST_W, - TEMP_TO_REG(adm1021_INIT_REMOTE_THYST)); - adm1021_write_value(new_client,adm1021_REG_CONFIG_W,0); /* Enable ADC and disable suspend mode */ - /* Set Conversion rate to 1/sec (this can be tinkered with) */ - adm1021_write_value(new_client,adm1021_REG_CONV_RATE_W,0x04); - - continue; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -ERROR3: - i2c_detach_client(new_client); -ERROR2: - adm1021_list[i] = NULL; -ERROR1: - kfree(new_client); - } - return err; -} - -int adm1021_detach_client(struct i2c_client *client) -{ - int err,i; - for (i = 0; i < MAX_adm1021_NR; i++) - if (client == adm1021_list[i]) - break; - if ((i == MAX_adm1021_NR)) { - printk("adm1021.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct adm1021_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("adm1021.o: Client deregistration failed, client not detached.\n"); - return err; - } - - adm1021_list[i] = NULL; - kfree(client); - return 0; -} - - -/* No commands defined yet */ -int adm1021_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void adm1021_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void adm1021_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u16 swap_bytes(u16 val) -{ - return (val >> 8) | (val << 8); -} - -/* All registers are byte-sized */ -int adm1021_read_value(struct i2c_client *client, u8 reg) -{ - return smbus_read_byte_data(client->adapter,client->addr,reg); -} - -int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - return smbus_write_byte_data(client->adapter,client->addr,reg,value); -} - -void adm1021_update_client(struct i2c_client *client) -{ - struct adm1021_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ+HZ/2 ) || - (jiffies < data->last_updated) || ! data->valid) { - -#ifdef DEBUG - printk("Starting adm1021 update\n"); -#endif - - data->temp = adm1021_read_value(client,adm1021_REG_TEMP); - data->temp_os = adm1021_read_value(client,adm1021_REG_TOS_R); - data->temp_hyst = adm1021_read_value(client,adm1021_REG_THYST_R); - data->remote_temp = adm1021_read_value(client,adm1021_REG_REMOTE_TEMP); - data->remote_temp_os = adm1021_read_value(client,adm1021_REG_REMOTE_TOS_R); - data->remote_temp_hyst = adm1021_read_value(client,adm1021_REG_REMOTE_THYST_R); - data->die_code = adm1021_read_value(client,adm1021_REG_DIE_CODE); - data->status = adm1021_read_value(client,adm1021_REG_STATUS); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void adm1021_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_os); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os = TEMP_TO_REG(results[0]); - adm1021_write_value(client,adm1021_REG_TOS_W,data->temp_os); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - adm1021_write_value(client,adm1021_REG_THYST_W,data->temp_hyst); - } - } -} - -void adm1021_remote_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_temp_os); - results[1] = TEMP_FROM_REG(data->remote_temp_hyst); - results[2] = TEMP_FROM_REG(data->remote_temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->remote_temp_os = TEMP_TO_REG(results[0]); - adm1021_write_value(client,adm1021_REG_REMOTE_TOS_W,data->remote_temp_os); - } - if (*nrels_mag >= 2) { - data->remote_temp_hyst = TEMP_TO_REG(results[1]); - adm1021_write_value(client,adm1021_REG_REMOTE_THYST_W,data->remote_temp_hyst); - } - } -} - -void adm1021_die_code(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = data->die_code; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* Can't write to it */ - } -} - -void adm1021_status(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm1021_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm1021_update_client(client); - results[0] = data->status; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - /* Can't write to it */ - } -} - -int adm1021_init(void) -{ - int res; - - printk("adm1021.o version %s (%s)\n",LM_VERSION,LM_DATE); - adm1021_initialized = 0; - if ((res = i2c_add_driver(&adm1021_driver))) { - printk("adm1021.o: Driver registration failed, module not inserted.\n"); - adm1021_cleanup(); - return res; - } - adm1021_initialized ++; - return 0; -} - -int adm1021_cleanup(void) -{ - int res; - - if (adm1021_initialized >= 1) { - if ((res = i2c_del_driver(&adm1021_driver))) { - printk("adm1021.o: Driver deregistration failed, module not removed.\n"); - return res; - } - adm1021_initialized --; - } - - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("adm1021 driver"); - -int init_module(void) -{ - return adm1021_init(); -} - -int cleanup_module(void) -{ - return adm1021_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/adm9240.c b/src/adm9240.c deleted file mode 100644 index 4739d375..00000000 --- a/src/adm9240.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - adm9240.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1999 Frodo Looijaard - and Philip Edelbrock - - 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. -*/ - -/* - A couple notes about the ADM2940: - -* It claims to be 'LM7x' register compatible. This must be in reference - to only the LM78, because it is missing stuff to emulate LM75's as well. - (like the Winbond W83781 does) - -* This driver was written from rev. 0 of the PDF, but it seems well - written and complete (unlike the W83781 which is horrible and has - supposidly gone through a few revisions.. rev 0 of that one must - have been in crayon on construction paper...) - -* All analog inputs can range from 0 to 2.5, eventhough some inputs are - marked as being 5V, 12V, etc. I don't have any real voltages going - into my prototype, so I'm not sure that things are computed right, - but at least the limits seem to be working OK. - -* Another curiousity is that the fan_div seems to be read-only. I.e., - any written value to it doesn't seem to make any difference. The - fan_div seems to be 'stuck' at 2 (which isn't a bad value in most cases). - - - --Phil - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "smbus.h" -#include "version.h" -#include "isa.h" -#include "sensors.h" -#include "i2c.h" -#include "compat.h" - -/* Many ADM9240 constants specified below */ - -#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define ADM9240_REG_IN(nr) (0x20 + (nr)) - -/* The ADM9240 registers */ -#define ADM9240_REG_TEST 0x15 -#define ADM9240_REG_ANALOG_OUT 0x19 -/* These are all read-only */ -#define ADM9240_REG_2_5V 0x20 -#define ADM9240_REG_VCCP1 0x21 -#define ADM9240_REG_3_3V 0x22 -#define ADM9240_REG_5V 0x23 -#define ADM9240_REG_12V 0x24 -#define ADM9240_REG_VCCP2 0x25 -#define ADM9240_REG_TEMP 0x27 -#define ADM9240_REG_FAN1 0x28 -#define ADM9240_REG_FAN2 0x29 -#define ADM9240_REG_COMPANY_ID 0x3E /* Should always read 0x23 */ -#define ADM9240_REG_DIE_REV 0x3F -/* These are read/write */ -#define ADM9240_REG_2_5V_HIGH 0x2B -#define ADM9240_REG_2_5V_LOW 0x2C -#define ADM9240_REG_VCCP1_HIGH 0x2D -#define ADM9240_REG_VCCP1_LOW 0x2E -#define ADM9240_REG_3_3V_HIGH 0x2F -#define ADM9240_REG_3_3V_LOW 0x30 -#define ADM9240_REG_5V_HIGH 0x31 -#define ADM9240_REG_5V_LOW 0x32 -#define ADM9240_REG_12V_HIGH 0x33 -#define ADM9240_REG_12V_LOW 0x34 -#define ADM9240_REG_VCCP2_HIGH 0x35 -#define ADM9240_REG_VCCP2_LOW 0x36 -#define ADM9240_REG_TOS 0x39 -#define ADM9240_REG_THYST 0x3A -#define ADM9240_REG_FAN1_MIN 0x3B -#define ADM9240_REG_FAN2_MIN 0x3C - -#define ADM9240_REG_CONFIG 0x40 -#define ADM9240_REG_INT1_STAT 0x41 -#define ADM9240_REG_INT2_STAT 0x42 -#define ADM9240_REG_INT1_MASK 0x43 -#define ADM9240_REG_INT2_MASK 0x44 - -#define ADM9240_REG_COMPAT 0x45 /* dummy compat. register for other drivers? */ -#define ADM9240_REG_CHASSIS_CLEAR 0x46 -#define ADM9240_REG_VID_FAN_DIV 0x47 -#define ADM9240_REG_I2C_ADDR 0x48 -#define ADM9240_REG_VID4 0x49 -#define ADM9240_REG_TEMP_CONFIG 0x4B - -/* Conversions. Rounding is only done on the TO_REG variants. */ -#define IN_TO_REG(val,nr) ((val) & 0xff) -#define IN_FROM_REG(val,nr) (val) - -#define FAN_TO_REG(val,div) ((val)==0?255:\ - ((1350000+(val)*(div)/2)/((val)*(div))) & 0xff) -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -#define TEMP_FROM_REG(val) adm9240_temp_from_reg(val) - -#define TEMP_LIMIT_TO_REG(val) (((val)<0?(((val)-50)/100)&0xff:\ - ((val)+50)/100) & 0xff) -#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*100) - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << val) -#define DIV_TO_REG(val) (val==1?0:(val==2?1:(val==4?2:3))) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - (val)>=0x06?0:205-(val)*5) - -/* Initial limits */ -#define ADM9240_INIT_IN_0 190 -#define ADM9240_INIT_IN_1 190 -#define ADM9240_INIT_IN_2 190 -#define ADM9240_INIT_IN_3 190 -#define ADM9240_INIT_IN_4 190 -#define ADM9240_INIT_IN_5 190 - -#define ADM9240_INIT_IN_PERCENTAGE 10 - -#define ADM9240_INIT_IN_MIN_0 \ - (ADM9240_INIT_IN_0 - ADM9240_INIT_IN_0 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MAX_0 \ - (ADM9240_INIT_IN_0 + ADM9240_INIT_IN_0 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MIN_1 \ - (ADM9240_INIT_IN_1 - ADM9240_INIT_IN_1 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MAX_1 \ - (ADM9240_INIT_IN_1 + ADM9240_INIT_IN_1 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MIN_2 \ - (ADM9240_INIT_IN_2 - ADM9240_INIT_IN_2 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MAX_2 \ - (ADM9240_INIT_IN_2 + ADM9240_INIT_IN_2 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MIN_3 \ - (ADM9240_INIT_IN_3 - ADM9240_INIT_IN_3 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MAX_3 \ - (ADM9240_INIT_IN_3 + ADM9240_INIT_IN_3 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MIN_4 \ - (ADM9240_INIT_IN_4 - ADM9240_INIT_IN_4 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MAX_4 \ - (ADM9240_INIT_IN_4 + ADM9240_INIT_IN_4 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MIN_5 \ - (ADM9240_INIT_IN_5 - ADM9240_INIT_IN_5 * ADM9240_INIT_IN_PERCENTAGE / 100) -#define ADM9240_INIT_IN_MAX_5 \ - (ADM9240_INIT_IN_5 + ADM9240_INIT_IN_5 * ADM9240_INIT_IN_PERCENTAGE / 100) - -#define ADM9240_INIT_FAN_MIN_1 3000 -#define ADM9240_INIT_FAN_MIN_2 3000 - -#define ADM9240_INIT_TEMP_OS_MAX 600 -#define ADM9240_INIT_TEMP_OS_HYST 500 -#define ADM9240_INIT_TEMP_HOT_MAX 700 -#define ADM9240_INIT_TEMP_HOT_HYST 600 - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -/* For each registered ADM9240, we need to keep some data in memory. That - data is pointed to by adm9240_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new adm9240 client is - allocated. */ -struct adm9240_data { - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[6]; /* Register value */ - u8 in_max[6]; /* Register value */ - u8 in_min[6]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - int temp; /* Temp, shifted right */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - u16 alarms; /* Register encoding, combined */ - u8 analog_out; /* Register value */ - u8 vid; /* Register value combined */ -}; - - -static int adm9240_init(void); -static int adm9240_cleanup(void); - -static int adm9240_attach_adapter(struct i2c_adapter *adapter); -static int adm9240_detach_client(struct i2c_client *client); -static int adm9240_new_client(struct i2c_adapter *adapter, - struct i2c_client *new_client); -static void adm9240_remove_client(struct i2c_client *client); -static int adm9240_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void adm9240_inc_use (struct i2c_client *client); -static void adm9240_dec_use (struct i2c_client *client); - -static long adm9240_temp_from_reg(u16 regs); - -static int adm9240_read_value(struct i2c_client *client, u8 register); -static int adm9240_write_value(struct i2c_client *client, u8 register, u8 value); -static void adm9240_update_client(struct i2c_client *client); -static void adm9240_init_client(struct i2c_client *client); - - -static void adm9240_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm9240_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm9240_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm9240_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm9240_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm9240_analog_out(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void adm9240_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -/* I choose here for semi-static ADM9240 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_ADM9240_NR 4 -static struct i2c_client *adm9240_list[MAX_ADM9240_NR]; - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver adm9240_driver = { - /* name */ "ADM9240 sensor driver", - /* id */ I2C_DRIVERID_ADM9240, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &adm9240_attach_adapter, - /* detach_client */ &adm9240_detach_client, - /* command */ &adm9240_command, - /* inc_use */ &adm9240_inc_use, - /* dec_use */ &adm9240_dec_use -}; - -/* Used by adm9240_init/cleanup */ -static int adm9240_initialized = 0; - -/* The /proc/sys entries */ -/* These files are created for each detected ADM9240. 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 adm9240_dir_table_template[] = { - { ADM9240_SYSCTL_IN0, "2.5V", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_in }, - { ADM9240_SYSCTL_IN1, "Vccp1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_in }, - { ADM9240_SYSCTL_IN2, "3.3V", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_in }, - { ADM9240_SYSCTL_IN3, "5V", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_in }, - { ADM9240_SYSCTL_IN4, "12V", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_in }, - { ADM9240_SYSCTL_IN5, "Vccp2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_in }, - { ADM9240_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_fan }, - { ADM9240_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_fan }, - { ADM9240_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_temp }, - { ADM9240_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_fan_div }, - { ADM9240_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_alarms }, - { ADM9240_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_analog_out }, - { ADM9240_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &adm9240_vid }, - { 0 } -}; - - -int adm9240_attach_adapter(struct i2c_adapter *adapter) -{ - int address,err,temp; - struct i2c_client *new_client; - const char *type_name,*client_name; - - err = 0; - /* The address of the ADM2940 must at least start somewhere in - 0x2C to 0x2F, but can be changed to be anyelse after that. - (But, why??) */ - for (address = 0x2C; (! err) && (address <= 0x2f); 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,ADM9240_REG_COMPANY_ID) != 0x23) - continue; - - temp=smbus_read_byte_data(adapter,address,ADM9240_REG_DIE_REV); - printk("adm9240.o: ADM9240 detected with die rev.: 0x%X\n",temp); - type_name = "adm9240"; - client_name = "ADM9240 chip"; - - - /* 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 adm9240_data), - GFP_KERNEL))) { - err = -ENOMEM; - continue; - } - - /* Fill the new client structure with data */ - new_client->data = (struct adm9240_data *) (new_client + 1); - new_client->addr = address; - strcpy(new_client->name,client_name); - if ((err = adm9240_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, - adm9240_dir_table_template)) < 0) - goto ERROR4; - ((struct adm9240_data *) (new_client->data))->sysctl_id = err; - err = 0; - - /* Initialize the ADM9240 chip */ - adm9240_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: - adm9240_remove_client((struct i2c_client *) new_client); -ERROR2: - kfree(new_client); - } - return err; -} - -int adm9240_detach_client(struct i2c_client *client) -{ - int err,i; - for (i = 0; i < MAX_ADM9240_NR; i++) - if (client == adm9240_list[i]) - break; - if ((i == MAX_ADM9240_NR)) { - printk("adm9240.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct adm9240_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("adm9240.o: Client deregistration failed, client not detached.\n"); - return err; - } - adm9240_remove_client(client); - kfree(client); - return 0; -} - - -/* Find a free slot, and initialize most of the fields */ -int adm9240_new_client(struct i2c_adapter *adapter, - struct i2c_client *new_client) -{ - int i; - struct adm9240_data *data; - - /* First, seek out an empty slot */ - for(i = 0; i < MAX_ADM9240_NR; i++) - if (! adm9240_list[i]) - break; - if (i == MAX_ADM9240_NR) { - printk("adm9240.o: No empty slots left, recompile and heighten " - "MAX_ADM9240_NR!\n"); - return -ENOMEM; - } - - adm9240_list[i] = new_client; - new_client->id = i; - new_client->adapter = adapter; - new_client->driver = &adm9240_driver; - data = new_client->data; - data->valid = 0; - data->update_lock = MUTEX; - return 0; -} - -/* Inverse of adm9240_new_client */ -void adm9240_remove_client(struct i2c_client *client) -{ - int i; - for (i = 0; i < MAX_ADM9240_NR; i++) - if (client == adm9240_list[i]) - adm9240_list[i] = NULL; -} - -/* No commands defined yet */ -int adm9240_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void adm9240_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void adm9240_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - -long adm9240_temp_from_reg(u16 temp) -{ - if (temp < 256) - return (((temp & 0x1fe) >> 1) * 10) + ((temp & 1) * 5); - else - return ((((temp & 0x01fe) >> 1) - 255) * 10) - ((temp & 1) * 5); -} - -int adm9240_read_value(struct i2c_client *client, u8 reg) -{ - return 0xFF & smbus_read_byte_data(client->adapter,client->addr, reg); -} - -int adm9240_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 ADM9240. It should set limits, etc. */ -void adm9240_init_client(struct i2c_client *client) -{ - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others. This makes most other - initializations unnecessary */ - adm9240_write_value(client,ADM9240_REG_CONFIG,0x80); - - adm9240_write_value(client,ADM9240_REG_IN_MIN(0),IN_TO_REG(ADM9240_INIT_IN_MIN_0,0)); - adm9240_write_value(client,ADM9240_REG_IN_MAX(0),IN_TO_REG(ADM9240_INIT_IN_MAX_0,0)); - adm9240_write_value(client,ADM9240_REG_IN_MIN(1),IN_TO_REG(ADM9240_INIT_IN_MIN_1,1)); - adm9240_write_value(client,ADM9240_REG_IN_MAX(1),IN_TO_REG(ADM9240_INIT_IN_MAX_1,1)); - adm9240_write_value(client,ADM9240_REG_IN_MIN(2),IN_TO_REG(ADM9240_INIT_IN_MIN_2,2)); - adm9240_write_value(client,ADM9240_REG_IN_MAX(2),IN_TO_REG(ADM9240_INIT_IN_MAX_2,2)); - adm9240_write_value(client,ADM9240_REG_IN_MIN(3),IN_TO_REG(ADM9240_INIT_IN_MIN_3,3)); - adm9240_write_value(client,ADM9240_REG_IN_MAX(3),IN_TO_REG(ADM9240_INIT_IN_MAX_3,3)); - adm9240_write_value(client,ADM9240_REG_IN_MIN(4),IN_TO_REG(ADM9240_INIT_IN_MIN_4,4)); - adm9240_write_value(client,ADM9240_REG_IN_MAX(4),IN_TO_REG(ADM9240_INIT_IN_MAX_4,4)); - adm9240_write_value(client,ADM9240_REG_IN_MIN(5),IN_TO_REG(ADM9240_INIT_IN_MIN_5,5)); - adm9240_write_value(client,ADM9240_REG_IN_MAX(5),IN_TO_REG(ADM9240_INIT_IN_MAX_5,5)); - adm9240_write_value(client,ADM9240_REG_FAN1_MIN,FAN_TO_REG(ADM9240_INIT_FAN_MIN_1,2)); - adm9240_write_value(client,ADM9240_REG_FAN2_MIN,FAN_TO_REG(ADM9240_INIT_FAN_MIN_2,2)); - adm9240_write_value(client,ADM9240_REG_TOS, - TEMP_LIMIT_TO_REG(ADM9240_INIT_TEMP_OS_MAX)); - adm9240_write_value(client,ADM9240_REG_THYST, - TEMP_LIMIT_TO_REG(ADM9240_INIT_TEMP_OS_HYST)); - adm9240_write_value(client,ADM9240_REG_TEMP_CONFIG,0x00); - - /* Start monitoring */ - adm9240_write_value(client,ADM9240_REG_CONFIG,0x0B); -} - -void adm9240_update_client(struct i2c_client *client) -{ - struct adm9240_data *data = client->data; - u8 i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2*HZ ) || - (jiffies < data->last_updated) || ! data->valid) { - -#ifdef DEBUG - printk("Starting adm9240 update\n"); -#endif - for (i = 0; i <= 5; i++) { - data->in[i] = adm9240_read_value(client,ADM9240_REG_IN(i)); - data->in_min[i] = adm9240_read_value(client,ADM9240_REG_IN_MIN(i)); - data->in_max[i] = adm9240_read_value(client,ADM9240_REG_IN_MAX(i)); - } - data->fan[0] = adm9240_read_value(client,ADM9240_REG_FAN1); - data->fan_min[0] = adm9240_read_value(client,ADM9240_REG_FAN1_MIN); - data->fan[1] = adm9240_read_value(client,ADM9240_REG_FAN2); - data->fan_min[1] = adm9240_read_value(client,ADM9240_REG_FAN2_MIN); - data->temp = (adm9240_read_value(client,ADM9240_REG_TEMP) << 1) + - ((adm9240_read_value(client,ADM9240_REG_TEMP_CONFIG) & 0x80) >> 7); - data->temp_os_max = adm9240_read_value(client,ADM9240_REG_TOS); - data->temp_os_hyst = adm9240_read_value(client,ADM9240_REG_THYST); - - i = adm9240_read_value(client,ADM9240_REG_VID_FAN_DIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - data->vid = i & 0x0f; - data->vid |= (adm9240_read_value(client,ADM9240_REG_VID4) & 0x01) << 4; - - data->alarms = adm9240_read_value(client,ADM9240_REG_INT1_STAT) + - (adm9240_read_value(client,ADM9240_REG_INT2_STAT) << 8); - data->analog_out = adm9240_read_value(client,ADM9240_REG_ANALOG_OUT); - 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 date - 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 adm9240_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - int nr = ctl_name - ADM9240_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr],nr); - results[1] = IN_FROM_REG(data->in_max[nr],nr); - results[2] = IN_FROM_REG(data->in[nr],nr); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0],nr); - adm9240_write_value(client,ADM9240_REG_IN_MIN(nr),data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1],nr); - adm9240_write_value(client,ADM9240_REG_IN_MAX(nr),data->in_max[nr]); - } - } -} - -void adm9240_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - int nr = ctl_name - ADM9240_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr-1], - DIV_FROM_REG(data->fan_div[nr-1])); - results[1] = FAN_FROM_REG(data->fan[nr-1], - DIV_FROM_REG(data->fan_div[nr-1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr-1] = FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - adm9240_write_value(client,nr==1?ADM9240_REG_FAN1_MIN:ADM9240_REG_FAN2_MIN, - data->fan_min[nr-1]); - } - } -} - - -void adm9240_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp_os_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os_max = TEMP_LIMIT_TO_REG(results[0]); - adm9240_write_value(client,ADM9240_REG_TOS,data->temp_os_max); - } - if (*nrels_mag >= 2) { - data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[1]); - adm9240_write_value(client,ADM9240_REG_THYST,data->temp_os_hyst); - } - } -} - -void adm9240_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void adm9240_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_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 = adm9240_read_value(client,ADM9240_REG_VID_FAN_DIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xcf) | (data->fan_div[1] << 6); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0x3f) | (data->fan_div[0] << 4); - adm9240_write_value(client,ADM9240_REG_VID_FAN_DIV,old); - } - } -} - -void adm9240_analog_out(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = data->analog_out; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->analog_out = results[0]; - adm9240_write_value(client,ADM9240_REG_ANALOG_OUT,data->analog_out); - } - } -} - -void adm9240_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct adm9240_data *data = client->data; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - adm9240_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -int adm9240_init(void) -{ - int res; - - printk("adm9240.o version %s (%s)\n",LM_VERSION,LM_DATE); - adm9240_initialized = 0; - - if ((res =i2c_add_driver(&adm9240_driver))) { - printk("adm9240.o: Driver registration failed, module not inserted.\n"); - adm9240_cleanup(); - return res; - } - adm9240_initialized ++; - return 0; -} - -int adm9240_cleanup(void) -{ - int res; - - if (adm9240_initialized >= 1) { - if ((res = i2c_del_driver(&adm9240_driver))) { - printk("adm9240.o: Driver deregistration failed, module not removed.\n"); - return res; - } - adm9240_initialized --; - } - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("ADM9240 driver"); - -int init_module(void) -{ - return adm9240_init(); -} - -int cleanup_module(void) -{ - return adm9240_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/compat.h b/src/compat.h deleted file mode 100644 index 04b0c455..00000000 --- a/src/compat.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - compat.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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. -*/ - -#ifndef SENSORS_COMPAT_H -#define SENSORS_COMPAT_H - -/* This useful macro is not defined in the 2.0 kernels */ - -#include -#ifndef KERNEL_VERSION -#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c)) -#endif - -#ifdef MODULE -#include -#ifndef MODULE_AUTHOR -#define MODULE_AUTHOR(whatever) -#endif -#ifndef MODULE_DESCRIPTION -#define MODULE_DESCRIPTION(whatever) -#endif -#endif /* def MODULE */ - -/* copy_from/to_usr is called memcpy_from/to_fs in 2.0 kernels - get_user was redefined in 2.1 kernels to use two arguments, and returns - an error code */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4)) -#define copy_from_user memcpy_fromfs -#define copy_to_user memcpy_tofs -#define get_user_data(to,from) ((to) = get_user(from),0) -#else -#include -#define get_user_data(to,from) get_user(to,from) -#endif - -/* Add a scheduling fix for the new code in kernel 2.1.127 */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,127)) -#define schedule_timeout(x) ( current->timeout = jiffies + (x), schedule() ) -#endif - -/* If the new PCI interface is not present, fall back on the old PCI BIOS - interface. We also define some things to unite both interfaces. Not - very nice, but it works like a charm. - device is the 2.1 struct pci_dev, bus is the 2.0 bus number, dev is the - 2.0 device/function code, com is the PCI command, and res is the result. */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54)) -#define pci_present pcibios_present -#define pci_read_config_byte_united(device,bus,dev,com,res) \ - pcibios_read_config_byte(bus,dev,com,res); -#define pci_read_config_word_united(device,bus,dev,com,res) \ - pcibios_read_config_word(bus,dev,com,res); -#define pci_write_config_byte_united(device,bus,dev,com,res) \ - pcibios_write_config_byte(bus,dev,com,res); -#define pci_write_config_word_united(device,bus,dev,com,res) \ - pcibios_write_config_word(bus,dev,com,res); -#else -#define pci_read_config_byte_united(device,bus,dev,com,res) \ - pci_read_config_byte(device,com,res); -#define pci_read_config_word_united(device,bus,dev,com,res) \ - pci_read_config_word(device,com,res); -#define pci_write_config_byte_united(device,bus,dev,com,res) \ - pci_write_config_byte(device,com,res); -#define pci_write_config_word_united(device,bus,dev,com,res) \ - pci_write_config_byte(device,com,res); -#endif - - -#endif /* SENSORS_COMPAT_H */ diff --git a/src/eeprom.c b/src/eeprom.c deleted file mode 100644 index 20f1f876..00000000 --- a/src/eeprom.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - eeprom.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard and - Philip Edelbrock - - 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 -#include -#include "smbus.h" -#include "sensors.h" -#include "i2c.h" -#include "version.h" - -/* Many constants specified below */ - -/* EEPROM memory types: */ -#define ONE_K 1 -#define TWO_K 2 -#define FOUR_K 3 -#define EIGHT_K 4 -#define SIXTEEN_K 5 - -/* Conversions */ -/* Size of EEPROM in bytes */ -#define EEPROM_SIZE 128 - -/* Each client has this additional data */ -struct eeprom_data { - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 data[EEPROM_SIZE]; /* Register values */ - int memtype; -}; - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static int eeprom_init(void); -static int eeprom_cleanup(void); - -static int eeprom_attach_adapter(struct i2c_adapter *adapter); -static int eeprom_detach_client(struct i2c_client *client); -static int eeprom_command(struct i2c_client *client, unsigned int cmd, - void *arg); - -static void eeprom_inc_use (struct i2c_client *client); -static void eeprom_dec_use (struct i2c_client *client); - -static u16 swap_bytes(u16 val); - -static int eeprom_read_value(struct i2c_client *client, u8 reg); -static int eeprom_write_value(struct i2c_client *client, u8 reg, u16 value); - -static void eeprom_contents(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void eeprom_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver eeprom_driver = { - /* name */ "EEPROM READER", - /* id */ I2C_DRIVERID_EEPROM, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &eeprom_attach_adapter, - /* detach_client */ &eeprom_detach_client, - /* command */ &eeprom_command, - /* inc_use */ &eeprom_inc_use, - /* dec_use */ &eeprom_dec_use -}; - -/* These files are created for each detected EEPROM. 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 eeprom_dir_table_template[] = { - { EEPROM_SYSCTL1, "data0-15", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &eeprom_contents }, - { EEPROM_SYSCTL2, "data16-31", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &eeprom_contents }, - { EEPROM_SYSCTL3, "data32-47", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &eeprom_contents }, - { EEPROM_SYSCTL4, "data48-63", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &eeprom_contents }, - { EEPROM_SYSCTL5, "data64-79", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &eeprom_contents }, - { EEPROM_SYSCTL6, "data80-95", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &eeprom_contents }, - { EEPROM_SYSCTL7, "data96-111", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &eeprom_contents }, - { EEPROM_SYSCTL8, "data112-127", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &eeprom_contents }, - { 0 } -}; - -/* Used by init/cleanup */ -static int eeprom_initialized = 0; - -/* I choose here for semi-static LM78 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_EEPROM_NR 8 -static struct i2c_client *eeprom_list[MAX_EEPROM_NR]; - - -int eeprom_attach_adapter(struct i2c_adapter *adapter) -{ - int address,err,i; - struct i2c_client *new_client; - struct eeprom_data *data; - - err = 0; - - /* OK, this is no detection. I know. It will do for now, though. */ - - /* Set err only if a global error would make registering other clients - impossible too (like out-of-memory). */ - - /* Serial EEPROMs for SMBus use addresses from 0x50 to 0x57 */ - for (address = 0x50; (! err) && (address <= 0x57); 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(adapter,address) < 0) { -#ifdef DEBUG - printk("eeprom.o: No eeprom found at: 0x%X\n",address); -#endif - continue; - } - - /* Real detection code goes here */ - - /* Allocate space for a new client structure */ - if (! (new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct eeprom_data), - GFP_KERNEL))) { - err = -ENOMEM; - continue; - } - - /* Find a place in our global list */ - for (i = 0; i < MAX_EEPROM_NR; i++) - if (! eeprom_list[i]) - break; - if (i == MAX_EEPROM_NR) { - err = -ENOMEM; - printk("eeprom.o: No empty slots left, recompile and heighten " - "MAX_EEPROM_NR!\n"); - goto ERROR1; - } - eeprom_list[i] = new_client; - - /* Fill the new client structure with data */ - data = (struct eeprom_data *) (new_client + 1); - new_client->data = data; - new_client->id = i; - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &eeprom_driver; - strcpy(new_client->name,"EEPROM chip"); - data->valid = 0; - data->update_lock = MUTEX; - - /* Tell i2c-core a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Register a new directory entry with module sensors */ - if ((err = sensors_register_entry(new_client,"eeprom", - eeprom_dir_table_template)) < 0) - goto ERROR3; - data->sysctl_id = err; - err = 0; - - continue; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -ERROR3: - i2c_detach_client(new_client); -ERROR2: - eeprom_list[i] = NULL; -ERROR1: - kfree(new_client); - } - return err; -} - -int eeprom_detach_client(struct i2c_client *client) -{ - int err,i; - for (i = 0; i < MAX_EEPROM_NR; i++) - if (client == eeprom_list[i]) - break; - if ((i == MAX_EEPROM_NR)) { - printk("eeprom.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct eeprom_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("eeprom.o: Client deregistration failed, client not detached.\n"); - return err; - } - - eeprom_list[i] = NULL; - kfree(client); - return 0; -} - - -/* No commands defined yet */ -int eeprom_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void eeprom_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void eeprom_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u16 swap_bytes(u16 val) -{ - return (val >> 8) | (val << 8); -} - -/* No swapping needed here! */ -int eeprom_write_value(struct i2c_client *client, u8 reg, u16 value) -{/* - if (reg == EEPROM_REG_CONF) - return smbus_write_byte_data(client->adapter,client->addr,reg,value); - else - return smbus_write_word_data(client->adapter,client->addr,reg,value); */ - - /* No writes yet (PAE) */ - return 0; -} - -void eeprom_update_client(struct i2c_client *client) -{ - struct eeprom_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("Starting eeprom update\n"); -#endif - - if (smbus_write_byte(client->adapter,client->addr,0)) { -#ifdef DEBUG - printk("eeprom read start has failed!\n"); -#endif - } - for (i=0;idata[i] = (u8)smbus_read_byte(client->adapter,client->addr); - } - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void eeprom_contents(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - int i; - int base=0; - struct eeprom_data *data = client->data; - - if (ctl_name == EEPROM_SYSCTL2){ base=16; } - if (ctl_name == EEPROM_SYSCTL3){ base=32; } - if (ctl_name == EEPROM_SYSCTL4){ base=48; } - if (ctl_name == EEPROM_SYSCTL5){ base=64; } - if (ctl_name == EEPROM_SYSCTL6){ base=80; } - if (ctl_name == EEPROM_SYSCTL7){ base=96; } - if (ctl_name == EEPROM_SYSCTL8){ base=112; } - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - eeprom_update_client(client); - for (i=0; i<16; i++) { - results[i]=data->data[i + base]; - } -#ifdef DEBUG - printk("eeprom.o: 0x%X EEPROM Contents (base %d): ",client->addr,base); - for (i=0; i<16; i++) { - printk(" 0x%X",data->data[i + base]); - } - printk(" .\n"); -#endif - *nrels_mag = 16; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - -/* No writes to the EEPROM (yet, anyway) (PAE) */ - printk("eeprom.o: No writes to EEPROMs supported!\n"); - } -} - -int eeprom_init(void) -{ - int res; - - printk("eeprom.o version %s (%s)\n",LM_VERSION,LM_DATE); - eeprom_initialized = 0; - if ((res = i2c_add_driver(&eeprom_driver))) { - printk("eeprom.o: Driver registration failed, module not inserted.\n"); - eeprom_cleanup(); - return res; - } - eeprom_initialized ++; - return 0; -} - -int eeprom_cleanup(void) -{ - int res; - - if (eeprom_initialized >= 1) { - if ((res = i2c_del_driver(&eeprom_driver))) { - printk("eeprom.o: Driver deregistration failed, module not removed.\n"); - return res; - } - } else - eeprom_initialized --; - - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("EEPROM driver"); - -int init_module(void) -{ - return eeprom_init(); -} - -int cleanup_module(void) -{ - return eeprom_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/gl518sm.c b/src/gl518sm.c deleted file mode 100644 index 93a41065..00000000 --- a/src/gl518sm.c +++ /dev/null @@ -1,680 +0,0 @@ -/* - gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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 -#include -#include "smbus.h" -#include "sensors.h" -#include "i2c.h" -#include "version.h" - - -/* Many GL518 constants specified below */ - -/* The GL518 registers */ -#define GL518_REG_CHIP_ID 0x00 -#define GL518_REG_REVISION 0x01 -#define GL518_REG_VENDOR_ID 0x02 -#define GL518_REG_CONF 0x03 -#define GL518_REG_TEMP 0x04 -#define GL518_REG_TEMP_OVER 0x05 -#define GL518_REG_TEMP_HYST 0x06 -#define GL518_REG_FAN_COUNT 0x07 -#define GL518_REG_FAN_LIMIT 0x08 -#define GL518_REG_VIN1_LIMIT 0x09 -#define GL518_REG_VIN2_LIMIT 0x0a -#define GL518_REG_VIN3_LIMIT 0x0b -#define GL518_REG_VDD_LIMIT 0x0c -#define GL518_REG_VIN3 0x0d -#define GL518_REG_MISC 0x0f -#define GL518_REG_ALARM 0x10 -#define GL518_REG_MASK 0x11 -#define GL518_REG_INT 0x12 -#define GL518_REG_VIN2 0x13 -#define GL518_REG_VIN1 0x14 -#define GL518_REG_VDD 0x15 - - -/* Conversions. Rounding is only done on the TO_REG variants. */ -#define TEMP_TO_REG(val) (((((val)<0?(val)-5:(val)+5) / 10) + 119) & 0xff) -#define TEMP_FROM_REG(val) (((val) - 119) * 10) - -#define FAN_TO_REG(val,div) (((val)==0?255:\ - (960000+((val)*(div)))/(2*(val)*(div))) & 0xff) -#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:960000/(2*(val)*(div))) - -#define IN_TO_REG(val) ((((val)*10+8)/19) & 0xff) -#define IN_FROM_REG(val) (((val)*19)/10) - -#define VDD_TO_REG(val) ((((val)*10+11)/23) & 0xff) -#define VDD_FROM_REG(val) (((val)*23)/10) - -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) -#define DIV_FROM_REG(val) (1 << (val)) - -#define ALARMS_FROM_REG(val) val - -#define BEEP_ENABLE_TO_REG(val) ((val)?0:1) -#define BEEP_ENABLE_FROM_REG(val) ((val)?0:1) - -#define BEEPS_TO_REG(val) ((val) & 0x7f) -#define BEEPS_FROM_REG(val) (val) - -/* Initial values */ -#define GL518_INIT_TEMP_OVER 600 -#define GL518_INIT_TEMP_HYST 500 -#define GL518_INIT_FAN_MIN_1 3000 -#define GL518_INIT_FAN_MIN_2 3000 - -/* What are sane values for these?!? */ -#define GL518_INIT_VIN_1 300 -#define GL518_INIT_VIN_2 300 -#define GL518_INIT_VIN_3 300 -#define GL518_INIT_VDD 500 - -#define GL518_INIT_PERCENTAGE 10 - -#define GL518_INIT_VIN_MIN_1 \ - (GL518_INIT_VIN_1 - GL518_INIT_VIN_1 * GL518_INIT_PERCENTAGE / 100) -#define GL518_INIT_VIN_MAX_1 \ - (GL518_INIT_VIN_1 + GL518_INIT_VIN_1 * GL518_INIT_PERCENTAGE / 100) -#define GL518_INIT_VIN_MIN_2 \ - (GL518_INIT_VIN_2 - GL518_INIT_VIN_2 * GL518_INIT_PERCENTAGE / 100) -#define GL518_INIT_VIN_MAX_2 \ - (GL518_INIT_VIN_2 + GL518_INIT_VIN_2 * GL518_INIT_PERCENTAGE / 100) -#define GL518_INIT_VIN_MIN_3 \ - (GL518_INIT_VIN_3 - GL518_INIT_VIN_3 * GL518_INIT_PERCENTAGE / 100) -#define GL518_INIT_VIN_MAX_3 \ - (GL518_INIT_VIN_3 + GL518_INIT_VIN_3 * GL518_INIT_PERCENTAGE / 100) -#define GL518_INIT_VDD_MIN \ - (GL518_INIT_VDD - GL518_INIT_VDD * GL518_INIT_PERCENTAGE / 100) -#define GL518_INIT_VDD_MAX \ - (GL518_INIT_VDD + GL518_INIT_VDD * GL518_INIT_PERCENTAGE / 100) - - -/* Each client has this additional data */ -struct gl518_data { - int sysctl_id; - - u8 revision; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 voltage[4]; /* Register values; [0] = VDD */ - u8 voltage_min[4]; /* Register values; [0] = VDD */ - u8 voltage_max[4]; /* Register values; [0] = VDD */ - u8 fan[2]; - u8 fan_min[2]; - u8 temp; /* Register values */ - u8 temp_over; /* Register values */ - u8 temp_hyst; /* Register values */ - u8 alarms,beeps; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u8 beep_enable; /* Boolean */ -}; - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static int gl518_init(void); -static int gl518_cleanup(void); -static int gl518_attach_adapter(struct i2c_adapter *adapter); -static int gl518_detach_client(struct i2c_client *client); -static int gl518_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void gl518_inc_use (struct i2c_client *client); -static void gl518_dec_use (struct i2c_client *client); -static u16 swap_bytes(u16 val); -static int gl518_read_value(struct i2c_client *client, u8 reg); -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); -static void gl518_update_client(struct i2c_client *client); - -static void gl518_vin(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void gl518_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -/* This is the driver that will be inserted */ -static struct i2c_driver gl518_driver = { - /* name */ "GL518SM sensor chip driver", - /* id */ I2C_DRIVERID_GL518, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &gl518_attach_adapter, - /* detach_client */ &gl518_detach_client, - /* command */ &gl518_command, - /* inc_use */ &gl518_inc_use, - /* dec_use */ &gl518_dec_use -}; - -/* These files are created for each detected GL518. 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 gl518_dir_table_template[] = { - { GL518_SYSCTL_VIN1, "vin1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_vin }, - { GL518_SYSCTL_VIN2, "vin2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_vin }, - { GL518_SYSCTL_VIN3, "vin3", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_vin }, - { GL518_SYSCTL_VDD, "vdd", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_vin }, - { GL518_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_fan }, - { GL518_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_fan }, - { GL518_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_temp }, - { GL518_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_fan_div }, - { GL518_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_alarms }, - { GL518_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &gl518_beep }, - { 0 } -}; - -/* Used by init/cleanup */ -static int gl518_initialized = 0; - -/* I choose here for semi-static LM78 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_GL518_NR 4 -static struct i2c_client *gl518_list[MAX_GL518_NR]; - - -int gl518_attach_adapter(struct i2c_adapter *adapter) -{ - int address,err,i; - struct i2c_client *new_client; - struct gl518_data *data; - u8 revision; - char name[11]; - - err = 0; - - /* OK, this is no detection. I know. It will do for now, though. */ - - /* Set err only if a global error would make registering other clients - impossible too (like out-of-memory). */ - for (address = 0x2c; (! err) && (address <= 0x2d); address ++) { - - /* Later on, we will keep a list of registered addresses for each - adapter, and check whether they are used here */ - - if ((i = smbus_read_byte_data(adapter,address,GL518_REG_CHIP_ID)) < 0) - continue; - - if (i != 0x80) - continue; - - revision = smbus_read_byte_data(adapter,address,GL518_REG_REVISION); - if ((revision != 0x00) && (revision != 0x80)) - continue; - - /* Real detection code goes here */ - - /* Allocate space for a new client structure */ - if (! (new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct gl518_data), - GFP_KERNEL))) { - err = -ENOMEM; - continue; - } - - /* Find a place in our global list */ - for (i = 0; i < MAX_GL518_NR; i++) - if (! gl518_list[i]) - break; - if (i == MAX_GL518_NR) { - err = -ENOMEM; - printk("gl518sm.o: No empty slots left, recompile and heighten " - "MAX_GL518_NR!\n"); - goto ERROR1; - } - gl518_list[i] = new_client; - - /* Fill the new client structure with data */ - data = (struct gl518_data *) (new_client + 1); - new_client->data = data; - new_client->id = i; - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &gl518_driver; - sprintf(new_client->name,"GL518SM chip rev. %02x",revision); - data->valid = 0; - data->update_lock = MUTEX; - data->revision = revision; - - /* Tell i2c-core a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - sprintf(name,"gl518sm-r%02x",revision); - /* Register a new directory entry with module sensors */ - if ((err = sensors_register_entry(new_client,name, - gl518_dir_table_template)) < 0) - goto ERROR3; - data->sysctl_id = err; - err = 0; - - /* Initialize the GL518SM chip */ - /* Power-on defaults (bit 7=1) */ - gl518_write_value(new_client,GL518_REG_CONF,0x80); - /* No noisy output (bit 2=1), Comparator mode (bit 3=0), two fans (bit4=0), - standby mode (bit6=0) */ - gl518_write_value(new_client,GL518_REG_CONF,0x04); - /* Never interrupts */ - gl518_write_value(new_client,GL518_REG_MASK,0x00); - gl518_write_value(new_client,GL518_REG_TEMP_HYST, - TEMP_TO_REG(GL518_INIT_TEMP_HYST)); - gl518_write_value(new_client,GL518_REG_TEMP_OVER, - TEMP_TO_REG(GL518_INIT_TEMP_OVER)); - gl518_write_value(new_client,GL518_REG_MISC,(DIV_TO_REG(2) << 6) | - (DIV_TO_REG(2) << 4) | 0x08); - gl518_write_value(new_client,GL518_REG_FAN_LIMIT, - (FAN_TO_REG(GL518_INIT_FAN_MIN_1,2) << 8) | - FAN_TO_REG(GL518_INIT_FAN_MIN_2,2)); - gl518_write_value(new_client,GL518_REG_VIN1_LIMIT, - (IN_TO_REG(GL518_INIT_VIN_MAX_1) << 8) | - IN_TO_REG(GL518_INIT_VIN_MIN_1)); - gl518_write_value(new_client,GL518_REG_VIN2_LIMIT, - (IN_TO_REG(GL518_INIT_VIN_MAX_2) << 8) | - IN_TO_REG(GL518_INIT_VIN_MIN_2)); - gl518_write_value(new_client,GL518_REG_VIN3_LIMIT, - (IN_TO_REG(GL518_INIT_VIN_MAX_3) << 8) | - IN_TO_REG(GL518_INIT_VIN_MIN_3)); - gl518_write_value(new_client,GL518_REG_VDD_LIMIT, - (VDD_TO_REG(GL518_INIT_VDD_MAX) << 8) | - VDD_TO_REG(GL518_INIT_VDD_MIN)); - /* Clear status register (bit 5=1), start (bit6=1) */ - gl518_write_value(new_client,GL518_REG_CONF,0x24); - gl518_write_value(new_client,GL518_REG_CONF,0x44); - - continue; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -ERROR3: - i2c_detach_client(new_client); -ERROR2: - gl518_list[i] = NULL; -ERROR1: - kfree(new_client); - } - return err; -} - -int gl518_detach_client(struct i2c_client *client) -{ - int err,i; - for (i = 0; i < MAX_GL518_NR; i++) - if (client == gl518_list[i]) - break; - if ((i == MAX_GL518_NR)) { - printk("gl518sm.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct gl518_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("gl518sm.o: Client deregistration failed, client not detached.\n"); - return err; - } - - gl518_list[i] = NULL; - kfree(client); - return 0; -} - - -/* No commands defined yet */ -int gl518_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void gl518_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void gl518_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u16 swap_bytes(u16 val) -{ - return (val >> 8) | (val << 8); -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -int gl518_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return swap_bytes(smbus_read_word_data(client->adapter,client->addr,reg)); - else - return smbus_read_byte_data(client->adapter,client->addr,reg); -} - -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return smbus_write_word_data(client->adapter,client->addr,reg, - swap_bytes(value)); - else - return smbus_write_byte_data(client->adapter,client->addr,reg,value); -} - -void gl518_update_client(struct i2c_client *client) -{ - struct gl518_data *data = client->data; - int val; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ+HZ/2 ) || - (jiffies < data->last_updated) || ! data->valid) { - -#ifdef DEBUG - printk("Starting gl518 update\n"); -#endif - - if (data->revision != 0x00) { - data->voltage[0] = gl518_read_value(client,GL518_REG_VDD); - data->voltage[1] = gl518_read_value(client,GL518_REG_VIN1); - data->voltage[2] = gl518_read_value(client,GL518_REG_VIN2); - } - data->voltage[3] = gl518_read_value(client,GL518_REG_VIN3); - - val = gl518_read_value(client,GL518_REG_VDD_LIMIT); - data->voltage_min[0] = val & 0xff; - data->voltage_max[0] = (val >> 8) & 0xff; - val = gl518_read_value(client,GL518_REG_VIN1_LIMIT); - data->voltage_min[1] = val & 0xff; - data->voltage_max[1] = (val >> 8) & 0xff; - val = gl518_read_value(client,GL518_REG_VIN2_LIMIT); - data->voltage_min[2] = val & 0xff; - data->voltage_max[2] = (val >> 8) & 0xff; - val = gl518_read_value(client,GL518_REG_VIN3_LIMIT); - data->voltage_min[3] = val & 0xff; - data->voltage_max[3] = (val >> 8) & 0xff; - - val = gl518_read_value(client,GL518_REG_FAN_COUNT); - data->fan[0] = (val >> 8) & 0xff; - data->fan[1] = val & 0xff; - - val = gl518_read_value(client,GL518_REG_FAN_LIMIT); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp = gl518_read_value(client,GL518_REG_TEMP); - data->temp_over = gl518_read_value(client,GL518_REG_TEMP_OVER); - data->temp_hyst = gl518_read_value(client,GL518_REG_TEMP_HYST); - - data->alarms = gl518_read_value(client,GL518_REG_INT); - data->beeps = gl518_read_value(client,GL518_REG_ALARM); - - val = gl518_read_value(client,GL518_REG_MISC); - data->fan_div[0] = (val >> 4) & 0x03; - data->fan_div[1] = (val >> 6) & 0x03; - data->beep_enable = (gl518_read_value(client,GL518_REG_CONF) >> 2) & 1; - - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void gl518_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - gl518_write_value(client,GL518_REG_TEMP_OVER,data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_over = TEMP_TO_REG(results[1]); - gl518_write_value(client,GL518_REG_TEMP_HYST,data->temp_over); - } - } -} - -void gl518_vin(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int nr = ctl_name - GL518_SYSCTL_VDD; - int regnr,old=0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = nr?IN_FROM_REG(data->voltage_min[nr]): - VDD_FROM_REG(data->voltage_min[nr]); - results[1] = nr?IN_FROM_REG(data->voltage_max[nr]): - VDD_FROM_REG(data->voltage_max[nr]); - if ((data->revision == 0x00) && (nr != 3)) - results[2] = 0; - else - results[2] = nr?IN_FROM_REG(data->voltage[nr]): - VDD_FROM_REG(data->voltage[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - regnr=nr==0?GL518_REG_VDD_LIMIT:nr==1?GL518_REG_VIN1_LIMIT:nr==2? - GL518_REG_VIN2_LIMIT:GL518_REG_VIN3_LIMIT; - if (*nrels_mag == 1) - old = gl518_read_value(client,regnr) & 0xff00; - if (*nrels_mag >= 2) { - data->voltage_max[nr] = nr?IN_TO_REG(results[1]):VDD_TO_REG(results[1]); - old = data->voltage_max[nr] << 8; - } - if (*nrels_mag >= 1) { - data->voltage_min[nr] = nr?IN_TO_REG(results[0]):VDD_TO_REG(results[0]); - old |= data->voltage_min[nr]; - gl518_write_value(client,regnr,old); - } - } -} - - -void gl518_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int nr = ctl_name - GL518_SYSCTL_FAN1; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); - results[1] = FAN_FROM_REG(data->fan[nr],DIV_FROM_REG(data->fan_div[nr])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr] = FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr])); - old = gl518_read_value(client,GL518_REG_FAN_LIMIT); - if (nr == 0) - old = (old & 0x00ff) | (data->fan_min[nr] << 8); - else - old = (old & 0xff00) | data->fan_min[nr]; - gl518_write_value(client,GL518_REG_FAN_LIMIT,old); - } - } -} - - -void gl518_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void gl518_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = BEEPS_FROM_REG(data->beeps); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - gl518_write_value(client,GL518_REG_CONF, - (gl518_read_value(client,GL518_REG_CONF) & 0xfb) | - (data->beep_enable << 2)); - } - if (*nrels_mag >= 2) { - data->beeps = BEEPS_TO_REG(results[1]); - gl518_write_value(client,GL518_REG_ALARM,data->beeps); - } - } -} - -void gl518_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct gl518_data *data = client->data; - int old; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - gl518_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 = gl518_read_value(client,GL518_REG_MISC); - 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); - gl518_write_value(client,GL518_REG_MISC,old); - } - } -} - - -int gl518_init(void) -{ - int res; - - printk("gl518sm.o version %s (%s)\n",LM_VERSION,LM_DATE); - gl518_initialized = 0; - if ((res = i2c_add_driver(&gl518_driver))) { - printk("gl518sm.o: Driver registration failed, module not inserted.\n"); - gl518_cleanup(); - return res; - } - gl518_initialized ++; - return 0; -} - -int gl518_cleanup(void) -{ - int res; - - if (gl518_initialized >= 1) { - if ((res = i2c_del_driver(&gl518_driver))) { - printk("gl518.o: Driver deregistration failed, module not removed.\n"); - return res; - } - gl518_initialized --; - } - - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("GL518SM driver"); - -int init_module(void) -{ - return gl518_init(); -} - -int cleanup_module(void) -{ - return gl518_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/i2c-dev.c b/src/i2c-dev.c deleted file mode 100644 index 00e5f670..00000000 --- a/src/i2c-dev.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - i2c-dev.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1995-1997, 1999 by Frodo Looijaard and - Simon Vogl - - 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. -*/ - -/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module. - But I have used so much of his original code and ideas that it seems - only fair to recognize him as co-author -- Frodo */ - -#include -#include -#include -#include "compat.h" -#include "i2c.h" -#include "smbus.h" -#include "isa.h" -#include "sensors.h" -#include "version.h" -#include "i2c-dev.h" - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* def MODULE */ - -/* struct file_operations changed too often in the 2.1 series for nice code */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) -static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56)) -static long long i2cdev_lseek (struct file *file, long long offset, int origin); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -static long long i2cdev_llseek (struct inode *inode, struct file *file, - long long offset, int origin); -#else -static int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset, - int origin); -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) -static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, - loff_t *offset); -static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, - loff_t *offset); -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -static long i2cdev_read (struct inode *inode, struct file *file, char *buf, - unsigned long count); -static long i2cdev_write (struct inode *inode, struct file *file, - const char *buf, unsigned long offset); -#else -static int i2cdev_read(struct inode *inode, struct file *file, char *buf, - int count); -static int i2cdev_write(struct inode *inode, struct file *file, - const char *buf, int count); -#endif - -static int i2cdev_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static int i2cdev_open (struct inode *inode, struct file *file); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31)) -static int i2cdev_release (struct inode *inode, struct file *file); -#else -static void i2cdev_release (struct inode *inode, struct file *file); -#endif - - -static int i2cdev_attach_adapter(struct i2c_adapter *adap); -static int i2cdev_detach_client(struct i2c_client *client); -static int i2cdev_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void i2cdev_inc_use(struct i2c_client *client); -static void i2cdev_dec_use(struct i2c_client *client); - -static int i2cdev_init(void); -static int i2cdev_cleanup(void); - -static struct file_operations i2cdev_fops = { - i2cdev_lseek, - i2cdev_read, - i2cdev_write, - NULL, /* i2cdev_readdir */ - NULL, /* i2cdev_select */ - i2cdev_ioctl, - NULL, /* i2cdev_mmap */ - i2cdev_open, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118) - NULL, /* i2cdev_flush */ -#endif - i2cdev_release, -}; - -#define I2CDEV_CLIENTS_MAX I2C_ADAP_MAX -static struct i2c_client *i2cdev_clients[I2CDEV_CLIENTS_MAX]; - -static struct i2c_driver i2cdev_driver = { - /* name */ "i2c-dev dummy driver", - /* id */ I2C_DRIVERID_I2CDEV, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &i2cdev_attach_adapter, - /* detach_client */ &i2cdev_detach_client, - /* command */ &i2cdev_command, - /* inc_use */ &i2cdev_inc_use, - /* dec_use */ &i2cdev_dec_use -}; - -static struct i2c_client i2cdev_client_template = { - /* name */ "I2C /dev entry", - /* id */ 1, - /* flags */ 0, - /* addr */ -1, - /* adapter */ NULL, - /* driver */ &i2cdev_driver, - /* data */ NULL -}; - -static int i2cdev_initialized; - -/* Note that the lseek function is called llseek in 2.1 kernels. But things - are complicated enough as is. */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) -loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56)) -long long i2cdev_lseek (struct file *file, long long offset, int origin) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -long long i2cdev_llseek (struct inode *inode, struct file *file, - long long offset, int origin) -#else -int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset, - int origin) -#endif -{ -#ifdef DEBUG -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56)) - struct inode *inode = file->f_dentry->d_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ - printk("i2c_dev,o: i2c-%d lseek to %ld bytes relative to %d.\n", - MINOR(inode->i_rdev),offset,origin); -#endif /* DEBUG */ - return -ESPIPE; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) -static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, - loff_t *offset) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -static long i2cdev_read (struct inode *inode, struct file *file, char *buf, - unsigned long count) -#else -static int i2cdev_read(struct inode *inode, struct file *file, char *buf, - int count) -#endif -{ - char *tmp; - int ret; - -#ifdef DEBUG -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) - struct inode *inode = file->f_dentry->d_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ -#endif /* DEBUG */ - - struct i2c_client *client = (struct i2c_client *)file->private_data; - - /* copy user space data to kernel space. */ - tmp = kmalloc(count,GFP_KERNEL); - if (tmp==NULL) - return -ENOMEM; - -#ifdef DEBUG - printk("i2c_dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),count); -#endif - - ret = i2c_master_recv(client,tmp,count); - copy_to_user(buf,tmp,count); - kfree(tmp); - return ret; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) -static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, - loff_t *offset) -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)) -static long i2cdev_write (struct inode *inode, struct file *file, - const char *buf, unsigned long offset) -#else -static int i2cdev_write(struct inode *inode, struct file *file, - const char *buf, int count) -#endif -{ - int ret; - char *tmp; - struct i2c_client *client = (struct i2c_client *)file->private_data; - -#ifdef DEBUG -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) - struct inode *inode = file->f_dentry->d_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ -#endif /* DEBUG */ - - /* copy user space data to kernel space. */ - tmp = kmalloc(count,GFP_KERNEL); - if (tmp==NULL) - return -ENOMEM; - copy_from_user(tmp,buf,count); - -#ifdef DEBUG - printk("i2c_dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),count); -#endif - ret = i2c_master_send(client,tmp,count); - kfree(tmp); - return ret; -} - -int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct i2c_client *client = (struct i2c_client *)file->private_data; - struct i2c_smbus_data data_arg; - union smbus_data temp; - int ver,datasize,res; - -#ifdef DEBUG -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) - struct inode *inode = file->f_dentry->d_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */ - printk("i2c_dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", - MINOR(inode->i_rdev),cmd, arg); -#endif /* DEBUG */ - - switch ( cmd ) { - case I2C_SLAVE: - if (arg > 0x7f) - return -EINVAL; - client->addr = arg; - return 0; - case I2C_TENBIT: - printk("i2c-dev.o: ioctl I2C_TENBIT not (yet) supported!\n"); - return -EINVAL; - case I2C_SMBUS: - if (! arg) { -#ifdef DEBUG - printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n"); -#endif - return -EINVAL; - } - if (verify_area(VERIFY_READ,(struct i2c_smbus_data *) arg, - sizeof(struct i2c_smbus_data))) { -#ifdef DEBUG - printk("i2c-dev.o: invalid argument pointer (%ld) " - "in IOCTL I2C_SMBUS.\n", arg); -#endif - return -EINVAL; - } - copy_from_user(&data_arg,(struct i2c_smbus_data *) arg, - sizeof(struct i2c_smbus_data)); - if ((data_arg.size != SMBUS_BYTE) && - (data_arg.size != SMBUS_QUICK) && - (data_arg.size != SMBUS_BYTE_DATA) && - (data_arg.size != SMBUS_WORD_DATA) && - (data_arg.size != SMBUS_PROC_CALL) && - (data_arg.size != SMBUS_BLOCK_DATA)) { -#ifdef DEBUG - printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.size); -#endif - return -EINVAL; - } - /* Note that SMBUS_READ and SMBUS_WRITE are 0 and 1, so the check is - valid if size==SMBUS_QUICK too. */ - if ((data_arg.read_write != SMBUS_READ) && - (data_arg.read_write != SMBUS_WRITE)) { -#ifdef DEBUG - printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.read_write); -#endif - return -EINVAL; - } - - /* Note that command values are always valid! */ - - if ((data_arg.size == SMBUS_QUICK) || - ((data_arg.size == SMBUS_BYTE) && - (data_arg.read_write == SMBUS_WRITE))) - /* These are special: we do not use data */ - return smbus_access(client->adapter, client->addr, - data_arg.read_write, data_arg.command, - data_arg.size, NULL); - - if (data_arg.data == NULL) { -#ifdef DEBUG - printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n"); -#endif - return -EINVAL; - } - - /* This seems unlogical but it is not: if the user wants to read a - value, we must write that value to user memory! */ - ver = (data_arg.read_write == SMBUS_WRITE)?VERIFY_READ:VERIFY_WRITE; - - if ((data_arg.size == SMBUS_BYTE_DATA) || (data_arg.size == SMBUS_BYTE)) - datasize = sizeof(data_arg.data->byte); - else if (data_arg.size == SMBUS_WORD_DATA) - datasize = sizeof(data_arg.data->word); - else /* size == SMBUS_BLOCK_DATA */ - datasize = sizeof(data_arg.data->block); - - if (verify_area(ver,data_arg.data,datasize)) { -#ifdef DEBUG - printk("i2c-dev.o: invalid pointer data (%p) in ioctl I2C_SMBUS.\n", - data_arg.data); -#endif - return -EINVAL; - } - if (data_arg.read_write == SMBUS_WRITE) { - copy_from_user(&temp,data_arg.data,datasize); - return smbus_access(client->adapter,client->addr,data_arg.read_write, - data_arg.command,data_arg.size,&temp); - } else { - res = smbus_access(client->adapter,client->addr,data_arg.read_write, - data_arg.command,data_arg.size,&temp); - if (!res) - copy_to_user(data_arg.data,&temp,datasize); - return res; - } - default: - return i2c_control(client,cmd,arg); - } - return 0; -} - -int i2cdev_open (struct inode *inode, struct file *file) -{ - unsigned int minor = MINOR(inode->i_rdev); - struct i2c_client *client; - - if (! i2cdev_clients[minor]) { -#ifdef DEBUG - printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",minor); -#endif - return -ENODEV; - } - - /* Note that we here allocate a client for later use, but we will *not* - register this client! Yes, this is safe. No, it is not very clean. */ - if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) - return -ENOMEM; - memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client)); - client->adapter = i2cdev_clients[minor]->adapter; - file->private_data = client; - - MOD_INC_USE_COUNT; - -#ifdef DEBUG - printk("i2c-dev.o: opened i2c-%d\n",minor); -#endif - return 0; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31)) -static int i2cdev_release (struct inode *inode, struct file *file) -#else -static void i2cdev_release (struct inode *inode, struct file *file) -#endif -{ - kfree(file->private_data); - file->private_data=NULL; -#ifdef DEBUG - printk("i2c-dev.o: Closed: i2c-%d\n", MINOR(inode->i_rdev)); -#endif - MOD_DEC_USE_COUNT; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31)) - return 0; -#endif -} - -int i2cdev_attach_adapter(struct i2c_adapter *adap) -{ - int i,res; - struct i2c_client *client; - - if ((i = i2c_adapter_id(adap)) < 0) { - printk("i2c-dev.o: Unknown adapter to attach?!?\n"); - return -ENODEV; - } - if (i >= I2CDEV_CLIENTS_MAX) { - printk("i2c-dev.o: Adapter number to attach too large?!? (%d)\n",i); - return -ENODEV; - } - if (i2cdev_clients[i]) { - printk("i2c-dev.o: Adapter to attach already in use?!? (%d)\n",i); - return -EBUSY; - } - if (i2c_is_isa_adapter(adap)) { -#ifdef DEBUG - printk("i2c-dev.o: Can't attach ISA adapter!\n"); -#endif - return 0; - } - - if (! (client = (struct i2c_client *)kmalloc(sizeof(struct i2c_client), - GFP_KERNEL))) - return -ENOMEM; - memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client)); - client->adapter = adap; - if ((res = i2c_attach_client(client))) { - printk("i2c-dev.o: Attaching client failed.\n"); - kfree(client); - return res; - } - i2cdev_clients[i] = client; - printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); - return 0; -} - -int i2cdev_detach_client(struct i2c_client *client) -{ - struct i2c_adapter *adap = client->adapter; - int i,res; - - if ((i = i2c_adapter_id(adap)) < 0) { - printk("i2c-dev.o: Detaching unknown adapter?!?\n"); - return -ENODEV; - } - if (i >= I2CDEV_CLIENTS_MAX) { - printk("i2c-dev.o: Adapter number to detach too large?!? (%d)\n",i); - return -ENODEV; - } - if (!i2cdev_clients[i]) { - printk("i2c-dev.o: Adapter to detach not in use?!? (%d)\n",i); - return -ENODEV; - } - - if ((res = i2c_detach_client(client))) { - printk("i2c-dev.o: detaching client %d failed.\n",i); - return res; - } - - kfree(i2cdev_clients[i]); - i2cdev_clients[i] = NULL; - -#ifdef DEBUG - printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name); -#endif - return 0; -} - -static int i2cdev_command(struct i2c_client *client, unsigned int cmd, - void *arg) -{ - return -1; -} - - -static void i2cdev_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -static void i2cdev_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -int i2cdev_init(void) -{ - int res; - - printk("i2c-dev.o version %s (%s)\n",LM_VERSION,LM_DATE); - i2cdev_initialized = 0; - if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) { - printk("i2c-dev.o: unable to get major %d for i2c bus\n",I2C_MAJOR); - return -EIO; - } - i2cdev_initialized ++; - - if ((res = i2c_add_driver(&i2cdev_driver))) { - printk("i2c-dev.o: Driver registration failed, module not inserted.\n"); - i2cdev_cleanup(); - return res; - } - i2cdev_initialized ++; - return 0; -} - -int i2cdev_cleanup(void) -{ - int res; - - if (i2cdev_initialized >= 2) { - if ((res = i2c_del_driver(&i2cdev_driver))) { - printk("i2c-dev.o: Driver deregistration failed, " - "module not removed.\n"); - return res; - } - i2cdev_initialized ++; - } - - if (i2cdev_initialized >= 1) { - if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) { - printk("i2c-dev.o: unable to release major %d for i2c bus\n",I2C_MAJOR); - return res; - } - i2cdev_initialized --; - } - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard and Simon G. Vogl "); -MODULE_DESCRIPTION("I2C /dev entries driver"); - -int init_module(void) -{ - return i2cdev_init(); -} - -int cleanup_module(void) -{ - return i2cdev_cleanup(); -} - -#endif /* def MODULE */ - diff --git a/src/i2c-dev.h b/src/i2c-dev.h deleted file mode 100644 index cd35f7fe..00000000 --- a/src/i2c-dev.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - i2c-dev.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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. -*/ - -#ifndef SENSORS_I2C_DEV_H -#define SENSORS_I2C_DEV_H - -#ifdef LM_SENSORS -#include "i2c.h" -#include "smbus.h" -#else /* ndef LM_SENSORS */ -#include -#include -#endif /* def LM_SENSORS */ - -#include - -/* Some IOCTL commands are defined in */ -/* Note: 10-bit addresses are NOT supported! */ - -#define I2C_SMBUS 0x0720 - -/* This is the structure as used in the I2C_SMBUS ioctl call */ -struct i2c_smbus_data { - char read_write; - __u8 command; - int size; - union smbus_data *data; -}; - -#ifndef __KERNEL__ - -#include - -extern inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, - int size, union smbus_data *data) -{ - struct i2c_smbus_data args; - - args.read_write = read_write; - args.command = command; - args.size = size; - args.data = data; - return ioctl(file,I2C_SMBUS,&args); -} - - -extern inline __s32 i2c_smbus_write_quick(int file, __u8 value) -{ - return i2c_smbus_access(file,value,0,SMBUS_QUICK,NULL); -} - -extern inline __s32 i2c_smbus_read_byte(int file) -{ - union smbus_data data; - if (i2c_smbus_access(file,SMBUS_READ,0,SMBUS_BYTE,&data)) - return -1; - else - return 0x0FF & data.byte; -} - -extern inline __s32 i2c_smbus_write_byte(int file, __u8 value) -{ - return i2c_smbus_access(file,SMBUS_WRITE,value, SMBUS_BYTE,NULL); -} - -extern inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) -{ - union smbus_data data; - if (i2c_smbus_access(file,SMBUS_READ,command,SMBUS_BYTE_DATA,&data)) - return -1; - else - return 0x0FF & data.byte; -} - -extern inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, - __u8 value) -{ - union smbus_data data; - data.byte = value; - return i2c_smbus_access(file,SMBUS_WRITE,command,SMBUS_BYTE_DATA,&data); -} - -extern inline __s32 i2c_smbus_read_word_data(int file, __u8 command) -{ - union smbus_data data; - if (i2c_smbus_access(file,SMBUS_READ,command,SMBUS_WORD_DATA,&data)) - return -1; - else - return 0x0FFFF & data.word; -} - -extern inline __s32 i2c_smbus_write_word_data(int file, __u8 command, - __u16 value) -{ - union smbus_data data; - data.word = value; - return i2c_smbus_access(file,SMBUS_WRITE,command,SMBUS_WORD_DATA, &data); -} - -extern inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) -{ - union smbus_data data; - data.word = value; - if (i2c_smbus_access(file,SMBUS_WRITE,command,SMBUS_PROC_CALL,&data)) - return -1; - else - return 0x0FFFF & data.word; -} - - -/* Returns the number of read bytes */ -extern inline __s32 i2c_smbus_read_block_data(int file, __u8 command, - __u8 *values) -{ - union smbus_data data; - int i; - if (i2c_smbus_access(file,SMBUS_READ,command,SMBUS_BLOCK_DATA,&data)) - return -1; - else { - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; - } -} - -extern inline __s32 i2c_smbus_write_block_data(int file, __u8 command, - __u8 length, __u8 *values) -{ - union smbus_data data; - int i; - if (length > 32) - length = 32; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - data.block[0] = length; - return i2c_smbus_access(file,SMBUS_WRITE,command,SMBUS_BLOCK_DATA,&data); -} - -#endif /* ndef __KERNEL__ */ - -#endif diff --git a/src/i2c-proc.c b/src/i2c-proc.c deleted file mode 100644 index 8b3046bd..00000000 --- a/src/i2c-proc.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - i2c-proc.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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 -#include - -#include "i2c.h" -#include "smbus.h" -#include "isa.h" -#include "version.h" -#include "compat.h" -#include "sensors.h" - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* def MODULE */ - -static int i2cproc_init(void); -static int i2cproc_cleanup(void); -static int i2cproc_attach_adapter(struct i2c_adapter *adapter); -static int i2cproc_detach_client(struct i2c_client *client); -static int i2cproc_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void i2cproc_inc_use(struct i2c_client *client); -static void i2cproc_dec_use(struct i2c_client *client); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) -static void monitor_bus_i2c(struct inode *inode, int fill); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - -static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, - loff_t *ppos); -static int read_bus_i2c(char *buf, char **start, off_t offset, int len, - int *eof , void *private); - -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - -static int i2cproc_bus_read(struct inode * inode, struct file * file, - char * buf, int count); -static int read_bus_i2c(char *buf, char **start, off_t offset, int len, - int unused); - -static struct proc_dir_entry proc_bus_dir = - { - /* low_ino */ 0, /* Set by proc_register_dynamic */ - /* namelen */ 3, - /* name */ "bus", - /* mode */ S_IRUGO | S_IXUGO | S_IFDIR, - /* nlink */ 2, /* Corrected by proc_register[_dynamic] */ - /* uid */ 0, - /* gid */ 0, - /* size */ 0, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36)) - /* ops */ &proc_dir_inode_operations, -#endif - }; - -static struct proc_dir_entry proc_bus_i2c_dir = - { - /* low_ino */ 0, /* Set by proc_register_dynamic */ - /* namelen */ 3, - /* name */ "i2c", - /* mode */ S_IRUGO | S_IFREG, - /* nlink */ 1, - /* uid */ 0, - /* gid */ 0, - /* size */ 0, - /* ops */ NULL, - /* get_info */ &read_bus_i2c - }; - -/* List of registered entries in /proc/bus */ -static struct proc_dir_entry *i2cproc_proc_entries[I2C_ADAP_MAX]; - -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - -/* To implement the dynamic /proc/bus/i2c-? files, we need our own - implementation of the read hook */ -static struct file_operations i2cproc_operations = { - NULL, - i2cproc_bus_read, -}; - -static struct inode_operations i2cproc_inode_operations = { - &i2cproc_operations -}; - - -/* Used by init/cleanup */ -static int i2cproc_initialized; - -/* This is a sorted list of all adapters that will have entries in /proc/bus */ -static struct i2c_adapter *i2cproc_adapters[I2C_ADAP_MAX]; - -/* Inodes of /dev/bus/i2c-? files */ -static int i2cproc_inodes[I2C_ADAP_MAX]; - -/* We will use a nasty trick: we register a driver, that will be notified - for each adapter. Then, we register a dummy client on the adapter, that - will get notified if the adapter is removed. This is the same trick as - used in i2c/i2c-dev.c */ -static struct i2c_driver i2cproc_driver = { - /* name */ "i2c-proc dummy driver", - /* id */ I2C_DRIVERID_I2CPROC, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &i2cproc_attach_adapter, - /* detach_client */ &i2cproc_detach_client, - /* command */ &i2cproc_command, - /* inc_use */ &i2cproc_inc_use, - /* dec_use */ &i2cproc_dec_use -}; - -static struct i2c_client i2cproc_client_template = { - /* name */ "i2c-proc dummy client", - /* id */ 1, - /* flags */ 0, - /* addr */ -1, - /* adapter */ NULL, - /* driver */ &i2cproc_driver, - /* data */ NULL -}; - - -int i2cproc_init(void) -{ - int res; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - struct proc_dir_entry *proc_bus_i2c; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - - printk("i2c-proc.o version %s (%s)\n",LM_VERSION,LM_DATE); - i2cproc_initialized = 0; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - if (! proc_bus) { - printk("i2c-proc.o: /proc/bus/ does not exist, module not inserted.\n"); - i2cproc_cleanup(); - return -ENOENT; - } - proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); - if (!proc_bus_i2c) { - printk("i2c-proc.o: Could not create /proc/bus/i2c, " - "module not inserted.\n"); - i2cproc_cleanup(); - return -ENOENT; - } - proc_bus_i2c->read_proc = &read_bus_i2c; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) - proc_bus_i2c->fill_inode = &monitor_bus_i2c; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - i2cproc_initialized += 2; -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - /* In Linux 2.0.x, there is no /proc/bus! But I hope no other module - introduced it, or we are fucked. And 2.0.35 and earlier does not - export proc_dir_inode_operations, so we grab it from proc_net, - which also uses it. Not nice. */ -/* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,0,36) */ - proc_bus_dir.ops = proc_net.ops; -/* #endif */ - if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) { - printk("i2c-proc.o: Could not create /proc/bus/, module not inserted.\n"); - i2cproc_cleanup(); - return res; - } - i2cproc_initialized ++; - if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) { - printk("i2c-proc.o: Could not create /proc/bus/i2c, " - "module not inserted.\n"); - i2cproc_cleanup(); - return res; - } - i2cproc_initialized ++; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - if ((res = i2c_add_driver(&i2cproc_driver))) { - printk("i2c-proc.o: Driver registration failed, module not inserted.\n"); - i2cproc_cleanup(); - return res; - } - i2cproc_initialized ++; - return 0; -} - -int i2cproc_cleanup(void) -{ - int res; - - if (i2cproc_initialized >= 3) { - if ((res = i2c_del_driver(&i2cproc_driver))) { - printk("i2c-proc.o: Driver deregistration failed, " - "module not removed.\n"); - return res; - } - i2cproc_initialized--; - } - if (i2cproc_initialized >= 1) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - remove_proc_entry("i2c",proc_bus); - i2cproc_initialized -= 2; -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - if (i2cproc_initialized >= 2) { - if ((res = proc_unregister(&proc_bus_dir,proc_bus_i2c_dir.low_ino))) { - printk("i2c-proc.o: could not delete /proc/bus/i2c, " - "module not removed."); - return res; - } - i2cproc_initialized --; - } - if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) { - printk("i2c-proc.o: could not delete /proc/bus/, " - "module not removed."); - return res; - } - i2cproc_initialized --; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - } - return 0; -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) -/* Monitor access to /proc/bus/i2c*; make unloading i2c-proc.o impossible - if some process still uses it or some file in it */ -void monitor_bus_i2c(struct inode *inode, int fill) -{ - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ - - -/* This function generates the output for /proc/bus/i2c */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) -int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, - void *private) -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ -int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused) -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ -{ - int i; - len = 0; - for (i = 0; i < I2C_ADAP_MAX; i++) - if (i2cproc_adapters[i]) - len += sprintf(buf+len, "i2c-%d\t%s\t%-32s\t%-32s\n", - i2c_adapter_id(i2cproc_adapters[i]), - i2c_is_smbus_adapter(i2cproc_adapters[i])?"smbus": -#ifdef DEBUG - i2c_is_isa_adapter(i2cproc_adapters[i])?"isa": -#endif /* def DEBUG */ - "i2c", - i2cproc_adapters[i]->name, - i2cproc_adapters[i]->algo->name); - return len; -} - -/* This function generates the output for /proc/bus/i2c-? */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) -ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, - loff_t *ppos) -{ - struct inode * inode = file->f_dentry->d_inode; -#else (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) -int i2cproc_bus_read(struct inode * inode, struct file * file,char * buf, - int count) -{ -#endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - char *kbuf; - struct i2c_client *client; - int i,j,len=0; - - if (count < 0) - return -EINVAL; - if (count > 4000) - count = 4000; - for (i = 0; i < I2C_ADAP_MAX; i++) - if (i2cproc_inodes[i] == inode->i_ino) { - if (! (kbuf = kmalloc(count,GFP_KERNEL))) - return -ENOMEM; - for (j = 0; j < I2C_CLIENT_MAX; j++) - if ((client = i2cproc_adapters[i]->clients[j])) - /* Filter out dummy clients */ -#ifndef DEBUG - if ((client->driver->id != I2C_DRIVERID_I2CPROC) && - (client->driver->id != I2C_DRIVERID_I2CDEV)) -#endif /* ndef DEBUG */ - len += sprintf(kbuf+len,"%x\t%-32s\t%-32s\n", -#ifdef DEBUG - i2c_is_isa_client(client)? - ((struct isa_client *) client)->isa_addr&0xffffff: -#endif /* def DEBUG */ - client->addr, - client->name,client->driver->name); - if (file->f_pos+len > count) - len = count - file->f_pos; - len = len - file->f_pos; - if (len < 0) - len = 0; - copy_to_user (buf,kbuf+file->f_pos,len); - file->f_pos += len; - kfree(kbuf); - return len; - } - return -ENOENT; -} - - -/* We need to add the adapter to i2cproc_adapters, if it is interesting - enough */ -int i2cproc_attach_adapter(struct i2c_adapter *adapter) -{ - struct i2c_client *client; - int i,res; - char name[8]; - - struct proc_dir_entry *proc_entry; - -#ifndef DEBUG - if (i2c_is_isa_adapter(adapter)) - return 0; -#endif /* ndef DEBUG */ - - for (i = 0; i < I2C_ADAP_MAX; i++) - if(!i2cproc_adapters[i]) - break; - if (i == I2C_ADAP_MAX) { - printk("i2c-proc.o: Too many adapters!\n"); - return -ENOMEM; - } - -#ifndef DEBUG - if (! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) { -#else /* def DEBUG */ - if (! (client = kmalloc(sizeof(struct isa_client),GFP_KERNEL))) { -#endif - printk("i2c-proc.o: Out of memory!\n"); - return -ENOMEM; - } - memcpy(client,&i2cproc_client_template,sizeof(struct i2c_client)); -#ifdef DEBUG - ((struct isa_client *) client) -> isa_addr = -1; -#endif /* def DEBUG */ - client->adapter = adapter; - if ((res = i2c_attach_client(client))) { - printk("i2c-proc.o: Attaching client failed.\n"); - kfree(client); - return res; - } - i2cproc_adapters[i] = adapter; - - sprintf(name,"i2c-%d",i2c_adapter_id(adapter)); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - proc_entry = create_proc_entry(name,0,proc_bus); - if (! proc_entry) { - printk("i2c-proc.o: Could not create /proc/bus/%s\n",name); - kfree(client); - return -ENOENT; - } - proc_entry->ops = &i2cproc_inode_operations; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) - proc_entry->fill_inode = &monitor_bus_i2c; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+strlen(name)+1, - GFP_KERNEL))) { - printk("i2c-proc.o: Out of memory!\n"); - return -ENOMEM; - } - - memset(proc_entry,0,sizeof(struct proc_dir_entry)); - proc_entry->namelen = strlen(name); - proc_entry->name = (char *) (proc_entry + 1); - proc_entry->mode = S_IRUGO | S_IFREG; - proc_entry->nlink = 1; - proc_entry->ops = &i2cproc_inode_operations; - strcpy((char *) proc_entry->name,name); - - if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) { - printk("i2c-proc.o: Could not create %s.\n",name); - kfree(proc_entry); - kfree(client); - return res; - } - - i2cproc_proc_entries[i] = proc_entry; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - - i2cproc_inodes[i] = proc_entry->low_ino; - return 0; -} - -int i2cproc_detach_client(struct i2c_client *client) -{ - int i,res; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - char name[8]; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - -#ifndef DEBUG - if (i2c_is_isa_client(client)) - return 0; -#endif /* ndef DEBUG */ - - for (i = 0; i < I2C_ADAP_MAX; i++) - if (client->adapter == i2cproc_adapters[i]) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) - sprintf(name,"i2c-%d",i2c_adapter_id(i2cproc_adapters[i])); - remove_proc_entry(name,proc_bus); -#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ - if ((res = proc_unregister(&proc_bus_dir, - i2cproc_proc_entries[i]->low_ino))) { - printk("i2c-proc.o: Deregistration of /proc entry failed, " - "client not detached.\n"); - return res; - } - kfree(i2cproc_proc_entries[i]); - i2cproc_proc_entries[i] = NULL; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ - if ((res = i2c_detach_client(client))) { - printk("i2c-proc.o: Client deregistration failed, " - "client not detached.\n"); - return res; - } - i2cproc_adapters[i] = NULL; - i2cproc_inodes[i] = 0; - kfree(client); - return 0; - } - return -ENOENT; -} - -/* Nothing here yet */ -int i2cproc_command(struct i2c_client *client, unsigned int cmd, - void *arg) -{ - return -1; -} - -/* Nothing here yet */ -void i2cproc_inc_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void i2cproc_dec_use(struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("I2C /proc/bus entries driver"); - -int init_module(void) -{ - return i2cproc_init(); -} - -int cleanup_module(void) -{ - return i2cproc_cleanup(); -} - -#endif /* def MODULE */ - diff --git a/src/i2c.h b/src/i2c.h deleted file mode 100644 index 644565c5..00000000 --- a/src/i2c.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - i2c.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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 is a stub files, that either includes (the kernel - header) or "i2c/i2c.h" (the header in the i2c directory). */ - -#ifdef I2C -#include "i2c/i2c.h" -#else /* def I2C */ -#include -#endif /* def I2C */ - diff --git a/src/isa.c b/src/isa.c deleted file mode 100644 index 8ec904ae..00000000 --- a/src/isa.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - isa.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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 i2c algorithm/adapter for ISA bus. Not that this is - on first sight very useful; almost no functionality is preserved. - Except that it makes writing drivers for chips which can be on both - the SMBus and the ISA bus very much easier. See lm78.c for an example - of this. */ - -#include -#include - -#include "i2c.h" -#ifdef SPINLOCK -#include -#else -#include -#endif - -#include "version.h" -#include "isa.h" - -static int isa_master_xfer (struct isa_adapter *adap, - struct i2c_msg msgs[], int num); -static int isa_slave_send (struct isa_adapter *adap, char *data, int len); -static int isa_slave_recv (struct isa_adapter *adap, char *data, int len); -static int isa_algo_control (struct isa_adapter *adap, unsigned int cmd, - unsigned long arg); -static int isa_client_register (struct isa_client *client); -static int isa_client_unregister (struct isa_client *client); - -static int isa_init(void); -static int isa_cleanup(void); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -/* This is the actual algorithm we define */ -static struct isa_algorithm isa_algorithm = { - /* name */ "ISA bus adapter", - /* id */ ALGO_ISA, - /* master_xfer */ &isa_master_xfer, - /* slave_send */ &isa_slave_send, - /* slave_rcv */ &isa_slave_recv, - /* algo_control */ &isa_algo_control, - /* client_register */ &isa_client_register, - /* client_unregister*/&isa_client_unregister -}; - -/* There can only be one... */ -static struct isa_adapter isa_adapter; - -/* Used in isa_init/cleanup */ -static int isa_initialized; - -/* Algorithm master_xfer call-back implementation. Can't do that... */ -int isa_master_xfer (struct isa_adapter *adap, struct i2c_msg msgs[], - int num) -{ -#ifdef DEBUG - printk("isa.o: isa_master_xfer called for adapter `%s' " - "(no i2c level access possible!)\n", - adap->name); -#endif - return -1; -} - -/* Algorithm slave_send call-back implementation. Can't do that... */ -int isa_slave_send (struct isa_adapter *adap, char *data, int len) -{ -#ifdef DEBUG - printk("isa.o: isa_slave_send called for adapter `%s' " - "(no i2c level access possible!)\n", - adap->name); -#endif - return -1; -} - -/* Algorithm slave_recv call-back implementation. Can't do that... */ -int isa_slave_recv (struct isa_adapter *adap, char *data, int len) -{ -#ifdef DEBUG - printk("isa.o: isa_slave_recv called for adapter `%s' " - "(no i2c level access possible!)\n", - adap->name); -#endif - return -1; -} - -/* Here we can put additional calls to modify the workings of the algorithm. - But right now, there is no need for that. */ -int isa_algo_control (struct isa_adapter *adap, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - -/* Ehm... This is called when a client is registered to an adapter. We could - do all kinds of neat stuff here like, ehm - returning success? */ -int isa_client_register (struct isa_client *client) -{ - return 0; -} - -int isa_client_unregister (struct isa_client *client) -{ - return 0; -} - -int isa_init(void) -{ - int res; - printk("isa.o version %s (%s)\n",LM_VERSION,LM_DATE); -#ifdef DEBUG - if (isa_initialized) { - printk("isa.o: Oops, isa_init called a second time!\n"); - return -EBUSY; - } -#endif - isa_initialized = 0; - if ((res = isa_add_algorithm(&isa_algorithm))) { - printk("isa.o: Algorithm registration failed, module not inserted.\n"); - isa_cleanup(); - return res; - } - isa_initialized++; - strcpy(isa_adapter.name,"ISA main adapter"); - isa_adapter.id = ALGO_ISA | ISA_MAIN; - isa_adapter.algo = &isa_algorithm; - if ((res = isa_add_adapter(&isa_adapter))) { - printk("isa.o: Adapter registration failed, " - "module isa.o is not inserted\n."); - isa_cleanup(); - return res; - } - isa_initialized++; - printk("isa.o: ISA bus access for i2c modules initialized.\n"); - return 0; -} - -int isa_cleanup(void) -{ - int res; - if (isa_initialized >= 2) - { - if ((res = isa_del_adapter(&isa_adapter))) { - printk("isa.o: Adapter deregistration failed, module not removed.\n"); - return res; - } else - isa_initialized--; - } - if (isa_initialized >= 1) - { - if ((res = isa_del_algorithm(&isa_algorithm))) { - printk("isa.o: Algorithm deregistration failed, module not removed.\n"); - return res; - } else - isa_initialized--; - } - return 0; -} - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("ISA bus access through i2c"); - -int init_module(void) -{ - return isa_init(); -} - -int cleanup_module(void) -{ - return isa_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/isa.h b/src/isa.h deleted file mode 100644 index df8bb5ff..00000000 --- a/src/isa.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - isa.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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. -*/ - -#ifndef SENSORS_SENSOR_H -#define SENSORS_SENSOR_H - -#ifdef __KERNEL__ - -/* This file must interface with Simon Vogl's i2c driver. Version 19981006 is - OK, earlier versions are not; later versions will probably give problems - too. -*/ -#include - -/* SPINLOCK is defined in i2c.h. */ -#ifdef SPINLOCK -#include -#else -#include -#endif - -#ifdef LM_SENSORS -#include "i2c.h" -#else /* ndef LM_SENSORS */ -#include -#endif /* def LM_SENSORS */ - -/* Note that this driver is *not* built upon smbus.c, but is parallel to it. - We do not need SMBus facilities if we are on the ISA bus, after all */ - -/* Declarations, to keep the compiler happy */ -struct isa_driver; -struct isa_client; -struct isa_algorithm; -struct isa_adapter; - -/* A driver tells us how we should handle a specific kind of chip. - A specific instance of such a chip is called a client. - This structure is essentially the same as i2c_driver. */ -struct isa_driver { - char name[32]; - int id; - unsigned int flags; - int (* attach_adapter) (struct isa_adapter *); - int (* detach_client) (struct isa_client *); - int (* command) (struct isa_client *, unsigned int cmd, void *arg); - void (* inc_use) (struct isa_client *); - void (* dec_use) (struct isa_client *); -}; - -/* A client is a specifc instance of a chip: for each detected chip, there will - be a client. Its operation is controlled by a driver. - This structure is an extension of i2c_client. */ -struct isa_client { - char name[32]; - int id; - unsigned int flags; - unsigned char addr; - struct isa_adapter *adapter; - struct isa_driver *driver; - void *data; - - /* Here ended i2c_client */ - unsigned int isa_addr; -}; - -/* An algorithm describes how a certain class of busses can be accessed. - A specific instance of sucj a bus is called an adapter. - This structure is essentially the same as i2c_adapter. */ -struct isa_algorithm { - char name[32]; - unsigned int id; - int (* master_xfer) (struct isa_adapter *adap, struct i2c_msg msgs[], - int num); - int (* slave_send) (struct isa_adapter *,char *, int); - int (* slave_recv) (struct isa_adapter *,char *, int); - int (* algo_control) (struct isa_adapter *, unsigned int, unsigned long); - int (* client_register) (struct isa_client *); - int (* client_unregister) (struct isa_client *); -}; - -/* An adapter is a specifc instance of a bus: for each detected bus, there will - be an adapter. Its operation is controlled by an algorithm. - SPINLOCK must be the same as declared in i2c.h. - This structure is essentially the same as i2c_algorithm. */ -struct isa_adapter { - char name[32]; - unsigned int id; - struct isa_algorithm *algo; - void *data; -#ifdef SPINLOCK - spinlock_t lock; - unsigned long lockflags; -#else - struct semaphore lock; -#endif - unsigned int flags; - struct isa_client *clients[I2C_CLIENT_MAX]; - int client_count; - int timeout; - int retries; -}; - - -/* Detect whether we are on the isa bus. If this returns true, all i2c - access will fail! */ -#define i2c_is_isa_client(clientptr) \ - ((clientptr)->adapter->algo->id == ALGO_ISA) -#define i2c_is_isa_adapter(adapptr) \ - ((adapptr)->algo->id == ALGO_ISA) - -/* Next: define ISA variants of registering. */ -#define isa_add_algorithm(algoptr) \ - i2c_add_algorithm((struct i2c_algorithm *) (algoptr)) -#define isa_del_algorithm(algoptr) \ - i2c_del_algorithm((struct i2c_algorithm *) (algoptr)) - -#define isa_add_adapter(adapptr) \ - i2c_add_adapter((struct i2c_adapter *) (adapptr)) -#define isa_del_adapter(adapptr) \ - i2c_del_adapter((struct i2c_adapter *) (adapptr)) - -#define isa_add_driver(driverptr) \ - i2c_add_driver((struct i2c_driver *) (driverptr)) -#define isa_del_driver(driverptr) \ - i2c_add_driver((struct i2c_driver *) (driverptr)) - -#define isa_attach_client(clientptr) \ - i2c_attach_client((struct i2c_client *) (clientptr)) -#define isa_detach_client(clientptr) \ - i2c_detach_client((struct i2c_client *) (clientptr)) - -#endif /* def __KERNEL__ */ - -/* We need to mark ISA algorithms in the algorithm structure. */ -#define ALGO_ISA 0x50000 - -/* ISA Adapter ids */ -#define ISA_MAIN 1 - -#endif /* ndef SENSORS_ISA_H */ diff --git a/src/lm75.c b/src/lm75.c deleted file mode 100644 index 4ab9f4de..00000000 --- a/src/lm75.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - lm75.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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 -#include -#include "smbus.h" -#include "sensors.h" -#include "i2c.h" -#include "version.h" - -/* Many LM75 constants specified below */ - -/* The LM75 registers */ -#define LM75_REG_TEMP 0x00 -#define LM75_REG_CONF 0x01 -#define LM75_REG_TEMP_HYST 0x02 -#define LM75_REG_TEMP_OS 0x03 - -/* Conversions */ -#define TEMP_FROM_REG(val) (((val) >> 7) * 5) -#define TEMP_TO_REG(val) (((((val) + 2) / 5) << 7) & 0xff80) - -/* Initial values */ -#define LM75_INIT_TEMP_OS 600 -#define LM75_INIT_TEMP_HYST 500 - -/* Each client has this additional data */ -struct lm75_data { - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp,temp_os,temp_hyst; /* Register values */ -}; - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static int lm75_init(void); -static int lm75_cleanup(void); -static int lm75_attach_adapter(struct i2c_adapter *adapter); -static int lm75_detach_client(struct i2c_client *client); -static int lm75_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void lm75_inc_use (struct i2c_client *client); -static void lm75_dec_use (struct i2c_client *client); -static u16 swap_bytes(u16 val); -static int lm75_read_value(struct i2c_client *client, u8 reg); -static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); -static void lm75_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm75_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver lm75_driver = { - /* name */ "LM75 sensor chip driver", - /* id */ I2C_DRIVERID_LM75, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &lm75_attach_adapter, - /* detach_client */ &lm75_detach_client, - /* command */ &lm75_command, - /* inc_use */ &lm75_inc_use, - /* dec_use */ &lm75_dec_use -}; - -/* These files are created for each detected LM75. 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 lm75_dir_table_template[] = { - { LM75_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm75_temp }, - { 0 } -}; - -/* Used by init/cleanup */ -static int lm75_initialized = 0; - -/* I choose here for semi-static LM78 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_LM75_NR 8 -static struct i2c_client *lm75_list[MAX_LM75_NR]; - - -int lm75_attach_adapter(struct i2c_adapter *adapter) -{ - int address,err,i; - struct i2c_client *new_client; - struct lm75_data *data; - - err = 0; - - /* OK, this is no detection. I know. It will do for now, though. */ - - /* Set err only if a global error would make registering other clients - impossible too (like out-of-memory). */ - for (address = 0x48; (! err) && (address <= 0x4f); 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,LM75_REG_CONF) < 0) - continue; - - /* Real detection code goes here */ - - /* Allocate space for a new client structure */ - if (! (new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct lm75_data), - GFP_KERNEL))) { - err = -ENOMEM; - continue; - } - - /* Find a place in our global list */ - for (i = 0; i < MAX_LM75_NR; i++) - if (! lm75_list[i]) - break; - if (i == MAX_LM75_NR) { - err = -ENOMEM; - printk("lm75.o: No empty slots left, recompile and heighten " - "MAX_LM75_NR!\n"); - goto ERROR1; - } - lm75_list[i] = new_client; - - /* Fill the new client structure with data */ - data = (struct lm75_data *) (new_client + 1); - new_client->data = data; - new_client->id = i; - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &lm75_driver; - strcpy(new_client->name,"LM75 chip"); - data->valid = 0; - data->update_lock = MUTEX; - - /* Tell i2c-core a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Register a new directory entry with module sensors */ - if ((err = sensors_register_entry(new_client,"lm75", - lm75_dir_table_template)) < 0) - goto ERROR3; - data->sysctl_id = err; - err = 0; - - /* Initialize the LM75 chip */ - lm75_write_value(new_client,LM75_REG_TEMP_OS, - TEMP_TO_REG(LM75_INIT_TEMP_OS)); - lm75_write_value(new_client,LM75_REG_TEMP_HYST, - TEMP_TO_REG(LM75_INIT_TEMP_HYST)); - lm75_write_value(new_client,LM75_REG_CONF,0); - - continue; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -ERROR3: - i2c_detach_client(new_client); -ERROR2: - lm75_list[i] = NULL; -ERROR1: - kfree(new_client); - } - return err; -} - -int lm75_detach_client(struct i2c_client *client) -{ - int err,i; - for (i = 0; i < MAX_LM75_NR; i++) - if (client == lm75_list[i]) - break; - if ((i == MAX_LM75_NR)) { - printk("lm75.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct lm75_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("lm75.o: Client deregistration failed, client not detached.\n"); - return err; - } - - lm75_list[i] = NULL; - kfree(client); - return 0; -} - - -/* No commands defined yet */ -int lm75_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void lm75_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void lm75_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - -u16 swap_bytes(u16 val) -{ - return (val >> 8) | (val << 8); -} - -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -int lm75_read_value(struct i2c_client *client, u8 reg) -{ - if (reg == LM75_REG_CONF) - return smbus_read_byte_data(client->adapter,client->addr,reg); - else - return swap_bytes(smbus_read_word_data(client->adapter,client->addr,reg)); -} - -/* All registers are word-sized, except for the configuration register. - LM75 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ -int lm75_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (reg == LM75_REG_CONF) - return smbus_write_byte_data(client->adapter,client->addr,reg,value); - else - return smbus_write_word_data(client->adapter,client->addr,reg, - swap_bytes(value)); -} - -void lm75_update_client(struct i2c_client *client) -{ - struct lm75_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ+HZ/2 ) || - (jiffies < data->last_updated) || ! data->valid) { - -#ifdef DEBUG - printk("Starting lm75 update\n"); -#endif - - data->temp = lm75_read_value(client,LM75_REG_TEMP); - data->temp_os = lm75_read_value(client,LM75_REG_TEMP_OS); - data->temp_hyst = lm75_read_value(client,LM75_REG_TEMP_HYST); - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void lm75_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm75_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm75_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_os); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os = TEMP_TO_REG(results[0]); - lm75_write_value(client,LM75_REG_TEMP_OS,data->temp_os); - } - if (*nrels_mag >= 2) { - data->temp_os = TEMP_TO_REG(results[1]); - lm75_write_value(client,LM75_REG_TEMP_HYST,data->temp_os); - } - } -} - -int lm75_init(void) -{ - int res; - - printk("lm75.o version %s (%s)\n",LM_VERSION,LM_DATE); - lm75_initialized = 0; - if ((res = i2c_add_driver(&lm75_driver))) { - printk("lm75.o: Driver registration failed, module not inserted.\n"); - lm75_cleanup(); - return res; - } - lm75_initialized ++; - return 0; -} - -int lm75_cleanup(void) -{ - int res; - - if (lm75_initialized >= 1) { - if ((res = i2c_del_driver(&lm75_driver))) { - printk("lm75.o: Driver deregistration failed, module not removed.\n"); - return res; - } - lm75_initialized --; - } - - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM75 driver"); - -int init_module(void) -{ - return lm75_init(); -} - -int cleanup_module(void) -{ - return lm75_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/lm78.c b/src/lm78.c deleted file mode 100644 index f8a56de4..00000000 --- a/src/lm78.c +++ /dev/null @@ -1,926 +0,0 @@ -/* - lm78.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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 -#include -#include -#include -#include -#include -#include -#include -#include "smbus.h" -#include "version.h" -#include "isa.h" -#include "sensors.h" -#include "i2c.h" -#include "compat.h" - -/* Many LM78 constants specified below */ - -/* Length of ISA address segment */ -#define LM78_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define LM78_ADDR_REG_OFFSET 5 -#define LM78_DATA_REG_OFFSET 6 - -/* The LM78 registers */ -#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define LM78_REG_IN(nr) (0x20 + (nr)) - -#define LM78_REG_FAN_MIN(nr) (0x3a + (nr)) -#define LM78_REG_FAN(nr) (0x27 + (nr)) - -#define LM78_REG_TEMP 0x27 -#define LM78_REG_TEMP_OVER 0x39 -#define LM78_REG_TEMP_HYST 0x3a - -#define LM78_REG_ALARM1 0x41 -#define LM78_REG_ALARM2 0x42 - -#define LM78_REG_VID_FANDIV 0x47 - -#define LM78_REG_CONFIG 0x40 -#define LM78_REG_CHIPID 0x49 - - -/* Conversions. Rounding is only done on the TO_REG variants. */ -#define IN_TO_REG(val) (((val) * 10 + 8)/16) -#define IN_FROM_REG(val) (((val) * 16) / 10) - -#define FAN_TO_REG(val,div) ((val)==0?255:((1350000+(val)*(div)/2)/\ - ((val)*(div))) & 0xff) -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) - -#define TEMP_TO_REG(val) (((val)<0?(((val)-5)/10)&0xff:((val)+5)/10) & 0xff) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - (val)>=0x06?0:205-(val)*5) -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -/* Initial limits. To keep them sane, we use the 'standard' translation as - specified in the LM78 sheet. Use the config file to set better limits. */ -#define LM78_INIT_IN_0 (vid==350?280:vid) -#define LM78_INIT_IN_1 (vid==350?280:vid) -#define LM78_INIT_IN_2 330 -#define LM78_INIT_IN_3 (((500) * 100)/168) -#define LM78_INIT_IN_4 (((1200) * 10)/38) -#define LM78_INIT_IN_5 (((-1200) * -604)/2100) -#define LM78_INIT_IN_6 (((-500) * -604)/909) - -#define LM78_INIT_IN_PERCENTAGE 10 - -#define LM78_INIT_IN_MIN_0 \ - (LM78_INIT_IN_0 - LM78_INIT_IN_0 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MAX_0 \ - (LM78_INIT_IN_0 + LM78_INIT_IN_0 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MIN_1 \ - (LM78_INIT_IN_1 - LM78_INIT_IN_1 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MAX_1 \ - (LM78_INIT_IN_1 + LM78_INIT_IN_1 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MIN_2 \ - (LM78_INIT_IN_2 - LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MAX_2 \ - (LM78_INIT_IN_2 + LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MIN_3 \ - (LM78_INIT_IN_3 - LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MAX_3 \ - (LM78_INIT_IN_3 + LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MIN_4 \ - (LM78_INIT_IN_4 - LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MAX_4 \ - (LM78_INIT_IN_4 + LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MIN_5 \ - (LM78_INIT_IN_5 - LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MAX_5 \ - (LM78_INIT_IN_5 + LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MIN_6 \ - (LM78_INIT_IN_6 - LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100) -#define LM78_INIT_IN_MAX_6 \ - (LM78_INIT_IN_6 + LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100) - -#define LM78_INIT_FAN_MIN_1 3000 -#define LM78_INIT_FAN_MIN_2 3000 -#define LM78_INIT_FAN_MIN_3 3000 - -#define LM78_INIT_TEMP_OVER 600 -#define LM78_INIT_TEMP_HYST 500 - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -/* There are some complications in a module like this. First off, LM78 chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - LM78 chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the LM78 at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* Types of chips supported */ -enum lm78_type { lm78, lm78j, lm79 }; - -/* For each registered LM78, we need to keep some data in memory. That - data is pointed to by lm78_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new lm78 client is - allocated. */ -struct lm78_data { - struct semaphore lock; - int sysctl_id; - enum lm78_type type; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; /* Register value */ - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u16 alarms; /* Register encoding, combined */ -}; - - -static int lm78_init(void); -static int lm78_cleanup(void); - -static int lm78_attach_adapter(struct i2c_adapter *adapter); -static int lm78_detect_isa(struct isa_adapter *adapter); -static int lm78_detect_smbus(struct i2c_adapter *adapter); -static int lm78_detach_client(struct i2c_client *client); -static int lm78_detach_isa(struct isa_client *client); -static int lm78_detach_smbus(struct i2c_client *client); -static int lm78_new_client(struct i2c_adapter *adapter, - struct i2c_client *new_client); -static void lm78_remove_client(struct i2c_client *client); -static int lm78_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void lm78_inc_use (struct i2c_client *client); -static void lm78_dec_use (struct i2c_client *client); - -static int lm78_read_value(struct i2c_client *client, u8 register); -static int lm78_write_value(struct i2c_client *client, u8 register, u8 value); -static void lm78_update_client(struct i2c_client *client); -static void lm78_init_client(struct i2c_client *client); - - -static void lm78_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm78_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm78_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm78_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm78_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -/* I choose here for semi-static LM78 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_LM78_NR 4 -static struct i2c_client *lm78_list[MAX_LM78_NR]; - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver lm78_driver = { - /* name */ "LM78(-J) and LM79 sensor driver", - /* id */ I2C_DRIVERID_LM78, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &lm78_attach_adapter, - /* detach_client */ &lm78_detach_client, - /* command */ &lm78_command, - /* inc_use */ &lm78_inc_use, - /* dec_use */ &lm78_dec_use -}; - -/* Used by lm78_init/cleanup */ -static int lm78_initialized = 0; - -/* The /proc/sys entries */ -/* These files are created for each detected LM78. 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 lm78_dir_table_template[] = { - { LM78_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_in }, - { LM78_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_in }, - { LM78_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_in }, - { LM78_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_in }, - { LM78_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_in }, - { LM78_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_in }, - { LM78_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_in }, - { LM78_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_fan }, - { LM78_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_fan }, - { LM78_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_fan }, - { LM78_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_temp }, - { LM78_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_vid }, - { LM78_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_fan_div }, - { LM78_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm78_alarms }, - { 0 } -}; - - -/* This function is called when: - * lm78_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm78_driver is still present) */ -int lm78_attach_adapter(struct i2c_adapter *adapter) -{ - if (i2c_is_isa_adapter(adapter)) - return lm78_detect_isa((struct isa_adapter *) adapter); - else - return lm78_detect_smbus(adapter); -} - -/* This function is called whenever a client should be removed: - * lm78_driver is removed (when this module is unloaded) - * when an adapter is removed which has a lm78 client (and lm78_driver - is still present). */ -int lm78_detach_client(struct i2c_client *client) -{ - if (i2c_is_isa_client(client)) - return lm78_detach_isa((struct isa_client *) client); - else - return lm78_detach_smbus(client); -} - -/* Detect whether there is a LM78 on the ISA bus, register and initialize - it. */ -int lm78_detect_isa(struct isa_adapter *adapter) -{ - int address,err; - struct isa_client *new_client; - enum lm78_type type; - const char *type_name; - const char *client_name; - - /* OK, this is no detection. I know. It will do for now, though. */ - - err = 0; - for (address = 0x290; (! err) && (address <= 0x290); address += 0x08) { - if (check_region(address, LM78_EXTENT)) - continue; - - /* Awful, but true: unused port addresses should return 0xff */ - if ((inb_p(address + 1) != 0xff) || (inb_p(address + 2) != 0xff) || - (inb_p(address + 3) != 0xff) || (inb_p(address + 7) != 0xff)) - continue; - - if (inb_p(address + LM78_ADDR_REG_OFFSET) == 0xff) { - outb_p(0x00,address + LM78_ADDR_REG_OFFSET); - if (inb_p(address + LM78_ADDR_REG_OFFSET) == 0xff) - continue; - } - - /* Real detection code goes here */ - - /* Determine exact type */ - outb_p(LM78_REG_CHIPID,address + LM78_ADDR_REG_OFFSET); - err = inb_p(address + LM78_DATA_REG_OFFSET) & 0xfe; - if (err == 0x00) { - type = lm78; - type_name = "lm78"; - client_name = "LM78 chip"; - } else if (err == 0x40) { - type = lm78j; - type_name = "lm78-j"; - client_name = "LM78-J chip"; - } else if (err == 0xc0) { - type = lm79; - type_name = "lm79"; - client_name = "LM79 chip"; - } else if (err == 0x02) { - printk("lm78.o: Warning: Winbond W83781D detected (treated as a LM79)\n"); - type = lm79; - type_name = "lm79"; - client_name = "LM79 chip"; - } else { -#ifdef DEBUG - printk("lm78.o: warning: probed non-lm78 chip?!? (%x)\n",err); -#endif - continue; - } - - request_region(address, LM78_EXTENT, type_name); - - /* Allocate space for a new client structure */ - if (! (new_client = kmalloc(sizeof(struct isa_client) + - sizeof(struct lm78_data), - GFP_KERNEL))) - { - err=-ENOMEM; - goto ERROR1; - } - - /* Fill the new client structure with data */ - new_client->data = (struct lm78_data *) (new_client + 1); - new_client->addr = 0; - strcpy(new_client->name,client_name); - ((struct lm78_data *) (new_client->data))->type = type; - new_client->isa_addr = address; - if ((err = lm78_new_client((struct i2c_adapter *) adapter, - (struct i2c_client *) new_client))) - goto ERROR2; - - /* Tell i2c-core a new client has arrived */ - if ((err = isa_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((err = sensors_register_entry((struct i2c_client *) new_client, - type_name, - lm78_dir_table_template)) < 0) - goto ERROR4; - ((struct lm78_data *) (new_client->data)) -> sysctl_id = err; - err = 0; - - /* Initialize the LM78 chip */ - lm78_init_client((struct i2c_client *) new_client); - continue; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -ERROR4: - isa_detach_client(new_client); -ERROR3: - lm78_remove_client((struct i2c_client *) new_client); -ERROR2: - kfree(new_client); -ERROR1: - release_region(address, LM78_EXTENT); - } - return err; - -} - -/* Deregister and remove a LM78 client */ -int lm78_detach_isa(struct isa_client *client) -{ - int err,i; - for (i = 0; i < MAX_LM78_NR; i++) - if ((client == (struct isa_client *) (lm78_list[i]))) - break; - if (i == MAX_LM78_NR) { - printk("lm78.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id); - - if ((err = isa_detach_client(client))) { - printk("lm78.o: Client deregistration failed, client not detached.\n"); - return err; - } - lm78_remove_client((struct i2c_client *) client); - release_region(client->isa_addr,LM78_EXTENT); - kfree(client); - return 0; -} - -int lm78_detect_smbus(struct i2c_adapter *adapter) -{ - int address,err; - struct i2c_client *new_client; - enum lm78_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 = 0x20; (! err) && (address <= 0x2f); 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,LM78_REG_CONFIG) < 0) - continue; - - /* Real detection code goes here */ - - /* Determine exact type */ - err = smbus_read_byte_data(adapter,address,LM78_REG_CHIPID) & 0xfe; - if (err == 0x00) { - type = lm78; - type_name = "lm78"; - client_name = "LM78 chip"; - } else if (err == 0x40) { - type = lm78j; - type_name = "lm78-j"; - client_name = "LM78-J chip"; - } else if (err == 0xc0) { - type = lm79; - type_name = "lm79"; - client_name = "LM79 chip"; - } else if (err == 0x02) { - printk("lm78.o: Warning: Winbond W83781D detected (treated as a LM79)\n"); - type = lm79; - type_name = "lm79"; - client_name = "LM79 chip"; - } else { -#ifdef DEBUG - printk("lm78.o: warning: probed non-lm78 chip?!? (%x)\n",err); -#endif - continue; - } - - - /* Allocate space for a new client structure. To counter memory - ragmentation somewhat, we only do one kmalloc. */ - if (! (new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct lm78_data), - GFP_KERNEL))) { - err = -ENOMEM; - continue; - } - - /* Fill the new client structure with data */ - new_client->data = (struct lm78_data *) (new_client + 1); - new_client->addr = address; - strcpy(new_client->name,client_name); - ((struct lm78_data *) (new_client->data))->type = type; - if ((err = lm78_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, - lm78_dir_table_template)) < 0) - goto ERROR4; - ((struct lm78_data *) (new_client->data))->sysctl_id = err; - err = 0; - - /* Initialize the LM78 chip */ - lm78_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: - lm78_remove_client((struct i2c_client *) new_client); -ERROR2: - kfree(new_client); - } - return err; -} - -int lm78_detach_smbus(struct i2c_client *client) -{ - int err,i; - for (i = 0; i < MAX_LM78_NR; i++) - if (client == lm78_list[i]) - break; - if ((i == MAX_LM78_NR)) { - printk("lm78.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("lm78.o: Client deregistration failed, client not detached.\n"); - return err; - } - lm78_remove_client(client); - kfree(client); - return 0; -} - - -/* Find a free slot, and initialize most of the fields */ -int lm78_new_client(struct i2c_adapter *adapter, - struct i2c_client *new_client) -{ - int i; - struct lm78_data *data; - - /* First, seek out an empty slot */ - for(i = 0; i < MAX_LM78_NR; i++) - if (! lm78_list[i]) - break; - if (i == MAX_LM78_NR) { - printk("lm78.o: No empty slots left, recompile and heighten " - "MAX_LM78_NR!\n"); - return -ENOMEM; - } - - lm78_list[i] = new_client; - new_client->id = i; - new_client->adapter = adapter; - new_client->driver = &lm78_driver; - data = new_client->data; - data->valid = 0; - data->lock = MUTEX; - data->update_lock = MUTEX; - return 0; -} - -/* Inverse of lm78_new_client */ -void lm78_remove_client(struct i2c_client *client) -{ - int i; - for (i = 0; i < MAX_LM78_NR; i++) - if (client == lm78_list[i]) - lm78_list[i] = NULL; -} - -/* No commands defined yet */ -int lm78_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void lm78_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void lm78_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - -/* The SMBus locks itself, but ISA access must be locked explicitely! - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -int lm78_read_value(struct i2c_client *client, u8 reg) -{ - int res; - if (i2c_is_isa_client(client)) { - down((struct semaphore *) (client->data)); - outb_p(reg,(((struct isa_client *) client)->isa_addr) + - LM78_ADDR_REG_OFFSET); - res = inb_p((((struct isa_client *) client)->isa_addr) + - LM78_DATA_REG_OFFSET); - up((struct semaphore *) (client->data)); - return res; - } else - return smbus_read_byte_data(client->adapter,client->addr, reg); -} - -/* The SMBus locks itself, but ISA access muse be locked explicitely! - We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM78 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - if (i2c_is_isa_client(client)) { - down((struct semaphore *) (client->data)); - outb_p(reg,((struct isa_client *) client)->isa_addr + LM78_ADDR_REG_OFFSET); - outb_p(value,((struct isa_client *) client)->isa_addr + LM78_DATA_REG_OFFSET); - up((struct semaphore *) (client->data)); - return 0; - } else - return smbus_write_byte_data(client->adapter, client->addr, reg,value); -} - -/* Called when we have found a new LM78. It should set limits, etc. */ -void lm78_init_client(struct i2c_client *client) -{ - int vid; - - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - lm78_write_value(client,LM78_REG_CONFIG,0x80); - - vid = lm78_read_value(client,LM78_REG_VID_FANDIV) & 0x0f; - if (((struct lm78_data *) (client->data))->type == lm79) - vid |= (lm78_read_value(client,LM78_REG_CHIPID) & 0x01) >> 4; - else - vid |= 0x10; - vid = VID_FROM_REG(vid); - - lm78_write_value(client,LM78_REG_IN_MIN(0),IN_TO_REG(LM78_INIT_IN_MIN_0)); - lm78_write_value(client,LM78_REG_IN_MAX(0),IN_TO_REG(LM78_INIT_IN_MAX_0)); - lm78_write_value(client,LM78_REG_IN_MIN(1),IN_TO_REG(LM78_INIT_IN_MIN_1)); - lm78_write_value(client,LM78_REG_IN_MAX(1),IN_TO_REG(LM78_INIT_IN_MAX_1)); - lm78_write_value(client,LM78_REG_IN_MIN(2),IN_TO_REG(LM78_INIT_IN_MIN_2)); - lm78_write_value(client,LM78_REG_IN_MAX(2),IN_TO_REG(LM78_INIT_IN_MAX_2)); - lm78_write_value(client,LM78_REG_IN_MIN(3),IN_TO_REG(LM78_INIT_IN_MIN_3)); - lm78_write_value(client,LM78_REG_IN_MAX(3),IN_TO_REG(LM78_INIT_IN_MAX_3)); - lm78_write_value(client,LM78_REG_IN_MIN(4),IN_TO_REG(LM78_INIT_IN_MIN_4)); - lm78_write_value(client,LM78_REG_IN_MAX(4),IN_TO_REG(LM78_INIT_IN_MAX_4)); - lm78_write_value(client,LM78_REG_IN_MIN(5),IN_TO_REG(LM78_INIT_IN_MIN_5)); - lm78_write_value(client,LM78_REG_IN_MAX(5),IN_TO_REG(LM78_INIT_IN_MAX_5)); - lm78_write_value(client,LM78_REG_IN_MIN(6),IN_TO_REG(LM78_INIT_IN_MIN_6)); - lm78_write_value(client,LM78_REG_IN_MAX(6),IN_TO_REG(LM78_INIT_IN_MAX_6)); - lm78_write_value(client,LM78_REG_FAN_MIN(1), - FAN_TO_REG(LM78_INIT_FAN_MIN_1,2)); - lm78_write_value(client,LM78_REG_FAN_MIN(2), - FAN_TO_REG(LM78_INIT_FAN_MIN_2,2)); - lm78_write_value(client,LM78_REG_FAN_MIN(3), - FAN_TO_REG(LM78_INIT_FAN_MIN_3,2)); - lm78_write_value(client,LM78_REG_TEMP_OVER,TEMP_TO_REG(LM78_INIT_TEMP_OVER)); - lm78_write_value(client,LM78_REG_TEMP_HYST,TEMP_TO_REG(LM78_INIT_TEMP_HYST)); - - /* Start monitoring */ - lm78_write_value(client,LM78_REG_CONFIG, - (lm78_read_value(client,LM78_REG_CONFIG) & 0xf7) | 0x01); - -} - -void lm78_update_client(struct i2c_client *client) -{ - struct lm78_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("Starting lm78 update\n"); -#endif - for (i = 0; i <= 6; i++) { - data->in[i] = lm78_read_value(client,LM78_REG_IN(i)); - data->in_min[i] = lm78_read_value(client,LM78_REG_IN_MIN(i)); - data->in_max[i] = lm78_read_value(client,LM78_REG_IN_MAX(i)); - } - for (i = 1; i <= 3; i++) { - data->fan[i-1] = lm78_read_value(client,LM78_REG_FAN(i)); - data->fan_min[i-1] = lm78_read_value(client,LM78_REG_FAN_MIN(i)); - } - data->temp = lm78_read_value(client,LM78_REG_TEMP); - data->temp_over = lm78_read_value(client,LM78_REG_TEMP_OVER); - data->temp_hyst = lm78_read_value(client,LM78_REG_TEMP_HYST); - i = lm78_read_value(client,LM78_REG_VID_FANDIV); - data->vid = i & 0x0f; - if (data->type == lm79) - data->vid |= (lm78_read_value(client,LM78_REG_CHIPID) & 0x01) >> 4; - else - data->vid |= 0x10; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->alarms = lm78_read_value(client,LM78_REG_ALARM1) + - (lm78_read_value(client,LM78_REG_ALARM2) << 8); - data->last_updated = jiffies; - data->valid = 1; - - data->fan_div[2] = 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 date - 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 lm78_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - int nr = ctl_name - LM78_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr]); - results[1] = IN_FROM_REG(data->in_max[nr]); - results[2] = IN_FROM_REG(data->in[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0]); - lm78_write_value(client,LM78_REG_IN_MIN(nr),data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1]); - lm78_write_value(client,LM78_REG_IN_MAX(nr),data->in_max[nr]); - } - } -} - -void lm78_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - int nr = ctl_name - LM78_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr-1], - DIV_FROM_REG(data->fan_div[nr-1])); - results[1] = FAN_FROM_REG(data->fan[nr-1], - DIV_FROM_REG(data->fan_div[nr-1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr-1] = FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - lm78_write_value(client,LM78_REG_FAN_MIN(nr),data->fan_min[nr-1]); - } - } -} - - -void lm78_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - lm78_write_value(client,LM78_REG_TEMP_OVER,data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - lm78_write_value(client,LM78_REG_TEMP_HYST,data->temp_hyst); - } - } -} - -void lm78_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -void lm78_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm78_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm78_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = 2; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm78_read_value(client,LM78_REG_VID_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); - lm78_write_value(client,LM78_REG_VID_FANDIV,old); - } - } -} - -int lm78_init(void) -{ - int res; - - printk("lm78.o version %s (%s)\n",LM_VERSION,LM_DATE); - lm78_initialized = 0; - - if ((res =i2c_add_driver(&lm78_driver))) { - printk("lm78.o: Driver registration failed, module not inserted.\n"); - lm78_cleanup(); - return res; - } - lm78_initialized ++; - return 0; -} - -int lm78_cleanup(void) -{ - int res; - - if (lm78_initialized >= 1) { - if ((res = i2c_del_driver(&lm78_driver))) { - printk("lm78.o: Driver deregistration failed, module not removed.\n"); - return res; - } - lm78_initialized --; - } - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); - -int init_module(void) -{ - return lm78_init(); -} - -int cleanup_module(void) -{ - return lm78_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/lm80.c b/src/lm80.c deleted file mode 100644 index 97644aa9..00000000 --- a/src/lm80.c +++ /dev/null @@ -1,689 +0,0 @@ -/* - lm80.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - and Philip Edelbrock - - 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 -#include -#include -#include -#include -#include -#include -#include -#include "smbus.h" -#include "version.h" -#include "isa.h" -#include "sensors.h" -#include "i2c.h" -#include "compat.h" - -/* Many LM80 constants specified below */ - -/* The LM80 registers */ -#define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2) -#define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) -#define LM80_REG_IN(nr) (0x20 + (nr)) - -#define LM80_REG_FAN1_MIN 0x3c -#define LM80_REG_FAN2_MIN 0x3d -#define LM80_REG_FAN1 0x28 -#define LM80_REG_FAN2 0x29 - -#define LM80_REG_TEMP 0x27 -#define LM80_REG_TEMP_HOT_MAX 0x38 -#define LM80_REG_TEMP_HOT_HYST 0x39 -#define LM80_REG_TEMP_OS_MAX 0x3a -#define LM80_REG_TEMP_OS_HYST 0x3b - -#define LM80_REG_CONFIG 0x00 -#define LM80_REG_ALARM1 0x01 -#define LM80_REG_ALARM2 0x02 -#define LM80_REG_MASK1 0x03 -#define LM80_REG_MASK2 0x04 -#define LM80_REG_FANDIV 0x05 -#define LM80_REG_RES 0x06 - - -/* Conversions. Rounding is only done on the TO_REG variants. */ -#define IN_TO_REG(val,nr) ((val) & 0xff) -#define IN_FROM_REG(val,nr) (val) - -#define FAN_TO_REG(val,div) ((val)==0?255:\ - ((1350000+(val)*(div)/2)/((val)*(div))) & 0xff) -#define FAN_FROM_REG(val,div) ((val)==0?-1:\ - (val)==255?0:1350000/((div)*(val))) - -#define TEMP_FROM_REG(val) lm80_temp_from_reg(val) - -#define TEMP_LIMIT_TO_REG(val) (((val)<0?(((val)-50)/100)&0xff:\ - ((val)+50)/100) & 0xff) -#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*100) - -#define ALARMS_FROM_REG(val) (val) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -/* Initial limits */ -#define LM80_INIT_IN_0 190 -#define LM80_INIT_IN_1 190 -#define LM80_INIT_IN_2 190 -#define LM80_INIT_IN_3 190 -#define LM80_INIT_IN_4 190 -#define LM80_INIT_IN_5 190 -#define LM80_INIT_IN_6 190 - -#define LM80_INIT_IN_PERCENTAGE 10 - -#define LM80_INIT_IN_MIN_0 \ - (LM80_INIT_IN_0 - LM80_INIT_IN_0 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MAX_0 \ - (LM80_INIT_IN_0 + LM80_INIT_IN_0 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MIN_1 \ - (LM80_INIT_IN_1 - LM80_INIT_IN_1 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MAX_1 \ - (LM80_INIT_IN_1 + LM80_INIT_IN_1 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MIN_2 \ - (LM80_INIT_IN_2 - LM80_INIT_IN_2 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MAX_2 \ - (LM80_INIT_IN_2 + LM80_INIT_IN_2 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MIN_3 \ - (LM80_INIT_IN_3 - LM80_INIT_IN_3 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MAX_3 \ - (LM80_INIT_IN_3 + LM80_INIT_IN_3 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MIN_4 \ - (LM80_INIT_IN_4 - LM80_INIT_IN_4 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MAX_4 \ - (LM80_INIT_IN_4 + LM80_INIT_IN_4 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MIN_5 \ - (LM80_INIT_IN_5 - LM80_INIT_IN_5 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MAX_5 \ - (LM80_INIT_IN_5 + LM80_INIT_IN_5 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MIN_6 \ - (LM80_INIT_IN_6 - LM80_INIT_IN_6 * LM80_INIT_IN_PERCENTAGE / 100) -#define LM80_INIT_IN_MAX_6 \ - (LM80_INIT_IN_6 + LM80_INIT_IN_6 * LM80_INIT_IN_PERCENTAGE / 100) - -#define LM80_INIT_FAN_MIN_1 3000 -#define LM80_INIT_FAN_MIN_2 3000 - -#define LM80_INIT_TEMP_OS_MAX 600 -#define LM80_INIT_TEMP_OS_HYST 500 -#define LM80_INIT_TEMP_HOT_MAX 700 -#define LM80_INIT_TEMP_HOT_HYST 600 - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -/* For each registered LM80, we need to keep some data in memory. That - data is pointed to by lm80_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new lm80 client is - allocated. */ -struct lm80_data { - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ - u8 fan_div[2]; /* Register encoding, shifted right */ - u16 temp; /* Register values, shifted right */ - u8 temp_hot_max; /* Register value */ - u8 temp_hot_hyst; /* Register value */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ - u16 alarms; /* Register encoding, combined */ -}; - - -static int lm80_init(void); -static int lm80_cleanup(void); - -static int lm80_attach_adapter(struct i2c_adapter *adapter); -static int lm80_detach_client(struct i2c_client *client); -static int lm80_new_client(struct i2c_adapter *adapter, - struct i2c_client *new_client); -static void lm80_remove_client(struct i2c_client *client); -static int lm80_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void lm80_inc_use (struct i2c_client *client); -static void lm80_dec_use (struct i2c_client *client); - -static long lm80_temp_from_reg(u16 regs); - -static int lm80_read_value(struct i2c_client *client, u8 register); -static int lm80_write_value(struct i2c_client *client, u8 register, u8 value); -static void lm80_update_client(struct i2c_client *client); -static void lm80_init_client(struct i2c_client *client); - - -static void lm80_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm80_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm80_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm80_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); - -/* I choose here for semi-static LM80 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_LM80_NR 4 -static struct i2c_client *lm80_list[MAX_LM80_NR]; - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver lm80_driver = { - /* name */ "LM80 sensor driver", - /* id */ I2C_DRIVERID_LM80, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &lm80_attach_adapter, - /* detach_client */ &lm80_detach_client, - /* command */ &lm80_command, - /* inc_use */ &lm80_inc_use, - /* dec_use */ &lm80_dec_use -}; - -/* Used by lm80_init/cleanup */ -static int lm80_initialized = 0; - -/* The /proc/sys entries */ -/* These files are created for each detected LM80. 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 lm80_dir_table_template[] = { - { LM80_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_in }, - { LM80_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_in }, - { LM80_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_in }, - { LM80_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_in }, - { LM80_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_in }, - { LM80_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_in }, - { LM80_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_in }, - { LM80_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_fan }, - { LM80_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_fan }, - { LM80_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_temp }, - { LM80_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_fan_div }, - { LM80_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_alarms }, - { 0 } -}; - - -int lm80_attach_adapter(struct i2c_adapter *adapter) -{ - int address,err; - struct i2c_client *new_client; - const char *type_name,*client_name; - - /* OK, this is no detection. I know. It will do for now, though. */ - err = 0; - for (address = 0x20; (! err) && (address <= 0x2f); 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,LM80_REG_CONFIG) < 0) - continue; - - /* Real detection code goes here */ - - printk("lm80.o: LM80 detected\n"); - type_name = "lm80"; - client_name = "LM80 chip"; - - - /* 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 lm80_data), - GFP_KERNEL))) { - err = -ENOMEM; - continue; - } - - /* Fill the new client structure with data */ - new_client->data = (struct lm80_data *) (new_client + 1); - new_client->addr = address; - strcpy(new_client->name,client_name); - if ((err = lm80_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, - lm80_dir_table_template)) < 0) - goto ERROR4; - ((struct lm80_data *) (new_client->data))->sysctl_id = err; - err = 0; - - /* Initialize the LM80 chip */ - lm80_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: - lm80_remove_client((struct i2c_client *) new_client); -ERROR2: - kfree(new_client); - } - return err; -} - -int lm80_detach_client(struct i2c_client *client) -{ - int err,i; - for (i = 0; i < MAX_LM80_NR; i++) - if (client == lm80_list[i]) - break; - if ((i == MAX_LM80_NR)) { - printk("lm80.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct lm80_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("lm80.o: Client deregistration failed, client not detached.\n"); - return err; - } - lm80_remove_client(client); - kfree(client); - return 0; -} - - -/* Find a free slot, and initialize most of the fields */ -int lm80_new_client(struct i2c_adapter *adapter, - struct i2c_client *new_client) -{ - int i; - struct lm80_data *data; - - /* First, seek out an empty slot */ - for(i = 0; i < MAX_LM80_NR; i++) - if (! lm80_list[i]) - break; - if (i == MAX_LM80_NR) { - printk("lm80.o: No empty slots left, recompile and heighten " - "MAX_LM80_NR!\n"); - return -ENOMEM; - } - - lm80_list[i] = new_client; - new_client->id = i; - new_client->adapter = adapter; - new_client->driver = &lm80_driver; - data = new_client->data; - data->valid = 0; - data->update_lock = MUTEX; - return 0; -} - -/* Inverse of lm80_new_client */ -void lm80_remove_client(struct i2c_client *client) -{ - int i; - for (i = 0; i < MAX_LM80_NR; i++) - if (client == lm80_list[i]) - lm80_list[i] = NULL; -} - -/* No commands defined yet */ -int lm80_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void lm80_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void lm80_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - -long lm80_temp_from_reg(u16 temp) -{ - long res; - res = ((temp & 0xff00) >> 8) * 10000 + ((temp & 0x10) >> 4) * 5000 + - ((temp & 0x20) >> 5) * 2500 + ((temp & 0x40) >> 6) * 1250 + - ((temp & 0x80) >> 7) * 625; - temp /= 100; - if (temp >= 0x80 * 100) - temp = - (0x100 * 100 - temp); - return temp; -} - -int lm80_read_value(struct i2c_client *client, u8 reg) -{ - return smbus_read_byte_data(client->adapter,client->addr, reg); -} - -int lm80_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 LM80. It should set limits, etc. */ -void lm80_init_client(struct i2c_client *client) -{ - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others. This makes most other - initializations unnecessary */ - lm80_write_value(client,LM80_REG_CONFIG,0x80); - /* Set 11-bit temperature resolution */ - lm80_write_value(client,LM80_REG_RES,0x08); - - lm80_write_value(client,LM80_REG_IN_MIN(0),IN_TO_REG(LM80_INIT_IN_MIN_0,0)); - lm80_write_value(client,LM80_REG_IN_MAX(0),IN_TO_REG(LM80_INIT_IN_MAX_0,0)); - lm80_write_value(client,LM80_REG_IN_MIN(1),IN_TO_REG(LM80_INIT_IN_MIN_1,1)); - lm80_write_value(client,LM80_REG_IN_MAX(1),IN_TO_REG(LM80_INIT_IN_MAX_1,1)); - lm80_write_value(client,LM80_REG_IN_MIN(2),IN_TO_REG(LM80_INIT_IN_MIN_2,2)); - lm80_write_value(client,LM80_REG_IN_MAX(2),IN_TO_REG(LM80_INIT_IN_MAX_2,2)); - lm80_write_value(client,LM80_REG_IN_MIN(3),IN_TO_REG(LM80_INIT_IN_MIN_3,3)); - lm80_write_value(client,LM80_REG_IN_MAX(3),IN_TO_REG(LM80_INIT_IN_MAX_3,3)); - lm80_write_value(client,LM80_REG_IN_MIN(4),IN_TO_REG(LM80_INIT_IN_MIN_4,4)); - lm80_write_value(client,LM80_REG_IN_MAX(4),IN_TO_REG(LM80_INIT_IN_MAX_4,4)); - lm80_write_value(client,LM80_REG_IN_MIN(5),IN_TO_REG(LM80_INIT_IN_MIN_5,5)); - lm80_write_value(client,LM80_REG_IN_MAX(5),IN_TO_REG(LM80_INIT_IN_MAX_5,5)); - lm80_write_value(client,LM80_REG_IN_MIN(6),IN_TO_REG(LM80_INIT_IN_MIN_6,6)); - lm80_write_value(client,LM80_REG_IN_MAX(6),IN_TO_REG(LM80_INIT_IN_MAX_6,6)); - lm80_write_value(client,LM80_REG_FAN1_MIN,FAN_TO_REG(LM80_INIT_FAN_MIN_1,2)); - lm80_write_value(client,LM80_REG_FAN2_MIN,FAN_TO_REG(LM80_INIT_FAN_MIN_2,2)); - lm80_write_value(client,LM80_REG_TEMP_HOT_MAX, - TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_MAX)); - lm80_write_value(client,LM80_REG_TEMP_HOT_HYST, - TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_HYST)); - lm80_write_value(client,LM80_REG_TEMP_OS_MAX, - TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_MAX)); - lm80_write_value(client,LM80_REG_TEMP_OS_HYST, - TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_HYST)); - - /* Start monitoring */ - lm80_write_value(client,LM80_REG_CONFIG,0x01); -} - -void lm80_update_client(struct i2c_client *client) -{ - struct lm80_data *data = client->data; - int i; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > 2*HZ ) || - (jiffies < data->last_updated) || ! data->valid) { - -#ifdef DEBUG - printk("Starting lm80 update\n"); -#endif - for (i = 0; i <= 6; i++) { - data->in[i] = lm80_read_value(client,LM80_REG_IN(i)); - data->in_min[i] = lm80_read_value(client,LM80_REG_IN_MIN(i)); - data->in_max[i] = lm80_read_value(client,LM80_REG_IN_MAX(i)); - } - data->fan[0] = lm80_read_value(client,LM80_REG_FAN1); - data->fan_min[0] = lm80_read_value(client,LM80_REG_FAN1_MIN); - data->fan[1] = lm80_read_value(client,LM80_REG_FAN2); - data->fan_min[1] = lm80_read_value(client,LM80_REG_FAN2_MIN); - - data->temp = (lm80_read_value(client,LM80_REG_TEMP) << 8) | - (lm80_read_value(client,LM80_REG_RES) & 0xf0); - data->temp_os_max = lm80_read_value(client,LM80_REG_TEMP_OS_MAX); - data->temp_os_hyst = lm80_read_value(client,LM80_REG_TEMP_OS_HYST); - data->temp_hot_max = lm80_read_value(client,LM80_REG_TEMP_HOT_MAX); - data->temp_hot_hyst = lm80_read_value(client,LM80_REG_TEMP_HOT_HYST); - - i = lm80_read_value(client,LM80_REG_FANDIV); - data->fan_div[0] = (i >> 2) & 0x03; - data->fan_div[1] = (i >> 4) & 0x03; - data->alarms = lm80_read_value(client,LM80_REG_ALARM1) + - (lm80_read_value(client,LM80_REG_ALARM2) << 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 date - 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 lm80_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - int nr = ctl_name - LM80_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr],nr); - results[1] = IN_FROM_REG(data->in_max[nr],nr); - results[2] = IN_FROM_REG(data->in[nr],nr); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0],nr); - lm80_write_value(client,LM80_REG_IN_MIN(nr),data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1],nr); - lm80_write_value(client,LM80_REG_IN_MAX(nr),data->in_max[nr]); - } - } -} - -void lm80_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - int nr = ctl_name - LM80_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr-1], - DIV_FROM_REG(data->fan_div[nr-1])); - results[1] = FAN_FROM_REG(data->fan[nr-1], - DIV_FROM_REG(data->fan_div[nr-1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr-1] = FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - lm80_write_value(client,nr==1?LM80_REG_FAN1_MIN:LM80_REG_FAN2_MIN, - data->fan_min[nr-1]); - } - } -} - - -void lm80_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = TEMP_LIMIT_FROM_REG(data->temp_hot_max); - results[1] = TEMP_LIMIT_FROM_REG(data->temp_hot_hyst); - results[2] = TEMP_LIMIT_FROM_REG(data->temp_os_max); - results[3] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); - results[4] = TEMP_FROM_REG(data->temp); - *nrels_mag = 5; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_hot_max = TEMP_LIMIT_TO_REG(results[0]); - lm80_write_value(client,LM80_REG_TEMP_HOT_MAX,data->temp_hot_max); - } - if (*nrels_mag >= 2) { - data->temp_hot_hyst = TEMP_LIMIT_TO_REG(results[1]); - lm80_write_value(client,LM80_REG_TEMP_HOT_HYST,data->temp_hot_hyst); - } - if (*nrels_mag >= 3) { - data->temp_os_max = TEMP_LIMIT_TO_REG(results[2]); - lm80_write_value(client,LM80_REG_TEMP_OS_MAX,data->temp_os_max); - } - if (*nrels_mag >= 4) { - data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[3]); - lm80_write_value(client,LM80_REG_TEMP_OS_HYST,data->temp_os_hyst); - } - } -} - -void lm80_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = 2; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm80_read_value(client,LM80_REG_FANDIV); - if (*nrels_mag >= 2) { - data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0xcf) | (data->fan_div[1] << 4); - } - if (*nrels_mag >= 1) { - data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xf3) | (data->fan_div[0] << 2); - lm80_write_value(client,LM80_REG_FANDIV,old); - } - } -} - -int lm80_init(void) -{ - int res; - - printk("lm80.o version %s (%s)\n",LM_VERSION,LM_DATE); - lm80_initialized = 0; - - if ((res =i2c_add_driver(&lm80_driver))) { - printk("lm80.o: Driver registration failed, module not inserted.\n"); - lm80_cleanup(); - return res; - } - lm80_initialized ++; - return 0; -} - -int lm80_cleanup(void) -{ - int res; - - if (lm80_initialized >= 1) { - if ((res = i2c_del_driver(&lm80_driver))) { - printk("lm80.o: Driver deregistration failed, module not removed.\n"); - return res; - } - lm80_initialized --; - } - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("LM80 driver"); - -int init_module(void) -{ - return lm80_init(); -} - -int cleanup_module(void) -{ - return lm80_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/ltc1710.c b/src/ltc1710.c deleted file mode 100644 index 446c7b38..00000000 --- a/src/ltc1710.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - ltc1710.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1999 Frodo Looijaard and - Philip Edelbrock - - 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. -*/ - -/* A few notes about the LTC1710: - -* The LTC1710 is a dual programmable switch. It can be used to turn - anything on or off anything which consumes less than 300mA of - current and up to 5.5V - -* The LTC1710 is a very, very simple SMBus device with three possible - SMBus addresses (0x58,0x59, or 0x5A). Only SMBus byte writes - (command writes) are supported. - -* Since only writes are supported, READS DON'T WORK! The device - plays dead in the event of a read, so this makes detection a - bit tricky. - -* BTW- I can safely say that this driver has been tested under - every possible case, so there should be no bugs. :') - - --Phil - -*/ - - -#include -#include -#include "smbus.h" -#include "sensors.h" -#include "i2c.h" -#include "version.h" - - -/* The LTC1710 registers */ - -/* (No registers. [Wow! This thing is SIMPLE!] ) */ - -/* Initial values */ -#define LTC1710_INIT 0 /* Both off */ - -/* Each client has this additional data */ -struct ltc1710_data { - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u8 status; /* Register values */ -}; - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static int ltc1710_init(void); -static int ltc1710_cleanup(void); -static int ltc1710_attach_adapter(struct i2c_adapter *adapter); -static int ltc1710_detach_client(struct i2c_client *client); -static int ltc1710_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void ltc1710_inc_use (struct i2c_client *client); -static void ltc1710_dec_use (struct i2c_client *client); -static u16 swap_bytes(u16 val); -static void ltc1710_switch1(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void ltc1710_switch2(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void ltc1710_update_client(struct i2c_client *client); - - -/* This is the driver that will be inserted */ -static struct i2c_driver ltc1710_driver = { - /* name */ "LTC1710 sensor chip driver", - /* id */ I2C_DRIVERID_LTC1710, - /* flags */ DF_NOTIFY, - /* attach_adapter */ <c1710_attach_adapter, - /* detach_client */ <c1710_detach_client, - /* command */ <c1710_command, - /* inc_use */ <c1710_inc_use, - /* dec_use */ <c1710_dec_use -}; - -/* These files are created for each detected LTC1710. 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 ltc1710_dir_table_template[] = { - { LTC1710_SYSCTL_SWITCH_1, "switch1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, <c1710_switch1 }, - { LTC1710_SYSCTL_SWITCH_2, "switch2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, <c1710_switch2 }, - { 0 } -}; - -/* Used by init/cleanup */ -static int ltc1710_initialized = 0; - -/* I choose here for semi-static LM78 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_LTC1710_NR 3 -static struct i2c_client *ltc1710_list[MAX_LTC1710_NR]; - - -int ltc1710_attach_adapter(struct i2c_adapter *adapter) -{ - int address,err,i; - struct i2c_client *new_client; - struct ltc1710_data *data; - - err = 0; - - /* OK, this is no detection. I know. It will do for now, though. */ - - /* Set err only if a global error would make registering other clients - impossible too (like out-of-memory). */ - for (address = 0x58; (! err) && (address <= 0x5A); address ++) { - - /* Later on, we will keep a list of registered addresses for each - adapter, and check whether they are used here */ - - /* We must do a write to test because a read fails! */ - if (smbus_write_byte(adapter,address,0) < 0) - continue; - - /* There is no real detection possible, the device is too simple. */ - - /* Allocate space for a new client structure */ - if (! (new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct ltc1710_data), - GFP_KERNEL))) { - err = -ENOMEM; - continue; - } - - /* Find a place in our global list */ - for (i = 0; i < MAX_LTC1710_NR; i++) - if (! ltc1710_list[i]) - break; - if (i == MAX_LTC1710_NR) { - err = -ENOMEM; - printk("ltc1710.o: No empty slots left, recompile and heighten " - "MAX_LTC1710_NR!\n"); - goto ERROR1; - } - ltc1710_list[i] = new_client; - - /* Fill the new client structure with data */ - data = (struct ltc1710_data *) (new_client + 1); - new_client->data = data; - new_client->id = i; - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = <c1710_driver; - strcpy(new_client->name,"LTC1710 chip"); - data->valid = 0; - data->update_lock = MUTEX; - - /* Tell i2c-core a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR2; - - /* Register a new directory entry with module sensors */ - if ((err = sensors_register_entry(new_client,"ltc1710", - ltc1710_dir_table_template)) < 0) - goto ERROR3; - data->sysctl_id = err; - err = 0; - continue; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -ERROR3: - i2c_detach_client(new_client); -ERROR2: - ltc1710_list[i] = NULL; -ERROR1: - kfree(new_client); - } - return err; -} - -int ltc1710_detach_client(struct i2c_client *client) -{ - int err,i; - for (i = 0; i < MAX_LTC1710_NR; i++) - if (client == ltc1710_list[i]) - break; - if ((i == MAX_LTC1710_NR)) { - printk("ltc1710.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct ltc1710_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("ltc1710.o: Client deregistration failed, client not detached.\n"); - return err; - } - - ltc1710_list[i] = NULL; - kfree(client); - return 0; -} - - -/* No commands defined yet */ -int ltc1710_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -/* Nothing here yet */ -void ltc1710_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -/* Nothing here yet */ -void ltc1710_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - -void ltc1710_update_client(struct i2c_client *client) -{ - struct ltc1710_data *data = client->data; - - down(&data->update_lock); - - if ((jiffies - data->last_updated > HZ+HZ/2 ) || - (jiffies < data->last_updated) || ! data->valid) { - -#ifdef DEBUG - printk("Starting ltc1710 update\n"); -#endif - - /* data->status = smbus_read_byte(client->adapter,client->addr); - Unfortunately, reads always fail! */ - data->last_updated = jiffies; - data->valid = 1; - } - - up(&data->update_lock); -} - - -void ltc1710_switch1(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ltc1710_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ltc1710_update_client(client); - results[0] = data->status & 1; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->status = (data->status & 2) | results[0]; - smbus_write_byte(client->adapter,client->addr,data->status); - } - } -} - -void ltc1710_switch2(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct ltc1710_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - ltc1710_update_client(client); - results[0] = (data->status & 2) >> 1; - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->status = (data->status & 1) | (results[0] << 1); - smbus_write_byte(client->adapter,client->addr,data->status); - } - } -} - -int ltc1710_init(void) -{ - int res; - - printk("ltc1710.o version %s (%s)\n",LM_VERSION,LM_DATE); - ltc1710_initialized = 0; - if ((res = i2c_add_driver(<c1710_driver))) { - printk("ltc1710.o: Driver registration failed, module not inserted.\n"); - ltc1710_cleanup(); - return res; - } - ltc1710_initialized ++; - return 0; -} - -int ltc1710_cleanup(void) -{ - int res; - - if (ltc1710_initialized >= 1) { - if ((res = i2c_del_driver(<c1710_driver))) { - printk("ltc1710.o: Driver deregistration failed, module not removed.\n"); - return res; - } - ltc1710_initialized --; - } - - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("LTC1710 driver"); - -int init_module(void) -{ - return ltc1710_init(); -} - -int cleanup_module(void) -{ - return ltc1710_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/piix4.c b/src/piix4.c deleted file mode 100644 index 592b6929..00000000 --- a/src/piix4.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - piix4.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard and - Philip Edelbrock - - 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. -*/ - -/* Note: we assume there can only be one PIIX4, with one SMBus interface */ - -#include -#include -#include -#include -#include -#include -#include -#include "smbus.h" -#include "version.h" -#include "compat.h" - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54)) -#include -#endif - - -/* PIIX4 SMBus address offsets */ -#define SMBHSTSTS (0 + piix4_smba) -#define SMBHSLVSTS (1 + piix4_smba) -#define SMBHSTCNT (2 + piix4_smba) -#define SMBHSTCMD (3 + piix4_smba) -#define SMBHSTADD (4 + piix4_smba) -#define SMBHSTDAT0 (5 + piix4_smba) -#define SMBHSTDAT1 (6 + piix4_smba) -#define SMBBLKDAT (7 + piix4_smba) -#define SMBSLVCNT (8 + piix4_smba) -#define SMBSHDWCMD (9 + piix4_smba) -#define SMBSLVEVT (0xA + piix4_smba) -#define SMBSLVDAT (0xC + piix4_smba) - -/* PCI Address Constants */ -#define SMBBA 0x090 -#define SMBHSTCFG 0x0D2 -#define SMBSLVC 0x0D3 -#define SMBSHDW1 0x0D4 -#define SMBSHDW2 0x0D5 -#define SMBREV 0x0D6 - -/* Other settings */ -#define MAX_TIMEOUT 500 -#define ENABLE_INT9 0 - -/* PIIX4 constants */ -#define PIIX4_QUICK 0x00 -#define PIIX4_BYTE 0x04 -#define PIIX4_BYTE_DATA 0x08 -#define PIIX4_WORD_DATA 0x0C -#define PIIX4_BLOCK_DATA 0x14 - - -static int piix4_init(void); -static int piix4_cleanup(void); -static int piix4_setup(void); -static s32 piix4_access(u8 addr, char read_write, - u8 command, int size, union smbus_data * data); -static void piix4_do_pause( unsigned int amount ); -static int piix4_transaction(void); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static struct smbus_adapter piix4_adapter; -static int piix4_initialized; -static unsigned short piix4_smba = 0; - - -/* Detect whether a PIIX4 can be found, and initialize it, where necessary. - Note the differences between kernels with the old PCI BIOS interface and - newer kernels with the real PCI interface. In compat.h some things are - defined to make the transition easier. */ -int piix4_setup(void) -{ - int error_return=0; - unsigned char temp; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54)) - struct pci_dev *PIIX4_dev; -#else - unsigned char PIIX4_bus, PIIX4_devfn; - int i,res; -#endif - - /* First check whether we can access PCI at all */ - if (pci_present() == 0) { - printk("piix4.o: Error: No PCI-bus found!\n"); - error_return=-ENODEV; - goto END; - } - - /* Look for the PIIX4, function 3 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54)) - /* Note: we keep on searching until we have found 'function 3' */ - PIIX4_dev = NULL; - do - PIIX4_dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, PIIX4_dev); - while(PIIX4_dev && (PCI_FUNC(PIIX4_dev->devfn) != 3)); - if(PIIX4_dev == NULL) { -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54) */ - for (i = 0; - ! (res = pcibios_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, - i,&PIIX4_bus, &PIIX4_devfn)) && - PCI_FUNC(PIIX4_devfn) != 3; - i++); - - if (res) { -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54) */ - printk("piix4.o: Error: Can't detect PIIX4, function 3!\n"); - error_return=-ENODEV; - goto END; - } - -/* Determine the address of the SMBus areas */ - pci_read_config_word_united(PIIX4_dev, PIIX4_bus ,PIIX4_devfn, - SMBBA,&piix4_smba); - piix4_smba &= 0xfff0; - - if (check_region(piix4_smba, 8)) { - printk("piix4.o: PIIX4_smb region 0x%x already in use!\n", piix4_smba); - error_return=-ENODEV; - goto END; - } - - pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn, - SMBHSTCFG, &temp); - - -#ifdef FORCE_PIIX4_ENABLE -/* This should never need to be done, but has been noted that - many Dell machines have the SMBus interface on the PIIX4 - disabled!? NOTE: This assumes I/O space and other allocations WERE - done by the Bios! Don't complain if your hardware does weird - things after enabling this. :') Check for Bios updates before - resorting to this. */ - if ((temp & 1) == 0) { - pci_write_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn, - SMBHSTCFG, temp | 1); - printk("piix4.0: WARNING: PIIX4 SMBus interface has been FORCEFULLY " - "ENABLED!!\n"); - /* Update configuration value */ - pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn, - SMBHSTCFG, &temp); - /* Note: We test the bit again in the next 'if' just to be sure... */ - } -#endif /* FORCE_PIIX4_ENABLE */ - - if ((temp & 1) == 0) { - printk("SMBUS: Error: Host SMBus controller not enabled!\n"); - error_return=-ENODEV; - goto END; - } - - /* Everything is happy, let's grab the memory and set things up. */ - request_region(piix4_smba, 8, "piix4"); - -#ifdef DEBUG - if ((temp & 0x0E) == 8) - printk("piix4.o: PIIX4 using Interrupt 9 for SMBus.\n"); - else if ((temp & 0x0E) == 0) - printk("piix4.o: PIIX4 using Interrupt SMI# for SMBus.\n"); - else - printk("piix4.o: PIIX4: Illegal Interrupt configuration (or code out " - "of date)!\n"); - - pci_read_config_byte_united(PIIX4_dev, PIIX4_bus, PIIX4_devfn, SMBREV, - &temp); - printk("piix4.o: SMBREV = 0x%X\n",temp); - printk("piix4.o: PIIX4_smba = 0x%X\n",piix4_smba); -#endif /* DEBUG */ - -END: - return error_return; -} - - -/* Internally used pause function */ -void piix4_do_pause( unsigned int amount ) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(amount); -} - -/* Another internally used function */ -int piix4_transaction(void) -{ - int temp; - int result=0; - int timeout=0; - -#ifdef DEBUG - printk("piix4.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, " - "DAT1=%02x\n", - inb_p(SMBHSTCNT),inb_p(SMBHSTCMD),inb_p(SMBHSTADD),inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); -#endif - - /* Make sure the SMBus host is ready to start transmitting */ - if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk("piix4.o: SMBus busy (%02x). Resetting... \n",temp); -#endif - outb_p(temp, SMBHSTSTS); - if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk("piix4.o: Failed! (%02x)\n",temp); -#endif - return -1; - } else { -#ifdef DEBUG - printk("piix4.o: Successfull!\n"); -#endif - } - } - - /* start the transaction by setting bit 6 */ - outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); - - /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */ - do { - piix4_do_pause(1); - temp=inb_p(SMBHSTSTS); - } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT)); - - /* If the SMBus is still busy, we give up */ - if (timeout >= MAX_TIMEOUT) { -#ifdef DEBUG - printk("piix4.o: SMBus Timeout!\n"); - result = -1; -#endif - } - - if (temp & 0x10) { - result = -1; -#ifdef DEBUG - printk("piix4.o: Error: Failed bus transaction\n"); -#endif - } - - if (temp & 0x08) { - result = -1; - printk("piix4.o: Bus collision! SMBus may be locked until next hard - reset. (sorry!)\n"); - /* Clock stops and slave is stuck in mid-transmission */ - } - - if (temp & 0x04) { - result = -1; -#ifdef DEBUG - printk("piix4.o: Error: no response!\n"); -#endif - } - - if (inb_p(SMBHSTSTS) != 0x00) - outb_p( inb(SMBHSTSTS), SMBHSTSTS); - - if ((temp = inb_p(SMBHSTSTS)) != 0x00) { -#ifdef DEBUG - printk("piix4.o: Failed reset at end of transaction (%02x)\n",temp); -#endif - } -#ifdef DEBUG - printk("piix4.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, " - "DAT0=%02x, DAT1=%02x\n", - inb_p(SMBHSTCNT),inb_p(SMBHSTCMD),inb_p(SMBHSTADD),inb_p(SMBHSTDAT0), - inb_p(SMBHSTDAT1)); -#endif - return result; -} - -/* Return -1 on error. See smbus.h for more information */ -s32 piix4_access(u8 addr, char read_write, - u8 command, int size, union smbus_data * data) -{ - int i,len; - - switch(size) { - case SMBUS_PROC_CALL: - printk("piix4.o: SMBUS_PROC_CALL not supported!\n"); - return -1; - case SMBUS_QUICK: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - size = PIIX4_QUICK; - break; - case SMBUS_BYTE: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - if (read_write == SMBUS_WRITE) - outb_p(command, SMBHSTCMD); - size = PIIX4_BYTE; - break; - case SMBUS_BYTE_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == SMBUS_WRITE) - outb_p(data->byte,SMBHSTDAT0); - size = PIIX4_BYTE_DATA; - break; - case SMBUS_WORD_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == SMBUS_WRITE) { - outb_p(data->word & 0xff,SMBHSTDAT0); - outb_p((data->word & 0xff00) >> 8,SMBHSTDAT1); - } - size = PIIX4_WORD_DATA; - break; - case SMBUS_BLOCK_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); - outb_p(command, SMBHSTCMD); - if (read_write == SMBUS_WRITE) { - len = data->block[0]; - if (len < 0) - len = 0; - if (len > 32) - len = 32; - outb_p(len,SMBHSTDAT0); - i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= len; i ++) - outb_p(data->block[i],SMBBLKDAT); - } - size = PIIX4_BLOCK_DATA; - break; - } - - outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); - - if (piix4_transaction()) /* Error in transaction */ - return -1; - - if ((read_write == SMBUS_WRITE) || (size == PIIX4_QUICK)) - return 0; - - - switch(size) { - case PIIX4_BYTE: /* Where is the result put? I assume here it is in - SMBHSTDAT0 but it might just as well be in the - SMBHSTCMD. No clue in the docs */ - - data->byte = inb_p(SMBHSTDAT0); - break; - case PIIX4_BYTE_DATA: - data->byte = inb_p(SMBHSTDAT0); - break; - case PIIX4_WORD_DATA: - data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); - break; - case PIIX4_BLOCK_DATA: - data->block[0] = inb_p(SMBHSTDAT0); - i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ - for (i = 1; i <= data->block[0]; i++) - data->block[i] = inb_p(SMBBLKDAT); - break; - } - return 0; -} - - -int piix4_init(void) -{ - int res; - printk("piix4.o version %s (%s)\n",LM_VERSION,LM_DATE); -#ifdef DEBUG -/* PE- It might be good to make this a permanent part of the code! */ - if (piix4_initialized) { - printk("piix4.o: Oops, piix4_init called a second time!\n"); - return -EBUSY; - } -#endif - piix4_initialized = 0; - if ((res = piix4_setup())) { - printk("piix4.o: PIIX4 not detected, module not inserted.\n"); - piix4_cleanup(); - return res; - } - piix4_initialized ++; - sprintf(piix4_adapter.name,"SMBus PIIX4 adapter at %04x",piix4_smba); - piix4_adapter.id = ALGO_SMBUS | SMBUS_PIIX4; - piix4_adapter.algo = &smbus_algorithm; - piix4_adapter.smbus_access = &piix4_access; - if ((res = smbus_add_adapter(&piix4_adapter))) { - printk("piix4.o: Adapter registration failed, module not inserted.\n"); - piix4_cleanup(); - return res; - } - piix4_initialized++; - printk("piix4.o: PIIX4 bus detected and initialized\n"); - return 0; -} - -int piix4_cleanup(void) -{ - int res; - if (piix4_initialized >= 2) - { - if ((res = smbus_del_adapter(&piix4_adapter))) { - printk("piix4.o: smbus_del_adapter failed, module not removed\n"); - return res; - } else - piix4_initialized--; - } - if (piix4_initialized >= 1) { - release_region(piix4_smba, 8); - piix4_initialized--; - } - return 0; -} - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("PIIX4 SMBus driver"); - -int init_module(void) -{ - return piix4_init(); -} - -int cleanup_module(void) -{ - return piix4_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/sensors.c b/src/sensors.c deleted file mode 100644 index 2823810b..00000000 --- a/src/sensors.c +++ /dev/null @@ -1,617 +0,0 @@ -/* - sensors.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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 -#include -#include -#include -#include - -#include "version.h" -#include "compat.h" -#include "i2c.h" -#include "isa.h" -#include "sensors.h" - - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -static int sensors_create_name(char **name, const char *prefix, - struct i2c_adapter * adapter, int addr); -static void sensors_parse_reals(int *nrels, void *buffer, int bufsize, - long *results, int magnitude); -static void sensors_write_reals(int nrels,void *buffer,int *bufsize, - long *results, int magnitude); -static int sensors_proc_chips(ctl_table *ctl, int write, struct file * filp, - void *buffer, size_t *lenp); -static int sensors_sysctl_chips (ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, void *newval, - size_t newlen, void **context); - -static int sensors_init(void); -static int sensors_cleanup(void); - -#define SENSORS_ENTRY_MAX 20 -static struct ctl_table_header *sensors_entries[SENSORS_ENTRY_MAX]; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) -static struct i2c_client *sensors_clients[SENSORS_ENTRY_MAX]; -static unsigned short sensors_inodes[SENSORS_ENTRY_MAX]; -static void sensors_fill_inode(struct inode *inode, int fill); -static void sensors_dir_fill_inode(struct inode *inode, int fill); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ - -static ctl_table sysctl_table[] = { - { CTL_DEV, "dev", NULL, 0, 0555 }, - { 0 }, - { DEV_SENSORS, "sensors", NULL, 0, 0555 }, - { 0 }, - { 0, NULL, NULL, 0, 0555 }, - { 0 } -}; - -static ctl_table sensors_proc_dev_sensors[] = { - { SENSORS_CHIPS, "chips", NULL, 0, 0644, NULL, &sensors_proc_chips, - &sensors_sysctl_chips }, - { 0 } -}; - -static ctl_table sensors_proc_dev[] = { - { DEV_SENSORS, "sensors", NULL, 0, 0555, sensors_proc_dev_sensors }, - { 0 }, -}; - - -static ctl_table sensors_proc[] = { - { CTL_DEV, "dev", NULL, 0, 0555, sensors_proc_dev }, - { 0 } -}; - - -static struct ctl_table_header *sensors_proc_header; -static int sensors_initialized; - -/* This returns a nice name for a new directory; for example lm78-isa-0310 - (for a LM78 chip on the ISA bus at port 0x310), or lm75-i2c-3-4e (for - a LM75 chip on the third i2c bus at address 0x4e). - name is allocated first. */ -int sensors_create_name(char **name, const char *prefix, - struct i2c_adapter * adapter, int addr) -{ - char name_buffer[50]; - int id; - if (i2c_is_isa_adapter(adapter)) - sprintf(name_buffer,"%s-isa-%04x",prefix,addr); - else { - if ((id = i2c_adapter_id(adapter)) < 0) - return -ENOENT; - sprintf(name_buffer,"%s-i2c-%d-%02x",prefix,id,addr); - } - *name = kmalloc(strlen(name_buffer)+1,GFP_KERNEL); - strcpy(*name,name_buffer); - return 0; -} - -/* This rather complex function must be called when you want to add an entry - to /proc/sys/dev/sensors/chips (not yet implemented). It also creates - a new directory within /proc/sys/dev/sensors/. - ctl_template should be a template of the newly created directory. It is - copied in memory. The extra2 field of each file is set to point to client. - If any driver wants subdirectories within the newly created directory, - this function must be updated! */ -int sensors_register_entry(struct i2c_client *client ,const char *prefix, - ctl_table *ctl_template) -{ - int i,res,len,id; - ctl_table *new_table; - char *name; - struct ctl_table_header *new_header; - - if ((res = sensors_create_name(&name,prefix,client->adapter, - i2c_is_isa_client(client)? - ((struct isa_client *) client)->isa_addr: - client->addr))) - return res; - - for (id = 0; id < SENSORS_ENTRY_MAX; id++) - if (! sensors_entries[id]) { - break; - } - if (id == SENSORS_ENTRY_MAX) { - kfree(name); - return -ENOMEM; - } - id += 256; - - len = 0; - while (ctl_template[len].procname) - len++; - len += 7; - if (! (new_table = kmalloc(sizeof(ctl_table) * len,GFP_KERNEL))) { - kfree(name); - return -ENOMEM; - } - - memcpy(new_table,sysctl_table,6 * sizeof(ctl_table)); - new_table[0].child = &new_table[2]; - new_table[2].child = &new_table[4]; - new_table[4].child = &new_table[6]; - new_table[4].procname = name; - new_table[4].ctl_name = id; - memcpy(new_table+6,ctl_template,(len-6) * sizeof(ctl_table)); - for (i = 6; i < len; i++) - new_table[i].extra2 = client; - - if (! (new_header = register_sysctl_table(new_table,0))) { - kfree(new_table); - kfree(name); - return -ENOMEM; - } - - sensors_entries[id-256] = new_header; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) - sensors_clients[id-256] = client; -#ifdef DEBUG - if (!new_header || !new_header->ctl_table || - !new_header->ctl_table->child || - !new_header->ctl_table->child->child || - !new_header->ctl_table->child->child->de) { - printk("sensors.o: NULL pointer when trying to install fill_inode fix!\n"); - return id; - } -#endif /* DEBUG */ - sensors_inodes[id-256] = new_header->ctl_table->child->child->de->low_ino; - new_header->ctl_table->child->child->de->fill_inode = &sensors_dir_fill_inode; -#endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) - - return id; -} - -void sensors_deregister_entry(int id) -{ - ctl_table *table; - id -= 256; - if (sensors_entries[id]) { - table = sensors_entries[id]->ctl_table; - unregister_sysctl_table(sensors_entries[id]); - kfree((void *) (table[4].procname)); - kfree(table); - sensors_entries[id] = NULL; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) - sensors_clients[id] = NULL; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ - } -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) -/* Monitor access for /proc/sys/dev/sensors; make unloading sensors.o - impossible if some process still uses it or some file in it */ -void sensors_fill_inode(struct inode *inode, int fill) -{ - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - -/* Monitor access for /proc/sys/dev/sensors/ directories; make unloading - the corresponding module impossible if some process still uses it or - some file in it */ -void sensors_dir_fill_inode(struct inode *inode, int fill) -{ - int i; - struct i2c_client *client; - -#ifdef DEBUG - if (! inode) { - printk("sensors.o: Warning: inode NULL in fill_inode()\n"); - return; - } -#endif /* def DEBUG */ - - for (i = 0; i < SENSORS_ENTRY_MAX; i++) - if (sensors_clients[i] && (sensors_inodes[i] == inode->i_ino)) - break; -#ifdef DEBUG - if (i == SENSORS_ENTRY_MAX) { - printk("sensors.o: Warning: inode (%ld) not found in fill_inode()\n", - inode->i_ino); - return; - } -#endif /* def DEBUG */ - client = sensors_clients[i]; - if (fill) - client->driver->inc_use(client); - else - client->driver->dec_use(client); -} -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ - -int sensors_proc_chips(ctl_table *ctl, int write, struct file * filp, - void *buffer, size_t *lenp) -{ - char BUF[SENSORS_PREFIX_MAX + 30]; - int buflen,curbufsize,i; - struct ctl_table *client_tbl; - - if (write) - return 0; - - /* If buffer is size 0, or we try to read when not at the start, we - return nothing. Note that I think writing when not at the start - does not work either, but anyway, this is straight from the kernel - sources. */ - if (!*lenp || (filp->f_pos && !write)) { - *lenp = 0; - return 0; - } - curbufsize = 0; - for (i = 0; i < SENSORS_ENTRY_MAX; i ++) - if (sensors_entries[i]) { - client_tbl = sensors_entries[i]->ctl_table->child->child; - buflen = sprintf(BUF,"%d\t%s\n",client_tbl->ctl_name, - client_tbl->procname); - if (buflen + curbufsize > *lenp) - buflen=*lenp-curbufsize; - copy_to_user(buffer,BUF,buflen); - curbufsize += buflen; - (char *) buffer += buflen; - } - *lenp = curbufsize; - filp->f_pos += curbufsize; - return 0; -} - -int sensors_sysctl_chips (ctl_table *table, int *name, int nlen, void *oldval, - size_t *oldlenp, void *newval, size_t newlen, - void **context) -{ - struct sensors_chips_data data; - int i,oldlen,nrels,maxels; - struct ctl_table *client_tbl; - - if (oldval && oldlenp && ! get_user_data(oldlen,oldlenp) && oldlen) { - maxels = oldlen / sizeof(struct sensors_chips_data); - nrels = 0; - for (i = 0; (i < SENSORS_ENTRY_MAX) && (nrels < maxels); i++) - if (sensors_entries[i]) { - client_tbl = sensors_entries[i]->ctl_table->child->child; - data.sysctl_id = client_tbl->ctl_name; - strcpy(data.name,client_tbl->procname); - copy_to_user(oldval,&data,sizeof(struct sensors_chips_data)); - (char *) oldval += sizeof(struct sensors_chips_data); - nrels++; - } - oldlen = nrels * sizeof(struct sensors_chips_data); - put_user(oldlen,oldlenp); - } - return 0; -} - - -/* This funcion reads or writes a 'real' value (encoded by the combination - of an integer and a magnitude, the last is the power of ten the value - should be divided with) to a /proc/sys directory. To use this function, - you must (before registering the ctl_table) set the extra2 field to the - client, and the extra1 field to a function of the form: - void func(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) - This function can be called for three values of operation. If operation - equals SENSORS_PROC_REAL_INFO, the magnitude should be returned in - nrels_mag. If operation equals SENSORS_PROC_REAL_READ, values should - be read into results. nrels_mag should return the number of elements - read; the maximum number is put in it on entry. Finally, if operation - equals SENSORS_PROC_REAL_WRITE, the values in results should be - written to the chip. nrels_mag contains on entry the number of elements - found. - In all cases, client points to the client we wish to interact with, - and ctl_name is the SYSCTL id of the file we are accessing. */ -int sensors_proc_real(ctl_table *ctl, int write, struct file * filp, - void *buffer, size_t *lenp) -{ -#define MAX_RESULTS 20 - int mag,nrels=MAX_RESULTS; - long results[MAX_RESULTS]; - sensors_real_callback callback = ctl -> extra1; - struct i2c_client *client = ctl -> extra2; - - /* If buffer is size 0, or we try to read when not at the start, we - return nothing. Note that I think writing when not at the start - does not work either, but anyway, this is straight from the kernel - sources. */ - if (!*lenp || (filp->f_pos && !write)) { - *lenp = 0; - return 0; - } - - /* Get the magnitude */ - callback(client,SENSORS_PROC_REAL_INFO,ctl->ctl_name,&mag,NULL); - - if (write) { - /* Read the complete input into results, converting to longs */ - sensors_parse_reals(&nrels,buffer,*lenp,results,mag); - - if (! nrels) - return 0; - - /* Now feed this information back to the client */ - callback(client,SENSORS_PROC_REAL_WRITE,ctl->ctl_name,&nrels,results); - - filp->f_pos += *lenp; - return 0; - } else { /* read */ - /* Get the information from the client into results */ - callback(client,SENSORS_PROC_REAL_READ,ctl->ctl_name,&nrels,results); - - /* And write them to buffer, converting to reals */ - sensors_write_reals(nrels,buffer,lenp,results,mag); - filp->f_pos += *lenp; - return 0; - } -} - -/* This function is equivalent to sensors_proc_real, only it interacts with - the sysctl(2) syscall, and returns no reals, but integers */ -int sensors_sysctl_real (ctl_table *table, int *name, int nlen, void *oldval, - size_t *oldlenp, void *newval, size_t newlen, - void **context) -{ - long results[MAX_RESULTS]; - int oldlen,nrels=MAX_RESULTS; - sensors_real_callback callback = table -> extra1; - struct i2c_client *client = table -> extra2; - - /* Check if we need to output the old values */ - if (oldval && oldlenp && ! get_user_data(oldlen,oldlenp) && oldlen) { - callback(client,SENSORS_PROC_REAL_READ,table->ctl_name,&nrels,results); - - /* Note the rounding factor! */ - if (nrels * sizeof(long) < oldlen) - oldlen = nrels * sizeof(long); - oldlen = (oldlen / sizeof(long)) * sizeof(long); - copy_to_user(oldval,results,oldlen); - put_user(oldlen,oldlenp); - } - - if (newval && newlen) { - /* Note the rounding factor! */ - newlen -= newlen % sizeof(long); - nrels = newlen / sizeof(long); - copy_from_user(results,newval,newlen); - - /* Get the new values back to the client */ - callback(client,SENSORS_PROC_REAL_WRITE,table->ctl_name,&nrels,results); - } - return 0; -} - - -/* nrels contains initially the maximum number of elements which can be - put in results, and finally the number of elements actually put there. - A magnitude of 1 will multiply everything with 10; etc. - buffer, bufsize is the character buffer we read from and its length. - results will finally contain the parsed integers. - - Buffer should contain several reals, separated by whitespace. A real - has the following syntax: - [ Minus ] Digit* [ Dot Digit* ] - (everything between [] is optional; * means zero or more). - When the next character is unparsable, everything is skipped until the - next whitespace. - - WARNING! This is tricky code. I have tested it, but there may still be - hidden bugs in it, even leading to crashes and things! -*/ -void sensors_parse_reals(int *nrels, void *buffer, int bufsize, - long *results, int magnitude) -{ - int maxels,min,mag; - long res; - char nextchar=0; - - maxels = *nrels; - *nrels = 0; - - while (bufsize && (*nrels < maxels)) { - - /* Skip spaces at the start */ - while (bufsize && ! get_user_data(nextchar,(char *) buffer) && - isspace((int) nextchar)) { - bufsize --; - ((char *) buffer)++; - } - - /* Well, we may be done now */ - if (! bufsize) - return; - - /* New defaults for our result */ - min = 0; - res = 0; - mag = magnitude; - - /* Check for a minus */ - if (! get_user_data(nextchar,(char *) buffer) && (nextchar == '-')) { - min=1; - bufsize--; - ((char *) buffer)++; - } - - /* Digits before a decimal dot */ - while (bufsize && !get_user_data(nextchar,(char *) buffer) && - isdigit((int) nextchar)) { - res = res * 10 + nextchar - '0'; - bufsize--; - ((char *) buffer)++; - } - - /* If mag < 0, we must actually divide here! */ - while (mag < 0) { - res = res / 10; - mag++; - } - - if (bufsize && (nextchar == '.')) { - /* Skip the dot */ - bufsize--; - ((char *) buffer)++; - - /* Read digits while they are significant */ - while(bufsize && (mag > 0) && - !get_user_data(nextchar,(char *) buffer) && - isdigit((int) nextchar)) { - res = res * 10 + nextchar - '0'; - mag--; - bufsize--; - ((char *) buffer)++; - } - } - /* If we are out of data, but mag > 0, we need to scale here */ - while (mag > 0) { - res = res * 10; - mag --; - } - - /* Skip everything until we hit whitespace */ - while(bufsize && !get_user_data(nextchar,(char *) buffer) && - isspace ((int) nextchar)) { - bufsize --; - ((char *) buffer) ++; - } - - /* Put res in results */ - results[*nrels] = (min?-1:1)*res; - (*nrels)++; - } - - /* Well, there may be more in the buffer, but we need no more data. - Ignore anything that is left. */ - return; -} - -void sensors_write_reals(int nrels,void *buffer,int *bufsize,long *results, - int magnitude) -{ - #define BUFLEN 20 - char BUF[BUFLEN+1]; /* An individual representation should fit in here! */ - char printfstr[10]; - int nr=0; - int buflen,mag,times; - int curbufsize=0; - - while ((nr < nrels) && (curbufsize < *bufsize)) { - mag=magnitude; - - if (nr != 0) { - put_user(' ', (char *) buffer); - curbufsize ++; - ((char *) buffer) ++; - } - - /* Fill BUF with the representation of the next string */ - if (mag <= 0) { - - buflen=sprintf(BUF,"%ld",results[nr]); - if (buflen < 0) { /* Oops, a sprintf error! */ - *bufsize=0; - return; - } - while ((mag < 0) && (buflen < BUFLEN)) { - BUF[buflen++]='0'; - mag++; - } - BUF[buflen]=0; - } else { - times=1; - for (times=1; mag-- > 0; times *= 10); - if (results[nr] < 0) { - BUF[0] = '-'; - buflen = 1; - } else - buflen=0; - strcpy(printfstr,"%ld.%0Xld"); - printfstr[6]=magnitude+'0'; - buflen+=sprintf(BUF+buflen,printfstr,abs(results[nr])/times, - abs(results[nr])%times); - if (buflen < 0) { /* Oops, a sprintf error! */ - *bufsize=0; - return; - } - } - - /* Now copy it to the user-space buffer */ - if (buflen + curbufsize > *bufsize) - buflen=*bufsize-curbufsize; - copy_to_user(buffer,BUF,buflen); - curbufsize += buflen; - (char *) buffer += buflen; - - nr ++; - } - if (curbufsize < *bufsize) { - put_user('\n', (char *) buffer); - curbufsize ++; - } - *bufsize=curbufsize; -} - -int sensors_init(void) -{ - printk("sensors.o version %s (%s)\n",LM_VERSION,LM_DATE); - sensors_initialized = 0; - if (! (sensors_proc_header = register_sysctl_table(sensors_proc,0))) - return -ENOMEM; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) - sensors_proc_header->ctl_table->child->de->fill_inode = &sensors_fill_inode; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ - sensors_initialized ++; - return 0; -} - -int sensors_cleanup(void) -{ - if (sensors_initialized >= 1) { - unregister_sysctl_table(sensors_proc_header); - sensors_initialized --; - } - return 0; -} - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("LM78 driver"); - -int init_module(void) -{ - return sensors_init(); -} - -int cleanup_module(void) -{ - return sensors_cleanup(); -} - -#endif /* MODULE */ - diff --git a/src/sensors.h b/src/sensors.h deleted file mode 100644 index 83a18aa2..00000000 --- a/src/sensors.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - sensors.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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. -*/ - -#ifndef SENSORS_SENSORS_H -#define SENSORS_SENSORS_H - -#ifdef __KERNEL__ - -/* Next two must be included before sysctl.h can be included, in 2.0 kernels */ -#include -#include -#include - -/* The type of callback functions used in sensors_{proc,sysctl}_real */ -typedef void (*sensors_real_callback) (struct i2c_client *client, - int operation, int ctl_name, - int *nrels_mag, long *results); - -/* Values for the operation field in the above function type */ -#define SENSORS_PROC_REAL_INFO 1 -#define SENSORS_PROC_REAL_READ 2 -#define SENSORS_PROC_REAL_WRITE 3 - -/* These funcion reads or writes a 'real' value (encoded by the combination - of an integer and a magnitude, the last is the power of ten the value - should be divided with) to a /proc/sys directory. To use these functions, - you must (before registering the ctl_table) set the extra2 field to the - client, and the extra1 field to a function of the form: - void func(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) - This last function can be called for three values of operation. If - operation equals SENSORS_PROC_REAL_INFO, the magnitude should be returned - in nrels_mag. If operation equals SENSORS_PROC_REAL_READ, values should - be read into results. nrels_mag should return the number of elements - read; the maximum number is put in it on entry. Finally, if operation - equals SENSORS_PROC_REAL_WRITE, the values in results should be - written to the chip. nrels_mag contains on entry the number of elements - found. - In all cases, client points to the client we wish to interact with, - and ctl_name is the SYSCTL id of the file we are accessing. */ -extern int sensors_sysctl_real (ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, void *newval, - size_t newlen, void **context); -extern int sensors_proc_real(ctl_table *ctl, int write, struct file * filp, - void *buffer, size_t *lenp); - - - -/* These rather complex functions must be called when you want to add or - delete an entry in /proc/sys/dev/sensors/chips (not yet implemented). It - also creates a new directory within /proc/sys/dev/sensors/. - ctl_template should be a template of the newly created directory. It is - copied in memory. The extra2 field of each file is set to point to client. - If any driver wants subdirectories within the newly created directory, - these functions must be updated! */ -extern int sensors_register_entry(struct i2c_client *client, - const char *prefix, ctl_table *ctl_template); -extern void sensors_deregister_entry(int id); - -#endif /* def __KERNEL__ */ - - -/* The maximum length of the prefix */ -#define SENSORS_PREFIX_MAX 20 - -/* Driver IDs */ -#define I2C_DRIVERID_I2CDEV 1000 -#define I2C_DRIVERID_I2CPROC 1001 -#define I2C_DRIVERID_LM78 1002 -#define I2C_DRIVERID_LM75 1003 -#define I2C_DRIVERID_GL518 1004 -#define I2C_DRIVERID_EEPROM 1005 -#define I2C_DRIVERID_W83781D 1006 -#define I2C_DRIVERID_LM80 1007 -#define I2C_DRIVERID_ADM1021 1008 -#define I2C_DRIVERID_ADM9240 1009 -#define I2C_DRIVERID_LTC1710 1010 - -/* Sysctl IDs */ -#ifdef DEV_HWMON -#define DEV_SENSORS DEV_HWMON -#else /* ndef DEV_HWMOM */ -#define DEV_SENSORS 2 /* The id of the lm_sensors directory within the - dev table */ -#endif /* def DEV_HWMON */ - -#define SENSORS_CHIPS 1 -struct sensors_chips_data { - int sysctl_id; - char name[SENSORS_PREFIX_MAX + 13]; -}; - -#define LM78_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM78_SYSCTL_IN1 1001 -#define LM78_SYSCTL_IN2 1002 -#define LM78_SYSCTL_IN3 1003 -#define LM78_SYSCTL_IN4 1004 -#define LM78_SYSCTL_IN5 1005 -#define LM78_SYSCTL_IN6 1006 -#define LM78_SYSCTL_FAN1 1101 /* Rotations/min */ -#define LM78_SYSCTL_FAN2 1102 -#define LM78_SYSCTL_FAN3 1103 -#define LM78_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ -#define LM78_SYSCTL_VID 1300 /* Volts * 100 */ -#define LM78_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM78_SYSCTL_ALARMS 2001 /* bitvector */ - -#define LM78_ALARM_IN0 0x0001 -#define LM78_ALARM_IN1 0x0002 -#define LM78_ALARM_IN2 0x0004 -#define LM78_ALARM_IN3 0x0008 -#define LM78_ALARM_IN4 0x0100 -#define LM78_ALARM_IN5 0x0200 -#define LM78_ALARM_IN6 0x0400 -#define LM78_ALARM_FAN1 0x0040 -#define LM78_ALARM_FAN2 0x0080 -#define LM78_ALARM_FAN3 0x0800 -#define LM78_ALARM_TEMP 0x0010 -#define LM78_ALARM_BTI 0x0020 -#define LM78_ALARM_CHAS 0x1000 -#define LM78_ALARM_FIFO 0x2000 -#define LM78_ALARM_SMI_IN 0x4000 - -#define W83781D_SYSCTL_IN0 1000 /* Volts * 100 */ -#define W83781D_SYSCTL_IN1 1001 -#define W83781D_SYSCTL_IN2 1002 -#define W83781D_SYSCTL_IN3 1003 -#define W83781D_SYSCTL_IN4 1004 -#define W83781D_SYSCTL_IN5 1005 -#define W83781D_SYSCTL_IN6 1006 -#define W83781D_SYSCTL_FAN1 1101 /* Rotations/min */ -#define W83781D_SYSCTL_FAN2 1102 -#define W83781D_SYSCTL_FAN3 1103 -#define W83781D_SYSCTL_TEMP1 1200 /* Degrees Celcius * 10 */ -#define W83781D_SYSCTL_TEMP2 1201 /* Degrees Celcius * 10 */ -#define W83781D_SYSCTL_TEMP3 1202 /* Degrees Celcius * 10 */ -#define W83781D_SYSCTL_VID 1300 /* Volts * 100 */ -#define W83781D_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define W83781D_SYSCTL_ALARMS 2001 /* bitvector */ -#define W83781D_SYSCTL_BEEP 2002 /* bitvector */ - -#define W83781D_ALARM_IN0 0x0001 -#define W83781D_ALARM_IN1 0x0002 -#define W83781D_ALARM_IN2 0x0004 -#define W83781D_ALARM_IN3 0x0008 -#define W83781D_ALARM_IN4 0x0100 -#define W83781D_ALARM_IN5 0x0200 -#define W83781D_ALARM_IN6 0x0400 -#define W83781D_ALARM_FAN1 0x0040 -#define W83781D_ALARM_FAN2 0x0080 -#define W83781D_ALARM_FAN3 0x0800 -#define W83781D_ALARM_TEMP1 0x0010 -#define W83781D_ALARM_TEMP23 0x0020 -#define W83781D_ALARM_CHAS 0x1000 - -#define LM75_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ - -#define ADM1021_SYSCTL_TEMP 1200 -#define ADM1021_SYSCTL_REMOTE_TEMP 1201 -#define ADM1021_SYSCTL_DIE_CODE 1202 -#define ADM1021_SYSCTL_STATUS 1203 - -#define GL518_SYSCTL_VDD 1000 /* Volts * 100 */ -#define GL518_SYSCTL_VIN1 1001 -#define GL518_SYSCTL_VIN2 1002 -#define GL518_SYSCTL_VIN3 1003 -#define GL518_SYSCTL_FAN1 1101 /* RPM */ -#define GL518_SYSCTL_FAN2 1102 -#define GL518_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */ -#define GL518_SYSCTL_VID 1300 -#define GL518_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define GL518_SYSCTL_ALARMS 2001 /* bitvector */ -#define GL518_SYSCTL_BEEP 2002 /* bitvector */ - -#define GL518_ALARM_VDD 0x01 -#define GL518_ALARM_VIN1 0x02 -#define GL518_ALARM_VIN2 0x04 -#define GL518_ALARM_VIN3 0x08 -#define GL518_ALARM_TEMP 0x10 -#define GL518_ALARM_FAN1 0x20 -#define GL518_ALARM_FAN2 0x40 - -#define EEPROM_SYSCTL1 1000 -#define EEPROM_SYSCTL2 1001 -#define EEPROM_SYSCTL3 1002 -#define EEPROM_SYSCTL4 1003 -#define EEPROM_SYSCTL5 1004 -#define EEPROM_SYSCTL6 1005 -#define EEPROM_SYSCTL7 1006 -#define EEPROM_SYSCTL8 1007 - -#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ -#define LM80_SYSCTL_IN1 1001 -#define LM80_SYSCTL_IN2 1002 -#define LM80_SYSCTL_IN3 1003 -#define LM80_SYSCTL_IN4 1004 -#define LM80_SYSCTL_IN5 1005 -#define LM80_SYSCTL_IN6 1006 -#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ -#define LM80_SYSCTL_FAN2 1102 -#define LM80_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ -#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ - -#define ADM9240_SYSCTL_IN0 1000 /* Volts * 100 */ -#define ADM9240_SYSCTL_IN1 1001 -#define ADM9240_SYSCTL_IN2 1002 -#define ADM9240_SYSCTL_IN3 1003 -#define ADM9240_SYSCTL_IN4 1004 -#define ADM9240_SYSCTL_IN5 1005 -#define ADM9240_SYSCTL_FAN1 1101 /* Rotations/min */ -#define ADM9240_SYSCTL_FAN2 1102 -#define ADM9240_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ -#define ADM9240_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ -#define ADM9240_SYSCTL_ALARMS 2001 /* bitvector */ -#define ADM9240_SYSCTL_ANALOG_OUT 2002 -#define ADM9240_SYSCTL_VID 2003 - -#define LTC1710_SYSCTL_SWITCH_1 1000 -#define LTC1710_SYSCTL_SWITCH_2 1001 - -#define LM80_ALARM_IN0 0x0001 -#define LM80_ALARM_IN1 0x0002 -#define LM80_ALARM_IN2 0x0004 -#define LM80_ALARM_IN3 0x0008 -#define LM80_ALARM_IN4 0x0010 -#define LM80_ALARM_IN5 0x0020 -#define LM80_ALARM_IN6 0x0040 -#define LM80_ALARM_FAN1 0x0400 -#define LM80_ALARM_FAN2 0x0800 -#define LM80_ALARM_TEMP_HOT 0x0100 -#define LM80_ALARM_TEMP_OS 0x2000 -#define LM80_ALARM_CHAS 0x1000 -#define LM80_ALARM_BTI 0x0200 -#define LM80_ALARM_INT_IN 0x0080 -#endif /* def SENSORS_SENSORS_H */ diff --git a/src/smbus.c b/src/smbus.c deleted file mode 100644 index d61c2e94..00000000 --- a/src/smbus.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - smbus.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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 -#include -#include - -#include "i2c.h" -#ifdef SPINLOCK -#include -#else -#include -#endif - -#include "version.h" -#include "smbus.h" - -static s32 smbus_access_i2c (struct i2c_adapter * adapter, u8 addr, - char read_write, u8 command, int size, - union smbus_data * data); - -static int smbus_master_xfer (struct smbus_adapter *adap, - struct i2c_msg msgs[], int num); -static int smbus_slave_send (struct smbus_adapter *adap, char *data, int len); -static int smbus_slave_recv (struct smbus_adapter *adap, char *data, int len); -static int smbus_algo_control (struct smbus_adapter *adap, unsigned int cmd, - unsigned long arg); -static int smbus_client_register (struct smbus_client *client); -static int smbus_client_unregister (struct smbus_client *client); - -static int smbus_init(void); -static int smbus_cleanup(void); - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -/* This is the actual algorithm we define */ -struct smbus_algorithm smbus_algorithm = { - /* name */ "Non-I2C SMBus adapter", - /* id */ ALGO_SMBUS, - /* master_xfer */ &smbus_master_xfer, - /* slave_send */ &smbus_slave_send, - /* slave_rcv */ &smbus_slave_recv, - /* algo_control */ &smbus_algo_control, - /* client_register */ &smbus_client_register, - /* client_unregister*/&smbus_client_unregister -}; - - -/* OK, so you want to access a bus using the SMBus protocols. Well, it either - is registered as a SMBus-only adapter (like the PIIX4), or we need to - simulate the SMBus commands using the i2c access routines. - We do all locking here, so you can ignore that in the adapter-specific - smbus_accesss routine. */ -s32 smbus_access (struct i2c_adapter * adapter, u8 addr, char read_write, - u8 command, int size, union smbus_data * data) -{ - int res; - if ((adapter->id & ALGO_MASK) == ALGO_SMBUS) { -#ifdef SPINLOCK - spin_lock_irqsave(&adapter->lock,adapter->lockflags); -#else - down(&adapter->lock); -#endif - res = ((struct smbus_adapter *) adapter) -> - smbus_access(addr,read_write,command,size,data); -#ifdef SPINLOCK - spin_unlock_irqrestore(&adapter->lock,adapter->lockflags); -#else - up(&adapter->lock); -#endif - } else - res = smbus_access_i2c(adapter,addr,read_write,command,size,data); - return res; -} - -/* Simulate a SMBus command using the i2c protocol - No checking of paramters is done! */ -s32 smbus_access_i2c(struct i2c_adapter * adapter, u8 addr, char read_write, - u8 command, int size, union smbus_data * data) -{ - /* So we need to generate a series of msgs. In the case of writing, we - need to use only one message; when reading, we need two. We initialize - most things with sane defaults, to keep the code below somewhat - simpler. */ - char msgbuf0[33]; - char msgbuf1[33]; - int num = read_write == SMBUS_READ?2:1; - struct i2c_msg msg[2] = { { addr, 0, 1, msgbuf0 }, - { addr, I2C_M_RD, 0, msgbuf1 } - }; - int i; - - msgbuf0[0] = command; - switch(size) { - case SMBUS_QUICK: - msg[0].len = 0; - num = 1; /* Special case: The read/write field is used as data */ - break; - case SMBUS_BYTE: - if (read_write == SMBUS_READ) - /* Special case: only a read! */ - msg[0].flags = I2C_M_RD; - break; - case SMBUS_BYTE_DATA: - if (read_write == SMBUS_READ) - msg[1].len = 1; - else { - msg[0].len = 2; - msgbuf0[1] = data->byte; - } - break; - case SMBUS_WORD_DATA: - if (read_write == SMBUS_READ) - msg[1].len = 2; - else { - msg[0].len=3; - msgbuf0[1] = data->word & 0xff; - msgbuf0[2] = (data->word >> 8) & 0xff; - } - break; - case SMBUS_PROC_CALL: - num = 2; /* Special case */ - msg[0].len = 3; - msg[1].len = 2; - msgbuf0[1] = data->word & 0xff; - msgbuf0[2] = (data->word >> 8) & 0xff; - break; - case SMBUS_BLOCK_DATA: - if (read_write == SMBUS_READ) { - printk("smbus.o: Block read not supported under I2C emulation!\n"); - return -1; - } else { - msg[1].len = data->block[0] + 1; - if (msg[1].len > 32) { - printk("smbus.o: smbus_access called with invalid block write " - "size (%d)\n",msg[1].len); - return -1; - } - for (i = 1; i <= msg[1].len; i++) - msgbuf0[i] = data->block[1]; - } - break; - default: - printk("smbus.o: smbus_access called with invalid size (%d)\n",size); - return -1; - } - - if (i2c_transfer(adapter, msg, num) < 0) - return -1; - - if(read_write == SMBUS_READ) - switch(size) { - case SMBUS_BYTE: - data->byte = msgbuf0[0]; - break; - case SMBUS_BYTE_DATA: - data->byte = msgbuf1[0]; - break; - case SMBUS_WORD_DATA: - case SMBUS_PROC_CALL: - data->word = msgbuf1[0] + (msgbuf1[1] << 8); - break; - } - return 0; -} - -/* Algorithm master_xfer call-back implementation. Can't do that... */ -int smbus_master_xfer (struct smbus_adapter *adap, struct i2c_msg msgs[], - int num) -{ -#ifdef DEBUG - printk("smbus.o: smbus_master_xfer called for adapter `%s' " - "(no i2c level access possible!)\n", - adap->name); -#endif - return -1; -} - -/* Algorithm slave_send call-back implementation. Can't do that... */ -int smbus_slave_send (struct smbus_adapter *adap, char *data, int len) -{ -#ifdef DEBUG - printk("smbus.o: smbus_slave_send called for adapter `%s' " - "(no i2c level access possible!)\n", - adap->name); -#endif - return -1; -} - -/* Algorithm slave_recv call-back implementation. Can't do that... */ -int smbus_slave_recv (struct smbus_adapter *adap, char *data, int len) -{ -#ifdef DEBUG - printk("smbus.o: smbus_slave_recv called for adapter `%s' " - "(no i2c level access possible!)\n", - adap->name); -#endif - return -1; -} - -/* Here we can put additional calls to modify the workings of the algorithm. - But right now, there is no need for that. */ -int smbus_algo_control (struct smbus_adapter *adap, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - -/* Ehm... This is called when a client is registered to an adapter. We could - do all kinds of neat stuff here like, ehm - returning success? */ -int smbus_client_register (struct smbus_client *client) -{ - return 0; -} - -int smbus_client_unregister (struct smbus_client *client) -{ - return 0; -} - -int smbus_init(void) -{ - int res; - printk("smbus.o version %s (%s)\n",LM_VERSION,LM_DATE); - if ((res = smbus_add_algorithm(&smbus_algorithm))) - printk("smbus.o: Algorithm registration failed, module not inserted.\n"); - else - printk("smbus.o initialized\n"); - return res; -} - -int smbus_cleanup(void) -{ - int res; - if ((res = smbus_del_algorithm(&smbus_algorithm))) - printk("smbus.o: Algorithm deregistration failed, module not removed\n"); - return res; -} - -/* OK, this will for now _only_ compile as a module, but this is neat for - later, if we want to compile it straight into the kernel */ -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("System Management Bus (SMBus) access"); - -int init_module(void) -{ - return smbus_init(); -} - -int cleanup_module(void) -{ - return smbus_cleanup(); -} - -#endif /* MODULE */ diff --git a/src/smbus.h b/src/smbus.h deleted file mode 100644 index e3f7b1dc..00000000 --- a/src/smbus.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - smbus.h - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - - 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. -*/ - -#ifndef SENSORS_SMBUS_H -#define SENSORS_SMBUS_H - -/* This file must interface with Simon Vogl's i2c driver. Version 19981006 is - OK, earlier versions are not; later versions will probably give problems - too. -*/ -#include - -/* This union is used within smbus_access routines */ -union smbus_data { - __u8 byte; - __u16 word; - __u8 block[32]; -}; - -/* smbus_access read or write markers */ -#define SMBUS_READ 1 -#define SMBUS_WRITE 0 - -/* SMBus transaction types (size parameter in the above functions) - Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ -#define SMBUS_QUICK 0 -#define SMBUS_BYTE 1 -#define SMBUS_BYTE_DATA 2 -#define SMBUS_WORD_DATA 3 -#define SMBUS_PROC_CALL 4 -#define SMBUS_BLOCK_DATA 5 - -#ifdef __KERNEL__ - -/* SPINLOCK is defined in i2c.h. */ -#ifdef SPINLOCK -#include -#else -#include -#endif - -#ifdef LM_SENSORS -#include "i2c.h" -#else -#include -#endif - -/* Declarations, to keep the compiler happy */ -struct smbus_driver; -struct smbus_client; -struct smbus_algorithm; -struct smbus_adapter; -union smbus_data; - -/* A driver tells us how we should handle a specific kind of chip. - A specific instance of such a chip is called a client. - This structure is essentially the same as i2c_driver. */ -struct smbus_driver { - char name[32]; - int id; - unsigned int flags; - int (* attach_adapter) (struct smbus_adapter *); - int (* detach_client) (struct smbus_client *); - int (* command) (struct smbus_client *, unsigned int cmd, void *arg); - void (* inc_use) (struct smbus_client *); - void (* dec_use) (struct smbus_client *); -}; - -/* A client is a specifc instance of a chip: for each detected chip, there will - be a client. Its operation is controlled by a driver. - This structure is essentially the same as i2c_client. */ -struct smbus_client { - char name[32]; - int id; - unsigned int flags; - unsigned char addr; - struct smbus_adapter *adapter; - struct smbus_driver *driver; - void *data; -}; - -/* An algorithm describes how a certain class of busses can be accessed. - A specific instance of sucj a bus is called an adapter. - This structure is essentially the same as i2c_adapter. */ -struct smbus_algorithm { - char name[32]; - unsigned int id; - int (* master_xfer) (struct smbus_adapter *adap, struct i2c_msg msgs[], - int num); - int (* slave_send) (struct smbus_adapter *,char *, int); - int (* slave_recv) (struct smbus_adapter *,char *, int); - int (* algo_control) (struct smbus_adapter *, unsigned int, unsigned long); - int (* client_register) (struct smbus_client *); - int (* client_unregister) (struct smbus_client *); -}; - -/* An adapter is a specifc instance of a bus: for each detected bus, there will - be an adapter. Its operation is controlled by an algorithm. - SPINLOCK must be the same as declared in i2c.h. - This structure is an extension of i2c_algorithm. */ -struct smbus_adapter { - char name[32]; - unsigned int id; - struct smbus_algorithm *algo; - void *data; -#ifdef SPINLOCK - spinlock_t lock; - unsigned long lockflags; -#else - struct semaphore lock; -#endif - unsigned int flags; - struct smbus_client *clients[I2C_CLIENT_MAX]; - int client_count; - int timeout; - int retries; - - /* Here ended i2c_adapter */ - s32 (* smbus_access) (u8 addr, char read_write, - u8 command, int size, union smbus_data * data); -}; - -/* We need to mark SMBus algorithms in the algorithm structure. - Note that any and all adapters using a non-i2c driver use in this - setup ALGO_SMBUS. Adapters define their own smbus access routine. - This also means that adapter->smbus_access is only available if - this flag is set! */ -#define ALGO_SMBUS 0x40000 - -/* SMBus Adapter ids */ -#define SMBUS_PIIX4 1 - -/* Detect whether we are on an SMBus-only bus. Note that if this returns - false, you can still use the smbus access routines, as these emulate - the SMBus on I2C. Unless they are undefined on your algorithm, of - course. */ -#define i2c_is_smbus_client(clientptr) \ - ((clientptr)->adapter->algo->id == ALGO_SMBUS) -#define i2c_is_smbus_adapter(adapptr) \ - ((adapptr)->algo->id == ALGO_SMBUS) - - -/* Declare an algorithm structure. All SMBus derived adapters should use this - algorithm! */ -extern struct smbus_algorithm smbus_algorithm; - -/* This is the very generalized SMBus access routine. You probably do not - want to use this, though; one of the functions below may be much easier, - and probably just as fast. - Note that we use i2c_adapter here, because you do not need a specific - smbus adapter to call this function. */ -extern s32 smbus_access (struct i2c_adapter * adapter, u8 addr, - char read_write, u8 command, int size, - union smbus_data * data); - -/* Now follow the 'nice' access routines. These also document the calling - conventions of smbus_access. */ - -extern inline s32 smbus_write_quick(struct i2c_adapter * adapter, u8 addr, - u8 value) -{ - return smbus_access(adapter,addr,value,0,SMBUS_QUICK,NULL); -} - -extern inline s32 smbus_read_byte(struct i2c_adapter * adapter,u8 addr) -{ - union smbus_data data; - if (smbus_access(adapter,addr,SMBUS_READ,0,SMBUS_BYTE,&data)) - return -1; - else - return 0x0FF & data.byte; -} - -extern inline s32 smbus_write_byte(struct i2c_adapter * adapter, u8 addr, - u8 value) -{ - return smbus_access(adapter,addr,SMBUS_WRITE,value, SMBUS_BYTE,NULL); -} - -extern inline s32 smbus_read_byte_data(struct i2c_adapter * adapter, - u8 addr, u8 command) -{ - union smbus_data data; - if (smbus_access(adapter,addr,SMBUS_READ,command,SMBUS_BYTE_DATA,&data)) - return -1; - else - return 0x0FF & data.byte; -} - -extern inline s32 smbus_write_byte_data(struct i2c_adapter * adapter, - u8 addr, u8 command, u8 value) -{ - union smbus_data data; - data.byte = value; - return smbus_access(adapter,addr,SMBUS_WRITE,command,SMBUS_BYTE_DATA,&data); -} - -extern inline s32 smbus_read_word_data(struct i2c_adapter * adapter, - u8 addr, u8 command) -{ - union smbus_data data; - if (smbus_access(adapter,addr,SMBUS_READ,command,SMBUS_WORD_DATA,&data)) - return -1; - else - return 0x0FFFF & data.word; -} - -extern inline s32 smbus_write_word_data(struct i2c_adapter * adapter, - u8 addr, u8 command, u16 value) -{ - union smbus_data data; - data.word = value; - return smbus_access(adapter,addr,SMBUS_WRITE,command,SMBUS_WORD_DATA,&data); -} - -extern inline s32 smbus_process_call(struct i2c_adapter * adapter, - u8 addr, u8 command, u16 value) -{ - union smbus_data data; - data.word = value; - if (smbus_access(adapter,addr,SMBUS_WRITE,command,SMBUS_PROC_CALL,&data)) - return -1; - else - return 0x0FFFF & data.word; -} - -/* Returns the number of read bytes */ -extern inline s32 smbus_read_block_data(struct i2c_adapter * adapter, - u8 addr, u8 command, u8 *values) -{ - union smbus_data data; - int i; - if (smbus_access(adapter,addr,SMBUS_READ,command,SMBUS_BLOCK_DATA,&data)) - return -1; - else { - for (i = 1; i <= data.block[0]; i++) - values[i-1] = data.block[i]; - return data.block[0]; - } -} - -extern inline s32 smbus_write_block_data(struct i2c_adapter * adapter, - u8 addr, u8 command, u8 length, - u8 *values) -{ - union smbus_data data; - int i; - if (length > 32) - length = 32; - for (i = 1; i <= length; i++) - data.block[i] = values[i-1]; - data.block[0] = length; - return smbus_access(adapter,addr,SMBUS_WRITE,command,SMBUS_BLOCK_DATA,&data); -} - - -/* Next: define SMBus variants of registering. */ - -#define smbus_add_algorithm(algoptr) \ - i2c_add_algorithm((struct i2c_algorithm *) (algoptr)) -#define smbus_del_algorithm(algoptr) \ - i2c_del_algorithm((struct i2c_algorithm *) (algoptr)) - -#define smbus_add_adapter(adapptr) \ - i2c_add_adapter((struct i2c_adapter *) (adapptr)) -#define smbus_del_adapter(adapptr) \ - i2c_del_adapter((struct i2c_adapter *) (adapptr)) - -#define smbus_add_driver(driverptr) \ - i2c_add_driver((struct i2c_driver *) (driverptr)) -#define smbus_del_driver(driverptr) \ - i2c_add_driver((struct i2c_driver *) (driverptr)) - -#define smbus_attach_client(clientptr) \ - i2c_attach_client((struct i2c_client *) (clientptr)) -#define smbus_detach_client(clientptr) \ - i2c_detach_client((struct i2c_client *) (clientptr)) - - -#endif /* def __KERNEL__ */ - -#endif /* ndef SENSORS_SMBUS_H */ - diff --git a/src/w83781d.c b/src/w83781d.c deleted file mode 100644 index fbf8bf0e..00000000 --- a/src/w83781d.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* - w83781d.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 Frodo Looijaard - and Philip Edelbrock - - 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 -#include -#include -#include -#include -#include -#include -#include -#include "smbus.h" -#include "version.h" -#include "isa.h" -#include "sensors.h" -#include "i2c.h" -#include "compat.h" - -/* Many W83781D constants specified below */ - -/* Length of ISA address segment */ -#define W83781D_EXTENT 8 - -/* Where are the ISA address/data registers relative to the base address */ -#define W83781D_ADDR_REG_OFFSET 5 -#define W83781D_DATA_REG_OFFSET 6 - -/* The W83781D registers */ -#define W83781D_REG_IN_MAX(nr) (0x2b + (nr) * 2) -#define W83781D_REG_IN_MIN(nr) (0x2c + (nr) * 2) -#define W83781D_REG_IN(nr) (0x20 + (nr)) - -#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) -#define W83781D_REG_FAN(nr) (0x27 + (nr)) - -#define W83781D_REG_TEMP2 0x0150 -#define W83781D_REG_TEMP3 0x0250 -#define W83781D_REG_TEMP2_HYST 0x153 -#define W83781D_REG_TEMP3_HYST 0x253 -#define W83781D_REG_TEMP2_CONFIG 0x152 -#define W83781D_REG_TEMP3_CONFIG 0x252 -#define W83781D_REG_TEMP2_OVER 0x155 -#define W83781D_REG_TEMP3_OVER 0x255 - -#define W83781D_REG_TEMP 0x27 -#define W83781D_REG_TEMP_OVER 0x39 -#define W83781D_REG_TEMP_HYST 0x3A -#define W83781D_REG_TEMP_CONFIG 0x52 -#define W83781D_REG_BANK 0x4E - -#define W83781D_REG_CONFIG 0x40 -#define W83781D_REG_ALARM1 0x41 -#define W83781D_REG_ALARM2 0x42 - -#define W83781D_REG_BEEP_CONFIG 0x4D -#define W83781D_REG_BEEP_INTS1 0x56 -#define W83781D_REG_BEEP_INTS2 0x57 - -#define W83781D_REG_VID_FANDIV 0x47 - -#define W83781D_REG_CHIPID 0x49 -#define W83781D_REG_WCHIPID 0x58 -#define W83781D_REG_CHIPMAN 0x4F -#define W83781D_REG_PIN 0x4B - - -/* Conversions. Rounding is only done on the TO_REG variants. */ -#define IN_TO_REG(val,nr) (((val) * 10 + 8)/16) -#define IN_FROM_REG(val,nr) (((val) * 16) / 10) - -#define FAN_TO_REG(val,div) ((val)==0?255:((1350000+(val)*(div)/2)/\ - ((val)*(div))) & 0xff) -#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*2*(div))) - -#define TEMP_TO_REG(val) (((val)<0?(((val)-5)/10)&0xff:((val)+5)/10) & 0xff) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) - -#define TEMP_ADD_TO_REG(val) (((((val) + 2) / 5) << 7) & 0xff80) -#define TEMP_ADD_FROM_REG(val) (((val) >> 7) * 5) - -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - (val)>=0x06?0:205-(val)*5) -#define ALARMS_FROM_REG(val) (val) -#define BEEPS_FROM_REG(val) (val) -#define BEEPS_TO_REG(val) ((val) & 0xffff) - -#define BEEP_ENABLE_TO_REG(val) (val) -#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) - -#define DIV_FROM_REG(val) (1 << (val)) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) - -/* Initial limits */ -#define W83781D_INIT_IN_0 (vid==350?280:vid) -#define W83781D_INIT_IN_1 (vid==350?280:vid) -#define W83781D_INIT_IN_2 330 -#define W83781D_INIT_IN_3 (((500) * 100)/168) -#define W83781D_INIT_IN_4 (((1200) * 10)/38) -#define W83781D_INIT_IN_5 (((-1200) * -604)/2100) -#define W83781D_INIT_IN_6 (((-500) * -604)/909) - -#define W83781D_INIT_IN_PERCENTAGE 10 - -#define W83781D_INIT_IN_MIN_0 \ - (W83781D_INIT_IN_0 - W83781D_INIT_IN_0 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MAX_0 \ - (W83781D_INIT_IN_0 + W83781D_INIT_IN_0 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MIN_1 \ - (W83781D_INIT_IN_1 - W83781D_INIT_IN_1 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MAX_1 \ - (W83781D_INIT_IN_1 + W83781D_INIT_IN_1 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MIN_2 \ - (W83781D_INIT_IN_2 - W83781D_INIT_IN_2 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MAX_2 \ - (W83781D_INIT_IN_2 + W83781D_INIT_IN_2 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MIN_3 \ - (W83781D_INIT_IN_3 - W83781D_INIT_IN_3 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MAX_3 \ - (W83781D_INIT_IN_3 + W83781D_INIT_IN_3 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MIN_4 \ - (W83781D_INIT_IN_4 - W83781D_INIT_IN_4 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MAX_4 \ - (W83781D_INIT_IN_4 + W83781D_INIT_IN_4 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MIN_5 \ - (W83781D_INIT_IN_5 - W83781D_INIT_IN_5 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MAX_5 \ - (W83781D_INIT_IN_5 + W83781D_INIT_IN_5 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MIN_6 \ - (W83781D_INIT_IN_6 - W83781D_INIT_IN_6 * W83781D_INIT_IN_PERCENTAGE \ - / 100) -#define W83781D_INIT_IN_MAX_6 \ - (W83781D_INIT_IN_6 + W83781D_INIT_IN_6 * W83781D_INIT_IN_PERCENTAGE \ - / 100) - -#define W83781D_INIT_FAN_MIN_1 3000 -#define W83781D_INIT_FAN_MIN_2 3000 -#define W83781D_INIT_FAN_MIN_3 3000 - -#define W83781D_INIT_TEMP_OVER 600 -#define W83781D_INIT_TEMP_HYST 500 -#define W83781D_INIT_TEMP2_OVER 600 -#define W83781D_INIT_TEMP2_HYST 500 -#define W83781D_INIT_TEMP3_OVER 600 -#define W83781D_INIT_TEMP3_HYST 500 - -#ifdef MODULE -extern int init_module(void); -extern int cleanup_module(void); -#endif /* MODULE */ - -/* There are some complications in a module like this. First off, W83781D chips - may be both present on the SMBus and the ISA bus, and we have to handle - those cases separately at some places. Second, there might be several - W83781D chips available (well, actually, that is probably never done; but - it is a clean illustration of how to handle a case like that). Finally, - a specific chip may be attached to *both* ISA and SMBus, and we would - not like to detect it double. Fortunately, in the case of the W83781D at - least, a register tells us what SMBus address we are on, so that helps - a bit - except if there could be more than one SMBus. Groan. No solution - for this yet. */ - -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - -/* For each registered W83781D, we need to keep some data in memory. That - data is pointed to by w83781d_list[NR]->data. The structure itself is - dynamically allocated, at the same time when a new w83781d client is - allocated. */ -struct w83781d_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 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ - u16 temp_add[2]; /* Register value */ - u16 temp_add_over[2]; /* Register value */ - u16 temp_add_hyst[2]; /* Register value */ - u8 fan_div[3]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ - u16 alarms; /* Register encoding, combined */ - u16 beeps; /* Register encoding, combined */ - u8 beep_enable; /* Boolean */ -}; - - -static int w83781d_init(void); -static int w83781d_cleanup(void); - -static int w83781d_attach_adapter(struct i2c_adapter *adapter); -static int w83781d_detect_isa(struct isa_adapter *adapter); -static int w83781d_detect_smbus(struct i2c_adapter *adapter); -static int w83781d_detach_client(struct i2c_client *client); -static int w83781d_detach_isa(struct isa_client *client); -static int w83781d_detach_smbus(struct i2c_client *client); -static int w83781d_new_client(struct i2c_adapter *adapter, - struct i2c_client *new_client); -static void w83781d_remove_client(struct i2c_client *client); -static int w83781d_command(struct i2c_client *client, unsigned int cmd, - void *arg); -static void w83781d_inc_use (struct i2c_client *client); -static void w83781d_dec_use (struct i2c_client *client); - -static int w83781d_read_value(struct i2c_client *client, u16 register); -static int w83781d_write_value(struct i2c_client *client, u16 register, - u16 value); -static void w83781d_update_client(struct i2c_client *client); -static void w83781d_init_client(struct i2c_client *client); - - -static void w83781d_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void w83781d_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void w83781d_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_temp_add(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void w83781d_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void w83781d_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void w83781d_fan_div(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -/* I choose here for semi-static W83781D 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_W83781D_NR 4 -static struct i2c_client *w83781d_list[MAX_W83781D_NR]; - -/* The driver. I choose to use type i2c_driver, as at is identical to both - smbus_driver and isa_driver, and clients could be of either kind */ -static struct i2c_driver w83781d_driver = { - /* name */ "W83781D sensor driver", - /* id */ I2C_DRIVERID_W83781D, - /* flags */ DF_NOTIFY, - /* attach_adapter */ &w83781d_attach_adapter, - /* detach_client */ &w83781d_detach_client, - /* command */ &w83781d_command, - /* inc_use */ &w83781d_inc_use, - /* dec_use */ &w83781d_dec_use -}; - -/* Used by w83781d_init/cleanup */ -static int w83781d_initialized = 0; - -/* The /proc/sys entries */ -/* These files are created for each detected W83781D. 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 w83781d_dir_table_template[] = { - { W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_in }, - { W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_in }, - { W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_in }, - { W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_in }, - { W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_in }, - { W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_in }, - { W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_in }, - { W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_fan }, - { W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_fan }, - { W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_fan }, - { W83781D_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_temp }, - { W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_temp_add }, - { W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_temp_add }, - { W83781D_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_vid }, - { W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_fan_div }, - { W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_alarms }, - { W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &w83781d_beep }, - { 0 } -}; - - -/* This function is called when: - * w83781d_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and w83781d_driver is still present) */ -int w83781d_attach_adapter(struct i2c_adapter *adapter) -{ - if (i2c_is_isa_adapter(adapter)) - return w83781d_detect_isa((struct isa_adapter *) adapter); - else - return w83781d_detect_smbus(adapter); -} - -/* This function is called whenever a client should be removed: - * w83781d_driver is removed (when this module is unloaded) - * when an adapter is removed which has a w83781d client (and w83781d_driver - is still present). */ -int w83781d_detach_client(struct i2c_client *client) -{ - if (i2c_is_isa_client(client)) - return w83781d_detach_isa((struct isa_client *) client); - else - return w83781d_detach_smbus(client); -} - -/* Detect whether there is a W83781D on the ISA bus, register and initialize - it. */ -int w83781d_detect_isa(struct isa_adapter *adapter) -{ - int address,err,temp; - struct isa_client *new_client; - const char *type_name; - const char *client_name; - - /* OK, this is no detection. I know. It will do for now, though. */ - - err = 0; - for (address = 0x290; (! err) && (address <= 0x290); address += 0x08) { - if (check_region(address, W83781D_EXTENT)) - continue; - - /* Awful, but true: unused port addresses should return 0xff */ - if ((inb_p(address + 1) != 0xff) || (inb_p(address + 2) != 0xff) || - (inb_p(address + 3) != 0xff) || (inb_p(address + 7) != 0xff)) - continue; - - if (inb_p(address + W83781D_ADDR_REG_OFFSET) == 0xff) { - outb_p(0x00,address + W83781D_ADDR_REG_OFFSET); - if (inb_p(address + W83781D_ADDR_REG_OFFSET) == 0xff) - continue; - } - - /* Real detection code goes here */ - - /* The Winbond may be stuck in bank 1 or 2. This should reset it. - We really need some nifty detection code, because this can lead - to a lot of problems if there is no Winbond present! */ - outb_p(W83781D_REG_BANK,address + W83781D_ADDR_REG_OFFSET); - outb_p(0x00,address + W83781D_DATA_REG_OFFSET); - - /* Detection -- To bad we can't do this before setting to bank 0 */ - outb_p(W83781D_REG_CHIPMAN,address + W83781D_ADDR_REG_OFFSET); - temp=inb_p(address + W83781D_DATA_REG_OFFSET); - #ifdef DEBUG - printk("w83781d.o: Detect byte: 0x%X\n",temp); - #endif - if (temp != 0x0A3) { - #ifdef DEBUG - printk("83781d.o: Winbond W83781D detection failed (ISA at 0x%X)\n",address); - #endif - continue; - } - printk("w83781d.o: Winbond W83781D detected (ISA addr=0x%X)\n",address); - type_name = "w83781d"; - client_name = "Winbond W83781D chip"; - - request_region(address, W83781D_EXTENT, type_name); - - /* Allocate space for a new client structure */ - if (! (new_client = kmalloc(sizeof(struct isa_client) + - sizeof(struct w83781d_data), - GFP_KERNEL))) - { - err=-ENOMEM; - goto ERROR1; - } - - /* Fill the new client structure with data */ - new_client->data = (struct w83781d_data *) (new_client + 1); - new_client->addr = 0; - strcpy(new_client->name,client_name); - new_client->isa_addr = address; - if ((err = w83781d_new_client((struct i2c_adapter *) adapter, - (struct i2c_client *) new_client))) - goto ERROR2; - - /* Tell i2c-core a new client has arrived */ - if ((err = isa_attach_client(new_client))) - goto ERROR3; - - /* Register a new directory entry with module sensors */ - if ((err = sensors_register_entry((struct i2c_client *) new_client, - type_name, - w83781d_dir_table_template)) < 0) - goto ERROR4; - ((struct w83781d_data *) (new_client->data)) -> sysctl_id = err; - err = 0; - - /* Initialize the W83781D chip */ - w83781d_init_client((struct i2c_client *) new_client); - continue; - -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - -ERROR4: - isa_detach_client(new_client); -ERROR3: - w83781d_remove_client((struct i2c_client *) new_client); -ERROR2: - kfree(new_client); -ERROR1: - release_region(address, W83781D_EXTENT); - } - return err; - -} - -/* Deregister and remove a W83781D client */ -int w83781d_detach_isa(struct isa_client *client) -{ - int err,i; - for (i = 0; i < MAX_W83781D_NR; i++) - if ((client == (struct isa_client *) (w83781d_list[i]))) - break; - if (i == MAX_W83781D_NR) { - printk("w83781d.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct w83781d_data *)(client->data))->sysctl_id); - - if ((err = isa_detach_client(client))) { - printk("w83781d.o: Client deregistration failed, client not detached.\n"); - return err; - } - w83781d_remove_client((struct i2c_client *) client); - release_region(client->isa_addr,W83781D_EXTENT); - kfree(client); - return 0; -} - -int w83781d_detect_smbus(struct i2c_adapter *adapter) -{ - int address,err; - struct i2c_client *new_client; - const char *type_name,*client_name; - - /* OK, this is no detection. I know. It will do for now, though. */ - err = 0; - for (address = 0x20; (! err) && (address <= 0x2f); 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,W83781D_REG_CONFIG) < 0) - continue; - - smbus_write_byte_data(adapter,address,W83781D_REG_BANK,0x00); - - err = smbus_read_byte_data(adapter,address,W83781D_REG_CHIPMAN); - #ifdef DEBUG - printk("w83781d.o: Detect byte: 0x%X\n",err); - #endif - if (err == 0x0A3) { - printk("w83781d.o: Winbond W83781D detected (SMBus addr 0x%X)\n",address); - type_name = "w83781d"; - client_name = "Winbond W83781D chip"; - err=0; - } else { - #ifdef DEBUG - printk("83781d.o: Winbond W83781D detection failed (SMBus/I2C at 0x%X)\n",address); - #endif - continue; - } - - - /* Allocate space for a new client structure. To counter memory - ragmentation somewhat, we only do one kmalloc. */ - if (! (new_client = kmalloc(sizeof(struct i2c_client) + - sizeof(struct w83781d_data), - GFP_KERNEL))) { - err = -ENOMEM; - continue; - } - - /* Fill the new client structure with data */ - new_client->data = (struct w83781d_data *) (new_client + 1); - new_client->addr = address; - strcpy(new_client->name,client_name); - if ((err = w83781d_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, - w83781d_dir_table_template)) < 0) - goto ERROR4; - ((struct w83781d_data *) (new_client->data))->sysctl_id = err; - err = 0; - - /* Initialize the W83781D chip */ - w83781d_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: - w83781d_remove_client((struct i2c_client *) new_client); -ERROR2: - kfree(new_client); - } - return err; -} - -int w83781d_detach_smbus(struct i2c_client *client) -{ - int err,i; - for (i = 0; i < MAX_W83781D_NR; i++) - if (client == w83781d_list[i]) - break; - if ((i == MAX_W83781D_NR)) { - printk("w83781d.o: Client to detach not found.\n"); - return -ENOENT; - } - - sensors_deregister_entry(((struct w83781d_data *)(client->data))->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk("w83781d.o: Client deregistration failed, client not detached.\n"); - return err; - } - w83781d_remove_client(client); - kfree(client); - return 0; -} - - -/* Find a free slot, and initialize most of the fields */ -int w83781d_new_client(struct i2c_adapter *adapter, - struct i2c_client *new_client) -{ - int i; - struct w83781d_data *data; - - /* First, seek out an empty slot */ - for(i = 0; i < MAX_W83781D_NR; i++) - if (! w83781d_list[i]) - break; - if (i == MAX_W83781D_NR) { - printk("w83781d.o: No empty slots left, recompile and heighten " - "MAX_W83781D_NR!\n"); - return -ENOMEM; - } - - w83781d_list[i] = new_client; - new_client->id = i; - new_client->adapter = adapter; - new_client->driver = &w83781d_driver; - data = new_client->data; - data->valid = 0; - data->lock = MUTEX; - data->update_lock = MUTEX; - return 0; -} - -/* Inverse of w83781d_new_client */ -void w83781d_remove_client(struct i2c_client *client) -{ - int i; - for (i = 0; i < MAX_W83781D_NR; i++) - if (client == w83781d_list[i]) - w83781d_list[i] = NULL; -} - -/* No commands defined yet */ -int w83781d_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - return 0; -} - -void w83781d_inc_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif -} - -void w83781d_dec_use (struct i2c_client *client) -{ -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif -} - - -/* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitely! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -int w83781d_read_value(struct i2c_client *client, u16 reg) -{ - int res,word_sized; - - word_sized = (reg & 0xff00) && (((reg & 0x00ff) == 0x50) || - ((reg & 0x00ff) == 0x53) || - ((reg & 0x00ff) == 0x55)); - down((struct semaphore *) (client->data)); - if (i2c_is_isa_client(client)) { - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK,(((struct isa_client *) client)->isa_addr) + - W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8,(((struct isa_client *) client)->isa_addr) + - W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff,(((struct isa_client *) client)->isa_addr) + - W83781D_ADDR_REG_OFFSET); - res = inb_p((((struct isa_client *) client)->isa_addr) + - W83781D_DATA_REG_OFFSET); - if (word_sized) { - outb_p((reg & 0xff)+1,(((struct isa_client *) client)->isa_addr) + - W83781D_ADDR_REG_OFFSET); - res = (res << 8) + inb_p((((struct isa_client *) client)->isa_addr) + - W83781D_DATA_REG_OFFSET); - } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK,(((struct isa_client *) client)->isa_addr) + - W83781D_ADDR_REG_OFFSET); - outb_p(0,(((struct isa_client *) client)->isa_addr) + - W83781D_DATA_REG_OFFSET); - } - } else { - if (reg & 0xff00) - smbus_write_byte_data(client->adapter,client->addr,W83781D_REG_BANK, - reg >> 8); - res = smbus_read_byte_data(client->adapter,client->addr, reg); - if (word_sized) - res = (res << 8) + smbus_read_byte_data(client->adapter,client->addr, - reg); - if (reg & 0xff00) - smbus_write_byte_data(client->adapter,client->addr,W83781D_REG_BANK,0); - } - up((struct semaphore *) (client->data)); - return res; -} - -/* The SMBus locks itself, usually, but nothing may access the Winbond between - bank switches. ISA access must always be locked explicitely! - We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, - would slow down the W83781D access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) -{ - int word_sized; - - word_sized = (reg & 0xff00) && (((reg & 0x00ff) == 0x50) || - ((reg & 0x00ff) == 0x53) || - ((reg & 0x00ff) == 0x55)); - down((struct semaphore *) (client->data)); - if (i2c_is_isa_client(client)) { - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK,(((struct isa_client *) client)->isa_addr) + - W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8,(((struct isa_client *) client)->isa_addr) + - W83781D_DATA_REG_OFFSET); - } - outb_p(reg & 0xff,(((struct isa_client *) client)->isa_addr) + - W83781D_ADDR_REG_OFFSET); - if (word_sized) { - outb_p(value >> 8,(((struct isa_client *) client)->isa_addr) + - W83781D_DATA_REG_OFFSET); - outb_p((reg & 0xff)+1,(((struct isa_client *) client)->isa_addr) + - W83781D_ADDR_REG_OFFSET); - } - outb_p(value &0xff,(((struct isa_client *) client)->isa_addr) + - W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK,(((struct isa_client *) client)->isa_addr) + - W83781D_ADDR_REG_OFFSET); - outb_p(0,(((struct isa_client *) client)->isa_addr) + - W83781D_DATA_REG_OFFSET); - } - } else { - if (reg & 0xff00) - smbus_write_byte_data(client->adapter,client->addr,W83781D_REG_BANK, - reg >> 8); - if (word_sized) { - smbus_write_byte_data(client->adapter,client->addr, reg, value >> 8); - smbus_write_byte_data(client->adapter,client->addr, reg+1, value &0xff); - } else - smbus_write_byte_data(client->adapter,client->addr, reg, value &0xff); - if (reg & 0xff00) - smbus_write_byte_data(client->adapter,client->addr,W83781D_REG_BANK,0); - } - up((struct semaphore *) (client->data)); - return 0; -} - -/* Called when we have found a new W83781D. It should set limits, etc. */ -void w83781d_init_client(struct i2c_client *client) -{ - int vid; - - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ - w83781d_write_value(client,W83781D_REG_CONFIG,0x80); - - vid = w83781d_read_value(client,W83781D_REG_VID_FANDIV) & 0x0f; - vid |= (w83781d_read_value(client,W83781D_REG_CHIPID) & 0x01) >> 4; - vid = VID_FROM_REG(vid); - - w83781d_write_value(client,W83781D_REG_IN_MIN(0), - IN_TO_REG(W83781D_INIT_IN_MIN_0,0)); - w83781d_write_value(client,W83781D_REG_IN_MAX(0), - IN_TO_REG(W83781D_INIT_IN_MAX_0,0)); - w83781d_write_value(client,W83781D_REG_IN_MIN(1), - IN_TO_REG(W83781D_INIT_IN_MIN_1,1)); - w83781d_write_value(client,W83781D_REG_IN_MAX(1), - IN_TO_REG(W83781D_INIT_IN_MAX_1,1)); - w83781d_write_value(client,W83781D_REG_IN_MIN(2), - IN_TO_REG(W83781D_INIT_IN_MIN_2,2)); - w83781d_write_value(client,W83781D_REG_IN_MAX(2), - IN_TO_REG(W83781D_INIT_IN_MAX_2,2)); - w83781d_write_value(client,W83781D_REG_IN_MIN(3), - IN_TO_REG(W83781D_INIT_IN_MIN_3,3)); - w83781d_write_value(client,W83781D_REG_IN_MAX(3), - IN_TO_REG(W83781D_INIT_IN_MAX_3,3)); - w83781d_write_value(client,W83781D_REG_IN_MIN(4), - IN_TO_REG(W83781D_INIT_IN_MIN_4,4)); - w83781d_write_value(client,W83781D_REG_IN_MAX(4), - IN_TO_REG(W83781D_INIT_IN_MAX_4,4)); - w83781d_write_value(client,W83781D_REG_IN_MIN(5), - IN_TO_REG(W83781D_INIT_IN_MIN_5,5)); - w83781d_write_value(client,W83781D_REG_IN_MAX(5), - IN_TO_REG(W83781D_INIT_IN_MAX_5,5)); - w83781d_write_value(client,W83781D_REG_IN_MIN(6), - IN_TO_REG(W83781D_INIT_IN_MIN_6,6)); - w83781d_write_value(client,W83781D_REG_IN_MAX(6), - IN_TO_REG(W83781D_INIT_IN_MAX_6,6)); - w83781d_write_value(client,W83781D_REG_FAN_MIN(1), - FAN_TO_REG(W83781D_INIT_FAN_MIN_1,2)); - w83781d_write_value(client,W83781D_REG_FAN_MIN(2), - FAN_TO_REG(W83781D_INIT_FAN_MIN_2,2)); - w83781d_write_value(client,W83781D_REG_FAN_MIN(3), - FAN_TO_REG(W83781D_INIT_FAN_MIN_3,2)); - - w83781d_write_value(client,W83781D_REG_TEMP_OVER, - TEMP_TO_REG(W83781D_INIT_TEMP_OVER)); - w83781d_write_value(client,W83781D_REG_TEMP_HYST, - TEMP_TO_REG(W83781D_INIT_TEMP_HYST)); - w83781d_write_value(client,W83781D_REG_TEMP_CONFIG,0x00); - - w83781d_write_value(client,W83781D_REG_TEMP2_OVER, - TEMP_ADD_TO_REG(W83781D_INIT_TEMP2_OVER)); - w83781d_write_value(client,W83781D_REG_TEMP2_HYST, - TEMP_ADD_TO_REG(W83781D_INIT_TEMP2_HYST)); - w83781d_write_value(client,W83781D_REG_TEMP2_CONFIG,0x00); - - w83781d_write_value(client,W83781D_REG_TEMP3_OVER, - TEMP_ADD_TO_REG(W83781D_INIT_TEMP3_OVER)); - w83781d_write_value(client,W83781D_REG_TEMP3_HYST, - TEMP_ADD_TO_REG(W83781D_INIT_TEMP3_HYST)); - w83781d_write_value(client,W83781D_REG_TEMP3_CONFIG,0x00); - - /* Start monitoring */ - w83781d_write_value(client,W83781D_REG_CONFIG, - (w83781d_read_value(client, - W83781D_REG_CONFIG) & 0xf7) | 0x01); -} - -void w83781d_update_client(struct i2c_client *client) -{ - struct w83781d_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("Starting w83781d update\n"); -#endif - for (i = 0; i <= 6; i++) { - data->in[i] = w83781d_read_value(client,W83781D_REG_IN(i)); - data->in_min[i] = w83781d_read_value(client,W83781D_REG_IN_MIN(i)); - data->in_max[i] = w83781d_read_value(client,W83781D_REG_IN_MAX(i)); - } - for (i = 1; i <= 3; i++) { - data->fan[i-1] = w83781d_read_value(client,W83781D_REG_FAN(i)); - data->fan_min[i-1] = w83781d_read_value(client,W83781D_REG_FAN_MIN(i)); - } - data->temp = w83781d_read_value(client,W83781D_REG_TEMP); - data->temp_over = w83781d_read_value(client,W83781D_REG_TEMP_OVER); - data->temp_hyst = w83781d_read_value(client,W83781D_REG_TEMP_HYST); - data->temp_add[0] = w83781d_read_value(client,W83781D_REG_TEMP2); - data->temp_add_over[0] = w83781d_read_value(client,W83781D_REG_TEMP2_OVER); - data->temp_add_hyst[0] = w83781d_read_value(client,W83781D_REG_TEMP2_HYST); - data->temp_add[1] = w83781d_read_value(client,W83781D_REG_TEMP3); - data->temp_add_over[1] = w83781d_read_value(client,W83781D_REG_TEMP3_OVER); - data->temp_add_hyst[1] = w83781d_read_value(client,W83781D_REG_TEMP3_HYST); - i = w83781d_read_value(client,W83781D_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (w83781d_read_value(client,W83781D_REG_CHIPID) & 0x01) << 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; - data->fan_div[2] = (w83781d_read_value(client,W83781D_REG_PIN) >> 6) & 0x03; - data->alarms = w83781d_read_value(client,W83781D_REG_ALARM1) + - (w83781d_read_value(client,W83781D_REG_ALARM2) << 8); - i = w83781d_read_value(client,W83781D_REG_BEEP_INTS2); - data->beep_enable = i >> 7; - data->beeps = ((i & 0x7f) << 8) + - w83781d_read_value(client,W83781D_REG_BEEP_INTS1); - 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 date - 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 w83781d_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_IN0; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = IN_FROM_REG(data->in_min[nr],nr); - results[1] = IN_FROM_REG(data->in_max[nr],nr); - results[2] = IN_FROM_REG(data->in[nr],nr); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->in_min[nr] = IN_TO_REG(results[0],nr); - w83781d_write_value(client,W83781D_REG_IN_MIN(nr),data->in_min[nr]); - } - if (*nrels_mag >= 2) { - data->in_max[nr] = IN_TO_REG(results[1],nr); - w83781d_write_value(client,W83781D_REG_IN_MAX(nr),data->in_max[nr]); - } - } -} - -void w83781d_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_FAN1 + 1; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr-1], - DIV_FROM_REG(data->fan_div[nr-1])); - results[1] = FAN_FROM_REG(data->fan[nr-1], - DIV_FROM_REG(data->fan_div[nr-1])); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->fan_min[nr-1] = FAN_TO_REG(results[0], - DIV_FROM_REG(data->fan_div[nr-1])); - w83781d_write_value(client,W83781D_REG_FAN_MIN(nr),data->fan_min[nr-1]); - } - } -} - - -void w83781d_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - w83781d_write_value(client,W83781D_REG_TEMP_OVER,data->temp_over); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - w83781d_write_value(client,W83781D_REG_TEMP_HYST,data->temp_hyst); - } - } -} - - -void w83781d_temp_add(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int nr = ctl_name - W83781D_SYSCTL_TEMP2; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = TEMP_ADD_FROM_REG(data->temp_add_over[nr]); - results[1] = TEMP_ADD_FROM_REG(data->temp_add_hyst[nr]); - results[2] = TEMP_ADD_FROM_REG(data->temp_add[nr]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_add_over[nr] = TEMP_ADD_TO_REG(results[0]); - w83781d_write_value(client, - nr?W83781D_REG_TEMP3_OVER:W83781D_REG_TEMP2_OVER, - data->temp_add_over[nr]); - } - if (*nrels_mag >= 2) { - data->temp_add_hyst[nr] = TEMP_ADD_TO_REG(results[1]); - w83781d_write_value(client, - nr?W83781D_REG_TEMP3_HYST:W83781D_REG_TEMP2_HYST, - data->temp_add_hyst[nr]); - } - } -} - - -void w83781d_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; - } -} - -void w83781d_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = ALARMS_FROM_REG(data->alarms); - *nrels_mag = 1; - } -} - -void w83781d_beep(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int val; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable); - results[1] = BEEPS_FROM_REG(data->beeps); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 2) { - data->beeps = BEEPS_TO_REG(results[1]); - w83781d_write_value(client,W83781D_REG_BEEP_INTS1,data->beeps & 0xff); - val = data->beeps >> 8; - } else if (*nrels_mag >= 1) - val = w83781d_read_value(client,W83781D_REG_BEEP_INTS1) & 0x7f; - if (*nrels_mag >= 1) { - data->beep_enable = BEEP_ENABLE_TO_REG(results[0]); - w83781d_write_value(client,W83781D_REG_BEEP_INTS2, - val | data->beep_enable << 7); - } - } -} - -void w83781d_fan_div(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct w83781d_data *data = client->data; - int old; - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - w83781d_update_client(client); - results[0] = DIV_FROM_REG(data->fan_div[0]); - results[1] = DIV_FROM_REG(data->fan_div[1]); - results[2] = DIV_FROM_REG(data->fan_div[2]); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = w83781d_read_value(client,W83781D_REG_VID_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); - w83781d_write_value(client,W83781D_REG_VID_FANDIV,old); - } - if (*nrels_mag >= 3) { - data->fan_div[2] = DIV_TO_REG(results[2]); - w83781d_write_value(client,W83781D_REG_PIN, - w83781d_read_value(client,W83781D_REG_PIN)); - } - } -} - -int w83781d_init(void) -{ - int res; - - printk("w83781d.o version %s (%s)\n",LM_VERSION,LM_DATE); - w83781d_initialized = 0; - - if ((res =i2c_add_driver(&w83781d_driver))) { - printk("w83781d.o: Driver registration failed, module not inserted.\n"); - w83781d_cleanup(); - return res; - } - w83781d_initialized ++; - return 0; -} - -int w83781d_cleanup(void) -{ - int res; - - if (w83781d_initialized >= 1) { - if ((res = i2c_del_driver(&w83781d_driver))) { - printk("w83781d.o: Driver deregistration failed, module not removed.\n"); - return res; - } - w83781d_initialized --; - } - return 0; -} - - -#ifdef MODULE - -MODULE_AUTHOR("Frodo Looijaard and Philip Edelbrock "); -MODULE_DESCRIPTION("W83781D driver"); - -int init_module(void) -{ - return w83781d_init(); -} - -int cleanup_module(void) -{ - return w83781d_cleanup(); -} - -#endif /* MODULE */ -