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