xref: /openbmc/linux/tools/iio/iio_utils.c (revision 1e952e95843d437b8a904dbd5b48d72db8ac23ec)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2817020cfSRoberta Dobrescu /* IIO - useful set of util functionality
3817020cfSRoberta Dobrescu  *
4817020cfSRoberta Dobrescu  * Copyright (c) 2008 Jonathan Cameron
5817020cfSRoberta Dobrescu  */
6817020cfSRoberta Dobrescu #include <string.h>
7817020cfSRoberta Dobrescu #include <stdlib.h>
8817020cfSRoberta Dobrescu #include <stdio.h>
9817020cfSRoberta Dobrescu #include <stdint.h>
10817020cfSRoberta Dobrescu #include <dirent.h>
11817020cfSRoberta Dobrescu #include <errno.h>
12817020cfSRoberta Dobrescu #include <ctype.h>
13817020cfSRoberta Dobrescu #include "iio_utils.h"
14817020cfSRoberta Dobrescu 
15817020cfSRoberta Dobrescu const char *iio_dir = "/sys/bus/iio/devices/";
16817020cfSRoberta Dobrescu 
17d9d7b990SIrina Tirdea static char * const iio_direction[] = {
18d9d7b990SIrina Tirdea 	"in",
19d9d7b990SIrina Tirdea 	"out",
20d9d7b990SIrina Tirdea };
21d9d7b990SIrina Tirdea 
22817020cfSRoberta Dobrescu /**
23817020cfSRoberta Dobrescu  * iioutils_break_up_name() - extract generic name from full channel name
24817020cfSRoberta Dobrescu  * @full_name: the full channel name
25817020cfSRoberta Dobrescu  * @generic_name: the output generic channel name
265dc65d79SHartmut Knaack  *
275dc65d79SHartmut Knaack  * Returns 0 on success, or a negative error code if string extraction failed.
28817020cfSRoberta Dobrescu  **/
iioutils_break_up_name(const char * full_name,char ** generic_name)297663a4aaSHartmut Knaack int iioutils_break_up_name(const char *full_name, char **generic_name)
30817020cfSRoberta Dobrescu {
31817020cfSRoberta Dobrescu 	char *current;
32817020cfSRoberta Dobrescu 	char *w, *r;
33d9d7b990SIrina Tirdea 	char *working, *prefix = "";
34e9e45b43SHartmut Knaack 	int i, ret;
35817020cfSRoberta Dobrescu 
3634cbea19SCristina Opriceana 	for (i = 0; i < ARRAY_SIZE(iio_direction); i++)
37d9d7b990SIrina Tirdea 		if (!strncmp(full_name, iio_direction[i],
38d9d7b990SIrina Tirdea 			     strlen(iio_direction[i]))) {
39d9d7b990SIrina Tirdea 			prefix = iio_direction[i];
40d9d7b990SIrina Tirdea 			break;
41d9d7b990SIrina Tirdea 		}
42d9d7b990SIrina Tirdea 
43d9d7b990SIrina Tirdea 	current = strdup(full_name + strlen(prefix) + 1);
44e9e45b43SHartmut Knaack 	if (!current)
45e9e45b43SHartmut Knaack 		return -ENOMEM;
46e9e45b43SHartmut Knaack 
47817020cfSRoberta Dobrescu 	working = strtok(current, "_\0");
4853118557SHartmut Knaack 	if (!working) {
4953118557SHartmut Knaack 		free(current);
5053118557SHartmut Knaack 		return -EINVAL;
5153118557SHartmut Knaack 	}
52d9d7b990SIrina Tirdea 
53817020cfSRoberta Dobrescu 	w = working;
54817020cfSRoberta Dobrescu 	r = working;
55817020cfSRoberta Dobrescu 
56817020cfSRoberta Dobrescu 	while (*r != '\0') {
57817020cfSRoberta Dobrescu 		if (!isdigit(*r)) {
58817020cfSRoberta Dobrescu 			*w = *r;
59817020cfSRoberta Dobrescu 			w++;
60817020cfSRoberta Dobrescu 		}
617663a4aaSHartmut Knaack 
62817020cfSRoberta Dobrescu 		r++;
63817020cfSRoberta Dobrescu 	}
64817020cfSRoberta Dobrescu 	*w = '\0';
65e9e45b43SHartmut Knaack 	ret = asprintf(generic_name, "%s_%s", prefix, working);
66817020cfSRoberta Dobrescu 	free(current);
67817020cfSRoberta Dobrescu 
68e9e45b43SHartmut Knaack 	return (ret == -1) ? -ENOMEM : 0;
69817020cfSRoberta Dobrescu }
70817020cfSRoberta Dobrescu 
71817020cfSRoberta Dobrescu /**
72817020cfSRoberta Dobrescu  * iioutils_get_type() - find and process _type attribute data
73817020cfSRoberta Dobrescu  * @is_signed: output whether channel is signed
74817020cfSRoberta Dobrescu  * @bytes: output how many bytes the channel storage occupies
755dc65d79SHartmut Knaack  * @bits_used: output number of valid bits of data
765dc65d79SHartmut Knaack  * @shift: output amount of bits to shift right data before applying bit mask
77817020cfSRoberta Dobrescu  * @mask: output a bit mask for the raw data
785dc65d79SHartmut Knaack  * @be: output if data in big endian
795dc65d79SHartmut Knaack  * @device_dir: the IIO device directory
808827faabSAlexandru Ardelean  * @buffer_idx: the IIO buffer index
81817020cfSRoberta Dobrescu  * @name: the channel name
82817020cfSRoberta Dobrescu  * @generic_name: the channel type name
835dc65d79SHartmut Knaack  *
845dc65d79SHartmut Knaack  * Returns a value >= 0 on success, otherwise a negative error code.
85817020cfSRoberta Dobrescu  **/
iioutils_get_type(unsigned int * is_signed,unsigned int * bytes,unsigned int * bits_used,unsigned int * shift,uint64_t * mask,unsigned int * be,const char * device_dir,int buffer_idx,const char * name,const char * generic_name)86a605c8f4SAlexandru Ardelean static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes,
87a605c8f4SAlexandru Ardelean 			     unsigned int *bits_used, unsigned int *shift,
88a605c8f4SAlexandru Ardelean 			     uint64_t *mask, unsigned int *be,
898827faabSAlexandru Ardelean 			     const char *device_dir, int buffer_idx,
908827faabSAlexandru Ardelean 			     const char *name, const char *generic_name)
91817020cfSRoberta Dobrescu {
92817020cfSRoberta Dobrescu 	FILE *sysfsfp;
93817020cfSRoberta Dobrescu 	int ret;
94817020cfSRoberta Dobrescu 	DIR *dp;
95817020cfSRoberta Dobrescu 	char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;
96817020cfSRoberta Dobrescu 	char signchar, endianchar;
97817020cfSRoberta Dobrescu 	unsigned padint;
98817020cfSRoberta Dobrescu 	const struct dirent *ent;
99817020cfSRoberta Dobrescu 
1008827faabSAlexandru Ardelean 	ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx);
1010e799878SHartmut Knaack 	if (ret < 0)
1020e799878SHartmut Knaack 		return -ENOMEM;
1030e799878SHartmut Knaack 
104817020cfSRoberta Dobrescu 	ret = asprintf(&builtname, FORMAT_TYPE_FILE, name);
105817020cfSRoberta Dobrescu 	if (ret < 0) {
106817020cfSRoberta Dobrescu 		ret = -ENOMEM;
107817020cfSRoberta Dobrescu 		goto error_free_scan_el_dir;
108817020cfSRoberta Dobrescu 	}
109817020cfSRoberta Dobrescu 	ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name);
110817020cfSRoberta Dobrescu 	if (ret < 0) {
111817020cfSRoberta Dobrescu 		ret = -ENOMEM;
112817020cfSRoberta Dobrescu 		goto error_free_builtname;
113817020cfSRoberta Dobrescu 	}
114817020cfSRoberta Dobrescu 
115817020cfSRoberta Dobrescu 	dp = opendir(scan_el_dir);
116ff1ac639SCristina Opriceana 	if (!dp) {
117817020cfSRoberta Dobrescu 		ret = -errno;
118817020cfSRoberta Dobrescu 		goto error_free_builtname_generic;
119817020cfSRoberta Dobrescu 	}
1207663a4aaSHartmut Knaack 
12153118557SHartmut Knaack 	ret = -ENOENT;
122ff1ac639SCristina Opriceana 	while (ent = readdir(dp), ent)
123817020cfSRoberta Dobrescu 		if ((strcmp(builtname, ent->d_name) == 0) ||
124817020cfSRoberta Dobrescu 		    (strcmp(builtname_generic, ent->d_name) == 0)) {
125817020cfSRoberta Dobrescu 			ret = asprintf(&filename,
126817020cfSRoberta Dobrescu 				       "%s/%s", scan_el_dir, ent->d_name);
127817020cfSRoberta Dobrescu 			if (ret < 0) {
128817020cfSRoberta Dobrescu 				ret = -ENOMEM;
129817020cfSRoberta Dobrescu 				goto error_closedir;
130817020cfSRoberta Dobrescu 			}
1317663a4aaSHartmut Knaack 
132817020cfSRoberta Dobrescu 			sysfsfp = fopen(filename, "r");
133ff1ac639SCristina Opriceana 			if (!sysfsfp) {
134817020cfSRoberta Dobrescu 				ret = -errno;
135d9abc615SCristina Opriceana 				fprintf(stderr, "failed to open %s\n",
136d9abc615SCristina Opriceana 					filename);
137817020cfSRoberta Dobrescu 				goto error_free_filename;
138817020cfSRoberta Dobrescu 			}
139817020cfSRoberta Dobrescu 
140817020cfSRoberta Dobrescu 			ret = fscanf(sysfsfp,
141817020cfSRoberta Dobrescu 				     "%ce:%c%u/%u>>%u",
142817020cfSRoberta Dobrescu 				     &endianchar,
143817020cfSRoberta Dobrescu 				     &signchar,
144817020cfSRoberta Dobrescu 				     bits_used,
145817020cfSRoberta Dobrescu 				     &padint, shift);
146817020cfSRoberta Dobrescu 			if (ret < 0) {
147817020cfSRoberta Dobrescu 				ret = -errno;
148d9abc615SCristina Opriceana 				fprintf(stderr,
149d9abc615SCristina Opriceana 					"failed to pass scan type description\n");
150817020cfSRoberta Dobrescu 				goto error_close_sysfsfp;
151dc8b5d6eSHartmut Knaack 			} else if (ret != 5) {
152dc8b5d6eSHartmut Knaack 				ret = -EIO;
153d9abc615SCristina Opriceana 				fprintf(stderr,
154d9abc615SCristina Opriceana 					"scan type description didn't match\n");
155dc8b5d6eSHartmut Knaack 				goto error_close_sysfsfp;
156817020cfSRoberta Dobrescu 			}
1577663a4aaSHartmut Knaack 
158817020cfSRoberta Dobrescu 			*be = (endianchar == 'b');
159817020cfSRoberta Dobrescu 			*bytes = padint / 8;
160817020cfSRoberta Dobrescu 			if (*bits_used == 64)
161208a68c8SBastien Nocera 				*mask = ~(0ULL);
162817020cfSRoberta Dobrescu 			else
163208a68c8SBastien Nocera 				*mask = (1ULL << *bits_used) - 1ULL;
1647663a4aaSHartmut Knaack 
16533ebcb21SHartmut Knaack 			*is_signed = (signchar == 's');
16653118557SHartmut Knaack 			if (fclose(sysfsfp)) {
16753118557SHartmut Knaack 				ret = -errno;
168d9abc615SCristina Opriceana 				fprintf(stderr, "Failed to close %s\n",
169d9abc615SCristina Opriceana 					filename);
17053118557SHartmut Knaack 				goto error_free_filename;
17153118557SHartmut Knaack 			}
17253118557SHartmut Knaack 
173ace76e42SHartmut Knaack 			sysfsfp = 0;
174817020cfSRoberta Dobrescu 			free(filename);
175817020cfSRoberta Dobrescu 			filename = 0;
1766356f1b9SMatt Ranostay 
1776356f1b9SMatt Ranostay 			/*
1786356f1b9SMatt Ranostay 			 * Avoid having a more generic entry overwriting
1796356f1b9SMatt Ranostay 			 * the settings.
1806356f1b9SMatt Ranostay 			 */
1816356f1b9SMatt Ranostay 			if (strcmp(builtname, ent->d_name) == 0)
1826356f1b9SMatt Ranostay 				break;
183817020cfSRoberta Dobrescu 		}
1847663a4aaSHartmut Knaack 
185817020cfSRoberta Dobrescu error_close_sysfsfp:
186817020cfSRoberta Dobrescu 	if (sysfsfp)
18753118557SHartmut Knaack 		if (fclose(sysfsfp))
18853118557SHartmut Knaack 			perror("iioutils_get_type(): Failed to close file");
18953118557SHartmut Knaack 
190817020cfSRoberta Dobrescu error_free_filename:
191817020cfSRoberta Dobrescu 	if (filename)
192817020cfSRoberta Dobrescu 		free(filename);
1937663a4aaSHartmut Knaack 
194817020cfSRoberta Dobrescu error_closedir:
19553118557SHartmut Knaack 	if (closedir(dp) == -1)
19653118557SHartmut Knaack 		perror("iioutils_get_type(): Failed to close directory");
19753118557SHartmut Knaack 
198817020cfSRoberta Dobrescu error_free_builtname_generic:
199817020cfSRoberta Dobrescu 	free(builtname_generic);
200817020cfSRoberta Dobrescu error_free_builtname:
201817020cfSRoberta Dobrescu 	free(builtname);
202817020cfSRoberta Dobrescu error_free_scan_el_dir:
203817020cfSRoberta Dobrescu 	free(scan_el_dir);
2040e799878SHartmut Knaack 
205817020cfSRoberta Dobrescu 	return ret;
206817020cfSRoberta Dobrescu }
207817020cfSRoberta Dobrescu 
2085dc65d79SHartmut Knaack /**
2095dc65d79SHartmut Knaack  * iioutils_get_param_float() - read a float value from a channel parameter
2105dc65d79SHartmut Knaack  * @output: output the float value
2115dc65d79SHartmut Knaack  * @param_name: the parameter name to read
2125dc65d79SHartmut Knaack  * @device_dir: the IIO device directory in sysfs
2135dc65d79SHartmut Knaack  * @name: the channel name
2145dc65d79SHartmut Knaack  * @generic_name: the channel type name
2155dc65d79SHartmut Knaack  *
2165dc65d79SHartmut Knaack  * Returns a value >= 0 on success, otherwise a negative error code.
2175dc65d79SHartmut Knaack  **/
iioutils_get_param_float(float * output,const char * param_name,const char * device_dir,const char * name,const char * generic_name)2187663a4aaSHartmut Knaack int iioutils_get_param_float(float *output, const char *param_name,
2197663a4aaSHartmut Knaack 			     const char *device_dir, const char *name,
220817020cfSRoberta Dobrescu 			     const char *generic_name)
221817020cfSRoberta Dobrescu {
222817020cfSRoberta Dobrescu 	FILE *sysfsfp;
223817020cfSRoberta Dobrescu 	int ret;
224817020cfSRoberta Dobrescu 	DIR *dp;
225817020cfSRoberta Dobrescu 	char *builtname, *builtname_generic;
226817020cfSRoberta Dobrescu 	char *filename = NULL;
227817020cfSRoberta Dobrescu 	const struct dirent *ent;
228817020cfSRoberta Dobrescu 
229817020cfSRoberta Dobrescu 	ret = asprintf(&builtname, "%s_%s", name, param_name);
2300e799878SHartmut Knaack 	if (ret < 0)
2310e799878SHartmut Knaack 		return -ENOMEM;
2320e799878SHartmut Knaack 
233817020cfSRoberta Dobrescu 	ret = asprintf(&builtname_generic,
234817020cfSRoberta Dobrescu 		       "%s_%s", generic_name, param_name);
235817020cfSRoberta Dobrescu 	if (ret < 0) {
236817020cfSRoberta Dobrescu 		ret = -ENOMEM;
237817020cfSRoberta Dobrescu 		goto error_free_builtname;
238817020cfSRoberta Dobrescu 	}
2397663a4aaSHartmut Knaack 
240817020cfSRoberta Dobrescu 	dp = opendir(device_dir);
241ff1ac639SCristina Opriceana 	if (!dp) {
242817020cfSRoberta Dobrescu 		ret = -errno;
243817020cfSRoberta Dobrescu 		goto error_free_builtname_generic;
244817020cfSRoberta Dobrescu 	}
2457663a4aaSHartmut Knaack 
24653118557SHartmut Knaack 	ret = -ENOENT;
247ff1ac639SCristina Opriceana 	while (ent = readdir(dp), ent)
248817020cfSRoberta Dobrescu 		if ((strcmp(builtname, ent->d_name) == 0) ||
249817020cfSRoberta Dobrescu 		    (strcmp(builtname_generic, ent->d_name) == 0)) {
250817020cfSRoberta Dobrescu 			ret = asprintf(&filename,
251817020cfSRoberta Dobrescu 				       "%s/%s", device_dir, ent->d_name);
252817020cfSRoberta Dobrescu 			if (ret < 0) {
253817020cfSRoberta Dobrescu 				ret = -ENOMEM;
254817020cfSRoberta Dobrescu 				goto error_closedir;
255817020cfSRoberta Dobrescu 			}
2567663a4aaSHartmut Knaack 
257817020cfSRoberta Dobrescu 			sysfsfp = fopen(filename, "r");
258817020cfSRoberta Dobrescu 			if (!sysfsfp) {
259817020cfSRoberta Dobrescu 				ret = -errno;
260817020cfSRoberta Dobrescu 				goto error_free_filename;
261817020cfSRoberta Dobrescu 			}
2627663a4aaSHartmut Knaack 
26353118557SHartmut Knaack 			errno = 0;
26453118557SHartmut Knaack 			if (fscanf(sysfsfp, "%f", output) != 1)
26553118557SHartmut Knaack 				ret = errno ? -errno : -ENODATA;
26653118557SHartmut Knaack 
267f2edf0c8SYulong Zhang 			fclose(sysfsfp);
268817020cfSRoberta Dobrescu 			break;
269817020cfSRoberta Dobrescu 		}
270817020cfSRoberta Dobrescu error_free_filename:
271817020cfSRoberta Dobrescu 	if (filename)
272817020cfSRoberta Dobrescu 		free(filename);
2737663a4aaSHartmut Knaack 
274817020cfSRoberta Dobrescu error_closedir:
27553118557SHartmut Knaack 	if (closedir(dp) == -1)
27653118557SHartmut Knaack 		perror("iioutils_get_param_float(): Failed to close directory");
27753118557SHartmut Knaack 
278817020cfSRoberta Dobrescu error_free_builtname_generic:
279817020cfSRoberta Dobrescu 	free(builtname_generic);
280817020cfSRoberta Dobrescu error_free_builtname:
281817020cfSRoberta Dobrescu 	free(builtname);
2820e799878SHartmut Knaack 
283817020cfSRoberta Dobrescu 	return ret;
284817020cfSRoberta Dobrescu }
285817020cfSRoberta Dobrescu 
286817020cfSRoberta Dobrescu /**
2875dc65d79SHartmut Knaack  * bsort_channel_array_by_index() - sort the array in index order
2885dc65d79SHartmut Knaack  * @ci_array: the iio_channel_info array to be sorted
2895dc65d79SHartmut Knaack  * @cnt: the amount of array elements
290817020cfSRoberta Dobrescu  **/
291817020cfSRoberta Dobrescu 
bsort_channel_array_by_index(struct iio_channel_info * ci_array,int cnt)29295ddd3f4SJoo Aun Saw void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt)
293817020cfSRoberta Dobrescu {
294817020cfSRoberta Dobrescu 	struct iio_channel_info temp;
295817020cfSRoberta Dobrescu 	int x, y;
296817020cfSRoberta Dobrescu 
297817020cfSRoberta Dobrescu 	for (x = 0; x < cnt; x++)
298817020cfSRoberta Dobrescu 		for (y = 0; y < (cnt - 1); y++)
29995ddd3f4SJoo Aun Saw 			if (ci_array[y].index > ci_array[y + 1].index) {
30095ddd3f4SJoo Aun Saw 				temp = ci_array[y + 1];
30195ddd3f4SJoo Aun Saw 				ci_array[y + 1] = ci_array[y];
30295ddd3f4SJoo Aun Saw 				ci_array[y] = temp;
303817020cfSRoberta Dobrescu 			}
304817020cfSRoberta Dobrescu }
305817020cfSRoberta Dobrescu 
306817020cfSRoberta Dobrescu /**
307817020cfSRoberta Dobrescu  * build_channel_array() - function to figure out what channels are present
308817020cfSRoberta Dobrescu  * @device_dir: the IIO device directory in sysfs
3098827faabSAlexandru Ardelean  * @buffer_idx: the IIO buffer for this channel array
3105dc65d79SHartmut Knaack  * @ci_array: output the resulting array of iio_channel_info
3115dc65d79SHartmut Knaack  * @counter: output the amount of array elements
3125dc65d79SHartmut Knaack  *
3135dc65d79SHartmut Knaack  * Returns 0 on success, otherwise a negative error code.
314817020cfSRoberta Dobrescu  **/
build_channel_array(const char * device_dir,int buffer_idx,struct iio_channel_info ** ci_array,int * counter)3158827faabSAlexandru Ardelean int build_channel_array(const char *device_dir, int buffer_idx,
3167663a4aaSHartmut Knaack 			struct iio_channel_info **ci_array, int *counter)
317817020cfSRoberta Dobrescu {
318817020cfSRoberta Dobrescu 	DIR *dp;
319817020cfSRoberta Dobrescu 	FILE *sysfsfp;
3201e7c3478SHartmut Knaack 	int count = 0, i;
321817020cfSRoberta Dobrescu 	struct iio_channel_info *current;
322817020cfSRoberta Dobrescu 	int ret;
323817020cfSRoberta Dobrescu 	const struct dirent *ent;
324817020cfSRoberta Dobrescu 	char *scan_el_dir;
325817020cfSRoberta Dobrescu 	char *filename;
326817020cfSRoberta Dobrescu 
327817020cfSRoberta Dobrescu 	*counter = 0;
3288827faabSAlexandru Ardelean 	ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx);
3290e799878SHartmut Knaack 	if (ret < 0)
3300e799878SHartmut Knaack 		return -ENOMEM;
3310e799878SHartmut Knaack 
332817020cfSRoberta Dobrescu 	dp = opendir(scan_el_dir);
333ff1ac639SCristina Opriceana 	if (!dp) {
334817020cfSRoberta Dobrescu 		ret = -errno;
335817020cfSRoberta Dobrescu 		goto error_free_name;
336817020cfSRoberta Dobrescu 	}
3377663a4aaSHartmut Knaack 
338ff1ac639SCristina Opriceana 	while (ent = readdir(dp), ent)
339817020cfSRoberta Dobrescu 		if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
340817020cfSRoberta Dobrescu 			   "_en") == 0) {
341817020cfSRoberta Dobrescu 			ret = asprintf(&filename,
342817020cfSRoberta Dobrescu 				       "%s/%s", scan_el_dir, ent->d_name);
343817020cfSRoberta Dobrescu 			if (ret < 0) {
344817020cfSRoberta Dobrescu 				ret = -ENOMEM;
345817020cfSRoberta Dobrescu 				goto error_close_dir;
346817020cfSRoberta Dobrescu 			}
3477663a4aaSHartmut Knaack 
348817020cfSRoberta Dobrescu 			sysfsfp = fopen(filename, "r");
349f2edf0c8SYulong Zhang 			free(filename);
350ff1ac639SCristina Opriceana 			if (!sysfsfp) {
351817020cfSRoberta Dobrescu 				ret = -errno;
352817020cfSRoberta Dobrescu 				goto error_close_dir;
353817020cfSRoberta Dobrescu 			}
3547663a4aaSHartmut Knaack 
35553118557SHartmut Knaack 			errno = 0;
35653118557SHartmut Knaack 			if (fscanf(sysfsfp, "%i", &ret) != 1) {
35753118557SHartmut Knaack 				ret = errno ? -errno : -ENODATA;
35853118557SHartmut Knaack 				if (fclose(sysfsfp))
35953118557SHartmut Knaack 					perror("build_channel_array(): Failed to close file");
36053118557SHartmut Knaack 
36153118557SHartmut Knaack 				goto error_close_dir;
36253118557SHartmut Knaack 			}
363817020cfSRoberta Dobrescu 			if (ret == 1)
364817020cfSRoberta Dobrescu 				(*counter)++;
3657663a4aaSHartmut Knaack 
36653118557SHartmut Knaack 			if (fclose(sysfsfp)) {
36753118557SHartmut Knaack 				ret = -errno;
36853118557SHartmut Knaack 				goto error_close_dir;
36953118557SHartmut Knaack 			}
37053118557SHartmut Knaack 
371817020cfSRoberta Dobrescu 		}
3727663a4aaSHartmut Knaack 
373817020cfSRoberta Dobrescu 	*ci_array = malloc(sizeof(**ci_array) * (*counter));
374ff1ac639SCristina Opriceana 	if (!*ci_array) {
375817020cfSRoberta Dobrescu 		ret = -ENOMEM;
376817020cfSRoberta Dobrescu 		goto error_close_dir;
377817020cfSRoberta Dobrescu 	}
3787663a4aaSHartmut Knaack 
379*bb72eb81SPetre Rodan 	rewinddir(dp);
380ff1ac639SCristina Opriceana 	while (ent = readdir(dp), ent) {
381817020cfSRoberta Dobrescu 		if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
382817020cfSRoberta Dobrescu 			   "_en") == 0) {
383817020cfSRoberta Dobrescu 			int current_enabled = 0;
384817020cfSRoberta Dobrescu 
385817020cfSRoberta Dobrescu 			current = &(*ci_array)[count++];
386817020cfSRoberta Dobrescu 			ret = asprintf(&filename,
387817020cfSRoberta Dobrescu 				       "%s/%s", scan_el_dir, ent->d_name);
388817020cfSRoberta Dobrescu 			if (ret < 0) {
389817020cfSRoberta Dobrescu 				ret = -ENOMEM;
390817020cfSRoberta Dobrescu 				/* decrement count to avoid freeing name */
391817020cfSRoberta Dobrescu 				count--;
392817020cfSRoberta Dobrescu 				goto error_cleanup_array;
393817020cfSRoberta Dobrescu 			}
3947663a4aaSHartmut Knaack 
395817020cfSRoberta Dobrescu 			sysfsfp = fopen(filename, "r");
396f2edf0c8SYulong Zhang 			free(filename);
397ff1ac639SCristina Opriceana 			if (!sysfsfp) {
398817020cfSRoberta Dobrescu 				ret = -errno;
399121b5e50SHartmut Knaack 				count--;
400817020cfSRoberta Dobrescu 				goto error_cleanup_array;
401817020cfSRoberta Dobrescu 			}
4027663a4aaSHartmut Knaack 
40353118557SHartmut Knaack 			errno = 0;
40453118557SHartmut Knaack 			if (fscanf(sysfsfp, "%i", &current_enabled) != 1) {
40553118557SHartmut Knaack 				ret = errno ? -errno : -ENODATA;
40653118557SHartmut Knaack 				count--;
40753118557SHartmut Knaack 				goto error_cleanup_array;
40853118557SHartmut Knaack 			}
40953118557SHartmut Knaack 
41053118557SHartmut Knaack 			if (fclose(sysfsfp)) {
41153118557SHartmut Knaack 				ret = -errno;
41253118557SHartmut Knaack 				count--;
41353118557SHartmut Knaack 				goto error_cleanup_array;
41453118557SHartmut Knaack 			}
415817020cfSRoberta Dobrescu 
416817020cfSRoberta Dobrescu 			if (!current_enabled) {
417817020cfSRoberta Dobrescu 				count--;
418817020cfSRoberta Dobrescu 				continue;
419817020cfSRoberta Dobrescu 			}
420817020cfSRoberta Dobrescu 
421817020cfSRoberta Dobrescu 			current->scale = 1.0;
422817020cfSRoberta Dobrescu 			current->offset = 0;
423817020cfSRoberta Dobrescu 			current->name = strndup(ent->d_name,
424817020cfSRoberta Dobrescu 						strlen(ent->d_name) -
425817020cfSRoberta Dobrescu 						strlen("_en"));
426ff1ac639SCristina Opriceana 			if (!current->name) {
427817020cfSRoberta Dobrescu 				ret = -ENOMEM;
428121b5e50SHartmut Knaack 				count--;
429817020cfSRoberta Dobrescu 				goto error_cleanup_array;
430817020cfSRoberta Dobrescu 			}
4317663a4aaSHartmut Knaack 
432817020cfSRoberta Dobrescu 			/* Get the generic and specific name elements */
433817020cfSRoberta Dobrescu 			ret = iioutils_break_up_name(current->name,
434817020cfSRoberta Dobrescu 						     &current->generic_name);
435817020cfSRoberta Dobrescu 			if (ret) {
436121b5e50SHartmut Knaack 				free(current->name);
437121b5e50SHartmut Knaack 				count--;
438817020cfSRoberta Dobrescu 				goto error_cleanup_array;
439817020cfSRoberta Dobrescu 			}
4407663a4aaSHartmut Knaack 
441817020cfSRoberta Dobrescu 			ret = asprintf(&filename,
442817020cfSRoberta Dobrescu 				       "%s/%s_index",
443817020cfSRoberta Dobrescu 				       scan_el_dir,
444817020cfSRoberta Dobrescu 				       current->name);
445817020cfSRoberta Dobrescu 			if (ret < 0) {
446817020cfSRoberta Dobrescu 				ret = -ENOMEM;
447817020cfSRoberta Dobrescu 				goto error_cleanup_array;
448817020cfSRoberta Dobrescu 			}
4497663a4aaSHartmut Knaack 
450817020cfSRoberta Dobrescu 			sysfsfp = fopen(filename, "r");
451f2edf0c8SYulong Zhang 			free(filename);
452ff1ac639SCristina Opriceana 			if (!sysfsfp) {
45353118557SHartmut Knaack 				ret = -errno;
454f2edf0c8SYulong Zhang 				fprintf(stderr, "failed to open %s/%s_index\n",
455f2edf0c8SYulong Zhang 					scan_el_dir, current->name);
45653118557SHartmut Knaack 				goto error_cleanup_array;
45753118557SHartmut Knaack 			}
45853118557SHartmut Knaack 
45953118557SHartmut Knaack 			errno = 0;
46053118557SHartmut Knaack 			if (fscanf(sysfsfp, "%u", &current->index) != 1) {
46153118557SHartmut Knaack 				ret = errno ? -errno : -ENODATA;
46253118557SHartmut Knaack 				if (fclose(sysfsfp))
46353118557SHartmut Knaack 					perror("build_channel_array(): Failed to close file");
46453118557SHartmut Knaack 
46553118557SHartmut Knaack 				goto error_cleanup_array;
46653118557SHartmut Knaack 			}
46753118557SHartmut Knaack 
46853118557SHartmut Knaack 			if (fclose(sysfsfp)) {
46953118557SHartmut Knaack 				ret = -errno;
47053118557SHartmut Knaack 				goto error_cleanup_array;
47153118557SHartmut Knaack 			}
47253118557SHartmut Knaack 
473817020cfSRoberta Dobrescu 			/* Find the scale */
474817020cfSRoberta Dobrescu 			ret = iioutils_get_param_float(&current->scale,
475817020cfSRoberta Dobrescu 						       "scale",
476817020cfSRoberta Dobrescu 						       device_dir,
477817020cfSRoberta Dobrescu 						       current->name,
478817020cfSRoberta Dobrescu 						       current->generic_name);
4797868dfd2SJoo Aun Saw 			if ((ret < 0) && (ret != -ENOENT))
480817020cfSRoberta Dobrescu 				goto error_cleanup_array;
4817663a4aaSHartmut Knaack 
482817020cfSRoberta Dobrescu 			ret = iioutils_get_param_float(&current->offset,
483817020cfSRoberta Dobrescu 						       "offset",
484817020cfSRoberta Dobrescu 						       device_dir,
485817020cfSRoberta Dobrescu 						       current->name,
486817020cfSRoberta Dobrescu 						       current->generic_name);
4877868dfd2SJoo Aun Saw 			if ((ret < 0) && (ret != -ENOENT))
488817020cfSRoberta Dobrescu 				goto error_cleanup_array;
4897663a4aaSHartmut Knaack 
490817020cfSRoberta Dobrescu 			ret = iioutils_get_type(&current->is_signed,
491817020cfSRoberta Dobrescu 						&current->bytes,
492817020cfSRoberta Dobrescu 						&current->bits_used,
493817020cfSRoberta Dobrescu 						&current->shift,
494817020cfSRoberta Dobrescu 						&current->mask,
495817020cfSRoberta Dobrescu 						&current->be,
496817020cfSRoberta Dobrescu 						device_dir,
4978827faabSAlexandru Ardelean 						buffer_idx,
498817020cfSRoberta Dobrescu 						current->name,
499817020cfSRoberta Dobrescu 						current->generic_name);
50053118557SHartmut Knaack 			if (ret < 0)
50153118557SHartmut Knaack 				goto error_cleanup_array;
502817020cfSRoberta Dobrescu 		}
503817020cfSRoberta Dobrescu 	}
504817020cfSRoberta Dobrescu 
50553118557SHartmut Knaack 	if (closedir(dp) == -1) {
50653118557SHartmut Knaack 		ret = -errno;
50753118557SHartmut Knaack 		goto error_cleanup_array;
50853118557SHartmut Knaack 	}
50953118557SHartmut Knaack 
51066dd08fdSHartmut Knaack 	free(scan_el_dir);
511817020cfSRoberta Dobrescu 	/* reorder so that the array is in index order */
51295ddd3f4SJoo Aun Saw 	bsort_channel_array_by_index(*ci_array, *counter);
513817020cfSRoberta Dobrescu 
514817020cfSRoberta Dobrescu 	return 0;
515817020cfSRoberta Dobrescu 
516817020cfSRoberta Dobrescu error_cleanup_array:
51763f05c85SHartmut Knaack 	for (i = count - 1;  i >= 0; i--) {
518817020cfSRoberta Dobrescu 		free((*ci_array)[i].name);
51963f05c85SHartmut Knaack 		free((*ci_array)[i].generic_name);
52063f05c85SHartmut Knaack 	}
521817020cfSRoberta Dobrescu 	free(*ci_array);
5226b20f406SJoo Aun Saw 	*ci_array = NULL;
5236b20f406SJoo Aun Saw 	*counter = 0;
524817020cfSRoberta Dobrescu error_close_dir:
52553118557SHartmut Knaack 	if (dp)
52653118557SHartmut Knaack 		if (closedir(dp) == -1)
52753118557SHartmut Knaack 			perror("build_channel_array(): Failed to close dir");
52853118557SHartmut Knaack 
529817020cfSRoberta Dobrescu error_free_name:
530817020cfSRoberta Dobrescu 	free(scan_el_dir);
5310e799878SHartmut Knaack 
532817020cfSRoberta Dobrescu 	return ret;
533817020cfSRoberta Dobrescu }
534817020cfSRoberta Dobrescu 
calc_digits(int num)5355e37c523SJoo Aun Saw static int calc_digits(int num)
536096f9b86SHartmut Knaack {
537096f9b86SHartmut Knaack 	int count = 0;
538096f9b86SHartmut Knaack 
53972b2aa38SMatti Vaittinen 	/* It takes a digit to represent zero */
54072b2aa38SMatti Vaittinen 	if (!num)
54172b2aa38SMatti Vaittinen 		return 1;
54272b2aa38SMatti Vaittinen 
543096f9b86SHartmut Knaack 	while (num != 0) {
544096f9b86SHartmut Knaack 		num /= 10;
545096f9b86SHartmut Knaack 		count++;
546096f9b86SHartmut Knaack 	}
547096f9b86SHartmut Knaack 
548096f9b86SHartmut Knaack 	return count;
549096f9b86SHartmut Knaack }
550096f9b86SHartmut Knaack 
551817020cfSRoberta Dobrescu /**
552817020cfSRoberta Dobrescu  * find_type_by_name() - function to match top level types by name
553817020cfSRoberta Dobrescu  * @name: top level type instance name
5545dc65d79SHartmut Knaack  * @type: the type of top level instance being searched
555817020cfSRoberta Dobrescu  *
5565dc65d79SHartmut Knaack  * Returns the device number of a matched IIO device on success, otherwise a
5575dc65d79SHartmut Knaack  * negative error code.
558817020cfSRoberta Dobrescu  * Typical types this is used for are device and trigger.
559817020cfSRoberta Dobrescu  **/
find_type_by_name(const char * name,const char * type)560817020cfSRoberta Dobrescu int find_type_by_name(const char *name, const char *type)
561817020cfSRoberta Dobrescu {
562817020cfSRoberta Dobrescu 	const struct dirent *ent;
563096f9b86SHartmut Knaack 	int number, numstrlen, ret;
564817020cfSRoberta Dobrescu 
565a9d7acc8SHartmut Knaack 	FILE *namefp;
566817020cfSRoberta Dobrescu 	DIR *dp;
567817020cfSRoberta Dobrescu 	char thisname[IIO_MAX_NAME_LENGTH];
568817020cfSRoberta Dobrescu 	char *filename;
569817020cfSRoberta Dobrescu 
570817020cfSRoberta Dobrescu 	dp = opendir(iio_dir);
571ff1ac639SCristina Opriceana 	if (!dp) {
572d9abc615SCristina Opriceana 		fprintf(stderr, "No industrialio devices available\n");
573817020cfSRoberta Dobrescu 		return -ENODEV;
574817020cfSRoberta Dobrescu 	}
575817020cfSRoberta Dobrescu 
576ff1ac639SCristina Opriceana 	while (ent = readdir(dp), ent) {
577817020cfSRoberta Dobrescu 		if (strcmp(ent->d_name, ".") != 0 &&
578817020cfSRoberta Dobrescu 		    strcmp(ent->d_name, "..") != 0 &&
579817020cfSRoberta Dobrescu 		    strlen(ent->d_name) > strlen(type) &&
580817020cfSRoberta Dobrescu 		    strncmp(ent->d_name, type, strlen(type)) == 0) {
581096f9b86SHartmut Knaack 			errno = 0;
582096f9b86SHartmut Knaack 			ret = sscanf(ent->d_name + strlen(type), "%d", &number);
583096f9b86SHartmut Knaack 			if (ret < 0) {
584096f9b86SHartmut Knaack 				ret = -errno;
585d9abc615SCristina Opriceana 				fprintf(stderr,
586d9abc615SCristina Opriceana 					"failed to read element number\n");
587096f9b86SHartmut Knaack 				goto error_close_dir;
588096f9b86SHartmut Knaack 			} else if (ret != 1) {
589096f9b86SHartmut Knaack 				ret = -EIO;
590d9abc615SCristina Opriceana 				fprintf(stderr,
591d9abc615SCristina Opriceana 					"failed to match element number\n");
592096f9b86SHartmut Knaack 				goto error_close_dir;
593096f9b86SHartmut Knaack 			}
594096f9b86SHartmut Knaack 
595096f9b86SHartmut Knaack 			numstrlen = calc_digits(number);
596817020cfSRoberta Dobrescu 			/* verify the next character is not a colon */
597817020cfSRoberta Dobrescu 			if (strncmp(ent->d_name + strlen(type) + numstrlen,
5987663a4aaSHartmut Knaack 			    ":", 1) != 0) {
5997663a4aaSHartmut Knaack 				filename = malloc(strlen(iio_dir) + strlen(type)
6007663a4aaSHartmut Knaack 						  + numstrlen + 6);
601ff1ac639SCristina Opriceana 				if (!filename) {
60253118557SHartmut Knaack 					ret = -ENOMEM;
60353118557SHartmut Knaack 					goto error_close_dir;
604817020cfSRoberta Dobrescu 				}
60553118557SHartmut Knaack 
60653118557SHartmut Knaack 				ret = sprintf(filename, "%s%s%d/name", iio_dir,
60753118557SHartmut Knaack 					      type, number);
60853118557SHartmut Knaack 				if (ret < 0) {
60953118557SHartmut Knaack 					free(filename);
61053118557SHartmut Knaack 					goto error_close_dir;
61153118557SHartmut Knaack 				}
61253118557SHartmut Knaack 
613a9d7acc8SHartmut Knaack 				namefp = fopen(filename, "r");
614a9d7acc8SHartmut Knaack 				if (!namefp) {
615817020cfSRoberta Dobrescu 					free(filename);
616817020cfSRoberta Dobrescu 					continue;
617817020cfSRoberta Dobrescu 				}
6187663a4aaSHartmut Knaack 
619817020cfSRoberta Dobrescu 				free(filename);
62053118557SHartmut Knaack 				errno = 0;
621a9d7acc8SHartmut Knaack 				if (fscanf(namefp, "%s", thisname) != 1) {
62253118557SHartmut Knaack 					ret = errno ? -errno : -ENODATA;
62353118557SHartmut Knaack 					goto error_close_dir;
62453118557SHartmut Knaack 				}
62553118557SHartmut Knaack 
626a9d7acc8SHartmut Knaack 				if (fclose(namefp)) {
62753118557SHartmut Knaack 					ret = -errno;
62853118557SHartmut Knaack 					goto error_close_dir;
62953118557SHartmut Knaack 				}
63053118557SHartmut Knaack 
631817020cfSRoberta Dobrescu 				if (strcmp(name, thisname) == 0) {
63253118557SHartmut Knaack 					if (closedir(dp) == -1)
63353118557SHartmut Knaack 						return -errno;
6347663a4aaSHartmut Knaack 
635817020cfSRoberta Dobrescu 					return number;
636817020cfSRoberta Dobrescu 				}
637817020cfSRoberta Dobrescu 			}
638817020cfSRoberta Dobrescu 		}
639817020cfSRoberta Dobrescu 	}
64053118557SHartmut Knaack 	if (closedir(dp) == -1)
64153118557SHartmut Knaack 		return -errno;
64253118557SHartmut Knaack 
643817020cfSRoberta Dobrescu 	return -ENODEV;
644096f9b86SHartmut Knaack 
645096f9b86SHartmut Knaack error_close_dir:
646096f9b86SHartmut Knaack 	if (closedir(dp) == -1)
647096f9b86SHartmut Knaack 		perror("find_type_by_name(): Failed to close directory");
6487663a4aaSHartmut Knaack 
649096f9b86SHartmut Knaack 	return ret;
650817020cfSRoberta Dobrescu }
651817020cfSRoberta Dobrescu 
_write_sysfs_int(const char * filename,const char * basedir,int val,int verify)6529d475254SHartmut Knaack static int _write_sysfs_int(const char *filename, const char *basedir, int val,
6539d475254SHartmut Knaack 			    int verify)
654817020cfSRoberta Dobrescu {
655817020cfSRoberta Dobrescu 	int ret = 0;
656817020cfSRoberta Dobrescu 	FILE *sysfsfp;
657817020cfSRoberta Dobrescu 	int test;
658817020cfSRoberta Dobrescu 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
659817020cfSRoberta Dobrescu 
660ff1ac639SCristina Opriceana 	if (!temp)
661817020cfSRoberta Dobrescu 		return -ENOMEM;
6627663a4aaSHartmut Knaack 
66353118557SHartmut Knaack 	ret = sprintf(temp, "%s/%s", basedir, filename);
66453118557SHartmut Knaack 	if (ret < 0)
66553118557SHartmut Knaack 		goto error_free;
66653118557SHartmut Knaack 
667817020cfSRoberta Dobrescu 	sysfsfp = fopen(temp, "w");
668ff1ac639SCristina Opriceana 	if (!sysfsfp) {
669817020cfSRoberta Dobrescu 		ret = -errno;
670d9abc615SCristina Opriceana 		fprintf(stderr, "failed to open %s\n", temp);
671817020cfSRoberta Dobrescu 		goto error_free;
672817020cfSRoberta Dobrescu 	}
6737663a4aaSHartmut Knaack 
67453118557SHartmut Knaack 	ret = fprintf(sysfsfp, "%d", val);
67553118557SHartmut Knaack 	if (ret < 0) {
67653118557SHartmut Knaack 		if (fclose(sysfsfp))
67753118557SHartmut Knaack 			perror("_write_sysfs_int(): Failed to close dir");
67853118557SHartmut Knaack 
67953118557SHartmut Knaack 		goto error_free;
68053118557SHartmut Knaack 	}
68153118557SHartmut Knaack 
68253118557SHartmut Knaack 	if (fclose(sysfsfp)) {
68353118557SHartmut Knaack 		ret = -errno;
68453118557SHartmut Knaack 		goto error_free;
68553118557SHartmut Knaack 	}
68653118557SHartmut Knaack 
687817020cfSRoberta Dobrescu 	if (verify) {
688817020cfSRoberta Dobrescu 		sysfsfp = fopen(temp, "r");
689ff1ac639SCristina Opriceana 		if (!sysfsfp) {
690817020cfSRoberta Dobrescu 			ret = -errno;
691d9abc615SCristina Opriceana 			fprintf(stderr, "failed to open %s\n", temp);
692817020cfSRoberta Dobrescu 			goto error_free;
693817020cfSRoberta Dobrescu 		}
6947663a4aaSHartmut Knaack 
69553118557SHartmut Knaack 		if (fscanf(sysfsfp, "%d", &test) != 1) {
69653118557SHartmut Knaack 			ret = errno ? -errno : -ENODATA;
69753118557SHartmut Knaack 			if (fclose(sysfsfp))
69853118557SHartmut Knaack 				perror("_write_sysfs_int(): Failed to close dir");
69953118557SHartmut Knaack 
70053118557SHartmut Knaack 			goto error_free;
70153118557SHartmut Knaack 		}
70253118557SHartmut Knaack 
70353118557SHartmut Knaack 		if (fclose(sysfsfp)) {
70453118557SHartmut Knaack 			ret = -errno;
70553118557SHartmut Knaack 			goto error_free;
70653118557SHartmut Knaack 		}
70753118557SHartmut Knaack 
708817020cfSRoberta Dobrescu 		if (test != val) {
709d9abc615SCristina Opriceana 			fprintf(stderr,
710d9abc615SCristina Opriceana 				"Possible failure in int write %d to %s/%s\n",
7117663a4aaSHartmut Knaack 				val, basedir, filename);
712817020cfSRoberta Dobrescu 			ret = -1;
713817020cfSRoberta Dobrescu 		}
714817020cfSRoberta Dobrescu 	}
7157663a4aaSHartmut Knaack 
716817020cfSRoberta Dobrescu error_free:
717817020cfSRoberta Dobrescu 	free(temp);
718817020cfSRoberta Dobrescu 	return ret;
719817020cfSRoberta Dobrescu }
720817020cfSRoberta Dobrescu 
7215dc65d79SHartmut Knaack /**
7225dc65d79SHartmut Knaack  * write_sysfs_int() - write an integer value to a sysfs file
7235dc65d79SHartmut Knaack  * @filename: name of the file to write to
7245dc65d79SHartmut Knaack  * @basedir: the sysfs directory in which the file is to be found
7255dc65d79SHartmut Knaack  * @val: integer value to write to file
7265dc65d79SHartmut Knaack  *
7275dc65d79SHartmut Knaack  * Returns a value >= 0 on success, otherwise a negative error code.
7285dc65d79SHartmut Knaack  **/
write_sysfs_int(const char * filename,const char * basedir,int val)7299d475254SHartmut Knaack int write_sysfs_int(const char *filename, const char *basedir, int val)
730817020cfSRoberta Dobrescu {
731817020cfSRoberta Dobrescu 	return _write_sysfs_int(filename, basedir, val, 0);
732817020cfSRoberta Dobrescu }
733817020cfSRoberta Dobrescu 
7345dc65d79SHartmut Knaack /**
7355dc65d79SHartmut Knaack  * write_sysfs_int_and_verify() - write an integer value to a sysfs file
7365dc65d79SHartmut Knaack  *				  and verify
7375dc65d79SHartmut Knaack  * @filename: name of the file to write to
7385dc65d79SHartmut Knaack  * @basedir: the sysfs directory in which the file is to be found
7395dc65d79SHartmut Knaack  * @val: integer value to write to file
7405dc65d79SHartmut Knaack  *
7415dc65d79SHartmut Knaack  * Returns a value >= 0 on success, otherwise a negative error code.
7425dc65d79SHartmut Knaack  **/
write_sysfs_int_and_verify(const char * filename,const char * basedir,int val)7439d475254SHartmut Knaack int write_sysfs_int_and_verify(const char *filename, const char *basedir,
7449d475254SHartmut Knaack 			       int val)
745817020cfSRoberta Dobrescu {
746817020cfSRoberta Dobrescu 	return _write_sysfs_int(filename, basedir, val, 1);
747817020cfSRoberta Dobrescu }
748817020cfSRoberta Dobrescu 
_write_sysfs_string(const char * filename,const char * basedir,const char * val,int verify)7499d475254SHartmut Knaack static int _write_sysfs_string(const char *filename, const char *basedir,
7509d475254SHartmut Knaack 			       const char *val, int verify)
751817020cfSRoberta Dobrescu {
752817020cfSRoberta Dobrescu 	int ret = 0;
753817020cfSRoberta Dobrescu 	FILE  *sysfsfp;
754817020cfSRoberta Dobrescu 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
755817020cfSRoberta Dobrescu 
756ff1ac639SCristina Opriceana 	if (!temp) {
757d9abc615SCristina Opriceana 		fprintf(stderr, "Memory allocation failed\n");
758817020cfSRoberta Dobrescu 		return -ENOMEM;
759817020cfSRoberta Dobrescu 	}
7607663a4aaSHartmut Knaack 
76153118557SHartmut Knaack 	ret = sprintf(temp, "%s/%s", basedir, filename);
76253118557SHartmut Knaack 	if (ret < 0)
76353118557SHartmut Knaack 		goto error_free;
76453118557SHartmut Knaack 
765817020cfSRoberta Dobrescu 	sysfsfp = fopen(temp, "w");
766ff1ac639SCristina Opriceana 	if (!sysfsfp) {
767817020cfSRoberta Dobrescu 		ret = -errno;
768d9abc615SCristina Opriceana 		fprintf(stderr, "Could not open %s\n", temp);
769817020cfSRoberta Dobrescu 		goto error_free;
770817020cfSRoberta Dobrescu 	}
7717663a4aaSHartmut Knaack 
77253118557SHartmut Knaack 	ret = fprintf(sysfsfp, "%s", val);
77353118557SHartmut Knaack 	if (ret < 0) {
77453118557SHartmut Knaack 		if (fclose(sysfsfp))
77553118557SHartmut Knaack 			perror("_write_sysfs_string(): Failed to close dir");
77653118557SHartmut Knaack 
77753118557SHartmut Knaack 		goto error_free;
77853118557SHartmut Knaack 	}
77953118557SHartmut Knaack 
78053118557SHartmut Knaack 	if (fclose(sysfsfp)) {
78153118557SHartmut Knaack 		ret = -errno;
78253118557SHartmut Knaack 		goto error_free;
78353118557SHartmut Knaack 	}
78453118557SHartmut Knaack 
785817020cfSRoberta Dobrescu 	if (verify) {
786817020cfSRoberta Dobrescu 		sysfsfp = fopen(temp, "r");
787ff1ac639SCristina Opriceana 		if (!sysfsfp) {
788817020cfSRoberta Dobrescu 			ret = -errno;
789d9abc615SCristina Opriceana 			fprintf(stderr, "Could not open file to verify\n");
790817020cfSRoberta Dobrescu 			goto error_free;
791817020cfSRoberta Dobrescu 		}
7927663a4aaSHartmut Knaack 
79353118557SHartmut Knaack 		if (fscanf(sysfsfp, "%s", temp) != 1) {
79453118557SHartmut Knaack 			ret = errno ? -errno : -ENODATA;
79553118557SHartmut Knaack 			if (fclose(sysfsfp))
79653118557SHartmut Knaack 				perror("_write_sysfs_string(): Failed to close dir");
79753118557SHartmut Knaack 
79853118557SHartmut Knaack 			goto error_free;
79953118557SHartmut Knaack 		}
80053118557SHartmut Knaack 
80153118557SHartmut Knaack 		if (fclose(sysfsfp)) {
80253118557SHartmut Knaack 			ret = -errno;
80353118557SHartmut Knaack 			goto error_free;
80453118557SHartmut Knaack 		}
80553118557SHartmut Knaack 
806817020cfSRoberta Dobrescu 		if (strcmp(temp, val) != 0) {
807d9abc615SCristina Opriceana 			fprintf(stderr,
808d9abc615SCristina Opriceana 				"Possible failure in string write of %s "
8097663a4aaSHartmut Knaack 				"Should be %s written to %s/%s\n", temp, val,
8107663a4aaSHartmut Knaack 				basedir, filename);
811817020cfSRoberta Dobrescu 			ret = -1;
812817020cfSRoberta Dobrescu 		}
813817020cfSRoberta Dobrescu 	}
8147663a4aaSHartmut Knaack 
815817020cfSRoberta Dobrescu error_free:
816817020cfSRoberta Dobrescu 	free(temp);
817817020cfSRoberta Dobrescu 
818817020cfSRoberta Dobrescu 	return ret;
819817020cfSRoberta Dobrescu }
820817020cfSRoberta Dobrescu 
821817020cfSRoberta Dobrescu /**
822817020cfSRoberta Dobrescu  * write_sysfs_string_and_verify() - string write, readback and verify
823817020cfSRoberta Dobrescu  * @filename: name of file to write to
824817020cfSRoberta Dobrescu  * @basedir: the sysfs directory in which the file is to be found
825817020cfSRoberta Dobrescu  * @val: the string to write
8265dc65d79SHartmut Knaack  *
8275dc65d79SHartmut Knaack  * Returns a value >= 0 on success, otherwise a negative error code.
828817020cfSRoberta Dobrescu  **/
write_sysfs_string_and_verify(const char * filename,const char * basedir,const char * val)8299d475254SHartmut Knaack int write_sysfs_string_and_verify(const char *filename, const char *basedir,
8309d475254SHartmut Knaack 				  const char *val)
831817020cfSRoberta Dobrescu {
832817020cfSRoberta Dobrescu 	return _write_sysfs_string(filename, basedir, val, 1);
833817020cfSRoberta Dobrescu }
834817020cfSRoberta Dobrescu 
8355dc65d79SHartmut Knaack /**
8365dc65d79SHartmut Knaack  * write_sysfs_string() - write string to a sysfs file
8375dc65d79SHartmut Knaack  * @filename: name of file to write to
8385dc65d79SHartmut Knaack  * @basedir: the sysfs directory in which the file is to be found
8395dc65d79SHartmut Knaack  * @val: the string to write
8405dc65d79SHartmut Knaack  *
8415dc65d79SHartmut Knaack  * Returns a value >= 0 on success, otherwise a negative error code.
8425dc65d79SHartmut Knaack  **/
write_sysfs_string(const char * filename,const char * basedir,const char * val)8439d475254SHartmut Knaack int write_sysfs_string(const char *filename, const char *basedir,
8449d475254SHartmut Knaack 		       const char *val)
845817020cfSRoberta Dobrescu {
846817020cfSRoberta Dobrescu 	return _write_sysfs_string(filename, basedir, val, 0);
847817020cfSRoberta Dobrescu }
848817020cfSRoberta Dobrescu 
8495dc65d79SHartmut Knaack /**
8505dc65d79SHartmut Knaack  * read_sysfs_posint() - read an integer value from file
8515dc65d79SHartmut Knaack  * @filename: name of file to read from
8525dc65d79SHartmut Knaack  * @basedir: the sysfs directory in which the file is to be found
8535dc65d79SHartmut Knaack  *
8545dc65d79SHartmut Knaack  * Returns the read integer value >= 0 on success, otherwise a negative error
8555dc65d79SHartmut Knaack  * code.
8565dc65d79SHartmut Knaack  **/
read_sysfs_posint(const char * filename,const char * basedir)8579d475254SHartmut Knaack int read_sysfs_posint(const char *filename, const char *basedir)
858817020cfSRoberta Dobrescu {
859817020cfSRoberta Dobrescu 	int ret;
860817020cfSRoberta Dobrescu 	FILE  *sysfsfp;
861817020cfSRoberta Dobrescu 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
862817020cfSRoberta Dobrescu 
863ff1ac639SCristina Opriceana 	if (!temp) {
864d9abc615SCristina Opriceana 		fprintf(stderr, "Memory allocation failed");
865817020cfSRoberta Dobrescu 		return -ENOMEM;
866817020cfSRoberta Dobrescu 	}
8677663a4aaSHartmut Knaack 
86853118557SHartmut Knaack 	ret = sprintf(temp, "%s/%s", basedir, filename);
86953118557SHartmut Knaack 	if (ret < 0)
87053118557SHartmut Knaack 		goto error_free;
87153118557SHartmut Knaack 
872817020cfSRoberta Dobrescu 	sysfsfp = fopen(temp, "r");
873ff1ac639SCristina Opriceana 	if (!sysfsfp) {
874817020cfSRoberta Dobrescu 		ret = -errno;
875817020cfSRoberta Dobrescu 		goto error_free;
876817020cfSRoberta Dobrescu 	}
8777663a4aaSHartmut Knaack 
87853118557SHartmut Knaack 	errno = 0;
87953118557SHartmut Knaack 	if (fscanf(sysfsfp, "%d\n", &ret) != 1) {
88053118557SHartmut Knaack 		ret = errno ? -errno : -ENODATA;
88153118557SHartmut Knaack 		if (fclose(sysfsfp))
88253118557SHartmut Knaack 			perror("read_sysfs_posint(): Failed to close dir");
88353118557SHartmut Knaack 
88453118557SHartmut Knaack 		goto error_free;
88553118557SHartmut Knaack 	}
88653118557SHartmut Knaack 
88753118557SHartmut Knaack 	if (fclose(sysfsfp))
88853118557SHartmut Knaack 		ret = -errno;
88953118557SHartmut Knaack 
890817020cfSRoberta Dobrescu error_free:
891817020cfSRoberta Dobrescu 	free(temp);
8927663a4aaSHartmut Knaack 
893817020cfSRoberta Dobrescu 	return ret;
894817020cfSRoberta Dobrescu }
895817020cfSRoberta Dobrescu 
8965dc65d79SHartmut Knaack /**
8975dc65d79SHartmut Knaack  * read_sysfs_float() - read a float value from file
8985dc65d79SHartmut Knaack  * @filename: name of file to read from
8995dc65d79SHartmut Knaack  * @basedir: the sysfs directory in which the file is to be found
9005dc65d79SHartmut Knaack  * @val: output the read float value
9015dc65d79SHartmut Knaack  *
9025dc65d79SHartmut Knaack  * Returns a value >= 0 on success, otherwise a negative error code.
9035dc65d79SHartmut Knaack  **/
read_sysfs_float(const char * filename,const char * basedir,float * val)9049d475254SHartmut Knaack int read_sysfs_float(const char *filename, const char *basedir, float *val)
905817020cfSRoberta Dobrescu {
906817020cfSRoberta Dobrescu 	int ret = 0;
907817020cfSRoberta Dobrescu 	FILE  *sysfsfp;
908817020cfSRoberta Dobrescu 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
909817020cfSRoberta Dobrescu 
910ff1ac639SCristina Opriceana 	if (!temp) {
911d9abc615SCristina Opriceana 		fprintf(stderr, "Memory allocation failed");
912817020cfSRoberta Dobrescu 		return -ENOMEM;
913817020cfSRoberta Dobrescu 	}
9147663a4aaSHartmut Knaack 
91553118557SHartmut Knaack 	ret = sprintf(temp, "%s/%s", basedir, filename);
91653118557SHartmut Knaack 	if (ret < 0)
91753118557SHartmut Knaack 		goto error_free;
91853118557SHartmut Knaack 
919817020cfSRoberta Dobrescu 	sysfsfp = fopen(temp, "r");
920ff1ac639SCristina Opriceana 	if (!sysfsfp) {
921817020cfSRoberta Dobrescu 		ret = -errno;
922817020cfSRoberta Dobrescu 		goto error_free;
923817020cfSRoberta Dobrescu 	}
9247663a4aaSHartmut Knaack 
92553118557SHartmut Knaack 	errno = 0;
92653118557SHartmut Knaack 	if (fscanf(sysfsfp, "%f\n", val) != 1) {
92753118557SHartmut Knaack 		ret = errno ? -errno : -ENODATA;
92853118557SHartmut Knaack 		if (fclose(sysfsfp))
92953118557SHartmut Knaack 			perror("read_sysfs_float(): Failed to close dir");
93053118557SHartmut Knaack 
93153118557SHartmut Knaack 		goto error_free;
93253118557SHartmut Knaack 	}
93353118557SHartmut Knaack 
93453118557SHartmut Knaack 	if (fclose(sysfsfp))
93553118557SHartmut Knaack 		ret = -errno;
93653118557SHartmut Knaack 
937817020cfSRoberta Dobrescu error_free:
938817020cfSRoberta Dobrescu 	free(temp);
9397663a4aaSHartmut Knaack 
940817020cfSRoberta Dobrescu 	return ret;
941817020cfSRoberta Dobrescu }
942817020cfSRoberta Dobrescu 
9435dc65d79SHartmut Knaack /**
9445dc65d79SHartmut Knaack  * read_sysfs_string() - read a string from file
9455dc65d79SHartmut Knaack  * @filename: name of file to read from
9465dc65d79SHartmut Knaack  * @basedir: the sysfs directory in which the file is to be found
9475dc65d79SHartmut Knaack  * @str: output the read string
9485dc65d79SHartmut Knaack  *
9495dc65d79SHartmut Knaack  * Returns a value >= 0 on success, otherwise a negative error code.
9505dc65d79SHartmut Knaack  **/
read_sysfs_string(const char * filename,const char * basedir,char * str)951817020cfSRoberta Dobrescu int read_sysfs_string(const char *filename, const char *basedir, char *str)
952817020cfSRoberta Dobrescu {
953817020cfSRoberta Dobrescu 	int ret = 0;
954817020cfSRoberta Dobrescu 	FILE  *sysfsfp;
955817020cfSRoberta Dobrescu 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
956817020cfSRoberta Dobrescu 
957ff1ac639SCristina Opriceana 	if (!temp) {
958d9abc615SCristina Opriceana 		fprintf(stderr, "Memory allocation failed");
959817020cfSRoberta Dobrescu 		return -ENOMEM;
960817020cfSRoberta Dobrescu 	}
9617663a4aaSHartmut Knaack 
96253118557SHartmut Knaack 	ret = sprintf(temp, "%s/%s", basedir, filename);
96353118557SHartmut Knaack 	if (ret < 0)
96453118557SHartmut Knaack 		goto error_free;
96553118557SHartmut Knaack 
966817020cfSRoberta Dobrescu 	sysfsfp = fopen(temp, "r");
967ff1ac639SCristina Opriceana 	if (!sysfsfp) {
968817020cfSRoberta Dobrescu 		ret = -errno;
969817020cfSRoberta Dobrescu 		goto error_free;
970817020cfSRoberta Dobrescu 	}
9717663a4aaSHartmut Knaack 
97253118557SHartmut Knaack 	errno = 0;
97353118557SHartmut Knaack 	if (fscanf(sysfsfp, "%s\n", str) != 1) {
97453118557SHartmut Knaack 		ret = errno ? -errno : -ENODATA;
97553118557SHartmut Knaack 		if (fclose(sysfsfp))
97653118557SHartmut Knaack 			perror("read_sysfs_string(): Failed to close dir");
97753118557SHartmut Knaack 
97853118557SHartmut Knaack 		goto error_free;
97953118557SHartmut Knaack 	}
98053118557SHartmut Knaack 
98153118557SHartmut Knaack 	if (fclose(sysfsfp))
98253118557SHartmut Knaack 		ret = -errno;
98353118557SHartmut Knaack 
984817020cfSRoberta Dobrescu error_free:
985817020cfSRoberta Dobrescu 	free(temp);
9867663a4aaSHartmut Knaack 
987817020cfSRoberta Dobrescu 	return ret;
988817020cfSRoberta Dobrescu }
989