| | 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)(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)(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 | /****************************************************************************/ |
| 433 | | struct sysfs_bus *bus; |
| 434 | | struct dlist *devs; |
| 435 | | struct sysfs_device *dev; |
| 436 | | int ret = 0; |
| 437 | | |
| 438 | | if (!(bus = sysfs_open_bus("i2c"))) { |
| 439 | | if (errno && errno != ENOENT) |
| 440 | | ret = -SENSORS_ERR_KERNEL; |
| 441 | | goto exit0; |
| 442 | | } |
| 443 | | |
| 444 | | if (!(devs = sysfs_get_bus_devices(bus))) { |
| 445 | | if (errno && errno != ENOENT) |
| 446 | | ret = -SENSORS_ERR_KERNEL; |
| 447 | | goto exit1; |
| 448 | | } |
| 449 | | |
| 450 | | dlist_for_each_data(devs, dev, struct sysfs_device) |
| 451 | | if ((ret = sensors_read_one_sysfs_chip(dev))) |
| 452 | | goto exit1; |
| 453 | | |
| 454 | | exit1: |
| 455 | | /* this frees bus and devs */ |
| 456 | | sysfs_close_bus(bus); |
| 457 | | |
| 458 | | exit0: |
| 459 | | return ret; |
| | 533 | int ret; |
| | 534 | |
| | 535 | ret = sysfs_foreach_busdev("i2c", sensors_read_one_sysfs_chip); |
| | 536 | if (ret && ret != ENOENT) |
| | 537 | return -SENSORS_ERR_KERNEL; |
| | 538 | |
| | 539 | return 0; |
| | 540 | } |
| | 541 | |
| | 542 | static int sensors_add_hwmon_device(char *path, const char *classdev) |
| | 543 | { |
| | 544 | char device[NAME_MAX]; |
| | 545 | int path_off = strlen(path); |
| | 546 | int dev_len; |
| | 547 | (void)classdev; /* hide warning */ |
| | 548 | |
| | 549 | snprintf(path + path_off, NAME_MAX - path_off, "/device"); |
| | 550 | dev_len = readlink(path, device, NAME_MAX - 1); |
| | 551 | if (dev_len < 0) |
| | 552 | return -SENSORS_ERR_KERNEL; |
| | 553 | device[dev_len] = '\0'; |
| | 554 | |
| | 555 | return sensors_read_one_sysfs_chip(path, strrchr(device, '/') + 1); |
| 475 | | if (!(clsdevs = sysfs_get_class_devices(cls))) { |
| 476 | | if (errno && errno != ENOENT) |
| 477 | | ret = -SENSORS_ERR_KERNEL; |
| 478 | | goto exit; |
| 479 | | } |
| 480 | | |
| 481 | | dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) { |
| 482 | | struct sysfs_device *dev; |
| 483 | | if (!(dev = sysfs_get_classdev_device(clsdev))) { |
| 484 | | ret = -SENSORS_ERR_KERNEL; |
| 485 | | goto exit; |
| 486 | | } |
| 487 | | if ((ret = sensors_read_one_sysfs_chip(dev))) |
| 488 | | goto exit; |
| 489 | | } |
| 490 | | |
| 491 | | exit: |
| 492 | | /* this frees cls and clsdevs */ |
| 493 | | sysfs_close_class(cls); |
| | 569 | if (ret > 0) |
| | 570 | ret = -SENSORS_ERR_KERNEL; |
| | 572 | } |
| | 573 | |
| | 574 | /* returns 0 if successful, !0 otherwise */ |
| | 575 | static int sensors_add_i2c_bus(char *path, const char *classdev) |
| | 576 | { |
| | 577 | sensors_bus entry; |
| | 578 | |
| | 579 | if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 || |
| | 580 | entry.bus.nr == 9191) /* legacy ISA */ |
| | 581 | return 0; |
| | 582 | entry.bus.type = SENSORS_BUS_TYPE_I2C; |
| | 583 | |
| | 584 | /* Get the adapter name from the classdev "name" attribute |
| | 585 | * (Linux 2.6.20 and later). If it fails, fall back to |
| | 586 | * the device "name" attribute (for older kernels). */ |
| | 587 | entry.adapter = sysfs_read_attr(path, "name"); |
| | 588 | if (!entry.adapter) |
| | 589 | entry.adapter = sysfs_read_attr(path, "device/name"); |
| | 590 | if (entry.adapter) |
| | 591 | sensors_add_proc_bus(&entry); |
| | 592 | |
| | 593 | return 0; |
| 500 | | struct sysfs_class *cls; |
| 501 | | struct dlist *clsdevs; |
| 502 | | struct sysfs_class_device *clsdev; |
| 503 | | sensors_bus entry; |
| 504 | | int ret = 0; |
| 505 | | |
| 506 | | if (!(cls = sysfs_open_class("i2c-adapter"))) { |
| 507 | | if (errno && errno != ENOENT) |
| 508 | | ret = -SENSORS_ERR_KERNEL; |
| 509 | | goto exit0; |
| 510 | | } |
| 511 | | |
| 512 | | if (!(clsdevs = sysfs_get_class_devices(cls))) { |
| 513 | | if (errno && errno != ENOENT) |
| 514 | | ret = -SENSORS_ERR_KERNEL; |
| 515 | | goto exit1; |
| 516 | | } |
| 517 | | |
| 518 | | dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) { |
| 519 | | struct sysfs_device *dev; |
| 520 | | struct sysfs_attribute *attr; |
| 521 | | |
| 522 | | /* Get the adapter name from the classdev "name" attribute |
| 523 | | * (Linux 2.6.20 and later). If it fails, fall back to |
| 524 | | * the device "name" attribute (for older kernels). */ |
| 525 | | if (!(attr = sysfs_get_classdev_attr(clsdev, "name")) |
| 526 | | && !((dev = sysfs_get_classdev_device(clsdev)) && |
| 527 | | (attr = sysfs_get_device_attr(dev, "name")))) |
| 528 | | continue; |
| 529 | | |
| 530 | | if (sscanf(clsdev->name, "i2c-%hd", &entry.bus.nr) != 1 || |
| 531 | | entry.bus.nr == 9191) /* legacy ISA */ |
| 532 | | continue; |
| 533 | | entry.bus.type = SENSORS_BUS_TYPE_I2C; |
| 534 | | |
| 535 | | /* NB: attr->value[attr->len-1] == '\n'; chop that off */ |
| 536 | | entry.adapter = strndup(attr->value, attr->len - 1); |
| 537 | | if (!entry.adapter) |
| 538 | | sensors_fatal_error(__FUNCTION__, "out of memory"); |
| 539 | | |
| 540 | | sensors_add_proc_bus(&entry); |
| 541 | | } |
| 542 | | |
| 543 | | exit1: |
| 544 | | /* this frees *cls _and_ *clsdevs */ |
| 545 | | sysfs_close_class(cls); |
| 546 | | |
| 547 | | exit0: |
| 548 | | return ret; |
| | 599 | int ret; |
| | 600 | |
| | 601 | ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus); |
| | 602 | if (ret && ret != ENOENT) |
| | 603 | return -SENSORS_ERR_KERNEL; |
| | 604 | |
| | 605 | return 0; |