Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* IIO - useful set of util functionality
0003  *
0004  * Copyright (c) 2008 Jonathan Cameron
0005  */
0006 #include <string.h>
0007 #include <stdlib.h>
0008 #include <stdio.h>
0009 #include <stdint.h>
0010 #include <dirent.h>
0011 #include <errno.h>
0012 #include <ctype.h>
0013 #include "iio_utils.h"
0014 
0015 const char *iio_dir = "/sys/bus/iio/devices/";
0016 
0017 static char * const iio_direction[] = {
0018     "in",
0019     "out",
0020 };
0021 
0022 /**
0023  * iioutils_break_up_name() - extract generic name from full channel name
0024  * @full_name: the full channel name
0025  * @generic_name: the output generic channel name
0026  *
0027  * Returns 0 on success, or a negative error code if string extraction failed.
0028  **/
0029 int iioutils_break_up_name(const char *full_name, char **generic_name)
0030 {
0031     char *current;
0032     char *w, *r;
0033     char *working, *prefix = "";
0034     int i, ret;
0035 
0036     for (i = 0; i < ARRAY_SIZE(iio_direction); i++)
0037         if (!strncmp(full_name, iio_direction[i],
0038                  strlen(iio_direction[i]))) {
0039             prefix = iio_direction[i];
0040             break;
0041         }
0042 
0043     current = strdup(full_name + strlen(prefix) + 1);
0044     if (!current)
0045         return -ENOMEM;
0046 
0047     working = strtok(current, "_\0");
0048     if (!working) {
0049         free(current);
0050         return -EINVAL;
0051     }
0052 
0053     w = working;
0054     r = working;
0055 
0056     while (*r != '\0') {
0057         if (!isdigit(*r)) {
0058             *w = *r;
0059             w++;
0060         }
0061 
0062         r++;
0063     }
0064     *w = '\0';
0065     ret = asprintf(generic_name, "%s_%s", prefix, working);
0066     free(current);
0067 
0068     return (ret == -1) ? -ENOMEM : 0;
0069 }
0070 
0071 /**
0072  * iioutils_get_type() - find and process _type attribute data
0073  * @is_signed: output whether channel is signed
0074  * @bytes: output how many bytes the channel storage occupies
0075  * @bits_used: output number of valid bits of data
0076  * @shift: output amount of bits to shift right data before applying bit mask
0077  * @mask: output a bit mask for the raw data
0078  * @be: output if data in big endian
0079  * @device_dir: the IIO device directory
0080  * @buffer_idx: the IIO buffer index
0081  * @name: the channel name
0082  * @generic_name: the channel type name
0083  *
0084  * Returns a value >= 0 on success, otherwise a negative error code.
0085  **/
0086 static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes,
0087                  unsigned int *bits_used, unsigned int *shift,
0088                  uint64_t *mask, unsigned int *be,
0089                  const char *device_dir, int buffer_idx,
0090                  const char *name, const char *generic_name)
0091 {
0092     FILE *sysfsfp;
0093     int ret;
0094     DIR *dp;
0095     char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;
0096     char signchar, endianchar;
0097     unsigned padint;
0098     const struct dirent *ent;
0099 
0100     ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx);
0101     if (ret < 0)
0102         return -ENOMEM;
0103 
0104     ret = asprintf(&builtname, FORMAT_TYPE_FILE, name);
0105     if (ret < 0) {
0106         ret = -ENOMEM;
0107         goto error_free_scan_el_dir;
0108     }
0109     ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name);
0110     if (ret < 0) {
0111         ret = -ENOMEM;
0112         goto error_free_builtname;
0113     }
0114 
0115     dp = opendir(scan_el_dir);
0116     if (!dp) {
0117         ret = -errno;
0118         goto error_free_builtname_generic;
0119     }
0120 
0121     ret = -ENOENT;
0122     while (ent = readdir(dp), ent)
0123         if ((strcmp(builtname, ent->d_name) == 0) ||
0124             (strcmp(builtname_generic, ent->d_name) == 0)) {
0125             ret = asprintf(&filename,
0126                        "%s/%s", scan_el_dir, ent->d_name);
0127             if (ret < 0) {
0128                 ret = -ENOMEM;
0129                 goto error_closedir;
0130             }
0131 
0132             sysfsfp = fopen(filename, "r");
0133             if (!sysfsfp) {
0134                 ret = -errno;
0135                 fprintf(stderr, "failed to open %s\n",
0136                     filename);
0137                 goto error_free_filename;
0138             }
0139 
0140             ret = fscanf(sysfsfp,
0141                      "%ce:%c%u/%u>>%u",
0142                      &endianchar,
0143                      &signchar,
0144                      bits_used,
0145                      &padint, shift);
0146             if (ret < 0) {
0147                 ret = -errno;
0148                 fprintf(stderr,
0149                     "failed to pass scan type description\n");
0150                 goto error_close_sysfsfp;
0151             } else if (ret != 5) {
0152                 ret = -EIO;
0153                 fprintf(stderr,
0154                     "scan type description didn't match\n");
0155                 goto error_close_sysfsfp;
0156             }
0157 
0158             *be = (endianchar == 'b');
0159             *bytes = padint / 8;
0160             if (*bits_used == 64)
0161                 *mask = ~(0ULL);
0162             else
0163                 *mask = (1ULL << *bits_used) - 1ULL;
0164 
0165             *is_signed = (signchar == 's');
0166             if (fclose(sysfsfp)) {
0167                 ret = -errno;
0168                 fprintf(stderr, "Failed to close %s\n",
0169                     filename);
0170                 goto error_free_filename;
0171             }
0172 
0173             sysfsfp = 0;
0174             free(filename);
0175             filename = 0;
0176 
0177             /*
0178              * Avoid having a more generic entry overwriting
0179              * the settings.
0180              */
0181             if (strcmp(builtname, ent->d_name) == 0)
0182                 break;
0183         }
0184 
0185 error_close_sysfsfp:
0186     if (sysfsfp)
0187         if (fclose(sysfsfp))
0188             perror("iioutils_get_type(): Failed to close file");
0189 
0190 error_free_filename:
0191     if (filename)
0192         free(filename);
0193 
0194 error_closedir:
0195     if (closedir(dp) == -1)
0196         perror("iioutils_get_type(): Failed to close directory");
0197 
0198 error_free_builtname_generic:
0199     free(builtname_generic);
0200 error_free_builtname:
0201     free(builtname);
0202 error_free_scan_el_dir:
0203     free(scan_el_dir);
0204 
0205     return ret;
0206 }
0207 
0208 /**
0209  * iioutils_get_param_float() - read a float value from a channel parameter
0210  * @output: output the float value
0211  * @param_name: the parameter name to read
0212  * @device_dir: the IIO device directory in sysfs
0213  * @name: the channel name
0214  * @generic_name: the channel type name
0215  *
0216  * Returns a value >= 0 on success, otherwise a negative error code.
0217  **/
0218 int iioutils_get_param_float(float *output, const char *param_name,
0219                  const char *device_dir, const char *name,
0220                  const char *generic_name)
0221 {
0222     FILE *sysfsfp;
0223     int ret;
0224     DIR *dp;
0225     char *builtname, *builtname_generic;
0226     char *filename = NULL;
0227     const struct dirent *ent;
0228 
0229     ret = asprintf(&builtname, "%s_%s", name, param_name);
0230     if (ret < 0)
0231         return -ENOMEM;
0232 
0233     ret = asprintf(&builtname_generic,
0234                "%s_%s", generic_name, param_name);
0235     if (ret < 0) {
0236         ret = -ENOMEM;
0237         goto error_free_builtname;
0238     }
0239 
0240     dp = opendir(device_dir);
0241     if (!dp) {
0242         ret = -errno;
0243         goto error_free_builtname_generic;
0244     }
0245 
0246     ret = -ENOENT;
0247     while (ent = readdir(dp), ent)
0248         if ((strcmp(builtname, ent->d_name) == 0) ||
0249             (strcmp(builtname_generic, ent->d_name) == 0)) {
0250             ret = asprintf(&filename,
0251                        "%s/%s", device_dir, ent->d_name);
0252             if (ret < 0) {
0253                 ret = -ENOMEM;
0254                 goto error_closedir;
0255             }
0256 
0257             sysfsfp = fopen(filename, "r");
0258             if (!sysfsfp) {
0259                 ret = -errno;
0260                 goto error_free_filename;
0261             }
0262 
0263             errno = 0;
0264             if (fscanf(sysfsfp, "%f", output) != 1)
0265                 ret = errno ? -errno : -ENODATA;
0266 
0267             break;
0268         }
0269 error_free_filename:
0270     if (filename)
0271         free(filename);
0272 
0273 error_closedir:
0274     if (closedir(dp) == -1)
0275         perror("iioutils_get_param_float(): Failed to close directory");
0276 
0277 error_free_builtname_generic:
0278     free(builtname_generic);
0279 error_free_builtname:
0280     free(builtname);
0281 
0282     return ret;
0283 }
0284 
0285 /**
0286  * bsort_channel_array_by_index() - sort the array in index order
0287  * @ci_array: the iio_channel_info array to be sorted
0288  * @cnt: the amount of array elements
0289  **/
0290 
0291 void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt)
0292 {
0293     struct iio_channel_info temp;
0294     int x, y;
0295 
0296     for (x = 0; x < cnt; x++)
0297         for (y = 0; y < (cnt - 1); y++)
0298             if (ci_array[y].index > ci_array[y + 1].index) {
0299                 temp = ci_array[y + 1];
0300                 ci_array[y + 1] = ci_array[y];
0301                 ci_array[y] = temp;
0302             }
0303 }
0304 
0305 /**
0306  * build_channel_array() - function to figure out what channels are present
0307  * @device_dir: the IIO device directory in sysfs
0308  * @buffer_idx: the IIO buffer for this channel array
0309  * @ci_array: output the resulting array of iio_channel_info
0310  * @counter: output the amount of array elements
0311  *
0312  * Returns 0 on success, otherwise a negative error code.
0313  **/
0314 int build_channel_array(const char *device_dir, int buffer_idx,
0315             struct iio_channel_info **ci_array, int *counter)
0316 {
0317     DIR *dp;
0318     FILE *sysfsfp;
0319     int count = 0, i;
0320     struct iio_channel_info *current;
0321     int ret;
0322     const struct dirent *ent;
0323     char *scan_el_dir;
0324     char *filename;
0325 
0326     *counter = 0;
0327     ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx);
0328     if (ret < 0)
0329         return -ENOMEM;
0330 
0331     dp = opendir(scan_el_dir);
0332     if (!dp) {
0333         ret = -errno;
0334         goto error_free_name;
0335     }
0336 
0337     while (ent = readdir(dp), ent)
0338         if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
0339                "_en") == 0) {
0340             ret = asprintf(&filename,
0341                        "%s/%s", scan_el_dir, ent->d_name);
0342             if (ret < 0) {
0343                 ret = -ENOMEM;
0344                 goto error_close_dir;
0345             }
0346 
0347             sysfsfp = fopen(filename, "r");
0348             if (!sysfsfp) {
0349                 ret = -errno;
0350                 free(filename);
0351                 goto error_close_dir;
0352             }
0353 
0354             errno = 0;
0355             if (fscanf(sysfsfp, "%i", &ret) != 1) {
0356                 ret = errno ? -errno : -ENODATA;
0357                 if (fclose(sysfsfp))
0358                     perror("build_channel_array(): Failed to close file");
0359 
0360                 free(filename);
0361                 goto error_close_dir;
0362             }
0363             if (ret == 1)
0364                 (*counter)++;
0365 
0366             if (fclose(sysfsfp)) {
0367                 ret = -errno;
0368                 free(filename);
0369                 goto error_close_dir;
0370             }
0371 
0372             free(filename);
0373         }
0374 
0375     *ci_array = malloc(sizeof(**ci_array) * (*counter));
0376     if (!*ci_array) {
0377         ret = -ENOMEM;
0378         goto error_close_dir;
0379     }
0380 
0381     seekdir(dp, 0);
0382     while (ent = readdir(dp), ent) {
0383         if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
0384                "_en") == 0) {
0385             int current_enabled = 0;
0386 
0387             current = &(*ci_array)[count++];
0388             ret = asprintf(&filename,
0389                        "%s/%s", scan_el_dir, ent->d_name);
0390             if (ret < 0) {
0391                 ret = -ENOMEM;
0392                 /* decrement count to avoid freeing name */
0393                 count--;
0394                 goto error_cleanup_array;
0395             }
0396 
0397             sysfsfp = fopen(filename, "r");
0398             if (!sysfsfp) {
0399                 ret = -errno;
0400                 free(filename);
0401                 count--;
0402                 goto error_cleanup_array;
0403             }
0404 
0405             errno = 0;
0406             if (fscanf(sysfsfp, "%i", &current_enabled) != 1) {
0407                 ret = errno ? -errno : -ENODATA;
0408                 free(filename);
0409                 count--;
0410                 goto error_cleanup_array;
0411             }
0412 
0413             if (fclose(sysfsfp)) {
0414                 ret = -errno;
0415                 free(filename);
0416                 count--;
0417                 goto error_cleanup_array;
0418             }
0419 
0420             if (!current_enabled) {
0421                 free(filename);
0422                 count--;
0423                 continue;
0424             }
0425 
0426             current->scale = 1.0;
0427             current->offset = 0;
0428             current->name = strndup(ent->d_name,
0429                         strlen(ent->d_name) -
0430                         strlen("_en"));
0431             if (!current->name) {
0432                 free(filename);
0433                 ret = -ENOMEM;
0434                 count--;
0435                 goto error_cleanup_array;
0436             }
0437 
0438             /* Get the generic and specific name elements */
0439             ret = iioutils_break_up_name(current->name,
0440                              &current->generic_name);
0441             if (ret) {
0442                 free(filename);
0443                 free(current->name);
0444                 count--;
0445                 goto error_cleanup_array;
0446             }
0447 
0448             ret = asprintf(&filename,
0449                        "%s/%s_index",
0450                        scan_el_dir,
0451                        current->name);
0452             if (ret < 0) {
0453                 free(filename);
0454                 ret = -ENOMEM;
0455                 goto error_cleanup_array;
0456             }
0457 
0458             sysfsfp = fopen(filename, "r");
0459             if (!sysfsfp) {
0460                 ret = -errno;
0461                 fprintf(stderr, "failed to open %s\n",
0462                     filename);
0463                 free(filename);
0464                 goto error_cleanup_array;
0465             }
0466 
0467             errno = 0;
0468             if (fscanf(sysfsfp, "%u", &current->index) != 1) {
0469                 ret = errno ? -errno : -ENODATA;
0470                 if (fclose(sysfsfp))
0471                     perror("build_channel_array(): Failed to close file");
0472 
0473                 free(filename);
0474                 goto error_cleanup_array;
0475             }
0476 
0477             if (fclose(sysfsfp)) {
0478                 ret = -errno;
0479                 free(filename);
0480                 goto error_cleanup_array;
0481             }
0482 
0483             free(filename);
0484             /* Find the scale */
0485             ret = iioutils_get_param_float(&current->scale,
0486                                "scale",
0487                                device_dir,
0488                                current->name,
0489                                current->generic_name);
0490             if ((ret < 0) && (ret != -ENOENT))
0491                 goto error_cleanup_array;
0492 
0493             ret = iioutils_get_param_float(&current->offset,
0494                                "offset",
0495                                device_dir,
0496                                current->name,
0497                                current->generic_name);
0498             if ((ret < 0) && (ret != -ENOENT))
0499                 goto error_cleanup_array;
0500 
0501             ret = iioutils_get_type(&current->is_signed,
0502                         &current->bytes,
0503                         &current->bits_used,
0504                         &current->shift,
0505                         &current->mask,
0506                         &current->be,
0507                         device_dir,
0508                         buffer_idx,
0509                         current->name,
0510                         current->generic_name);
0511             if (ret < 0)
0512                 goto error_cleanup_array;
0513         }
0514     }
0515 
0516     if (closedir(dp) == -1) {
0517         ret = -errno;
0518         goto error_cleanup_array;
0519     }
0520 
0521     free(scan_el_dir);
0522     /* reorder so that the array is in index order */
0523     bsort_channel_array_by_index(*ci_array, *counter);
0524 
0525     return 0;
0526 
0527 error_cleanup_array:
0528     for (i = count - 1;  i >= 0; i--) {
0529         free((*ci_array)[i].name);
0530         free((*ci_array)[i].generic_name);
0531     }
0532     free(*ci_array);
0533     *ci_array = NULL;
0534     *counter = 0;
0535 error_close_dir:
0536     if (dp)
0537         if (closedir(dp) == -1)
0538             perror("build_channel_array(): Failed to close dir");
0539 
0540 error_free_name:
0541     free(scan_el_dir);
0542 
0543     return ret;
0544 }
0545 
0546 static int calc_digits(int num)
0547 {
0548     int count = 0;
0549 
0550     while (num != 0) {
0551         num /= 10;
0552         count++;
0553     }
0554 
0555     return count;
0556 }
0557 
0558 /**
0559  * find_type_by_name() - function to match top level types by name
0560  * @name: top level type instance name
0561  * @type: the type of top level instance being searched
0562  *
0563  * Returns the device number of a matched IIO device on success, otherwise a
0564  * negative error code.
0565  * Typical types this is used for are device and trigger.
0566  **/
0567 int find_type_by_name(const char *name, const char *type)
0568 {
0569     const struct dirent *ent;
0570     int number, numstrlen, ret;
0571 
0572     FILE *namefp;
0573     DIR *dp;
0574     char thisname[IIO_MAX_NAME_LENGTH];
0575     char *filename;
0576 
0577     dp = opendir(iio_dir);
0578     if (!dp) {
0579         fprintf(stderr, "No industrialio devices available\n");
0580         return -ENODEV;
0581     }
0582 
0583     while (ent = readdir(dp), ent) {
0584         if (strcmp(ent->d_name, ".") != 0 &&
0585             strcmp(ent->d_name, "..") != 0 &&
0586             strlen(ent->d_name) > strlen(type) &&
0587             strncmp(ent->d_name, type, strlen(type)) == 0) {
0588             errno = 0;
0589             ret = sscanf(ent->d_name + strlen(type), "%d", &number);
0590             if (ret < 0) {
0591                 ret = -errno;
0592                 fprintf(stderr,
0593                     "failed to read element number\n");
0594                 goto error_close_dir;
0595             } else if (ret != 1) {
0596                 ret = -EIO;
0597                 fprintf(stderr,
0598                     "failed to match element number\n");
0599                 goto error_close_dir;
0600             }
0601 
0602             numstrlen = calc_digits(number);
0603             /* verify the next character is not a colon */
0604             if (strncmp(ent->d_name + strlen(type) + numstrlen,
0605                 ":", 1) != 0) {
0606                 filename = malloc(strlen(iio_dir) + strlen(type)
0607                           + numstrlen + 6);
0608                 if (!filename) {
0609                     ret = -ENOMEM;
0610                     goto error_close_dir;
0611                 }
0612 
0613                 ret = sprintf(filename, "%s%s%d/name", iio_dir,
0614                           type, number);
0615                 if (ret < 0) {
0616                     free(filename);
0617                     goto error_close_dir;
0618                 }
0619 
0620                 namefp = fopen(filename, "r");
0621                 if (!namefp) {
0622                     free(filename);
0623                     continue;
0624                 }
0625 
0626                 free(filename);
0627                 errno = 0;
0628                 if (fscanf(namefp, "%s", thisname) != 1) {
0629                     ret = errno ? -errno : -ENODATA;
0630                     goto error_close_dir;
0631                 }
0632 
0633                 if (fclose(namefp)) {
0634                     ret = -errno;
0635                     goto error_close_dir;
0636                 }
0637 
0638                 if (strcmp(name, thisname) == 0) {
0639                     if (closedir(dp) == -1)
0640                         return -errno;
0641 
0642                     return number;
0643                 }
0644             }
0645         }
0646     }
0647     if (closedir(dp) == -1)
0648         return -errno;
0649 
0650     return -ENODEV;
0651 
0652 error_close_dir:
0653     if (closedir(dp) == -1)
0654         perror("find_type_by_name(): Failed to close directory");
0655 
0656     return ret;
0657 }
0658 
0659 static int _write_sysfs_int(const char *filename, const char *basedir, int val,
0660                 int verify)
0661 {
0662     int ret = 0;
0663     FILE *sysfsfp;
0664     int test;
0665     char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
0666 
0667     if (!temp)
0668         return -ENOMEM;
0669 
0670     ret = sprintf(temp, "%s/%s", basedir, filename);
0671     if (ret < 0)
0672         goto error_free;
0673 
0674     sysfsfp = fopen(temp, "w");
0675     if (!sysfsfp) {
0676         ret = -errno;
0677         fprintf(stderr, "failed to open %s\n", temp);
0678         goto error_free;
0679     }
0680 
0681     ret = fprintf(sysfsfp, "%d", val);
0682     if (ret < 0) {
0683         if (fclose(sysfsfp))
0684             perror("_write_sysfs_int(): Failed to close dir");
0685 
0686         goto error_free;
0687     }
0688 
0689     if (fclose(sysfsfp)) {
0690         ret = -errno;
0691         goto error_free;
0692     }
0693 
0694     if (verify) {
0695         sysfsfp = fopen(temp, "r");
0696         if (!sysfsfp) {
0697             ret = -errno;
0698             fprintf(stderr, "failed to open %s\n", temp);
0699             goto error_free;
0700         }
0701 
0702         if (fscanf(sysfsfp, "%d", &test) != 1) {
0703             ret = errno ? -errno : -ENODATA;
0704             if (fclose(sysfsfp))
0705                 perror("_write_sysfs_int(): Failed to close dir");
0706 
0707             goto error_free;
0708         }
0709 
0710         if (fclose(sysfsfp)) {
0711             ret = -errno;
0712             goto error_free;
0713         }
0714 
0715         if (test != val) {
0716             fprintf(stderr,
0717                 "Possible failure in int write %d to %s/%s\n",
0718                 val, basedir, filename);
0719             ret = -1;
0720         }
0721     }
0722 
0723 error_free:
0724     free(temp);
0725     return ret;
0726 }
0727 
0728 /**
0729  * write_sysfs_int() - write an integer value to a sysfs file
0730  * @filename: name of the file to write to
0731  * @basedir: the sysfs directory in which the file is to be found
0732  * @val: integer value to write to file
0733  *
0734  * Returns a value >= 0 on success, otherwise a negative error code.
0735  **/
0736 int write_sysfs_int(const char *filename, const char *basedir, int val)
0737 {
0738     return _write_sysfs_int(filename, basedir, val, 0);
0739 }
0740 
0741 /**
0742  * write_sysfs_int_and_verify() - write an integer value to a sysfs file
0743  *                and verify
0744  * @filename: name of the file to write to
0745  * @basedir: the sysfs directory in which the file is to be found
0746  * @val: integer value to write to file
0747  *
0748  * Returns a value >= 0 on success, otherwise a negative error code.
0749  **/
0750 int write_sysfs_int_and_verify(const char *filename, const char *basedir,
0751                    int val)
0752 {
0753     return _write_sysfs_int(filename, basedir, val, 1);
0754 }
0755 
0756 static int _write_sysfs_string(const char *filename, const char *basedir,
0757                    const char *val, int verify)
0758 {
0759     int ret = 0;
0760     FILE  *sysfsfp;
0761     char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
0762 
0763     if (!temp) {
0764         fprintf(stderr, "Memory allocation failed\n");
0765         return -ENOMEM;
0766     }
0767 
0768     ret = sprintf(temp, "%s/%s", basedir, filename);
0769     if (ret < 0)
0770         goto error_free;
0771 
0772     sysfsfp = fopen(temp, "w");
0773     if (!sysfsfp) {
0774         ret = -errno;
0775         fprintf(stderr, "Could not open %s\n", temp);
0776         goto error_free;
0777     }
0778 
0779     ret = fprintf(sysfsfp, "%s", val);
0780     if (ret < 0) {
0781         if (fclose(sysfsfp))
0782             perror("_write_sysfs_string(): Failed to close dir");
0783 
0784         goto error_free;
0785     }
0786 
0787     if (fclose(sysfsfp)) {
0788         ret = -errno;
0789         goto error_free;
0790     }
0791 
0792     if (verify) {
0793         sysfsfp = fopen(temp, "r");
0794         if (!sysfsfp) {
0795             ret = -errno;
0796             fprintf(stderr, "Could not open file to verify\n");
0797             goto error_free;
0798         }
0799 
0800         if (fscanf(sysfsfp, "%s", temp) != 1) {
0801             ret = errno ? -errno : -ENODATA;
0802             if (fclose(sysfsfp))
0803                 perror("_write_sysfs_string(): Failed to close dir");
0804 
0805             goto error_free;
0806         }
0807 
0808         if (fclose(sysfsfp)) {
0809             ret = -errno;
0810             goto error_free;
0811         }
0812 
0813         if (strcmp(temp, val) != 0) {
0814             fprintf(stderr,
0815                 "Possible failure in string write of %s "
0816                 "Should be %s written to %s/%s\n", temp, val,
0817                 basedir, filename);
0818             ret = -1;
0819         }
0820     }
0821 
0822 error_free:
0823     free(temp);
0824 
0825     return ret;
0826 }
0827 
0828 /**
0829  * write_sysfs_string_and_verify() - string write, readback and verify
0830  * @filename: name of file to write to
0831  * @basedir: the sysfs directory in which the file is to be found
0832  * @val: the string to write
0833  *
0834  * Returns a value >= 0 on success, otherwise a negative error code.
0835  **/
0836 int write_sysfs_string_and_verify(const char *filename, const char *basedir,
0837                   const char *val)
0838 {
0839     return _write_sysfs_string(filename, basedir, val, 1);
0840 }
0841 
0842 /**
0843  * write_sysfs_string() - write string to a sysfs file
0844  * @filename: name of file to write to
0845  * @basedir: the sysfs directory in which the file is to be found
0846  * @val: the string to write
0847  *
0848  * Returns a value >= 0 on success, otherwise a negative error code.
0849  **/
0850 int write_sysfs_string(const char *filename, const char *basedir,
0851                const char *val)
0852 {
0853     return _write_sysfs_string(filename, basedir, val, 0);
0854 }
0855 
0856 /**
0857  * read_sysfs_posint() - read an integer value from file
0858  * @filename: name of file to read from
0859  * @basedir: the sysfs directory in which the file is to be found
0860  *
0861  * Returns the read integer value >= 0 on success, otherwise a negative error
0862  * code.
0863  **/
0864 int read_sysfs_posint(const char *filename, const char *basedir)
0865 {
0866     int ret;
0867     FILE  *sysfsfp;
0868     char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
0869 
0870     if (!temp) {
0871         fprintf(stderr, "Memory allocation failed");
0872         return -ENOMEM;
0873     }
0874 
0875     ret = sprintf(temp, "%s/%s", basedir, filename);
0876     if (ret < 0)
0877         goto error_free;
0878 
0879     sysfsfp = fopen(temp, "r");
0880     if (!sysfsfp) {
0881         ret = -errno;
0882         goto error_free;
0883     }
0884 
0885     errno = 0;
0886     if (fscanf(sysfsfp, "%d\n", &ret) != 1) {
0887         ret = errno ? -errno : -ENODATA;
0888         if (fclose(sysfsfp))
0889             perror("read_sysfs_posint(): Failed to close dir");
0890 
0891         goto error_free;
0892     }
0893 
0894     if (fclose(sysfsfp))
0895         ret = -errno;
0896 
0897 error_free:
0898     free(temp);
0899 
0900     return ret;
0901 }
0902 
0903 /**
0904  * read_sysfs_float() - read a float value from file
0905  * @filename: name of file to read from
0906  * @basedir: the sysfs directory in which the file is to be found
0907  * @val: output the read float value
0908  *
0909  * Returns a value >= 0 on success, otherwise a negative error code.
0910  **/
0911 int read_sysfs_float(const char *filename, const char *basedir, float *val)
0912 {
0913     int ret = 0;
0914     FILE  *sysfsfp;
0915     char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
0916 
0917     if (!temp) {
0918         fprintf(stderr, "Memory allocation failed");
0919         return -ENOMEM;
0920     }
0921 
0922     ret = sprintf(temp, "%s/%s", basedir, filename);
0923     if (ret < 0)
0924         goto error_free;
0925 
0926     sysfsfp = fopen(temp, "r");
0927     if (!sysfsfp) {
0928         ret = -errno;
0929         goto error_free;
0930     }
0931 
0932     errno = 0;
0933     if (fscanf(sysfsfp, "%f\n", val) != 1) {
0934         ret = errno ? -errno : -ENODATA;
0935         if (fclose(sysfsfp))
0936             perror("read_sysfs_float(): Failed to close dir");
0937 
0938         goto error_free;
0939     }
0940 
0941     if (fclose(sysfsfp))
0942         ret = -errno;
0943 
0944 error_free:
0945     free(temp);
0946 
0947     return ret;
0948 }
0949 
0950 /**
0951  * read_sysfs_string() - read a string from file
0952  * @filename: name of file to read from
0953  * @basedir: the sysfs directory in which the file is to be found
0954  * @str: output the read string
0955  *
0956  * Returns a value >= 0 on success, otherwise a negative error code.
0957  **/
0958 int read_sysfs_string(const char *filename, const char *basedir, char *str)
0959 {
0960     int ret = 0;
0961     FILE  *sysfsfp;
0962     char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
0963 
0964     if (!temp) {
0965         fprintf(stderr, "Memory allocation failed");
0966         return -ENOMEM;
0967     }
0968 
0969     ret = sprintf(temp, "%s/%s", basedir, filename);
0970     if (ret < 0)
0971         goto error_free;
0972 
0973     sysfsfp = fopen(temp, "r");
0974     if (!sysfsfp) {
0975         ret = -errno;
0976         goto error_free;
0977     }
0978 
0979     errno = 0;
0980     if (fscanf(sysfsfp, "%s\n", str) != 1) {
0981         ret = errno ? -errno : -ENODATA;
0982         if (fclose(sysfsfp))
0983             perror("read_sysfs_string(): Failed to close dir");
0984 
0985         goto error_free;
0986     }
0987 
0988     if (fclose(sysfsfp))
0989         ret = -errno;
0990 
0991 error_free:
0992     free(temp);
0993 
0994     return ret;
0995 }