root/lm-sensors/trunk/lib/access.c @ 5786

Revision 5786, 15.9 KB (checked in by khali, 4 years ago)

Add support for HID devices.

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