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