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