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