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