root/lm-sensors/tags/V3-0-1/lib/sysfs.c

Revision 5093, 18.2 kB (checked in by khali, 11 months ago)

Add support for drivers that place the hwmon attributes in the hwmon
class device directory rather than directly in the device directory.
The latter is what all drivers do at the moment, but in the long run
the former is preferred as it prevents attribute name collisions.

  • 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /* this define needed for strndup() */
22 #define _GNU_SOURCE
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <limits.h>
30 #include <errno.h>
31 #include <dirent.h>
32 #include "data.h"
33 #include "error.h"
34 #include "access.h"
35 #include "general.h"
36 #include "sysfs.h"
37
38
39 /****************************************************************************/
40
41 #define ATTR_MAX        128
42
43 /*
44  * Read an attribute from sysfs
45  * Returns a pointer to a freshly allocated string; free it yourself.
46  * If the file doesn't exist or can't be read, NULL is returned.
47  */
48 static char *sysfs_read_attr(const char *device, const char *attr)
49 {
50         char path[NAME_MAX];
51         char buf[ATTR_MAX], *p;
52         FILE *f;
53
54         snprintf(path, NAME_MAX, "%s/%s", device, attr);
55
56         if (!(f = fopen(path, "r")))
57                 return NULL;
58         p = fgets(buf, ATTR_MAX, f);
59         fclose(f);
60         if (!p)
61                 return NULL;
62
63         /* Last byte is a '\n'; chop that off */
64         p = strndup(buf, strlen(buf) - 1);
65         if (!p)
66                 sensors_fatal_error(__FUNCTION__, "out of memory");
67         return p;
68 }
69
70 /*
71  * Call an arbitrary function for each class device of the given class
72  * Returns 0 on success (all calls returned 0), a positive errno for
73  * local errors, or a negative error value if any call fails.
74  */
75 static int sysfs_foreach_classdev(const char *class_name,
76                                    int (*func)(const char *, const char *))
77 {
78         char path[NAME_MAX];
79         int path_off, ret;
80         DIR *dir;
81         struct dirent *ent;
82
83         path_off = snprintf(path, NAME_MAX, "%s/class/%s",
84                             sensors_sysfs_mount, class_name);
85         if (!(dir = opendir(path)))
86                 return errno;
87
88         ret = 0;
89         while (!ret && (ent = readdir(dir))) {
90                 if (ent->d_name[0] == '.')      /* skip hidden entries */
91                         continue;
92
93                 snprintf(path + path_off, NAME_MAX - path_off, "/%s",
94                          ent->d_name);
95                 ret = func(path, ent->d_name);
96         }
97
98         closedir(dir);
99         return ret;
100 }
101
102 /*
103  * Call an arbitrary function for each device of the given bus type
104  * Returns 0 on success (all calls returned 0), a positive errno for
105  * local errors, or a negative error value if any call fails.
106  */
107 static int sysfs_foreach_busdev(const char *bus_type,
108                                  int (*func)(const char *, const char *))
109 {
110         char path[NAME_MAX];
111         int path_off, ret;
112         DIR *dir;
113         struct dirent *ent;
114
115         path_off = snprintf(path, NAME_MAX, "%s/bus/%s/devices",
116                             sensors_sysfs_mount, bus_type);
117         if (!(dir = opendir(path)))
118                 return errno;
119
120         ret = 0;
121         while (!ret && (ent = readdir(dir))) {
122                 if (ent->d_name[0] == '.')      /* skip hidden entries */
123                         continue;
124
125                 snprintf(path + path_off, NAME_MAX - path_off, "/%s",
126                          ent->d_name);
127                 ret = func(path, ent->d_name);
128         }
129
130         closedir(dir);
131         return ret;
132 }
133
134 /****************************************************************************/
135
136 char sensors_sysfs_mount[NAME_MAX];
137
138 #define MAX_SENSORS_PER_TYPE    20
139 #define MAX_SUBFEATURES         8
140 /* Room for all 3 types (in, fan, temp) with all their subfeatures + VID
141    + misc features */
142 #define ALL_POSSIBLE_SUBFEATURES \
143                                 (MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 \
144                                  + MAX_SENSORS_PER_TYPE + 1)
145
146 static
147 int get_type_scaling(sensors_subfeature_type type)
148 {
149         switch (type & 0xFF80) {
150         case SENSORS_SUBFEATURE_IN_INPUT:
151         case SENSORS_SUBFEATURE_TEMP_INPUT:
152                 return 1000;
153         case SENSORS_SUBFEATURE_FAN_INPUT:
154                 return 1;
155         }
156
157         switch (type) {
158         case SENSORS_SUBFEATURE_VID:
159         case SENSORS_SUBFEATURE_TEMP_OFFSET:
160                 return 1000;
161         default:
162                 return 1;
163         }
164 }
165
166 static
167 char *get_feature_name(sensors_feature_type ftype, char *sfname)
168 {
169         char *name, *underscore;
170
171         switch (ftype) {
172         case SENSORS_FEATURE_IN:
173         case SENSORS_FEATURE_FAN:
174         case SENSORS_FEATURE_TEMP:
175                 underscore = strchr(sfname, '_');
176                 name = strndup(sfname, underscore - sfname);
177                 break;
178         default:
179                 name = strdup(sfname);
180         }
181
182         return name;
183 }
184
185 /* Static mappings for use by sensors_subfeature_get_type() */
186 struct subfeature_type_match
187 {
188         const char *name;
189         sensors_subfeature_type type;
190 };
191
192 struct feature_type_match
193 {
194         const char *name;
195         const struct subfeature_type_match *submatches;
196 };
197
198 static const struct subfeature_type_match temp_matches[] = {
199         { "input", SENSORS_SUBFEATURE_TEMP_INPUT },
200         { "max", SENSORS_SUBFEATURE_TEMP_MAX },
201         { "max_hyst", SENSORS_SUBFEATURE_TEMP_MAX_HYST },
202         { "min", SENSORS_SUBFEATURE_TEMP_MIN },
203         { "crit", SENSORS_SUBFEATURE_TEMP_CRIT },
204         { "crit_hyst", SENSORS_SUBFEATURE_TEMP_CRIT_HYST },
205         { "alarm", SENSORS_SUBFEATURE_TEMP_ALARM },
206         { "min_alarm", SENSORS_SUBFEATURE_TEMP_MIN_ALARM },
207         { "max_alarm", SENSORS_SUBFEATURE_TEMP_MAX_ALARM },
208         { "crit_alarm", SENSORS_SUBFEATURE_TEMP_CRIT_ALARM },
209         { "fault", SENSORS_SUBFEATURE_TEMP_FAULT },
210         { "type", SENSORS_SUBFEATURE_TEMP_TYPE },
211         { "offset", SENSORS_SUBFEATURE_TEMP_OFFSET },
212         { NULL, 0 }
213 };
214
215 static const struct subfeature_type_match in_matches[] = {
216         { "input", SENSORS_SUBFEATURE_IN_INPUT },
217         { "min", SENSORS_SUBFEATURE_IN_MIN },
218         { "max", SENSORS_SUBFEATURE_IN_MAX },
219         { "alarm", SENSORS_SUBFEATURE_IN_ALARM },
220         { "min_alarm", SENSORS_SUBFEATURE_IN_MIN_ALARM },
221         { "max_alarm", SENSORS_SUBFEATURE_IN_MAX_ALARM },
222         { NULL, 0 }
223 };
224
225 static const struct subfeature_type_match fan_matches[] = {
226         { "input", SENSORS_SUBFEATURE_FAN_INPUT },
227         { "min", SENSORS_SUBFEATURE_FAN_MIN },
228         { "div", SENSORS_SUBFEATURE_FAN_DIV },
229         { "alarm", SENSORS_SUBFEATURE_FAN_ALARM },
230         { "fault", SENSORS_SUBFEATURE_FAN_FAULT },
231         { NULL, 0 }
232 };
233
234 static const struct subfeature_type_match cpu_matches[] = {
235         { "vid", SENSORS_SUBFEATURE_VID },
236         { NULL, 0 }
237 };
238
239 static struct feature_type_match matches[] = {
240         { "temp%d%c", temp_matches },
241         { "in%d%c", in_matches },
242         { "fan%d%c", fan_matches },
243         { "cpu%d%c", cpu_matches },
244 };
245
246 /* Return the subfeature type and channel number based on the subfeature
247    name */
248 static
249 sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr)
250 {
251         char c;
252         int i, count;
253         const struct subfeature_type_match *submatches;
254
255         /* Special case */
256         if (!strcmp(name, "beep_enable")) {
257                 *nr = 0;
258                 return SENSORS_SUBFEATURE_BEEP_ENABLE;
259         }
260
261         for (i = 0; i < ARRAY_SIZE(matches); i++)
262                 if ((count = sscanf(name, matches[i].name, nr, &c)))
263                         break;
264
265         if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
266                 return SENSORS_SUBFEATURE_UNKNOWN;  /* no match */
267
268         submatches = matches[i].submatches;
269         name = strchr(name + 3, '_') + 1;
270         for (i = 0; submatches[i].name != NULL; i++)
271                 if (!strcmp(name, submatches[i].name))
272                         return submatches[i].type;
273
274         return SENSORS_SUBFEATURE_UNKNOWN;
275 }
276
277 static int sensors_get_attr_mode(const char *device, const char *attr)
278 {
279         char path[NAME_MAX];
280         struct stat st;
281         int mode = 0;
282
283         snprintf(path, NAME_MAX, "%s/%s", device, attr);
284         if (!stat(path, &st)) {
285                 if (st.st_mode & S_IRUSR)
286                         mode |= SENSORS_MODE_R;
287                 if (st.st_mode & S_IWUSR)
288                         mode |= SENSORS_MODE_W;
289         }
290         return mode;
291 }
292
293 static int sensors_read_dynamic_chip(sensors_chip_features *chip,
294                                      const char *dev_path)
295 {
296         int i, fnum = 0, sfnum = 0, prev_slot;
297         DIR *dir;
298         struct dirent *ent;
299         sensors_subfeature *all_subfeatures;
300         sensors_subfeature *dyn_subfeatures;
301         sensors_feature *dyn_features;
302         sensors_feature_type ftype;
303         sensors_subfeature_type sftype;
304
305         if (!(dir = opendir(dev_path)))
306                 return -errno;
307
308         /* We use a large sparse table at first to store all found
309            subfeatures, so that we can store them sorted at type and index
310            and then later create a dense sorted table. */
311         all_subfeatures = calloc(ALL_POSSIBLE_SUBFEATURES,
312                                  sizeof(sensors_subfeature));
313         if (!all_subfeatures)
314                 sensors_fatal_error(__FUNCTION__, "Out of memory");
315
316         while ((ent = readdir(dir))) {
317                 char *name = ent->d_name;
318                 int nr;
319
320                 if (ent->d_name[0] == '.')
321                         continue;
322
323                 sftype = sensors_subfeature_get_type(name, &nr);
324                 if (sftype == SENSORS_SUBFEATURE_UNKNOWN)
325                         continue;
326
327                 /* Adjust the channel number */
328                 switch (sftype & 0xFF00) {
329                         case SENSORS_SUBFEATURE_FAN_INPUT:
330                         case SENSORS_SUBFEATURE_TEMP_INPUT:
331                                 nr--;
332                                 break;
333                 }
334
335                 if (nr < 0 || nr >= MAX_SENSORS_PER_TYPE) {
336                         /* More sensors of one type than MAX_SENSORS_PER_TYPE,
337                            we have to ignore it */
338 #ifdef DEBUG
339                         sensors_fatal_error(__FUNCTION__,
340                                             "Increase MAX_SENSORS_PER_TYPE!");
341 #endif
342                         continue;
343                 }
344
345                 /* "calculate" a place to store the subfeature in our sparse,
346                    sorted table */
347                 switch (sftype) {
348                 case SENSORS_SUBFEATURE_VID:
349                         i = nr + MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6;
350                         break;
351                 case SENSORS_SUBFEATURE_BEEP_ENABLE:
352                         i = MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 +
353                             MAX_SENSORS_PER_TYPE;
354                         break;
355                 default:
356                         i = (sftype >> 8) * MAX_SENSORS_PER_TYPE *
357                             MAX_SUBFEATURES * 2 + nr * MAX_SUBFEATURES * 2 +
358                             ((sftype & 0x80) >> 7) * MAX_SUBFEATURES +
359                             (sftype & 0x7F);
360                 }
361
362                 if (all_subfeatures[i].name) {
363 #ifdef DEBUG
364                         sensors_fatal_error(__FUNCTION__,
365                                             "Duplicate subfeature");
366 #endif
367                         continue;
368                 }
369
370                 /* fill in the subfeature members */
371                 all_subfeatures[i].type = sftype;
372                 all_subfeatures[i].name = strdup(name);
373                 if (!(sftype & 0x80))
374                         all_subfeatures[i].flags |= SENSORS_COMPUTE_MAPPING;
375                 all_subfeatures[i].flags |= sensors_get_attr_mode(dev_path, name);
376
377                 sfnum++;
378         }
379         closedir(dir);
380
381         if (!sfnum) { /* No subfeature */
382                 chip->subfeature = NULL;
383                 goto exit_free;
384         }
385
386         /* How many main features? */
387         prev_slot = -1;
388         for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
389                 if (!all_subfeatures[i].name)
390                         continue;
391
392                 if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 ||
393                     i / (MAX_SUBFEATURES * 2) != prev_slot) {
394                         fnum++;
395                         prev_slot = i / (MAX_SUBFEATURES * 2);
396                 }
397         }
398
399         dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature));
400         dyn_features = calloc(fnum, sizeof(sensors_feature));
401         if (!dyn_subfeatures || !dyn_features)
402                 sensors_fatal_error(__FUNCTION__, "Out of memory");
403
404         /* Copy from the sparse array to the compact array */
405         sfnum = 0;
406         fnum = -1;
407         prev_slot = -1;
408         for (i = 0; i < ALL_POSSIBLE_SUBFEATURES; i++) {
409                 if (!all_subfeatures[i].name)
410                         continue;
411
412                 /* New main feature? */
413                 if (i >= MAX_SENSORS_PER_TYPE * MAX_SUBFEATURES * 6 ||
414                     i / (MAX_SUBFEATURES * 2) != prev_slot) {
415                         ftype = all_subfeatures[i].type >> 8;
416                         fnum++;
417                         prev_slot = i / (MAX_SUBFEATURES * 2);
418
419                         dyn_features[fnum].name = get_feature_name(ftype,
420                                                 all_subfeatures[i].name);
421                         dyn_features[fnum].number = fnum;
422                         dyn_features[fnum].first_subfeature = sfnum;
423                         dyn_features[fnum].type = ftype;
424                 }
425
426                 dyn_subfeatures[sfnum] = all_subfeatures[i];
427                 dyn_subfeatures[sfnum].number = sfnum;
428                 /* Back to the feature */
429                 dyn_subfeatures[sfnum].mapping = fnum;
430
431                 sfnum++;
432         }
433
434         chip->subfeature = dyn_subfeatures;
435         chip->subfeature_count = sfnum;
436         chip->feature = dyn_features;
437         chip->feature_count = ++fnum;
438
439 exit_free:
440         free(all_subfeatures);
441         return 0;
442 }
443
444 /* returns !0 if sysfs filesystem was found, 0 otherwise */
445 int sensors_init_sysfs(void)
446 {
447         struct stat statbuf;
448
449         snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys");
450         if (stat(sensors_sysfs_mount, &statbuf) < 0
451          || statbuf.st_nlink <= 2)      /* Empty directory */
452                 return 0;
453
454         return 1;
455 }
456
457 /* returns: number of devices added (0 or 1) if successful, <0 otherwise */
458 static int sensors_read_one_sysfs_chip(const char *dev_path,
459                                        const char *dev_name,
460                                        const char *hwmon_path)
461 {
462         int domain, bus, slot, fn;
463         int err = -SENSORS_ERR_KERNEL;
464         char *bus_attr;
465         char bus_path[NAME_MAX];
466         char linkpath[NAME_MAX];
467         char subsys_path[NAME_MAX], *subsys;
468         int sub_len;
469         sensors_chip_features entry;
470
471         /* ignore any device without name attribute */
472         if (!(entry.chip.prefix = sysfs_read_attr(hwmon_path, "name")))
473                 return 0;
474
475         entry.chip.path = strdup(hwmon_path);
476         if (!entry.chip.path)
477                 sensors_fatal_error(__FUNCTION__, "out of memory");
478
479         /* Find bus type */
480         snprintf(linkpath, NAME_MAX, "%s/subsystem", dev_path);
481         sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
482         if (sub_len < 0 && errno == ENOENT) {
483                 /* Fallback to "bus" link for kernels <= 2.6.17 */
484                 snprintf(linkpath, NAME_MAX, "%s/bus", dev_path);
485                 sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
486         }
487         if (sub_len < 0) {
488                 /* Older kernels (<= 2.6.11) have neither the subsystem
489                    symlink nor the bus symlink */
490                 if (errno == ENOENT)
491                         subsys = NULL;
492                 else
493                         goto exit_free;
494         } else {
495                 subsys_path[sub_len] = '\0';
496                 subsys = strrchr(subsys_path, '/') + 1;
497         }
498
499         if ((!subsys || !strcmp(subsys, "i2c")) &&
500             sscanf(dev_name, "%hd-%x", &entry.chip.bus.nr,
501                    &entry.chip.addr) == 2) {
502                 /* find out if legacy ISA or not */
503                 if (entry.chip.bus.nr == 9191) {
504                         entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
505                         entry.chip.bus.nr = 0;
506                 } else {
507                         entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
508                         snprintf(bus_path, sizeof(bus_path),
509                                 "%s/class/i2c-adapter/i2c-%d/device",
510                                 sensors_sysfs_mount, entry.chip.bus.nr);
511
512                         if ((bus_attr = sysfs_read_attr(bus_path, "name"))) {
513                                 if (!strncmp(bus_attr, "ISA ", 4)) {
514                                         entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
515                                         entry.chip.bus.nr = 0;
516                                 }
517
518                                 free(bus_attr);
519                         }
520                 }
521         } else
522         if ((!subsys || !strcmp(subsys, "spi")) &&
523             sscanf(dev_name, "spi%hd.%d", &entry.chip.bus.nr,
524                    &entry.chip.addr) == 2) {
525                 /* SPI */
526                 entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
527         } else
528         if ((!subsys || !strcmp(subsys, "platform"))) {
529                 /* must be new ISA (platform driver) */
530                 if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry.chip.addr) != 1)
531                         entry.chip.addr = 0;
532                 entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
533                 entry.chip.bus.nr = 0;
534         } else
535         if ((!subsys || !strcmp(subsys, "pci")) &&
536             sscanf(dev_name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
537                 /* PCI */
538                 entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
539                 entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
540                 entry.chip.bus.nr = 0;
541         } else {
542                 /* Ignore unknown device */
543                 err = 0;
544                 goto exit_free;
545         }
546
547         if (sensors_read_dynamic_chip(&entry, hwmon_path) < 0)
548                 goto exit_free;
549         if (!entry.subfeature) { /* No subfeature, discard chip */
550                 err = 0;
551                 goto exit_free;
552         }
553         sensors_add_proc_chips(&entry);
554
555         return 1;
556
557 exit_free:
558         free(entry.chip.prefix);
559         free(entry.chip.path);
560         return err;
561 }
562
563 static int sensors_add_hwmon_device_compat(const char *path,
564                                            const char *dev_name)
565 {
566         int err;
567
568         err = sensors_read_one_sysfs_chip(path, dev_name, path);
569         if (err < 0)
570                 return err;
571         return 0;
572 }
573
574 /* returns 0 if successful, !0 otherwise */
575 static int sensors_read_sysfs_chips_compat(void)
576 {
577         int ret;
578
579         ret = sysfs_foreach_busdev("i2c", sensors_add_hwmon_device_compat);
580         if (ret && ret != ENOENT)
581                 return -SENSORS_ERR_KERNEL;
582
583         return 0;
584 }
585
586 static int sensors_add_hwmon_device(const char *path, const char *classdev)
587 {
588         char linkpath[NAME_MAX];
589         char device[NAME_MAX], *device_p;
590         int dev_len, err;
591         (void)classdev; /* hide warning */
592
593         snprintf(linkpath, NAME_MAX, "%s/device", path);
594         dev_len = readlink(linkpath, device, NAME_MAX - 1);
595         if (dev_len < 0)
596                 return -SENSORS_ERR_KERNEL;
597         device[dev_len] = '\0';
598         device_p = strrchr(device, '/') + 1;
599
600         /* The attributes we want might be those of the hwmon class device,
601            or those of the device itself. */
602         err = sensors_read_one_sysfs_chip(linkpath, device_p, path);
603         if (err == 0)
604                 err = sensors_read_one_sysfs_chip(linkpath, device_p, linkpath);
605         if (err < 0)
606                 return err;
607         return 0;
608 }
609
610 /* returns 0 if successful, !0 otherwise */
611 int sensors_read_sysfs_chips(void)
612 {
613         int ret;
614
615         ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device);
616         if (ret == ENOENT) {
617                 /* compatibility function for kernel 2.6.n where n <= 13 */
618                 return sensors_read_sysfs_chips_compat();
619         }
620
621         if (ret > 0)
622                 ret = -SENSORS_ERR_KERNEL;
623         return ret;
624 }
625
626 /* returns 0 if successful, !0 otherwise */
627 static int sensors_add_i2c_bus(const char *path, const char *classdev)
628 {
629         sensors_bus entry;
630
631         if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 ||
632             entry.bus.nr == 9191) /* legacy ISA */
633                 return 0;
634         entry.bus.type = SENSORS_BUS_TYPE_I2C;
635
636         /* Get the adapter name from the classdev "name" attribute
637          * (Linux 2.6.20 and later). If it fails, fall back to
638          * the device "name" attribute (for older kernels). */
639         entry.adapter = sysfs_read_attr(path, "name");
640         if (!entry.adapter)
641                 entry.adapter = sysfs_read_attr(path, "device/name");
642         if (entry.adapter)
643                 sensors_add_proc_bus(&entry);
644
645         return 0;
646 }
647
648 /* returns 0 if successful, !0 otherwise */
649 int sensors_read_sysfs_bus(void)
650 {
651         int ret;
652
653         ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus);
654         if (ret && ret != ENOENT)
655                 return -SENSORS_ERR_KERNEL;
656
657         return 0;
658 }
659
660 int sensors_read_sysfs_attr(const sensors_chip_name *name,
661                             const sensors_subfeature *subfeature,
662                             double *value)
663 {
664         char n[NAME_MAX];
665         FILE *f;
666
667         snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
668         if ((f = fopen(n, "r"))) {
669                 int res, err = 0;
670
671                 errno = 0;
672                 res = fscanf(f, "%lf", value);
673                 if (res == EOF && errno == EIO)
674                         err = -SENSORS_ERR_IO;
675                 else if (res != 1)
676                         err = -SENSORS_ERR_ACCESS_R;
677                 res = fclose(f);
678                 if (err)
679                         return err;
680
681                 if (res == EOF) {
682                         if (errno == EIO)
683                                 return -SENSORS_ERR_IO;
684                         else
685                                 return -SENSORS_ERR_ACCESS_R;
686                 }
687                 *value /= get_type_scaling(subfeature->type);
688         } else
689                 return -SENSORS_ERR_KERNEL;
690
691         return 0;
692 }
693
694 int sensors_write_sysfs_attr(const sensors_chip_name *name,
695                              const sensors_subfeature *subfeature,
696                              double value)
697 {
698         char n[NAME_MAX];
699         FILE *f;
700
701         snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
702         if ((f = fopen(n, "w"))) {
703                 int res, err = 0;
704
705                 value *= get_type_scaling(subfeature->type);
706                 res = fprintf(f, "%d", (int) value);
707                 if (res == -EIO)
708                         err = -SENSORS_ERR_IO;
709                 else if (res < 0)
710                         err = -SENSORS_ERR_ACCESS_W;
711                 res = fclose(f);
712                 if (err)
713                         return err;
714
715                 if (res == EOF) {
716                         if (errno == EIO)
717                                 return -SENSORS_ERR_IO;
718                         else
719                                 return -SENSORS_ERR_ACCESS_W;
720                 }
721         } else
722                 return -SENSORS_ERR_KERNEL;
723
724         return 0;
725 }
Note: See TracBrowser for help on using the browser.