1 // SPDX-License-Identifier: GPL-2.0-only 2 /* IIO - useful set of util functionality 3 * 4 * Copyright (c) 2008 Jonathan Cameron 5 */ 6 #include <string.h> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <stdint.h> 10 #include <dirent.h> 11 #include <errno.h> 12 #include <ctype.h> 13 #include "iio_utils.h" 14 15 const char *iio_dir = "/sys/bus/iio/devices/"; 16 17 static char * const iio_direction[] = { 18 "in", 19 "out", 20 }; 21 22 /** 23 * iioutils_break_up_name() - extract generic name from full channel name 24 * @full_name: the full channel name 25 * @generic_name: the output generic channel name 26 * 27 * Returns 0 on success, or a negative error code if string extraction failed. 28 **/ 29 int iioutils_break_up_name(const char *full_name, char **generic_name) 30 { 31 char *current; 32 char *w, *r; 33 char *working, *prefix = ""; 34 int i, ret; 35 36 for (i = 0; i < ARRAY_SIZE(iio_direction); i++) 37 if (!strncmp(full_name, iio_direction[i], 38 strlen(iio_direction[i]))) { 39 prefix = iio_direction[i]; 40 break; 41 } 42 43 current = strdup(full_name + strlen(prefix) + 1); 44 if (!current) 45 return -ENOMEM; 46 47 working = strtok(current, "_\0"); 48 if (!working) { 49 free(current); 50 return -EINVAL; 51 } 52 53 w = working; 54 r = working; 55 56 while (*r != '\0') { 57 if (!isdigit(*r)) { 58 *w = *r; 59 w++; 60 } 61 62 r++; 63 } 64 *w = '\0'; 65 ret = asprintf(generic_name, "%s_%s", prefix, working); 66 free(current); 67 68 return (ret == -1) ? -ENOMEM : 0; 69 } 70 71 /** 72 * iioutils_get_type() - find and process _type attribute data 73 * @is_signed: output whether channel is signed 74 * @bytes: output how many bytes the channel storage occupies 75 * @bits_used: output number of valid bits of data 76 * @shift: output amount of bits to shift right data before applying bit mask 77 * @mask: output a bit mask for the raw data 78 * @be: output if data in big endian 79 * @device_dir: the IIO device directory 80 * @name: the channel name 81 * @generic_name: the channel type name 82 * 83 * Returns a value >= 0 on success, otherwise a negative error code. 84 **/ 85 int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, 86 unsigned *shift, uint64_t *mask, unsigned *be, 87 const char *device_dir, const char *name, 88 const char *generic_name) 89 { 90 FILE *sysfsfp; 91 int ret; 92 DIR *dp; 93 char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; 94 char signchar, endianchar; 95 unsigned padint; 96 const struct dirent *ent; 97 98 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 99 if (ret < 0) 100 return -ENOMEM; 101 102 ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); 103 if (ret < 0) { 104 ret = -ENOMEM; 105 goto error_free_scan_el_dir; 106 } 107 ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); 108 if (ret < 0) { 109 ret = -ENOMEM; 110 goto error_free_builtname; 111 } 112 113 dp = opendir(scan_el_dir); 114 if (!dp) { 115 ret = -errno; 116 goto error_free_builtname_generic; 117 } 118 119 ret = -ENOENT; 120 while (ent = readdir(dp), ent) 121 if ((strcmp(builtname, ent->d_name) == 0) || 122 (strcmp(builtname_generic, ent->d_name) == 0)) { 123 ret = asprintf(&filename, 124 "%s/%s", scan_el_dir, ent->d_name); 125 if (ret < 0) { 126 ret = -ENOMEM; 127 goto error_closedir; 128 } 129 130 sysfsfp = fopen(filename, "r"); 131 if (!sysfsfp) { 132 ret = -errno; 133 fprintf(stderr, "failed to open %s\n", 134 filename); 135 goto error_free_filename; 136 } 137 138 ret = fscanf(sysfsfp, 139 "%ce:%c%u/%u>>%u", 140 &endianchar, 141 &signchar, 142 bits_used, 143 &padint, shift); 144 if (ret < 0) { 145 ret = -errno; 146 fprintf(stderr, 147 "failed to pass scan type description\n"); 148 goto error_close_sysfsfp; 149 } else if (ret != 5) { 150 ret = -EIO; 151 fprintf(stderr, 152 "scan type description didn't match\n"); 153 goto error_close_sysfsfp; 154 } 155 156 *be = (endianchar == 'b'); 157 *bytes = padint / 8; 158 if (*bits_used == 64) 159 *mask = ~(0ULL); 160 else 161 *mask = (1ULL << *bits_used) - 1ULL; 162 163 *is_signed = (signchar == 's'); 164 if (fclose(sysfsfp)) { 165 ret = -errno; 166 fprintf(stderr, "Failed to close %s\n", 167 filename); 168 goto error_free_filename; 169 } 170 171 sysfsfp = 0; 172 free(filename); 173 filename = 0; 174 175 /* 176 * Avoid having a more generic entry overwriting 177 * the settings. 178 */ 179 if (strcmp(builtname, ent->d_name) == 0) 180 break; 181 } 182 183 error_close_sysfsfp: 184 if (sysfsfp) 185 if (fclose(sysfsfp)) 186 perror("iioutils_get_type(): Failed to close file"); 187 188 error_free_filename: 189 if (filename) 190 free(filename); 191 192 error_closedir: 193 if (closedir(dp) == -1) 194 perror("iioutils_get_type(): Failed to close directory"); 195 196 error_free_builtname_generic: 197 free(builtname_generic); 198 error_free_builtname: 199 free(builtname); 200 error_free_scan_el_dir: 201 free(scan_el_dir); 202 203 return ret; 204 } 205 206 /** 207 * iioutils_get_param_float() - read a float value from a channel parameter 208 * @output: output the float value 209 * @param_name: the parameter name to read 210 * @device_dir: the IIO device directory in sysfs 211 * @name: the channel name 212 * @generic_name: the channel type name 213 * 214 * Returns a value >= 0 on success, otherwise a negative error code. 215 **/ 216 int iioutils_get_param_float(float *output, const char *param_name, 217 const char *device_dir, const char *name, 218 const char *generic_name) 219 { 220 FILE *sysfsfp; 221 int ret; 222 DIR *dp; 223 char *builtname, *builtname_generic; 224 char *filename = NULL; 225 const struct dirent *ent; 226 227 ret = asprintf(&builtname, "%s_%s", name, param_name); 228 if (ret < 0) 229 return -ENOMEM; 230 231 ret = asprintf(&builtname_generic, 232 "%s_%s", generic_name, param_name); 233 if (ret < 0) { 234 ret = -ENOMEM; 235 goto error_free_builtname; 236 } 237 238 dp = opendir(device_dir); 239 if (!dp) { 240 ret = -errno; 241 goto error_free_builtname_generic; 242 } 243 244 ret = -ENOENT; 245 while (ent = readdir(dp), ent) 246 if ((strcmp(builtname, ent->d_name) == 0) || 247 (strcmp(builtname_generic, ent->d_name) == 0)) { 248 ret = asprintf(&filename, 249 "%s/%s", device_dir, ent->d_name); 250 if (ret < 0) { 251 ret = -ENOMEM; 252 goto error_closedir; 253 } 254 255 sysfsfp = fopen(filename, "r"); 256 if (!sysfsfp) { 257 ret = -errno; 258 goto error_free_filename; 259 } 260 261 errno = 0; 262 if (fscanf(sysfsfp, "%f", output) != 1) 263 ret = errno ? -errno : -ENODATA; 264 265 break; 266 } 267 error_free_filename: 268 if (filename) 269 free(filename); 270 271 error_closedir: 272 if (closedir(dp) == -1) 273 perror("iioutils_get_param_float(): Failed to close directory"); 274 275 error_free_builtname_generic: 276 free(builtname_generic); 277 error_free_builtname: 278 free(builtname); 279 280 return ret; 281 } 282 283 /** 284 * bsort_channel_array_by_index() - sort the array in index order 285 * @ci_array: the iio_channel_info array to be sorted 286 * @cnt: the amount of array elements 287 **/ 288 289 void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) 290 { 291 struct iio_channel_info temp; 292 int x, y; 293 294 for (x = 0; x < cnt; x++) 295 for (y = 0; y < (cnt - 1); y++) 296 if (ci_array[y].index > ci_array[y + 1].index) { 297 temp = ci_array[y + 1]; 298 ci_array[y + 1] = ci_array[y]; 299 ci_array[y] = temp; 300 } 301 } 302 303 /** 304 * build_channel_array() - function to figure out what channels are present 305 * @device_dir: the IIO device directory in sysfs 306 * @ci_array: output the resulting array of iio_channel_info 307 * @counter: output the amount of array elements 308 * 309 * Returns 0 on success, otherwise a negative error code. 310 **/ 311 int build_channel_array(const char *device_dir, 312 struct iio_channel_info **ci_array, int *counter) 313 { 314 DIR *dp; 315 FILE *sysfsfp; 316 int count = 0, i; 317 struct iio_channel_info *current; 318 int ret; 319 const struct dirent *ent; 320 char *scan_el_dir; 321 char *filename; 322 323 *counter = 0; 324 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 325 if (ret < 0) 326 return -ENOMEM; 327 328 dp = opendir(scan_el_dir); 329 if (!dp) { 330 ret = -errno; 331 goto error_free_name; 332 } 333 334 while (ent = readdir(dp), ent) 335 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 336 "_en") == 0) { 337 ret = asprintf(&filename, 338 "%s/%s", scan_el_dir, ent->d_name); 339 if (ret < 0) { 340 ret = -ENOMEM; 341 goto error_close_dir; 342 } 343 344 sysfsfp = fopen(filename, "r"); 345 if (!sysfsfp) { 346 ret = -errno; 347 free(filename); 348 goto error_close_dir; 349 } 350 351 errno = 0; 352 if (fscanf(sysfsfp, "%i", &ret) != 1) { 353 ret = errno ? -errno : -ENODATA; 354 if (fclose(sysfsfp)) 355 perror("build_channel_array(): Failed to close file"); 356 357 free(filename); 358 goto error_close_dir; 359 } 360 if (ret == 1) 361 (*counter)++; 362 363 if (fclose(sysfsfp)) { 364 ret = -errno; 365 free(filename); 366 goto error_close_dir; 367 } 368 369 free(filename); 370 } 371 372 *ci_array = malloc(sizeof(**ci_array) * (*counter)); 373 if (!*ci_array) { 374 ret = -ENOMEM; 375 goto error_close_dir; 376 } 377 378 seekdir(dp, 0); 379 while (ent = readdir(dp), ent) { 380 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 381 "_en") == 0) { 382 int current_enabled = 0; 383 384 current = &(*ci_array)[count++]; 385 ret = asprintf(&filename, 386 "%s/%s", scan_el_dir, ent->d_name); 387 if (ret < 0) { 388 ret = -ENOMEM; 389 /* decrement count to avoid freeing name */ 390 count--; 391 goto error_cleanup_array; 392 } 393 394 sysfsfp = fopen(filename, "r"); 395 if (!sysfsfp) { 396 ret = -errno; 397 free(filename); 398 count--; 399 goto error_cleanup_array; 400 } 401 402 errno = 0; 403 if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { 404 ret = errno ? -errno : -ENODATA; 405 free(filename); 406 count--; 407 goto error_cleanup_array; 408 } 409 410 if (fclose(sysfsfp)) { 411 ret = -errno; 412 free(filename); 413 count--; 414 goto error_cleanup_array; 415 } 416 417 if (!current_enabled) { 418 free(filename); 419 count--; 420 continue; 421 } 422 423 current->scale = 1.0; 424 current->offset = 0; 425 current->name = strndup(ent->d_name, 426 strlen(ent->d_name) - 427 strlen("_en")); 428 if (!current->name) { 429 free(filename); 430 ret = -ENOMEM; 431 count--; 432 goto error_cleanup_array; 433 } 434 435 /* Get the generic and specific name elements */ 436 ret = iioutils_break_up_name(current->name, 437 ¤t->generic_name); 438 if (ret) { 439 free(filename); 440 free(current->name); 441 count--; 442 goto error_cleanup_array; 443 } 444 445 ret = asprintf(&filename, 446 "%s/%s_index", 447 scan_el_dir, 448 current->name); 449 if (ret < 0) { 450 free(filename); 451 ret = -ENOMEM; 452 goto error_cleanup_array; 453 } 454 455 sysfsfp = fopen(filename, "r"); 456 if (!sysfsfp) { 457 ret = -errno; 458 fprintf(stderr, "failed to open %s\n", 459 filename); 460 free(filename); 461 goto error_cleanup_array; 462 } 463 464 errno = 0; 465 if (fscanf(sysfsfp, "%u", ¤t->index) != 1) { 466 ret = errno ? -errno : -ENODATA; 467 if (fclose(sysfsfp)) 468 perror("build_channel_array(): Failed to close file"); 469 470 free(filename); 471 goto error_cleanup_array; 472 } 473 474 if (fclose(sysfsfp)) { 475 ret = -errno; 476 free(filename); 477 goto error_cleanup_array; 478 } 479 480 free(filename); 481 /* Find the scale */ 482 ret = iioutils_get_param_float(¤t->scale, 483 "scale", 484 device_dir, 485 current->name, 486 current->generic_name); 487 if ((ret < 0) && (ret != -ENOENT)) 488 goto error_cleanup_array; 489 490 ret = iioutils_get_param_float(¤t->offset, 491 "offset", 492 device_dir, 493 current->name, 494 current->generic_name); 495 if ((ret < 0) && (ret != -ENOENT)) 496 goto error_cleanup_array; 497 498 ret = iioutils_get_type(¤t->is_signed, 499 ¤t->bytes, 500 ¤t->bits_used, 501 ¤t->shift, 502 ¤t->mask, 503 ¤t->be, 504 device_dir, 505 current->name, 506 current->generic_name); 507 if (ret < 0) 508 goto error_cleanup_array; 509 } 510 } 511 512 if (closedir(dp) == -1) { 513 ret = -errno; 514 goto error_cleanup_array; 515 } 516 517 free(scan_el_dir); 518 /* reorder so that the array is in index order */ 519 bsort_channel_array_by_index(*ci_array, *counter); 520 521 return 0; 522 523 error_cleanup_array: 524 for (i = count - 1; i >= 0; i--) { 525 free((*ci_array)[i].name); 526 free((*ci_array)[i].generic_name); 527 } 528 free(*ci_array); 529 *ci_array = NULL; 530 *counter = 0; 531 error_close_dir: 532 if (dp) 533 if (closedir(dp) == -1) 534 perror("build_channel_array(): Failed to close dir"); 535 536 error_free_name: 537 free(scan_el_dir); 538 539 return ret; 540 } 541 542 static int calc_digits(int num) 543 { 544 int count = 0; 545 546 while (num != 0) { 547 num /= 10; 548 count++; 549 } 550 551 return count; 552 } 553 554 /** 555 * find_type_by_name() - function to match top level types by name 556 * @name: top level type instance name 557 * @type: the type of top level instance being searched 558 * 559 * Returns the device number of a matched IIO device on success, otherwise a 560 * negative error code. 561 * Typical types this is used for are device and trigger. 562 **/ 563 int find_type_by_name(const char *name, const char *type) 564 { 565 const struct dirent *ent; 566 int number, numstrlen, ret; 567 568 FILE *namefp; 569 DIR *dp; 570 char thisname[IIO_MAX_NAME_LENGTH]; 571 char *filename; 572 573 dp = opendir(iio_dir); 574 if (!dp) { 575 fprintf(stderr, "No industrialio devices available\n"); 576 return -ENODEV; 577 } 578 579 while (ent = readdir(dp), ent) { 580 if (strcmp(ent->d_name, ".") != 0 && 581 strcmp(ent->d_name, "..") != 0 && 582 strlen(ent->d_name) > strlen(type) && 583 strncmp(ent->d_name, type, strlen(type)) == 0) { 584 errno = 0; 585 ret = sscanf(ent->d_name + strlen(type), "%d", &number); 586 if (ret < 0) { 587 ret = -errno; 588 fprintf(stderr, 589 "failed to read element number\n"); 590 goto error_close_dir; 591 } else if (ret != 1) { 592 ret = -EIO; 593 fprintf(stderr, 594 "failed to match element number\n"); 595 goto error_close_dir; 596 } 597 598 numstrlen = calc_digits(number); 599 /* verify the next character is not a colon */ 600 if (strncmp(ent->d_name + strlen(type) + numstrlen, 601 ":", 1) != 0) { 602 filename = malloc(strlen(iio_dir) + strlen(type) 603 + numstrlen + 6); 604 if (!filename) { 605 ret = -ENOMEM; 606 goto error_close_dir; 607 } 608 609 ret = sprintf(filename, "%s%s%d/name", iio_dir, 610 type, number); 611 if (ret < 0) { 612 free(filename); 613 goto error_close_dir; 614 } 615 616 namefp = fopen(filename, "r"); 617 if (!namefp) { 618 free(filename); 619 continue; 620 } 621 622 free(filename); 623 errno = 0; 624 if (fscanf(namefp, "%s", thisname) != 1) { 625 ret = errno ? -errno : -ENODATA; 626 goto error_close_dir; 627 } 628 629 if (fclose(namefp)) { 630 ret = -errno; 631 goto error_close_dir; 632 } 633 634 if (strcmp(name, thisname) == 0) { 635 if (closedir(dp) == -1) 636 return -errno; 637 638 return number; 639 } 640 } 641 } 642 } 643 if (closedir(dp) == -1) 644 return -errno; 645 646 return -ENODEV; 647 648 error_close_dir: 649 if (closedir(dp) == -1) 650 perror("find_type_by_name(): Failed to close directory"); 651 652 return ret; 653 } 654 655 static int _write_sysfs_int(const char *filename, const char *basedir, int val, 656 int verify) 657 { 658 int ret = 0; 659 FILE *sysfsfp; 660 int test; 661 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 662 663 if (!temp) 664 return -ENOMEM; 665 666 ret = sprintf(temp, "%s/%s", basedir, filename); 667 if (ret < 0) 668 goto error_free; 669 670 sysfsfp = fopen(temp, "w"); 671 if (!sysfsfp) { 672 ret = -errno; 673 fprintf(stderr, "failed to open %s\n", temp); 674 goto error_free; 675 } 676 677 ret = fprintf(sysfsfp, "%d", val); 678 if (ret < 0) { 679 if (fclose(sysfsfp)) 680 perror("_write_sysfs_int(): Failed to close dir"); 681 682 goto error_free; 683 } 684 685 if (fclose(sysfsfp)) { 686 ret = -errno; 687 goto error_free; 688 } 689 690 if (verify) { 691 sysfsfp = fopen(temp, "r"); 692 if (!sysfsfp) { 693 ret = -errno; 694 fprintf(stderr, "failed to open %s\n", temp); 695 goto error_free; 696 } 697 698 if (fscanf(sysfsfp, "%d", &test) != 1) { 699 ret = errno ? -errno : -ENODATA; 700 if (fclose(sysfsfp)) 701 perror("_write_sysfs_int(): Failed to close dir"); 702 703 goto error_free; 704 } 705 706 if (fclose(sysfsfp)) { 707 ret = -errno; 708 goto error_free; 709 } 710 711 if (test != val) { 712 fprintf(stderr, 713 "Possible failure in int write %d to %s/%s\n", 714 val, basedir, filename); 715 ret = -1; 716 } 717 } 718 719 error_free: 720 free(temp); 721 return ret; 722 } 723 724 /** 725 * write_sysfs_int() - write an integer value to a sysfs file 726 * @filename: name of the file to write to 727 * @basedir: the sysfs directory in which the file is to be found 728 * @val: integer value to write to file 729 * 730 * Returns a value >= 0 on success, otherwise a negative error code. 731 **/ 732 int write_sysfs_int(const char *filename, const char *basedir, int val) 733 { 734 return _write_sysfs_int(filename, basedir, val, 0); 735 } 736 737 /** 738 * write_sysfs_int_and_verify() - write an integer value to a sysfs file 739 * and verify 740 * @filename: name of the file to write to 741 * @basedir: the sysfs directory in which the file is to be found 742 * @val: integer value to write to file 743 * 744 * Returns a value >= 0 on success, otherwise a negative error code. 745 **/ 746 int write_sysfs_int_and_verify(const char *filename, const char *basedir, 747 int val) 748 { 749 return _write_sysfs_int(filename, basedir, val, 1); 750 } 751 752 static int _write_sysfs_string(const char *filename, const char *basedir, 753 const char *val, int verify) 754 { 755 int ret = 0; 756 FILE *sysfsfp; 757 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 758 759 if (!temp) { 760 fprintf(stderr, "Memory allocation failed\n"); 761 return -ENOMEM; 762 } 763 764 ret = sprintf(temp, "%s/%s", basedir, filename); 765 if (ret < 0) 766 goto error_free; 767 768 sysfsfp = fopen(temp, "w"); 769 if (!sysfsfp) { 770 ret = -errno; 771 fprintf(stderr, "Could not open %s\n", temp); 772 goto error_free; 773 } 774 775 ret = fprintf(sysfsfp, "%s", val); 776 if (ret < 0) { 777 if (fclose(sysfsfp)) 778 perror("_write_sysfs_string(): Failed to close dir"); 779 780 goto error_free; 781 } 782 783 if (fclose(sysfsfp)) { 784 ret = -errno; 785 goto error_free; 786 } 787 788 if (verify) { 789 sysfsfp = fopen(temp, "r"); 790 if (!sysfsfp) { 791 ret = -errno; 792 fprintf(stderr, "Could not open file to verify\n"); 793 goto error_free; 794 } 795 796 if (fscanf(sysfsfp, "%s", temp) != 1) { 797 ret = errno ? -errno : -ENODATA; 798 if (fclose(sysfsfp)) 799 perror("_write_sysfs_string(): Failed to close dir"); 800 801 goto error_free; 802 } 803 804 if (fclose(sysfsfp)) { 805 ret = -errno; 806 goto error_free; 807 } 808 809 if (strcmp(temp, val) != 0) { 810 fprintf(stderr, 811 "Possible failure in string write of %s " 812 "Should be %s written to %s/%s\n", temp, val, 813 basedir, filename); 814 ret = -1; 815 } 816 } 817 818 error_free: 819 free(temp); 820 821 return ret; 822 } 823 824 /** 825 * write_sysfs_string_and_verify() - string write, readback and verify 826 * @filename: name of file to write to 827 * @basedir: the sysfs directory in which the file is to be found 828 * @val: the string to write 829 * 830 * Returns a value >= 0 on success, otherwise a negative error code. 831 **/ 832 int write_sysfs_string_and_verify(const char *filename, const char *basedir, 833 const char *val) 834 { 835 return _write_sysfs_string(filename, basedir, val, 1); 836 } 837 838 /** 839 * write_sysfs_string() - write string to a sysfs file 840 * @filename: name of file to write to 841 * @basedir: the sysfs directory in which the file is to be found 842 * @val: the string to write 843 * 844 * Returns a value >= 0 on success, otherwise a negative error code. 845 **/ 846 int write_sysfs_string(const char *filename, const char *basedir, 847 const char *val) 848 { 849 return _write_sysfs_string(filename, basedir, val, 0); 850 } 851 852 /** 853 * read_sysfs_posint() - read an integer value from file 854 * @filename: name of file to read from 855 * @basedir: the sysfs directory in which the file is to be found 856 * 857 * Returns the read integer value >= 0 on success, otherwise a negative error 858 * code. 859 **/ 860 int read_sysfs_posint(const char *filename, const char *basedir) 861 { 862 int ret; 863 FILE *sysfsfp; 864 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 865 866 if (!temp) { 867 fprintf(stderr, "Memory allocation failed"); 868 return -ENOMEM; 869 } 870 871 ret = sprintf(temp, "%s/%s", basedir, filename); 872 if (ret < 0) 873 goto error_free; 874 875 sysfsfp = fopen(temp, "r"); 876 if (!sysfsfp) { 877 ret = -errno; 878 goto error_free; 879 } 880 881 errno = 0; 882 if (fscanf(sysfsfp, "%d\n", &ret) != 1) { 883 ret = errno ? -errno : -ENODATA; 884 if (fclose(sysfsfp)) 885 perror("read_sysfs_posint(): Failed to close dir"); 886 887 goto error_free; 888 } 889 890 if (fclose(sysfsfp)) 891 ret = -errno; 892 893 error_free: 894 free(temp); 895 896 return ret; 897 } 898 899 /** 900 * read_sysfs_float() - read a float value from file 901 * @filename: name of file to read from 902 * @basedir: the sysfs directory in which the file is to be found 903 * @val: output the read float value 904 * 905 * Returns a value >= 0 on success, otherwise a negative error code. 906 **/ 907 int read_sysfs_float(const char *filename, const char *basedir, float *val) 908 { 909 int ret = 0; 910 FILE *sysfsfp; 911 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 912 913 if (!temp) { 914 fprintf(stderr, "Memory allocation failed"); 915 return -ENOMEM; 916 } 917 918 ret = sprintf(temp, "%s/%s", basedir, filename); 919 if (ret < 0) 920 goto error_free; 921 922 sysfsfp = fopen(temp, "r"); 923 if (!sysfsfp) { 924 ret = -errno; 925 goto error_free; 926 } 927 928 errno = 0; 929 if (fscanf(sysfsfp, "%f\n", val) != 1) { 930 ret = errno ? -errno : -ENODATA; 931 if (fclose(sysfsfp)) 932 perror("read_sysfs_float(): Failed to close dir"); 933 934 goto error_free; 935 } 936 937 if (fclose(sysfsfp)) 938 ret = -errno; 939 940 error_free: 941 free(temp); 942 943 return ret; 944 } 945 946 /** 947 * read_sysfs_string() - read a string from file 948 * @filename: name of file to read from 949 * @basedir: the sysfs directory in which the file is to be found 950 * @str: output the read string 951 * 952 * Returns a value >= 0 on success, otherwise a negative error code. 953 **/ 954 int read_sysfs_string(const char *filename, const char *basedir, char *str) 955 { 956 int ret = 0; 957 FILE *sysfsfp; 958 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 959 960 if (!temp) { 961 fprintf(stderr, "Memory allocation failed"); 962 return -ENOMEM; 963 } 964 965 ret = sprintf(temp, "%s/%s", basedir, filename); 966 if (ret < 0) 967 goto error_free; 968 969 sysfsfp = fopen(temp, "r"); 970 if (!sysfsfp) { 971 ret = -errno; 972 goto error_free; 973 } 974 975 errno = 0; 976 if (fscanf(sysfsfp, "%s\n", str) != 1) { 977 ret = errno ? -errno : -ENODATA; 978 if (fclose(sysfsfp)) 979 perror("read_sysfs_string(): Failed to close dir"); 980 981 goto error_free; 982 } 983 984 if (fclose(sysfsfp)) 985 ret = -errno; 986 987 error_free: 988 free(temp); 989 990 return ret; 991 } 992