xref: /openbmc/linux/tools/iio/iio_utils.c (revision 0df289a2)
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 #ifndef _IIO_UTILS_H
10 #define _IIO_UTILS_H
11 
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <stdint.h>
16 #include <dirent.h>
17 #include <errno.h>
18 #include <ctype.h>
19 #include "iio_utils.h"
20 
21 const char *iio_dir = "/sys/bus/iio/devices/";
22 
23 static char * const iio_direction[] = {
24 	"in",
25 	"out",
26 };
27 
28 /**
29  * iioutils_break_up_name() - extract generic name from full channel name
30  * @full_name: the full channel name
31  * @generic_name: the output generic channel name
32  **/
33 int iioutils_break_up_name(const char *full_name,
34 				  char **generic_name)
35 {
36 	char *current;
37 	char *w, *r;
38 	char *working, *prefix = "";
39 	int i;
40 
41 	for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++)
42 		if (!strncmp(full_name, iio_direction[i],
43 			     strlen(iio_direction[i]))) {
44 			prefix = iio_direction[i];
45 			break;
46 		}
47 
48 	current = strdup(full_name + strlen(prefix) + 1);
49 	working = strtok(current, "_\0");
50 
51 	w = working;
52 	r = working;
53 
54 	while (*r != '\0') {
55 		if (!isdigit(*r)) {
56 			*w = *r;
57 			w++;
58 		}
59 		r++;
60 	}
61 	*w = '\0';
62 	asprintf(generic_name, "%s_%s", prefix, working);
63 	free(current);
64 
65 	return 0;
66 }
67 
68 /**
69  * iioutils_get_type() - find and process _type attribute data
70  * @is_signed: output whether channel is signed
71  * @bytes: output how many bytes the channel storage occupies
72  * @mask: output a bit mask for the raw data
73  * @be: big endian
74  * @device_dir: the iio device directory
75  * @name: the channel name
76  * @generic_name: the channel type name
77  **/
78 int iioutils_get_type(unsigned *is_signed,
79 			     unsigned *bytes,
80 			     unsigned *bits_used,
81 			     unsigned *shift,
82 			     uint64_t *mask,
83 			     unsigned *be,
84 			     const char *device_dir,
85 			     const char *name,
86 			     const char *generic_name)
87 {
88 	FILE *sysfsfp;
89 	int ret;
90 	DIR *dp;
91 	char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;
92 	char signchar, endianchar;
93 	unsigned padint;
94 	const struct dirent *ent;
95 
96 	ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
97 	if (ret < 0) {
98 		ret = -ENOMEM;
99 		goto error_ret;
100 	}
101 	ret = asprintf(&builtname, FORMAT_TYPE_FILE, name);
102 	if (ret < 0) {
103 		ret = -ENOMEM;
104 		goto error_free_scan_el_dir;
105 	}
106 	ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name);
107 	if (ret < 0) {
108 		ret = -ENOMEM;
109 		goto error_free_builtname;
110 	}
111 
112 	dp = opendir(scan_el_dir);
113 	if (dp == NULL) {
114 		ret = -errno;
115 		goto error_free_builtname_generic;
116 	}
117 	while (ent = readdir(dp), ent != NULL)
118 		/*
119 		 * Do we allow devices to override a generic name with
120 		 * a specific one?
121 		 */
122 		if ((strcmp(builtname, ent->d_name) == 0) ||
123 		    (strcmp(builtname_generic, ent->d_name) == 0)) {
124 			ret = asprintf(&filename,
125 				       "%s/%s", scan_el_dir, ent->d_name);
126 			if (ret < 0) {
127 				ret = -ENOMEM;
128 				goto error_closedir;
129 			}
130 			sysfsfp = fopen(filename, "r");
131 			if (sysfsfp == NULL) {
132 				printf("failed to open %s\n", filename);
133 				ret = -errno;
134 				goto error_free_filename;
135 			}
136 
137 			ret = fscanf(sysfsfp,
138 				     "%ce:%c%u/%u>>%u",
139 				     &endianchar,
140 				     &signchar,
141 				     bits_used,
142 				     &padint, shift);
143 			if (ret < 0) {
144 				printf("failed to pass scan type description\n");
145 				ret = -errno;
146 				goto error_close_sysfsfp;
147 			}
148 			*be = (endianchar == 'b');
149 			*bytes = padint / 8;
150 			if (*bits_used == 64)
151 				*mask = ~0;
152 			else
153 				*mask = (1 << *bits_used) - 1;
154 			if (signchar == 's')
155 				*is_signed = 1;
156 			else
157 				*is_signed = 0;
158 			fclose(sysfsfp);
159 			free(filename);
160 
161 			filename = 0;
162 			sysfsfp = 0;
163 		}
164 error_close_sysfsfp:
165 	if (sysfsfp)
166 		fclose(sysfsfp);
167 error_free_filename:
168 	if (filename)
169 		free(filename);
170 error_closedir:
171 	closedir(dp);
172 error_free_builtname_generic:
173 	free(builtname_generic);
174 error_free_builtname:
175 	free(builtname);
176 error_free_scan_el_dir:
177 	free(scan_el_dir);
178 error_ret:
179 	return ret;
180 }
181 
182 int iioutils_get_param_float(float *output,
183 				    const char *param_name,
184 				    const char *device_dir,
185 				    const char *name,
186 				    const char *generic_name)
187 {
188 	FILE *sysfsfp;
189 	int ret;
190 	DIR *dp;
191 	char *builtname, *builtname_generic;
192 	char *filename = NULL;
193 	const struct dirent *ent;
194 
195 	ret = asprintf(&builtname, "%s_%s", name, param_name);
196 	if (ret < 0) {
197 		ret = -ENOMEM;
198 		goto error_ret;
199 	}
200 	ret = asprintf(&builtname_generic,
201 		       "%s_%s", generic_name, param_name);
202 	if (ret < 0) {
203 		ret = -ENOMEM;
204 		goto error_free_builtname;
205 	}
206 	dp = opendir(device_dir);
207 	if (dp == NULL) {
208 		ret = -errno;
209 		goto error_free_builtname_generic;
210 	}
211 	while (ent = readdir(dp), ent != NULL)
212 		if ((strcmp(builtname, ent->d_name) == 0) ||
213 		    (strcmp(builtname_generic, ent->d_name) == 0)) {
214 			ret = asprintf(&filename,
215 				       "%s/%s", device_dir, ent->d_name);
216 			if (ret < 0) {
217 				ret = -ENOMEM;
218 				goto error_closedir;
219 			}
220 			sysfsfp = fopen(filename, "r");
221 			if (!sysfsfp) {
222 				ret = -errno;
223 				goto error_free_filename;
224 			}
225 			fscanf(sysfsfp, "%f", output);
226 			break;
227 		}
228 error_free_filename:
229 	if (filename)
230 		free(filename);
231 error_closedir:
232 	closedir(dp);
233 error_free_builtname_generic:
234 	free(builtname_generic);
235 error_free_builtname:
236 	free(builtname);
237 error_ret:
238 	return ret;
239 }
240 
241 /**
242  * bsort_channel_array_by_index() - reorder so that the array is in index order
243  *
244  **/
245 
246 void bsort_channel_array_by_index(struct iio_channel_info **ci_array,
247 					 int cnt)
248 {
249 
250 	struct iio_channel_info temp;
251 	int x, y;
252 
253 	for (x = 0; x < cnt; x++)
254 		for (y = 0; y < (cnt - 1); y++)
255 			if ((*ci_array)[y].index > (*ci_array)[y+1].index) {
256 				temp = (*ci_array)[y + 1];
257 				(*ci_array)[y + 1] = (*ci_array)[y];
258 				(*ci_array)[y] = temp;
259 			}
260 }
261 
262 /**
263  * build_channel_array() - function to figure out what channels are present
264  * @device_dir: the IIO device directory in sysfs
265  * @
266  **/
267 int build_channel_array(const char *device_dir,
268 			      struct iio_channel_info **ci_array,
269 			      int *counter)
270 {
271 	DIR *dp;
272 	FILE *sysfsfp;
273 	int count, i;
274 	struct iio_channel_info *current;
275 	int ret;
276 	const struct dirent *ent;
277 	char *scan_el_dir;
278 	char *filename;
279 
280 	*counter = 0;
281 	ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
282 	if (ret < 0) {
283 		ret = -ENOMEM;
284 		goto error_ret;
285 	}
286 	dp = opendir(scan_el_dir);
287 	if (dp == NULL) {
288 		ret = -errno;
289 		goto error_free_name;
290 	}
291 	while (ent = readdir(dp), ent != NULL)
292 		if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
293 			   "_en") == 0) {
294 			ret = asprintf(&filename,
295 				       "%s/%s", scan_el_dir, ent->d_name);
296 			if (ret < 0) {
297 				ret = -ENOMEM;
298 				goto error_close_dir;
299 			}
300 			sysfsfp = fopen(filename, "r");
301 			if (sysfsfp == NULL) {
302 				ret = -errno;
303 				free(filename);
304 				goto error_close_dir;
305 			}
306 			fscanf(sysfsfp, "%i", &ret);
307 			if (ret == 1)
308 				(*counter)++;
309 			fclose(sysfsfp);
310 			free(filename);
311 		}
312 	*ci_array = malloc(sizeof(**ci_array) * (*counter));
313 	if (*ci_array == NULL) {
314 		ret = -ENOMEM;
315 		goto error_close_dir;
316 	}
317 	seekdir(dp, 0);
318 	count = 0;
319 	while (ent = readdir(dp), ent != NULL) {
320 		if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
321 			   "_en") == 0) {
322 			int current_enabled = 0;
323 
324 			current = &(*ci_array)[count++];
325 			ret = asprintf(&filename,
326 				       "%s/%s", scan_el_dir, ent->d_name);
327 			if (ret < 0) {
328 				ret = -ENOMEM;
329 				/* decrement count to avoid freeing name */
330 				count--;
331 				goto error_cleanup_array;
332 			}
333 			sysfsfp = fopen(filename, "r");
334 			if (sysfsfp == NULL) {
335 				free(filename);
336 				ret = -errno;
337 				goto error_cleanup_array;
338 			}
339 			fscanf(sysfsfp, "%i", &current_enabled);
340 			fclose(sysfsfp);
341 
342 			if (!current_enabled) {
343 				free(filename);
344 				count--;
345 				continue;
346 			}
347 
348 			current->scale = 1.0;
349 			current->offset = 0;
350 			current->name = strndup(ent->d_name,
351 						strlen(ent->d_name) -
352 						strlen("_en"));
353 			if (current->name == NULL) {
354 				free(filename);
355 				ret = -ENOMEM;
356 				goto error_cleanup_array;
357 			}
358 			/* Get the generic and specific name elements */
359 			ret = iioutils_break_up_name(current->name,
360 						     &current->generic_name);
361 			if (ret) {
362 				free(filename);
363 				goto error_cleanup_array;
364 			}
365 			ret = asprintf(&filename,
366 				       "%s/%s_index",
367 				       scan_el_dir,
368 				       current->name);
369 			if (ret < 0) {
370 				free(filename);
371 				ret = -ENOMEM;
372 				goto error_cleanup_array;
373 			}
374 			sysfsfp = fopen(filename, "r");
375 			fscanf(sysfsfp, "%u", &current->index);
376 			fclose(sysfsfp);
377 			free(filename);
378 			/* Find the scale */
379 			ret = iioutils_get_param_float(&current->scale,
380 						       "scale",
381 						       device_dir,
382 						       current->name,
383 						       current->generic_name);
384 			if (ret < 0)
385 				goto error_cleanup_array;
386 			ret = iioutils_get_param_float(&current->offset,
387 						       "offset",
388 						       device_dir,
389 						       current->name,
390 						       current->generic_name);
391 			if (ret < 0)
392 				goto error_cleanup_array;
393 			ret = iioutils_get_type(&current->is_signed,
394 						&current->bytes,
395 						&current->bits_used,
396 						&current->shift,
397 						&current->mask,
398 						&current->be,
399 						device_dir,
400 						current->name,
401 						current->generic_name);
402 		}
403 	}
404 
405 	closedir(dp);
406 	/* reorder so that the array is in index order */
407 	bsort_channel_array_by_index(ci_array, *counter);
408 
409 	return 0;
410 
411 error_cleanup_array:
412 	for (i = count - 1;  i >= 0; i--)
413 		free((*ci_array)[i].name);
414 	free(*ci_array);
415 error_close_dir:
416 	closedir(dp);
417 error_free_name:
418 	free(scan_el_dir);
419 error_ret:
420 	return ret;
421 }
422 
423 /**
424  * find_type_by_name() - function to match top level types by name
425  * @name: top level type instance name
426  * @type: the type of top level instance being sort
427  *
428  * Typical types this is used for are device and trigger.
429  **/
430 int find_type_by_name(const char *name, const char *type)
431 {
432 	const struct dirent *ent;
433 	int number, numstrlen;
434 
435 	FILE *nameFile;
436 	DIR *dp;
437 	char thisname[IIO_MAX_NAME_LENGTH];
438 	char *filename;
439 
440 	dp = opendir(iio_dir);
441 	if (dp == NULL) {
442 		printf("No industrialio devices available\n");
443 		return -ENODEV;
444 	}
445 
446 	while (ent = readdir(dp), ent != NULL) {
447 		if (strcmp(ent->d_name, ".") != 0 &&
448 			strcmp(ent->d_name, "..") != 0 &&
449 			strlen(ent->d_name) > strlen(type) &&
450 			strncmp(ent->d_name, type, strlen(type)) == 0) {
451 			numstrlen = sscanf(ent->d_name + strlen(type),
452 					   "%d",
453 					   &number);
454 			/* verify the next character is not a colon */
455 			if (strncmp(ent->d_name + strlen(type) + numstrlen,
456 					":",
457 					1) != 0) {
458 				filename = malloc(strlen(iio_dir)
459 						+ strlen(type)
460 						+ numstrlen
461 						+ 6);
462 				if (filename == NULL) {
463 					closedir(dp);
464 					return -ENOMEM;
465 				}
466 				sprintf(filename, "%s%s%d/name",
467 					iio_dir,
468 					type,
469 					number);
470 				nameFile = fopen(filename, "r");
471 				if (!nameFile) {
472 					free(filename);
473 					continue;
474 				}
475 				free(filename);
476 				fscanf(nameFile, "%s", thisname);
477 				fclose(nameFile);
478 				if (strcmp(name, thisname) == 0) {
479 					closedir(dp);
480 					return number;
481 				}
482 			}
483 		}
484 	}
485 	closedir(dp);
486 	return -ENODEV;
487 }
488 
489 int _write_sysfs_int(char *filename, char *basedir, int val, int verify)
490 {
491 	int ret = 0;
492 	FILE *sysfsfp;
493 	int test;
494 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
495 
496 	if (temp == NULL)
497 		return -ENOMEM;
498 	sprintf(temp, "%s/%s", basedir, filename);
499 	sysfsfp = fopen(temp, "w");
500 	if (sysfsfp == NULL) {
501 		printf("failed to open %s\n", temp);
502 		ret = -errno;
503 		goto error_free;
504 	}
505 	fprintf(sysfsfp, "%d", val);
506 	fclose(sysfsfp);
507 	if (verify) {
508 		sysfsfp = fopen(temp, "r");
509 		if (sysfsfp == NULL) {
510 			printf("failed to open %s\n", temp);
511 			ret = -errno;
512 			goto error_free;
513 		}
514 		fscanf(sysfsfp, "%d", &test);
515 		fclose(sysfsfp);
516 		if (test != val) {
517 			printf("Possible failure in int write %d to %s%s\n",
518 				val,
519 				basedir,
520 				filename);
521 			ret = -1;
522 		}
523 	}
524 error_free:
525 	free(temp);
526 	return ret;
527 }
528 
529 int write_sysfs_int(char *filename, char *basedir, int val)
530 {
531 	return _write_sysfs_int(filename, basedir, val, 0);
532 }
533 
534 int write_sysfs_int_and_verify(char *filename, char *basedir, int val)
535 {
536 	return _write_sysfs_int(filename, basedir, val, 1);
537 }
538 
539 int _write_sysfs_string(char *filename, char *basedir, char *val, int verify)
540 {
541 	int ret = 0;
542 	FILE  *sysfsfp;
543 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
544 
545 	if (temp == NULL) {
546 		printf("Memory allocation failed\n");
547 		return -ENOMEM;
548 	}
549 	sprintf(temp, "%s/%s", basedir, filename);
550 	sysfsfp = fopen(temp, "w");
551 	if (sysfsfp == NULL) {
552 		printf("Could not open %s\n", temp);
553 		ret = -errno;
554 		goto error_free;
555 	}
556 	fprintf(sysfsfp, "%s", val);
557 	fclose(sysfsfp);
558 	if (verify) {
559 		sysfsfp = fopen(temp, "r");
560 		if (sysfsfp == NULL) {
561 			printf("could not open file to verify\n");
562 			ret = -errno;
563 			goto error_free;
564 		}
565 		fscanf(sysfsfp, "%s", temp);
566 		fclose(sysfsfp);
567 		if (strcmp(temp, val) != 0) {
568 			printf("Possible failure in string write of %s "
569 				"Should be %s "
570 				"written to %s\%s\n",
571 				temp,
572 				val,
573 				basedir,
574 				filename);
575 			ret = -1;
576 		}
577 	}
578 error_free:
579 	free(temp);
580 
581 	return ret;
582 }
583 
584 /**
585  * write_sysfs_string_and_verify() - string write, readback and verify
586  * @filename: name of file to write to
587  * @basedir: the sysfs directory in which the file is to be found
588  * @val: the string to write
589  **/
590 int write_sysfs_string_and_verify(char *filename, char *basedir, char *val)
591 {
592 	return _write_sysfs_string(filename, basedir, val, 1);
593 }
594 
595 int write_sysfs_string(char *filename, char *basedir, char *val)
596 {
597 	return _write_sysfs_string(filename, basedir, val, 0);
598 }
599 
600 int read_sysfs_posint(char *filename, char *basedir)
601 {
602 	int ret;
603 	FILE  *sysfsfp;
604 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
605 
606 	if (temp == NULL) {
607 		printf("Memory allocation failed");
608 		return -ENOMEM;
609 	}
610 	sprintf(temp, "%s/%s", basedir, filename);
611 	sysfsfp = fopen(temp, "r");
612 	if (sysfsfp == NULL) {
613 		ret = -errno;
614 		goto error_free;
615 	}
616 	fscanf(sysfsfp, "%d\n", &ret);
617 	fclose(sysfsfp);
618 error_free:
619 	free(temp);
620 	return ret;
621 }
622 
623 int read_sysfs_float(char *filename, char *basedir, float *val)
624 {
625 	int ret = 0;
626 	FILE  *sysfsfp;
627 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
628 
629 	if (temp == NULL) {
630 		printf("Memory allocation failed");
631 		return -ENOMEM;
632 	}
633 	sprintf(temp, "%s/%s", basedir, filename);
634 	sysfsfp = fopen(temp, "r");
635 	if (sysfsfp == NULL) {
636 		ret = -errno;
637 		goto error_free;
638 	}
639 	fscanf(sysfsfp, "%f\n", val);
640 	fclose(sysfsfp);
641 error_free:
642 	free(temp);
643 	return ret;
644 }
645 
646 int read_sysfs_string(const char *filename, const char *basedir, char *str)
647 {
648 	int ret = 0;
649 	FILE  *sysfsfp;
650 	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
651 
652 	if (temp == NULL) {
653 		printf("Memory allocation failed");
654 		return -ENOMEM;
655 	}
656 	sprintf(temp, "%s/%s", basedir, filename);
657 	sysfsfp = fopen(temp, "r");
658 	if (sysfsfp == NULL) {
659 		ret = -errno;
660 		goto error_free;
661 	}
662 	fscanf(sysfsfp, "%s\n", str);
663 	fclose(sysfsfp);
664 error_free:
665 	free(temp);
666 	return ret;
667 }
668 
669 #endif /* _IIO_UTILS_H */
670