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-2014 Jean Delvare <jdelvare@suse.de>
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.
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.
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,
22
/* this define needed for strndup() */
25
#include <sys/types.h>
41
/****************************************************************************/
44
#define SYSFS_MAGIC 0x62656572
47
* Read an attribute from sysfs
48
* Returns a pointer to a freshly allocated string; free it yourself.
49
* If the file doesn't exist or can't be read, NULL is returned.
51
static char *sysfs_read_attr(const char *device, const char *attr)
54
char buf[ATTR_MAX], *p;
57
snprintf(path, NAME_MAX, "%s/%s", device, attr);
59
if (!(f = fopen(path, "r")))
61
p = fgets(buf, ATTR_MAX, f);
66
/* Last byte is a '\n'; chop that off */
67
p = strndup(buf, strlen(buf) - 1);
69
sensors_fatal_error(__func__, "Out of memory");
74
* Call an arbitrary function for each class device of the given class
75
* Returns 0 on success (all calls returned 0), a positive errno for
76
* local errors, or a negative error value if any call fails.
78
static int sysfs_foreach_classdev(const char *class_name,
79
int (*func)(const char *, const char *))
86
path_off = snprintf(path, NAME_MAX, "%s/class/%s",
87
sensors_sysfs_mount, class_name);
88
if (!(dir = opendir(path)))
92
while (!ret && (ent = readdir(dir))) {
93
if (ent->d_name[0] == '.') /* skip hidden entries */
96
snprintf(path + path_off, NAME_MAX - path_off, "/%s",
98
ret = func(path, ent->d_name);
106
* Call an arbitrary function for each device of the given bus type
107
* Returns 0 on success (all calls returned 0), a positive errno for
108
* local errors, or a negative error value if any call fails.
110
static int sysfs_foreach_busdev(const char *bus_type,
111
int (*func)(const char *, const char *))
118
path_off = snprintf(path, NAME_MAX, "%s/bus/%s/devices",
119
sensors_sysfs_mount, bus_type);
120
if (!(dir = opendir(path)))
124
while (!ret && (ent = readdir(dir))) {
125
if (ent->d_name[0] == '.') /* skip hidden entries */
128
snprintf(path + path_off, NAME_MAX - path_off, "/%s",
130
ret = func(path, ent->d_name);
137
/****************************************************************************/
139
char sensors_sysfs_mount[NAME_MAX];
142
int get_type_scaling(sensors_subfeature_type type)
144
/* Multipliers for subfeatures */
145
switch (type & 0xFF80) {
146
case SENSORS_SUBFEATURE_IN_INPUT:
147
case SENSORS_SUBFEATURE_TEMP_INPUT:
148
case SENSORS_SUBFEATURE_CURR_INPUT:
149
case SENSORS_SUBFEATURE_HUMIDITY_INPUT:
151
case SENSORS_SUBFEATURE_FAN_INPUT:
153
case SENSORS_SUBFEATURE_POWER_AVERAGE:
154
case SENSORS_SUBFEATURE_ENERGY_INPUT:
158
/* Multipliers for second class subfeatures
159
that need their own multiplier */
161
case SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL:
162
case SENSORS_SUBFEATURE_VID:
163
case SENSORS_SUBFEATURE_TEMP_OFFSET:
171
char *get_feature_name(sensors_feature_type ftype, char *sfname)
173
char *name, *underscore;
176
case SENSORS_FEATURE_IN:
177
case SENSORS_FEATURE_FAN:
178
case SENSORS_FEATURE_TEMP:
179
case SENSORS_FEATURE_POWER:
180
case SENSORS_FEATURE_ENERGY:
181
case SENSORS_FEATURE_CURR:
182
case SENSORS_FEATURE_HUMIDITY:
183
case SENSORS_FEATURE_INTRUSION:
184
underscore = strchr(sfname, '_');
185
name = strndup(sfname, underscore - sfname);
187
sensors_fatal_error(__func__, "Out of memory");
191
name = strdup(sfname);
193
sensors_fatal_error(__func__, "Out of memory");
199
/* Static mappings for use by sensors_subfeature_get_type() */
200
struct subfeature_type_match
203
sensors_subfeature_type type;
206
struct feature_type_match
209
const struct subfeature_type_match *submatches;
212
static const struct subfeature_type_match temp_matches[] = {
213
{ "input", SENSORS_SUBFEATURE_TEMP_INPUT },
214
{ "max", SENSORS_SUBFEATURE_TEMP_MAX },
215
{ "max_hyst", SENSORS_SUBFEATURE_TEMP_MAX_HYST },
216
{ "min", SENSORS_SUBFEATURE_TEMP_MIN },
217
{ "min_hyst", SENSORS_SUBFEATURE_TEMP_MIN_HYST },
218
{ "crit", SENSORS_SUBFEATURE_TEMP_CRIT },
219
{ "crit_hyst", SENSORS_SUBFEATURE_TEMP_CRIT_HYST },
220
{ "lcrit", SENSORS_SUBFEATURE_TEMP_LCRIT },
221
{ "lcrit_hyst", SENSORS_SUBFEATURE_TEMP_LCRIT_HYST },
222
{ "emergency", SENSORS_SUBFEATURE_TEMP_EMERGENCY },
223
{ "emergency_hyst", SENSORS_SUBFEATURE_TEMP_EMERGENCY_HYST },
224
{ "lowest", SENSORS_SUBFEATURE_TEMP_LOWEST },
225
{ "highest", SENSORS_SUBFEATURE_TEMP_HIGHEST },
226
{ "alarm", SENSORS_SUBFEATURE_TEMP_ALARM },
227
{ "min_alarm", SENSORS_SUBFEATURE_TEMP_MIN_ALARM },
228
{ "max_alarm", SENSORS_SUBFEATURE_TEMP_MAX_ALARM },
229
{ "crit_alarm", SENSORS_SUBFEATURE_TEMP_CRIT_ALARM },
230
{ "emergency_alarm", SENSORS_SUBFEATURE_TEMP_EMERGENCY_ALARM },
231
{ "lcrit_alarm", SENSORS_SUBFEATURE_TEMP_LCRIT_ALARM },
232
{ "fault", SENSORS_SUBFEATURE_TEMP_FAULT },
233
{ "type", SENSORS_SUBFEATURE_TEMP_TYPE },
234
{ "offset", SENSORS_SUBFEATURE_TEMP_OFFSET },
235
{ "beep", SENSORS_SUBFEATURE_TEMP_BEEP },
239
static const struct subfeature_type_match in_matches[] = {
240
{ "input", SENSORS_SUBFEATURE_IN_INPUT },
241
{ "min", SENSORS_SUBFEATURE_IN_MIN },
242
{ "max", SENSORS_SUBFEATURE_IN_MAX },
243
{ "lcrit", SENSORS_SUBFEATURE_IN_LCRIT },
244
{ "crit", SENSORS_SUBFEATURE_IN_CRIT },
245
{ "average", SENSORS_SUBFEATURE_IN_AVERAGE },
246
{ "lowest", SENSORS_SUBFEATURE_IN_LOWEST },
247
{ "highest", SENSORS_SUBFEATURE_IN_HIGHEST },
248
{ "alarm", SENSORS_SUBFEATURE_IN_ALARM },
249
{ "min_alarm", SENSORS_SUBFEATURE_IN_MIN_ALARM },
250
{ "max_alarm", SENSORS_SUBFEATURE_IN_MAX_ALARM },
251
{ "lcrit_alarm", SENSORS_SUBFEATURE_IN_LCRIT_ALARM },
252
{ "crit_alarm", SENSORS_SUBFEATURE_IN_CRIT_ALARM },
253
{ "beep", SENSORS_SUBFEATURE_IN_BEEP },
257
static const struct subfeature_type_match fan_matches[] = {
258
{ "input", SENSORS_SUBFEATURE_FAN_INPUT },
259
{ "min", SENSORS_SUBFEATURE_FAN_MIN },
260
{ "max", SENSORS_SUBFEATURE_FAN_MAX },
261
{ "div", SENSORS_SUBFEATURE_FAN_DIV },
262
{ "pulses", SENSORS_SUBFEATURE_FAN_PULSES },
263
{ "alarm", SENSORS_SUBFEATURE_FAN_ALARM },
264
{ "min_alarm", SENSORS_SUBFEATURE_FAN_MIN_ALARM },
265
{ "max_alarm", SENSORS_SUBFEATURE_FAN_MAX_ALARM },
266
{ "fault", SENSORS_SUBFEATURE_FAN_FAULT },
267
{ "beep", SENSORS_SUBFEATURE_FAN_BEEP },
271
static const struct subfeature_type_match power_matches[] = {
272
{ "average", SENSORS_SUBFEATURE_POWER_AVERAGE },
273
{ "average_highest", SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST },
274
{ "average_lowest", SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST },
275
{ "input", SENSORS_SUBFEATURE_POWER_INPUT },
276
{ "input_highest", SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST },
277
{ "input_lowest", SENSORS_SUBFEATURE_POWER_INPUT_LOWEST },
278
{ "cap", SENSORS_SUBFEATURE_POWER_CAP },
279
{ "cap_hyst", SENSORS_SUBFEATURE_POWER_CAP_HYST },
280
{ "cap_alarm", SENSORS_SUBFEATURE_POWER_CAP_ALARM },
281
{ "alarm", SENSORS_SUBFEATURE_POWER_ALARM },
282
{ "max", SENSORS_SUBFEATURE_POWER_MAX },
283
{ "min", SENSORS_SUBFEATURE_POWER_MIN },
284
{ "min_alarm", SENSORS_SUBFEATURE_POWER_MIN_ALARM },
285
{ "max_alarm", SENSORS_SUBFEATURE_POWER_MAX_ALARM },
286
{ "crit", SENSORS_SUBFEATURE_POWER_CRIT },
287
{ "lcrit", SENSORS_SUBFEATURE_POWER_LCRIT },
288
{ "crit_alarm", SENSORS_SUBFEATURE_POWER_CRIT_ALARM },
289
{ "lcrit_alarm", SENSORS_SUBFEATURE_POWER_LCRIT_ALARM },
290
{ "average_interval", SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL },
294
static const struct subfeature_type_match energy_matches[] = {
295
{ "input", SENSORS_SUBFEATURE_ENERGY_INPUT },
299
static 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
{ "average", SENSORS_SUBFEATURE_CURR_AVERAGE },
306
{ "lowest", SENSORS_SUBFEATURE_CURR_LOWEST },
307
{ "highest", SENSORS_SUBFEATURE_CURR_HIGHEST },
308
{ "alarm", SENSORS_SUBFEATURE_CURR_ALARM },
309
{ "min_alarm", SENSORS_SUBFEATURE_CURR_MIN_ALARM },
310
{ "max_alarm", SENSORS_SUBFEATURE_CURR_MAX_ALARM },
311
{ "lcrit_alarm", SENSORS_SUBFEATURE_CURR_LCRIT_ALARM },
312
{ "crit_alarm", SENSORS_SUBFEATURE_CURR_CRIT_ALARM },
313
{ "beep", SENSORS_SUBFEATURE_CURR_BEEP },
317
static const struct subfeature_type_match humidity_matches[] = {
318
{ "input", SENSORS_SUBFEATURE_HUMIDITY_INPUT },
322
static const struct subfeature_type_match cpu_matches[] = {
323
{ "vid", SENSORS_SUBFEATURE_VID },
327
static const struct subfeature_type_match intrusion_matches[] = {
328
{ "alarm", SENSORS_SUBFEATURE_INTRUSION_ALARM },
329
{ "beep", SENSORS_SUBFEATURE_INTRUSION_BEEP },
332
static struct feature_type_match matches[] = {
333
{ "temp%d%c", temp_matches },
334
{ "in%d%c", in_matches },
335
{ "fan%d%c", fan_matches },
336
{ "cpu%d%c", cpu_matches },
337
{ "power%d%c", power_matches },
338
{ "curr%d%c", curr_matches },
339
{ "energy%d%c", energy_matches },
340
{ "intrusion%d%c", intrusion_matches },
341
{ "humidity%d%c", humidity_matches },
344
/* Return the subfeature type and channel number based on the subfeature
347
sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr)
351
const struct subfeature_type_match *submatches;
354
if (!strcmp(name, "beep_enable")) {
356
return SENSORS_SUBFEATURE_BEEP_ENABLE;
359
for (i = 0; i < ARRAY_SIZE(matches); i++)
360
if ((count = sscanf(name, matches[i].name, nr, &c)))
363
if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
364
return SENSORS_SUBFEATURE_UNKNOWN; /* no match */
366
submatches = matches[i].submatches;
367
name = strchr(name + 3, '_') + 1;
368
for (i = 0; submatches[i].name != NULL; i++)
369
if (!strcmp(name, submatches[i].name))
370
return submatches[i].type;
372
return SENSORS_SUBFEATURE_UNKNOWN;
375
static int sensors_compute_max_sf(void)
377
int i, j, max, offset;
378
const struct subfeature_type_match *submatches;
379
sensors_feature_type ftype;
382
for (i = 0; i < ARRAY_SIZE(matches); i++) {
383
submatches = matches[i].submatches;
384
for (j = 0; submatches[j].name != NULL; j++) {
385
ftype = submatches[j].type >> 8;
387
if (ftype < SENSORS_FEATURE_VID) {
388
offset = submatches[j].type & 0x7F;
392
offset = submatches[j].type & 0xFF;
393
if (offset >= max * 2)
394
max = ((offset + 1) + 1) / 2;
402
static int sensors_get_attr_mode(const char *device, const char *attr)
408
snprintf(path, NAME_MAX, "%s/%s", device, attr);
409
if (!stat(path, &st)) {
410
if (st.st_mode & S_IRUSR)
411
mode |= SENSORS_MODE_R;
412
if (st.st_mode & S_IWUSR)
413
mode |= SENSORS_MODE_W;
418
static int sensors_read_dynamic_chip(sensors_chip_features *chip,
419
const char *dev_path)
421
int i, fnum = 0, sfnum = 0, prev_slot;
422
static int max_subfeatures, feature_size;
427
sensors_subfeature *sf;
428
} all_types[SENSORS_FEATURE_MAX];
429
sensors_subfeature *dyn_subfeatures;
430
sensors_feature *dyn_features;
431
sensors_feature_type ftype;
432
sensors_subfeature_type sftype;
434
if (!(dir = opendir(dev_path)))
437
/* Dynamically figure out the max number of subfeatures */
438
if (!max_subfeatures) {
439
max_subfeatures = sensors_compute_max_sf();
440
feature_size = max_subfeatures * 2;
443
/* We use a set of large sparse tables at first (one per main
444
feature type present) to store all found subfeatures, so that we
445
can store them sorted and then later create a dense sorted table. */
446
memset(&all_types, 0, sizeof(all_types));
448
while ((ent = readdir(dir))) {
452
/* Skip directories and symlinks */
453
if (ent->d_type != DT_REG)
458
sftype = sensors_subfeature_get_type(name, &nr);
459
if (sftype == SENSORS_SUBFEATURE_UNKNOWN)
463
/* Adjust the channel number */
465
case SENSORS_FEATURE_FAN:
466
case SENSORS_FEATURE_TEMP:
467
case SENSORS_FEATURE_POWER:
468
case SENSORS_FEATURE_ENERGY:
469
case SENSORS_FEATURE_CURR:
470
case SENSORS_FEATURE_HUMIDITY:
477
/* Skip invalid entries. The high limit is arbitrary, we just
478
don't want to allocate an insane amount of memory. */
479
if (nr < 0 || nr >= 1024) {
481
sensors_fatal_error(__func__,
482
"Invalid channel number!");
487
/* (Re-)allocate memory if needed */
488
if (all_types[ftype].count < nr + 1) {
489
int old_count = all_types[ftype].count;
490
int step = ftype < SENSORS_FEATURE_VID ? 8 :
491
ftype < SENSORS_FEATURE_BEEP_ENABLE ? 2 : 1;
493
while (all_types[ftype].count < nr + 1)
494
all_types[ftype].count += step;
496
all_types[ftype].sf = realloc(all_types[ftype].sf,
497
all_types[ftype].count *
499
sizeof(sensors_subfeature));
500
if (!all_types[ftype].sf)
501
sensors_fatal_error(__func__, "Out of memory");
502
memset(all_types[ftype].sf + old_count * feature_size,
503
0, (all_types[ftype].count - old_count) *
504
feature_size * sizeof(sensors_subfeature));
507
/* "calculate" a place to store the subfeature in our sparse,
509
if (ftype < SENSORS_FEATURE_VID)
510
i = nr * feature_size +
511
((sftype & 0x80) >> 7) * max_subfeatures +
514
i = nr * feature_size + (sftype & 0xFF);
516
if (all_types[ftype].sf[i].name) {
518
sensors_fatal_error(__func__, "Duplicate subfeature");
523
/* fill in the subfeature members */
524
all_types[ftype].sf[i].type = sftype;
525
all_types[ftype].sf[i].name = strdup(name);
526
if (!all_types[ftype].sf[i].name)
527
sensors_fatal_error(__func__, "Out of memory");
529
/* Other and misc subfeatures are never scaled */
530
if (sftype < SENSORS_SUBFEATURE_VID && !(sftype & 0x80))
531
all_types[ftype].sf[i].flags |= SENSORS_COMPUTE_MAPPING;
532
all_types[ftype].sf[i].flags |=
533
sensors_get_attr_mode(dev_path, name);
539
if (!sfnum) { /* No subfeature */
540
chip->subfeature = NULL;
544
/* How many main features? */
545
for (ftype = 0; ftype < SENSORS_FEATURE_MAX; ftype++) {
547
for (i = 0; i < all_types[ftype].count * feature_size; i++) {
548
if (!all_types[ftype].sf[i].name)
551
if (i / feature_size != prev_slot) {
553
prev_slot = i / feature_size;
558
dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature));
559
dyn_features = calloc(fnum, sizeof(sensors_feature));
560
if (!dyn_subfeatures || !dyn_features)
561
sensors_fatal_error(__func__, "Out of memory");
563
/* Copy from the sparse array to the compact array */
566
for (ftype = 0; ftype < SENSORS_FEATURE_MAX; ftype++) {
568
for (i = 0; i < all_types[ftype].count * feature_size; i++) {
569
if (!all_types[ftype].sf[i].name)
572
/* New main feature? */
573
if (i / feature_size != prev_slot) {
575
prev_slot = i / feature_size;
577
dyn_features[fnum].name =
578
get_feature_name(ftype,
579
all_types[ftype].sf[i].name);
580
dyn_features[fnum].number = fnum;
581
dyn_features[fnum].first_subfeature = sfnum;
582
dyn_features[fnum].type = ftype;
585
dyn_subfeatures[sfnum] = all_types[ftype].sf[i];
586
dyn_subfeatures[sfnum].number = sfnum;
587
/* Back to the feature */
588
dyn_subfeatures[sfnum].mapping = fnum;
594
chip->subfeature = dyn_subfeatures;
595
chip->subfeature_count = sfnum;
596
chip->feature = dyn_features;
597
chip->feature_count = ++fnum;
600
for (ftype = 0; ftype < SENSORS_FEATURE_MAX; ftype++)
601
free(all_types[ftype].sf);
605
/* returns !0 if sysfs filesystem was found, 0 otherwise */
606
int sensors_init_sysfs(void)
608
struct statfs statfsbuf;
610
snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys");
611
if (statfs(sensors_sysfs_mount, &statfsbuf) < 0
612
|| statfsbuf.f_type != SYSFS_MAGIC)
618
static int classify_device(const char *dev_name,
620
sensors_chip_features *entry)
622
int domain, bus, slot, fn, vendor, product, id;
623
char bus_path[NAME_MAX];
627
if ((!subsys || !strcmp(subsys, "i2c")) &&
628
sscanf(dev_name, "%hd-%x", &entry->chip.bus.nr,
629
&entry->chip.addr) == 2) {
630
/* find out if legacy ISA or not */
631
if (entry->chip.bus.nr == 9191) {
632
entry->chip.bus.type = SENSORS_BUS_TYPE_ISA;
633
entry->chip.bus.nr = 0;
635
entry->chip.bus.type = SENSORS_BUS_TYPE_I2C;
636
snprintf(bus_path, sizeof(bus_path),
637
"%s/class/i2c-adapter/i2c-%d/device",
638
sensors_sysfs_mount, entry->chip.bus.nr);
640
if ((bus_attr = sysfs_read_attr(bus_path, "name"))) {
641
if (!strncmp(bus_attr, "ISA ", 4)) {
642
entry->chip.bus.type = SENSORS_BUS_TYPE_ISA;
643
entry->chip.bus.nr = 0;
650
if ((!subsys || !strcmp(subsys, "spi")) &&
651
sscanf(dev_name, "spi%hd.%d", &entry->chip.bus.nr,
652
&entry->chip.addr) == 2) {
654
entry->chip.bus.type = SENSORS_BUS_TYPE_SPI;
656
if ((!subsys || !strcmp(subsys, "pci")) &&
657
sscanf(dev_name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
659
entry->chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
660
entry->chip.bus.type = SENSORS_BUS_TYPE_PCI;
661
entry->chip.bus.nr = 0;
663
if ((!subsys || !strcmp(subsys, "platform") ||
664
!strcmp(subsys, "of_platform"))) {
665
/* must be new ISA (platform driver) */
666
if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry->chip.addr) != 1)
667
entry->chip.addr = 0;
668
entry->chip.bus.type = SENSORS_BUS_TYPE_ISA;
669
entry->chip.bus.nr = 0;
670
} else if (subsys && !strcmp(subsys, "acpi")) {
671
entry->chip.bus.type = SENSORS_BUS_TYPE_ACPI;
672
/* For now we assume that acpi devices are unique */
673
entry->chip.bus.nr = 0;
674
entry->chip.addr = 0;
676
if (subsys && !strcmp(subsys, "hid") &&
677
sscanf(dev_name, "%x:%x:%x.%x", &bus, &vendor, &product, &id) == 4) {
678
entry->chip.bus.type = SENSORS_BUS_TYPE_HID;
679
/* As of kernel 2.6.32, the hid device names don't look good */
680
entry->chip.bus.nr = bus;
681
entry->chip.addr = id;
683
if (subsys && !strcmp(subsys, "mdio_bus")) {
684
if (sscanf(dev_name, "%*[^:]:%d", &entry->chip.addr) != 1)
685
entry->chip.addr = 0;
686
entry->chip.bus.type = SENSORS_BUS_TYPE_MDIO;
687
entry->chip.bus.nr = 0;
689
if (subsys && !strcmp(subsys, "scsi") &&
690
sscanf(dev_name, "%d:%d:%d:%x", &domain, &bus, &slot, &fn) == 4) {
691
/* adapter(host), channel(bus), id(target), lun */
692
entry->chip.addr = (bus << 8) + (slot << 4) + fn;
693
entry->chip.bus.type = SENSORS_BUS_TYPE_SCSI;
694
entry->chip.bus.nr = domain;
703
static int find_bus_type(const char *dev_path,
704
const char *dev_name,
705
sensors_chip_features *entry)
707
char linkpath[NAME_MAX];
708
char subsys_path[NAME_MAX], *subsys;
710
char *my_dev_path = NULL;
713
my_dev_path = strdup(dev_path);
714
if (my_dev_path == NULL)
715
sensors_fatal_error(__func__, "Out of memory");
718
while (!ret && my_dev_path != NULL) {
719
snprintf(linkpath, NAME_MAX, "%s/subsystem", my_dev_path);
720
sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
721
if (sub_len < 0 && errno == ENOENT) {
722
/* Fallback to "bus" link for kernels <= 2.6.17 */
723
snprintf(linkpath, NAME_MAX, "%s/bus", my_dev_path);
724
sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
727
/* Older kernels (<= 2.6.11) have neither the subsystem
728
symlink nor the bus symlink */
729
if (errno == ENOENT) {
732
ret = -SENSORS_ERR_KERNEL;
736
subsys_path[sub_len] = '\0';
737
subsys = strrchr(subsys_path, '/') + 1;
739
ret = classify_device(dev_name, subsys, entry);
741
snprintf(linkpath, NAME_MAX, "%s/device", my_dev_path);
743
my_dev_path = realpath(linkpath, NULL);
744
if (my_dev_path != NULL)
745
dev_name = strrchr(my_dev_path, '/') + 1;
746
else if (errno == ENOMEM)
747
sensors_fatal_error(__func__, "Out of memory");
751
if (my_dev_path != NULL)
756
/* returns: number of devices added (0 or 1) if successful, <0 otherwise */
757
static int sensors_read_one_sysfs_chip(const char *dev_path,
758
const char *dev_name,
759
const char *hwmon_path)
763
sensors_chip_features entry;
765
/* ignore any device without name attribute */
766
if (!(entry.chip.prefix = sysfs_read_attr(hwmon_path, "name")))
769
entry.chip.path = strdup(hwmon_path);
770
if (!entry.chip.path)
771
sensors_fatal_error(__func__, "Out of memory");
773
if (dev_path == NULL) {
776
ret = find_bus_type(dev_path, dev_name, &entry);
780
} else if (ret < 0) {
786
entry.chip.bus.type = SENSORS_BUS_TYPE_VIRTUAL;
787
entry.chip.bus.nr = 0;
788
/* For now we assume that virtual devices are unique */
792
if (sensors_read_dynamic_chip(&entry, hwmon_path) < 0) {
793
ret = -SENSORS_ERR_KERNEL;
796
if (!entry.subfeature) { /* No subfeature, discard chip */
800
sensors_add_proc_chips(&entry);
805
free(entry.chip.prefix);
806
free(entry.chip.path);
810
static int sensors_add_hwmon_device_compat(const char *path,
811
const char *dev_name)
815
err = sensors_read_one_sysfs_chip(path, dev_name, path);
821
/* returns 0 if successful, !0 otherwise */
822
static int sensors_read_sysfs_chips_compat(void)
826
ret = sysfs_foreach_busdev("i2c", sensors_add_hwmon_device_compat);
827
if (ret && ret != ENOENT)
828
return -SENSORS_ERR_KERNEL;
833
static int sensors_add_hwmon_device(const char *path, const char *classdev)
835
char linkpath[NAME_MAX];
836
char *dev_path, *dev_name;
838
(void)classdev; /* hide warning */
840
snprintf(linkpath, NAME_MAX, "%s/device", path);
841
dev_path = realpath(linkpath, NULL);
842
if (dev_path == NULL) {
843
if (errno == ENOMEM) {
844
sensors_fatal_error(__func__, "Out of memory");
846
/* No device link? Treat as virtual */
847
err = sensors_read_one_sysfs_chip(NULL, NULL, path);
850
dev_name = strrchr(dev_path, '/') + 1;
852
/* The attributes we want might be those of the hwmon class
853
device, or those of the device itself. */
854
err = sensors_read_one_sysfs_chip(dev_path, dev_name, path);
856
err = sensors_read_one_sysfs_chip(dev_path, dev_name,
865
/* returns 0 if successful, !0 otherwise */
866
int sensors_read_sysfs_chips(void)
870
ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device);
872
/* compatibility function for kernel 2.6.n where n <= 13 */
873
return sensors_read_sysfs_chips_compat();
877
ret = -SENSORS_ERR_KERNEL;
881
/* returns 0 if successful, !0 otherwise */
882
static int sensors_add_i2c_bus(const char *path, const char *classdev)
886
if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 ||
887
entry.bus.nr == 9191) /* legacy ISA */
889
entry.bus.type = SENSORS_BUS_TYPE_I2C;
891
/* Get the adapter name from the classdev "name" attribute
892
* (Linux 2.6.20 and later). If it fails, fall back to
893
* the device "name" attribute (for older kernels). */
894
entry.adapter = sysfs_read_attr(path, "name");
896
entry.adapter = sysfs_read_attr(path, "device/name");
898
sensors_add_proc_bus(&entry);
903
/* returns 0 if successful, !0 otherwise */
904
int sensors_read_sysfs_bus(void)
908
ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus);
910
ret = sysfs_foreach_busdev("i2c", sensors_add_i2c_bus);
911
if (ret && ret != ENOENT)
912
return -SENSORS_ERR_KERNEL;
917
int sensors_read_sysfs_attr(const sensors_chip_name *name,
918
const sensors_subfeature *subfeature,
924
snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
925
if ((f = fopen(n, "r"))) {
929
res = fscanf(f, "%lf", value);
930
if (res == EOF && errno == EIO)
931
err = -SENSORS_ERR_IO;
933
err = -SENSORS_ERR_ACCESS_R;
940
return -SENSORS_ERR_IO;
942
return -SENSORS_ERR_ACCESS_R;
944
*value /= get_type_scaling(subfeature->type);
946
return -SENSORS_ERR_KERNEL;
951
int sensors_write_sysfs_attr(const sensors_chip_name *name,
952
const sensors_subfeature *subfeature,
958
snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
959
if ((f = fopen(n, "w"))) {
962
value *= get_type_scaling(subfeature->type);
963
res = fprintf(f, "%d", (int) value);
965
err = -SENSORS_ERR_IO;
967
err = -SENSORS_ERR_ACCESS_W;
974
return -SENSORS_ERR_IO;
976
return -SENSORS_ERR_ACCESS_W;
979
return -SENSORS_ERR_KERNEL;