]> Pileus Git - ~andy/linux/blob - drivers/staging/iio/Documentation/iio_utils.h
iio staging: fix potential resource leak in generic_buffer
[~andy/linux] / 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 #include <dirent.h>
17
18 #define IIO_MAX_NAME_LENGTH 30
19
20 #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
21 #define FORMAT_TYPE_FILE "%s_type"
22
23 const char *iio_dir = "/sys/bus/iio/devices/";
24
25 /**
26  * iioutils_break_up_name() - extract generic name from full channel name
27  * @full_name: the full channel name
28  * @generic_name: the output generic channel name
29  **/
30 static int iioutils_break_up_name(const char *full_name,
31                                   char **generic_name)
32 {
33         char *current;
34         char *w, *r;
35         char *working;
36         current = strdup(full_name);
37         working = strtok(current, "_\0");
38         w = working;
39         r = working;
40
41         while (*r != '\0') {
42                 if (!isdigit(*r)) {
43                         *w = *r;
44                         w++;
45                 }
46                 r++;
47         }
48         *w = '\0';
49         *generic_name = strdup(working);
50         free(current);
51
52         return 0;
53 }
54
55 /**
56  * struct iio_channel_info - information about a given channel
57  * @name: channel name
58  * @generic_name: general name for channel type
59  * @scale: scale factor to be applied for conversion to si units
60  * @offset: offset to be applied for conversion to si units
61  * @index: the channel index in the buffer output
62  * @bytes: number of bytes occupied in buffer output
63  * @mask: a bit mask for the raw output
64  * @is_signed: is the raw value stored signed
65  * @enabled: is this channel enabled
66  **/
67 struct iio_channel_info {
68         char *name;
69         char *generic_name;
70         float scale;
71         float offset;
72         unsigned index;
73         unsigned bytes;
74         unsigned bits_used;
75         unsigned shift;
76         uint64_t mask;
77         unsigned be;
78         unsigned is_signed;
79         unsigned enabled;
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, temp, 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                         current = &(*ci_array)[count++];
338                         ret = asprintf(&filename,
339                                        "%s/%s", scan_el_dir, ent->d_name);
340                         if (ret < 0) {
341                                 ret = -ENOMEM;
342                                 /* decrement count to avoid freeing name */
343                                 count--;
344                                 goto error_cleanup_array;
345                         }
346                         sysfsfp = fopen(filename, "r");
347                         if (sysfsfp == NULL) {
348                                 free(filename);
349                                 ret = -errno;
350                                 goto error_cleanup_array;
351                         }
352                         fscanf(sysfsfp, "%u", &current->enabled);
353                         fclose(sysfsfp);
354
355                         if (!current->enabled) {
356                                 free(filename);
357                                 count--;
358                                 continue;
359                         }
360
361                         current->scale = 1.0;
362                         current->offset = 0;
363                         current->name = strndup(ent->d_name,
364                                                 strlen(ent->d_name) -
365                                                 strlen("_en"));
366                         if (current->name == NULL) {
367                                 free(filename);
368                                 ret = -ENOMEM;
369                                 goto error_cleanup_array;
370                         }
371                         /* Get the generic and specific name elements */
372                         ret = iioutils_break_up_name(current->name,
373                                                      &current->generic_name);
374                         if (ret) {
375                                 free(filename);
376                                 goto error_cleanup_array;
377                         }
378                         ret = asprintf(&filename,
379                                        "%s/%s_index",
380                                        scan_el_dir,
381                                        current->name);
382                         if (ret < 0) {
383                                 free(filename);
384                                 ret = -ENOMEM;
385                                 goto error_cleanup_array;
386                         }
387                         sysfsfp = fopen(filename, "r");
388                         fscanf(sysfsfp, "%u", &current->index);
389                         fclose(sysfsfp);
390                         free(filename);
391                         /* Find the scale */
392                         ret = iioutils_get_param_float(&current->scale,
393                                                        "scale",
394                                                        device_dir,
395                                                        current->name,
396                                                        current->generic_name);
397                         if (ret < 0)
398                                 goto error_cleanup_array;
399                         ret = iioutils_get_param_float(&current->offset,
400                                                        "offset",
401                                                        device_dir,
402                                                        current->name,
403                                                        current->generic_name);
404                         if (ret < 0)
405                                 goto error_cleanup_array;
406                         ret = iioutils_get_type(&current->is_signed,
407                                                 &current->bytes,
408                                                 &current->bits_used,
409                                                 &current->shift,
410                                                 &current->mask,
411                                                 &current->be,
412                                                 device_dir,
413                                                 current->name,
414                                                 current->generic_name);
415                 }
416         }
417
418         closedir(dp);
419         /* reorder so that the array is in index order */
420         bsort_channel_array_by_index(ci_array, *counter);
421
422         return 0;
423
424 error_cleanup_array:
425         for (i = count - 1;  i >= 0; i--)
426                 free((*ci_array)[i].name);
427         free(*ci_array);
428 error_close_dir:
429         closedir(dp);
430 error_free_name:
431         free(scan_el_dir);
432 error_ret:
433         return ret;
434 }
435
436 /**
437  * find_type_by_name() - function to match top level types by name
438  * @name: top level type instance name
439  * @type: the type of top level instance being sort
440  *
441  * Typical types this is used for are device and trigger.
442  **/
443 inline int find_type_by_name(const char *name, const char *type)
444 {
445         const struct dirent *ent;
446         int number, numstrlen;
447
448         FILE *nameFile;
449         DIR *dp;
450         char thisname[IIO_MAX_NAME_LENGTH];
451         char *filename;
452
453         dp = opendir(iio_dir);
454         if (dp == NULL) {
455                 printf("No industrialio devices available");
456                 return -ENODEV;
457         }
458
459         while (ent = readdir(dp), ent != NULL) {
460                 if (strcmp(ent->d_name, ".") != 0 &&
461                         strcmp(ent->d_name, "..") != 0 &&
462                         strlen(ent->d_name) > strlen(type) &&
463                         strncmp(ent->d_name, type, strlen(type)) == 0) {
464                         numstrlen = sscanf(ent->d_name + strlen(type),
465                                            "%d",
466                                            &number);
467                         /* verify the next character is not a colon */
468                         if (strncmp(ent->d_name + strlen(type) + numstrlen,
469                                         ":",
470                                         1) != 0) {
471                                 filename = malloc(strlen(iio_dir)
472                                                 + strlen(type)
473                                                 + numstrlen
474                                                 + 6);
475                                 if (filename == NULL)
476                                         return -ENOMEM;
477                                 sprintf(filename, "%s%s%d/name",
478                                         iio_dir,
479                                         type,
480                                         number);
481                                 nameFile = fopen(filename, "r");
482                                 if (!nameFile)
483                                         continue;
484                                 free(filename);
485                                 fscanf(nameFile, "%s", thisname);
486                                 if (strcmp(name, thisname) == 0)
487                                         return number;
488                                 fclose(nameFile);
489                         }
490                 }
491         }
492         return -ENODEV;
493 }
494
495 inline int _write_sysfs_int(char *filename, char *basedir, int val, int verify)
496 {
497         int ret;
498         FILE *sysfsfp;
499         int test;
500         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
501         if (temp == NULL)
502                 return -ENOMEM;
503         sprintf(temp, "%s/%s", basedir, filename);
504         sysfsfp = fopen(temp, "w");
505         if (sysfsfp == NULL) {
506                 printf("failed to open %s\n", temp);
507                 ret = -errno;
508                 goto error_free;
509         }
510         fprintf(sysfsfp, "%d", val);
511         fclose(sysfsfp);
512         if (verify) {
513                 sysfsfp = fopen(temp, "r");
514                 if (sysfsfp == NULL) {
515                         printf("failed to open %s\n", temp);
516                         ret = -errno;
517                         goto error_free;
518                 }
519                 fscanf(sysfsfp, "%d", &test);
520                 if (test != val) {
521                         printf("Possible failure in int write %d to %s%s\n",
522                                 val,
523                                 basedir,
524                                 filename);
525                         ret = -1;
526                 }
527         }
528 error_free:
529         free(temp);
530         return ret;
531 }
532
533 int write_sysfs_int(char *filename, char *basedir, int val)
534 {
535         return _write_sysfs_int(filename, basedir, val, 0);
536 }
537
538 int write_sysfs_int_and_verify(char *filename, char *basedir, int val)
539 {
540         return _write_sysfs_int(filename, basedir, val, 1);
541 }
542
543 int _write_sysfs_string(char *filename, char *basedir, char *val, int verify)
544 {
545         int ret = 0;
546         FILE  *sysfsfp;
547         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
548         if (temp == NULL) {
549                 printf("Memory allocation failed\n");
550                 return -ENOMEM;
551         }
552         sprintf(temp, "%s/%s", basedir, filename);
553         sysfsfp = fopen(temp, "w");
554         if (sysfsfp == NULL) {
555                 printf("Could not open %s\n", temp);
556                 ret = -errno;
557                 goto error_free;
558         }
559         fprintf(sysfsfp, "%s", val);
560         fclose(sysfsfp);
561         if (verify) {
562                 sysfsfp = fopen(temp, "r");
563                 if (sysfsfp == NULL) {
564                         printf("could not open file to verify\n");
565                         ret = -errno;
566                         goto error_free;
567                 }
568                 fscanf(sysfsfp, "%s", temp);
569                 if (strcmp(temp, val) != 0) {
570                         printf("Possible failure in string write of %s "
571                                 "Should be %s "
572                                 "written to %s\%s\n",
573                                 temp,
574                                 val,
575                                 basedir,
576                                 filename);
577                         ret = -1;
578                 }
579         }
580 error_free:
581         free(temp);
582
583         return ret;
584 }
585
586 /**
587  * write_sysfs_string_and_verify() - string write, readback and verify
588  * @filename: name of file to write to
589  * @basedir: the sysfs directory in which the file is to be found
590  * @val: the string to write
591  **/
592 int write_sysfs_string_and_verify(char *filename, char *basedir, char *val)
593 {
594         return _write_sysfs_string(filename, basedir, val, 1);
595 }
596
597 int write_sysfs_string(char *filename, char *basedir, char *val)
598 {
599         return _write_sysfs_string(filename, basedir, val, 0);
600 }
601
602 int read_sysfs_posint(char *filename, char *basedir)
603 {
604         int ret;
605         FILE  *sysfsfp;
606         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
607         if (temp == NULL) {
608                 printf("Memory allocation failed");
609                 return -ENOMEM;
610         }
611         sprintf(temp, "%s/%s", basedir, filename);
612         sysfsfp = fopen(temp, "r");
613         if (sysfsfp == NULL) {
614                 ret = -errno;
615                 goto error_free;
616         }
617         fscanf(sysfsfp, "%d\n", &ret);
618         fclose(sysfsfp);
619 error_free:
620         free(temp);
621         return ret;
622 }
623
624 int read_sysfs_float(char *filename, char *basedir, float *val)
625 {
626         float ret = 0;
627         FILE  *sysfsfp;
628         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
629         if (temp == NULL) {
630                 printf("Memory allocation failed");
631                 return -ENOMEM;
632         }
633         sprintf(temp, "%s/%s", basedir, filename);
634         sysfsfp = fopen(temp, "r");
635         if (sysfsfp == NULL) {
636                 ret = -errno;
637                 goto error_free;
638         }
639         fscanf(sysfsfp, "%f\n", val);
640         fclose(sysfsfp);
641 error_free:
642         free(temp);
643         return ret;
644 }