blob: 0524725279bb3d675f33049758fc2c4bf921a917 [file] [log] [blame]
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +01001/* 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 */
Cristina Opriceana37e3be92015-03-04 02:37:15 +02009#ifndef _IIO_UTILS_H
10#define _IIO_UTILS_H
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +010011
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +010012#include <string.h>
13#include <stdlib.h>
Jonathan Camerone58537c2010-10-08 12:14:14 +010014#include <stdio.h>
15#include <stdint.h>
Lars-Peter Clausenbc9f35d2011-10-26 17:27:44 +010016#include <dirent.h>
Peter Meerwaldbb233782012-06-25 23:12:17 +020017#include <errno.h>
Roberta Dobrescubdcb31d2015-02-26 10:49:24 +020018#include <ctype.h>
19#include "iio_utils.h"
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +010020
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +010021const char *iio_dir = "/sys/bus/iio/devices/";
22
Irina Tirdead9d7b992015-03-27 13:53:00 +020023static char * const iio_direction[] = {
24 "in",
25 "out",
26};
27
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +010028/**
Jonathan Camerone58537c2010-10-08 12:14:14 +010029 * 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
Hartmut Knaack5dc65d72015-05-31 14:40:16 +020032 *
33 * Returns 0 on success, or a negative error code if string extraction failed.
Jonathan Camerone58537c2010-10-08 12:14:14 +010034 **/
Roberta Dobrescubdcb31d2015-02-26 10:49:24 +020035int iioutils_break_up_name(const char *full_name,
Jonathan Camerone58537c2010-10-08 12:14:14 +010036 char **generic_name)
37{
38 char *current;
39 char *w, *r;
Irina Tirdead9d7b992015-03-27 13:53:00 +020040 char *working, *prefix = "";
Hartmut Knaacke9e45b42015-05-31 14:40:02 +020041 int i, ret;
Melike Yurtoglu79bdd482014-10-03 23:35:54 +030042
Irina Tirdead9d7b992015-03-27 13:53:00 +020043 for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++)
44 if (!strncmp(full_name, iio_direction[i],
45 strlen(iio_direction[i]))) {
46 prefix = iio_direction[i];
47 break;
48 }
49
50 current = strdup(full_name + strlen(prefix) + 1);
Hartmut Knaacke9e45b42015-05-31 14:40:02 +020051 if (!current)
52 return -ENOMEM;
53
Jonathan Camerone58537c2010-10-08 12:14:14 +010054 working = strtok(current, "_\0");
Hartmut Knaack53118552015-05-31 14:40:14 +020055 if (!working) {
56 free(current);
57 return -EINVAL;
58 }
Irina Tirdead9d7b992015-03-27 13:53:00 +020059
Jonathan Camerone58537c2010-10-08 12:14:14 +010060 w = working;
61 r = working;
62
Michael Hennerich8b68bb22011-03-08 08:55:48 +010063 while (*r != '\0') {
Jonathan Camerone58537c2010-10-08 12:14:14 +010064 if (!isdigit(*r)) {
65 *w = *r;
66 w++;
67 }
68 r++;
69 }
70 *w = '\0';
Hartmut Knaacke9e45b42015-05-31 14:40:02 +020071 ret = asprintf(generic_name, "%s_%s", prefix, working);
Jonathan Camerone58537c2010-10-08 12:14:14 +010072 free(current);
73
Hartmut Knaacke9e45b42015-05-31 14:40:02 +020074 return (ret == -1) ? -ENOMEM : 0;
Jonathan Camerone58537c2010-10-08 12:14:14 +010075}
76
77/**
Jonathan Camerone58537c2010-10-08 12:14:14 +010078 * iioutils_get_type() - find and process _type attribute data
79 * @is_signed: output whether channel is signed
80 * @bytes: output how many bytes the channel storage occupies
Hartmut Knaack5dc65d72015-05-31 14:40:16 +020081 * @bits_used: output number of valid bits of data
82 * @shift: output amount of bits to shift right data before applying bit mask
Jonathan Camerone58537c2010-10-08 12:14:14 +010083 * @mask: output a bit mask for the raw data
Hartmut Knaack5dc65d72015-05-31 14:40:16 +020084 * @be: output if data in big endian
85 * @device_dir: the IIO device directory
Jonathan Camerone58537c2010-10-08 12:14:14 +010086 * @name: the channel name
87 * @generic_name: the channel type name
Hartmut Knaack5dc65d72015-05-31 14:40:16 +020088 *
89 * Returns a value >= 0 on success, otherwise a negative error code.
Jonathan Camerone58537c2010-10-08 12:14:14 +010090 **/
Roberta Dobrescubdcb31d2015-02-26 10:49:24 +020091int iioutils_get_type(unsigned *is_signed,
Jonathan Camerone58537c2010-10-08 12:14:14 +010092 unsigned *bytes,
93 unsigned *bits_used,
Jonathan Cameron52615d42011-05-18 14:41:19 +010094 unsigned *shift,
Jonathan Camerone58537c2010-10-08 12:14:14 +010095 uint64_t *mask,
Jonathan Cameron117cf8b2011-12-04 19:10:59 +000096 unsigned *be,
Jonathan Camerone58537c2010-10-08 12:14:14 +010097 const char *device_dir,
98 const char *name,
99 const char *generic_name)
100{
101 FILE *sysfsfp;
102 int ret;
103 DIR *dp;
104 char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;
Jonathan Cameron117cf8b2011-12-04 19:10:59 +0000105 char signchar, endianchar;
Michael Hennerichfc7f95a2011-02-24 16:34:54 +0100106 unsigned padint;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100107 const struct dirent *ent;
108
109 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
Hartmut Knaack0e799872015-05-31 14:40:17 +0200110 if (ret < 0)
111 return -ENOMEM;
112
Jonathan Camerone58537c2010-10-08 12:14:14 +0100113 ret = asprintf(&builtname, FORMAT_TYPE_FILE, name);
114 if (ret < 0) {
115 ret = -ENOMEM;
116 goto error_free_scan_el_dir;
117 }
118 ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name);
119 if (ret < 0) {
120 ret = -ENOMEM;
121 goto error_free_builtname;
122 }
123
124 dp = opendir(scan_el_dir);
125 if (dp == NULL) {
126 ret = -errno;
127 goto error_free_builtname_generic;
128 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200129 ret = -ENOENT;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100130 while (ent = readdir(dp), ent != NULL)
131 /*
132 * Do we allow devices to override a generic name with
133 * a specific one?
134 */
135 if ((strcmp(builtname, ent->d_name) == 0) ||
136 (strcmp(builtname_generic, ent->d_name) == 0)) {
137 ret = asprintf(&filename,
138 "%s/%s", scan_el_dir, ent->d_name);
139 if (ret < 0) {
140 ret = -ENOMEM;
141 goto error_closedir;
142 }
143 sysfsfp = fopen(filename, "r");
144 if (sysfsfp == NULL) {
Jonathan Camerone58537c2010-10-08 12:14:14 +0100145 ret = -errno;
Hartmut Knaack2b6a6e62015-05-31 14:39:48 +0200146 printf("failed to open %s\n", filename);
Jonathan Camerone58537c2010-10-08 12:14:14 +0100147 goto error_free_filename;
148 }
Jonathan Camerona7f7c362011-12-04 19:10:58 +0000149
150 ret = fscanf(sysfsfp,
151 "%ce:%c%u/%u>>%u",
152 &endianchar,
153 &signchar,
154 bits_used,
155 &padint, shift);
156 if (ret < 0) {
Peter Meerwald578f7372012-06-25 23:13:24 +0200157 ret = -errno;
Hartmut Knaack2b6a6e62015-05-31 14:39:48 +0200158 printf("failed to pass scan type description\n");
Peter Meerwald578f7372012-06-25 23:13:24 +0200159 goto error_close_sysfsfp;
Hartmut Knaackdc8b5d62015-05-31 14:39:59 +0200160 } else if (ret != 5) {
161 ret = -EIO;
162 printf("scan type description didn't match\n");
163 goto error_close_sysfsfp;
Jonathan Camerona7f7c362011-12-04 19:10:58 +0000164 }
Jonathan Cameron117cf8b2011-12-04 19:10:59 +0000165 *be = (endianchar == 'b');
Jonathan Camerone58537c2010-10-08 12:14:14 +0100166 *bytes = padint / 8;
Michael Hennerichfc7f95a2011-02-24 16:34:54 +0100167 if (*bits_used == 64)
Jonathan Camerone58537c2010-10-08 12:14:14 +0100168 *mask = ~0;
169 else
170 *mask = (1 << *bits_used) - 1;
171 if (signchar == 's')
172 *is_signed = 1;
173 else
174 *is_signed = 0;
Hartmut Knaack53118552015-05-31 14:40:14 +0200175 if (fclose(sysfsfp)) {
176 ret = -errno;
177 printf("Failed to close %s\n", filename);
178 goto error_free_filename;
179 }
180
Jonathan Camerona7f7c362011-12-04 19:10:58 +0000181 free(filename);
182
183 filename = 0;
Peter Meerwald578f7372012-06-25 23:13:24 +0200184 sysfsfp = 0;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100185 }
Peter Meerwald578f7372012-06-25 23:13:24 +0200186error_close_sysfsfp:
187 if (sysfsfp)
Hartmut Knaack53118552015-05-31 14:40:14 +0200188 if (fclose(sysfsfp))
189 perror("iioutils_get_type(): Failed to close file");
190
Jonathan Camerone58537c2010-10-08 12:14:14 +0100191error_free_filename:
192 if (filename)
193 free(filename);
194error_closedir:
Hartmut Knaack53118552015-05-31 14:40:14 +0200195 if (closedir(dp) == -1)
196 perror("iioutils_get_type(): Failed to close directory");
197
Jonathan Camerone58537c2010-10-08 12:14:14 +0100198error_free_builtname_generic:
199 free(builtname_generic);
200error_free_builtname:
201 free(builtname);
202error_free_scan_el_dir:
203 free(scan_el_dir);
Hartmut Knaack0e799872015-05-31 14:40:17 +0200204
Jonathan Camerone58537c2010-10-08 12:14:14 +0100205 return ret;
206}
207
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200208/**
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 **/
Roberta Dobrescubdcb31d2015-02-26 10:49:24 +0200218int iioutils_get_param_float(float *output,
Jonathan Camerone58537c2010-10-08 12:14:14 +0100219 const char *param_name,
220 const char *device_dir,
221 const char *name,
222 const char *generic_name)
223{
224 FILE *sysfsfp;
225 int ret;
226 DIR *dp;
227 char *builtname, *builtname_generic;
228 char *filename = NULL;
229 const struct dirent *ent;
230
231 ret = asprintf(&builtname, "%s_%s", name, param_name);
Hartmut Knaack0e799872015-05-31 14:40:17 +0200232 if (ret < 0)
233 return -ENOMEM;
234
Jonathan Camerone58537c2010-10-08 12:14:14 +0100235 ret = asprintf(&builtname_generic,
236 "%s_%s", generic_name, param_name);
237 if (ret < 0) {
238 ret = -ENOMEM;
239 goto error_free_builtname;
240 }
241 dp = opendir(device_dir);
242 if (dp == NULL) {
243 ret = -errno;
244 goto error_free_builtname_generic;
245 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200246 ret = -ENOENT;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100247 while (ent = readdir(dp), ent != NULL)
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 sysfsfp = fopen(filename, "r");
257 if (!sysfsfp) {
258 ret = -errno;
259 goto error_free_filename;
260 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200261 errno = 0;
262 if (fscanf(sysfsfp, "%f", output) != 1)
263 ret = errno ? -errno : -ENODATA;
264
Jonathan Camerone58537c2010-10-08 12:14:14 +0100265 break;
266 }
267error_free_filename:
268 if (filename)
269 free(filename);
270error_closedir:
Hartmut Knaack53118552015-05-31 14:40:14 +0200271 if (closedir(dp) == -1)
272 perror("iioutils_get_param_float(): Failed to close directory");
273
Jonathan Camerone58537c2010-10-08 12:14:14 +0100274error_free_builtname_generic:
275 free(builtname_generic);
276error_free_builtname:
277 free(builtname);
Hartmut Knaack0e799872015-05-31 14:40:17 +0200278
Jonathan Camerone58537c2010-10-08 12:14:14 +0100279 return ret;
280}
281
Michael Hennerich8b68bb22011-03-08 08:55:48 +0100282/**
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200283 * bsort_channel_array_by_index() - sort the array in index order
284 * @ci_array: the iio_channel_info array to be sorted
285 * @cnt: the amount of array elements
Michael Hennerich8b68bb22011-03-08 08:55:48 +0100286 **/
287
Roberta Dobrescubdcb31d2015-02-26 10:49:24 +0200288void bsort_channel_array_by_index(struct iio_channel_info **ci_array,
Michael Hennerich8b68bb22011-03-08 08:55:48 +0100289 int cnt)
290{
291
292 struct iio_channel_info temp;
293 int x, y;
294
295 for (x = 0; x < cnt; x++)
296 for (y = 0; y < (cnt - 1); y++)
297 if ((*ci_array)[y].index > (*ci_array)[y+1].index) {
298 temp = (*ci_array)[y + 1];
299 (*ci_array)[y + 1] = (*ci_array)[y];
300 (*ci_array)[y] = temp;
301 }
302}
Jonathan Camerone58537c2010-10-08 12:14:14 +0100303
304/**
305 * build_channel_array() - function to figure out what channels are present
306 * @device_dir: the IIO device directory in sysfs
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200307 * @ci_array: output the resulting array of iio_channel_info
308 * @counter: output the amount of array elements
309 *
310 * Returns 0 on success, otherwise a negative error code.
Jonathan Camerone58537c2010-10-08 12:14:14 +0100311 **/
Roberta Dobrescubdcb31d2015-02-26 10:49:24 +0200312int build_channel_array(const char *device_dir,
Jonathan Camerone58537c2010-10-08 12:14:14 +0100313 struct iio_channel_info **ci_array,
314 int *counter)
315{
316 DIR *dp;
317 FILE *sysfsfp;
Peter Meerwald10937922012-06-25 23:12:12 +0200318 int count, i;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100319 struct iio_channel_info *current;
320 int ret;
321 const struct dirent *ent;
322 char *scan_el_dir;
323 char *filename;
324
325 *counter = 0;
326 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
Hartmut Knaack0e799872015-05-31 14:40:17 +0200327 if (ret < 0)
328 return -ENOMEM;
329
Jonathan Camerone58537c2010-10-08 12:14:14 +0100330 dp = opendir(scan_el_dir);
331 if (dp == NULL) {
332 ret = -errno;
333 goto error_free_name;
334 }
335 while (ent = readdir(dp), ent != NULL)
336 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
337 "_en") == 0) {
338 ret = asprintf(&filename,
339 "%s/%s", scan_el_dir, ent->d_name);
340 if (ret < 0) {
341 ret = -ENOMEM;
342 goto error_close_dir;
343 }
344 sysfsfp = fopen(filename, "r");
345 if (sysfsfp == NULL) {
346 ret = -errno;
347 free(filename);
348 goto error_close_dir;
349 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200350 errno = 0;
351 if (fscanf(sysfsfp, "%i", &ret) != 1) {
352 ret = errno ? -errno : -ENODATA;
353 if (fclose(sysfsfp))
354 perror("build_channel_array(): Failed to close file");
355
356 free(filename);
357 goto error_close_dir;
358 }
359
Jonathan Camerone58537c2010-10-08 12:14:14 +0100360 if (ret == 1)
361 (*counter)++;
Hartmut Knaack53118552015-05-31 14:40:14 +0200362 if (fclose(sysfsfp)) {
363 ret = -errno;
364 free(filename);
365 goto error_close_dir;
366 }
367
Jonathan Camerone58537c2010-10-08 12:14:14 +0100368 free(filename);
369 }
Michael Hennerich8b68bb22011-03-08 08:55:48 +0100370 *ci_array = malloc(sizeof(**ci_array) * (*counter));
Jonathan Camerone58537c2010-10-08 12:14:14 +0100371 if (*ci_array == NULL) {
372 ret = -ENOMEM;
373 goto error_close_dir;
374 }
375 seekdir(dp, 0);
Michael Hennerich7ccd4502011-02-24 16:34:53 +0100376 count = 0;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100377 while (ent = readdir(dp), ent != NULL) {
378 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
379 "_en") == 0) {
Craig Markwardt66c65d92014-01-01 15:38:52 +0000380 int current_enabled = 0;
Melike Yurtoglu79bdd482014-10-03 23:35:54 +0300381
Jonathan Camerone58537c2010-10-08 12:14:14 +0100382 current = &(*ci_array)[count++];
383 ret = asprintf(&filename,
384 "%s/%s", scan_el_dir, ent->d_name);
385 if (ret < 0) {
386 ret = -ENOMEM;
387 /* decrement count to avoid freeing name */
388 count--;
389 goto error_cleanup_array;
390 }
391 sysfsfp = fopen(filename, "r");
392 if (sysfsfp == NULL) {
Jonathan Camerone58537c2010-10-08 12:14:14 +0100393 ret = -errno;
Hartmut Knaack2b6a6e62015-05-31 14:39:48 +0200394 free(filename);
Hartmut Knaack121b5e52015-05-31 14:39:45 +0200395 count--;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100396 goto error_cleanup_array;
397 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200398 errno = 0;
399 if (fscanf(sysfsfp, "%i", &current_enabled) != 1) {
400 ret = errno ? -errno : -ENODATA;
401 free(filename);
402 count--;
403 goto error_cleanup_array;
404 }
405
406 if (fclose(sysfsfp)) {
407 ret = -errno;
408 free(filename);
409 count--;
410 goto error_cleanup_array;
411 }
Michael Hennerich8b68bb22011-03-08 08:55:48 +0100412
Craig Markwardt66c65d92014-01-01 15:38:52 +0000413 if (!current_enabled) {
Michael Hennerich8b68bb22011-03-08 08:55:48 +0100414 free(filename);
415 count--;
416 continue;
417 }
418
Jonathan Camerone58537c2010-10-08 12:14:14 +0100419 current->scale = 1.0;
420 current->offset = 0;
421 current->name = strndup(ent->d_name,
422 strlen(ent->d_name) -
423 strlen("_en"));
424 if (current->name == NULL) {
425 free(filename);
426 ret = -ENOMEM;
Hartmut Knaack121b5e52015-05-31 14:39:45 +0200427 count--;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100428 goto error_cleanup_array;
429 }
430 /* Get the generic and specific name elements */
431 ret = iioutils_break_up_name(current->name,
432 &current->generic_name);
433 if (ret) {
434 free(filename);
Hartmut Knaack121b5e52015-05-31 14:39:45 +0200435 free(current->name);
436 count--;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100437 goto error_cleanup_array;
438 }
439 ret = asprintf(&filename,
440 "%s/%s_index",
441 scan_el_dir,
442 current->name);
443 if (ret < 0) {
444 free(filename);
445 ret = -ENOMEM;
446 goto error_cleanup_array;
447 }
448 sysfsfp = fopen(filename, "r");
Hartmut Knaack53118552015-05-31 14:40:14 +0200449 if (sysfsfp == NULL) {
450 ret = -errno;
451 printf("failed to open %s\n", filename);
452 free(filename);
453 goto error_cleanup_array;
454 }
455
456 errno = 0;
457 if (fscanf(sysfsfp, "%u", &current->index) != 1) {
458 ret = errno ? -errno : -ENODATA;
459 if (fclose(sysfsfp))
460 perror("build_channel_array(): Failed to close file");
461
462 free(filename);
463 goto error_cleanup_array;
464 }
465
466 if (fclose(sysfsfp)) {
467 ret = -errno;
468 free(filename);
469 goto error_cleanup_array;
470 }
471
Jonathan Camerone58537c2010-10-08 12:14:14 +0100472 free(filename);
473 /* Find the scale */
474 ret = iioutils_get_param_float(&current->scale,
475 "scale",
476 device_dir,
477 current->name,
478 current->generic_name);
479 if (ret < 0)
480 goto error_cleanup_array;
481 ret = iioutils_get_param_float(&current->offset,
482 "offset",
483 device_dir,
484 current->name,
485 current->generic_name);
486 if (ret < 0)
487 goto error_cleanup_array;
488 ret = iioutils_get_type(&current->is_signed,
489 &current->bytes,
490 &current->bits_used,
Jonathan Cameron52615d42011-05-18 14:41:19 +0100491 &current->shift,
Jonathan Camerone58537c2010-10-08 12:14:14 +0100492 &current->mask,
Jonathan Cameron117cf8b2011-12-04 19:10:59 +0000493 &current->be,
Jonathan Camerone58537c2010-10-08 12:14:14 +0100494 device_dir,
495 current->name,
496 current->generic_name);
Hartmut Knaack53118552015-05-31 14:40:14 +0200497 if (ret < 0)
498 goto error_cleanup_array;
Jonathan Camerone58537c2010-10-08 12:14:14 +0100499 }
500 }
Michael Hennerich8b68bb22011-03-08 08:55:48 +0100501
Hartmut Knaack53118552015-05-31 14:40:14 +0200502 if (closedir(dp) == -1) {
503 ret = -errno;
504 goto error_cleanup_array;
505 }
506
Hartmut Knaack66dd08f2015-05-31 14:39:43 +0200507 free(scan_el_dir);
Michael Hennerich8b68bb22011-03-08 08:55:48 +0100508 /* reorder so that the array is in index order */
509 bsort_channel_array_by_index(ci_array, *counter);
Jonathan Camerone58537c2010-10-08 12:14:14 +0100510
511 return 0;
512
513error_cleanup_array:
Hartmut Knaack63f05c82015-05-31 14:39:44 +0200514 for (i = count - 1; i >= 0; i--) {
Jonathan Camerone58537c2010-10-08 12:14:14 +0100515 free((*ci_array)[i].name);
Hartmut Knaack63f05c82015-05-31 14:39:44 +0200516 free((*ci_array)[i].generic_name);
517 }
Jonathan Camerone58537c2010-10-08 12:14:14 +0100518 free(*ci_array);
519error_close_dir:
Hartmut Knaack53118552015-05-31 14:40:14 +0200520 if (dp)
521 if (closedir(dp) == -1)
522 perror("build_channel_array(): Failed to close dir");
523
Jonathan Camerone58537c2010-10-08 12:14:14 +0100524error_free_name:
525 free(scan_el_dir);
Hartmut Knaack0e799872015-05-31 14:40:17 +0200526
Jonathan Camerone58537c2010-10-08 12:14:14 +0100527 return ret;
528}
529
Hartmut Knaack096f9b82015-05-31 14:40:00 +0200530int calc_digits(int num)
531{
532 int count = 0;
533
534 while (num != 0) {
535 num /= 10;
536 count++;
537 }
538
539 return count;
540}
541
Jonathan Camerone58537c2010-10-08 12:14:14 +0100542/**
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100543 * find_type_by_name() - function to match top level types by name
544 * @name: top level type instance name
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200545 * @type: the type of top level instance being searched
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100546 *
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200547 * Returns the device number of a matched IIO device on success, otherwise a
548 * negative error code.
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100549 * Typical types this is used for are device and trigger.
550 **/
Roberta Dobrescubdcb31d2015-02-26 10:49:24 +0200551int find_type_by_name(const char *name, const char *type)
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100552{
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100553 const struct dirent *ent;
Hartmut Knaack096f9b82015-05-31 14:40:00 +0200554 int number, numstrlen, ret;
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100555
556 FILE *nameFile;
557 DIR *dp;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100558 char thisname[IIO_MAX_NAME_LENGTH];
559 char *filename;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100560
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100561 dp = opendir(iio_dir);
562 if (dp == NULL) {
Peter Meerwaldc866ffc2012-07-01 00:47:41 +0200563 printf("No industrialio devices available\n");
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100564 return -ENODEV;
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100565 }
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100566
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100567 while (ent = readdir(dp), ent != NULL) {
568 if (strcmp(ent->d_name, ".") != 0 &&
569 strcmp(ent->d_name, "..") != 0 &&
570 strlen(ent->d_name) > strlen(type) &&
571 strncmp(ent->d_name, type, strlen(type)) == 0) {
Hartmut Knaack096f9b82015-05-31 14:40:00 +0200572 errno = 0;
573 ret = sscanf(ent->d_name + strlen(type), "%d", &number);
574 if (ret < 0) {
575 ret = -errno;
576 printf("failed to read element number\n");
577 goto error_close_dir;
578 } else if (ret != 1) {
579 ret = -EIO;
580 printf("failed to match element number\n");
581 goto error_close_dir;
582 }
583
584 numstrlen = calc_digits(number);
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100585 /* verify the next character is not a colon */
586 if (strncmp(ent->d_name + strlen(type) + numstrlen,
587 ":",
588 1) != 0) {
589 filename = malloc(strlen(iio_dir)
590 + strlen(type)
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100591 + numstrlen
Barry Songb6ee30a2010-05-25 17:40:04 +0800592 + 6);
Peter Meerwalda4d429e2012-06-25 23:13:25 +0200593 if (filename == NULL) {
Hartmut Knaack53118552015-05-31 14:40:14 +0200594 ret = -ENOMEM;
595 goto error_close_dir;
Peter Meerwalda4d429e2012-06-25 23:13:25 +0200596 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200597
598 ret = sprintf(filename, "%s%s%d/name", iio_dir,
599 type, number);
600 if (ret < 0) {
601 free(filename);
602 goto error_close_dir;
603 }
604
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100605 nameFile = fopen(filename, "r");
Peter Meerwalda4d429e2012-06-25 23:13:25 +0200606 if (!nameFile) {
607 free(filename);
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100608 continue;
Peter Meerwalda4d429e2012-06-25 23:13:25 +0200609 }
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100610 free(filename);
Hartmut Knaack53118552015-05-31 14:40:14 +0200611 errno = 0;
612 if (fscanf(nameFile, "%s", thisname) != 1) {
613 ret = errno ? -errno : -ENODATA;
614 goto error_close_dir;
615 }
616
617 if (fclose(nameFile)) {
618 ret = -errno;
619 goto error_close_dir;
620 }
621
Peter Meerwalda4d429e2012-06-25 23:13:25 +0200622 if (strcmp(name, thisname) == 0) {
Hartmut Knaack53118552015-05-31 14:40:14 +0200623 if (closedir(dp) == -1)
624 return -errno;
Peter Meerwalda4d429e2012-06-25 23:13:25 +0200625 return number;
626 }
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100627 }
628 }
629 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200630 if (closedir(dp) == -1)
631 return -errno;
632
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100633 return -ENODEV;
Hartmut Knaack096f9b82015-05-31 14:40:00 +0200634
635error_close_dir:
636 if (closedir(dp) == -1)
637 perror("find_type_by_name(): Failed to close directory");
638 return ret;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100639}
640
Hartmut Knaack2156b172015-05-31 14:40:01 +0200641static int _write_sysfs_int(char *filename, char *basedir, int val, int verify)
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100642{
Sebastian Andrzej Siewior11cb4542013-10-07 13:42:00 +0100643 int ret = 0;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100644 FILE *sysfsfp;
645 int test;
646 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
Melike Yurtoglu79bdd482014-10-03 23:35:54 +0300647
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100648 if (temp == NULL)
649 return -ENOMEM;
Hartmut Knaack53118552015-05-31 14:40:14 +0200650 ret = sprintf(temp, "%s/%s", basedir, filename);
651 if (ret < 0)
652 goto error_free;
653
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100654 sysfsfp = fopen(temp, "w");
655 if (sysfsfp == NULL) {
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100656 ret = -errno;
Hartmut Knaack2b6a6e62015-05-31 14:39:48 +0200657 printf("failed to open %s\n", temp);
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100658 goto error_free;
659 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200660 ret = fprintf(sysfsfp, "%d", val);
661 if (ret < 0) {
662 if (fclose(sysfsfp))
663 perror("_write_sysfs_int(): Failed to close dir");
664
665 goto error_free;
666 }
667
668 if (fclose(sysfsfp)) {
669 ret = -errno;
670 goto error_free;
671 }
672
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100673 if (verify) {
674 sysfsfp = fopen(temp, "r");
675 if (sysfsfp == NULL) {
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100676 ret = -errno;
Hartmut Knaack2b6a6e62015-05-31 14:39:48 +0200677 printf("failed to open %s\n", temp);
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100678 goto error_free;
679 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200680 if (fscanf(sysfsfp, "%d", &test) != 1) {
681 ret = errno ? -errno : -ENODATA;
682 if (fclose(sysfsfp))
683 perror("_write_sysfs_int(): Failed to close dir");
684
685 goto error_free;
686 }
687
688 if (fclose(sysfsfp)) {
689 ret = -errno;
690 goto error_free;
691 }
692
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100693 if (test != val) {
694 printf("Possible failure in int write %d to %s%s\n",
695 val,
696 basedir,
697 filename);
698 ret = -1;
699 }
700 }
701error_free:
702 free(temp);
703 return ret;
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100704}
705
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200706/**
707 * write_sysfs_int() - write an integer value to a sysfs file
708 * @filename: name of the file to write to
709 * @basedir: the sysfs directory in which the file is to be found
710 * @val: integer value to write to file
711 *
712 * Returns a value >= 0 on success, otherwise a negative error code.
713 **/
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100714int write_sysfs_int(char *filename, char *basedir, int val)
715{
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100716 return _write_sysfs_int(filename, basedir, val, 0);
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100717}
718
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200719/**
720 * write_sysfs_int_and_verify() - write an integer value to a sysfs file
721 * and verify
722 * @filename: name of the file to write to
723 * @basedir: the sysfs directory in which the file is to be found
724 * @val: integer value to write to file
725 *
726 * Returns a value >= 0 on success, otherwise a negative error code.
727 **/
Jonathan Cameroneaf86ff2010-05-04 14:43:04 +0100728int write_sysfs_int_and_verify(char *filename, char *basedir, int val)
729{
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100730 return _write_sysfs_int(filename, basedir, val, 1);
Jonathan Cameroneaf86ff2010-05-04 14:43:04 +0100731}
732
Hartmut Knaack2156b172015-05-31 14:40:01 +0200733static int _write_sysfs_string(char *filename, char *basedir, char *val,
734 int verify)
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100735{
Jonathan Camerone58537c2010-10-08 12:14:14 +0100736 int ret = 0;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100737 FILE *sysfsfp;
738 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
Melike Yurtoglu79bdd482014-10-03 23:35:54 +0300739
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100740 if (temp == NULL) {
741 printf("Memory allocation failed\n");
742 return -ENOMEM;
743 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200744 ret = sprintf(temp, "%s/%s", basedir, filename);
745 if (ret < 0)
746 goto error_free;
747
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100748 sysfsfp = fopen(temp, "w");
749 if (sysfsfp == NULL) {
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100750 ret = -errno;
Hartmut Knaack2b6a6e62015-05-31 14:39:48 +0200751 printf("Could not open %s\n", temp);
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100752 goto error_free;
753 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200754 ret = fprintf(sysfsfp, "%s", val);
755 if (ret < 0) {
756 if (fclose(sysfsfp))
757 perror("_write_sysfs_string(): Failed to close dir");
758
759 goto error_free;
760 }
761
762 if (fclose(sysfsfp)) {
763 ret = -errno;
764 goto error_free;
765 }
766
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100767 if (verify) {
768 sysfsfp = fopen(temp, "r");
769 if (sysfsfp == NULL) {
770 ret = -errno;
Hartmut Knaack2b6a6e62015-05-31 14:39:48 +0200771 printf("could not open file to verify\n");
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100772 goto error_free;
773 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200774 if (fscanf(sysfsfp, "%s", temp) != 1) {
775 ret = errno ? -errno : -ENODATA;
776 if (fclose(sysfsfp))
777 perror("_write_sysfs_string(): Failed to close dir");
778
779 goto error_free;
780 }
781
782 if (fclose(sysfsfp)) {
783 ret = -errno;
784 goto error_free;
785 }
786
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100787 if (strcmp(temp, val) != 0) {
788 printf("Possible failure in string write of %s "
789 "Should be %s "
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300790 "written to %s\%s\n",
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100791 temp,
792 val,
793 basedir,
794 filename);
795 ret = -1;
796 }
797 }
798error_free:
799 free(temp);
800
801 return ret;
802}
Jonathan Camerone58537c2010-10-08 12:14:14 +0100803
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100804/**
805 * write_sysfs_string_and_verify() - string write, readback and verify
806 * @filename: name of file to write to
807 * @basedir: the sysfs directory in which the file is to be found
808 * @val: the string to write
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200809 *
810 * Returns a value >= 0 on success, otherwise a negative error code.
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100811 **/
812int write_sysfs_string_and_verify(char *filename, char *basedir, char *val)
813{
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100814 return _write_sysfs_string(filename, basedir, val, 1);
815}
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100816
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200817/**
818 * write_sysfs_string() - write string to a sysfs file
819 * @filename: name of file to write to
820 * @basedir: the sysfs directory in which the file is to be found
821 * @val: the string to write
822 *
823 * Returns a value >= 0 on success, otherwise a negative error code.
824 **/
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100825int write_sysfs_string(char *filename, char *basedir, char *val)
826{
827 return _write_sysfs_string(filename, basedir, val, 0);
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100828}
829
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200830/**
831 * read_sysfs_posint() - read an integer value from file
832 * @filename: name of file to read from
833 * @basedir: the sysfs directory in which the file is to be found
834 *
835 * Returns the read integer value >= 0 on success, otherwise a negative error
836 * code.
837 **/
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100838int read_sysfs_posint(char *filename, char *basedir)
839{
840 int ret;
841 FILE *sysfsfp;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100842 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
Melike Yurtoglu79bdd482014-10-03 23:35:54 +0300843
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100844 if (temp == NULL) {
845 printf("Memory allocation failed");
846 return -ENOMEM;
847 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200848 ret = sprintf(temp, "%s/%s", basedir, filename);
849 if (ret < 0)
850 goto error_free;
851
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100852 sysfsfp = fopen(temp, "r");
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100853 if (sysfsfp == NULL) {
854 ret = -errno;
855 goto error_free;
856 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200857 errno = 0;
858 if (fscanf(sysfsfp, "%d\n", &ret) != 1) {
859 ret = errno ? -errno : -ENODATA;
860 if (fclose(sysfsfp))
861 perror("read_sysfs_posint(): Failed to close dir");
862
863 goto error_free;
864 }
865
866 if (fclose(sysfsfp))
867 ret = -errno;
868
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100869error_free:
870 free(temp);
871 return ret;
872}
873
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200874/**
875 * read_sysfs_float() - read a float value from file
876 * @filename: name of file to read from
877 * @basedir: the sysfs directory in which the file is to be found
878 * @val: output the read float value
879 *
880 * Returns a value >= 0 on success, otherwise a negative error code.
881 **/
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100882int read_sysfs_float(char *filename, char *basedir, float *val)
883{
Peter Meerwaldf5709d52014-12-06 06:00:00 +0000884 int ret = 0;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100885 FILE *sysfsfp;
886 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
Melike Yurtoglu79bdd482014-10-03 23:35:54 +0300887
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100888 if (temp == NULL) {
889 printf("Memory allocation failed");
890 return -ENOMEM;
891 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200892 ret = sprintf(temp, "%s/%s", basedir, filename);
893 if (ret < 0)
894 goto error_free;
895
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100896 sysfsfp = fopen(temp, "r");
897 if (sysfsfp == NULL) {
898 ret = -errno;
899 goto error_free;
900 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200901 errno = 0;
902 if (fscanf(sysfsfp, "%f\n", val) != 1) {
903 ret = errno ? -errno : -ENODATA;
904 if (fclose(sysfsfp))
905 perror("read_sysfs_float(): Failed to close dir");
906
907 goto error_free;
908 }
909
910 if (fclose(sysfsfp))
911 ret = -errno;
912
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100913error_free:
914 free(temp);
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100915 return ret;
916}
Manuel Stahl49d916e2014-05-02 13:23:00 +0100917
Hartmut Knaack5dc65d72015-05-31 14:40:16 +0200918/**
919 * read_sysfs_string() - read a string from file
920 * @filename: name of file to read from
921 * @basedir: the sysfs directory in which the file is to be found
922 * @str: output the read string
923 *
924 * Returns a value >= 0 on success, otherwise a negative error code.
925 **/
Peter Meerwaldf5709d52014-12-06 06:00:00 +0000926int read_sysfs_string(const char *filename, const char *basedir, char *str)
Manuel Stahl49d916e2014-05-02 13:23:00 +0100927{
Peter Meerwaldf5709d52014-12-06 06:00:00 +0000928 int ret = 0;
Manuel Stahl49d916e2014-05-02 13:23:00 +0100929 FILE *sysfsfp;
930 char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
Melike Yurtoglu79bdd482014-10-03 23:35:54 +0300931
Manuel Stahl49d916e2014-05-02 13:23:00 +0100932 if (temp == NULL) {
933 printf("Memory allocation failed");
934 return -ENOMEM;
935 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200936 ret = sprintf(temp, "%s/%s", basedir, filename);
937 if (ret < 0)
938 goto error_free;
939
Manuel Stahl49d916e2014-05-02 13:23:00 +0100940 sysfsfp = fopen(temp, "r");
941 if (sysfsfp == NULL) {
942 ret = -errno;
943 goto error_free;
944 }
Hartmut Knaack53118552015-05-31 14:40:14 +0200945 errno = 0;
946 if (fscanf(sysfsfp, "%s\n", str) != 1) {
947 ret = errno ? -errno : -ENODATA;
948 if (fclose(sysfsfp))
949 perror("read_sysfs_string(): Failed to close dir");
950
951 goto error_free;
952 }
953
954 if (fclose(sysfsfp))
955 ret = -errno;
956
Manuel Stahl49d916e2014-05-02 13:23:00 +0100957error_free:
958 free(temp);
959 return ret;
960}
Cristina Opriceana37e3be92015-03-04 02:37:15 +0200961
962#endif /* _IIO_UTILS_H */