From 730efd78ca9dd93911817ba4d5c0ef6f1c8412fb Mon Sep 17 00:00:00 2001 From: Frodo Looijaard Date: Sun, 20 Dec 1998 16:54:03 +0000 Subject: [PATCH] More library files This brings the archive into synch with my harddisk... Everything in the lib directory should compile without problems (yes, even without warnings even if WARN=1). It is not well-tested, though, and there are some minor functions which must still be added. It is now almost usable. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@95 7894878c-1315-0410-8ee3-d5d059ff63e0 --- lib/Module.mk | 8 +- lib/access.c | 207 +++++++++++++++++++++++++++++++++++++++++++ lib/access.h | 25 ++++++ lib/chips.c | 2 +- lib/data.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/data.h | 121 +++++++++++++++++++++++++ lib/general.c | 1 + lib/proc.c | 128 +++++++++++++++++++++++++++ lib/proc.h | 34 +++++++ lib/sensors.h | 70 +++++++++++++++ 10 files changed, 832 insertions(+), 4 deletions(-) create mode 100644 lib/access.c create mode 100644 lib/data.c create mode 100644 lib/data.h create mode 100644 lib/proc.c create mode 100644 lib/proc.h create mode 100644 lib/sensors.h diff --git a/lib/Module.mk b/lib/Module.mk index 94ee3f63..8b534b6d 100644 --- a/lib/Module.mk +++ b/lib/Module.mk @@ -35,12 +35,14 @@ LIBSHSONAME := libsensors.so.$(LIBMAINVER) LIBTARGETS := $(MODULE_DIR)/$(LIBSTLIBNAME) $(MODULE_DIR)/$(LIBSHLIBNAME) LIBCSOURCES := $(MODULE_DIR)/data.c $(MODULE_DIR)/general.c \ - $(MODULE_DIR)/error.c $(MODULE_DIR)/chips.c + $(MODULE_DIR)/error.c $(MODULE_DIR)/chips.c \ + $(MODULE_DIR)/proc.c $(MODULE_DIR)/access.c LIBOTHEROBJECTS := $(MODULE_DIR)/conf-parse.o $(MODULE_DIR)/conf-lex.o LIBSHOBJECTS := $(LIBCSOURCES:.c=.lo) $(LIBOTHEROBJECTS:.o=.lo) LIBSTOBJECTS := $(LIBCSOURCES:.c=.ao) $(LIBOTHEROBJECTS:.o=.ao) +LIBEXTRACLEAN := $(MODULE_DIR)/conf_parse.h -LIBHEADERFILES := $(MODULE_DIR)/error.h +LIBHEADERFILES := $(MODULE_DIR)/error.h $(MODULE_DIR)/sensors.h # How to create the shared library $(MODULE_DIR)/$(LIBSHLIBNAME): $(LIBSHOBJECTS) @@ -75,5 +77,5 @@ install :: install-lib clean-lib: $(RM) $(LIBTARGETS) $(LIBSHOBJECTS) $(LIBSTOBJECTS) $(RM) $(LIBSHOBJECTS:.lo=.ld) $(LIBSTOBJECTS:.ao=.ad) - $(RM) $(LIBOTHEROBJECTS:.o=.c) $(MODULE_DIR)/conf-parse.h + $(RM) $(LIBOTHEROBJECTS:.o=.c) $(LIBEXTRACLEAN) clean :: clean-lib diff --git a/lib/access.c b/lib/access.c new file mode 100644 index 00000000..f5568a47 --- /dev/null +++ b/lib/access.c @@ -0,0 +1,207 @@ +/* + access.c - Part of libsensors, a Linux library 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. +*/ + +#include +#include +#include "access.h" +#include "sensors.h" +#include "data.h" +#include "error.h" +#include "proc.h" + +/* Compare two chips name descriptions, to see whether they could match. + Return 0 if it does not match, return 1 if it does match. */ +int sensors_match_chip(sensors_chip_name chip1, sensors_chip_name chip2) +{ + if ((chip1.prefix != SENSORS_CHIP_NAME_PREFIX_ANY) && + (chip2.prefix != SENSORS_CHIP_NAME_PREFIX_ANY) && + strcmp(chip1.prefix,chip2.prefix)) + return 0; + if ((chip1.bus != SENSORS_CHIP_NAME_BUS_ANY) && + (chip2.bus != SENSORS_CHIP_NAME_BUS_ANY) && + (chip1.bus != chip2.bus)) { + if ((chip1.bus == SENSORS_CHIP_NAME_BUS_ISA) || + (chip2.bus == SENSORS_CHIP_NAME_BUS_ISA)) + return 0; + if ((chip1.bus != SENSORS_CHIP_NAME_BUS_ANY_I2C) && + (chip2.bus != SENSORS_CHIP_NAME_BUS_ANY_I2C)) + return 0; + } + if ((chip1.addr != chip2.addr) && + (chip1.addr != SENSORS_CHIP_NAME_ADDR_ANY) && + (chip2.addr != SENSORS_CHIP_NAME_ADDR_ANY)) + return 0; + return 1; +} + +/* Returns, one by one, a pointer to all sensor_chip structs of the + config file which match with the given chip name. Last should be + the value returned by the last call, or NULL if this is the first + call. Returns NULL if no more matches are found. Do not modify + the struct the return value points to! + Note that this visits the list of chips from last to first. Usually, + you want the match that was latest in the config file. */ +sensors_chip *sensors_for_all_config_chips(sensors_chip_name chip_name, + sensors_chip *last) +{ + int nr,i; + sensors_chip_name_list chips; + + for (nr = last?(last-sensors_config_chips)-1:sensors_config_chips_count-1; + nr >= 0; nr--) { + chips = sensors_config_chips[nr].chips; + for (i =0; i < chips.fits_count; i++) { + if (sensors_match_chip(chips.fits[i],chip_name)) + return sensors_config_chips+nr; + } + } + return NULL; +} + +/* Look up a resource in the intern chip list, and return a pointer to it. + Do not modify the struct the return value points to! Returns NULL if + not found.*/ +sensors_chip_feature *sensors_lookup_feature_nr(const char *prefix, int feature) +{ + int i,j; + sensors_chip_feature *features; + for (i = 0; sensors_chip_features_list[i].prefix; i++) + if (!strcmp(sensors_chip_features_list[i].prefix,prefix)) { + features = sensors_chip_features_list[i].feature; + for (j=0; features[j].name; j++) + if (features[j].number == feature) + return features + j; + } + return NULL; +} + +/* Look up a resource in the intern chip list, and return a pointer to it. + Do not modify the struct the return value points to! Returns NULL if + not found.*/ +sensors_chip_feature *sensors_lookup_feature_name(const char *prefix, + const char *feature) +{ + int i,j; + sensors_chip_feature *features; + for (i = 0; sensors_chip_features_list[i].prefix; i++) + if (!strcmp(sensors_chip_features_list[i].prefix,prefix)) { + features = sensors_chip_features_list[i].feature; + for (j=0; features[j].name; j++) + if (!strcmp(features[j].name,feature)) + return features + j; + } + return NULL; +} + + +/* Check whether the chip name is an 'absolute' name, which can only match + one chip, or whether it has wildcards. Returns 0 if it is absolute, 1 + if there are wildcards. */ +int sensors_chip_name_has_wildcards(sensors_chip_name chip) +{ + if ((chip.prefix == SENSORS_CHIP_NAME_PREFIX_ANY) || + (chip.bus == SENSORS_CHIP_NAME_BUS_ISA) || + (chip.bus == SENSORS_CHIP_NAME_BUS_ANY) || + (chip.bus == SENSORS_CHIP_NAME_BUS_ANY_I2C) || + (chip.bus == SENSORS_CHIP_NAME_ADDR_ANY)) + return 1; + else + return 0; +} + +/* Look up the label which belongs to this chip. Note that chip should not + contain wildcard values! *result is newly allocated (free it yourself). + This function will return 0 on success, and <0 on failure. */ +int sensors_get_label(sensors_chip_name name, int feature, char **result) +{ + sensors_chip *chip; + sensors_chip_feature *featureptr; + int i; + + if (sensors_chip_name_has_wildcards(name)) + return -SENSORS_ERR_WILDCARDS; + if (! (featureptr = sensors_lookup_feature_nr(name.prefix,feature))) + return -SENSORS_ERR_NO_ENTRY; + for (chip = NULL; (chip = sensors_for_all_config_chips(name,chip));) + for (i = 0; i < chip->labels_count; i++) + if (!strcmp(featureptr->name, chip->labels[i].name)) { + *result = strdup(chip->labels[i].name); + return 0; + } + *result = strdup(featureptr->name); + return 0; +} + +/* Read the value of a feature of a certain chip. Note that chip should not + contain wildcard values! This function will return 0 on success, and <0 + on failure. */ +int sensors_get_feature(sensors_chip_name name, int feature, double *result) +{ + sensors_chip_feature *featureptr; + sensors_chip *chip; + sensors_expr *expr = NULL; + double val; + int res,i; + + if (sensors_chip_name_has_wildcards(name)) + return -SENSORS_ERR_WILDCARDS; + if (! (featureptr = sensors_lookup_feature_nr(name.prefix,feature))) + return -SENSORS_ERR_NO_ENTRY; + if (! (featureptr->mode && SENSORS_R)) + return -SENSORS_ERR_ACCESS; + for (chip = NULL; !expr && (chip = sensors_for_all_config_chips(name,chip));) + for (i = 0; !expr && (i < chip->computes_count); i++) + if (!strcmp(featureptr->name,chip->computes->name)) + expr = chip->computes->from_proc; + if (sensors_read_proc(name,feature,&val)) + return -SENSORS_ERR_PROC; + if (! expr) + *result = val; + else if ((res = sensors_eval_expr(expr,val,result))) + return res; + return 0; +} + +/* Set the value of a feature of a certain chip. Note that chip should not + contain wildcard values! This function will return 0 on success, and <0 + on failure. */ +int sensors_set_value(sensors_chip_name name, int feature, double value) +{ + sensors_chip_feature *featureptr; + sensors_chip *chip; + sensors_expr *expr = NULL; + int i,res; + + if (sensors_chip_name_has_wildcards(name)) + return -SENSORS_ERR_WILDCARDS; + if (! (featureptr = sensors_lookup_feature_nr(name.prefix,feature))) + return -SENSORS_ERR_NO_ENTRY; + if (! (featureptr->mode && SENSORS_W)) + return -SENSORS_ERR_ACCESS; + for (chip = NULL; !expr && (chip = sensors_for_all_config_chips(name,chip));) + for (i = 0; !expr && (i < chip->computes_count); i++) + if (!strcmp(featureptr->name,chip->computes->name)) + expr = chip->computes->to_proc; + if (expr) + if ((res = sensors_eval_expr(expr,value,&value))) + return res; + if (sensors_write_proc(name,feature,value)) + return -SENSORS_ERR_PROC; + return 0; +} diff --git a/lib/access.h b/lib/access.h index 219d4bf3..097edf24 100644 --- a/lib/access.h +++ b/lib/access.h @@ -20,6 +20,9 @@ #ifndef LIB_SENSORS_ACCESS_H #define LIB_SENSORS_ACCESS_H +#include "sensors.h" +#include "data.h" + typedef struct sensors_chip_feature { int number; const char *name; @@ -45,4 +48,26 @@ typedef struct sensors_chip_features { extern sensors_chip_features sensors_chip_features_list[]; +/* Returns, one by one, a pointer to all sensor_chip structs of the + config file which match with the given chip name. Last should be + the value returned by the last call, or NULL if this is the first + call. Returns NULL if no more matches are found. Do not modify + the struct the return value points to! + Note that this visits the list of chips from last to first. Usually, + you want the match that was latest in the config file. */ +extern sensors_chip *sensors_for_all_config_chips(sensors_chip_name chip_name, + sensors_chip *last); + +/* Look up a resource in the intern chip list, and return a pointer to it. + Do not modify the struct the return value points to! Returns NULL if + not found. */ +extern sensors_chip_feature *sensors_lookup_feature_nr(const char *prefix, + int feature); + +/* Look up a resource in the intern chip list, and return a pointer to it. + Do not modify the struct the return value points to! Returns NULL if + not found.*/ +extern sensors_chip_feature *sensors_lookup_feature_name(const char *prefix, + const char *feature); + #endif /* def LIB_SENSORS_ACCESS_H */ diff --git a/lib/chips.c b/lib/chips.c index 40078f5b..de510c34 100644 --- a/lib/chips.c +++ b/lib/chips.c @@ -35,7 +35,7 @@ divided. */ -#define VALUE(x) (x-1) * sizeof(double) +#define VALUE(x) (x-1) * sizeof(long) static sensors_chip_feature lm78_features[] = { diff --git a/lib/data.c b/lib/data.c new file mode 100644 index 00000000..0e78b4b1 --- /dev/null +++ b/lib/data.c @@ -0,0 +1,240 @@ +/* + data.c - Part of libsensors, a Linux library 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. +*/ + +#include +#include + +#include "error.h" +#include "data.h" +#include "sensors.h" + +sensors_chip *sensors_config_chips = NULL; +int sensors_config_chips_count = 0; +int sensors_config_chips_max = 0; + +sensors_bus *sensors_config_busses = NULL; +int sensors_config_busses_count = 0; +int sensors_config_busses_max = 0; + + +/* Wow, this must be one of the ugliest functions I have ever written. + The idea is that it parses a chip name. These are valid names: + + lm78-i2c-10-5e *-i2c-10-5e + lm78-i2c-10-* *-i2c-10-* + lm78-i2c-*-5e *-i2c-*-5e + lm78-i2c-*-* *-i2c-*-* + lm78-isa-10dd *-isa-10dd + lm78-isa-* *-isa-* + lm78-* *-* + * + Here 'lm78' can be any prefix. To complicate matters, such a prefix + can also contain dashes (like lm78-j, for example!). 'i2c' and 'isa' are + literal strings, just like all dashes '-' and wildcards '*'. '10' can + be any decimal i2c bus number. '5e' can be any hexadecimal i2c device + address, and '10dd' any hexadecimal isa address. + + If '*' is used in prefixes, together with dashes, ambigious parses are + introduced. In that case, the prefix is kept as small as possible. + + The 'prefix' part in the result is freshly allocated. All old contents + of res is overwritten. res itself is not allocated. In case of an error + return (ie. != 0), res is undefined, but all allocations are undone. + + Don't tell me there are bugs in here, because I'll start screaming :-) +*/ + +int sensors_parse_chip_name(const char *orig_name, sensors_chip_name *res) +{ + char *part2, *part3, *part4; + char *name = strdup(orig_name); + int i; + + /* First split name in upto four pieces. */ + if ((part4 = strrchr(name,'-'))) + *part4++ = '\0'; + if ((part3 = strrchr(name,'-'))) + *part3++ = '\0'; + if ((part2 = strrchr(name,'-'))) + *part2++ = '\0'; + + /* No dashes found? */ + if (! part4) { + if (!strcmp(name,"*")) { + res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY; + res->bus = SENSORS_CHIP_NAME_BUS_ANY; + res->addr = SENSORS_CHIP_NAME_ADDR_ANY; + goto SUCCES; + } else + goto ERROR; + } + + /* At least one dash found. Now part4 is either '*', or an address */ + if (!strcmp(part4,"*")) + res->addr = SENSORS_CHIP_NAME_ADDR_ANY; + else { + if ((strlen(part4) > 4) || (strlen(part4) == 0)) + goto ERROR; + res->addr = 0; + for (i = 0; ; i++) { + switch (part4[i]) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + res->addr = res->addr * 16 + part4[i] - '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + res->addr = res->addr * 16 + part4[i] - 'a' + 10; + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + res->addr = res->addr * 16 + part4[i] - 'A' + 10; + break; + case 0: + goto DONE; + default: + goto ERROR; + } + } +DONE: + } + + /* OK. So let's look at part3. It must either be the number of the + i2c bus (and then part2 *must* be "i2c"), or it must be "isa", + or, if part4 was "*", it belongs to 'prefix'. Or no second dash + was found at all, of course. */ + if (! part3) { + if (res->addr == SENSORS_CHIP_NAME_ADDR_ANY) { + res->bus = SENSORS_CHIP_NAME_BUS_ANY; + } else + goto ERROR; + } else if (!strcmp(part3,"isa")) { + res->bus = SENSORS_CHIP_NAME_BUS_ISA; + if (part2) + *(part2-1) = '-'; + } else if (part2 && !strcmp(part2,"i2c") && !strcmp(part3,"*")) + res->bus = SENSORS_CHIP_NAME_BUS_ANY_I2C; + else if (part2 && !strcmp(part2,"i2c")) { + if ((strlen(part3) > 3) || (strlen(part3) == 0)) + goto ERROR; + res->bus = 0; + for (i = 0; ; i++) { + switch (part3[i]) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + res->bus = res->bus * 10 + part3[i] - '0'; + break; + case 0: + goto DONE2; + default: + goto ERROR; + } + } +DONE2: + } else if (res->addr == SENSORS_CHIP_NAME_ADDR_ANY) { + res->bus = SENSORS_CHIP_NAME_BUS_ANY; + if (part2) + *(part2-1) = '-'; + *(part3-1) = '-'; + } else + goto ERROR; + + if (!strcmp(name,"*")) + res->prefix = SENSORS_CHIP_NAME_PREFIX_ANY; + else + res->prefix = strdup(name); + goto SUCCES; + +SUCCES: + free(name); + return 0; + +ERROR: + free(name); + return -SENSORS_ERR_CHIP_NAME; +} + +int sensors_parse_i2cbus_name(const char *name, int *res) +{ + int i; + + if (! strcmp(name,"isa")) { + *res = SENSORS_CHIP_NAME_BUS_ISA; + return 0; + } + if (strncmp(name,"i2c-",4)) + return -1; + name += 4; + if ((strlen(name) > 3) || (strlen(name) == 0)) + return -SENSORS_ERR_BUS_NAME; + *res = 0; + for (i = 0; ; i++) { + switch (name[i]) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + *res = *res * 10 + name[i] - '0'; + break; + case 0: + return 0; + default: + return -SENSORS_ERR_BUS_NAME; + } + } +} + +int sensors_eval_expr(sensors_expr *expr, double val, double *result) +{ + double res1,res2; + int res; + + if (expr->kind == sensors_kind_val) { + *result = expr->data.val; + return 0; + } + if (expr->kind == sensors_kind_var) { + /* We should check the kind of variable here! */ + *result = val; + return 0; + } + if ((res = sensors_eval_expr(expr->data.subexpr.sub1,val,&res1))) + return res; + if (expr->data.subexpr.sub2 && + (res = sensors_eval_expr(expr->data.subexpr.sub2,val,&res2))) + return res; + switch(expr->data.subexpr.op) { + case sensors_add: + *result = res1 + res2; + return 0; + case sensors_sub: + *result = res1 - res2; + return 0; + case sensors_multiply: + *result = res1 * res2; + return 0; + case sensors_divide: + if (res2 == 0.0) + return -SENSORS_ERR_DIV_ZERO; + *result = res1 / res2; + return 0; + case sensors_negate: + *result = -res1; + return 0; + } + return 0; +} + + diff --git a/lib/data.h b/lib/data.h new file mode 100644 index 00000000..24ff9646 --- /dev/null +++ b/lib/data.h @@ -0,0 +1,121 @@ +/* + data.h - Part of libsensors, a Linux library 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. +*/ + +#ifndef LIB_SENSORS_DATA_H +#define LIB_SENSORS_DATA_H + +#include "sensors.h" + +/* This header file contains all kinds of data structures which are + internally used. */ + +typedef enum sensors_operation { + sensors_add, sensors_sub, sensors_multiply, sensors_divide, + sensors_negate } sensors_operation; + +typedef enum sensors_expr_kind { + sensors_kind_val, sensors_kind_var, sensors_kind_sub } sensors_expr_kind; + +struct sensors_expr; + +typedef struct sensors_subexpr { + sensors_operation op; + struct sensors_expr *sub1; + struct sensors_expr *sub2; +} sensors_subexpr; + +typedef struct sensors_expr { + sensors_expr_kind kind; + union { + double val; + char *var; + sensors_subexpr subexpr; + } data; +} sensors_expr; + + +typedef struct sensors_label { + char *name; + char *value; +} sensors_label; + +typedef struct sensors_set { + char *name; + sensors_expr *value; +} sensors_set; + +typedef struct sensors_compute { + char *name; + sensors_expr *from_proc; + sensors_expr *to_proc; +} sensors_compute; + +typedef struct sensors_chip_name_list { + sensors_chip_name *fits; + int fits_count; + int fits_max; +} sensors_chip_name_list; + +typedef struct sensors_chip { + sensors_chip_name_list chips; + sensors_label *labels; + int labels_count; + int labels_max; + sensors_set *sets; + int sets_count; + int sets_max; + sensors_compute *computes; + int computes_count; + int computes_max; +} sensors_chip; + +typedef enum sensors_bus_type {sensors_i2c, sensors_isa, + sensors_smbus } sensors_bus_type; + +typedef struct sensors_bus { + int number; + char *adapter; + char *algorithm; +} sensors_bus; + +typedef struct sensors_proc_chips_entry { + int sysctl; + sensors_chip_name name; +} sensors_proc_chips_entry; + +extern sensors_chip *sensors_config_chips; +extern int sensors_config_chips_count; +extern int sensors_config_chips_max; + +extern sensors_bus *sensors_config_busses; +extern int sensors_config_busses_count; +extern int sensors_config_busses_max; + +extern sensors_proc_chips_entry *sensors_proc_chips; +extern int sensors_proc_chips_count; +extern int sensors_proc_chips_max; + +/* Parse an i2c bus name into its components. Returns 0 on succes, a value from + error.h on failure. */ +extern int sensors_parse_i2cbus_name(const char *name, int *res); + +extern int sensors_eval_expr(sensors_expr *expr, double val, double *result); + + +#endif /* def LIB_SENSORS_DATA_H */ diff --git a/lib/general.c b/lib/general.c index 2f8700cf..39c9b4bf 100644 --- a/lib/general.c +++ b/lib/general.c @@ -17,6 +17,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "error.h" #include "general.h" #include #include diff --git a/lib/proc.c b/lib/proc.c new file mode 100644 index 00000000..faac3c23 --- /dev/null +++ b/lib/proc.c @@ -0,0 +1,128 @@ +/* + proc.c - Part of libsensors, a Linux library 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. +*/ + +#include +#include +#include +#include "src/sensors.h" +#include "data.h" +#include "error.h" +#include "access.h" +#include "general.h" + +/* OK, this proves one thing: if there are too many chips detected, we get in + trouble. The limit is around 4096/sizeof(struct sensors_chip_data), which + works out to about 100 entries right now. That seems sensible enough, + but if we ever get at the point where more chips can be detected, we must + enlarge buf, and check that sysctl can handle larger buffers. */ + +#define BUF_LEN 4096 + +static char buf[BUF_LEN]; + +static int sensors_get_chip_id(sensors_chip_name name); + +#define add_proc_chips(el) sensors_add_array_el(el,\ + (void **) &sensors_proc_chips,\ + &sensors_proc_chips_count,\ + &sensors_proc_chips_max,\ + sizeof(struct sensors_proc_chips_entry)) + +/* This reads /proc/sys/dev/sensors/chips into memory */ +int sensors_read_proc_chips(void) +{ + int name[3] = { CTL_DEV, DEV_SENSORS, SENSORS_CHIPS }; + int buflen = BUF_LEN; + char *bufptr = buf; + sensors_proc_chips_entry entry; + int res; + + if (sysctl(name, 3, bufptr, &buflen, NULL, 0)) + return -SENSORS_ERR_PROC; + + while (buflen >= sizeof(struct sensors_chips_data)) { + if ((res = + sensors_parse_chip_name(((struct sensors_chips_data *) bufptr)->name, + &entry.name))) + return res; + entry.sysctl = ((struct sensors_chips_data *) bufptr)->sysctl_id; + add_proc_chips(&entry); + bufptr += sizeof(struct sensors_chips_data); + buflen -= sizeof(struct sensors_chips_data); + } + return 0; +} + +/* This returns the first detected chip which matches the name */ +int sensors_get_chip_id(sensors_chip_name name) +{ + int i; + for (i = 0; i < sensors_proc_chips_count; i++) + if (sensors_match_chip(name, sensors_proc_chips[i].name)) + return sensors_proc_chips[i].sysctl; + return -SENSORS_ERR_NO_ENTRY; +} + +/* This reads a feature /proc file */ +int sensors_read_proc(sensors_chip_name name, int feature, double *value) +{ + int sysctl_name[4] = { CTL_DEV, DEV_SENSORS }; + sensors_chip_feature *the_feature; + int buflen = BUF_LEN; + int mag; + + if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0) + return sysctl_name[2]; + if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature))) + return -SENSORS_ERR_NO_ENTRY; + sysctl_name[3] = the_feature->sysctl; + if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0)) + return -SENSORS_ERR_PROC; + *value = *((long *) (buf + the_feature->offset)); + for (mag = the_feature->scaling; mag > 0; mag --) + *value /= 10.0; + for (; mag < 0; mag --) + *value *= 10.0; + return 0; +} + +int sensors_write_proc(sensors_chip_name name, int feature, double value) +{ + int sysctl_name[4] = { CTL_DEV, DEV_SENSORS }; + sensors_chip_feature *the_feature; + int buflen = BUF_LEN; + int mag; + + if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0) + return sysctl_name[2]; + if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature))) + return -SENSORS_ERR_NO_ENTRY; + sysctl_name[3] = the_feature->sysctl; + if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0)) + return -SENSORS_ERR_PROC; + for (mag = the_feature->scaling; mag > 0; mag --) + value *= 10.0; + for (; mag < 0; mag --) + value /= 10.0; + * ((long *) (buf + the_feature->offset)) = (long) value; + buflen = the_feature->offset + sizeof(long); + if (sysctl(sysctl_name, 4, NULL, 0, buf, buflen)) + return -SENSORS_ERR_PROC; + return 0; +} diff --git a/lib/proc.h b/lib/proc.h new file mode 100644 index 00000000..bbd0f1eb --- /dev/null +++ b/lib/proc.h @@ -0,0 +1,34 @@ +/* + proc.h - Part of libsensors, a Linux library 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. +*/ + +#ifndef SENSORS_LIB_PROC_H +#define SENSORS_LIB_PROC_H + +/* Read /proc/sys/dev/sensors/chips */ +extern int sensors_read_proc_chips(void); + +/* Read a value out of a /proc file */ +extern int sensors_read_proc(sensors_chip_name name, int feature, + double *value); + +/* Write a value to a /proc file */ +extern int sensors_write_proc(sensors_chip_name name, int feature, + double value); + +#endif diff --git a/lib/sensors.h b/lib/sensors.h new file mode 100644 index 00000000..0f5c04f9 --- /dev/null +++ b/lib/sensors.h @@ -0,0 +1,70 @@ +/* + sensors.h - Part of libsensors, a Linux library 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. +*/ + +#ifndef LIB_SENSORS_SENSORS_H +#define LIB_SENSORS_SENSORS_H + +/* Publicly accessible library functions */ + +#define SENSORS_CHIP_NAME_PREFIX_ANY NULL +#define SENSORS_CHIP_NAME_BUS_ISA -1 +#define SENSORS_CHIP_NAME_BUS_ANY -2 +#define SENSORS_CHIP_NAME_BUS_ANY_I2C -3 +#define SENSORS_CHIP_NAME_ADDR_ANY -1 + +typedef struct sensors_chip_name { + char *prefix; + int bus; + int addr; +} sensors_chip_name; + +/* Parse a chip name to the internal representation. Return 0 on succes, <0 + on error. */ +extern int sensors_parse_chip_name(const char *orig_name, + sensors_chip_name *res); + +/* Compare two chips name descriptions, to see whether they could match. + Return 0 if it does not match, return 1 if it does match. */ +extern int sensors_match_chip(sensors_chip_name chip1, + sensors_chip_name chip2); + +/* Check whether the chip name is an 'absolute' name, which can only match + one chip, or whether it has wildcards. Returns 0 if it is absolute, 1 + if there are wildcards. */ +extern int sensors_chip_name_has_wildcards(sensors_chip_name chip); + +/* Look up the label which belongs to this chip. Note that chip should not + contain wildcard values! *result is newly allocated (free it yourself). + This function will return 0 on success, and <0 on failure. */ +extern int sensors_get_label(sensors_chip_name name, int feature, + char **result); + +/* Read the value of a feature of a certain chip. Note that chip should not + contain wildcard values! This function will return 0 on success, and <0 + on failure. */ +extern int sensors_get_feature(sensors_chip_name name, int feature, + double *result); + +/* Set the value of a feature of a certain chip. Note that chip should not + contain wildcard values! This function will return 0 on success, and <0 + on failure. */ +extern int sensors_set_value(sensors_chip_name name, int feature, + double value); + +#endif /* def LIB_SENSORS_ERROR_H */