root/lm-sensors/branches/lm-sensors-3.0.0/lib/access.c @ 4366

Revision 4366, 18.5 KB (checked in by jwrdegoede, 8 years ago)

Generic chip support / get featuretype fixes just received from Bob Schlarmann, as the version I committed wasn't the latest version

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    access.c - Part of libsensors, a Linux library for reading sensor data.
3    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20#include <stdlib.h>
21#include <string.h>
22#include <math.h>
23#include <regex.h>
24#include "access.h"
25#include "sensors.h"
26#include "data.h"
27#include "error.h"
28#include "proc.h"
29#include "general.h"
30
31#define GET_TYPE_REGEX "\\([[:alpha:]]\\{1,\\}\\)[[:digit:]]\\{0,\\}\\(_\\([[:alpha:]]\\{1,\\}\\)\\)\\{0,1\\}"
32
33#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
34#define container_of(ptr, type, member) ({                      \
35        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
36        (type *)( (const char *)__mptr - offsetof(type,member) );})
37
38static int sensors_do_this_chip_sets(sensors_chip_name name);
39
40/* Compare two chips name descriptions, to see whether they could match.
41   Return 0 if it does not match, return 1 if it does match. */
42int sensors_match_chip(sensors_chip_name chip1, sensors_chip_name chip2)
43{
44        if ((chip1.prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
45            (chip2.prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
46            strcasecmp(chip1.prefix, chip2.prefix))
47                return 0;
48
49        if ((chip1.bus != SENSORS_CHIP_NAME_BUS_ANY) &&
50            (chip2.bus != SENSORS_CHIP_NAME_BUS_ANY) &&
51            (chip1.bus != chip2.bus)) {
52
53                if ((chip1.bus == SENSORS_CHIP_NAME_BUS_ISA) ||
54                    (chip2.bus == SENSORS_CHIP_NAME_BUS_ISA))
55                        return 0;
56
57                if ((chip1.bus == SENSORS_CHIP_NAME_BUS_PCI) ||
58                    (chip2.bus == SENSORS_CHIP_NAME_BUS_PCI))
59                        return 0;
60
61                if ((chip1.bus != SENSORS_CHIP_NAME_BUS_ANY_I2C) &&
62                    (chip2.bus != SENSORS_CHIP_NAME_BUS_ANY_I2C))
63                        return 0;
64        }
65
66        if ((chip1.addr != chip2.addr) &&
67            (chip1.addr != SENSORS_CHIP_NAME_ADDR_ANY) &&
68            (chip2.addr != SENSORS_CHIP_NAME_ADDR_ANY))
69                return 0;
70
71        return 1;
72}
73
74/* Returns, one by one, a pointer to all sensor_chip structs of the
75   config file which match with the given chip name. Last should be
76   the value returned by the last call, or NULL if this is the first
77   call. Returns NULL if no more matches are found. Do not modify
78   the struct the return value points to!
79   Note that this visits the list of chips from last to first. Usually,
80   you want the match that was latest in the config file. */
81sensors_chip *sensors_for_all_config_chips(sensors_chip_name chip_name,
82                                           const sensors_chip * last)
83{
84        int nr, i;
85        sensors_chip_name_list chips;
86
87        for (nr = last ? last - sensors_config_chips - 1 :
88                         sensors_config_chips_count - 1; nr >= 0; nr--) {
89
90                chips = sensors_config_chips[nr].chips;
91                for (i = 0; i < chips.fits_count; i++) {
92                        if (sensors_match_chip(chips.fits[i], chip_name))
93                                return sensors_config_chips + nr;
94                }
95        }
96        return NULL;
97}
98
99/* Look up a resource in the intern chip list, and return a pointer to it.
100   Do not modify the struct the return value points to! Returns NULL if
101   not found.*/
102const sensors_chip_feature *sensors_lookup_feature_nr(const char *prefix,
103                                                      int feature)
104{
105        int i, j;
106        const sensors_chip_feature *features;
107
108        for (i = 0; sensors_chip_features_list[i].prefix; i++)
109                if (!strcasecmp(sensors_chip_features_list[i].prefix, prefix)) {
110                        features = sensors_chip_features_list[i].feature;
111                        for (j = 0; features[j].data.name; j++)
112                                if (features[j].data.number == feature)
113                                        return features + j;
114                }
115        return NULL;
116}
117
118/* Look up a resource in the intern chip list, and return a pointer to it.
119   Do not modify the struct the return value points to! Returns NULL if
120   not found.*/
121const sensors_chip_feature *sensors_lookup_feature_name(const char *prefix,
122                                                        const char *feature)
123{
124        int i, j;
125        const sensors_chip_feature *features;
126
127        for (i = 0; sensors_chip_features_list[i].prefix; i++)
128                if (!strcasecmp(sensors_chip_features_list[i].prefix, prefix)) {
129                        features = sensors_chip_features_list[i].feature;
130                        for (j = 0; features[j].data.name; j++)
131                                if (!strcasecmp(features[j].data.name, feature))
132                                        return features + j;
133                }
134        return NULL;
135}
136
137/* Check whether the chip name is an 'absolute' name, which can only match
138   one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
139   if there are wildcards. */
140int sensors_chip_name_has_wildcards(sensors_chip_name chip)
141{
142        if ((chip.prefix == SENSORS_CHIP_NAME_PREFIX_ANY) ||
143            (chip.bus == SENSORS_CHIP_NAME_BUS_ANY) ||
144            (chip.bus == SENSORS_CHIP_NAME_BUS_ANY_I2C) ||
145            (chip.addr == SENSORS_CHIP_NAME_ADDR_ANY))
146                return 1;
147        else
148                return 0;
149}
150
151/* Look up the label which belongs to this chip. Note that chip should not
152   contain wildcard values! *result is newly allocated (free it yourself).
153   This function will return 0 on success, and <0 on failure.
154   If no label exists for this feature, its name is returned itself. */
155int sensors_get_label(sensors_chip_name name, int feature, char **result)
156{
157        const sensors_chip *chip;
158        const sensors_chip_feature *featureptr;
159        int i;
160
161        *result = NULL;
162        if (sensors_chip_name_has_wildcards(name))
163                return -SENSORS_ERR_WILDCARDS;
164        if (!(featureptr = sensors_lookup_feature_nr(name.prefix, feature)))
165                return -SENSORS_ERR_NO_ENTRY;
166
167        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
168                for (i = 0; i < chip->labels_count; i++)
169                        if (!strcasecmp(featureptr->data.name,chip->labels[i].name)){
170                                if (*result)
171                                        free(*result);
172                                if (!(*result = strdup(chip->labels[i].value)))
173                                        sensors_fatal_error("sensors_get_label",
174                                                            "Allocating label text");
175                                return 0;
176                        }
177
178        /* No label, return the feature name instead */
179        if (!(*result = strdup(featureptr->data.name)))
180                sensors_fatal_error("sensors_get_label",
181                                    "Allocating label text");
182        return 0;
183}
184
185int sensors_get_ignored(sensors_chip_name name, int feature)
186{
187        const sensors_chip *chip;
188        const sensors_chip_feature *featureptr;
189        const sensors_chip_feature *alt_featureptr;
190        int i, res;
191
192        /* Default: valid */
193        res = 1;
194        if (sensors_chip_name_has_wildcards(name))
195                return -SENSORS_ERR_WILDCARDS;
196        if (!(featureptr = sensors_lookup_feature_nr(name.prefix, feature)))
197                return -SENSORS_ERR_NO_ENTRY;
198        if (featureptr->data.mapping == SENSORS_NO_MAPPING)
199                alt_featureptr = NULL;
200        else if (!(alt_featureptr =
201                   sensors_lookup_feature_nr(name.prefix,
202                                             featureptr->data.mapping)))
203                return -SENSORS_ERR_NO_ENTRY;
204        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
205                for (i = 0; i < chip->ignores_count; i++)
206                        if (!strcasecmp(featureptr->data.name, chip->ignores[i].name))
207                                return 0; /* Exact match always overrules! */
208                        else if (alt_featureptr &&
209                                 !strcasecmp(alt_featureptr->data.name,
210                                             chip->ignores[i].name))
211                                res = 0;
212        return res;
213}
214
215/* Read the value of a feature of a certain chip. Note that chip should not
216   contain wildcard values! This function will return 0 on success, and <0
217   on failure. */
218int sensors_get_feature(sensors_chip_name name, int feature, double *result)
219{
220        const sensors_chip_feature *main_feature;
221        const sensors_chip_feature *alt_feature;
222        const sensors_chip *chip;
223        const sensors_expr *expr = NULL;
224        double val;
225        int res, i;
226        int final_expr = 0;
227
228        if (sensors_chip_name_has_wildcards(name))
229                return -SENSORS_ERR_WILDCARDS;
230        if (!(main_feature = sensors_lookup_feature_nr(name.prefix, feature)))
231                return -SENSORS_ERR_NO_ENTRY;
232        if (main_feature->data.compute_mapping == SENSORS_NO_MAPPING)
233                alt_feature = NULL;
234        else if (!(alt_feature = sensors_lookup_feature_nr(name.prefix,
235                                        main_feature->data.compute_mapping)))
236                return -SENSORS_ERR_NO_ENTRY;
237        if (!(main_feature->data.mode & SENSORS_MODE_R))
238                return -SENSORS_ERR_ACCESS_R;
239        for (chip = NULL;
240             !expr && (chip = sensors_for_all_config_chips(name, chip));)
241                for (i = 0; !final_expr && (i < chip->computes_count); i++) {
242                        if (!strcasecmp(main_feature->data.name, chip->computes[i].name)) {
243                                expr = chip->computes[i].from_proc;
244                                final_expr = 1;
245                        } else if (alt_feature && !strcasecmp(alt_feature->data.name,
246                                               chip->computes[i].name)) {
247                                expr = chip->computes[i].from_proc;
248                        }
249                }
250        if (sensors_read_proc(name, feature, &val))
251                return -SENSORS_ERR_PROC;
252        if (!expr)
253                *result = val;
254        else if ((res = sensors_eval_expr(name, expr, val, result)))
255                return res;
256        return 0;
257}
258
259/* Set the value of a feature of a certain chip. Note that chip should not
260   contain wildcard values! This function will return 0 on success, and <0
261   on failure. */
262int sensors_set_feature(sensors_chip_name name, int feature, double value)
263{
264        const sensors_chip_feature *main_feature;
265        const sensors_chip_feature *alt_feature;
266        const sensors_chip *chip;
267        const sensors_expr *expr = NULL;
268        int i, res;
269        int final_expr = 0;
270        double to_write;
271
272        if (sensors_chip_name_has_wildcards(name))
273                return -SENSORS_ERR_WILDCARDS;
274        if (!(main_feature = sensors_lookup_feature_nr(name.prefix, feature)))
275                return -SENSORS_ERR_NO_ENTRY;
276        if (main_feature->data.compute_mapping == SENSORS_NO_MAPPING)
277                alt_feature = NULL;
278        else if (!(alt_feature = sensors_lookup_feature_nr(name.prefix,
279                                             main_feature->data.compute_mapping)))
280                return -SENSORS_ERR_NO_ENTRY;
281        if (!(main_feature->data.mode & SENSORS_MODE_W))
282                return -SENSORS_ERR_ACCESS_W;
283        for (chip = NULL;
284             !expr && (chip = sensors_for_all_config_chips(name, chip));)
285                for (i = 0; !final_expr && (i < chip->computes_count); i++)
286                        if (!strcasecmp(main_feature->data.name, chip->computes[i].name)) {
287                                expr = chip->computes->to_proc;
288                                final_expr = 1;
289                        } else if (alt_feature && !strcasecmp(alt_feature->data.name,
290                                               chip->computes[i].name)) {
291                                expr = chip->computes[i].to_proc;
292                        }
293
294        to_write = value;
295        if (expr)
296                if ((res = sensors_eval_expr(name, expr, value, &to_write)))
297                        return res;
298        if (sensors_write_proc(name, feature, to_write))
299                return -SENSORS_ERR_PROC;
300        return 0;
301}
302
303const sensors_chip_name *sensors_get_detected_chips(int *nr)
304{
305        const sensors_chip_name *res;
306        res = (*nr >= sensors_proc_chips_count ?
307                        NULL : &sensors_proc_chips[*nr].name);
308        (*nr)++;
309        return res;
310}
311
312const char *sensors_get_adapter_name(int bus_nr)
313{
314        int i;
315
316        if (bus_nr == SENSORS_CHIP_NAME_BUS_ISA)
317                return "ISA adapter";
318        if (bus_nr == SENSORS_CHIP_NAME_BUS_PCI)
319                return "PCI adapter";
320        if (bus_nr == SENSORS_CHIP_NAME_BUS_DUMMY)
321                return "Dummy adapter";
322        for (i = 0; i < sensors_proc_bus_count; i++)
323                if (sensors_proc_bus[i].number == bus_nr)
324                        return sensors_proc_bus[i].adapter;
325        return NULL;
326}
327
328/* This function is deprecated and will be dropped soon. */
329const char *sensors_get_algorithm_name(int bus_nr)
330{
331        return "No longer available";
332}
333
334/* nr1-1 is the last main feature found; nr2-1 is the last subfeature found */
335const sensors_feature_data *sensors_get_all_features(sensors_chip_name name,
336                                                     int *nr1, int *nr2)
337{
338        sensors_chip_feature *feature_list;
339        int i;
340
341        for (i = 0; sensors_chip_features_list[i].prefix; i++)
342                if (!strcasecmp(sensors_chip_features_list[i].prefix, name.prefix)) {
343                        feature_list = sensors_chip_features_list[i].feature;
344                        if (!*nr1 && !*nr2) {   /* Return the first entry */
345                                if (!feature_list[0].data.name) /* The list may be empty */
346                                        return NULL;
347                                *nr1 = *nr2 = 1;
348                                return &feature_list->data;
349                        }
350                        for ((*nr2)++; feature_list[*nr2 - 1].data.name; (*nr2)++)
351                                if (feature_list[*nr2 - 1].data.mapping ==
352                                    feature_list[*nr1 - 1].data.number)
353                                        return &((feature_list + *nr2 - 1)->data);
354                        for ((*nr1)++;
355                             feature_list[*nr1 - 1].data.name
356                             && (feature_list[*nr1 - 1].data.mapping !=
357                                 SENSORS_NO_MAPPING); (*nr1)++) ;
358                        *nr2 = *nr1;
359                        if (!feature_list[*nr1 - 1].data.name)
360                                return NULL;
361                        return &((feature_list + *nr1 - 1)->data);
362                }
363        return NULL;
364}
365
366int sensors_eval_expr(sensors_chip_name chipname, const sensors_expr * expr,
367                      double val, double *result)
368{
369        double res1, res2;
370        int res;
371        const sensors_chip_feature *feature;
372
373        if (expr->kind == sensors_kind_val) {
374                *result = expr->data.val;
375                return 0;
376        }
377        if (expr->kind == sensors_kind_source) {
378                *result = val;
379                return 0;
380        }
381        if (expr->kind == sensors_kind_var) {
382                if (!(feature = sensors_lookup_feature_name(chipname.prefix,
383                                                            expr->data.var)))
384                        return SENSORS_ERR_NO_ENTRY;
385                if (!(res = sensors_get_feature(chipname, feature->data.number, result)))
386                        return res;
387                return 0;
388        }
389        if ((res = sensors_eval_expr(chipname, expr->data.subexpr.sub1, val, &res1)))
390                return res;
391        if (expr->data.subexpr.sub2 &&
392            (res = sensors_eval_expr(chipname, expr->data.subexpr.sub2, val, &res2)))
393                return res;
394        switch (expr->data.subexpr.op) {
395        case sensors_add:
396                *result = res1 + res2;
397                return 0;
398        case sensors_sub:
399                *result = res1 - res2;
400                return 0;
401        case sensors_multiply:
402                *result = res1 * res2;
403                return 0;
404        case sensors_divide:
405                if (res2 == 0.0)
406                        return -SENSORS_ERR_DIV_ZERO;
407                *result = res1 / res2;
408                return 0;
409        case sensors_negate:
410                *result = -res1;
411                return 0;
412        case sensors_exp:
413                *result = exp(res1);
414                return 0;
415        case sensors_log:
416                if (res1 < 0.0)
417                        return -SENSORS_ERR_DIV_ZERO;
418                *result = log(res1);
419                return 0;
420        }
421        return 0;
422}
423
424/* Execute all set statements for this particular chip. The chip may not
425   contain wildcards!  This function will return 0 on success, and <0 on
426   failure. */
427int sensors_do_this_chip_sets(sensors_chip_name name)
428{
429        sensors_chip *chip;
430        double value;
431        int i, j;
432        int err = 0, res;
433        const sensors_chip_feature *feature;
434        int *feature_list = NULL;
435        int feature_count = 0;
436        int feature_max = 0;
437        int feature_nr;
438
439        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
440                for (i = 0; i < chip->sets_count; i++) {
441                        feature = sensors_lookup_feature_name(name.prefix,
442                                                        chip->sets[i].name);
443                        if (!feature) {
444                                sensors_parse_error("Unknown feature name",
445                                                    chip->sets[i].lineno);
446                                err = SENSORS_ERR_NO_ENTRY;
447                                continue;
448                        }
449                        feature_nr = feature->data.number;
450
451                        /* Check whether we already set this feature */
452                        for (j = 0; j < feature_count; j++)
453                                if (feature_list[j] == feature_nr)
454                                        break;
455                        if (j != feature_count)
456                                continue;
457                        sensors_add_array_el(&feature_nr, &feature_list,
458                                             &feature_count, &feature_max,
459                                             sizeof(int));
460
461                        res = sensors_eval_expr(name, chip->sets[i].value, 0,
462                                              &value);
463                        if (res) {
464                                sensors_parse_error("Error parsing expression",
465                                                    chip->sets[i].lineno);
466                                err = res;
467                                continue;
468                        }
469                        if ((res = sensors_set_feature(name, feature_nr, value))) {
470                                sensors_parse_error("Failed to set feature",
471                                                chip->sets[i].lineno);
472                                err = res;
473                                continue;
474                        }
475                }
476        free(feature_list);
477        return err;
478}
479
480/* Execute all set statements for this particular chip. The chip may contain
481   wildcards!  This function will return 0 on success, and <0 on failure. */
482int sensors_do_chip_sets(sensors_chip_name name)
483{
484        int nr, this_res;
485        const sensors_chip_name *found_name;
486        int res = 0;
487
488        for (nr = 0; (found_name = sensors_get_detected_chips(&nr));)
489                if (sensors_match_chip(name, *found_name)) {
490                        this_res = sensors_do_this_chip_sets(*found_name);
491                        if (!res)
492                                res = this_res;
493                }
494        return res;
495}
496
497/* Execute all set statements for all detected chips. This is the same as
498   calling sensors_do_chip_sets with an all wildcards chip name */
499int sensors_do_all_sets(void)
500{
501        sensors_chip_name name = { SENSORS_CHIP_NAME_PREFIX_ANY,
502                SENSORS_CHIP_NAME_BUS_ANY,
503                SENSORS_CHIP_NAME_ADDR_ANY
504        };
505        return sensors_do_chip_sets(name);
506}
507
508/* Static mappings for use by sensors_feature_get_type() */
509struct feature_type_match
510{
511        const char *name;
512        sensors_feature_type type;
513       
514        struct feature_type_match *submatches;
515};
516
517static struct feature_type_match temp_matches[] = {
518        { "max", SENSORS_FEATURE_TEMP_MAX },
519        { "min", SENSORS_FEATURE_TEMP_MIN },
520        { "type", SENSORS_FEATURE_TEMP_SENS },
521        { "hyst", SENSORS_FEATURE_TEMP_HYST },
522        { "over", SENSORS_FEATURE_TEMP_OVER },
523        { "max", SENSORS_FEATURE_TEMP_MAX },
524        { "min", SENSORS_FEATURE_TEMP_MIN },
525        { "low", SENSORS_FEATURE_TEMP_LOW },
526        { "crit", SENSORS_FEATURE_TEMP_CRIT },
527        { "fault", SENSORS_FEATURE_TEMP_FAULT },
528        { "alarm", SENSORS_FEATURE_TEMP_ALARM },
529        { "type", SENSORS_FEATURE_TEMP_SENS },
530        { 0 }
531};
532
533static struct feature_type_match in_matches[] = {
534        { "max", SENSORS_FEATURE_IN_MAX },
535        { "max_alarm", SENSORS_FEATURE_IN_MAX_ALARM },
536        { "min", SENSORS_FEATURE_IN_MIN },
537        { "min_alarm", SENSORS_FEATURE_IN_MIN_ALARM },
538        { "alarm", SENSORS_FEATURE_IN_ALARM },
539        { 0 }
540};
541
542static struct feature_type_match fan_matches[] = {
543        { "min", SENSORS_FEATURE_FAN_MIN },
544        { "div", SENSORS_FEATURE_FAN_DIV },
545        { "alarm", SENSORS_FEATURE_FAN_ALARM },
546        { "fault", SENSORS_FEATURE_FAN_FAULT },
547        { 0 }
548};
549
550static struct feature_type_match matches[] = { 
551        { "temp", SENSORS_FEATURE_TEMP, temp_matches },
552        { "in", SENSORS_FEATURE_IN, in_matches },
553        { "fan", SENSORS_FEATURE_FAN, fan_matches },
554        { "vrm", SENSORS_FEATURE_VRM, 0 },
555        { "vid", SENSORS_FEATURE_VID, 0 },
556        { "sensor", SENSORS_FEATURE_TEMP_SENS, 0 }, 
557        { 0 }
558};
559
560/* Return the feature type based on the feature name */
561sensors_feature_type sensors_feature_get_type(
562        const sensors_feature_data *feature)
563{
564        const char *name;
565        regex_t preg;
566        regmatch_t pmatch[4];
567        int size_first, size_second, retval, i;
568        struct feature_type_match *submatches;
569       
570        /* use sysname if exists */
571        if (container_of(feature, const struct sensors_chip_feature, data)->sysname)
572                name = container_of(feature, const struct sensors_chip_feature, data)->sysname;
573        else
574                name = feature->name;
575       
576        regcomp(&preg, GET_TYPE_REGEX, 0);
577       
578        retval = regexec(&preg, name, 4, pmatch, 0);
579       
580        regfree(&preg);
581       
582        if (retval == -1)
583                return SENSORS_FEATURE_UNKNOWN;
584       
585        size_first = pmatch[1].rm_eo - pmatch[1].rm_so;
586        size_second = pmatch[3].rm_eo - pmatch[3].rm_so;
587       
588        for(i = 0; matches[i].name != 0; i++)
589                if (!strncmp(name, matches[i].name, size_first))
590                        break;
591       
592        if (matches[i].name == NULL) /* no match */
593                return SENSORS_FEATURE_UNKNOWN;
594        else if (size_second == 0) /* single type */
595                return matches[i].type;
596        else if (matches[i].submatches == NULL) /* not single type, but no submatches */
597                return SENSORS_FEATURE_UNKNOWN;
598
599        submatches = matches[i].submatches;
600        for(i = 0; submatches[i].name != 0; i++)
601                if (!strncmp(name + pmatch[3].rm_so, submatches[i].name, size_second))
602                        return submatches[i].type;
603       
604        return SENSORS_FEATURE_UNKNOWN;
605}
Note: See TracBrowser for help on using the browser.