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