]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/staging/iio/Documentation/iio_utils.h
staging: iio: generic_buffer: initialize ret
[mirror_ubuntu-hirsute-kernel.git] / drivers / staging / iio / Documentation / iio_utils.h
CommitLineData
c57f1ba7
JC
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
9d8ae6c8
JC
10#include <string.h>
11#include <stdlib.h>
e58537cc
JC
12#include <ctype.h>
13#include <stdio.h>
14#include <stdint.h>
bc9f35db 15#include <dirent.h>
bb23378c 16#include <errno.h>
9d8ae6c8 17
b42f2a0c 18/* Made up value to limit allocation sizes */
9d8ae6c8
JC
19#define IIO_MAX_NAME_LENGTH 30
20
1aa04278 21#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
e58537cc 22#define FORMAT_TYPE_FILE "%s_type"
c57f1ba7 23
9d8ae6c8
JC
24const char *iio_dir = "/sys/bus/iio/devices/";
25
e58537cc
JC
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 **/
42196d39 31inline int iioutils_break_up_name(const char *full_name,
e58537cc
JC
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
8b68bb20 42 while (*r != '\0') {
e58537cc
JC
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 **/
68struct 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;
52615d47 76 unsigned shift;
e58537cc 77 uint64_t mask;
117cf8b7 78 unsigned be;
e58537cc
JC
79 unsigned is_signed;
80 unsigned enabled;
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
117cf8b7 89 * @be: big endian
e58537cc
JC
90 * @device_dir: the iio device directory
91 * @name: the channel name
92 * @generic_name: the channel type name
93 **/
94inline int iioutils_get_type(unsigned *is_signed,
95 unsigned *bytes,
96 unsigned *bits_used,
52615d47 97 unsigned *shift,
e58537cc 98 uint64_t *mask,
117cf8b7 99 unsigned *be,
e58537cc
JC
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;
117cf8b7 108 char signchar, endianchar;
fc7f95a9 109 unsigned padint;
e58537cc
JC
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 }
a7f7c364
JC
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");
578f737d
PM
161 ret = -errno;
162 goto error_close_sysfsfp;
a7f7c364 163 }
117cf8b7 164 *be = (endianchar == 'b');
e58537cc 165 *bytes = padint / 8;
fc7f95a9 166 if (*bits_used == 64)
e58537cc
JC
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;
a7f7c364
JC
174 fclose(sysfsfp);
175 free(filename);
176
177 filename = 0;
578f737d 178 sysfsfp = 0;
e58537cc 179 }
578f737d
PM
180error_close_sysfsfp:
181 if (sysfsfp)
182 fclose(sysfsfp);
e58537cc
JC
183error_free_filename:
184 if (filename)
185 free(filename);
186error_closedir:
187 closedir(dp);
188error_free_builtname_generic:
189 free(builtname_generic);
190error_free_builtname:
191 free(builtname);
192error_free_scan_el_dir:
193 free(scan_el_dir);
194error_ret:
195 return ret;
196}
197
198inline 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 }
244error_free_filename:
245 if (filename)
246 free(filename);
247error_closedir:
248 closedir(dp);
249error_free_builtname_generic:
250 free(builtname_generic);
251error_free_builtname:
252 free(builtname);
253error_ret:
254 return ret;
255}
256
8b68bb20
MH
257/**
258 * bsort_channel_array_by_index() - reorder so that the array is in index order
259 *
260 **/
261
262inline 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}
e58537cc
JC
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 **/
283inline 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;
10937921 289 int count, i;
e58537cc
JC
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, "%u", &ret);
323 if (ret == 1)
324 (*counter)++;
325 fclose(sysfsfp);
326 free(filename);
327 }
8b68bb20 328 *ci_array = malloc(sizeof(**ci_array) * (*counter));
e58537cc
JC
329 if (*ci_array == NULL) {
330 ret = -ENOMEM;
331 goto error_close_dir;
332 }
333 seekdir(dp, 0);
7ccd4506 334 count = 0;
e58537cc
JC
335 while (ent = readdir(dp), ent != NULL) {
336 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
337 "_en") == 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);
8b68bb20
MH
355
356 if (!current->enabled) {
357 free(filename);
358 count--;
359 continue;
360 }
361
e58537cc
JC
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,
52615d47 410 &current->shift,
e58537cc 411 &current->mask,
117cf8b7 412 &current->be,
e58537cc
JC
413 device_dir,
414 current->name,
415 current->generic_name);
416 }
417 }
8b68bb20 418
e58537cc 419 closedir(dp);
8b68bb20
MH
420 /* reorder so that the array is in index order */
421 bsort_channel_array_by_index(ci_array, *counter);
e58537cc
JC
422
423 return 0;
424
425error_cleanup_array:
267024a9 426 for (i = count - 1; i >= 0; i--)
e58537cc
JC
427 free((*ci_array)[i].name);
428 free(*ci_array);
429error_close_dir:
430 closedir(dp);
431error_free_name:
432 free(scan_el_dir);
433error_ret:
434 return ret;
435}
436
9d8ae6c8
JC
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 **/
444inline int find_type_by_name(const char *name, const char *type)
c57f1ba7 445{
c57f1ba7 446 const struct dirent *ent;
9d8ae6c8 447 int number, numstrlen;
c57f1ba7
JC
448
449 FILE *nameFile;
450 DIR *dp;
9d8ae6c8
JC
451 char thisname[IIO_MAX_NAME_LENGTH];
452 char *filename;
9d8ae6c8 453
c57f1ba7
JC
454 dp = opendir(iio_dir);
455 if (dp == NULL) {
c866ffc7 456 printf("No industrialio devices available\n");
9d8ae6c8 457 return -ENODEV;
c57f1ba7 458 }
9d8ae6c8 459
c57f1ba7 460 while (ent = readdir(dp), ent != NULL) {
c57f1ba7 461 if (strcmp(ent->d_name, ".") != 0 &&
9d8ae6c8
JC
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)
9d8ae6c8 474 + numstrlen
b6ee30a2 475 + 6);
a4d429e3
PM
476 if (filename == NULL) {
477 closedir(dp);
9d8ae6c8 478 return -ENOMEM;
a4d429e3 479 }
9d8ae6c8
JC
480 sprintf(filename, "%s%s%d/name",
481 iio_dir,
482 type,
483 number);
484 nameFile = fopen(filename, "r");
a4d429e3
PM
485 if (!nameFile) {
486 free(filename);
9d8ae6c8 487 continue;
a4d429e3 488 }
9d8ae6c8 489 free(filename);
c57f1ba7 490 fscanf(nameFile, "%s", thisname);
c57f1ba7 491 fclose(nameFile);
a4d429e3
PM
492 if (strcmp(name, thisname) == 0) {
493 closedir(dp);
494 return number;
495 }
c57f1ba7
JC
496 }
497 }
498 }
a4d429e3 499 closedir(dp);
9d8ae6c8 500 return -ENODEV;
c57f1ba7
JC
501}
502
9d8ae6c8 503inline int _write_sysfs_int(char *filename, char *basedir, int val, int verify)
c57f1ba7 504{
11cb454f 505 int ret = 0;
9d8ae6c8
JC
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);
c57f1ba7 512 sysfsfp = fopen(temp, "w");
9d8ae6c8
JC
513 if (sysfsfp == NULL) {
514 printf("failed to open %s\n", temp);
515 ret = -errno;
516 goto error_free;
517 }
c57f1ba7
JC
518 fprintf(sysfsfp, "%d", val);
519 fclose(sysfsfp);
9d8ae6c8
JC
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);
ce7b04c6 528 fclose(sysfsfp);
9d8ae6c8
JC
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 }
537error_free:
538 free(temp);
539 return ret;
540}
541
542int write_sysfs_int(char *filename, char *basedir, int val)
543{
544 return _write_sysfs_int(filename, basedir, val, 0);
c57f1ba7
JC
545}
546
eaf86ff9 547int write_sysfs_int_and_verify(char *filename, char *basedir, int val)
9d8ae6c8
JC
548{
549 return _write_sysfs_int(filename, basedir, val, 1);
550}
551
552int _write_sysfs_string(char *filename, char *basedir, char *val, int verify)
eaf86ff9 553{
e58537cc 554 int ret = 0;
eaf86ff9 555 FILE *sysfsfp;
9d8ae6c8
JC
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);
eaf86ff9 562 sysfsfp = fopen(temp, "w");
9d8ae6c8
JC
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);
eaf86ff9 569 fclose(sysfsfp);
9d8ae6c8
JC
570 if (verify) {
571 sysfsfp = fopen(temp, "r");
572 if (sysfsfp == NULL) {
e58537cc 573 printf("could not open file to verify\n");
9d8ae6c8
JC
574 ret = -errno;
575 goto error_free;
576 }
577 fscanf(sysfsfp, "%s", temp);
ce7b04c6 578 fclose(sysfsfp);
9d8ae6c8
JC
579 if (strcmp(temp, val) != 0) {
580 printf("Possible failure in string write of %s "
581 "Should be %s "
25985edc 582 "written to %s\%s\n",
9d8ae6c8
JC
583 temp,
584 val,
585 basedir,
586 filename);
587 ret = -1;
588 }
eaf86ff9 589 }
9d8ae6c8
JC
590error_free:
591 free(temp);
eaf86ff9 592
9d8ae6c8 593 return ret;
eaf86ff9 594}
e58537cc 595
c57f1ba7
JC
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 **/
602int write_sysfs_string_and_verify(char *filename, char *basedir, char *val)
603{
9d8ae6c8
JC
604 return _write_sysfs_string(filename, basedir, val, 1);
605}
c57f1ba7 606
9d8ae6c8
JC
607int write_sysfs_string(char *filename, char *basedir, char *val)
608{
609 return _write_sysfs_string(filename, basedir, val, 0);
c57f1ba7
JC
610}
611
612int read_sysfs_posint(char *filename, char *basedir)
613{
614 int ret;
615 FILE *sysfsfp;
9d8ae6c8
JC
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);
c57f1ba7 622 sysfsfp = fopen(temp, "r");
9d8ae6c8
JC
623 if (sysfsfp == NULL) {
624 ret = -errno;
625 goto error_free;
626 }
c57f1ba7
JC
627 fscanf(sysfsfp, "%d\n", &ret);
628 fclose(sysfsfp);
9d8ae6c8
JC
629error_free:
630 free(temp);
631 return ret;
632}
633
634int 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);
651error_free:
652 free(temp);
c57f1ba7
JC
653 return ret;
654}