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

Revision 5844, 21.3 KB (checked in by khali, 4 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
RevLine 
[3093]1/*
2    sysfs.c - Part of libsensors, a library for reading Linux sensor data
3    Copyright (c) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
[5134]4    Copyright (C) 2007-2008 Jean Delvare <khali@linux-fr.org>
[3093]5
[5844]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.
[3093]10
[5844]11    This library is distributed in the hope that it will be useful,
[3093]12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
[5844]14    GNU Lesser General Public License for more details.
[3093]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
[5163]18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19    MA 02110-1301 USA.
[3093]20*/
21
[3095]22/* this define needed for strndup() */
23#define _GNU_SOURCE
24
[4464]25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
[3093]28#include <string.h>
[4368]29#include <stdlib.h>
[3093]30#include <limits.h>
[3261]31#include <errno.h>
[5067]32#include <dirent.h>
[3094]33#include "data.h"
34#include "error.h"
35#include "access.h"
36#include "general.h"
[3093]37#include "sysfs.h"
38
[5067]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)
[5134]67                sensors_fatal_error(__func__, "Out of memory");
[5067]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,
[5075]77                                   int (*func)(const char *, const char *))
[5067]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,
[5075]109                                 int (*func)(const char *, const char *))
[5067]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
[3093]137char sensors_sysfs_mount[NAME_MAX];
138
[5826]139#define MAX_SENSORS_PER_TYPE    24
[4836]140#define MAX_SUBFEATURES         8
[5379]141#define MAX_SENSOR_TYPES        6
[5827]142/* Room for all 6 types (in, fan, temp, power, energy, current) with all
143   their subfeatures + VID + misc features */
[4836]144#define ALL_POSSIBLE_SUBFEATURES \
[5183]145                                (MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * \
146                                 MAX_SENSOR_TYPES * 2 + \
147                                 MAX_SENSORS_PER_TYPE + 1)
[4359]148
[4420]149static
[4850]150int get_type_scaling(sensors_subfeature_type type)
[4420]151{
[5183]152        /* Multipliers for subfeatures */
[4858]153        switch (type & 0xFF80) {
[4837]154        case SENSORS_SUBFEATURE_IN_INPUT:
155        case SENSORS_SUBFEATURE_TEMP_INPUT:
[5379]156        case SENSORS_SUBFEATURE_CURR_INPUT:
[4762]157                return 1000;
[4837]158        case SENSORS_SUBFEATURE_FAN_INPUT:
[4762]159                return 1;
[5183]160        case SENSORS_SUBFEATURE_POWER_AVERAGE:
161        case SENSORS_SUBFEATURE_ENERGY_INPUT:
162                return 1000000;
[4420]163        }
164
[5183]165        /* Multipliers for second class subfeatures
166           that need their own multiplier */
[4420]167        switch (type) {
[5183]168        case SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL:
[4837]169        case SENSORS_SUBFEATURE_VID:
170        case SENSORS_SUBFEATURE_TEMP_OFFSET:
[4762]171                return 1000;
[4420]172        default:
[4762]173                return 1;
[4420]174        }
175}
176
[4838]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:
[5183]186        case SENSORS_FEATURE_POWER:
187        case SENSORS_FEATURE_ENERGY:
[5379]188        case SENSORS_FEATURE_CURR:
[4838]189                underscore = strchr(sfname, '_');
190                name = strndup(sfname, underscore - sfname);
[5661]191                if (!name)
192                        sensors_fatal_error(__func__, "Out of memory");
193
[4838]194                break;
195        default:
196                name = strdup(sfname);
[5661]197                if (!name)
198                        sensors_fatal_error(__func__, "Out of memory");
[4838]199        }
200
201        return name;
202}
203
[4836]204/* Static mappings for use by sensors_subfeature_get_type() */
[4837]205struct subfeature_type_match
[4776]206{
207        const char *name;
[4837]208        sensors_subfeature_type type;
[4776]209};
210
211struct feature_type_match
212{
213        const char *name;
[4837]214        const struct subfeature_type_match *submatches;
[4776]215};
216
[4837]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 },
[5843]231        { "beep", SENSORS_SUBFEATURE_TEMP_BEEP },
[4776]232        { NULL, 0 }
233};
234
[4837]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 },
[5843]242        { "beep", SENSORS_SUBFEATURE_IN_BEEP },
[4776]243        { NULL, 0 }
244};
245
[4837]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 },
[5843]252        { "beep", SENSORS_SUBFEATURE_FAN_BEEP },
[4776]253        { NULL, 0 }
254};
255
[5183]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 },
[5378]260        { "input", SENSORS_SUBFEATURE_POWER_INPUT },
261        { "input_highest", SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST },
262        { "input_lowest", SENSORS_SUBFEATURE_POWER_INPUT_LOWEST },
[5183]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
[5379]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 },
[5843]279        { "beep", SENSORS_SUBFEATURE_CURR_BEEP },
[5379]280        { NULL, 0 }
281};
282
[4837]283static const struct subfeature_type_match cpu_matches[] = {
284        { "vid", SENSORS_SUBFEATURE_VID },
[4776]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 },
[5183]293        { "power%d%c", power_matches },
[5379]294        { "curr%d%c", curr_matches },
[5183]295        { "energy%d%c", energy_matches },
[4776]296};
297
[4836]298/* Return the subfeature type and channel number based on the subfeature
299   name */
[4776]300static
[4837]301sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr)
[4776]302{
303        char c;
304        int i, count;
[4837]305        const struct subfeature_type_match *submatches;
[4776]306
307        /* Special case */
308        if (!strcmp(name, "beep_enable")) {
309                *nr = 0;
[4837]310                return SENSORS_SUBFEATURE_BEEP_ENABLE;
[4776]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 != '_')
[4837]318                return SENSORS_SUBFEATURE_UNKNOWN;  /* no match */
[4776]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
[4837]326        return SENSORS_SUBFEATURE_UNKNOWN;
[4776]327}
328
[5067]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
[4510]345static int sensors_read_dynamic_chip(sensors_chip_features *chip,
[5067]346                                     const char *dev_path)
[4359]347{
[4838]348        int i, fnum = 0, sfnum = 0, prev_slot;
[5067]349        DIR *dir;
350        struct dirent *ent;
[4836]351        sensors_subfeature *all_subfeatures;
[4832]352        sensors_subfeature *dyn_subfeatures;
[4834]353        sensors_feature *dyn_features;
[4838]354        sensors_feature_type ftype;
355        sensors_subfeature_type sftype;
[4736]356
[5067]357        if (!(dir = opendir(dev_path)))
358                return -errno;
[4736]359
[4836]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)
[5134]366                sensors_fatal_error(__func__, "Out of memory");
[4736]367
[5067]368        while ((ent = readdir(dir))) {
[5636]369                char *name;
[4630]370                int nr;
[4736]371
[5636]372                /* Skip directories and symlinks */
373                if (ent->d_type != DT_REG)
[5067]374                        continue;
375
[5636]376                name = ent->d_name;
377
[4838]378                sftype = sensors_subfeature_get_type(name, &nr);
379                if (sftype == SENSORS_SUBFEATURE_UNKNOWN)
[4630]380                        continue;
381
382                /* Adjust the channel number */
[4838]383                switch (sftype & 0xFF00) {
[5183]384                case SENSORS_SUBFEATURE_FAN_INPUT:
385                case SENSORS_SUBFEATURE_TEMP_INPUT:
386                case SENSORS_SUBFEATURE_POWER_AVERAGE:
387                case SENSORS_SUBFEATURE_ENERGY_INPUT:
[5379]388                case SENSORS_SUBFEATURE_CURR_INPUT:
[5183]389                        nr--;
390                        break;
[4368]391                }
[4736]392
[4855]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
[5134]397                        sensors_fatal_error(__func__,
[4855]398                                            "Increase MAX_SENSORS_PER_TYPE!");
399#endif
[4368]400                        continue;
401                }
[4736]402
[4836]403                /* "calculate" a place to store the subfeature in our sparse,
[4368]404                   sorted table */
[4838]405                switch (sftype) {
[4837]406                case SENSORS_SUBFEATURE_VID:
[5183]407                        i = nr + MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
408                            MAX_SENSOR_TYPES * 2;
[4766]409                        break;
[4837]410                case SENSORS_SUBFEATURE_BEEP_ENABLE:
[5183]411                        i = MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
412                            MAX_SENSOR_TYPES * 2 + MAX_SENSORS_PER_TYPE;
[4766]413                        break;
414                default:
[4838]415                        i = (sftype >> 8) * MAX_SENSORS_PER_TYPE *
[4836]416                            MAX_SUBFEATURES * 2 + nr * MAX_SUBFEATURES * 2 +
[4858]417                            ((sftype & 0x80) >> 7) * MAX_SUBFEATURES +
418                            (sftype & 0x7F);
[4554]419                }
[4736]420
[4836]421                if (all_subfeatures[i].name) {
[4855]422#ifdef DEBUG
[5134]423                        sensors_fatal_error(__func__, "Duplicate subfeature");
[4855]424#endif
[4368]425                        continue;
426                }
[4736]427
[4836]428                /* fill in the subfeature members */
[4838]429                all_subfeatures[i].type = sftype;
430                all_subfeatures[i].name = strdup(name);
[5661]431                if (!all_subfeatures[i].name)
432                        sensors_fatal_error(__func__, "Out of memory");
433
[4858]434                if (!(sftype & 0x80))
[4838]435                        all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING;
[5067]436                all_subfeatures[i].flags |= sensors_get_attr_mode(dev_path, name);
[4368]437
[4838]438                sfnum++;
[4359]439        }
[5067]440        closedir(dir);
[4368]441
[4838]442        if (!sfnum) { /* No subfeature */
[4832]443                chip->subfeature = NULL;
[4731]444                goto exit_free;
[4637]445        }
446
[4838]447        /* How many main features? */
448        prev_slot = -1;
[4836]449        for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
[4838]450                if (!all_subfeatures[i].name)
451                        continue;
452
[5183]453                if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
454                    MAX_SENSOR_TYPES * 2 ||
[4838]455                    i / (MAX_SUBFEATURES * 2) != prev_slot) {
[4368]456                        fnum++;
[4838]457                        prev_slot = i / (MAX_SUBFEATURES * 2);
[4368]458                }
[4359]459        }
[4736]460
[4838]461        dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature));
[4834]462        dyn_features = calloc(fnum, sizeof(sensors_feature));
[4838]463        if (!dyn_subfeatures || !dyn_features)
[5134]464                sensors_fatal_error(__func__, "Out of memory");
[4834]465
[4838]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? */
[5183]475                if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES *
476                    MAX_SENSOR_TYPES * 2 ||
[4838]477                    i / (MAX_SUBFEATURES * 2) != prev_slot) {
478                        ftype = all_subfeatures[i].type >> 8;
[4834]479                        fnum++;
[4838]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;
[4834]487                }
[4838]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++;
[4834]495        }
496
[4838]497        chip->subfeature = dyn_subfeatures;
498        chip->subfeature_count = sfnum;
[4834]499        chip->feature = dyn_features;
[4838]500        chip->feature_count = ++fnum;
[4834]501
[4731]502exit_free:
[4836]503        free(all_subfeatures);
[4510]504        return 0;
[4359]505}
506
[3093]507/* returns !0 if sysfs filesystem was found, 0 otherwise */
508int sensors_init_sysfs(void)
509{
[4464]510        struct stat statbuf;
[3093]511
[5067]512        snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys");
513        if (stat(sensors_sysfs_mount, &statbuf) < 0
[4464]514         || statbuf.st_nlink <= 2)      /* Empty directory */
515                return 0;
516
517        return 1;
[3093]518}
[3094]519
[5093]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)
[3095]524{
[5786]525        int domain, bus, slot, fn, vendor, product, id;
[4854]526        int err = -SENSORS_ERR_KERNEL;
[5067]527        char *bus_attr;
528        char bus_path[NAME_MAX];
[5092]529        char linkpath[NAME_MAX];
530        char subsys_path[NAME_MAX], *subsys;
531        int sub_len;
[4510]532        sensors_chip_features entry;
[3095]533
534        /* ignore any device without name attribute */
[5093]535        if (!(entry.chip.prefix = sysfs_read_attr(hwmon_path, "name")))
[3095]536                return 0;
537
[5093]538        entry.chip.path = strdup(hwmon_path);
[4673]539        if (!entry.chip.path)
[5134]540                sensors_fatal_error(__func__, "Out of memory");
[3095]541
[5176]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
[5092]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) {
[3224]574                /* find out if legacy ISA or not */
[4686]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;
[4357]580                        snprintf(bus_path, sizeof(bus_path),
[5067]581                                "%s/class/i2c-adapter/i2c-%d/device",
[4686]582                                sensors_sysfs_mount, entry.chip.bus.nr);
[3095]583
[5067]584                        if ((bus_attr = sysfs_read_attr(bus_path, "name"))) {
585                                if (!strncmp(bus_attr, "ISA ", 4)) {
[4686]586                                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
587                                        entry.chip.bus.nr = 0;
588                                }
[3095]589
[5067]590                                free(bus_attr);
[4357]591                        }
[3224]592                }
[5092]593        } else
594        if ((!subsys || !strcmp(subsys, "spi")) &&
595            sscanf(dev_name, "spi%hd.%d", &entry.chip.bus.nr,
596                   &entry.chip.addr) == 2) {
[4689]597                /* SPI */
598                entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
[5092]599        } else
[5145]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
[5174]607        if ((!subsys || !strcmp(subsys, "platform") ||
608                        !strcmp(subsys, "of_platform"))) {
[3224]609                /* must be new ISA (platform driver) */
[5092]610                if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry.chip.addr) != 1)
611                        entry.chip.addr = 0;
[4686]612                entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
613                entry.chip.bus.nr = 0;
[5593]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;
[5786]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;
[4878]626        } else {
[5092]627                /* Ignore unknown device */
628                err = 0;
629                goto exit_free;
[4878]630        }
[4736]631
[5176]632done:
[5093]633        if (sensors_read_dynamic_chip(&entry, hwmon_path) < 0)
[4636]634                goto exit_free;
[4836]635        if (!entry.subfeature) { /* No subfeature, discard chip */
[4637]636                err = 0;
637                goto exit_free;
638        }
[4510]639        sensors_add_proc_chips(&entry);
[4359]640
[5093]641        return 1;
[4636]642
643exit_free:
644        free(entry.chip.prefix);
[4673]645        free(entry.chip.path);
[4637]646        return err;
[3095]647}
648
[5093]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
[3094]660/* returns 0 if successful, !0 otherwise */
[3095]661static int sensors_read_sysfs_chips_compat(void)
662{
[5067]663        int ret;
[3095]664
[5093]665        ret = sysfs_foreach_busdev("i2c", sensors_add_hwmon_device_compat);
[5067]666        if (ret && ret != ENOENT)
667                return -SENSORS_ERR_KERNEL;
[3095]668
[5067]669        return 0;
670}
[3095]671
[5075]672static int sensors_add_hwmon_device(const char *path, const char *classdev)
[5067]673{
[5075]674        char linkpath[NAME_MAX];
[5093]675        char device[NAME_MAX], *device_p;
676        int dev_len, err;
[5067]677        (void)classdev; /* hide warning */
[3095]678
[5075]679        snprintf(linkpath, NAME_MAX, "%s/device", path);
680        dev_len = readlink(linkpath, device, NAME_MAX - 1);
[5176]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;
[3095]687
[5176]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        }
[5093]695        if (err < 0)
696                return err;
697        return 0;
[3095]698}
699
700/* returns 0 if successful, !0 otherwise */
701int sensors_read_sysfs_chips(void)
702{
[5067]703        int ret;
[3095]704
[5067]705        ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device);
706        if (ret == ENOENT) {
[3095]707                /* compatibility function for kernel 2.6.n where n <= 13 */
708                return sensors_read_sysfs_chips_compat();
709        }
710
[5067]711        if (ret > 0)
712                ret = -SENSORS_ERR_KERNEL;
[3095]713        return ret;
714}
715
716/* returns 0 if successful, !0 otherwise */
[5075]717static int sensors_add_i2c_bus(const char *path, const char *classdev)
[3094]718{
719        sensors_bus entry;
720
[5067]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;
[3094]725
[5067]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);
[3094]734
[5067]735        return 0;
736}
[3094]737
[5067]738/* returns 0 if successful, !0 otherwise */
739int sensors_read_sysfs_bus(void)
740{
741        int ret;
[3094]742
[5067]743        ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus);
[5759]744        if (ret == ENOENT)
745                ret = sysfs_foreach_busdev("i2c", sensors_add_i2c_bus);
[5067]746        if (ret && ret != ENOENT)
747                return -SENSORS_ERR_KERNEL;
[4674]748
[5067]749        return 0;
[3094]750}
751
[4841]752int sensors_read_sysfs_attr(const sensors_chip_name *name,
753                            const sensors_subfeature *subfeature,
[4667]754                            double *value)
[4553]755{
756        char n[NAME_MAX];
757        FILE *f;
758
[4838]759        snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
[4553]760        if ((f = fopen(n, "r"))) {
[4899]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                }
[4836]779                *value /= get_type_scaling(subfeature->type);
[4553]780        } else
[4854]781                return -SENSORS_ERR_KERNEL;
[4553]782
783        return 0;
784}
[4736]785
[4841]786int sensors_write_sysfs_attr(const sensors_chip_name *name,
787                             const sensors_subfeature *subfeature,
[4667]788                             double value)
[4553]789{
790        char n[NAME_MAX];
791        FILE *f;
[4736]792
[4838]793        snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
[4553]794        if ((f = fopen(n, "w"))) {
[4899]795                int res, err = 0;
796
[4836]797                value *= get_type_scaling(subfeature->type);
[4895]798                res = fprintf(f, "%d", (int) value);
[4899]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                }
[4553]813        } else
[4854]814                return -SENSORS_ERR_KERNEL;
[4553]815
816        return 0;
817}
Note: See TracBrowser for help on using the browser.