From 2e4f1476477570dcd7eba710406032787c9e2cf6 Mon Sep 17 00:00:00 2001 From: Frodo Looijaard Date: Tue, 8 Dec 1998 22:52:05 +0000 Subject: [PATCH] Introduced /proc/sys/dev/sensors/chips file See doc/sysctl for an explanation why it is needed. Also fixed two very small cleanup bugs in lm75/lm78, which would probably be impossible to trigger anyway, but still. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@51 7894878c-1315-0410-8ee3-d5d059ff63e0 --- TODO | 3 -- doc/sysctl | 11 +++++ kernel/chips/lm75.c | 2 +- kernel/chips/lm78.c | 3 +- kernel/include/sensors.h | 10 ++++- kernel/sensors.c | 97 +++++++++++++++++++++++++++++++++++++++- src/lm75.c | 2 +- src/lm78.c | 3 +- src/sensors.c | 97 +++++++++++++++++++++++++++++++++++++++- src/sensors.h | 10 ++++- 10 files changed, 225 insertions(+), 13 deletions(-) create mode 100644 doc/sysctl diff --git a/TODO b/TODO index c2a460de..d838242e 100644 --- a/TODO +++ b/TODO @@ -10,9 +10,6 @@ Many, many things. Most notably: * Make it SMP-safe: there are no spinlocks yet. They are needed at many places, probably (everywhere where global vars are accessed). This must be done for the i2c modules, too. -* Extend sensors.c with a file /proc/sys/dev/sensors/chips, which lists - all directories under /proc/sys/dev/sensors with their SYSCTL id - (needed for good sysctl access). * Extend the mod_inc_use/mod_dec_use through the fill_inode trick, for all new /proc files. * Make lm78.c detect 'double hits', (same chip connected to both SMBus and diff --git a/doc/sysctl b/doc/sysctl new file mode 100644 index 00000000..13c057f1 --- /dev/null +++ b/doc/sysctl @@ -0,0 +1,11 @@ +You can access everything under /proc/sys through the sysctl interface. This +is mostly useful for C programs, which can use the sysctl function. Try +'man 2 sysctl' for more information. + +As each chip gets its own directory under /proc/sys/dev/sensors, you must +somehow know the sysctl id of these directories to access the sensor data. +This is done through the file /proc/sys/dev/sensors/chips (see sensors.h +for the corresponding SYSCTL ids). You can only read this file; it +returns an array of struct sensors_chips_data, as defined in sensors.h. +Each chip will have its own entry here, with both its sysctl id and +the corresponding /proc name. diff --git a/kernel/chips/lm75.c b/kernel/chips/lm75.c index 1a17ad20..c8b03e67 100644 --- a/kernel/chips/lm75.c +++ b/kernel/chips/lm75.c @@ -331,8 +331,8 @@ int lm75_cleanup(void) printk("lm75.o: Driver deregistration failed, module not removed.\n"); return res; } - } else lm75_initialized --; + } return 0; } diff --git a/kernel/chips/lm78.c b/kernel/chips/lm78.c index cc8af03e..e20db28b 100644 --- a/kernel/chips/lm78.c +++ b/kernel/chips/lm78.c @@ -878,9 +878,8 @@ int lm78_cleanup(void) printk("lm78.o: Driver deregistration failed, module not removed.\n"); return res; } - } else lm78_initialized --; - + } return 0; } diff --git a/kernel/include/sensors.h b/kernel/include/sensors.h index 4eae2cb4..d322debf 100644 --- a/kernel/include/sensors.h +++ b/kernel/include/sensors.h @@ -73,10 +73,12 @@ 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_I2CPROC 1001 #define I2C_DRIVERID_LM78 1002 @@ -90,6 +92,12 @@ extern void sensors_deregister_entry(int id); 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 diff --git a/kernel/sensors.c b/kernel/sensors.c index 90845f9d..bf9056a0 100644 --- a/kernel/sensors.c +++ b/kernel/sensors.c @@ -41,6 +41,11 @@ 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); @@ -63,6 +68,27 @@ static ctl_table sysctl_table[] = { { 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). @@ -207,6 +233,68 @@ void sensors_fill_inode(struct inode *inode, int fill) } #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, @@ -263,7 +351,6 @@ int sensors_proc_real(ctl_table *ctl, int write, struct file * filp, /* And write them to buffer, converting to reals */ sensors_write_reals(nrels,buffer,lenp,results,mag); - sensors_write_reals(nrels,buffer,lenp,results,mag); filp->f_pos += *lenp; return 0; } @@ -477,11 +564,19 @@ void sensors_write_reals(int nrels,void *buffer,int *bufsize,long *results, 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; + sensors_initialized ++; return 0; } int sensors_cleanup(void) { + if (sensors_initialized >= 1) { + unregister_sysctl_table(sensors_proc_header); + sensors_initialized --; + } return 0; } diff --git a/src/lm75.c b/src/lm75.c index 1a17ad20..c8b03e67 100644 --- a/src/lm75.c +++ b/src/lm75.c @@ -331,8 +331,8 @@ int lm75_cleanup(void) printk("lm75.o: Driver deregistration failed, module not removed.\n"); return res; } - } else lm75_initialized --; + } return 0; } diff --git a/src/lm78.c b/src/lm78.c index cc8af03e..e20db28b 100644 --- a/src/lm78.c +++ b/src/lm78.c @@ -878,9 +878,8 @@ int lm78_cleanup(void) printk("lm78.o: Driver deregistration failed, module not removed.\n"); return res; } - } else lm78_initialized --; - + } return 0; } diff --git a/src/sensors.c b/src/sensors.c index 90845f9d..bf9056a0 100644 --- a/src/sensors.c +++ b/src/sensors.c @@ -41,6 +41,11 @@ 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); @@ -63,6 +68,27 @@ static ctl_table sysctl_table[] = { { 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). @@ -207,6 +233,68 @@ void sensors_fill_inode(struct inode *inode, int fill) } #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, @@ -263,7 +351,6 @@ int sensors_proc_real(ctl_table *ctl, int write, struct file * filp, /* And write them to buffer, converting to reals */ sensors_write_reals(nrels,buffer,lenp,results,mag); - sensors_write_reals(nrels,buffer,lenp,results,mag); filp->f_pos += *lenp; return 0; } @@ -477,11 +564,19 @@ void sensors_write_reals(int nrels,void *buffer,int *bufsize,long *results, 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; + sensors_initialized ++; return 0; } int sensors_cleanup(void) { + if (sensors_initialized >= 1) { + unregister_sysctl_table(sensors_proc_header); + sensors_initialized --; + } return 0; } diff --git a/src/sensors.h b/src/sensors.h index 4eae2cb4..d322debf 100644 --- a/src/sensors.h +++ b/src/sensors.h @@ -73,10 +73,12 @@ 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_I2CPROC 1001 #define I2C_DRIVERID_LM78 1002 @@ -90,6 +92,12 @@ extern void sensors_deregister_entry(int id); 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