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