Merge tag 'iio-for-4.1a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio...
[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 /**
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  **/
28 int iioutils_break_up_name(const char *full_name,
29                                   char **generic_name)
30 {
31         char *current;
32         char *w, *r;
33         char *working;
34
35         current = strdup(full_name);
36         working = strtok(current, "_\0");
37         w = working;
38         r = working;
39
40         while (*r != '\0') {
41                 if (!isdigit(*r)) {
42                         *w = *r;
43                         w++;
44                 }
45                 r++;
46         }
47         *w = '\0';
48         *generic_name = strdup(working);
49         free(current);
50
51         return 0;
52 }
53
54 /**
55  * 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
59  * @be: big endian
60  * @device_dir: the iio device directory
61  * @name: the channel name
62  * @generic_name: the channel type name
63  **/
64 int iioutils_get_type(unsigned *is_signed,
65                              unsigned *bytes,
66                              unsigned *bits_used,
67                              unsigned *shift,
68                              uint64_t *mask,
69                              unsigned *be,
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;
78         char signchar, endianchar;
79         unsigned padint;
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                         }
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");
131                                 ret = -errno;
132                                 goto error_close_sysfsfp;
133                         }
134                         *be = (endianchar == 'b');
135                         *bytes = padint / 8;
136                         if (*bits_used == 64)
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;
144                         fclose(sysfsfp);
145                         free(filename);
146
147                         filename = 0;
148                         sysfsfp = 0;
149                 }
150 error_close_sysfsfp:
151         if (sysfsfp)
152                 fclose(sysfsfp);
153 error_free_filename:
154         if (filename)
155                 free(filename);
156 error_closedir:
157         closedir(dp);
158 error_free_builtname_generic:
159         free(builtname_generic);
160 error_free_builtname:
161         free(builtname);
162 error_free_scan_el_dir:
163         free(scan_el_dir);
164 error_ret:
165         return ret;
166 }
167
168 int iioutils_get_param_float(float *output,
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                 }
214 error_free_filename:
215         if (filename)
216                 free(filename);
217 error_closedir:
218         closedir(dp);
219 error_free_builtname_generic:
220         free(builtname_generic);
221 error_free_builtname:
222         free(builtname);
223 error_ret:
224         return ret;
225 }
226
227 /**
228  * bsort_channel_array_by_index() - reorder so that the array is in index order
229  *
230  **/
231
232 void bsort_channel_array_by_index(struct iio_channel_info **ci_array,
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 }
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  **/
253 int build_channel_array(const char *device_dir,
254                               struct iio_channel_info **ci_array,
255                               int *counter)
256 {
257         DIR *dp;
258         FILE *sysfsfp;
259         int count, i;
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                         }
292                         fscanf(sysfsfp, "%i", &ret);
293                         if (ret == 1)
294                                 (*counter)++;
295                         fclose(sysfsfp);
296                         free(filename);
297                 }
298         *ci_array = malloc(sizeof(**ci_array) * (*counter));
299         if (*ci_array == NULL) {
300                 ret = -ENOMEM;
301                 goto error_close_dir;
302         }
303         seekdir(dp, 0);
304         count = 0;
305         while (ent = readdir(dp), ent != NULL) {
306                 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
307                            "_en") == 0) {
308                         int current_enabled = 0;
309
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                         }
325                         fscanf(sysfsfp, "%i", &current_enabled);
326                         fclose(sysfsfp);
327
328                         if (!current_enabled) {
329                                 free(filename);
330                                 count--;
331                                 continue;
332                         }
333
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,
382                                                 &current->shift,
383                                                 &current->mask,
384                                                 &current->be,
385                                                 device_dir,
386                                                 current->name,
387                                                 current->generic_name);
388                 }
389         }
390
391         closedir(dp);
392         /* reorder so that the array is in index order */
393         bsort_channel_array_by_index(ci_array, *counter);
394
395         return 0;
396
397 error_cleanup_array:
398         for (i = count - 1;  i >= 0; i--)
399                 free((*ci_array)[i].name);
400         free(*ci_array);
401 error_close_dir:
402         closedir(dp);
403 error_free_name:
404         free(scan_el_dir);
405 error_ret:
406         return ret;
407 }
408
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  **/
416 int find_type_by_name(const char *name, const char *type)
417 {
418         const struct dirent *ent;
419         int number, numstrlen;
420
421         FILE *nameFile;
422         DIR *dp;
423         char thisname[IIO_MAX_NAME_LENGTH];
424         char *filename;
425
426         dp = opendir(iio_dir);
427         if (dp == NULL) {
428                 printf("No industrialio devices available\n");
429                 return -ENODEV;
430         }
431
432         while (ent = readdir(dp), ent != NULL) {
433                 if (strcmp(ent->d_name, ".") != 0 &&
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)
446                                                 + numstrlen
447                                                 + 6);
448                                 if (filename == NULL) {
449                                         closedir(dp);
450                                         return -ENOMEM;
451                                 }
452                                 sprintf(filename, "%s%s%d/name",
453                                         iio_dir,
454                                         type,
455                                         number);
456                                 nameFile = fopen(filename, "r");
457                                 if (!nameFile) {
458                                         free(filename);
459                                         continue;
460                                 }
461                                 free(filename);
462                                 fscanf(nameFile, "%s", thisname);
463                                 fclose(nameFile);
464                                 if (strcmp(name, thisname) == 0) {
465                                         closedir(dp);
466                                         return number;
467                                 }
468                         }
469                 }
470         }
471         closedir(dp);
472         return -ENODEV;
473 }
474
475 int _write_sysfs_int(char *filename, char *basedir, int val, int verify)
476 {
477         int ret = 0;
478         FILE *sysfsfp;
479         int test;
480         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
481
482         if (temp == NULL)
483                 return -ENOMEM;
484         sprintf(temp, "%s/%s", basedir, filename);
485         sysfsfp = fopen(temp, "w");
486         if (sysfsfp == NULL) {
487                 printf("failed to open %s\n", temp);
488                 ret = -errno;
489                 goto error_free;
490         }
491         fprintf(sysfsfp, "%d", val);
492         fclose(sysfsfp);
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);
501                 fclose(sysfsfp);
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         }
510 error_free:
511         free(temp);
512         return ret;
513 }
514
515 int write_sysfs_int(char *filename, char *basedir, int val)
516 {
517         return _write_sysfs_int(filename, basedir, val, 0);
518 }
519
520 int write_sysfs_int_and_verify(char *filename, char *basedir, int val)
521 {
522         return _write_sysfs_int(filename, basedir, val, 1);
523 }
524
525 int _write_sysfs_string(char *filename, char *basedir, char *val, int verify)
526 {
527         int ret = 0;
528         FILE  *sysfsfp;
529         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
530
531         if (temp == NULL) {
532                 printf("Memory allocation failed\n");
533                 return -ENOMEM;
534         }
535         sprintf(temp, "%s/%s", basedir, filename);
536         sysfsfp = fopen(temp, "w");
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);
543         fclose(sysfsfp);
544         if (verify) {
545                 sysfsfp = fopen(temp, "r");
546                 if (sysfsfp == NULL) {
547                         printf("could not open file to verify\n");
548                         ret = -errno;
549                         goto error_free;
550                 }
551                 fscanf(sysfsfp, "%s", temp);
552                 fclose(sysfsfp);
553                 if (strcmp(temp, val) != 0) {
554                         printf("Possible failure in string write of %s "
555                                 "Should be %s "
556                                 "written to %s\%s\n",
557                                 temp,
558                                 val,
559                                 basedir,
560                                 filename);
561                         ret = -1;
562                 }
563         }
564 error_free:
565         free(temp);
566
567         return ret;
568 }
569
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  **/
576 int write_sysfs_string_and_verify(char *filename, char *basedir, char *val)
577 {
578         return _write_sysfs_string(filename, basedir, val, 1);
579 }
580
581 int write_sysfs_string(char *filename, char *basedir, char *val)
582 {
583         return _write_sysfs_string(filename, basedir, val, 0);
584 }
585
586 int read_sysfs_posint(char *filename, char *basedir)
587 {
588         int ret;
589         FILE  *sysfsfp;
590         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
591
592         if (temp == NULL) {
593                 printf("Memory allocation failed");
594                 return -ENOMEM;
595         }
596         sprintf(temp, "%s/%s", basedir, filename);
597         sysfsfp = fopen(temp, "r");
598         if (sysfsfp == NULL) {
599                 ret = -errno;
600                 goto error_free;
601         }
602         fscanf(sysfsfp, "%d\n", &ret);
603         fclose(sysfsfp);
604 error_free:
605         free(temp);
606         return ret;
607 }
608
609 int read_sysfs_float(char *filename, char *basedir, float *val)
610 {
611         int ret = 0;
612         FILE  *sysfsfp;
613         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
614
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);
627 error_free:
628         free(temp);
629         return ret;
630 }
631
632 int read_sysfs_string(const char *filename, const char *basedir, char *str)
633 {
634         int ret = 0;
635         FILE  *sysfsfp;
636         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
637
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);
650 error_free:
651         free(temp);
652         return ret;
653 }
654
655 #endif /* _IIO_UTILS_H */