18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* IIO - useful set of util functionality
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2008 Jonathan Cameron
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include <string.h>
78c2ecf20Sopenharmony_ci#include <stdlib.h>
88c2ecf20Sopenharmony_ci#include <stdio.h>
98c2ecf20Sopenharmony_ci#include <stdint.h>
108c2ecf20Sopenharmony_ci#include <dirent.h>
118c2ecf20Sopenharmony_ci#include <errno.h>
128c2ecf20Sopenharmony_ci#include <ctype.h>
138c2ecf20Sopenharmony_ci#include "iio_utils.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciconst char *iio_dir = "/sys/bus/iio/devices/";
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic char * const iio_direction[] = {
188c2ecf20Sopenharmony_ci	"in",
198c2ecf20Sopenharmony_ci	"out",
208c2ecf20Sopenharmony_ci};
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/**
238c2ecf20Sopenharmony_ci * iioutils_break_up_name() - extract generic name from full channel name
248c2ecf20Sopenharmony_ci * @full_name: the full channel name
258c2ecf20Sopenharmony_ci * @generic_name: the output generic channel name
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * Returns 0 on success, or a negative error code if string extraction failed.
288c2ecf20Sopenharmony_ci **/
298c2ecf20Sopenharmony_ciint iioutils_break_up_name(const char *full_name, char **generic_name)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	char *current;
328c2ecf20Sopenharmony_ci	char *w, *r;
338c2ecf20Sopenharmony_ci	char *working, *prefix = "";
348c2ecf20Sopenharmony_ci	int i, ret;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(iio_direction); i++)
378c2ecf20Sopenharmony_ci		if (!strncmp(full_name, iio_direction[i],
388c2ecf20Sopenharmony_ci			     strlen(iio_direction[i]))) {
398c2ecf20Sopenharmony_ci			prefix = iio_direction[i];
408c2ecf20Sopenharmony_ci			break;
418c2ecf20Sopenharmony_ci		}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	current = strdup(full_name + strlen(prefix) + 1);
448c2ecf20Sopenharmony_ci	if (!current)
458c2ecf20Sopenharmony_ci		return -ENOMEM;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	working = strtok(current, "_\0");
488c2ecf20Sopenharmony_ci	if (!working) {
498c2ecf20Sopenharmony_ci		free(current);
508c2ecf20Sopenharmony_ci		return -EINVAL;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	w = working;
548c2ecf20Sopenharmony_ci	r = working;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	while (*r != '\0') {
578c2ecf20Sopenharmony_ci		if (!isdigit(*r)) {
588c2ecf20Sopenharmony_ci			*w = *r;
598c2ecf20Sopenharmony_ci			w++;
608c2ecf20Sopenharmony_ci		}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci		r++;
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci	*w = '\0';
658c2ecf20Sopenharmony_ci	ret = asprintf(generic_name, "%s_%s", prefix, working);
668c2ecf20Sopenharmony_ci	free(current);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return (ret == -1) ? -ENOMEM : 0;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/**
728c2ecf20Sopenharmony_ci * iioutils_get_type() - find and process _type attribute data
738c2ecf20Sopenharmony_ci * @is_signed: output whether channel is signed
748c2ecf20Sopenharmony_ci * @bytes: output how many bytes the channel storage occupies
758c2ecf20Sopenharmony_ci * @bits_used: output number of valid bits of data
768c2ecf20Sopenharmony_ci * @shift: output amount of bits to shift right data before applying bit mask
778c2ecf20Sopenharmony_ci * @mask: output a bit mask for the raw data
788c2ecf20Sopenharmony_ci * @be: output if data in big endian
798c2ecf20Sopenharmony_ci * @device_dir: the IIO device directory
808c2ecf20Sopenharmony_ci * @name: the channel name
818c2ecf20Sopenharmony_ci * @generic_name: the channel type name
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * Returns a value >= 0 on success, otherwise a negative error code.
848c2ecf20Sopenharmony_ci **/
858c2ecf20Sopenharmony_ciint iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
868c2ecf20Sopenharmony_ci		      unsigned *shift, uint64_t *mask, unsigned *be,
878c2ecf20Sopenharmony_ci		      const char *device_dir, const char *name,
888c2ecf20Sopenharmony_ci		      const char *generic_name)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	FILE *sysfsfp;
918c2ecf20Sopenharmony_ci	int ret;
928c2ecf20Sopenharmony_ci	DIR *dp;
938c2ecf20Sopenharmony_ci	char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;
948c2ecf20Sopenharmony_ci	char signchar, endianchar;
958c2ecf20Sopenharmony_ci	unsigned padint;
968c2ecf20Sopenharmony_ci	const struct dirent *ent;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
998c2ecf20Sopenharmony_ci	if (ret < 0)
1008c2ecf20Sopenharmony_ci		return -ENOMEM;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	ret = asprintf(&builtname, FORMAT_TYPE_FILE, name);
1038c2ecf20Sopenharmony_ci	if (ret < 0) {
1048c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1058c2ecf20Sopenharmony_ci		goto error_free_scan_el_dir;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci	ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name);
1088c2ecf20Sopenharmony_ci	if (ret < 0) {
1098c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1108c2ecf20Sopenharmony_ci		goto error_free_builtname;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	dp = opendir(scan_el_dir);
1148c2ecf20Sopenharmony_ci	if (!dp) {
1158c2ecf20Sopenharmony_ci		ret = -errno;
1168c2ecf20Sopenharmony_ci		goto error_free_builtname_generic;
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	ret = -ENOENT;
1208c2ecf20Sopenharmony_ci	while (ent = readdir(dp), ent)
1218c2ecf20Sopenharmony_ci		if ((strcmp(builtname, ent->d_name) == 0) ||
1228c2ecf20Sopenharmony_ci		    (strcmp(builtname_generic, ent->d_name) == 0)) {
1238c2ecf20Sopenharmony_ci			ret = asprintf(&filename,
1248c2ecf20Sopenharmony_ci				       "%s/%s", scan_el_dir, ent->d_name);
1258c2ecf20Sopenharmony_ci			if (ret < 0) {
1268c2ecf20Sopenharmony_ci				ret = -ENOMEM;
1278c2ecf20Sopenharmony_ci				goto error_closedir;
1288c2ecf20Sopenharmony_ci			}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci			sysfsfp = fopen(filename, "r");
1318c2ecf20Sopenharmony_ci			if (!sysfsfp) {
1328c2ecf20Sopenharmony_ci				ret = -errno;
1338c2ecf20Sopenharmony_ci				fprintf(stderr, "failed to open %s\n",
1348c2ecf20Sopenharmony_ci					filename);
1358c2ecf20Sopenharmony_ci				goto error_free_filename;
1368c2ecf20Sopenharmony_ci			}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci			ret = fscanf(sysfsfp,
1398c2ecf20Sopenharmony_ci				     "%ce:%c%u/%u>>%u",
1408c2ecf20Sopenharmony_ci				     &endianchar,
1418c2ecf20Sopenharmony_ci				     &signchar,
1428c2ecf20Sopenharmony_ci				     bits_used,
1438c2ecf20Sopenharmony_ci				     &padint, shift);
1448c2ecf20Sopenharmony_ci			if (ret < 0) {
1458c2ecf20Sopenharmony_ci				ret = -errno;
1468c2ecf20Sopenharmony_ci				fprintf(stderr,
1478c2ecf20Sopenharmony_ci					"failed to pass scan type description\n");
1488c2ecf20Sopenharmony_ci				goto error_close_sysfsfp;
1498c2ecf20Sopenharmony_ci			} else if (ret != 5) {
1508c2ecf20Sopenharmony_ci				ret = -EIO;
1518c2ecf20Sopenharmony_ci				fprintf(stderr,
1528c2ecf20Sopenharmony_ci					"scan type description didn't match\n");
1538c2ecf20Sopenharmony_ci				goto error_close_sysfsfp;
1548c2ecf20Sopenharmony_ci			}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci			*be = (endianchar == 'b');
1578c2ecf20Sopenharmony_ci			*bytes = padint / 8;
1588c2ecf20Sopenharmony_ci			if (*bits_used == 64)
1598c2ecf20Sopenharmony_ci				*mask = ~(0ULL);
1608c2ecf20Sopenharmony_ci			else
1618c2ecf20Sopenharmony_ci				*mask = (1ULL << *bits_used) - 1ULL;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci			*is_signed = (signchar == 's');
1648c2ecf20Sopenharmony_ci			if (fclose(sysfsfp)) {
1658c2ecf20Sopenharmony_ci				ret = -errno;
1668c2ecf20Sopenharmony_ci				fprintf(stderr, "Failed to close %s\n",
1678c2ecf20Sopenharmony_ci					filename);
1688c2ecf20Sopenharmony_ci				goto error_free_filename;
1698c2ecf20Sopenharmony_ci			}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci			sysfsfp = 0;
1728c2ecf20Sopenharmony_ci			free(filename);
1738c2ecf20Sopenharmony_ci			filename = 0;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci			/*
1768c2ecf20Sopenharmony_ci			 * Avoid having a more generic entry overwriting
1778c2ecf20Sopenharmony_ci			 * the settings.
1788c2ecf20Sopenharmony_ci			 */
1798c2ecf20Sopenharmony_ci			if (strcmp(builtname, ent->d_name) == 0)
1808c2ecf20Sopenharmony_ci				break;
1818c2ecf20Sopenharmony_ci		}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cierror_close_sysfsfp:
1848c2ecf20Sopenharmony_ci	if (sysfsfp)
1858c2ecf20Sopenharmony_ci		if (fclose(sysfsfp))
1868c2ecf20Sopenharmony_ci			perror("iioutils_get_type(): Failed to close file");
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cierror_free_filename:
1898c2ecf20Sopenharmony_ci	if (filename)
1908c2ecf20Sopenharmony_ci		free(filename);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cierror_closedir:
1938c2ecf20Sopenharmony_ci	if (closedir(dp) == -1)
1948c2ecf20Sopenharmony_ci		perror("iioutils_get_type(): Failed to close directory");
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cierror_free_builtname_generic:
1978c2ecf20Sopenharmony_ci	free(builtname_generic);
1988c2ecf20Sopenharmony_cierror_free_builtname:
1998c2ecf20Sopenharmony_ci	free(builtname);
2008c2ecf20Sopenharmony_cierror_free_scan_el_dir:
2018c2ecf20Sopenharmony_ci	free(scan_el_dir);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return ret;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/**
2078c2ecf20Sopenharmony_ci * iioutils_get_param_float() - read a float value from a channel parameter
2088c2ecf20Sopenharmony_ci * @output: output the float value
2098c2ecf20Sopenharmony_ci * @param_name: the parameter name to read
2108c2ecf20Sopenharmony_ci * @device_dir: the IIO device directory in sysfs
2118c2ecf20Sopenharmony_ci * @name: the channel name
2128c2ecf20Sopenharmony_ci * @generic_name: the channel type name
2138c2ecf20Sopenharmony_ci *
2148c2ecf20Sopenharmony_ci * Returns a value >= 0 on success, otherwise a negative error code.
2158c2ecf20Sopenharmony_ci **/
2168c2ecf20Sopenharmony_ciint iioutils_get_param_float(float *output, const char *param_name,
2178c2ecf20Sopenharmony_ci			     const char *device_dir, const char *name,
2188c2ecf20Sopenharmony_ci			     const char *generic_name)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	FILE *sysfsfp;
2218c2ecf20Sopenharmony_ci	int ret;
2228c2ecf20Sopenharmony_ci	DIR *dp;
2238c2ecf20Sopenharmony_ci	char *builtname, *builtname_generic;
2248c2ecf20Sopenharmony_ci	char *filename = NULL;
2258c2ecf20Sopenharmony_ci	const struct dirent *ent;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	ret = asprintf(&builtname, "%s_%s", name, param_name);
2288c2ecf20Sopenharmony_ci	if (ret < 0)
2298c2ecf20Sopenharmony_ci		return -ENOMEM;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	ret = asprintf(&builtname_generic,
2328c2ecf20Sopenharmony_ci		       "%s_%s", generic_name, param_name);
2338c2ecf20Sopenharmony_ci	if (ret < 0) {
2348c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2358c2ecf20Sopenharmony_ci		goto error_free_builtname;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	dp = opendir(device_dir);
2398c2ecf20Sopenharmony_ci	if (!dp) {
2408c2ecf20Sopenharmony_ci		ret = -errno;
2418c2ecf20Sopenharmony_ci		goto error_free_builtname_generic;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	ret = -ENOENT;
2458c2ecf20Sopenharmony_ci	while (ent = readdir(dp), ent)
2468c2ecf20Sopenharmony_ci		if ((strcmp(builtname, ent->d_name) == 0) ||
2478c2ecf20Sopenharmony_ci		    (strcmp(builtname_generic, ent->d_name) == 0)) {
2488c2ecf20Sopenharmony_ci			ret = asprintf(&filename,
2498c2ecf20Sopenharmony_ci				       "%s/%s", device_dir, ent->d_name);
2508c2ecf20Sopenharmony_ci			if (ret < 0) {
2518c2ecf20Sopenharmony_ci				ret = -ENOMEM;
2528c2ecf20Sopenharmony_ci				goto error_closedir;
2538c2ecf20Sopenharmony_ci			}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci			sysfsfp = fopen(filename, "r");
2568c2ecf20Sopenharmony_ci			if (!sysfsfp) {
2578c2ecf20Sopenharmony_ci				ret = -errno;
2588c2ecf20Sopenharmony_ci				goto error_free_filename;
2598c2ecf20Sopenharmony_ci			}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci			errno = 0;
2628c2ecf20Sopenharmony_ci			if (fscanf(sysfsfp, "%f", output) != 1)
2638c2ecf20Sopenharmony_ci				ret = errno ? -errno : -ENODATA;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci			fclose(sysfsfp);
2668c2ecf20Sopenharmony_ci			break;
2678c2ecf20Sopenharmony_ci		}
2688c2ecf20Sopenharmony_cierror_free_filename:
2698c2ecf20Sopenharmony_ci	if (filename)
2708c2ecf20Sopenharmony_ci		free(filename);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cierror_closedir:
2738c2ecf20Sopenharmony_ci	if (closedir(dp) == -1)
2748c2ecf20Sopenharmony_ci		perror("iioutils_get_param_float(): Failed to close directory");
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cierror_free_builtname_generic:
2778c2ecf20Sopenharmony_ci	free(builtname_generic);
2788c2ecf20Sopenharmony_cierror_free_builtname:
2798c2ecf20Sopenharmony_ci	free(builtname);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return ret;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci/**
2858c2ecf20Sopenharmony_ci * bsort_channel_array_by_index() - sort the array in index order
2868c2ecf20Sopenharmony_ci * @ci_array: the iio_channel_info array to be sorted
2878c2ecf20Sopenharmony_ci * @cnt: the amount of array elements
2888c2ecf20Sopenharmony_ci **/
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_civoid bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct iio_channel_info temp;
2938c2ecf20Sopenharmony_ci	int x, y;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	for (x = 0; x < cnt; x++)
2968c2ecf20Sopenharmony_ci		for (y = 0; y < (cnt - 1); y++)
2978c2ecf20Sopenharmony_ci			if (ci_array[y].index > ci_array[y + 1].index) {
2988c2ecf20Sopenharmony_ci				temp = ci_array[y + 1];
2998c2ecf20Sopenharmony_ci				ci_array[y + 1] = ci_array[y];
3008c2ecf20Sopenharmony_ci				ci_array[y] = temp;
3018c2ecf20Sopenharmony_ci			}
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci/**
3058c2ecf20Sopenharmony_ci * build_channel_array() - function to figure out what channels are present
3068c2ecf20Sopenharmony_ci * @device_dir: the IIO device directory in sysfs
3078c2ecf20Sopenharmony_ci * @ci_array: output the resulting array of iio_channel_info
3088c2ecf20Sopenharmony_ci * @counter: output the amount of array elements
3098c2ecf20Sopenharmony_ci *
3108c2ecf20Sopenharmony_ci * Returns 0 on success, otherwise a negative error code.
3118c2ecf20Sopenharmony_ci **/
3128c2ecf20Sopenharmony_ciint build_channel_array(const char *device_dir,
3138c2ecf20Sopenharmony_ci			struct iio_channel_info **ci_array, int *counter)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	DIR *dp;
3168c2ecf20Sopenharmony_ci	FILE *sysfsfp;
3178c2ecf20Sopenharmony_ci	int count = 0, i;
3188c2ecf20Sopenharmony_ci	struct iio_channel_info *current;
3198c2ecf20Sopenharmony_ci	int ret;
3208c2ecf20Sopenharmony_ci	const struct dirent *ent;
3218c2ecf20Sopenharmony_ci	char *scan_el_dir;
3228c2ecf20Sopenharmony_ci	char *filename;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	*counter = 0;
3258c2ecf20Sopenharmony_ci	ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
3268c2ecf20Sopenharmony_ci	if (ret < 0)
3278c2ecf20Sopenharmony_ci		return -ENOMEM;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	dp = opendir(scan_el_dir);
3308c2ecf20Sopenharmony_ci	if (!dp) {
3318c2ecf20Sopenharmony_ci		ret = -errno;
3328c2ecf20Sopenharmony_ci		goto error_free_name;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	while (ent = readdir(dp), ent)
3368c2ecf20Sopenharmony_ci		if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
3378c2ecf20Sopenharmony_ci			   "_en") == 0) {
3388c2ecf20Sopenharmony_ci			ret = asprintf(&filename,
3398c2ecf20Sopenharmony_ci				       "%s/%s", scan_el_dir, ent->d_name);
3408c2ecf20Sopenharmony_ci			if (ret < 0) {
3418c2ecf20Sopenharmony_ci				ret = -ENOMEM;
3428c2ecf20Sopenharmony_ci				goto error_close_dir;
3438c2ecf20Sopenharmony_ci			}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci			sysfsfp = fopen(filename, "r");
3468c2ecf20Sopenharmony_ci			free(filename);
3478c2ecf20Sopenharmony_ci			if (!sysfsfp) {
3488c2ecf20Sopenharmony_ci				ret = -errno;
3498c2ecf20Sopenharmony_ci				goto error_close_dir;
3508c2ecf20Sopenharmony_ci			}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci			errno = 0;
3538c2ecf20Sopenharmony_ci			if (fscanf(sysfsfp, "%i", &ret) != 1) {
3548c2ecf20Sopenharmony_ci				ret = errno ? -errno : -ENODATA;
3558c2ecf20Sopenharmony_ci				if (fclose(sysfsfp))
3568c2ecf20Sopenharmony_ci					perror("build_channel_array(): Failed to close file");
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci				goto error_close_dir;
3598c2ecf20Sopenharmony_ci			}
3608c2ecf20Sopenharmony_ci			if (ret == 1)
3618c2ecf20Sopenharmony_ci				(*counter)++;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci			if (fclose(sysfsfp)) {
3648c2ecf20Sopenharmony_ci				ret = -errno;
3658c2ecf20Sopenharmony_ci				goto error_close_dir;
3668c2ecf20Sopenharmony_ci			}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	*ci_array = malloc(sizeof(**ci_array) * (*counter));
3718c2ecf20Sopenharmony_ci	if (!*ci_array) {
3728c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3738c2ecf20Sopenharmony_ci		goto error_close_dir;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	seekdir(dp, 0);
3778c2ecf20Sopenharmony_ci	while (ent = readdir(dp), ent) {
3788c2ecf20Sopenharmony_ci		if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
3798c2ecf20Sopenharmony_ci			   "_en") == 0) {
3808c2ecf20Sopenharmony_ci			int current_enabled = 0;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci			current = &(*ci_array)[count++];
3838c2ecf20Sopenharmony_ci			ret = asprintf(&filename,
3848c2ecf20Sopenharmony_ci				       "%s/%s", scan_el_dir, ent->d_name);
3858c2ecf20Sopenharmony_ci			if (ret < 0) {
3868c2ecf20Sopenharmony_ci				ret = -ENOMEM;
3878c2ecf20Sopenharmony_ci				/* decrement count to avoid freeing name */
3888c2ecf20Sopenharmony_ci				count--;
3898c2ecf20Sopenharmony_ci				goto error_cleanup_array;
3908c2ecf20Sopenharmony_ci			}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci			sysfsfp = fopen(filename, "r");
3938c2ecf20Sopenharmony_ci			free(filename);
3948c2ecf20Sopenharmony_ci			if (!sysfsfp) {
3958c2ecf20Sopenharmony_ci				ret = -errno;
3968c2ecf20Sopenharmony_ci				count--;
3978c2ecf20Sopenharmony_ci				goto error_cleanup_array;
3988c2ecf20Sopenharmony_ci			}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci			errno = 0;
4018c2ecf20Sopenharmony_ci			if (fscanf(sysfsfp, "%i", &current_enabled) != 1) {
4028c2ecf20Sopenharmony_ci				ret = errno ? -errno : -ENODATA;
4038c2ecf20Sopenharmony_ci				count--;
4048c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4058c2ecf20Sopenharmony_ci			}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci			if (fclose(sysfsfp)) {
4088c2ecf20Sopenharmony_ci				ret = -errno;
4098c2ecf20Sopenharmony_ci				count--;
4108c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4118c2ecf20Sopenharmony_ci			}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci			if (!current_enabled) {
4148c2ecf20Sopenharmony_ci				count--;
4158c2ecf20Sopenharmony_ci				continue;
4168c2ecf20Sopenharmony_ci			}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci			current->scale = 1.0;
4198c2ecf20Sopenharmony_ci			current->offset = 0;
4208c2ecf20Sopenharmony_ci			current->name = strndup(ent->d_name,
4218c2ecf20Sopenharmony_ci						strlen(ent->d_name) -
4228c2ecf20Sopenharmony_ci						strlen("_en"));
4238c2ecf20Sopenharmony_ci			if (!current->name) {
4248c2ecf20Sopenharmony_ci				ret = -ENOMEM;
4258c2ecf20Sopenharmony_ci				count--;
4268c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4278c2ecf20Sopenharmony_ci			}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci			/* Get the generic and specific name elements */
4308c2ecf20Sopenharmony_ci			ret = iioutils_break_up_name(current->name,
4318c2ecf20Sopenharmony_ci						     &current->generic_name);
4328c2ecf20Sopenharmony_ci			if (ret) {
4338c2ecf20Sopenharmony_ci				free(current->name);
4348c2ecf20Sopenharmony_ci				count--;
4358c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4368c2ecf20Sopenharmony_ci			}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci			ret = asprintf(&filename,
4398c2ecf20Sopenharmony_ci				       "%s/%s_index",
4408c2ecf20Sopenharmony_ci				       scan_el_dir,
4418c2ecf20Sopenharmony_ci				       current->name);
4428c2ecf20Sopenharmony_ci			if (ret < 0) {
4438c2ecf20Sopenharmony_ci				ret = -ENOMEM;
4448c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4458c2ecf20Sopenharmony_ci			}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci			sysfsfp = fopen(filename, "r");
4488c2ecf20Sopenharmony_ci			free(filename);
4498c2ecf20Sopenharmony_ci			if (!sysfsfp) {
4508c2ecf20Sopenharmony_ci				ret = -errno;
4518c2ecf20Sopenharmony_ci				fprintf(stderr, "failed to open %s/%s_index\n",
4528c2ecf20Sopenharmony_ci					scan_el_dir, current->name);
4538c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4548c2ecf20Sopenharmony_ci			}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci			errno = 0;
4578c2ecf20Sopenharmony_ci			if (fscanf(sysfsfp, "%u", &current->index) != 1) {
4588c2ecf20Sopenharmony_ci				ret = errno ? -errno : -ENODATA;
4598c2ecf20Sopenharmony_ci				if (fclose(sysfsfp))
4608c2ecf20Sopenharmony_ci					perror("build_channel_array(): Failed to close file");
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4638c2ecf20Sopenharmony_ci			}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci			if (fclose(sysfsfp)) {
4668c2ecf20Sopenharmony_ci				ret = -errno;
4678c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4688c2ecf20Sopenharmony_ci			}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci			/* Find the scale */
4718c2ecf20Sopenharmony_ci			ret = iioutils_get_param_float(&current->scale,
4728c2ecf20Sopenharmony_ci						       "scale",
4738c2ecf20Sopenharmony_ci						       device_dir,
4748c2ecf20Sopenharmony_ci						       current->name,
4758c2ecf20Sopenharmony_ci						       current->generic_name);
4768c2ecf20Sopenharmony_ci			if ((ret < 0) && (ret != -ENOENT))
4778c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci			ret = iioutils_get_param_float(&current->offset,
4808c2ecf20Sopenharmony_ci						       "offset",
4818c2ecf20Sopenharmony_ci						       device_dir,
4828c2ecf20Sopenharmony_ci						       current->name,
4838c2ecf20Sopenharmony_ci						       current->generic_name);
4848c2ecf20Sopenharmony_ci			if ((ret < 0) && (ret != -ENOENT))
4858c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci			ret = iioutils_get_type(&current->is_signed,
4888c2ecf20Sopenharmony_ci						&current->bytes,
4898c2ecf20Sopenharmony_ci						&current->bits_used,
4908c2ecf20Sopenharmony_ci						&current->shift,
4918c2ecf20Sopenharmony_ci						&current->mask,
4928c2ecf20Sopenharmony_ci						&current->be,
4938c2ecf20Sopenharmony_ci						device_dir,
4948c2ecf20Sopenharmony_ci						current->name,
4958c2ecf20Sopenharmony_ci						current->generic_name);
4968c2ecf20Sopenharmony_ci			if (ret < 0)
4978c2ecf20Sopenharmony_ci				goto error_cleanup_array;
4988c2ecf20Sopenharmony_ci		}
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (closedir(dp) == -1) {
5028c2ecf20Sopenharmony_ci		ret = -errno;
5038c2ecf20Sopenharmony_ci		goto error_cleanup_array;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	free(scan_el_dir);
5078c2ecf20Sopenharmony_ci	/* reorder so that the array is in index order */
5088c2ecf20Sopenharmony_ci	bsort_channel_array_by_index(*ci_array, *counter);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	return 0;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cierror_cleanup_array:
5138c2ecf20Sopenharmony_ci	for (i = count - 1;  i >= 0; i--) {
5148c2ecf20Sopenharmony_ci		free((*ci_array)[i].name);
5158c2ecf20Sopenharmony_ci		free((*ci_array)[i].generic_name);
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	free(*ci_array);
5188c2ecf20Sopenharmony_ci	*ci_array = NULL;
5198c2ecf20Sopenharmony_ci	*counter = 0;
5208c2ecf20Sopenharmony_cierror_close_dir:
5218c2ecf20Sopenharmony_ci	if (dp)
5228c2ecf20Sopenharmony_ci		if (closedir(dp) == -1)
5238c2ecf20Sopenharmony_ci			perror("build_channel_array(): Failed to close dir");
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cierror_free_name:
5268c2ecf20Sopenharmony_ci	free(scan_el_dir);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	return ret;
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic int calc_digits(int num)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	int count = 0;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* It takes a digit to represent zero */
5368c2ecf20Sopenharmony_ci	if (!num)
5378c2ecf20Sopenharmony_ci		return 1;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	while (num != 0) {
5408c2ecf20Sopenharmony_ci		num /= 10;
5418c2ecf20Sopenharmony_ci		count++;
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	return count;
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci/**
5488c2ecf20Sopenharmony_ci * find_type_by_name() - function to match top level types by name
5498c2ecf20Sopenharmony_ci * @name: top level type instance name
5508c2ecf20Sopenharmony_ci * @type: the type of top level instance being searched
5518c2ecf20Sopenharmony_ci *
5528c2ecf20Sopenharmony_ci * Returns the device number of a matched IIO device on success, otherwise a
5538c2ecf20Sopenharmony_ci * negative error code.
5548c2ecf20Sopenharmony_ci * Typical types this is used for are device and trigger.
5558c2ecf20Sopenharmony_ci **/
5568c2ecf20Sopenharmony_ciint find_type_by_name(const char *name, const char *type)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	const struct dirent *ent;
5598c2ecf20Sopenharmony_ci	int number, numstrlen, ret;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	FILE *namefp;
5628c2ecf20Sopenharmony_ci	DIR *dp;
5638c2ecf20Sopenharmony_ci	char thisname[IIO_MAX_NAME_LENGTH];
5648c2ecf20Sopenharmony_ci	char *filename;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	dp = opendir(iio_dir);
5678c2ecf20Sopenharmony_ci	if (!dp) {
5688c2ecf20Sopenharmony_ci		fprintf(stderr, "No industrialio devices available\n");
5698c2ecf20Sopenharmony_ci		return -ENODEV;
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	while (ent = readdir(dp), ent) {
5738c2ecf20Sopenharmony_ci		if (strcmp(ent->d_name, ".") != 0 &&
5748c2ecf20Sopenharmony_ci		    strcmp(ent->d_name, "..") != 0 &&
5758c2ecf20Sopenharmony_ci		    strlen(ent->d_name) > strlen(type) &&
5768c2ecf20Sopenharmony_ci		    strncmp(ent->d_name, type, strlen(type)) == 0) {
5778c2ecf20Sopenharmony_ci			errno = 0;
5788c2ecf20Sopenharmony_ci			ret = sscanf(ent->d_name + strlen(type), "%d", &number);
5798c2ecf20Sopenharmony_ci			if (ret < 0) {
5808c2ecf20Sopenharmony_ci				ret = -errno;
5818c2ecf20Sopenharmony_ci				fprintf(stderr,
5828c2ecf20Sopenharmony_ci					"failed to read element number\n");
5838c2ecf20Sopenharmony_ci				goto error_close_dir;
5848c2ecf20Sopenharmony_ci			} else if (ret != 1) {
5858c2ecf20Sopenharmony_ci				ret = -EIO;
5868c2ecf20Sopenharmony_ci				fprintf(stderr,
5878c2ecf20Sopenharmony_ci					"failed to match element number\n");
5888c2ecf20Sopenharmony_ci				goto error_close_dir;
5898c2ecf20Sopenharmony_ci			}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci			numstrlen = calc_digits(number);
5928c2ecf20Sopenharmony_ci			/* verify the next character is not a colon */
5938c2ecf20Sopenharmony_ci			if (strncmp(ent->d_name + strlen(type) + numstrlen,
5948c2ecf20Sopenharmony_ci			    ":", 1) != 0) {
5958c2ecf20Sopenharmony_ci				filename = malloc(strlen(iio_dir) + strlen(type)
5968c2ecf20Sopenharmony_ci						  + numstrlen + 6);
5978c2ecf20Sopenharmony_ci				if (!filename) {
5988c2ecf20Sopenharmony_ci					ret = -ENOMEM;
5998c2ecf20Sopenharmony_ci					goto error_close_dir;
6008c2ecf20Sopenharmony_ci				}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci				ret = sprintf(filename, "%s%s%d/name", iio_dir,
6038c2ecf20Sopenharmony_ci					      type, number);
6048c2ecf20Sopenharmony_ci				if (ret < 0) {
6058c2ecf20Sopenharmony_ci					free(filename);
6068c2ecf20Sopenharmony_ci					goto error_close_dir;
6078c2ecf20Sopenharmony_ci				}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci				namefp = fopen(filename, "r");
6108c2ecf20Sopenharmony_ci				if (!namefp) {
6118c2ecf20Sopenharmony_ci					free(filename);
6128c2ecf20Sopenharmony_ci					continue;
6138c2ecf20Sopenharmony_ci				}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci				free(filename);
6168c2ecf20Sopenharmony_ci				errno = 0;
6178c2ecf20Sopenharmony_ci				if (fscanf(namefp, "%s", thisname) != 1) {
6188c2ecf20Sopenharmony_ci					ret = errno ? -errno : -ENODATA;
6198c2ecf20Sopenharmony_ci					goto error_close_dir;
6208c2ecf20Sopenharmony_ci				}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci				if (fclose(namefp)) {
6238c2ecf20Sopenharmony_ci					ret = -errno;
6248c2ecf20Sopenharmony_ci					goto error_close_dir;
6258c2ecf20Sopenharmony_ci				}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci				if (strcmp(name, thisname) == 0) {
6288c2ecf20Sopenharmony_ci					if (closedir(dp) == -1)
6298c2ecf20Sopenharmony_ci						return -errno;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci					return number;
6328c2ecf20Sopenharmony_ci				}
6338c2ecf20Sopenharmony_ci			}
6348c2ecf20Sopenharmony_ci		}
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_ci	if (closedir(dp) == -1)
6378c2ecf20Sopenharmony_ci		return -errno;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	return -ENODEV;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cierror_close_dir:
6428c2ecf20Sopenharmony_ci	if (closedir(dp) == -1)
6438c2ecf20Sopenharmony_ci		perror("find_type_by_name(): Failed to close directory");
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	return ret;
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_cistatic int _write_sysfs_int(const char *filename, const char *basedir, int val,
6498c2ecf20Sopenharmony_ci			    int verify)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	int ret = 0;
6528c2ecf20Sopenharmony_ci	FILE *sysfsfp;
6538c2ecf20Sopenharmony_ci	int test;
6548c2ecf20Sopenharmony_ci	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (!temp)
6578c2ecf20Sopenharmony_ci		return -ENOMEM;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	ret = sprintf(temp, "%s/%s", basedir, filename);
6608c2ecf20Sopenharmony_ci	if (ret < 0)
6618c2ecf20Sopenharmony_ci		goto error_free;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	sysfsfp = fopen(temp, "w");
6648c2ecf20Sopenharmony_ci	if (!sysfsfp) {
6658c2ecf20Sopenharmony_ci		ret = -errno;
6668c2ecf20Sopenharmony_ci		fprintf(stderr, "failed to open %s\n", temp);
6678c2ecf20Sopenharmony_ci		goto error_free;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	ret = fprintf(sysfsfp, "%d", val);
6718c2ecf20Sopenharmony_ci	if (ret < 0) {
6728c2ecf20Sopenharmony_ci		if (fclose(sysfsfp))
6738c2ecf20Sopenharmony_ci			perror("_write_sysfs_int(): Failed to close dir");
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		goto error_free;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if (fclose(sysfsfp)) {
6798c2ecf20Sopenharmony_ci		ret = -errno;
6808c2ecf20Sopenharmony_ci		goto error_free;
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	if (verify) {
6848c2ecf20Sopenharmony_ci		sysfsfp = fopen(temp, "r");
6858c2ecf20Sopenharmony_ci		if (!sysfsfp) {
6868c2ecf20Sopenharmony_ci			ret = -errno;
6878c2ecf20Sopenharmony_ci			fprintf(stderr, "failed to open %s\n", temp);
6888c2ecf20Sopenharmony_ci			goto error_free;
6898c2ecf20Sopenharmony_ci		}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci		if (fscanf(sysfsfp, "%d", &test) != 1) {
6928c2ecf20Sopenharmony_ci			ret = errno ? -errno : -ENODATA;
6938c2ecf20Sopenharmony_ci			if (fclose(sysfsfp))
6948c2ecf20Sopenharmony_ci				perror("_write_sysfs_int(): Failed to close dir");
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci			goto error_free;
6978c2ecf20Sopenharmony_ci		}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci		if (fclose(sysfsfp)) {
7008c2ecf20Sopenharmony_ci			ret = -errno;
7018c2ecf20Sopenharmony_ci			goto error_free;
7028c2ecf20Sopenharmony_ci		}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		if (test != val) {
7058c2ecf20Sopenharmony_ci			fprintf(stderr,
7068c2ecf20Sopenharmony_ci				"Possible failure in int write %d to %s/%s\n",
7078c2ecf20Sopenharmony_ci				val, basedir, filename);
7088c2ecf20Sopenharmony_ci			ret = -1;
7098c2ecf20Sopenharmony_ci		}
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cierror_free:
7138c2ecf20Sopenharmony_ci	free(temp);
7148c2ecf20Sopenharmony_ci	return ret;
7158c2ecf20Sopenharmony_ci}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci/**
7188c2ecf20Sopenharmony_ci * write_sysfs_int() - write an integer value to a sysfs file
7198c2ecf20Sopenharmony_ci * @filename: name of the file to write to
7208c2ecf20Sopenharmony_ci * @basedir: the sysfs directory in which the file is to be found
7218c2ecf20Sopenharmony_ci * @val: integer value to write to file
7228c2ecf20Sopenharmony_ci *
7238c2ecf20Sopenharmony_ci * Returns a value >= 0 on success, otherwise a negative error code.
7248c2ecf20Sopenharmony_ci **/
7258c2ecf20Sopenharmony_ciint write_sysfs_int(const char *filename, const char *basedir, int val)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	return _write_sysfs_int(filename, basedir, val, 0);
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci/**
7318c2ecf20Sopenharmony_ci * write_sysfs_int_and_verify() - write an integer value to a sysfs file
7328c2ecf20Sopenharmony_ci *				  and verify
7338c2ecf20Sopenharmony_ci * @filename: name of the file to write to
7348c2ecf20Sopenharmony_ci * @basedir: the sysfs directory in which the file is to be found
7358c2ecf20Sopenharmony_ci * @val: integer value to write to file
7368c2ecf20Sopenharmony_ci *
7378c2ecf20Sopenharmony_ci * Returns a value >= 0 on success, otherwise a negative error code.
7388c2ecf20Sopenharmony_ci **/
7398c2ecf20Sopenharmony_ciint write_sysfs_int_and_verify(const char *filename, const char *basedir,
7408c2ecf20Sopenharmony_ci			       int val)
7418c2ecf20Sopenharmony_ci{
7428c2ecf20Sopenharmony_ci	return _write_sysfs_int(filename, basedir, val, 1);
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic int _write_sysfs_string(const char *filename, const char *basedir,
7468c2ecf20Sopenharmony_ci			       const char *val, int verify)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	int ret = 0;
7498c2ecf20Sopenharmony_ci	FILE  *sysfsfp;
7508c2ecf20Sopenharmony_ci	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	if (!temp) {
7538c2ecf20Sopenharmony_ci		fprintf(stderr, "Memory allocation failed\n");
7548c2ecf20Sopenharmony_ci		return -ENOMEM;
7558c2ecf20Sopenharmony_ci	}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	ret = sprintf(temp, "%s/%s", basedir, filename);
7588c2ecf20Sopenharmony_ci	if (ret < 0)
7598c2ecf20Sopenharmony_ci		goto error_free;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	sysfsfp = fopen(temp, "w");
7628c2ecf20Sopenharmony_ci	if (!sysfsfp) {
7638c2ecf20Sopenharmony_ci		ret = -errno;
7648c2ecf20Sopenharmony_ci		fprintf(stderr, "Could not open %s\n", temp);
7658c2ecf20Sopenharmony_ci		goto error_free;
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	ret = fprintf(sysfsfp, "%s", val);
7698c2ecf20Sopenharmony_ci	if (ret < 0) {
7708c2ecf20Sopenharmony_ci		if (fclose(sysfsfp))
7718c2ecf20Sopenharmony_ci			perror("_write_sysfs_string(): Failed to close dir");
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci		goto error_free;
7748c2ecf20Sopenharmony_ci	}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	if (fclose(sysfsfp)) {
7778c2ecf20Sopenharmony_ci		ret = -errno;
7788c2ecf20Sopenharmony_ci		goto error_free;
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	if (verify) {
7828c2ecf20Sopenharmony_ci		sysfsfp = fopen(temp, "r");
7838c2ecf20Sopenharmony_ci		if (!sysfsfp) {
7848c2ecf20Sopenharmony_ci			ret = -errno;
7858c2ecf20Sopenharmony_ci			fprintf(stderr, "Could not open file to verify\n");
7868c2ecf20Sopenharmony_ci			goto error_free;
7878c2ecf20Sopenharmony_ci		}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci		if (fscanf(sysfsfp, "%s", temp) != 1) {
7908c2ecf20Sopenharmony_ci			ret = errno ? -errno : -ENODATA;
7918c2ecf20Sopenharmony_ci			if (fclose(sysfsfp))
7928c2ecf20Sopenharmony_ci				perror("_write_sysfs_string(): Failed to close dir");
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci			goto error_free;
7958c2ecf20Sopenharmony_ci		}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		if (fclose(sysfsfp)) {
7988c2ecf20Sopenharmony_ci			ret = -errno;
7998c2ecf20Sopenharmony_ci			goto error_free;
8008c2ecf20Sopenharmony_ci		}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci		if (strcmp(temp, val) != 0) {
8038c2ecf20Sopenharmony_ci			fprintf(stderr,
8048c2ecf20Sopenharmony_ci				"Possible failure in string write of %s "
8058c2ecf20Sopenharmony_ci				"Should be %s written to %s/%s\n", temp, val,
8068c2ecf20Sopenharmony_ci				basedir, filename);
8078c2ecf20Sopenharmony_ci			ret = -1;
8088c2ecf20Sopenharmony_ci		}
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_cierror_free:
8128c2ecf20Sopenharmony_ci	free(temp);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	return ret;
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci/**
8188c2ecf20Sopenharmony_ci * write_sysfs_string_and_verify() - string write, readback and verify
8198c2ecf20Sopenharmony_ci * @filename: name of file to write to
8208c2ecf20Sopenharmony_ci * @basedir: the sysfs directory in which the file is to be found
8218c2ecf20Sopenharmony_ci * @val: the string to write
8228c2ecf20Sopenharmony_ci *
8238c2ecf20Sopenharmony_ci * Returns a value >= 0 on success, otherwise a negative error code.
8248c2ecf20Sopenharmony_ci **/
8258c2ecf20Sopenharmony_ciint write_sysfs_string_and_verify(const char *filename, const char *basedir,
8268c2ecf20Sopenharmony_ci				  const char *val)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	return _write_sysfs_string(filename, basedir, val, 1);
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci/**
8328c2ecf20Sopenharmony_ci * write_sysfs_string() - write string to a sysfs file
8338c2ecf20Sopenharmony_ci * @filename: name of file to write to
8348c2ecf20Sopenharmony_ci * @basedir: the sysfs directory in which the file is to be found
8358c2ecf20Sopenharmony_ci * @val: the string to write
8368c2ecf20Sopenharmony_ci *
8378c2ecf20Sopenharmony_ci * Returns a value >= 0 on success, otherwise a negative error code.
8388c2ecf20Sopenharmony_ci **/
8398c2ecf20Sopenharmony_ciint write_sysfs_string(const char *filename, const char *basedir,
8408c2ecf20Sopenharmony_ci		       const char *val)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	return _write_sysfs_string(filename, basedir, val, 0);
8438c2ecf20Sopenharmony_ci}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci/**
8468c2ecf20Sopenharmony_ci * read_sysfs_posint() - read an integer value from file
8478c2ecf20Sopenharmony_ci * @filename: name of file to read from
8488c2ecf20Sopenharmony_ci * @basedir: the sysfs directory in which the file is to be found
8498c2ecf20Sopenharmony_ci *
8508c2ecf20Sopenharmony_ci * Returns the read integer value >= 0 on success, otherwise a negative error
8518c2ecf20Sopenharmony_ci * code.
8528c2ecf20Sopenharmony_ci **/
8538c2ecf20Sopenharmony_ciint read_sysfs_posint(const char *filename, const char *basedir)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	int ret;
8568c2ecf20Sopenharmony_ci	FILE  *sysfsfp;
8578c2ecf20Sopenharmony_ci	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	if (!temp) {
8608c2ecf20Sopenharmony_ci		fprintf(stderr, "Memory allocation failed");
8618c2ecf20Sopenharmony_ci		return -ENOMEM;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	ret = sprintf(temp, "%s/%s", basedir, filename);
8658c2ecf20Sopenharmony_ci	if (ret < 0)
8668c2ecf20Sopenharmony_ci		goto error_free;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	sysfsfp = fopen(temp, "r");
8698c2ecf20Sopenharmony_ci	if (!sysfsfp) {
8708c2ecf20Sopenharmony_ci		ret = -errno;
8718c2ecf20Sopenharmony_ci		goto error_free;
8728c2ecf20Sopenharmony_ci	}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	errno = 0;
8758c2ecf20Sopenharmony_ci	if (fscanf(sysfsfp, "%d\n", &ret) != 1) {
8768c2ecf20Sopenharmony_ci		ret = errno ? -errno : -ENODATA;
8778c2ecf20Sopenharmony_ci		if (fclose(sysfsfp))
8788c2ecf20Sopenharmony_ci			perror("read_sysfs_posint(): Failed to close dir");
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci		goto error_free;
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	if (fclose(sysfsfp))
8848c2ecf20Sopenharmony_ci		ret = -errno;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cierror_free:
8878c2ecf20Sopenharmony_ci	free(temp);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	return ret;
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci/**
8938c2ecf20Sopenharmony_ci * read_sysfs_float() - read a float value from file
8948c2ecf20Sopenharmony_ci * @filename: name of file to read from
8958c2ecf20Sopenharmony_ci * @basedir: the sysfs directory in which the file is to be found
8968c2ecf20Sopenharmony_ci * @val: output the read float value
8978c2ecf20Sopenharmony_ci *
8988c2ecf20Sopenharmony_ci * Returns a value >= 0 on success, otherwise a negative error code.
8998c2ecf20Sopenharmony_ci **/
9008c2ecf20Sopenharmony_ciint read_sysfs_float(const char *filename, const char *basedir, float *val)
9018c2ecf20Sopenharmony_ci{
9028c2ecf20Sopenharmony_ci	int ret = 0;
9038c2ecf20Sopenharmony_ci	FILE  *sysfsfp;
9048c2ecf20Sopenharmony_ci	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	if (!temp) {
9078c2ecf20Sopenharmony_ci		fprintf(stderr, "Memory allocation failed");
9088c2ecf20Sopenharmony_ci		return -ENOMEM;
9098c2ecf20Sopenharmony_ci	}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	ret = sprintf(temp, "%s/%s", basedir, filename);
9128c2ecf20Sopenharmony_ci	if (ret < 0)
9138c2ecf20Sopenharmony_ci		goto error_free;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	sysfsfp = fopen(temp, "r");
9168c2ecf20Sopenharmony_ci	if (!sysfsfp) {
9178c2ecf20Sopenharmony_ci		ret = -errno;
9188c2ecf20Sopenharmony_ci		goto error_free;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	errno = 0;
9228c2ecf20Sopenharmony_ci	if (fscanf(sysfsfp, "%f\n", val) != 1) {
9238c2ecf20Sopenharmony_ci		ret = errno ? -errno : -ENODATA;
9248c2ecf20Sopenharmony_ci		if (fclose(sysfsfp))
9258c2ecf20Sopenharmony_ci			perror("read_sysfs_float(): Failed to close dir");
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci		goto error_free;
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	if (fclose(sysfsfp))
9318c2ecf20Sopenharmony_ci		ret = -errno;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_cierror_free:
9348c2ecf20Sopenharmony_ci	free(temp);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	return ret;
9378c2ecf20Sopenharmony_ci}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci/**
9408c2ecf20Sopenharmony_ci * read_sysfs_string() - read a string from file
9418c2ecf20Sopenharmony_ci * @filename: name of file to read from
9428c2ecf20Sopenharmony_ci * @basedir: the sysfs directory in which the file is to be found
9438c2ecf20Sopenharmony_ci * @str: output the read string
9448c2ecf20Sopenharmony_ci *
9458c2ecf20Sopenharmony_ci * Returns a value >= 0 on success, otherwise a negative error code.
9468c2ecf20Sopenharmony_ci **/
9478c2ecf20Sopenharmony_ciint read_sysfs_string(const char *filename, const char *basedir, char *str)
9488c2ecf20Sopenharmony_ci{
9498c2ecf20Sopenharmony_ci	int ret = 0;
9508c2ecf20Sopenharmony_ci	FILE  *sysfsfp;
9518c2ecf20Sopenharmony_ci	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	if (!temp) {
9548c2ecf20Sopenharmony_ci		fprintf(stderr, "Memory allocation failed");
9558c2ecf20Sopenharmony_ci		return -ENOMEM;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	ret = sprintf(temp, "%s/%s", basedir, filename);
9598c2ecf20Sopenharmony_ci	if (ret < 0)
9608c2ecf20Sopenharmony_ci		goto error_free;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	sysfsfp = fopen(temp, "r");
9638c2ecf20Sopenharmony_ci	if (!sysfsfp) {
9648c2ecf20Sopenharmony_ci		ret = -errno;
9658c2ecf20Sopenharmony_ci		goto error_free;
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	errno = 0;
9698c2ecf20Sopenharmony_ci	if (fscanf(sysfsfp, "%s\n", str) != 1) {
9708c2ecf20Sopenharmony_ci		ret = errno ? -errno : -ENODATA;
9718c2ecf20Sopenharmony_ci		if (fclose(sysfsfp))
9728c2ecf20Sopenharmony_ci			perror("read_sysfs_string(): Failed to close dir");
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci		goto error_free;
9758c2ecf20Sopenharmony_ci	}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	if (fclose(sysfsfp))
9788c2ecf20Sopenharmony_ci		ret = -errno;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_cierror_free:
9818c2ecf20Sopenharmony_ci	free(temp);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	return ret;
9848c2ecf20Sopenharmony_ci}
985