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

Revision 5874, 21.4 KB (checked in by khali, 3 years ago)

Reorganize the temporary sparse subfeature table. It's a little larger
now, but this make it possible to add more feature types without
increasing the code complexity beyond reason. Define constants and use
them to make the code even easier to understand.

If anyone is really worried about the relatively large memory
allocation, one way to improve the situation would be a two-pass
approach. But remember the memory is only needed for a short time...

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