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