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