root/lm-sensors/branches/lm-sensors-3.0.0/lib/sysfs.c @ 4776

Revision 4776, 14.8 KB (checked in by khali, 7 years ago)

Move sensors_feature_get_type() from access.c to sysfs.c, it's only called
from this file. This lets the compiler do additional optimizations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    sysfs.c - Part of libsensors, a library for reading Linux sensor data
3    Copyright (c) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
4    Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21/* this define needed for strndup() */
22#define _GNU_SOURCE
23
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <string.h>
28#include <stdlib.h>
29#include <limits.h>
30#include <errno.h>
31#include <sysfs/libsysfs.h>
32#include "data.h"
33#include "error.h"
34#include "access.h"
35#include "general.h"
36#include "sysfs.h"
37
38char sensors_sysfs_mount[NAME_MAX];
39
40#define MAX_SENSORS_PER_TYPE    20
41#define MAX_SUB_FEATURES        7
42/* Room for all 3 types (in, fan, temp) with all their subfeatures + VID
43   + misc features */
44#define ALL_POSSIBLE_FEATURES   (MAX_SENSORS_PER_TYPE * MAX_SUB_FEATURES * 6 \
45                                 + MAX_SENSORS_PER_TYPE + 1)
46
47static
48int get_type_scaling(int type)
49{
50        switch (type & 0xFF10) {
51        case SENSORS_FEATURE_IN:
52        case SENSORS_FEATURE_TEMP:
53                return 1000;
54        case SENSORS_FEATURE_FAN:
55                return 1;
56        }
57
58        switch (type) {
59        case SENSORS_FEATURE_VID:
60        case SENSORS_FEATURE_TEMP_OFFSET:
61                return 1000;
62        default:
63                return 1;
64        }
65}
66
67/* Static mappings for use by sensors_feature_get_type() */
68struct feature_subtype_match
69{
70        const char *name;
71        sensors_feature_type type;
72};
73
74struct feature_type_match
75{
76        const char *name;
77        const struct feature_subtype_match *submatches;
78};
79
80static const struct feature_subtype_match temp_matches[] = {
81        { "input", SENSORS_FEATURE_TEMP },
82        { "max", SENSORS_FEATURE_TEMP_MAX },
83        { "max_hyst", SENSORS_FEATURE_TEMP_MAX_HYST },
84        { "min", SENSORS_FEATURE_TEMP_MIN },
85        { "crit", SENSORS_FEATURE_TEMP_CRIT },
86        { "crit_hyst", SENSORS_FEATURE_TEMP_CRIT_HYST },
87        { "alarm", SENSORS_FEATURE_TEMP_ALARM },
88        { "min_alarm", SENSORS_FEATURE_TEMP_MIN_ALARM },
89        { "max_alarm", SENSORS_FEATURE_TEMP_MAX_ALARM },
90        { "crit_alarm", SENSORS_FEATURE_TEMP_CRIT_ALARM },
91        { "fault", SENSORS_FEATURE_TEMP_FAULT },
92        { "type", SENSORS_FEATURE_TEMP_TYPE },
93        { "offset", SENSORS_FEATURE_TEMP_OFFSET },
94        { NULL, 0 }
95};
96
97static const struct feature_subtype_match in_matches[] = {
98        { "input", SENSORS_FEATURE_IN },
99        { "min", SENSORS_FEATURE_IN_MIN },
100        { "max", SENSORS_FEATURE_IN_MAX },
101        { "alarm", SENSORS_FEATURE_IN_ALARM },
102        { "min_alarm", SENSORS_FEATURE_IN_MIN_ALARM },
103        { "max_alarm", SENSORS_FEATURE_IN_MAX_ALARM },
104        { NULL, 0 }
105};
106
107static const struct feature_subtype_match fan_matches[] = {
108        { "input", SENSORS_FEATURE_FAN },
109        { "min", SENSORS_FEATURE_FAN_MIN },
110        { "div", SENSORS_FEATURE_FAN_DIV },
111        { "alarm", SENSORS_FEATURE_FAN_ALARM },
112        { "fault", SENSORS_FEATURE_FAN_FAULT },
113        { NULL, 0 }
114};
115
116static const struct feature_subtype_match cpu_matches[] = {
117        { "vid", SENSORS_FEATURE_VID },
118        { NULL, 0 }
119};
120
121static struct feature_type_match matches[] = {
122        { "temp%d%c", temp_matches },
123        { "in%d%c", in_matches },
124        { "fan%d%c", fan_matches },
125        { "cpu%d%c", cpu_matches },
126};
127
128/* Return the feature type and channel number based on the feature name */
129static
130sensors_feature_type sensors_feature_get_type(const char *name, int *nr)
131{
132        char c;
133        int i, count;
134        const struct feature_subtype_match *submatches;
135
136        /* Special case */
137        if (!strcmp(name, "beep_enable")) {
138                *nr = 0;
139                return SENSORS_FEATURE_BEEP_ENABLE;
140        }
141
142        for (i = 0; i < ARRAY_SIZE(matches); i++)
143                if ((count = sscanf(name, matches[i].name, nr, &c)))
144                        break;
145
146        if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
147                return SENSORS_FEATURE_UNKNOWN;  /* no match */
148
149        submatches = matches[i].submatches;
150        name = strchr(name + 3, '_') + 1;
151        for (i = 0; submatches[i].name != NULL; i++)
152                if (!strcmp(name, submatches[i].name))
153                        return submatches[i].type;
154
155        return SENSORS_FEATURE_UNKNOWN;
156}
157
158static int sensors_read_dynamic_chip(sensors_chip_features *chip,
159                                     struct sysfs_device *sysdir)
160{
161        int i, type, fnum = 0;
162        struct sysfs_attribute *attr;
163        struct dlist *attrs;
164        sensors_chip_feature *features;
165        sensors_chip_feature *dyn_features;
166        char *name;
167
168        attrs = sysfs_get_device_attributes(sysdir);
169
170        if (attrs == NULL)
171                return -ENOENT;
172
173        /* We use a large sparse table at first to store all found features,
174           so that we can store them sorted at type and index and then later
175           create a dense sorted table. */
176        features = calloc(ALL_POSSIBLE_FEATURES, sizeof(sensors_chip_feature));
177        if (!features)
178                sensors_fatal_error(__FUNCTION__, "Out of memory");
179
180        dlist_for_each_data(attrs, attr, struct sysfs_attribute) {
181                name = attr->name;
182                int nr;
183
184                type = sensors_feature_get_type(name, &nr);
185                if (type == SENSORS_FEATURE_UNKNOWN)
186                        continue;
187
188                /* Adjust the channel number */
189                switch (type & 0xFF00) {
190                        case SENSORS_FEATURE_FAN:
191                        case SENSORS_FEATURE_TEMP:
192                                if (nr)
193                                        nr--;
194                                break;
195                }
196
197                if (nr >= MAX_SENSORS_PER_TYPE) {
198                        fprintf(stderr, "libsensors error, more sensors of one"
199                                " type then MAX_SENSORS_PER_TYPE, ignoring "
200                                "feature: %s\n", name);
201                        continue;
202                }
203
204                /* "calculate" a place to store the feature in our sparse,
205                   sorted table */
206                switch (type) {
207                case SENSORS_FEATURE_VID:
208                        i = nr + MAX_SENSORS_PER_TYPE * MAX_SUB_FEATURES * 6;
209                        break;
210                case SENSORS_FEATURE_BEEP_ENABLE:
211                        i = MAX_SENSORS_PER_TYPE * MAX_SUB_FEATURES * 6 +
212                            MAX_SENSORS_PER_TYPE;
213                        break;
214                default:
215                        i = (type >> 8) * MAX_SENSORS_PER_TYPE *
216                            MAX_SUB_FEATURES * 2 + nr * MAX_SUB_FEATURES * 2 +
217                            ((type & 0x10) >> 4) * MAX_SUB_FEATURES +
218                            (type & 0x0F);
219                }
220
221                if (features[i].data.name) {
222                        fprintf(stderr, "libsensors error, trying to add dupli"
223                                "cate feature: %s to dynamic feature table\n",
224                                name);
225                        continue;
226                }
227
228                /* fill in the feature members */
229                features[i].data.type = type;
230
231                /* check for _input extension and remove */
232                nr = strlen(name);
233                if (nr > 6 && !strcmp(name + nr - 6, "_input"))
234                        features[i].data.name = strndup(name, nr - 6);
235                else
236                        features[i].data.name = strdup(name);
237
238                if ((type & 0x00FF) == 0) {
239                        /* main feature */
240                        features[i].data.mapping = SENSORS_NO_MAPPING;
241                } else {
242                        /* sub feature */
243                        /* The mapping is set below after numbering */
244                        if (!(type & 0x10))
245                                features[i].data.flags |= SENSORS_COMPUTE_MAPPING;
246                }
247
248                if (attr->method & SYSFS_METHOD_SHOW)
249                        features[i].data.flags |= SENSORS_MODE_R;
250                if (attr->method & SYSFS_METHOD_STORE)
251                        features[i].data.flags |= SENSORS_MODE_W;
252
253                fnum++;
254        }
255
256        if (!fnum) { /* No feature */
257                chip->feature = NULL;
258                goto exit_free;
259        }
260
261        dyn_features = calloc(fnum, sizeof(sensors_chip_feature));
262        if (dyn_features == NULL) {
263                sensors_fatal_error(__FUNCTION__, "Out of memory");
264        }
265
266        fnum = 0;
267        for (i = 0; i < ALL_POSSIBLE_FEATURES; i++) {
268                if (features[i].data.name) {
269                        dyn_features[fnum] = features[i];
270                        fnum++;
271                }
272        }
273
274        /* Number the features linearly, so that feature number N is at
275           position N in the array. This allows for O(1) look-ups. */
276        for (i = 0; i < fnum; i++) {
277                int j;
278
279                dyn_features[i].data.number = i;
280                if (dyn_features[i].data.mapping == SENSORS_NO_MAPPING) {
281                        /* Main feature, set the mapping field of all its
282                           subfeatures */
283                        for (j = i + 1; j < fnum &&
284                             dyn_features[j].data.mapping != SENSORS_NO_MAPPING;
285                             j++)
286                                dyn_features[j].data.mapping = i;
287                }
288        }
289
290        chip->feature = dyn_features;
291        chip->feature_count = fnum;
292
293exit_free:
294        free(features);
295        return 0;
296}
297
298/* returns !0 if sysfs filesystem was found, 0 otherwise */
299int sensors_init_sysfs(void)
300{
301        struct stat statbuf;
302
303        /* libsysfs will return success even if sysfs is not mounted,
304           so we have to double-check */
305        if (sysfs_get_mnt_path(sensors_sysfs_mount, NAME_MAX)
306         || stat(sensors_sysfs_mount, &statbuf) < 0
307         || statbuf.st_nlink <= 2)      /* Empty directory */
308                return 0;
309
310        return 1;
311}
312
313/* returns: 0 if successful, !0 otherwise */
314static int sensors_read_one_sysfs_chip(struct sysfs_device *dev)
315{
316        int domain, bus, slot, fn;
317        int err = -SENSORS_ERR_PARSE;
318        struct sysfs_attribute *attr, *bus_attr;
319        char bus_path[SYSFS_PATH_MAX];
320        sensors_chip_features entry;
321
322        /* ignore any device without name attribute */
323        if (!(attr = sysfs_get_device_attr(dev, "name")))
324                return 0;
325
326        /* NB: attr->value[attr->len-1] == '\n'; chop that off */
327        entry.chip.prefix = strndup(attr->value, attr->len - 1);
328        if (!entry.chip.prefix)
329                sensors_fatal_error(__FUNCTION__, "out of memory");
330
331        entry.chip.path = strdup(dev->path);
332        if (!entry.chip.path)
333                sensors_fatal_error(__FUNCTION__, "out of memory");
334
335        if (sscanf(dev->name, "%hd-%x", &entry.chip.bus.nr, &entry.chip.addr) == 2) {
336                /* find out if legacy ISA or not */
337                if (entry.chip.bus.nr == 9191) {
338                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
339                        entry.chip.bus.nr = 0;
340                } else {
341                        entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
342                        snprintf(bus_path, sizeof(bus_path),
343                                "%s/class/i2c-adapter/i2c-%d/device/name",
344                                sensors_sysfs_mount, entry.chip.bus.nr);
345
346                        if ((bus_attr = sysfs_open_attribute(bus_path))) {
347                                if (sysfs_read_attribute(bus_attr)) {
348                                        sysfs_close_attribute(bus_attr);
349                                        goto exit_free;
350                                }
351
352                                if (bus_attr->value
353                                 && !strncmp(bus_attr->value, "ISA ", 4)) {
354                                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
355                                        entry.chip.bus.nr = 0;
356                                }
357
358                                sysfs_close_attribute(bus_attr);
359                        }
360                }
361        } else if (sscanf(dev->name, "spi%hd.%d", &entry.chip.bus.nr,
362                          &entry.chip.addr) == 2) {
363                /* SPI */
364                entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
365        } else if (sscanf(dev->name, "%*[a-z0-9_].%d", &entry.chip.addr) == 1) {
366                /* must be new ISA (platform driver) */
367                entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
368                entry.chip.bus.nr = 0;
369        } else if (sscanf(dev->name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
370                /* PCI */
371                entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
372                entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
373                entry.chip.bus.nr = 0;
374        } else
375                goto exit_free;
376
377        if (sensors_read_dynamic_chip(&entry, dev) < 0)
378                goto exit_free;
379        if (!entry.feature) { /* No feature, discard chip */
380                err = 0;
381                goto exit_free;
382        }
383        sensors_add_proc_chips(&entry);
384
385        return 0;
386
387exit_free:
388        free(entry.chip.prefix);
389        free(entry.chip.path);
390        return err;
391}
392
393/* returns 0 if successful, !0 otherwise */
394static int sensors_read_sysfs_chips_compat(void)
395{
396        struct sysfs_bus *bus;
397        struct dlist *devs;
398        struct sysfs_device *dev;
399        int ret = 0;
400
401        if (!(bus = sysfs_open_bus("i2c"))) {
402                if (errno && errno != ENOENT)
403                        ret = -SENSORS_ERR_PROC;
404                goto exit0;
405        }
406
407        if (!(devs = sysfs_get_bus_devices(bus))) {
408                if (errno && errno != ENOENT)
409                        ret = -SENSORS_ERR_PROC;
410                goto exit1;
411        }
412
413        dlist_for_each_data(devs, dev, struct sysfs_device)
414                if ((ret = sensors_read_one_sysfs_chip(dev)))
415                        goto exit1;
416
417exit1:
418        /* this frees bus and devs */
419        sysfs_close_bus(bus);
420
421exit0:
422        return ret;
423}
424
425/* returns 0 if successful, !0 otherwise */
426int sensors_read_sysfs_chips(void)
427{
428        struct sysfs_class *cls;
429        struct dlist *clsdevs;
430        struct sysfs_class_device *clsdev;
431        int ret = 0;
432
433        if (!(cls = sysfs_open_class("hwmon"))) {
434                /* compatibility function for kernel 2.6.n where n <= 13 */
435                return sensors_read_sysfs_chips_compat();
436        }
437
438        if (!(clsdevs = sysfs_get_class_devices(cls))) {
439                if (errno && errno != ENOENT)
440                        ret = -SENSORS_ERR_PROC;
441                goto exit;
442        }
443
444        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
445                struct sysfs_device *dev;
446                if (!(dev = sysfs_get_classdev_device(clsdev))) {
447                        ret = -SENSORS_ERR_PROC;
448                        goto exit;
449                }
450                if ((ret = sensors_read_one_sysfs_chip(dev)))
451                        goto exit;
452        }
453
454exit:
455        /* this frees cls and clsdevs */
456        sysfs_close_class(cls);
457        return ret;
458}
459
460/* returns 0 if successful, !0 otherwise */
461int sensors_read_sysfs_bus(void)
462{
463        struct sysfs_class *cls;
464        struct dlist *clsdevs;
465        struct sysfs_class_device *clsdev;
466        sensors_bus entry;
467        int ret = 0;
468
469        if (!(cls = sysfs_open_class("i2c-adapter"))) {
470                if (errno && errno != ENOENT)
471                        ret = -SENSORS_ERR_PROC;
472                goto exit0;
473        }
474
475        if (!(clsdevs = sysfs_get_class_devices(cls))) {
476                if (errno && errno != ENOENT)
477                        ret = -SENSORS_ERR_PROC;
478                goto exit1;
479        }
480
481        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
482                struct sysfs_device *dev;
483                struct sysfs_attribute *attr;
484
485                /* Get the adapter name from the classdev "name" attribute
486                 * (Linux 2.6.20 and later). If it fails, fall back to
487                 * the device "name" attribute (for older kernels). */
488                if (!(attr = sysfs_get_classdev_attr(clsdev, "name"))
489                 && !((dev = sysfs_get_classdev_device(clsdev)) &&
490                      (attr = sysfs_get_device_attr(dev, "name"))))
491                        continue;
492
493                if (sscanf(clsdev->name, "i2c-%hd", &entry.bus.nr) != 1 ||
494                    entry.bus.nr == 9191) /* legacy ISA */
495                        continue;
496                entry.bus.type = SENSORS_BUS_TYPE_I2C;
497
498                /* NB: attr->value[attr->len-1] == '\n'; chop that off */
499                entry.adapter = strndup(attr->value, attr->len - 1);
500                if (!entry.adapter)
501                        sensors_fatal_error(__FUNCTION__, "out of memory");
502
503                sensors_add_proc_bus(&entry);
504        }
505
506exit1:
507        /* this frees *cls _and_ *clsdevs */
508        sysfs_close_class(cls);
509
510exit0:
511        return ret;
512}
513
514int sensors_read_sysfs_attr(const sensors_chip_name *name, int feature,
515                            double *value)
516{
517        const sensors_chip_feature *the_feature;
518        char n[NAME_MAX];
519        FILE *f;
520        const char *suffix = "";
521
522        if (!(the_feature = sensors_lookup_feature_nr(name, feature)))
523                return -SENSORS_ERR_NO_ENTRY;
524
525        /* REVISIT: this is a ugly hack */
526        if (the_feature->data.type == SENSORS_FEATURE_IN
527         || the_feature->data.type == SENSORS_FEATURE_FAN
528         || the_feature->data.type == SENSORS_FEATURE_TEMP)
529                suffix = "_input";
530
531        snprintf(n, NAME_MAX, "%s/%s%s", name->path, the_feature->data.name,
532                 suffix);
533        if ((f = fopen(n, "r"))) {
534                int res = fscanf(f, "%lf", value);
535                fclose(f);
536                if (res != 1)
537                        return -SENSORS_ERR_PROC;
538                *value /= get_type_scaling(the_feature->data.type);
539        } else
540                return -SENSORS_ERR_PROC;
541
542        return 0;
543}
544
545int sensors_write_sysfs_attr(const sensors_chip_name *name, int feature,
546                             double value)
547{
548        const sensors_chip_feature *the_feature;
549        char n[NAME_MAX];
550        FILE *f;
551        const char *suffix = "";
552
553        if (!(the_feature = sensors_lookup_feature_nr(name, feature)))
554                return -SENSORS_ERR_NO_ENTRY;
555
556        /* REVISIT: this is a ugly hack */
557        if (the_feature->data.type == SENSORS_FEATURE_IN
558         || the_feature->data.type == SENSORS_FEATURE_FAN
559         || the_feature->data.type == SENSORS_FEATURE_TEMP)
560                suffix = "_input";
561
562        snprintf(n, NAME_MAX, "%s/%s%s", name->path, the_feature->data.name,
563                 suffix);
564        if ((f = fopen(n, "w"))) {
565                value *= get_type_scaling(the_feature->data.type);
566                fprintf(f, "%d", (int) value);
567                fclose(f);
568        } else
569                return -SENSORS_ERR_PROC;
570
571        return 0;
572}
Note: See TracBrowser for help on using the browser.