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