]>
Commit | Line | Data |
---|---|---|
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 | */ | |
37e3be9d CO |
9 | #ifndef _IIO_UTILS_H |
10 | #define _IIO_UTILS_H | |
c57f1ba7 | 11 | |
9d8ae6c8 JC |
12 | #include <string.h> |
13 | #include <stdlib.h> | |
e58537cc JC |
14 | #include <stdio.h> |
15 | #include <stdint.h> | |
bc9f35db | 16 | #include <dirent.h> |
bb23378c | 17 | #include <errno.h> |
bdcb31d0 RD |
18 | #include <ctype.h> |
19 | #include "iio_utils.h" | |
c57f1ba7 | 20 | |
9d8ae6c8 JC |
21 | const char *iio_dir = "/sys/bus/iio/devices/"; |
22 | ||
d9d7b990 IT |
23 | static char * const iio_direction[] = { |
24 | "in", | |
25 | "out", | |
26 | }; | |
27 | ||
e58537cc JC |
28 | /** |
29 | * iioutils_break_up_name() - extract generic name from full channel name | |
30 | * @full_name: the full channel name | |
31 | * @generic_name: the output generic channel name | |
5dc65d79 HK |
32 | * |
33 | * Returns 0 on success, or a negative error code if string extraction failed. | |
e58537cc | 34 | **/ |
7663a4aa | 35 | int iioutils_break_up_name(const char *full_name, char **generic_name) |
e58537cc JC |
36 | { |
37 | char *current; | |
38 | char *w, *r; | |
d9d7b990 | 39 | char *working, *prefix = ""; |
e9e45b43 | 40 | int i, ret; |
d9d7b990 IT |
41 | |
42 | for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++) | |
43 | if (!strncmp(full_name, iio_direction[i], | |
44 | strlen(iio_direction[i]))) { | |
45 | prefix = iio_direction[i]; | |
46 | break; | |
47 | } | |
79bdd48a | 48 | |
d9d7b990 | 49 | current = strdup(full_name + strlen(prefix) + 1); |
e9e45b43 HK |
50 | if (!current) |
51 | return -ENOMEM; | |
52 | ||
e58537cc | 53 | working = strtok(current, "_\0"); |
53118557 HK |
54 | if (!working) { |
55 | free(current); | |
56 | return -EINVAL; | |
57 | } | |
d9d7b990 | 58 | |
e58537cc JC |
59 | w = working; |
60 | r = working; | |
61 | ||
8b68bb20 | 62 | while (*r != '\0') { |
e58537cc JC |
63 | if (!isdigit(*r)) { |
64 | *w = *r; | |
65 | w++; | |
66 | } | |
7663a4aa | 67 | |
e58537cc JC |
68 | r++; |
69 | } | |
70 | *w = '\0'; | |
e9e45b43 | 71 | ret = asprintf(generic_name, "%s_%s", prefix, working); |
e58537cc JC |
72 | free(current); |
73 | ||
e9e45b43 | 74 | return (ret == -1) ? -ENOMEM : 0; |
e58537cc JC |
75 | } |
76 | ||
e58537cc JC |
77 | /** |
78 | * iioutils_get_type() - find and process _type attribute data | |
79 | * @is_signed: output whether channel is signed | |
80 | * @bytes: output how many bytes the channel storage occupies | |
5dc65d79 HK |
81 | * @bits_used: output number of valid bits of data |
82 | * @shift: output amount of bits to shift right data before applying bit mask | |
e58537cc | 83 | * @mask: output a bit mask for the raw data |
5dc65d79 HK |
84 | * @be: output if data in big endian |
85 | * @device_dir: the IIO device directory | |
e58537cc JC |
86 | * @name: the channel name |
87 | * @generic_name: the channel type name | |
5dc65d79 HK |
88 | * |
89 | * Returns a value >= 0 on success, otherwise a negative error code. | |
e58537cc | 90 | **/ |
7663a4aa HK |
91 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, |
92 | unsigned *shift, uint64_t *mask, unsigned *be, | |
93 | const char *device_dir, const char *name, | |
94 | const char *generic_name) | |
e58537cc JC |
95 | { |
96 | FILE *sysfsfp; | |
97 | int ret; | |
98 | DIR *dp; | |
99 | char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; | |
117cf8b7 | 100 | char signchar, endianchar; |
fc7f95a9 | 101 | unsigned padint; |
e58537cc JC |
102 | const struct dirent *ent; |
103 | ||
104 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); | |
0e799878 HK |
105 | if (ret < 0) |
106 | return -ENOMEM; | |
107 | ||
e58537cc JC |
108 | ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); |
109 | if (ret < 0) { | |
110 | ret = -ENOMEM; | |
111 | goto error_free_scan_el_dir; | |
112 | } | |
113 | ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); | |
114 | if (ret < 0) { | |
115 | ret = -ENOMEM; | |
116 | goto error_free_builtname; | |
117 | } | |
118 | ||
119 | dp = opendir(scan_el_dir); | |
120 | if (dp == NULL) { | |
121 | ret = -errno; | |
122 | goto error_free_builtname_generic; | |
123 | } | |
7663a4aa | 124 | |
53118557 | 125 | ret = -ENOENT; |
e58537cc JC |
126 | while (ent = readdir(dp), ent != NULL) |
127 | /* | |
128 | * Do we allow devices to override a generic name with | |
129 | * a specific one? | |
130 | */ | |
131 | if ((strcmp(builtname, ent->d_name) == 0) || | |
132 | (strcmp(builtname_generic, ent->d_name) == 0)) { | |
133 | ret = asprintf(&filename, | |
134 | "%s/%s", scan_el_dir, ent->d_name); | |
135 | if (ret < 0) { | |
136 | ret = -ENOMEM; | |
137 | goto error_closedir; | |
138 | } | |
7663a4aa | 139 | |
e58537cc JC |
140 | sysfsfp = fopen(filename, "r"); |
141 | if (sysfsfp == NULL) { | |
e58537cc | 142 | ret = -errno; |
2b6a6e67 | 143 | printf("failed to open %s\n", filename); |
e58537cc JC |
144 | goto error_free_filename; |
145 | } | |
a7f7c364 JC |
146 | |
147 | ret = fscanf(sysfsfp, | |
148 | "%ce:%c%u/%u>>%u", | |
149 | &endianchar, | |
150 | &signchar, | |
151 | bits_used, | |
152 | &padint, shift); | |
153 | if (ret < 0) { | |
578f737d | 154 | ret = -errno; |
2b6a6e67 | 155 | printf("failed to pass scan type description\n"); |
578f737d | 156 | goto error_close_sysfsfp; |
dc8b5d6e HK |
157 | } else if (ret != 5) { |
158 | ret = -EIO; | |
159 | printf("scan type description didn't match\n"); | |
160 | goto error_close_sysfsfp; | |
a7f7c364 | 161 | } |
7663a4aa | 162 | |
117cf8b7 | 163 | *be = (endianchar == 'b'); |
e58537cc | 164 | *bytes = padint / 8; |
fc7f95a9 | 165 | if (*bits_used == 64) |
e58537cc JC |
166 | *mask = ~0; |
167 | else | |
168 | *mask = (1 << *bits_used) - 1; | |
7663a4aa | 169 | |
33ebcb21 | 170 | *is_signed = (signchar == 's'); |
53118557 HK |
171 | if (fclose(sysfsfp)) { |
172 | ret = -errno; | |
173 | printf("Failed to close %s\n", filename); | |
174 | goto error_free_filename; | |
175 | } | |
176 | ||
ace76e42 | 177 | sysfsfp = 0; |
a7f7c364 | 178 | free(filename); |
a7f7c364 | 179 | filename = 0; |
e58537cc | 180 | } |
7663a4aa | 181 | |
578f737d PM |
182 | error_close_sysfsfp: |
183 | if (sysfsfp) | |
53118557 HK |
184 | if (fclose(sysfsfp)) |
185 | perror("iioutils_get_type(): Failed to close file"); | |
186 | ||
e58537cc JC |
187 | error_free_filename: |
188 | if (filename) | |
189 | free(filename); | |
7663a4aa | 190 | |
e58537cc | 191 | error_closedir: |
53118557 HK |
192 | if (closedir(dp) == -1) |
193 | perror("iioutils_get_type(): Failed to close directory"); | |
194 | ||
e58537cc JC |
195 | error_free_builtname_generic: |
196 | free(builtname_generic); | |
197 | error_free_builtname: | |
198 | free(builtname); | |
199 | error_free_scan_el_dir: | |
200 | free(scan_el_dir); | |
0e799878 | 201 | |
e58537cc JC |
202 | return ret; |
203 | } | |
204 | ||
5dc65d79 HK |
205 | /** |
206 | * iioutils_get_param_float() - read a float value from a channel parameter | |
207 | * @output: output the float value | |
208 | * @param_name: the parameter name to read | |
209 | * @device_dir: the IIO device directory in sysfs | |
210 | * @name: the channel name | |
211 | * @generic_name: the channel type name | |
212 | * | |
213 | * Returns a value >= 0 on success, otherwise a negative error code. | |
214 | **/ | |
7663a4aa HK |
215 | int iioutils_get_param_float(float *output, const char *param_name, |
216 | const char *device_dir, const char *name, | |
217 | const char *generic_name) | |
e58537cc JC |
218 | { |
219 | FILE *sysfsfp; | |
220 | int ret; | |
221 | DIR *dp; | |
222 | char *builtname, *builtname_generic; | |
223 | char *filename = NULL; | |
224 | const struct dirent *ent; | |
225 | ||
226 | ret = asprintf(&builtname, "%s_%s", name, param_name); | |
0e799878 HK |
227 | if (ret < 0) |
228 | return -ENOMEM; | |
229 | ||
e58537cc JC |
230 | ret = asprintf(&builtname_generic, |
231 | "%s_%s", generic_name, param_name); | |
232 | if (ret < 0) { | |
233 | ret = -ENOMEM; | |
234 | goto error_free_builtname; | |
235 | } | |
7663a4aa | 236 | |
e58537cc JC |
237 | dp = opendir(device_dir); |
238 | if (dp == NULL) { | |
239 | ret = -errno; | |
240 | goto error_free_builtname_generic; | |
241 | } | |
7663a4aa | 242 | |
53118557 | 243 | ret = -ENOENT; |
e58537cc JC |
244 | while (ent = readdir(dp), ent != NULL) |
245 | if ((strcmp(builtname, ent->d_name) == 0) || | |
246 | (strcmp(builtname_generic, ent->d_name) == 0)) { | |
247 | ret = asprintf(&filename, | |
248 | "%s/%s", device_dir, ent->d_name); | |
249 | if (ret < 0) { | |
250 | ret = -ENOMEM; | |
251 | goto error_closedir; | |
252 | } | |
7663a4aa | 253 | |
e58537cc JC |
254 | sysfsfp = fopen(filename, "r"); |
255 | if (!sysfsfp) { | |
256 | ret = -errno; | |
257 | goto error_free_filename; | |
258 | } | |
7663a4aa | 259 | |
53118557 HK |
260 | errno = 0; |
261 | if (fscanf(sysfsfp, "%f", output) != 1) | |
262 | ret = errno ? -errno : -ENODATA; | |
263 | ||
e58537cc JC |
264 | break; |
265 | } | |
266 | error_free_filename: | |
267 | if (filename) | |
268 | free(filename); | |
7663a4aa | 269 | |
e58537cc | 270 | error_closedir: |
53118557 HK |
271 | if (closedir(dp) == -1) |
272 | perror("iioutils_get_param_float(): Failed to close directory"); | |
273 | ||
e58537cc JC |
274 | error_free_builtname_generic: |
275 | free(builtname_generic); | |
276 | error_free_builtname: | |
277 | free(builtname); | |
0e799878 | 278 | |
e58537cc JC |
279 | return ret; |
280 | } | |
281 | ||
8b68bb20 | 282 | /** |
5dc65d79 HK |
283 | * bsort_channel_array_by_index() - sort the array in index order |
284 | * @ci_array: the iio_channel_info array to be sorted | |
285 | * @cnt: the amount of array elements | |
8b68bb20 MH |
286 | **/ |
287 | ||
7663a4aa | 288 | void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt) |
8b68bb20 | 289 | { |
8b68bb20 MH |
290 | struct iio_channel_info temp; |
291 | int x, y; | |
292 | ||
293 | for (x = 0; x < cnt; x++) | |
294 | for (y = 0; y < (cnt - 1); y++) | |
7663a4aa | 295 | if ((*ci_array)[y].index > (*ci_array)[y + 1].index) { |
8b68bb20 MH |
296 | temp = (*ci_array)[y + 1]; |
297 | (*ci_array)[y + 1] = (*ci_array)[y]; | |
298 | (*ci_array)[y] = temp; | |
299 | } | |
300 | } | |
e58537cc JC |
301 | |
302 | /** | |
303 | * build_channel_array() - function to figure out what channels are present | |
304 | * @device_dir: the IIO device directory in sysfs | |
5dc65d79 HK |
305 | * @ci_array: output the resulting array of iio_channel_info |
306 | * @counter: output the amount of array elements | |
307 | * | |
308 | * Returns 0 on success, otherwise a negative error code. | |
e58537cc | 309 | **/ |
bdcb31d0 | 310 | int build_channel_array(const char *device_dir, |
7663a4aa | 311 | struct iio_channel_info **ci_array, int *counter) |
e58537cc JC |
312 | { |
313 | DIR *dp; | |
314 | FILE *sysfsfp; | |
1e7c3478 | 315 | int count = 0, i; |
e58537cc JC |
316 | struct iio_channel_info *current; |
317 | int ret; | |
318 | const struct dirent *ent; | |
319 | char *scan_el_dir; | |
320 | char *filename; | |
321 | ||
322 | *counter = 0; | |
323 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); | |
0e799878 HK |
324 | if (ret < 0) |
325 | return -ENOMEM; | |
326 | ||
e58537cc JC |
327 | dp = opendir(scan_el_dir); |
328 | if (dp == NULL) { | |
329 | ret = -errno; | |
330 | goto error_free_name; | |
331 | } | |
7663a4aa | 332 | |
e58537cc JC |
333 | while (ent = readdir(dp), ent != NULL) |
334 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), | |
335 | "_en") == 0) { | |
336 | ret = asprintf(&filename, | |
337 | "%s/%s", scan_el_dir, ent->d_name); | |
338 | if (ret < 0) { | |
339 | ret = -ENOMEM; | |
340 | goto error_close_dir; | |
341 | } | |
7663a4aa | 342 | |
e58537cc JC |
343 | sysfsfp = fopen(filename, "r"); |
344 | if (sysfsfp == NULL) { | |
345 | ret = -errno; | |
346 | free(filename); | |
347 | goto error_close_dir; | |
348 | } | |
7663a4aa | 349 | |
53118557 HK |
350 | errno = 0; |
351 | if (fscanf(sysfsfp, "%i", &ret) != 1) { | |
352 | ret = errno ? -errno : -ENODATA; | |
353 | if (fclose(sysfsfp)) | |
354 | perror("build_channel_array(): Failed to close file"); | |
355 | ||
356 | free(filename); | |
357 | goto error_close_dir; | |
358 | } | |
e58537cc JC |
359 | if (ret == 1) |
360 | (*counter)++; | |
7663a4aa | 361 | |
53118557 HK |
362 | if (fclose(sysfsfp)) { |
363 | ret = -errno; | |
364 | free(filename); | |
365 | goto error_close_dir; | |
366 | } | |
367 | ||
e58537cc JC |
368 | free(filename); |
369 | } | |
7663a4aa | 370 | |
8b68bb20 | 371 | *ci_array = malloc(sizeof(**ci_array) * (*counter)); |
e58537cc JC |
372 | if (*ci_array == NULL) { |
373 | ret = -ENOMEM; | |
374 | goto error_close_dir; | |
375 | } | |
7663a4aa | 376 | |
e58537cc JC |
377 | seekdir(dp, 0); |
378 | while (ent = readdir(dp), ent != NULL) { | |
379 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), | |
380 | "_en") == 0) { | |
66c65d90 | 381 | int current_enabled = 0; |
79bdd48a | 382 | |
e58537cc JC |
383 | current = &(*ci_array)[count++]; |
384 | ret = asprintf(&filename, | |
385 | "%s/%s", scan_el_dir, ent->d_name); | |
386 | if (ret < 0) { | |
387 | ret = -ENOMEM; | |
388 | /* decrement count to avoid freeing name */ | |
389 | count--; | |
390 | goto error_cleanup_array; | |
391 | } | |
7663a4aa | 392 | |
e58537cc JC |
393 | sysfsfp = fopen(filename, "r"); |
394 | if (sysfsfp == NULL) { | |
e58537cc | 395 | ret = -errno; |
2b6a6e67 | 396 | free(filename); |
121b5e50 | 397 | count--; |
e58537cc JC |
398 | goto error_cleanup_array; |
399 | } | |
7663a4aa | 400 | |
53118557 HK |
401 | errno = 0; |
402 | if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { | |
403 | ret = errno ? -errno : -ENODATA; | |
404 | free(filename); | |
405 | count--; | |
406 | goto error_cleanup_array; | |
407 | } | |
408 | ||
409 | if (fclose(sysfsfp)) { | |
410 | ret = -errno; | |
411 | free(filename); | |
412 | count--; | |
413 | goto error_cleanup_array; | |
414 | } | |
8b68bb20 | 415 | |
66c65d90 | 416 | if (!current_enabled) { |
8b68bb20 MH |
417 | free(filename); |
418 | count--; | |
419 | continue; | |
420 | } | |
421 | ||
e58537cc JC |
422 | current->scale = 1.0; |
423 | current->offset = 0; | |
424 | current->name = strndup(ent->d_name, | |
425 | strlen(ent->d_name) - | |
426 | strlen("_en")); | |
427 | if (current->name == NULL) { | |
428 | free(filename); | |
429 | ret = -ENOMEM; | |
121b5e50 | 430 | count--; |
e58537cc JC |
431 | goto error_cleanup_array; |
432 | } | |
7663a4aa | 433 | |
e58537cc JC |
434 | /* Get the generic and specific name elements */ |
435 | ret = iioutils_break_up_name(current->name, | |
436 | ¤t->generic_name); | |
437 | if (ret) { | |
438 | free(filename); | |
121b5e50 HK |
439 | free(current->name); |
440 | count--; | |
e58537cc JC |
441 | goto error_cleanup_array; |
442 | } | |
7663a4aa | 443 | |
e58537cc JC |
444 | ret = asprintf(&filename, |
445 | "%s/%s_index", | |
446 | scan_el_dir, | |
447 | current->name); | |
448 | if (ret < 0) { | |
449 | free(filename); | |
450 | ret = -ENOMEM; | |
451 | goto error_cleanup_array; | |
452 | } | |
7663a4aa | 453 | |
e58537cc | 454 | sysfsfp = fopen(filename, "r"); |
53118557 HK |
455 | if (sysfsfp == NULL) { |
456 | ret = -errno; | |
457 | printf("failed to open %s\n", filename); | |
458 | free(filename); | |
459 | goto error_cleanup_array; | |
460 | } | |
461 | ||
462 | errno = 0; | |
463 | if (fscanf(sysfsfp, "%u", ¤t->index) != 1) { | |
464 | ret = errno ? -errno : -ENODATA; | |
465 | if (fclose(sysfsfp)) | |
466 | perror("build_channel_array(): Failed to close file"); | |
467 | ||
468 | free(filename); | |
469 | goto error_cleanup_array; | |
470 | } | |
471 | ||
472 | if (fclose(sysfsfp)) { | |
473 | ret = -errno; | |
474 | free(filename); | |
475 | goto error_cleanup_array; | |
476 | } | |
477 | ||
e58537cc JC |
478 | free(filename); |
479 | /* Find the scale */ | |
480 | ret = iioutils_get_param_float(¤t->scale, | |
481 | "scale", | |
482 | device_dir, | |
483 | current->name, | |
484 | current->generic_name); | |
485 | if (ret < 0) | |
486 | goto error_cleanup_array; | |
7663a4aa | 487 | |
e58537cc JC |
488 | ret = iioutils_get_param_float(¤t->offset, |
489 | "offset", | |
490 | device_dir, | |
491 | current->name, | |
492 | current->generic_name); | |
493 | if (ret < 0) | |
494 | goto error_cleanup_array; | |
7663a4aa | 495 | |
e58537cc JC |
496 | ret = iioutils_get_type(¤t->is_signed, |
497 | ¤t->bytes, | |
498 | ¤t->bits_used, | |
52615d47 | 499 | ¤t->shift, |
e58537cc | 500 | ¤t->mask, |
117cf8b7 | 501 | ¤t->be, |
e58537cc JC |
502 | device_dir, |
503 | current->name, | |
504 | current->generic_name); | |
53118557 HK |
505 | if (ret < 0) |
506 | goto error_cleanup_array; | |
e58537cc JC |
507 | } |
508 | } | |
8b68bb20 | 509 | |
53118557 HK |
510 | if (closedir(dp) == -1) { |
511 | ret = -errno; | |
512 | goto error_cleanup_array; | |
513 | } | |
514 | ||
66dd08fd | 515 | free(scan_el_dir); |
8b68bb20 MH |
516 | /* reorder so that the array is in index order */ |
517 | bsort_channel_array_by_index(ci_array, *counter); | |
e58537cc JC |
518 | |
519 | return 0; | |
520 | ||
521 | error_cleanup_array: | |
63f05c85 | 522 | for (i = count - 1; i >= 0; i--) { |
e58537cc | 523 | free((*ci_array)[i].name); |
63f05c85 HK |
524 | free((*ci_array)[i].generic_name); |
525 | } | |
e58537cc JC |
526 | free(*ci_array); |
527 | error_close_dir: | |
53118557 HK |
528 | if (dp) |
529 | if (closedir(dp) == -1) | |
530 | perror("build_channel_array(): Failed to close dir"); | |
531 | ||
e58537cc JC |
532 | error_free_name: |
533 | free(scan_el_dir); | |
0e799878 | 534 | |
e58537cc JC |
535 | return ret; |
536 | } | |
537 | ||
096f9b86 HK |
538 | int calc_digits(int num) |
539 | { | |
540 | int count = 0; | |
541 | ||
542 | while (num != 0) { | |
543 | num /= 10; | |
544 | count++; | |
545 | } | |
546 | ||
547 | return count; | |
548 | } | |
549 | ||
9d8ae6c8 JC |
550 | /** |
551 | * find_type_by_name() - function to match top level types by name | |
552 | * @name: top level type instance name | |
5dc65d79 | 553 | * @type: the type of top level instance being searched |
9d8ae6c8 | 554 | * |
5dc65d79 HK |
555 | * Returns the device number of a matched IIO device on success, otherwise a |
556 | * negative error code. | |
9d8ae6c8 JC |
557 | * Typical types this is used for are device and trigger. |
558 | **/ | |
bdcb31d0 | 559 | int find_type_by_name(const char *name, const char *type) |
c57f1ba7 | 560 | { |
c57f1ba7 | 561 | const struct dirent *ent; |
096f9b86 | 562 | int number, numstrlen, ret; |
c57f1ba7 JC |
563 | |
564 | FILE *nameFile; | |
565 | DIR *dp; | |
9d8ae6c8 JC |
566 | char thisname[IIO_MAX_NAME_LENGTH]; |
567 | char *filename; | |
9d8ae6c8 | 568 | |
c57f1ba7 JC |
569 | dp = opendir(iio_dir); |
570 | if (dp == NULL) { | |
c866ffc7 | 571 | printf("No industrialio devices available\n"); |
9d8ae6c8 | 572 | return -ENODEV; |
c57f1ba7 | 573 | } |
9d8ae6c8 | 574 | |
c57f1ba7 | 575 | while (ent = readdir(dp), ent != NULL) { |
c57f1ba7 | 576 | if (strcmp(ent->d_name, ".") != 0 && |
7663a4aa HK |
577 | strcmp(ent->d_name, "..") != 0 && |
578 | strlen(ent->d_name) > strlen(type) && | |
579 | strncmp(ent->d_name, type, strlen(type)) == 0) { | |
096f9b86 HK |
580 | errno = 0; |
581 | ret = sscanf(ent->d_name + strlen(type), "%d", &number); | |
582 | if (ret < 0) { | |
583 | ret = -errno; | |
584 | printf("failed to read element number\n"); | |
585 | goto error_close_dir; | |
586 | } else if (ret != 1) { | |
587 | ret = -EIO; | |
588 | printf("failed to match element number\n"); | |
589 | goto error_close_dir; | |
590 | } | |
591 | ||
592 | numstrlen = calc_digits(number); | |
9d8ae6c8 JC |
593 | /* verify the next character is not a colon */ |
594 | if (strncmp(ent->d_name + strlen(type) + numstrlen, | |
7663a4aa HK |
595 | ":", 1) != 0) { |
596 | filename = malloc(strlen(iio_dir) + strlen(type) | |
597 | + numstrlen + 6); | |
a4d429e3 | 598 | if (filename == NULL) { |
53118557 HK |
599 | ret = -ENOMEM; |
600 | goto error_close_dir; | |
601 | } | |
602 | ||
603 | ret = sprintf(filename, "%s%s%d/name", iio_dir, | |
604 | type, number); | |
605 | if (ret < 0) { | |
606 | free(filename); | |
607 | goto error_close_dir; | |
a4d429e3 | 608 | } |
53118557 | 609 | |
9d8ae6c8 | 610 | nameFile = fopen(filename, "r"); |
a4d429e3 PM |
611 | if (!nameFile) { |
612 | free(filename); | |
9d8ae6c8 | 613 | continue; |
a4d429e3 | 614 | } |
7663a4aa | 615 | |
9d8ae6c8 | 616 | free(filename); |
53118557 HK |
617 | errno = 0; |
618 | if (fscanf(nameFile, "%s", thisname) != 1) { | |
619 | ret = errno ? -errno : -ENODATA; | |
620 | goto error_close_dir; | |
621 | } | |
622 | ||
623 | if (fclose(nameFile)) { | |
624 | ret = -errno; | |
625 | goto error_close_dir; | |
626 | } | |
627 | ||
a4d429e3 | 628 | if (strcmp(name, thisname) == 0) { |
53118557 HK |
629 | if (closedir(dp) == -1) |
630 | return -errno; | |
7663a4aa | 631 | |
a4d429e3 PM |
632 | return number; |
633 | } | |
c57f1ba7 JC |
634 | } |
635 | } | |
636 | } | |
53118557 HK |
637 | if (closedir(dp) == -1) |
638 | return -errno; | |
639 | ||
9d8ae6c8 | 640 | return -ENODEV; |
096f9b86 HK |
641 | |
642 | error_close_dir: | |
643 | if (closedir(dp) == -1) | |
644 | perror("find_type_by_name(): Failed to close directory"); | |
7663a4aa | 645 | |
096f9b86 | 646 | return ret; |
c57f1ba7 JC |
647 | } |
648 | ||
9d475254 HK |
649 | static int _write_sysfs_int(const char *filename, const char *basedir, int val, |
650 | int verify) | |
c57f1ba7 | 651 | { |
11cb454f | 652 | int ret = 0; |
9d8ae6c8 JC |
653 | FILE *sysfsfp; |
654 | int test; | |
655 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); | |
79bdd48a | 656 | |
9d8ae6c8 JC |
657 | if (temp == NULL) |
658 | return -ENOMEM; | |
7663a4aa | 659 | |
53118557 HK |
660 | ret = sprintf(temp, "%s/%s", basedir, filename); |
661 | if (ret < 0) | |
662 | goto error_free; | |
663 | ||
c57f1ba7 | 664 | sysfsfp = fopen(temp, "w"); |
9d8ae6c8 | 665 | if (sysfsfp == NULL) { |
9d8ae6c8 | 666 | ret = -errno; |
2b6a6e67 | 667 | printf("failed to open %s\n", temp); |
9d8ae6c8 JC |
668 | goto error_free; |
669 | } | |
7663a4aa | 670 | |
53118557 HK |
671 | ret = fprintf(sysfsfp, "%d", val); |
672 | if (ret < 0) { | |
673 | if (fclose(sysfsfp)) | |
674 | perror("_write_sysfs_int(): Failed to close dir"); | |
675 | ||
676 | goto error_free; | |
677 | } | |
678 | ||
679 | if (fclose(sysfsfp)) { | |
680 | ret = -errno; | |
681 | goto error_free; | |
682 | } | |
683 | ||
9d8ae6c8 JC |
684 | if (verify) { |
685 | sysfsfp = fopen(temp, "r"); | |
686 | if (sysfsfp == NULL) { | |
9d8ae6c8 | 687 | ret = -errno; |
2b6a6e67 | 688 | printf("failed to open %s\n", temp); |
9d8ae6c8 JC |
689 | goto error_free; |
690 | } | |
7663a4aa | 691 | |
53118557 HK |
692 | if (fscanf(sysfsfp, "%d", &test) != 1) { |
693 | ret = errno ? -errno : -ENODATA; | |
694 | if (fclose(sysfsfp)) | |
695 | perror("_write_sysfs_int(): Failed to close dir"); | |
696 | ||
697 | goto error_free; | |
698 | } | |
699 | ||
700 | if (fclose(sysfsfp)) { | |
701 | ret = -errno; | |
702 | goto error_free; | |
703 | } | |
704 | ||
9d8ae6c8 | 705 | if (test != val) { |
7663a4aa HK |
706 | printf("Possible failure in int write %d to %s/%s\n", |
707 | val, basedir, filename); | |
9d8ae6c8 JC |
708 | ret = -1; |
709 | } | |
710 | } | |
7663a4aa | 711 | |
9d8ae6c8 JC |
712 | error_free: |
713 | free(temp); | |
714 | return ret; | |
715 | } | |
716 | ||
5dc65d79 HK |
717 | /** |
718 | * write_sysfs_int() - write an integer value to a sysfs file | |
719 | * @filename: name of the file to write to | |
720 | * @basedir: the sysfs directory in which the file is to be found | |
721 | * @val: integer value to write to file | |
722 | * | |
723 | * Returns a value >= 0 on success, otherwise a negative error code. | |
724 | **/ | |
9d475254 | 725 | int write_sysfs_int(const char *filename, const char *basedir, int val) |
9d8ae6c8 JC |
726 | { |
727 | return _write_sysfs_int(filename, basedir, val, 0); | |
c57f1ba7 JC |
728 | } |
729 | ||
5dc65d79 HK |
730 | /** |
731 | * write_sysfs_int_and_verify() - write an integer value to a sysfs file | |
732 | * and verify | |
733 | * @filename: name of the file to write to | |
734 | * @basedir: the sysfs directory in which the file is to be found | |
735 | * @val: integer value to write to file | |
736 | * | |
737 | * Returns a value >= 0 on success, otherwise a negative error code. | |
738 | **/ | |
9d475254 HK |
739 | int write_sysfs_int_and_verify(const char *filename, const char *basedir, |
740 | int val) | |
9d8ae6c8 JC |
741 | { |
742 | return _write_sysfs_int(filename, basedir, val, 1); | |
743 | } | |
744 | ||
9d475254 HK |
745 | static int _write_sysfs_string(const char *filename, const char *basedir, |
746 | const char *val, int verify) | |
eaf86ff9 | 747 | { |
e58537cc | 748 | int ret = 0; |
eaf86ff9 | 749 | FILE *sysfsfp; |
9d8ae6c8 | 750 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); |
79bdd48a | 751 | |
9d8ae6c8 JC |
752 | if (temp == NULL) { |
753 | printf("Memory allocation failed\n"); | |
754 | return -ENOMEM; | |
755 | } | |
7663a4aa | 756 | |
53118557 HK |
757 | ret = sprintf(temp, "%s/%s", basedir, filename); |
758 | if (ret < 0) | |
759 | goto error_free; | |
760 | ||
eaf86ff9 | 761 | sysfsfp = fopen(temp, "w"); |
9d8ae6c8 | 762 | if (sysfsfp == NULL) { |
9d8ae6c8 | 763 | ret = -errno; |
2b6a6e67 | 764 | printf("Could not open %s\n", temp); |
9d8ae6c8 JC |
765 | goto error_free; |
766 | } | |
7663a4aa | 767 | |
53118557 HK |
768 | ret = fprintf(sysfsfp, "%s", val); |
769 | if (ret < 0) { | |
770 | if (fclose(sysfsfp)) | |
771 | perror("_write_sysfs_string(): Failed to close dir"); | |
772 | ||
773 | goto error_free; | |
774 | } | |
775 | ||
776 | if (fclose(sysfsfp)) { | |
777 | ret = -errno; | |
778 | goto error_free; | |
779 | } | |
780 | ||
9d8ae6c8 JC |
781 | if (verify) { |
782 | sysfsfp = fopen(temp, "r"); | |
783 | if (sysfsfp == NULL) { | |
784 | ret = -errno; | |
7663a4aa | 785 | printf("Could not open file to verify\n"); |
9d8ae6c8 JC |
786 | goto error_free; |
787 | } | |
7663a4aa | 788 | |
53118557 HK |
789 | if (fscanf(sysfsfp, "%s", temp) != 1) { |
790 | ret = errno ? -errno : -ENODATA; | |
791 | if (fclose(sysfsfp)) | |
792 | perror("_write_sysfs_string(): Failed to close dir"); | |
793 | ||
794 | goto error_free; | |
795 | } | |
796 | ||
797 | if (fclose(sysfsfp)) { | |
798 | ret = -errno; | |
799 | goto error_free; | |
800 | } | |
801 | ||
9d8ae6c8 JC |
802 | if (strcmp(temp, val) != 0) { |
803 | printf("Possible failure in string write of %s " | |
7663a4aa HK |
804 | "Should be %s written to %s/%s\n", temp, val, |
805 | basedir, filename); | |
9d8ae6c8 JC |
806 | ret = -1; |
807 | } | |
eaf86ff9 | 808 | } |
7663a4aa | 809 | |
9d8ae6c8 JC |
810 | error_free: |
811 | free(temp); | |
eaf86ff9 | 812 | |
9d8ae6c8 | 813 | return ret; |
eaf86ff9 | 814 | } |
e58537cc | 815 | |
c57f1ba7 JC |
816 | /** |
817 | * write_sysfs_string_and_verify() - string write, readback and verify | |
818 | * @filename: name of file to write to | |
819 | * @basedir: the sysfs directory in which the file is to be found | |
820 | * @val: the string to write | |
5dc65d79 HK |
821 | * |
822 | * Returns a value >= 0 on success, otherwise a negative error code. | |
c57f1ba7 | 823 | **/ |
9d475254 HK |
824 | int write_sysfs_string_and_verify(const char *filename, const char *basedir, |
825 | const char *val) | |
c57f1ba7 | 826 | { |
9d8ae6c8 JC |
827 | return _write_sysfs_string(filename, basedir, val, 1); |
828 | } | |
c57f1ba7 | 829 | |
5dc65d79 HK |
830 | /** |
831 | * write_sysfs_string() - write string to a sysfs file | |
832 | * @filename: name of file to write to | |
833 | * @basedir: the sysfs directory in which the file is to be found | |
834 | * @val: the string to write | |
835 | * | |
836 | * Returns a value >= 0 on success, otherwise a negative error code. | |
837 | **/ | |
9d475254 HK |
838 | int write_sysfs_string(const char *filename, const char *basedir, |
839 | const char *val) | |
9d8ae6c8 JC |
840 | { |
841 | return _write_sysfs_string(filename, basedir, val, 0); | |
c57f1ba7 JC |
842 | } |
843 | ||
5dc65d79 HK |
844 | /** |
845 | * read_sysfs_posint() - read an integer value from file | |
846 | * @filename: name of file to read from | |
847 | * @basedir: the sysfs directory in which the file is to be found | |
848 | * | |
849 | * Returns the read integer value >= 0 on success, otherwise a negative error | |
850 | * code. | |
851 | **/ | |
9d475254 | 852 | int read_sysfs_posint(const char *filename, const char *basedir) |
c57f1ba7 JC |
853 | { |
854 | int ret; | |
855 | FILE *sysfsfp; | |
9d8ae6c8 | 856 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); |
79bdd48a | 857 | |
9d8ae6c8 JC |
858 | if (temp == NULL) { |
859 | printf("Memory allocation failed"); | |
860 | return -ENOMEM; | |
861 | } | |
7663a4aa | 862 | |
53118557 HK |
863 | ret = sprintf(temp, "%s/%s", basedir, filename); |
864 | if (ret < 0) | |
865 | goto error_free; | |
866 | ||
c57f1ba7 | 867 | sysfsfp = fopen(temp, "r"); |
9d8ae6c8 JC |
868 | if (sysfsfp == NULL) { |
869 | ret = -errno; | |
870 | goto error_free; | |
871 | } | |
7663a4aa | 872 | |
53118557 HK |
873 | errno = 0; |
874 | if (fscanf(sysfsfp, "%d\n", &ret) != 1) { | |
875 | ret = errno ? -errno : -ENODATA; | |
876 | if (fclose(sysfsfp)) | |
877 | perror("read_sysfs_posint(): Failed to close dir"); | |
878 | ||
879 | goto error_free; | |
880 | } | |
881 | ||
882 | if (fclose(sysfsfp)) | |
883 | ret = -errno; | |
884 | ||
9d8ae6c8 JC |
885 | error_free: |
886 | free(temp); | |
7663a4aa | 887 | |
9d8ae6c8 JC |
888 | return ret; |
889 | } | |
890 | ||
5dc65d79 HK |
891 | /** |
892 | * read_sysfs_float() - read a float value from file | |
893 | * @filename: name of file to read from | |
894 | * @basedir: the sysfs directory in which the file is to be found | |
895 | * @val: output the read float value | |
896 | * | |
897 | * Returns a value >= 0 on success, otherwise a negative error code. | |
898 | **/ | |
9d475254 | 899 | int read_sysfs_float(const char *filename, const char *basedir, float *val) |
9d8ae6c8 | 900 | { |
f5709d5f | 901 | int ret = 0; |
9d8ae6c8 JC |
902 | FILE *sysfsfp; |
903 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); | |
79bdd48a | 904 | |
9d8ae6c8 JC |
905 | if (temp == NULL) { |
906 | printf("Memory allocation failed"); | |
907 | return -ENOMEM; | |
908 | } | |
7663a4aa | 909 | |
53118557 HK |
910 | ret = sprintf(temp, "%s/%s", basedir, filename); |
911 | if (ret < 0) | |
912 | goto error_free; | |
913 | ||
9d8ae6c8 JC |
914 | sysfsfp = fopen(temp, "r"); |
915 | if (sysfsfp == NULL) { | |
916 | ret = -errno; | |
917 | goto error_free; | |
918 | } | |
7663a4aa | 919 | |
53118557 HK |
920 | errno = 0; |
921 | if (fscanf(sysfsfp, "%f\n", val) != 1) { | |
922 | ret = errno ? -errno : -ENODATA; | |
923 | if (fclose(sysfsfp)) | |
924 | perror("read_sysfs_float(): Failed to close dir"); | |
925 | ||
926 | goto error_free; | |
927 | } | |
928 | ||
929 | if (fclose(sysfsfp)) | |
930 | ret = -errno; | |
931 | ||
9d8ae6c8 JC |
932 | error_free: |
933 | free(temp); | |
7663a4aa | 934 | |
c57f1ba7 JC |
935 | return ret; |
936 | } | |
49d916ec | 937 | |
5dc65d79 HK |
938 | /** |
939 | * read_sysfs_string() - read a string from file | |
940 | * @filename: name of file to read from | |
941 | * @basedir: the sysfs directory in which the file is to be found | |
942 | * @str: output the read string | |
943 | * | |
944 | * Returns a value >= 0 on success, otherwise a negative error code. | |
945 | **/ | |
f5709d5f | 946 | int read_sysfs_string(const char *filename, const char *basedir, char *str) |
49d916ec | 947 | { |
f5709d5f | 948 | int ret = 0; |
49d916ec MS |
949 | FILE *sysfsfp; |
950 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); | |
79bdd48a | 951 | |
49d916ec MS |
952 | if (temp == NULL) { |
953 | printf("Memory allocation failed"); | |
954 | return -ENOMEM; | |
955 | } | |
7663a4aa | 956 | |
53118557 HK |
957 | ret = sprintf(temp, "%s/%s", basedir, filename); |
958 | if (ret < 0) | |
959 | goto error_free; | |
960 | ||
49d916ec MS |
961 | sysfsfp = fopen(temp, "r"); |
962 | if (sysfsfp == NULL) { | |
963 | ret = -errno; | |
964 | goto error_free; | |
965 | } | |
7663a4aa | 966 | |
53118557 HK |
967 | errno = 0; |
968 | if (fscanf(sysfsfp, "%s\n", str) != 1) { | |
969 | ret = errno ? -errno : -ENODATA; | |
970 | if (fclose(sysfsfp)) | |
971 | perror("read_sysfs_string(): Failed to close dir"); | |
972 | ||
973 | goto error_free; | |
974 | } | |
975 | ||
976 | if (fclose(sysfsfp)) | |
977 | ret = -errno; | |
978 | ||
49d916ec MS |
979 | error_free: |
980 | free(temp); | |
7663a4aa | 981 | |
49d916ec MS |
982 | return ret; |
983 | } | |
37e3be9d CO |
984 | |
985 | #endif /* _IIO_UTILS_H */ |