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