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