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