root/lm-sensors/trunk/lib/sysfs.c @ 5827

Revision 5827, 21.1 KB (checked in by khali, 4 years ago)

Fix a comment.

  • 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-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/* this define needed for strndup() */
23#define _GNU_SOURCE
24
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include <string.h>
29#include <stdlib.h>
30#include <limits.h>
31#include <errno.h>
32#include <dirent.h>
33#include "data.h"
34#include "error.h"
35#include "access.h"
36#include "general.h"
37#include "sysfs.h"
38
39
40/****************************************************************************/
41
42#define ATTR_MAX        128
43
44/*
45 * Read an attribute from sysfs
46 * Returns a pointer to a freshly allocated string; free it yourself.
47 * If the file doesn't exist or can't be read, NULL is returned.
48 */
49static char *sysfs_read_attr(const char *device, const char *attr)
50{
51        char path[NAME_MAX];
52        char buf[ATTR_MAX], *p;
53        FILE *f;
54
55        snprintf(path, NAME_MAX, "%s/%s", device, attr);
56
57        if (!(f = fopen(path, "r")))
58                return NULL;
59        p = fgets(buf, ATTR_MAX, f);
60        fclose(f);
61        if (!p)
62                return NULL;
63
64        /* Last byte is a '\n'; chop that off */
65        p = strndup(buf, strlen(buf) - 1);
66        if (!p)
67                sensors_fatal_error(__func__, "Out of memory");
68        return p;
69}
70
71/*
72 * Call an arbitrary function for each class device of the given class
73 * Returns 0 on success (all calls returned 0), a positive errno for
74 * local errors, or a negative error value if any call fails.
75 */
76static int sysfs_foreach_classdev(const char *class_name,
77                                   int (*func)(const char *, const char *))
78{
79        char path[NAME_MAX];
80        int path_off, ret;
81        DIR *dir;
82        struct dirent *ent;
83
84        path_off = snprintf(path, NAME_MAX, "%s/class/%s",
85                            sensors_sysfs_mount, class_name);
86        if (!(dir = opendir(path)))
87                return errno;
88
89        ret = 0;
90        while (!ret && (ent = readdir(dir))) {
91                if (ent->d_name[0] == '.')      /* skip hidden entries */
92                        continue;
93
94                snprintf(path + path_off, NAME_MAX - path_off, "/%s",
95                         ent->d_name);
96                ret = func(path, ent->d_name);
97        }
98
99        closedir(dir);
100        return ret;
101}
102
103/*
104 * Call an arbitrary function for each device of the given bus type
105 * Returns 0 on success (all calls returned 0), a positive errno for
106 * local errors, or a negative error value if any call fails.
107 */
108static int sysfs_foreach_busdev(const char *bus_type,
109                                 int (*func)(const char *, const char *))
110{
111        char path[NAME_MAX];
112        int path_off, ret;
113        DIR *dir;
114        struct dirent *ent;
115
116        path_off = snprintf(path, NAME_MAX, "%s/bus/%s/devices",
117                            sensors_sysfs_mount, bus_type);
118        if (!(dir = opendir(path)))
119                return errno;
120
121        ret = 0;
122        while (!ret && (ent = readdir(dir))) {
123                if (ent->d_name[0] == '.')      /* skip hidden entries */
124                        continue;
125
126                snprintf(path + path_off, NAME_MAX - path_off, "/%s",
127                         ent->d_name);
128                ret = func(path, ent->d_name);
129        }
130
131        closedir(dir);
132        return ret;
133}
134
135/****************************************************************************/
136
137char sensors_sysfs_mount[NAME_MAX];
138
139#define MAX_SENSORS_PER_TYPE    24
140#define MAX_SUBFEATURES         8
141#define MAX_SENSOR_TYPES        6
142/* Room for all 6 types (in, fan, temp, power, energy, current) with all
143   their subfeatures + VID + misc features */
144#define ALL_POSSIBLE_SUBFEATURES \
145                                (MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * \
146                                 MAX_SENSOR_TYPES * 2 + \
147                                 MAX_SENSORS_PER_TYPE + 1)
148
149static
150int get_type_scaling(sensors_subfeature_type type)
151{
152        /* Multipliers for subfeatures */
153        switch (type & 0xFF80) {
154        case SENSORS_SUBFEATURE_IN_INPUT:
155        case SENSORS_SUBFEATURE_TEMP_INPUT:
156        case SENSORS_SUBFEATURE_CURR_INPUT:
157                return 1000;
158        case SENSORS_SUBFEATURE_FAN_INPUT:
159                return 1;
160        case SENSORS_SUBFEATURE_POWER_AVERAGE:
161        case SENSORS_SUBFEATURE_ENERGY_INPUT:
162                return 1000000;
163        }
164
165        /* Multipliers for second class subfeatures
166           that need their own multiplier */
167        switch (type) {
168        case SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL:
169        case SENSORS_SUBFEATURE_VID:
170        case SENSORS_SUBFEATURE_TEMP_OFFSET:
171                return 1000;
172        default:
173                return 1;
174        }
175}
176
177static
178char *get_feature_name(sensors_feature_type ftype, char *sfname)
179{
180        char *name, *underscore;
181
182        switch (ftype) {
183        case SENSORS_FEATURE_IN:
184        case SENSORS_FEATURE_FAN:
185        case SENSORS_FEATURE_TEMP:
186        case SENSORS_FEATURE_POWER:
187        case SENSORS_FEATURE_ENERGY:
188        case SENSORS_FEATURE_CURR:
189                underscore = strchr(sfname, '_');
190                name = strndup(sfname, underscore - sfname);
191                if (!name)
192                        sensors_fatal_error(__func__, "Out of memory");
193
194                break;
195        default:
196                name = strdup(sfname);
197                if (!name)
198                        sensors_fatal_error(__func__, "Out of memory");
199        }
200
201        return name;
202}
203
204/* Static mappings for use by sensors_subfeature_get_type() */
205struct subfeature_type_match
206{
207        const char *name;
208        sensors_subfeature_type type;
209};
210
211struct feature_type_match
212{
213        const char *name;
214        const struct subfeature_type_match *submatches;
215};
216
217static const struct subfeature_type_match temp_matches[] = {
218        { "input", SENSORS_SUBFEATURE_TEMP_INPUT },
219        { "max", SENSORS_SUBFEATURE_TEMP_MAX },
220        { "max_hyst", SENSORS_SUBFEATURE_TEMP_MAX_HYST },
221        { "min", SENSORS_SUBFEATURE_TEMP_MIN },
222        { "crit", SENSORS_SUBFEATURE_TEMP_CRIT },
223        { "crit_hyst", SENSORS_SUBFEATURE_TEMP_CRIT_HYST },
224        { "alarm", SENSORS_SUBFEATURE_TEMP_ALARM },
225        { "min_alarm", SENSORS_SUBFEATURE_TEMP_MIN_ALARM },
226        { "max_alarm", SENSORS_SUBFEATURE_TEMP_MAX_ALARM },
227        { "crit_alarm", SENSORS_SUBFEATURE_TEMP_CRIT_ALARM },
228        { "fault", SENSORS_SUBFEATURE_TEMP_FAULT },
229        { "type", SENSORS_SUBFEATURE_TEMP_TYPE },
230        { "offset", SENSORS_SUBFEATURE_TEMP_OFFSET },
231        { NULL, 0 }
232};
233
234static const struct subfeature_type_match in_matches[] = {
235        { "input", SENSORS_SUBFEATURE_IN_INPUT },
236        { "min", SENSORS_SUBFEATURE_IN_MIN },
237        { "max", SENSORS_SUBFEATURE_IN_MAX },
238        { "alarm", SENSORS_SUBFEATURE_IN_ALARM },
239        { "min_alarm", SENSORS_SUBFEATURE_IN_MIN_ALARM },
240        { "max_alarm", SENSORS_SUBFEATURE_IN_MAX_ALARM },
241        { NULL, 0 }
242};
243
244static const struct subfeature_type_match fan_matches[] = {
245        { "input", SENSORS_SUBFEATURE_FAN_INPUT },
246        { "min", SENSORS_SUBFEATURE_FAN_MIN },
247        { "div", SENSORS_SUBFEATURE_FAN_DIV },
248        { "alarm", SENSORS_SUBFEATURE_FAN_ALARM },
249        { "fault", SENSORS_SUBFEATURE_FAN_FAULT },
250        { NULL, 0 }
251};
252
253static const struct subfeature_type_match power_matches[] = {
254        { "average", SENSORS_SUBFEATURE_POWER_AVERAGE },
255        { "average_highest", SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST },
256        { "average_lowest", SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST },
257        { "input", SENSORS_SUBFEATURE_POWER_INPUT },
258        { "input_highest", SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST },
259        { "input_lowest", SENSORS_SUBFEATURE_POWER_INPUT_LOWEST },
260        { "average_interval", SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL },
261        { NULL, 0 }
262};
263
264static const struct subfeature_type_match energy_matches[] = {
265        { "input", SENSORS_SUBFEATURE_ENERGY_INPUT },
266        { NULL, 0 }
267};
268
269static const struct subfeature_type_match curr_matches[] = {
270        { "input", SENSORS_SUBFEATURE_CURR_INPUT },
271        { "min", SENSORS_SUBFEATURE_CURR_MIN },
272        { "max", SENSORS_SUBFEATURE_CURR_MAX },
273        { "alarm", SENSORS_SUBFEATURE_CURR_ALARM },
274        { "min_alarm", SENSORS_SUBFEATURE_CURR_MIN_ALARM },
275        { "max_alarm", SENSORS_SUBFEATURE_CURR_MAX_ALARM },
276        { NULL, 0 }
277};
278
279static const struct subfeature_type_match cpu_matches[] = {
280        { "vid", SENSORS_SUBFEATURE_VID },
281        { NULL, 0 }
282};
283
284static struct feature_type_match matches[] = {
285        { "temp%d%c", temp_matches },
286        { "in%d%c", in_matches },
287        { "fan%d%c", fan_matches },
288        { "cpu%d%c", cpu_matches },
289        { "power%d%c", power_matches },
290        { "curr%d%c", curr_matches },
291        { "energy%d%c", energy_matches },
292};
293
294/* Return the subfeature type and channel number based on the subfeature
295   name */
296static
297sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr)
298{
299        char c;
300        int i, count;
301        const struct subfeature_type_match *submatches;
302
303        /* Special case */
304        if (!strcmp(name, "beep_enable")) {
305                *nr = 0;
306                return SENSORS_SUBFEATURE_BEEP_ENABLE;
307        }
308
309        for (i = 0; i < ARRAY_SIZE(matches); i++)
310                if ((count = sscanf(name, matches[i].name, nr, &c)))
311                        break;
312
313        if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
314                return SENSORS_SUBFEATURE_UNKNOWN;  /* no match */
315
316        submatches = matches[i].submatches;
317        name = strchr(name + 3, '_') + 1;
318        for (i = 0; submatches[i].name != NULL; i++)
319                if (!strcmp(name, submatches[i].name))
320                        return submatches[i].type;
321
322        return SENSORS_SUBFEATURE_UNKNOWN;
323}
324
325static int sensors_get_attr_mode(const char *device, const char *attr)
326{
327        char path[NAME_MAX];
328        struct stat st;
329        int mode = 0;
330
331        snprintf(path, NAME_MAX, "%s/%s", device, attr);
332        if (!stat(path, &st)) {
333                if (st.st_mode & S_IRUSR)
334                        mode |= SENSORS_MODE_R;
335                if (st.st_mode & S_IWUSR)
336                        mode |= SENSORS_MODE_W;
337        }
338        return mode;
339}
340
341static int sensors_read_dynamic_chip(sensors_chip_features *chip,
342                                     const char *dev_path)
343{
344        int i, fnum = 0, sfnum = 0, prev_slot;
345        DIR *dir;
346        struct dirent *ent;
347        sensors_subfeature *all_subfeatures;
348        sensors_subfeature *dyn_subfeatures;
349        sensors_feature *dyn_features;
350        sensors_feature_type ftype;
351        sensors_subfeature_type sftype;
352
353        if (!(dir = opendir(dev_path)))
354                return -errno;
355
356        /* We use a large sparse table at first to store all found
357           subfeatures, so that we can store them sorted at type and index
358           and then later create a dense sorted table. */
359        all_subfeatures = calloc(ALL_POSSIBLE_SUBFEATURES,
360                                 sizeof(sensors_subfeature));
361        if (!all_subfeatures)
362                sensors_fatal_error(__func__, "Out of memory");
363
364        while ((ent = readdir(dir))) {
365                char *name;
366                int nr;
367
368                /* Skip directories and symlinks */
369                if (ent->d_type != DT_REG)
370                        continue;
371
372                name = ent->d_name;
373
374                sftype = sensors_subfeature_get_type(name, &nr);
375                if (sftype == SENSORS_SUBFEATURE_UNKNOWN)
376                        continue;
377
378                /* Adjust the channel number */
379                switch (sftype & 0xFF00) {
380                case SENSORS_SUBFEATURE_FAN_INPUT:
381                case SENSORS_SUBFEATURE_TEMP_INPUT:
382                case SENSORS_SUBFEATURE_POWER_AVERAGE:
383                case SENSORS_SUBFEATURE_ENERGY_INPUT:
384                case SENSORS_SUBFEATURE_CURR_INPUT:
385                        nr--;
386                        break;
387                }
388
389                if (nr < 0 || nr >= MAX_SENSORS_PER_TYPE) {
390                        /* More sensors of one type than MAX_SENSORS_PER_TYPE,
391                           we have to ignore it */
392#ifdef DEBUG
393                        sensors_fatal_error(__func__,
394                                            "Increase MAX_SENSORS_PER_TYPE!");
395#endif
396                        continue;
397                }
398
399                /* "calculate" a place to store the subfeature in our sparse,
400                   sorted table */
401                switch (sftype) {
402                case SENSORS_SUBFEATURE_VID:
403                        i = nr + MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
404                            MAX_SENSOR_TYPES * 2;
405                        break;
406                case SENSORS_SUBFEATURE_BEEP_ENABLE:
407                        i = MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
408                            MAX_SENSOR_TYPES * 2 + MAX_SENSORS_PER_TYPE;
409                        break;
410                default:
411                        i = (sftype >> 8) * MAX_SENSORS_PER_TYPE *
412                            MAX_SUBFEATURES * 2 + nr * MAX_SUBFEATURES * 2 +
413                            ((sftype & 0x80) >> 7) * MAX_SUBFEATURES +
414                            (sftype & 0x7F);
415                }
416
417                if (all_subfeatures[i].name) {
418#ifdef DEBUG
419                        sensors_fatal_error(__func__, "Duplicate subfeature");
420#endif
421                        continue;
422                }
423
424                /* fill in the subfeature members */
425                all_subfeatures[i].type = sftype;
426                all_subfeatures[i].name = strdup(name);
427                if (!all_subfeatures[i].name)
428                        sensors_fatal_error(__func__, "Out of memory");
429
430                if (!(sftype & 0x80))
431                        all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING;
432                all_subfeatures[i].flags |= sensors_get_attr_mode(dev_path, name);
433
434                sfnum++;
435        }
436        closedir(dir);
437
438        if (!sfnum) { /* No subfeature */
439                chip->subfeature = NULL;
440                goto exit_free;
441        }
442
443        /* How many main features? */
444        prev_slot = -1;
445        for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
446                if (!all_subfeatures[i].name)
447                        continue;
448
449                if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
450                    MAX_SENSOR_TYPES * 2 ||
451                    i / (MAX_SUBFEATURES * 2) != prev_slot) {
452                        fnum++;
453                        prev_slot = i / (MAX_SUBFEATURES * 2);
454                }
455        }
456
457        dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature));
458        dyn_features = calloc(fnum, sizeof(sensors_feature));
459        if (!dyn_subfeatures || !dyn_features)
460                sensors_fatal_error(__func__, "Out of memory");
461
462        /* Copy from the sparse array to the compact array */
463        sfnum = 0;
464        fnum = -1;
465        prev_slot = -1;
466        for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
467                if (!all_subfeatures[i].name)
468                        continue;
469
470                /* New main feature? */
471                if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
472                    MAX_SENSOR_TYPES * 2 ||
473                    i / (MAX_SUBFEATURES * 2) != prev_slot) {
474                        ftype = all_subfeatures[i].type >> 8;
475                        fnum++;
476                        prev_slot = i / (MAX_SUBFEATURES * 2);
477
478                        dyn_features[fnum].name = get_feature_name(ftype,
479                                                all_subfeatures[i].name);
480                        dyn_features[fnum].number = fnum;
481                        dyn_features[fnum].first_subfeature = sfnum;
482                        dyn_features[fnum].type = ftype;
483                }
484
485                dyn_subfeatures[sfnum] = all_subfeatures[i];
486                dyn_subfeatures[sfnum].number = sfnum;
487                /* Back to the feature */
488                dyn_subfeatures[sfnum].mapping = fnum;
489
490                sfnum++;
491        }
492
493        chip->subfeature = dyn_subfeatures;
494        chip->subfeature_count = sfnum;
495        chip->feature = dyn_features;
496        chip->feature_count = ++fnum;
497
498exit_free:
499        free(all_subfeatures);
500        return 0;
501}
502
503/* returns !0 if sysfs filesystem was found, 0 otherwise */
504int sensors_init_sysfs(void)
505{
506        struct stat statbuf;
507
508        snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys");
509        if (stat(sensors_sysfs_mount, &statbuf) < 0
510         || statbuf.st_nlink <= 2)      /* Empty directory */
511                return 0;
512
513        return 1;
514}
515
516/* returns: number of devices added (0 or 1) if successful, <0 otherwise */
517static int sensors_read_one_sysfs_chip(const char *dev_path,
518                                       const char *dev_name,
519                                       const char *hwmon_path)
520{
521        int domain, bus, slot, fn, vendor, product, id;
522        int err = -SENSORS_ERR_KERNEL;
523        char *bus_attr;
524        char bus_path[NAME_MAX];
525        char linkpath[NAME_MAX];
526        char subsys_path[NAME_MAX], *subsys;
527        int sub_len;
528        sensors_chip_features entry;
529
530        /* ignore any device without name attribute */
531        if (!(entry.chip.prefix = sysfs_read_attr(hwmon_path, "name")))
532                return 0;
533
534        entry.chip.path = strdup(hwmon_path);
535        if (!entry.chip.path)
536                sensors_fatal_error(__func__, "Out of memory");
537
538        if (dev_path == NULL) {
539                /* Virtual device */
540                entry.chip.bus.type = SENSORS_BUS_TYPE_VIRTUAL;
541                entry.chip.bus.nr = 0;
542                /* For now we assume that virtual devices are unique */
543                entry.chip.addr = 0;
544                goto done;
545        }
546
547        /* Find bus type */
548        snprintf(linkpath, NAME_MAX, "%s/subsystem", dev_path);
549        sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
550        if (sub_len < 0 && errno == ENOENT) {
551                /* Fallback to "bus" link for kernels <= 2.6.17 */
552                snprintf(linkpath, NAME_MAX, "%s/bus", dev_path);
553                sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
554        }
555        if (sub_len < 0) {
556                /* Older kernels (<= 2.6.11) have neither the subsystem
557                   symlink nor the bus symlink */
558                if (errno == ENOENT)
559                        subsys = NULL;
560                else
561                        goto exit_free;
562        } else {
563                subsys_path[sub_len] = '\0';
564                subsys = strrchr(subsys_path, '/') + 1;
565        }
566
567        if ((!subsys || !strcmp(subsys, "i2c")) &&
568            sscanf(dev_name, "%hd-%x", &entry.chip.bus.nr,
569                   &entry.chip.addr) == 2) {
570                /* find out if legacy ISA or not */
571                if (entry.chip.bus.nr == 9191) {
572                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
573                        entry.chip.bus.nr = 0;
574                } else {
575                        entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
576                        snprintf(bus_path, sizeof(bus_path),
577                                "%s/class/i2c-adapter/i2c-%d/device",
578                                sensors_sysfs_mount, entry.chip.bus.nr);
579
580                        if ((bus_attr = sysfs_read_attr(bus_path, "name"))) {
581                                if (!strncmp(bus_attr, "ISA ", 4)) {
582                                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
583                                        entry.chip.bus.nr = 0;
584                                }
585
586                                free(bus_attr);
587                        }
588                }
589        } else
590        if ((!subsys || !strcmp(subsys, "spi")) &&
591            sscanf(dev_name, "spi%hd.%d", &entry.chip.bus.nr,
592                   &entry.chip.addr) == 2) {
593                /* SPI */
594                entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
595        } else
596        if ((!subsys || !strcmp(subsys, "pci")) &&
597            sscanf(dev_name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
598                /* PCI */
599                entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
600                entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
601                entry.chip.bus.nr = 0;
602        } else
603        if ((!subsys || !strcmp(subsys, "platform") ||
604                        !strcmp(subsys, "of_platform"))) {
605                /* must be new ISA (platform driver) */
606                if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry.chip.addr) != 1)
607                        entry.chip.addr = 0;
608                entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
609                entry.chip.bus.nr = 0;
610        } else if (subsys && !strcmp(subsys, "acpi")) {
611                entry.chip.bus.type = SENSORS_BUS_TYPE_ACPI;
612                /* For now we assume that acpi devices are unique */
613                entry.chip.bus.nr = 0;
614                entry.chip.addr = 0;
615        } else
616        if (subsys && !strcmp(subsys, "hid") &&
617            sscanf(dev_name, "%x:%x:%x.%x", &bus, &vendor, &product, &id) == 4) {
618                entry.chip.bus.type = SENSORS_BUS_TYPE_HID;
619                /* As of kernel 2.6.32, the hid device names don't look good */
620                entry.chip.bus.nr = bus;
621                entry.chip.addr = id;
622        } else {
623                /* Ignore unknown device */
624                err = 0;
625                goto exit_free;
626        }
627
628done:
629        if (sensors_read_dynamic_chip(&entry, hwmon_path) < 0)
630                goto exit_free;
631        if (!entry.subfeature) { /* No subfeature, discard chip */
632                err = 0;
633                goto exit_free;
634        }
635        sensors_add_proc_chips(&entry);
636
637        return 1;
638
639exit_free:
640        free(entry.chip.prefix);
641        free(entry.chip.path);
642        return err;
643}
644
645static int sensors_add_hwmon_device_compat(const char *path,
646                                           const char *dev_name)
647{
648        int err;
649
650        err = sensors_read_one_sysfs_chip(path, dev_name, path);
651        if (err < 0)
652                return err;
653        return 0;
654}
655
656/* returns 0 if successful, !0 otherwise */
657static int sensors_read_sysfs_chips_compat(void)
658{
659        int ret;
660
661        ret = sysfs_foreach_busdev("i2c", sensors_add_hwmon_device_compat);
662        if (ret && ret != ENOENT)
663                return -SENSORS_ERR_KERNEL;
664
665        return 0;
666}
667
668static int sensors_add_hwmon_device(const char *path, const char *classdev)
669{
670        char linkpath[NAME_MAX];
671        char device[NAME_MAX], *device_p;
672        int dev_len, err;
673        (void)classdev; /* hide warning */
674
675        snprintf(linkpath, NAME_MAX, "%s/device", path);
676        dev_len = readlink(linkpath, device, NAME_MAX - 1);
677        if (dev_len < 0) {
678                /* No device link? Treat as virtual */
679                err = sensors_read_one_sysfs_chip(NULL, NULL, path);
680        } else {
681                device[dev_len] = '\0';
682                device_p = strrchr(device, '/') + 1;
683
684                /* The attributes we want might be those of the hwmon class
685                   device, or those of the device itself. */
686                err = sensors_read_one_sysfs_chip(linkpath, device_p, path);
687                if (err == 0)
688                        err = sensors_read_one_sysfs_chip(linkpath, device_p,
689                                                          linkpath);
690        }
691        if (err < 0)
692                return err;
693        return 0;
694}
695
696/* returns 0 if successful, !0 otherwise */
697int sensors_read_sysfs_chips(void)
698{
699        int ret;
700
701        ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device);
702        if (ret == ENOENT) {
703                /* compatibility function for kernel 2.6.n where n <= 13 */
704                return sensors_read_sysfs_chips_compat();
705        }
706
707        if (ret > 0)
708                ret = -SENSORS_ERR_KERNEL;
709        return ret;
710}
711
712/* returns 0 if successful, !0 otherwise */
713static int sensors_add_i2c_bus(const char *path, const char *classdev)
714{
715        sensors_bus entry;
716
717        if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 ||
718            entry.bus.nr == 9191) /* legacy ISA */
719                return 0;
720        entry.bus.type = SENSORS_BUS_TYPE_I2C;
721
722        /* Get the adapter name from the classdev "name" attribute
723         * (Linux 2.6.20 and later). If it fails, fall back to
724         * the device "name" attribute (for older kernels). */
725        entry.adapter = sysfs_read_attr(path, "name");
726        if (!entry.adapter)
727                entry.adapter = sysfs_read_attr(path, "device/name");
728        if (entry.adapter)
729                sensors_add_proc_bus(&entry);
730
731        return 0;
732}
733
734/* returns 0 if successful, !0 otherwise */
735int sensors_read_sysfs_bus(void)
736{
737        int ret;
738
739        ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus);
740        if (ret == ENOENT)
741                ret = sysfs_foreach_busdev("i2c", sensors_add_i2c_bus);
742        if (ret && ret != ENOENT)
743                return -SENSORS_ERR_KERNEL;
744
745        return 0;
746}
747
748int sensors_read_sysfs_attr(const sensors_chip_name *name,
749                            const sensors_subfeature *subfeature,
750                            double *value)
751{
752        char n[NAME_MAX];
753        FILE *f;
754
755        snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
756        if ((f = fopen(n, "r"))) {
757                int res, err = 0;
758
759                errno = 0;
760                res = fscanf(f, "%lf", value);
761                if (res == EOF && errno == EIO)
762                        err = -SENSORS_ERR_IO;
763                else if (res != 1)
764                        err = -SENSORS_ERR_ACCESS_R;
765                res = fclose(f);
766                if (err)
767                        return err;
768
769                if (res == EOF) {
770                        if (errno == EIO)
771                                return -SENSORS_ERR_IO;
772                        else 
773                                return -SENSORS_ERR_ACCESS_R;
774                }
775                *value /= get_type_scaling(subfeature->type);
776        } else
777                return -SENSORS_ERR_KERNEL;
778
779        return 0;
780}
781
782int sensors_write_sysfs_attr(const sensors_chip_name *name,
783                             const sensors_subfeature *subfeature,
784                             double value)
785{
786        char n[NAME_MAX];
787        FILE *f;
788
789        snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
790        if ((f = fopen(n, "w"))) {
791                int res, err = 0;
792
793                value *= get_type_scaling(subfeature->type);
794                res = fprintf(f, "%d", (int) value);
795                if (res == -EIO)
796                        err = -SENSORS_ERR_IO;
797                else if (res < 0)
798                        err = -SENSORS_ERR_ACCESS_W;
799                res = fclose(f);
800                if (err)
801                        return err;
802
803                if (res == EOF) {
804                        if (errno == EIO)
805                                return -SENSORS_ERR_IO;
806                        else 
807                                return -SENSORS_ERR_ACCESS_W;
808                }
809        } else
810                return -SENSORS_ERR_KERNEL;
811
812        return 0;
813}
Note: See TracBrowser for help on using the browser.