cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

iio_utils.c (21933B)


      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}