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

Revision 5844, 21.3 KB (checked in by khali, 3 years ago)

Change libsensors license from GPL to LGPL.

  • 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 library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    This library 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 Lesser 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        { "beep", SENSORS_SUBFEATURE_TEMP_BEEP },
232        { NULL, 0 }
233};
234
235static const struct subfeature_type_match in_matches[] = {
236        { "input", SENSORS_SUBFEATURE_IN_INPUT },
237        { "min", SENSORS_SUBFEATURE_IN_MIN },
238        { "max", SENSORS_SUBFEATURE_IN_MAX },
239        { "alarm", SENSORS_SUBFEATURE_IN_ALARM },
240        { "min_alarm", SENSORS_SUBFEATURE_IN_MIN_ALARM },
241        { "max_alarm", SENSORS_SUBFEATURE_IN_MAX_ALARM },
242        { "beep", SENSORS_SUBFEATURE_IN_BEEP },
243        { NULL, 0 }
244};
245
246static const struct subfeature_type_match fan_matches[] = {
247        { "input", SENSORS_SUBFEATURE_FAN_INPUT },
248        { "min", SENSORS_SUBFEATURE_FAN_MIN },
249        { "div", SENSORS_SUBFEATURE_FAN_DIV },
250        { "alarm", SENSORS_SUBFEATURE_FAN_ALARM },
251        { "fault", SENSORS_SUBFEATURE_FAN_FAULT },
252        { "beep", SENSORS_SUBFEATURE_FAN_BEEP },
253        { NULL, 0 }
254};
255
256static const struct subfeature_type_match power_matches[] = {
257        { "average", SENSORS_SUBFEATURE_POWER_AVERAGE },
258        { "average_highest", SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST },
259        { "average_lowest", SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST },
260        { "input", SENSORS_SUBFEATURE_POWER_INPUT },
261        { "input_highest", SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST },
262        { "input_lowest", SENSORS_SUBFEATURE_POWER_INPUT_LOWEST },
263        { "average_interval", SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL },
264        { NULL, 0 }
265};
266
267static const struct subfeature_type_match energy_matches[] = {
268        { "input", SENSORS_SUBFEATURE_ENERGY_INPUT },
269        { NULL, 0 }
270};
271
272static const struct subfeature_type_match curr_matches[] = {
273        { "input", SENSORS_SUBFEATURE_CURR_INPUT },
274        { "min", SENSORS_SUBFEATURE_CURR_MIN },
275        { "max", SENSORS_SUBFEATURE_CURR_MAX },
276        { "alarm", SENSORS_SUBFEATURE_CURR_ALARM },
277        { "min_alarm", SENSORS_SUBFEATURE_CURR_MIN_ALARM },
278        { "max_alarm", SENSORS_SUBFEATURE_CURR_MAX_ALARM },
279        { "beep", SENSORS_SUBFEATURE_CURR_BEEP },
280        { NULL, 0 }
281};
282
283static const struct subfeature_type_match cpu_matches[] = {
284        { "vid", SENSORS_SUBFEATURE_VID },
285        { NULL, 0 }
286};
287
288static struct feature_type_match matches[] = {
289        { "temp%d%c", temp_matches },
290        { "in%d%c", in_matches },
291        { "fan%d%c", fan_matches },
292        { "cpu%d%c", cpu_matches },
293        { "power%d%c", power_matches },
294        { "curr%d%c", curr_matches },
295        { "energy%d%c", energy_matches },
296};
297
298/* Return the subfeature type and channel number based on the subfeature
299   name */
300static
301sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr)
302{
303        char c;
304        int i, count;
305        const struct subfeature_type_match *submatches;
306
307        /* Special case */
308        if (!strcmp(name, "beep_enable")) {
309                *nr = 0;
310                return SENSORS_SUBFEATURE_BEEP_ENABLE;
311        }
312
313        for (i = 0; i < ARRAY_SIZE(matches); i++)
314                if ((count = sscanf(name, matches[i].name, nr, &c)))
315                        break;
316
317        if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
318                return SENSORS_SUBFEATURE_UNKNOWN;  /* no match */
319
320        submatches = matches[i].submatches;
321        name = strchr(name + 3, '_') + 1;
322        for (i = 0; submatches[i].name != NULL; i++)
323                if (!strcmp(name, submatches[i].name))
324                        return submatches[i].type;
325
326        return SENSORS_SUBFEATURE_UNKNOWN;
327}
328
329static int sensors_get_attr_mode(const char *device, const char *attr)
330{
331        char path[NAME_MAX];
332        struct stat st;
333        int mode = 0;
334
335        snprintf(path, NAME_MAX, "%s/%s", device, attr);
336        if (!stat(path, &st)) {
337                if (st.st_mode & S_IRUSR)
338                        mode |= SENSORS_MODE_R;
339                if (st.st_mode & S_IWUSR)
340                        mode |= SENSORS_MODE_W;
341        }
342        return mode;
343}
344
345static int sensors_read_dynamic_chip(sensors_chip_features *chip,
346                                     const char *dev_path)
347{
348        int i, fnum = 0, sfnum = 0, prev_slot;
349        DIR *dir;
350        struct dirent *ent;
351        sensors_subfeature *all_subfeatures;
352        sensors_subfeature *dyn_subfeatures;
353        sensors_feature *dyn_features;
354        sensors_feature_type ftype;
355        sensors_subfeature_type sftype;
356
357        if (!(dir = opendir(dev_path)))
358                return -errno;
359
360        /* We use a large sparse table at first to store all found
361           subfeatures, so that we can store them sorted at type and index
362           and then later create a dense sorted table. */
363        all_subfeatures = calloc(ALL_POSSIBLE_SUBFEATURES,
364                                 sizeof(sensors_subfeature));
365        if (!all_subfeatures)
366                sensors_fatal_error(__func__, "Out of memory");
367
368        while ((ent = readdir(dir))) {
369                char *name;
370                int nr;
371
372                /* Skip directories and symlinks */
373                if (ent->d_type != DT_REG)
374                        continue;
375
376                name = ent->d_name;
377
378                sftype = sensors_subfeature_get_type(name, &nr);
379                if (sftype == SENSORS_SUBFEATURE_UNKNOWN)
380                        continue;
381
382                /* Adjust the channel number */
383                switch (sftype & 0xFF00) {
384                case SENSORS_SUBFEATURE_FAN_INPUT:
385                case SENSORS_SUBFEATURE_TEMP_INPUT:
386                case SENSORS_SUBFEATURE_POWER_AVERAGE:
387                case SENSORS_SUBFEATURE_ENERGY_INPUT:
388                case SENSORS_SUBFEATURE_CURR_INPUT:
389                        nr--;
390                        break;
391                }
392
393                if (nr < 0 || nr >= MAX_SENSORS_PER_TYPE) {
394                        /* More sensors of one type than MAX_SENSORS_PER_TYPE,
395                           we have to ignore it */
396#ifdef DEBUG
397                        sensors_fatal_error(__func__,
398                                            "Increase MAX_SENSORS_PER_TYPE!");
399#endif
400                        continue;
401                }
402
403                /* "calculate" a place to store the subfeature in our sparse,
404                   sorted table */
405                switch (sftype) {
406                case SENSORS_SUBFEATURE_VID:
407                        i = nr + MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
408                            MAX_SENSOR_TYPES * 2;
409                        break;
410                case SENSORS_SUBFEATURE_BEEP_ENABLE:
411                        i = MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
412                            MAX_SENSOR_TYPES * 2 + MAX_SENSORS_PER_TYPE;
413                        break;
414                default:
415                        i = (sftype >> 8) * MAX_SENSORS_PER_TYPE *
416                            MAX_SUBFEATURES * 2 + nr * MAX_SUBFEATURES * 2 +
417                            ((sftype & 0x80) >> 7) * MAX_SUBFEATURES +
418                            (sftype & 0x7F);
419                }
420
421                if (all_subfeatures[i].name) {
422#ifdef DEBUG
423                        sensors_fatal_error(__func__, "Duplicate subfeature");
424#endif
425                        continue;
426                }
427
428                /* fill in the subfeature members */
429                all_subfeatures[i].type = sftype;
430                all_subfeatures[i].name = strdup(name);
431                if (!all_subfeatures[i].name)
432                        sensors_fatal_error(__func__, "Out of memory");
433
434                if (!(sftype & 0x80))
435                        all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING;
436                all_subfeatures[i].flags |= sensors_get_attr_mode(dev_path, name);
437
438                sfnum++;
439        }
440        closedir(dir);
441
442        if (!sfnum) { /* No subfeature */
443                chip->subfeature = NULL;
444                goto exit_free;
445        }
446
447        /* How many main features? */
448        prev_slot = -1;
449        for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
450                if (!all_subfeatures[i].name)
451                        continue;
452
453                if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
454                    MAX_SENSOR_TYPES * 2 ||
455                    i / (MAX_SUBFEATURES * 2) != prev_slot) {
456                        fnum++;
457                        prev_slot = i / (MAX_SUBFEATURES * 2);
458                }
459        }
460
461        dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature));
462        dyn_features = calloc(fnum, sizeof(sensors_feature));
463        if (!dyn_subfeatures || !dyn_features)
464                sensors_fatal_error(__func__, "Out of memory");
465
466        /* Copy from the sparse array to the compact array */
467        sfnum = 0;
468        fnum = -1;
469        prev_slot = -1;
470        for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
471                if (!all_subfeatures[i].name)
472                        continue;
473
474                /* New main feature? */
475                if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
476                    MAX_SENSOR_TYPES * 2 ||
477                    i / (MAX_SUBFEATURES * 2) != prev_slot) {
478                        ftype = all_subfeatures[i].type >> 8;
479                        fnum++;
480                        prev_slot = i / (MAX_SUBFEATURES * 2);
481
482                        dyn_features[fnum].name = get_feature_name(ftype,
483                                                all_subfeatures[i].name);
484                        dyn_features[fnum].number = fnum;
485                        dyn_features[fnum].first_subfeature = sfnum;
486                        dyn_features[fnum].type = ftype;
487                }
488
489                dyn_subfeatures[sfnum] = all_subfeatures[i];
490                dyn_subfeatures[sfnum].number = sfnum;
491                /* Back to the feature */
492                dyn_subfeatures[sfnum].mapping = fnum;
493
494                sfnum++;
495        }
496
497        chip->subfeature = dyn_subfeatures;
498        chip->subfeature_count = sfnum;
499        chip->feature = dyn_features;
500        chip->feature_count = ++fnum;
501
502exit_free:
503        free(all_subfeatures);
504        return 0;
505}
506
507/* returns !0 if sysfs filesystem was found, 0 otherwise */
508int sensors_init_sysfs(void)
509{
510        struct stat statbuf;
511
512        snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys");
513        if (stat(sensors_sysfs_mount, &statbuf) < 0
514         || statbuf.st_nlink <= 2)      /* Empty directory */
515                return 0;
516
517        return 1;
518}
519
520/* returns: number of devices added (0 or 1) if successful, <0 otherwise */
521static int sensors_read_one_sysfs_chip(const char *dev_path,
522                                       const char *dev_name,
523                                       const char *hwmon_path)
524{
525        int domain, bus, slot, fn, vendor, product, id;
526        int err = -SENSORS_ERR_KERNEL;
527        char *bus_attr;
528        char bus_path[NAME_MAX];
529        char linkpath[NAME_MAX];
530        char subsys_path[NAME_MAX], *subsys;
531        int sub_len;
532        sensors_chip_features entry;
533
534        /* ignore any device without name attribute */
535        if (!(entry.chip.prefix = sysfs_read_attr(hwmon_path, "name")))
536                return 0;
537
538        entry.chip.path = strdup(hwmon_path);
539        if (!entry.chip.path)
540                sensors_fatal_error(__func__, "Out of memory");
541
542        if (dev_path == NULL) {
543                /* Virtual device */
544                entry.chip.bus.type = SENSORS_BUS_TYPE_VIRTUAL;
545                entry.chip.bus.nr = 0;
546                /* For now we assume that virtual devices are unique */
547                entry.chip.addr = 0;
548                goto done;
549        }
550
551        /* Find bus type */
552        snprintf(linkpath, NAME_MAX, "%s/subsystem", dev_path);
553        sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
554        if (sub_len < 0 && errno == ENOENT) {
555                /* Fallback to "bus" link for kernels <= 2.6.17 */
556                snprintf(linkpath, NAME_MAX, "%s/bus", dev_path);
557                sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
558        }
559        if (sub_len < 0) {
560                /* Older kernels (<= 2.6.11) have neither the subsystem
561                   symlink nor the bus symlink */
562                if (errno == ENOENT)
563                        subsys = NULL;
564                else
565                        goto exit_free;
566        } else {
567                subsys_path[sub_len] = '\0';
568                subsys = strrchr(subsys_path, '/') + 1;
569        }
570
571        if ((!subsys || !strcmp(subsys, "i2c")) &&
572            sscanf(dev_name, "%hd-%x", &entry.chip.bus.nr,
573                   &entry.chip.addr) == 2) {
574                /* find out if legacy ISA or not */
575                if (entry.chip.bus.nr == 9191) {
576                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
577                        entry.chip.bus.nr = 0;
578                } else {
579                        entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
580                        snprintf(bus_path, sizeof(bus_path),
581                                "%s/class/i2c-adapter/i2c-%d/device",
582                                sensors_sysfs_mount, entry.chip.bus.nr);
583
584                        if ((bus_attr = sysfs_read_attr(bus_path, "name"))) {
585                                if (!strncmp(bus_attr, "ISA ", 4)) {
586                                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
587                                        entry.chip.bus.nr = 0;
588                                }
589
590                                free(bus_attr);
591                        }
592                }
593        } else
594        if ((!subsys || !strcmp(subsys, "spi")) &&
595            sscanf(dev_name, "spi%hd.%d", &entry.chip.bus.nr,
596                   &entry.chip.addr) == 2) {
597                /* SPI */
598                entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
599        } else
600        if ((!subsys || !strcmp(subsys, "pci")) &&
601            sscanf(dev_name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
602                /* PCI */
603                entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
604                entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
605                entry.chip.bus.nr = 0;
606        } else
607        if ((!subsys || !strcmp(subsys, "platform") ||
608                        !strcmp(subsys, "of_platform"))) {
609                /* must be new ISA (platform driver) */
610                if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry.chip.addr) != 1)
611                        entry.chip.addr = 0;
612                entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
613                entry.chip.bus.nr = 0;
614        } else if (subsys && !strcmp(subsys, "acpi")) {
615                entry.chip.bus.type = SENSORS_BUS_TYPE_ACPI;
616                /* For now we assume that acpi devices are unique */
617                entry.chip.bus.nr = 0;
618                entry.chip.addr = 0;
619        } else
620        if (subsys && !strcmp(subsys, "hid") &&
621            sscanf(dev_name, "%x:%x:%x.%x", &bus, &vendor, &product, &id) == 4) {
622                entry.chip.bus.type = SENSORS_BUS_TYPE_HID;
623                /* As of kernel 2.6.32, the hid device names don't look good */
624                entry.chip.bus.nr = bus;
625                entry.chip.addr = id;
626        } else {
627                /* Ignore unknown device */
628                err = 0;
629                goto exit_free;
630        }
631
632done:
633        if (sensors_read_dynamic_chip(&entry, hwmon_path) < 0)
634                goto exit_free;
635        if (!entry.subfeature) { /* No subfeature, discard chip */
636                err = 0;
637                goto exit_free;
638        }
639        sensors_add_proc_chips(&entry);
640
641        return 1;
642
643exit_free:
644        free(entry.chip.prefix);
645        free(entry.chip.path);
646        return err;
647}
648
649static int sensors_add_hwmon_device_compat(const char *path,
650                                           const char *dev_name)
651{
652        int err;
653
654        err = sensors_read_one_sysfs_chip(path, dev_name, path);
655        if (err < 0)
656                return err;
657        return 0;
658}
659
660/* returns 0 if successful, !0 otherwise */
661static int sensors_read_sysfs_chips_compat(void)
662{
663        int ret;
664
665        ret = sysfs_foreach_busdev("i2c", sensors_add_hwmon_device_compat);
666        if (ret && ret != ENOENT)
667                return -SENSORS_ERR_KERNEL;
668
669        return 0;
670}
671
672static int sensors_add_hwmon_device(const char *path, const char *classdev)
673{
674        char linkpath[NAME_MAX];
675        char device[NAME_MAX], *device_p;
676        int dev_len, err;
677        (void)classdev; /* hide warning */
678
679        snprintf(linkpath, NAME_MAX, "%s/device", path);
680        dev_len = readlink(linkpath, device, NAME_MAX - 1);
681        if (dev_len < 0) {
682                /* No device link? Treat as virtual */
683                err = sensors_read_one_sysfs_chip(NULL, NULL, path);
684        } else {
685                device[dev_len] = '\0';
686                device_p = strrchr(device, '/') + 1;
687
688                /* The attributes we want might be those of the hwmon class
689                   device, or those of the device itself. */
690                err = sensors_read_one_sysfs_chip(linkpath, device_p, path);
691                if (err == 0)
692                        err = sensors_read_one_sysfs_chip(linkpath, device_p,
693                                                          linkpath);
694        }
695        if (err < 0)
696                return err;
697        return 0;
698}
699
700/* returns 0 if successful, !0 otherwise */
701int sensors_read_sysfs_chips(void)
702{
703        int ret;
704
705        ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device);
706        if (ret == ENOENT) {
707                /* compatibility function for kernel 2.6.n where n <= 13 */
708                return sensors_read_sysfs_chips_compat();
709        }
710
711        if (ret > 0)
712                ret = -SENSORS_ERR_KERNEL;
713        return ret;
714}
715
716/* returns 0 if successful, !0 otherwise */
717static int sensors_add_i2c_bus(const char *path, const char *classdev)
718{
719        sensors_bus entry;
720
721        if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 ||
722            entry.bus.nr == 9191) /* legacy ISA */
723                return 0;
724        entry.bus.type = SENSORS_BUS_TYPE_I2C;
725
726        /* Get the adapter name from the classdev "name" attribute
727         * (Linux 2.6.20 and later). If it fails, fall back to
728         * the device "name" attribute (for older kernels). */
729        entry.adapter = sysfs_read_attr(path, "name");
730        if (!entry.adapter)
731                entry.adapter = sysfs_read_attr(path, "device/name");
732        if (entry.adapter)
733                sensors_add_proc_bus(&entry);
734
735        return 0;
736}
737
738/* returns 0 if successful, !0 otherwise */
739int sensors_read_sysfs_bus(void)
740{
741        int ret;
742
743        ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus);
744        if (ret == ENOENT)
745                ret = sysfs_foreach_busdev("i2c", sensors_add_i2c_bus);
746        if (ret && ret != ENOENT)
747                return -SENSORS_ERR_KERNEL;
748
749        return 0;
750}
751
752int sensors_read_sysfs_attr(const sensors_chip_name *name,
753                            const sensors_subfeature *subfeature,
754                            double *value)
755{
756        char n[NAME_MAX];
757        FILE *f;
758
759        snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
760        if ((f = fopen(n, "r"))) {
761                int res, err = 0;
762
763                errno = 0;
764                res = fscanf(f, "%lf", value);
765                if (res == EOF && errno == EIO)
766                        err = -SENSORS_ERR_IO;
767                else if (res != 1)
768                        err = -SENSORS_ERR_ACCESS_R;
769                res = fclose(f);
770                if (err)
771                        return err;
772
773                if (res == EOF) {
774                        if (errno == EIO)
775                                return -SENSORS_ERR_IO;
776                        else 
777                                return -SENSORS_ERR_ACCESS_R;
778                }
779                *value /= get_type_scaling(subfeature->type);
780        } else
781                return -SENSORS_ERR_KERNEL;
782
783        return 0;
784}
785
786int sensors_write_sysfs_attr(const sensors_chip_name *name,
787                             const sensors_subfeature *subfeature,
788                             double value)
789{
790        char n[NAME_MAX];
791        FILE *f;
792
793        snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
794        if ((f = fopen(n, "w"))) {
795                int res, err = 0;
796
797                value *= get_type_scaling(subfeature->type);
798                res = fprintf(f, "%d", (int) value);
799                if (res == -EIO)
800                        err = -SENSORS_ERR_IO;
801                else if (res < 0)
802                        err = -SENSORS_ERR_ACCESS_W;
803                res = fclose(f);
804                if (err)
805                        return err;
806
807                if (res == EOF) {
808                        if (errno == EIO)
809                                return -SENSORS_ERR_IO;
810                        else 
811                                return -SENSORS_ERR_ACCESS_W;
812                }
813        } else
814                return -SENSORS_ERR_KERNEL;
815
816        return 0;
817}
Note: See TracBrowser for help on using the browser.