Linux Audio

Check our new training course

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