blob: 03724246b95ad8a6bd350f18cc76a4f69c0d3900 [file] [log] [blame]
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +01001/* 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
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +010010/* Made up value to limit allocation sizes */
11#include <string.h>
12#include <stdlib.h>
Jonathan Camerone58537c2010-10-08 12:14:14 +010013#include <ctype.h>
14#include <stdio.h>
15#include <stdint.h>
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +010016
17#define IIO_MAX_NAME_LENGTH 30
18
Jonathan Camerone58537c2010-10-08 12:14:14 +010019#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"
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +010030
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +010031const char *iio_dir = "/sys/bus/iio/devices/";
32
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +010033struct iio_event_data {
34 int id;
35 __s64 timestamp;
36};
37
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +010038/**
Jonathan Camerone58537c2010-10-08 12:14:14 +010039 * 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 **/
43static 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 **/
80struct 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 **/
103inline 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 }
171error_free_filename:
172 if (filename)
173 free(filename);
174error_closedir:
175 closedir(dp);
176error_free_builtname_generic:
177 free(builtname_generic);
178error_free_builtname:
179 free(builtname);
180error_free_scan_el_dir:
181 free(scan_el_dir);
182error_ret:
183 return ret;
184}
185
186inline 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 }
232error_free_filename:
233 if (filename)
234 free(filename);
235error_closedir:
236 closedir(dp);
237error_free_builtname_generic:
238 free(builtname_generic);
239error_free_builtname:
240 free(builtname);
241error_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 **/
251inline 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
400error_cleanup_array:
401 for (i = count - 1; i >= 0; i++)
402 free((*ci_array)[i].name);
403 free(*ci_array);
404error_close_dir:
405 closedir(dp);
406error_free_name:
407 free(scan_el_dir);
408error_ret:
409 return ret;
410}
411
412/**
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100413 * 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 **/
419inline int find_type_by_name(const char *name, const char *type)
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100420{
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100421 const struct dirent *ent;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100422 int number, numstrlen;
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100423
424 FILE *nameFile;
425 DIR *dp;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100426 char thisname[IIO_MAX_NAME_LENGTH];
427 char *filename;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100428
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100429 dp = opendir(iio_dir);
430 if (dp == NULL) {
431 printf("No industrialio devices available");
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100432 return -ENODEV;
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100433 }
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100434
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100435 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)
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100449 + numstrlen
Barry Songb6ee30a2010-05-25 17:40:04 +0800450 + 6);
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100451 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);
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100465 }
466 }
467 }
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100468 return -ENODEV;
469}
470
471inline 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 }
504error_free:
505 free(temp);
506 return ret;
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100507}
508
509int write_sysfs_int(char *filename, char *basedir, int val)
510{
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100511 return _write_sysfs_int(filename, basedir, val, 0);
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100512}
513
Jonathan Cameroneaf86ff2010-05-04 14:43:04 +0100514int write_sysfs_int_and_verify(char *filename, char *basedir, int val)
515{
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100516 return _write_sysfs_int(filename, basedir, val, 1);
Jonathan Cameroneaf86ff2010-05-04 14:43:04 +0100517}
518
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100519int _write_sysfs_string(char *filename, char *basedir, char *val, int verify)
520{
Jonathan Camerone58537c2010-10-08 12:14:14 +0100521 int ret = 0;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100522 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) {
Jonathan Camerone58537c2010-10-08 12:14:14 +0100540 printf("could not open file to verify\n");
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100541 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 }
556error_free:
557 free(temp);
558
559 return ret;
560}
Jonathan Camerone58537c2010-10-08 12:14:14 +0100561
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100562/**
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 **/
568int write_sysfs_string_and_verify(char *filename, char *basedir, char *val)
569{
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100570 return _write_sysfs_string(filename, basedir, val, 1);
571}
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100572
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100573int write_sysfs_string(char *filename, char *basedir, char *val)
574{
575 return _write_sysfs_string(filename, basedir, val, 0);
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100576}
577
578int read_sysfs_posint(char *filename, char *basedir)
579{
580 int ret;
581 FILE *sysfsfp;
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100582 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);
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100588 sysfsfp = fopen(temp, "r");
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100589 if (sysfsfp == NULL) {
590 ret = -errno;
591 goto error_free;
592 }
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100593 fscanf(sysfsfp, "%d\n", &ret);
594 fclose(sysfsfp);
Jonathan Cameron9d8ae6c2010-05-04 14:43:13 +0100595error_free:
596 free(temp);
597 return ret;
598}
599
600int 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);
617error_free:
618 free(temp);
Jonathan Cameronc57f1ba2009-08-18 18:06:32 +0100619 return ret;
620}