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