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

Revision 5843, 21.2 KB (checked in by khali, 4 years ago)

Map individual beep features. We had symbols for them for a long time,
I have no idea why they weren't mapped to the sysfs file names.

  • 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        { "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.