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

Revision 5938, 23.9 KB (checked in by groeck, 2 years ago)

Added support for SENSORS_SUBFEATURE_FAN_PULSES to libsensors.

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