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 15const char *iio_dir = "/sys/bus/iio/devices/"; 16 17static 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 **/ 29int 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 **/ 85int 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 183error_close_sysfsfp: 184 if (sysfsfp) 185 if (fclose(sysfsfp)) 186 perror("iioutils_get_type(): Failed to close file"); 187 188error_free_filename: 189 if (filename) 190 free(filename); 191 192error_closedir: 193 if (closedir(dp) == -1) 194 perror("iioutils_get_type(): Failed to close directory"); 195 196error_free_builtname_generic: 197 free(builtname_generic); 198error_free_builtname: 199 free(builtname); 200error_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 **/ 216int 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 fclose(sysfsfp); 266 break; 267 } 268error_free_filename: 269 if (filename) 270 free(filename); 271 272error_closedir: 273 if (closedir(dp) == -1) 274 perror("iioutils_get_param_float(): Failed to close directory"); 275 276error_free_builtname_generic: 277 free(builtname_generic); 278error_free_builtname: 279 free(builtname); 280 281 return ret; 282} 283 284/** 285 * bsort_channel_array_by_index() - sort the array in index order 286 * @ci_array: the iio_channel_info array to be sorted 287 * @cnt: the amount of array elements 288 **/ 289 290void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) 291{ 292 struct iio_channel_info temp; 293 int x, y; 294 295 for (x = 0; x < cnt; x++) 296 for (y = 0; y < (cnt - 1); y++) 297 if (ci_array[y].index > ci_array[y + 1].index) { 298 temp = ci_array[y + 1]; 299 ci_array[y + 1] = ci_array[y]; 300 ci_array[y] = temp; 301 } 302} 303 304/** 305 * build_channel_array() - function to figure out what channels are present 306 * @device_dir: the IIO device directory in sysfs 307 * @ci_array: output the resulting array of iio_channel_info 308 * @counter: output the amount of array elements 309 * 310 * Returns 0 on success, otherwise a negative error code. 311 **/ 312int build_channel_array(const char *device_dir, 313 struct iio_channel_info **ci_array, int *counter) 314{ 315 DIR *dp; 316 FILE *sysfsfp; 317 int count = 0, i; 318 struct iio_channel_info *current; 319 int ret; 320 const struct dirent *ent; 321 char *scan_el_dir; 322 char *filename; 323 324 *counter = 0; 325 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 326 if (ret < 0) 327 return -ENOMEM; 328 329 dp = opendir(scan_el_dir); 330 if (!dp) { 331 ret = -errno; 332 goto error_free_name; 333 } 334 335 while (ent = readdir(dp), ent) 336 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 337 "_en") == 0) { 338 ret = asprintf(&filename, 339 "%s/%s", scan_el_dir, ent->d_name); 340 if (ret < 0) { 341 ret = -ENOMEM; 342 goto error_close_dir; 343 } 344 345 sysfsfp = fopen(filename, "r"); 346 free(filename); 347 if (!sysfsfp) { 348 ret = -errno; 349 goto error_close_dir; 350 } 351 352 errno = 0; 353 if (fscanf(sysfsfp, "%i", &ret) != 1) { 354 ret = errno ? -errno : -ENODATA; 355 if (fclose(sysfsfp)) 356 perror("build_channel_array(): Failed to close file"); 357 358 goto error_close_dir; 359 } 360 if (ret == 1) 361 (*counter)++; 362 363 if (fclose(sysfsfp)) { 364 ret = -errno; 365 goto error_close_dir; 366 } 367 368 } 369 370 *ci_array = malloc(sizeof(**ci_array) * (*counter)); 371 if (!*ci_array) { 372 ret = -ENOMEM; 373 goto error_close_dir; 374 } 375 376 seekdir(dp, 0); 377 while (ent = readdir(dp), ent) { 378 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 379 "_en") == 0) { 380 int current_enabled = 0; 381 382 current = &(*ci_array)[count++]; 383 ret = asprintf(&filename, 384 "%s/%s", scan_el_dir, ent->d_name); 385 if (ret < 0) { 386 ret = -ENOMEM; 387 /* decrement count to avoid freeing name */ 388 count--; 389 goto error_cleanup_array; 390 } 391 392 sysfsfp = fopen(filename, "r"); 393 free(filename); 394 if (!sysfsfp) { 395 ret = -errno; 396 count--; 397 goto error_cleanup_array; 398 } 399 400 errno = 0; 401 if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { 402 ret = errno ? -errno : -ENODATA; 403 count--; 404 goto error_cleanup_array; 405 } 406 407 if (fclose(sysfsfp)) { 408 ret = -errno; 409 count--; 410 goto error_cleanup_array; 411 } 412 413 if (!current_enabled) { 414 count--; 415 continue; 416 } 417 418 current->scale = 1.0; 419 current->offset = 0; 420 current->name = strndup(ent->d_name, 421 strlen(ent->d_name) - 422 strlen("_en")); 423 if (!current->name) { 424 ret = -ENOMEM; 425 count--; 426 goto error_cleanup_array; 427 } 428 429 /* Get the generic and specific name elements */ 430 ret = iioutils_break_up_name(current->name, 431 ¤t->generic_name); 432 if (ret) { 433 free(current->name); 434 count--; 435 goto error_cleanup_array; 436 } 437 438 ret = asprintf(&filename, 439 "%s/%s_index", 440 scan_el_dir, 441 current->name); 442 if (ret < 0) { 443 ret = -ENOMEM; 444 goto error_cleanup_array; 445 } 446 447 sysfsfp = fopen(filename, "r"); 448 free(filename); 449 if (!sysfsfp) { 450 ret = -errno; 451 fprintf(stderr, "failed to open %s/%s_index\n", 452 scan_el_dir, current->name); 453 goto error_cleanup_array; 454 } 455 456 errno = 0; 457 if (fscanf(sysfsfp, "%u", ¤t->index) != 1) { 458 ret = errno ? -errno : -ENODATA; 459 if (fclose(sysfsfp)) 460 perror("build_channel_array(): Failed to close file"); 461 462 goto error_cleanup_array; 463 } 464 465 if (fclose(sysfsfp)) { 466 ret = -errno; 467 goto error_cleanup_array; 468 } 469 470 /* Find the scale */ 471 ret = iioutils_get_param_float(¤t->scale, 472 "scale", 473 device_dir, 474 current->name, 475 current->generic_name); 476 if ((ret < 0) && (ret != -ENOENT)) 477 goto error_cleanup_array; 478 479 ret = iioutils_get_param_float(¤t->offset, 480 "offset", 481 device_dir, 482 current->name, 483 current->generic_name); 484 if ((ret < 0) && (ret != -ENOENT)) 485 goto error_cleanup_array; 486 487 ret = iioutils_get_type(¤t->is_signed, 488 ¤t->bytes, 489 ¤t->bits_used, 490 ¤t->shift, 491 ¤t->mask, 492 ¤t->be, 493 device_dir, 494 current->name, 495 current->generic_name); 496 if (ret < 0) 497 goto error_cleanup_array; 498 } 499 } 500 501 if (closedir(dp) == -1) { 502 ret = -errno; 503 goto error_cleanup_array; 504 } 505 506 free(scan_el_dir); 507 /* reorder so that the array is in index order */ 508 bsort_channel_array_by_index(*ci_array, *counter); 509 510 return 0; 511 512error_cleanup_array: 513 for (i = count - 1; i >= 0; i--) { 514 free((*ci_array)[i].name); 515 free((*ci_array)[i].generic_name); 516 } 517 free(*ci_array); 518 *ci_array = NULL; 519 *counter = 0; 520error_close_dir: 521 if (dp) 522 if (closedir(dp) == -1) 523 perror("build_channel_array(): Failed to close dir"); 524 525error_free_name: 526 free(scan_el_dir); 527 528 return ret; 529} 530 531static int calc_digits(int num) 532{ 533 int count = 0; 534 535 /* It takes a digit to represent zero */ 536 if (!num) 537 return 1; 538 539 while (num != 0) { 540 num /= 10; 541 count++; 542 } 543 544 return count; 545} 546 547/** 548 * find_type_by_name() - function to match top level types by name 549 * @name: top level type instance name 550 * @type: the type of top level instance being searched 551 * 552 * Returns the device number of a matched IIO device on success, otherwise a 553 * negative error code. 554 * Typical types this is used for are device and trigger. 555 **/ 556int find_type_by_name(const char *name, const char *type) 557{ 558 const struct dirent *ent; 559 int number, numstrlen, ret; 560 561 FILE *namefp; 562 DIR *dp; 563 char thisname[IIO_MAX_NAME_LENGTH]; 564 char *filename; 565 566 dp = opendir(iio_dir); 567 if (!dp) { 568 fprintf(stderr, "No industrialio devices available\n"); 569 return -ENODEV; 570 } 571 572 while (ent = readdir(dp), ent) { 573 if (strcmp(ent->d_name, ".") != 0 && 574 strcmp(ent->d_name, "..") != 0 && 575 strlen(ent->d_name) > strlen(type) && 576 strncmp(ent->d_name, type, strlen(type)) == 0) { 577 errno = 0; 578 ret = sscanf(ent->d_name + strlen(type), "%d", &number); 579 if (ret < 0) { 580 ret = -errno; 581 fprintf(stderr, 582 "failed to read element number\n"); 583 goto error_close_dir; 584 } else if (ret != 1) { 585 ret = -EIO; 586 fprintf(stderr, 587 "failed to match element number\n"); 588 goto error_close_dir; 589 } 590 591 numstrlen = calc_digits(number); 592 /* verify the next character is not a colon */ 593 if (strncmp(ent->d_name + strlen(type) + numstrlen, 594 ":", 1) != 0) { 595 filename = malloc(strlen(iio_dir) + strlen(type) 596 + numstrlen + 6); 597 if (!filename) { 598 ret = -ENOMEM; 599 goto error_close_dir; 600 } 601 602 ret = sprintf(filename, "%s%s%d/name", iio_dir, 603 type, number); 604 if (ret < 0) { 605 free(filename); 606 goto error_close_dir; 607 } 608 609 namefp = fopen(filename, "r"); 610 if (!namefp) { 611 free(filename); 612 continue; 613 } 614 615 free(filename); 616 errno = 0; 617 if (fscanf(namefp, "%s", thisname) != 1) { 618 ret = errno ? -errno : -ENODATA; 619 goto error_close_dir; 620 } 621 622 if (fclose(namefp)) { 623 ret = -errno; 624 goto error_close_dir; 625 } 626 627 if (strcmp(name, thisname) == 0) { 628 if (closedir(dp) == -1) 629 return -errno; 630 631 return number; 632 } 633 } 634 } 635 } 636 if (closedir(dp) == -1) 637 return -errno; 638 639 return -ENODEV; 640 641error_close_dir: 642 if (closedir(dp) == -1) 643 perror("find_type_by_name(): Failed to close directory"); 644 645 return ret; 646} 647 648static int _write_sysfs_int(const char *filename, const char *basedir, int val, 649 int verify) 650{ 651 int ret = 0; 652 FILE *sysfsfp; 653 int test; 654 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 655 656 if (!temp) 657 return -ENOMEM; 658 659 ret = sprintf(temp, "%s/%s", basedir, filename); 660 if (ret < 0) 661 goto error_free; 662 663 sysfsfp = fopen(temp, "w"); 664 if (!sysfsfp) { 665 ret = -errno; 666 fprintf(stderr, "failed to open %s\n", temp); 667 goto error_free; 668 } 669 670 ret = fprintf(sysfsfp, "%d", val); 671 if (ret < 0) { 672 if (fclose(sysfsfp)) 673 perror("_write_sysfs_int(): Failed to close dir"); 674 675 goto error_free; 676 } 677 678 if (fclose(sysfsfp)) { 679 ret = -errno; 680 goto error_free; 681 } 682 683 if (verify) { 684 sysfsfp = fopen(temp, "r"); 685 if (!sysfsfp) { 686 ret = -errno; 687 fprintf(stderr, "failed to open %s\n", temp); 688 goto error_free; 689 } 690 691 if (fscanf(sysfsfp, "%d", &test) != 1) { 692 ret = errno ? -errno : -ENODATA; 693 if (fclose(sysfsfp)) 694 perror("_write_sysfs_int(): Failed to close dir"); 695 696 goto error_free; 697 } 698 699 if (fclose(sysfsfp)) { 700 ret = -errno; 701 goto error_free; 702 } 703 704 if (test != val) { 705 fprintf(stderr, 706 "Possible failure in int write %d to %s/%s\n", 707 val, basedir, filename); 708 ret = -1; 709 } 710 } 711 712error_free: 713 free(temp); 714 return ret; 715} 716 717/** 718 * write_sysfs_int() - write an integer value to a sysfs file 719 * @filename: name of the file to write to 720 * @basedir: the sysfs directory in which the file is to be found 721 * @val: integer value to write to file 722 * 723 * Returns a value >= 0 on success, otherwise a negative error code. 724 **/ 725int write_sysfs_int(const char *filename, const char *basedir, int val) 726{ 727 return _write_sysfs_int(filename, basedir, val, 0); 728} 729 730/** 731 * write_sysfs_int_and_verify() - write an integer value to a sysfs file 732 * and verify 733 * @filename: name of the file to write to 734 * @basedir: the sysfs directory in which the file is to be found 735 * @val: integer value to write to file 736 * 737 * Returns a value >= 0 on success, otherwise a negative error code. 738 **/ 739int write_sysfs_int_and_verify(const char *filename, const char *basedir, 740 int val) 741{ 742 return _write_sysfs_int(filename, basedir, val, 1); 743} 744 745static int _write_sysfs_string(const char *filename, const char *basedir, 746 const char *val, int verify) 747{ 748 int ret = 0; 749 FILE *sysfsfp; 750 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 751 752 if (!temp) { 753 fprintf(stderr, "Memory allocation failed\n"); 754 return -ENOMEM; 755 } 756 757 ret = sprintf(temp, "%s/%s", basedir, filename); 758 if (ret < 0) 759 goto error_free; 760 761 sysfsfp = fopen(temp, "w"); 762 if (!sysfsfp) { 763 ret = -errno; 764 fprintf(stderr, "Could not open %s\n", temp); 765 goto error_free; 766 } 767 768 ret = fprintf(sysfsfp, "%s", val); 769 if (ret < 0) { 770 if (fclose(sysfsfp)) 771 perror("_write_sysfs_string(): Failed to close dir"); 772 773 goto error_free; 774 } 775 776 if (fclose(sysfsfp)) { 777 ret = -errno; 778 goto error_free; 779 } 780 781 if (verify) { 782 sysfsfp = fopen(temp, "r"); 783 if (!sysfsfp) { 784 ret = -errno; 785 fprintf(stderr, "Could not open file to verify\n"); 786 goto error_free; 787 } 788 789 if (fscanf(sysfsfp, "%s", temp) != 1) { 790 ret = errno ? -errno : -ENODATA; 791 if (fclose(sysfsfp)) 792 perror("_write_sysfs_string(): Failed to close dir"); 793 794 goto error_free; 795 } 796 797 if (fclose(sysfsfp)) { 798 ret = -errno; 799 goto error_free; 800 } 801 802 if (strcmp(temp, val) != 0) { 803 fprintf(stderr, 804 "Possible failure in string write of %s " 805 "Should be %s written to %s/%s\n", temp, val, 806 basedir, filename); 807 ret = -1; 808 } 809 } 810 811error_free: 812 free(temp); 813 814 return ret; 815} 816 817/** 818 * write_sysfs_string_and_verify() - string write, readback and verify 819 * @filename: name of file to write to 820 * @basedir: the sysfs directory in which the file is to be found 821 * @val: the string to write 822 * 823 * Returns a value >= 0 on success, otherwise a negative error code. 824 **/ 825int write_sysfs_string_and_verify(const char *filename, const char *basedir, 826 const char *val) 827{ 828 return _write_sysfs_string(filename, basedir, val, 1); 829} 830 831/** 832 * write_sysfs_string() - write string to a sysfs file 833 * @filename: name of file to write to 834 * @basedir: the sysfs directory in which the file is to be found 835 * @val: the string to write 836 * 837 * Returns a value >= 0 on success, otherwise a negative error code. 838 **/ 839int write_sysfs_string(const char *filename, const char *basedir, 840 const char *val) 841{ 842 return _write_sysfs_string(filename, basedir, val, 0); 843} 844 845/** 846 * read_sysfs_posint() - read an integer value from file 847 * @filename: name of file to read from 848 * @basedir: the sysfs directory in which the file is to be found 849 * 850 * Returns the read integer value >= 0 on success, otherwise a negative error 851 * code. 852 **/ 853int read_sysfs_posint(const char *filename, const char *basedir) 854{ 855 int ret; 856 FILE *sysfsfp; 857 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 858 859 if (!temp) { 860 fprintf(stderr, "Memory allocation failed"); 861 return -ENOMEM; 862 } 863 864 ret = sprintf(temp, "%s/%s", basedir, filename); 865 if (ret < 0) 866 goto error_free; 867 868 sysfsfp = fopen(temp, "r"); 869 if (!sysfsfp) { 870 ret = -errno; 871 goto error_free; 872 } 873 874 errno = 0; 875 if (fscanf(sysfsfp, "%d\n", &ret) != 1) { 876 ret = errno ? -errno : -ENODATA; 877 if (fclose(sysfsfp)) 878 perror("read_sysfs_posint(): Failed to close dir"); 879 880 goto error_free; 881 } 882 883 if (fclose(sysfsfp)) 884 ret = -errno; 885 886error_free: 887 free(temp); 888 889 return ret; 890} 891 892/** 893 * read_sysfs_float() - read a float value from file 894 * @filename: name of file to read from 895 * @basedir: the sysfs directory in which the file is to be found 896 * @val: output the read float value 897 * 898 * Returns a value >= 0 on success, otherwise a negative error code. 899 **/ 900int read_sysfs_float(const char *filename, const char *basedir, float *val) 901{ 902 int ret = 0; 903 FILE *sysfsfp; 904 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 905 906 if (!temp) { 907 fprintf(stderr, "Memory allocation failed"); 908 return -ENOMEM; 909 } 910 911 ret = sprintf(temp, "%s/%s", basedir, filename); 912 if (ret < 0) 913 goto error_free; 914 915 sysfsfp = fopen(temp, "r"); 916 if (!sysfsfp) { 917 ret = -errno; 918 goto error_free; 919 } 920 921 errno = 0; 922 if (fscanf(sysfsfp, "%f\n", val) != 1) { 923 ret = errno ? -errno : -ENODATA; 924 if (fclose(sysfsfp)) 925 perror("read_sysfs_float(): Failed to close dir"); 926 927 goto error_free; 928 } 929 930 if (fclose(sysfsfp)) 931 ret = -errno; 932 933error_free: 934 free(temp); 935 936 return ret; 937} 938 939/** 940 * read_sysfs_string() - read a string from file 941 * @filename: name of file to read from 942 * @basedir: the sysfs directory in which the file is to be found 943 * @str: output the read string 944 * 945 * Returns a value >= 0 on success, otherwise a negative error code. 946 **/ 947int read_sysfs_string(const char *filename, const char *basedir, char *str) 948{ 949 int ret = 0; 950 FILE *sysfsfp; 951 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 952 953 if (!temp) { 954 fprintf(stderr, "Memory allocation failed"); 955 return -ENOMEM; 956 } 957 958 ret = sprintf(temp, "%s/%s", basedir, filename); 959 if (ret < 0) 960 goto error_free; 961 962 sysfsfp = fopen(temp, "r"); 963 if (!sysfsfp) { 964 ret = -errno; 965 goto error_free; 966 } 967 968 errno = 0; 969 if (fscanf(sysfsfp, "%s\n", str) != 1) { 970 ret = errno ? -errno : -ENODATA; 971 if (fclose(sysfsfp)) 972 perror("read_sysfs_string(): Failed to close dir"); 973 974 goto error_free; 975 } 976 977 if (fclose(sysfsfp)) 978 ret = -errno; 979 980error_free: 981 free(temp); 982 983 return ret; 984} 985