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