• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 const char *iio_dir = "/sys/bus/iio/devices/";
16 
17 static 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  **/
iioutils_break_up_name(const char * full_name,char ** generic_name)29 int 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  **/
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 int 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 
183 error_close_sysfsfp:
184 	if (sysfsfp)
185 		if (fclose(sysfsfp))
186 			perror("iioutils_get_type(): Failed to close file");
187 
188 error_free_filename:
189 	if (filename)
190 		free(filename);
191 
192 error_closedir:
193 	if (closedir(dp) == -1)
194 		perror("iioutils_get_type(): Failed to close directory");
195 
196 error_free_builtname_generic:
197 	free(builtname_generic);
198 error_free_builtname:
199 	free(builtname);
200 error_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  **/
iioutils_get_param_float(float * output,const char * param_name,const char * device_dir,const char * name,const char * generic_name)216 int 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 		}
268 error_free_filename:
269 	if (filename)
270 		free(filename);
271 
272 error_closedir:
273 	if (closedir(dp) == -1)
274 		perror("iioutils_get_param_float(): Failed to close directory");
275 
276 error_free_builtname_generic:
277 	free(builtname_generic);
278 error_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 
bsort_channel_array_by_index(struct iio_channel_info * ci_array,int cnt)290 void 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  **/
build_channel_array(const char * device_dir,struct iio_channel_info ** ci_array,int * counter)312 int 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 	rewinddir(dp);
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 
512 error_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;
520 error_close_dir:
521 	if (dp)
522 		if (closedir(dp) == -1)
523 			perror("build_channel_array(): Failed to close dir");
524 
525 error_free_name:
526 	free(scan_el_dir);
527 
528 	return ret;
529 }
530 
calc_digits(int num)531 static 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  **/
find_type_by_name(const char * name,const char * type)556 int 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 
641 error_close_dir:
642 	if (closedir(dp) == -1)
643 		perror("find_type_by_name(): Failed to close directory");
644 
645 	return ret;
646 }
647 
_write_sysfs_int(const char * filename,const char * basedir,int val,int verify)648 static 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 
712 error_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  **/
write_sysfs_int(const char * filename,const char * basedir,int val)725 int 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  **/
write_sysfs_int_and_verify(const char * filename,const char * basedir,int val)739 int 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 
_write_sysfs_string(const char * filename,const char * basedir,const char * val,int verify)745 static 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 
811 error_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  **/
write_sysfs_string_and_verify(const char * filename,const char * basedir,const char * val)825 int 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  **/
write_sysfs_string(const char * filename,const char * basedir,const char * val)839 int 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  **/
read_sysfs_posint(const char * filename,const char * basedir)853 int 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 
886 error_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  **/
read_sysfs_float(const char * filename,const char * basedir,float * val)900 int 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 
933 error_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  **/
read_sysfs_string(const char * filename,const char * basedir,char * str)947 int 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 
980 error_free:
981 	free(temp);
982 
983 	return ret;
984 }
985