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

Revision 5593, 15.7 KB (checked in by jwrdegoede, 4 years ago)

Add ACPI bus

  • 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    Copyright (C) 2007, 2008  Jean Delvare <khali@linux-fr.org>
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19    MA 02110-1301 USA.
20*/
21
22#include <stdlib.h>
23#include <string.h>
24#include <math.h>
25#include "access.h"
26#include "sensors.h"
27#include "data.h"
28#include "error.h"
29#include "sysfs.h"
30#include "general.h"
31
32/* We watch the recursion depth for variables only, as an easy way to
33   detect cycles. */
34#define DEPTH_MAX       8
35
36static int sensors_eval_expr(const sensors_chip_features *chip_features,
37                             const sensors_expr *expr,
38                             double val, int depth, double *result);
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. */
42static int sensors_match_chip(const sensors_chip_name *chip1,
43                       const sensors_chip_name *chip2)
44{
45        if ((chip1->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
46            (chip2->prefix != SENSORS_CHIP_NAME_PREFIX_ANY) &&
47            strcmp(chip1->prefix, chip2->prefix))
48                return 0;
49
50        if ((chip1->bus.type != SENSORS_BUS_TYPE_ANY) &&
51            (chip2->bus.type != SENSORS_BUS_TYPE_ANY) &&
52            (chip1->bus.type != chip2->bus.type))
53                return 0;
54
55        if ((chip1->bus.nr != SENSORS_BUS_NR_ANY) &&
56            (chip2->bus.nr != SENSORS_BUS_NR_ANY) &&
57            (chip1->bus.nr != chip2->bus.nr))
58                return 0;
59
60        if ((chip1->addr != chip2->addr) &&
61            (chip1->addr != SENSORS_CHIP_NAME_ADDR_ANY) &&
62            (chip2->addr != SENSORS_CHIP_NAME_ADDR_ANY))
63                return 0;
64
65        return 1;
66}
67
68/* Returns, one by one, a pointer to all sensor_chip structs of the
69   config file which match with the given chip name. Last should be
70   the value returned by the last call, or NULL if this is the first
71   call. Returns NULL if no more matches are found. Do not modify
72   the struct the return value points to!
73   Note that this visits the list of chips from last to first. Usually,
74   you want the match that was latest in the config file. */
75static sensors_chip *
76sensors_for_all_config_chips(const sensors_chip_name *name,
77                             const sensors_chip *last)
78{
79        int nr, i;
80        sensors_chip_name_list chips;
81
82        for (nr = last ? last - sensors_config_chips - 1 :
83                         sensors_config_chips_count - 1; nr >= 0; nr--) {
84
85                chips = sensors_config_chips[nr].chips;
86                for (i = 0; i < chips.fits_count; i++) {
87                        if (sensors_match_chip(&chips.fits[i], name))
88                                return sensors_config_chips + nr;
89                }
90        }
91        return NULL;
92}
93
94/* Look up a chip in the intern chip list, and return a pointer to it.
95   Do not modify the struct the return value points to! Returns NULL if
96   not found.*/
97static const sensors_chip_features *
98sensors_lookup_chip(const sensors_chip_name *name)
99{
100        int i;
101
102        for (i = 0; i < sensors_proc_chips_count; i++)
103                if (sensors_match_chip(&sensors_proc_chips[i].chip, name))
104                        return &sensors_proc_chips[i];
105
106        return NULL;
107}
108
109/* Look up a subfeature of the given chip, and return a pointer to it.
110   Do not modify the struct the return value points to! Returns NULL if
111   not found.*/
112static const sensors_subfeature *
113sensors_lookup_subfeature_nr(const sensors_chip_features *chip,
114                             int subfeat_nr)
115{
116        if (subfeat_nr < 0 ||
117            subfeat_nr >= chip->subfeature_count)
118                return NULL;
119        return chip->subfeature + subfeat_nr;
120}
121
122/* Look up a feature of the given chip, and return a pointer to it.
123   Do not modify the struct the return value points to! Returns NULL if
124   not found.*/
125static const sensors_feature *
126sensors_lookup_feature_nr(const sensors_chip_features *chip, int feat_nr)
127{
128        if (feat_nr < 0 ||
129            feat_nr >= chip->feature_count)
130                return NULL;
131        return chip->feature + feat_nr;
132}
133
134/* Look up a subfeature by name, and return a pointer to it.
135   Do not modify the struct the return value points to! Returns NULL if
136   not found.*/
137static const sensors_subfeature *
138sensors_lookup_subfeature_name(const sensors_chip_features *chip,
139                               const char *name)
140{
141        int j;
142
143        for (j = 0; j < chip->subfeature_count; j++)
144                if (!strcmp(chip->subfeature[j].name, name))
145                        return chip->subfeature + j;
146        return NULL;
147}
148
149/* Check whether the chip name is an 'absolute' name, which can only match
150   one chip, or whether it has wildcards. Returns 0 if it is absolute, 1
151   if there are wildcards. */
152int sensors_chip_name_has_wildcards(const sensors_chip_name *chip)
153{
154        if ((chip->prefix == SENSORS_CHIP_NAME_PREFIX_ANY) ||
155            (chip->bus.type == SENSORS_BUS_TYPE_ANY) ||
156            (chip->bus.nr == SENSORS_BUS_NR_ANY) ||
157            (chip->addr == SENSORS_CHIP_NAME_ADDR_ANY))
158                return 1;
159        else
160                return 0;
161}
162
163/* Look up the label for a given feature. Note that chip should not
164   contain wildcard values! The returned string is newly allocated (free it
165   yourself). On failure, NULL is returned.
166   If no label exists for this feature, its name is returned itself. */
167char *sensors_get_label(const sensors_chip_name *name,
168                        const sensors_feature *feature)
169{
170        char *label;
171        const sensors_chip *chip;
172        char buf[128], path[PATH_MAX];
173        FILE *f;
174        int i;
175
176        if (sensors_chip_name_has_wildcards(name))
177                return NULL;
178
179        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
180                for (i = 0; i < chip->labels_count; i++)
181                        if (!strcmp(feature->name, chip->labels[i].name)) {
182                                label = strdup(chip->labels[i].value);
183                                goto sensors_get_label_exit;
184                        }
185
186        /* No user specified label, check for a _label sysfs file */
187        snprintf(path, PATH_MAX, "%s/%s_label", name->path, feature->name);
188       
189        if ((f = fopen(path, "r"))) {
190                i = fread(buf, 1, sizeof(buf) - 1, f);
191                fclose(f);
192                if (i > 0) {
193                        /* i - 1 to strip the '\n' at the end */
194                        buf[i - 1] = 0;
195                        label = strdup(buf);
196                        goto sensors_get_label_exit;
197                }
198        }
199
200        /* No label, return the feature name instead */
201        label = strdup(feature->name);
202       
203sensors_get_label_exit:
204        if (!label)
205                sensors_fatal_error("sensors_get_label",
206                                    "Allocating label text");
207        return label;
208}
209
210/* Looks up whether a feature should be ignored. Returns
211   1 if it should be ignored, 0 if not. */
212static int sensors_get_ignored(const sensors_chip_name *name,
213                               const sensors_feature *feature)
214{
215        const sensors_chip *chip;
216        int i;
217
218        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
219                for (i = 0; i < chip->ignores_count; i++)
220                        if (!strcmp(feature->name, chip->ignores[i].name))
221                                return 1;
222        return 0;
223}
224
225/* Read the value of a subfeature of a certain chip. Note that chip should not
226   contain wildcard values! This function will return 0 on success, and <0
227   on failure. */
228static int __sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
229                               int depth, double *result)
230{
231        const sensors_chip_features *chip_features;
232        const sensors_subfeature *subfeature;
233        const sensors_expr *expr = NULL;
234        double val;
235        int res, i;
236
237        if (depth >= DEPTH_MAX)
238                return -SENSORS_ERR_RECURSION;
239        if (sensors_chip_name_has_wildcards(name))
240                return -SENSORS_ERR_WILDCARDS;
241        if (!(chip_features = sensors_lookup_chip(name)))
242                return -SENSORS_ERR_NO_ENTRY;
243        if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
244                                                        subfeat_nr)))
245                return -SENSORS_ERR_NO_ENTRY;
246        if (!(subfeature->flags & SENSORS_MODE_R))
247                return -SENSORS_ERR_ACCESS_R;
248
249        /* Apply compute statement if it exists */
250        if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
251                const sensors_feature *feature;
252                const sensors_chip *chip;
253
254                feature = sensors_lookup_feature_nr(chip_features,
255                                        subfeature->mapping);
256
257                chip = NULL;
258                while (!expr &&
259                       (chip = sensors_for_all_config_chips(name, chip)))
260                        for (i = 0; i < chip->computes_count; i++) {
261                                if (!strcmp(feature->name,
262                                            chip->computes[i].name)) {
263                                        expr = chip->computes[i].from_proc;
264                                        break;
265                                }
266                        }
267        }
268
269        res = sensors_read_sysfs_attr(name, subfeature, &val);
270        if (res)
271                return res;
272        if (!expr)
273                *result = val;
274        else if ((res = sensors_eval_expr(chip_features, expr, val, depth,
275                                          result)))
276                return res;
277        return 0;
278}
279
280int sensors_get_value(const sensors_chip_name *name, int subfeat_nr,
281                      double *result)
282{
283        return __sensors_get_value(name, subfeat_nr, 0, result);
284}
285
286/* Set the value of a subfeature of a certain chip. Note that chip should not
287   contain wildcard values! This function will return 0 on success, and <0
288   on failure. */
289int sensors_set_value(const sensors_chip_name *name, int subfeat_nr,
290                      double value)
291{
292        const sensors_chip_features *chip_features;
293        const sensors_subfeature *subfeature;
294        const sensors_expr *expr = NULL;
295        int i, res;
296        double to_write;
297
298        if (sensors_chip_name_has_wildcards(name))
299                return -SENSORS_ERR_WILDCARDS;
300        if (!(chip_features = sensors_lookup_chip(name)))
301                return -SENSORS_ERR_NO_ENTRY;
302        if (!(subfeature = sensors_lookup_subfeature_nr(chip_features,
303                                                        subfeat_nr)))
304                return -SENSORS_ERR_NO_ENTRY;
305        if (!(subfeature->flags & SENSORS_MODE_W))
306                return -SENSORS_ERR_ACCESS_W;
307
308        /* Apply compute statement if it exists */
309        if (subfeature->flags & SENSORS_COMPUTE_MAPPING) {
310                const sensors_feature *feature;
311                const sensors_chip *chip;
312
313                feature = sensors_lookup_feature_nr(chip_features,
314                                        subfeature->mapping);
315
316                chip = NULL;
317                while (!expr &&
318                       (chip = sensors_for_all_config_chips(name, chip)))
319                        for (i = 0; i < chip->computes_count; i++) {
320                                if (!strcmp(feature->name,
321                                            chip->computes[i].name)) {
322                                        expr = chip->computes[i].to_proc;
323                                        break;
324                                }
325                        }
326        }
327
328        to_write = value;
329        if (expr)
330                if ((res = sensors_eval_expr(chip_features, expr,
331                                             value, 0, &to_write)))
332                        return res;
333        return sensors_write_sysfs_attr(name, subfeature, to_write);
334}
335
336const sensors_chip_name *sensors_get_detected_chips(const sensors_chip_name
337                                                    *match, int *nr)
338{
339        const sensors_chip_name *res;
340
341        while (*nr < sensors_proc_chips_count) {
342                res = &sensors_proc_chips[(*nr)++].chip;
343                if (!match || sensors_match_chip(res, match))
344                        return res;
345        }
346        return NULL;
347}
348
349const char *sensors_get_adapter_name(const sensors_bus_id *bus)
350{
351        int i;
352
353        /* bus types with a single instance */
354        switch (bus->type) {
355        case SENSORS_BUS_TYPE_ISA:
356                return "ISA adapter";
357        case SENSORS_BUS_TYPE_PCI:
358                return "PCI adapter";
359        /* SPI should not be here, but for now SPI adapters have no name
360           so we don't have any custom string to return. */
361        case SENSORS_BUS_TYPE_SPI:
362                return "SPI adapter";
363        case SENSORS_BUS_TYPE_VIRTUAL:
364                return "Virtual device";
365        case SENSORS_BUS_TYPE_ACPI:
366                return "ACPI interface";
367        }
368
369        /* bus types with several instances */
370        for (i = 0; i < sensors_proc_bus_count; i++)
371                if (sensors_proc_bus[i].bus.type == bus->type &&
372                    sensors_proc_bus[i].bus.nr == bus->nr)
373                        return sensors_proc_bus[i].adapter;
374        return NULL;
375}
376
377const sensors_feature *
378sensors_get_features(const sensors_chip_name *name, int *nr)
379{
380        const sensors_chip_features *chip;
381
382        if (!(chip = sensors_lookup_chip(name)))
383                return NULL;    /* No such chip */
384
385        while (*nr < chip->feature_count
386            && sensors_get_ignored(name, &chip->feature[*nr]))
387                (*nr)++;
388        if (*nr >= chip->feature_count)
389                return NULL;
390        return &chip->feature[(*nr)++];
391}
392
393const sensors_subfeature *
394sensors_get_all_subfeatures(const sensors_chip_name *name,
395                        const sensors_feature *feature, int *nr)
396{
397        const sensors_chip_features *chip;
398        const sensors_subfeature *subfeature;
399
400        if (!(chip = sensors_lookup_chip(name)))
401                return NULL;    /* No such chip */
402
403        /* Seek directly to the first subfeature */
404        if (*nr < feature->first_subfeature)
405                *nr = feature->first_subfeature;
406
407        if (*nr >= chip->subfeature_count)
408                return NULL;    /* end of list */
409        subfeature = &chip->subfeature[(*nr)++];
410        if (subfeature->mapping == feature->number)
411                return subfeature;
412        return NULL;    /* end of subfeature list */
413}
414
415const sensors_subfeature *
416sensors_get_subfeature(const sensors_chip_name *name,
417                       const sensors_feature *feature,
418                       sensors_subfeature_type type)
419{
420        const sensors_chip_features *chip;
421        int i;
422
423        if (!(chip = sensors_lookup_chip(name)))
424                return NULL;    /* No such chip */
425
426        for (i = feature->first_subfeature; i < chip->subfeature_count &&
427             chip->subfeature[i].mapping == feature->number; i++) {
428                if (chip->subfeature[i].type == type)
429                        return &chip->subfeature[i];
430        }
431        return NULL;    /* No such subfeature */
432}
433
434/* Evaluate an expression */
435int sensors_eval_expr(const sensors_chip_features *chip_features,
436                      const sensors_expr *expr,
437                      double val, int depth, double *result)
438{
439        double res1, res2;
440        int res;
441        const sensors_subfeature *subfeature;
442
443        if (expr->kind == sensors_kind_val) {
444                *result = expr->data.val;
445                return 0;
446        }
447        if (expr->kind == sensors_kind_source) {
448                *result = val;
449                return 0;
450        }
451        if (expr->kind == sensors_kind_var) {
452                if (!(subfeature = sensors_lookup_subfeature_name(chip_features,
453                                                            expr->data.var)))
454                        return -SENSORS_ERR_NO_ENTRY;
455                return __sensors_get_value(&chip_features->chip,
456                                           subfeature->number, depth + 1,
457                                           result);
458        }
459        if ((res = sensors_eval_expr(chip_features, expr->data.subexpr.sub1,
460                                     val, depth, &res1)))
461                return res;
462        if (expr->data.subexpr.sub2 &&
463            (res = sensors_eval_expr(chip_features, expr->data.subexpr.sub2,
464                                     val, depth, &res2)))
465                return res;
466        switch (expr->data.subexpr.op) {
467        case sensors_add:
468                *result = res1 + res2;
469                return 0;
470        case sensors_sub:
471                *result = res1 - res2;
472                return 0;
473        case sensors_multiply:
474                *result = res1 * res2;
475                return 0;
476        case sensors_divide:
477                if (res2 == 0.0)
478                        return -SENSORS_ERR_DIV_ZERO;
479                *result = res1 / res2;
480                return 0;
481        case sensors_negate:
482                *result = -res1;
483                return 0;
484        case sensors_exp:
485                *result = exp(res1);
486                return 0;
487        case sensors_log:
488                if (res1 < 0.0)
489                        return -SENSORS_ERR_DIV_ZERO;
490                *result = log(res1);
491                return 0;
492        }
493        return 0;
494}
495
496/* Execute all set statements for this particular chip. The chip may not
497   contain wildcards!  This function will return 0 on success, and <0 on
498   failure. */
499static int sensors_do_this_chip_sets(const sensors_chip_name *name)
500{
501        const sensors_chip_features *chip_features;
502        sensors_chip *chip;
503        double value;
504        int i;
505        int err = 0, res;
506        const sensors_subfeature *subfeature;
507
508        chip_features = sensors_lookup_chip(name);      /* Can't fail */
509
510        for (chip = NULL; (chip = sensors_for_all_config_chips(name, chip));)
511                for (i = 0; i < chip->sets_count; i++) {
512                        subfeature = sensors_lookup_subfeature_name(chip_features,
513                                                        chip->sets[i].name);
514                        if (!subfeature) {
515                                sensors_parse_error("Unknown feature name",
516                                                    chip->sets[i].lineno);
517                                err = -SENSORS_ERR_NO_ENTRY;
518                                continue;
519                        }
520
521                        res = sensors_eval_expr(chip_features,
522                                                chip->sets[i].value, 0,
523                                                0, &value);
524                        if (res) {
525                                sensors_parse_error("Error parsing expression",
526                                                    chip->sets[i].lineno);
527                                err = res;
528                                continue;
529                        }
530                        if ((res = sensors_set_value(name, subfeature->number,
531                                                     value))) {
532                                sensors_parse_error("Failed to set value",
533                                                chip->sets[i].lineno);
534                                err = res;
535                                continue;
536                        }
537                }
538        return err;
539}
540
541/* Execute all set statements for this particular chip. The chip may contain
542   wildcards!  This function will return 0 on success, and <0 on failure. */
543int sensors_do_chip_sets(const sensors_chip_name *name)
544{
545        int nr, this_res;
546        const sensors_chip_name *found_name;
547        int res = 0;
548
549        for (nr = 0; (found_name = sensors_get_detected_chips(name, &nr));) {
550                this_res = sensors_do_this_chip_sets(found_name);
551                if (this_res)
552                        res = this_res;
553        }
554        return res;
555}
Note: See TracBrowser for help on using the browser.