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 | */ | |
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 |
24 | const 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 | 31 | inline 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 | **/ | |
68 | struct 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 | 79 | unsigned is_signed; |
e58537cc JC |
80 | unsigned location; |
81 | }; | |
82 | ||
83 | /** | |
84 | * iioutils_get_type() - find and process _type attribute data | |
85 | * @is_signed: output whether channel is signed | |
86 | * @bytes: output how many bytes the channel storage occupies | |
87 | * @mask: output a bit mask for the raw data | |
117cf8b7 | 88 | * @be: big endian |
e58537cc JC |
89 | * @device_dir: the iio device directory |
90 | * @name: the channel name | |
91 | * @generic_name: the channel type name | |
92 | **/ | |
93 | inline int iioutils_get_type(unsigned *is_signed, | |
94 | unsigned *bytes, | |
95 | unsigned *bits_used, | |
52615d47 | 96 | unsigned *shift, |
e58537cc | 97 | uint64_t *mask, |
117cf8b7 | 98 | unsigned *be, |
e58537cc JC |
99 | const char *device_dir, |
100 | const char *name, | |
101 | const char *generic_name) | |
102 | { | |
103 | FILE *sysfsfp; | |
104 | int ret; | |
105 | DIR *dp; | |
106 | char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; | |
117cf8b7 | 107 | char signchar, endianchar; |
fc7f95a9 | 108 | unsigned padint; |
e58537cc JC |
109 | const struct dirent *ent; |
110 | ||
111 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); | |
112 | if (ret < 0) { | |
113 | ret = -ENOMEM; | |
114 | goto error_ret; | |
115 | } | |
116 | ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); | |
117 | if (ret < 0) { | |
118 | ret = -ENOMEM; | |
119 | goto error_free_scan_el_dir; | |
120 | } | |
121 | ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); | |
122 | if (ret < 0) { | |
123 | ret = -ENOMEM; | |
124 | goto error_free_builtname; | |
125 | } | |
126 | ||
127 | dp = opendir(scan_el_dir); | |
128 | if (dp == NULL) { | |
129 | ret = -errno; | |
130 | goto error_free_builtname_generic; | |
131 | } | |
132 | while (ent = readdir(dp), ent != NULL) | |
133 | /* | |
134 | * Do we allow devices to override a generic name with | |
135 | * a specific one? | |
136 | */ | |
137 | if ((strcmp(builtname, ent->d_name) == 0) || | |
138 | (strcmp(builtname_generic, ent->d_name) == 0)) { | |
139 | ret = asprintf(&filename, | |
140 | "%s/%s", scan_el_dir, ent->d_name); | |
141 | if (ret < 0) { | |
142 | ret = -ENOMEM; | |
143 | goto error_closedir; | |
144 | } | |
145 | sysfsfp = fopen(filename, "r"); | |
146 | if (sysfsfp == NULL) { | |
147 | printf("failed to open %s\n", filename); | |
148 | ret = -errno; | |
149 | goto error_free_filename; | |
150 | } | |
a7f7c364 JC |
151 | |
152 | ret = fscanf(sysfsfp, | |
153 | "%ce:%c%u/%u>>%u", | |
154 | &endianchar, | |
155 | &signchar, | |
156 | bits_used, | |
157 | &padint, shift); | |
158 | if (ret < 0) { | |
159 | printf("failed to pass scan type description\n"); | |
578f737d PM |
160 | ret = -errno; |
161 | goto error_close_sysfsfp; | |
a7f7c364 | 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; | |
169 | if (signchar == 's') | |
170 | *is_signed = 1; | |
171 | else | |
172 | *is_signed = 0; | |
a7f7c364 JC |
173 | fclose(sysfsfp); |
174 | free(filename); | |
175 | ||
176 | filename = 0; | |
578f737d | 177 | sysfsfp = 0; |
e58537cc | 178 | } |
578f737d PM |
179 | error_close_sysfsfp: |
180 | if (sysfsfp) | |
181 | fclose(sysfsfp); | |
e58537cc JC |
182 | error_free_filename: |
183 | if (filename) | |
184 | free(filename); | |
185 | error_closedir: | |
186 | closedir(dp); | |
187 | error_free_builtname_generic: | |
188 | free(builtname_generic); | |
189 | error_free_builtname: | |
190 | free(builtname); | |
191 | error_free_scan_el_dir: | |
192 | free(scan_el_dir); | |
193 | error_ret: | |
194 | return ret; | |
195 | } | |
196 | ||
197 | inline int iioutils_get_param_float(float *output, | |
198 | const char *param_name, | |
199 | const char *device_dir, | |
200 | const char *name, | |
201 | const char *generic_name) | |
202 | { | |
203 | FILE *sysfsfp; | |
204 | int ret; | |
205 | DIR *dp; | |
206 | char *builtname, *builtname_generic; | |
207 | char *filename = NULL; | |
208 | const struct dirent *ent; | |
209 | ||
210 | ret = asprintf(&builtname, "%s_%s", name, param_name); | |
211 | if (ret < 0) { | |
212 | ret = -ENOMEM; | |
213 | goto error_ret; | |
214 | } | |
215 | ret = asprintf(&builtname_generic, | |
216 | "%s_%s", generic_name, param_name); | |
217 | if (ret < 0) { | |
218 | ret = -ENOMEM; | |
219 | goto error_free_builtname; | |
220 | } | |
221 | dp = opendir(device_dir); | |
222 | if (dp == NULL) { | |
223 | ret = -errno; | |
224 | goto error_free_builtname_generic; | |
225 | } | |
226 | while (ent = readdir(dp), ent != NULL) | |
227 | if ((strcmp(builtname, ent->d_name) == 0) || | |
228 | (strcmp(builtname_generic, ent->d_name) == 0)) { | |
229 | ret = asprintf(&filename, | |
230 | "%s/%s", device_dir, ent->d_name); | |
231 | if (ret < 0) { | |
232 | ret = -ENOMEM; | |
233 | goto error_closedir; | |
234 | } | |
235 | sysfsfp = fopen(filename, "r"); | |
236 | if (!sysfsfp) { | |
237 | ret = -errno; | |
238 | goto error_free_filename; | |
239 | } | |
240 | fscanf(sysfsfp, "%f", output); | |
241 | break; | |
242 | } | |
243 | error_free_filename: | |
244 | if (filename) | |
245 | free(filename); | |
246 | error_closedir: | |
247 | closedir(dp); | |
248 | error_free_builtname_generic: | |
249 | free(builtname_generic); | |
250 | error_free_builtname: | |
251 | free(builtname); | |
252 | error_ret: | |
253 | return ret; | |
254 | } | |
255 | ||
8b68bb20 MH |
256 | /** |
257 | * bsort_channel_array_by_index() - reorder so that the array is in index order | |
258 | * | |
259 | **/ | |
260 | ||
261 | inline void bsort_channel_array_by_index(struct iio_channel_info **ci_array, | |
262 | int cnt) | |
263 | { | |
264 | ||
265 | struct iio_channel_info temp; | |
266 | int x, y; | |
267 | ||
268 | for (x = 0; x < cnt; x++) | |
269 | for (y = 0; y < (cnt - 1); y++) | |
270 | if ((*ci_array)[y].index > (*ci_array)[y+1].index) { | |
271 | temp = (*ci_array)[y + 1]; | |
272 | (*ci_array)[y + 1] = (*ci_array)[y]; | |
273 | (*ci_array)[y] = temp; | |
274 | } | |
275 | } | |
e58537cc JC |
276 | |
277 | /** | |
278 | * build_channel_array() - function to figure out what channels are present | |
279 | * @device_dir: the IIO device directory in sysfs | |
280 | * @ | |
281 | **/ | |
282 | inline int build_channel_array(const char *device_dir, | |
283 | struct iio_channel_info **ci_array, | |
284 | int *counter) | |
285 | { | |
286 | DIR *dp; | |
287 | FILE *sysfsfp; | |
10937921 | 288 | int count, i; |
e58537cc JC |
289 | struct iio_channel_info *current; |
290 | int ret; | |
291 | const struct dirent *ent; | |
292 | char *scan_el_dir; | |
293 | char *filename; | |
294 | ||
295 | *counter = 0; | |
296 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); | |
297 | if (ret < 0) { | |
298 | ret = -ENOMEM; | |
299 | goto error_ret; | |
300 | } | |
301 | dp = opendir(scan_el_dir); | |
302 | if (dp == NULL) { | |
303 | ret = -errno; | |
304 | goto error_free_name; | |
305 | } | |
306 | while (ent = readdir(dp), ent != NULL) | |
307 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), | |
308 | "_en") == 0) { | |
309 | ret = asprintf(&filename, | |
310 | "%s/%s", scan_el_dir, ent->d_name); | |
311 | if (ret < 0) { | |
312 | ret = -ENOMEM; | |
313 | goto error_close_dir; | |
314 | } | |
315 | sysfsfp = fopen(filename, "r"); | |
316 | if (sysfsfp == NULL) { | |
317 | ret = -errno; | |
318 | free(filename); | |
319 | goto error_close_dir; | |
320 | } | |
321 | fscanf(sysfsfp, "%u", &ret); | |
322 | if (ret == 1) | |
323 | (*counter)++; | |
324 | fclose(sysfsfp); | |
325 | free(filename); | |
326 | } | |
8b68bb20 | 327 | *ci_array = malloc(sizeof(**ci_array) * (*counter)); |
e58537cc JC |
328 | if (*ci_array == NULL) { |
329 | ret = -ENOMEM; | |
330 | goto error_close_dir; | |
331 | } | |
332 | seekdir(dp, 0); | |
7ccd4506 | 333 | count = 0; |
e58537cc JC |
334 | while (ent = readdir(dp), ent != NULL) { |
335 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), | |
336 | "_en") == 0) { | |
66c65d90 | 337 | int current_enabled = 0; |
e58537cc JC |
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 | } | |
66c65d90 | 353 | fscanf(sysfsfp, "%u", ¤t_enabled); |
e58537cc | 354 | fclose(sysfsfp); |
8b68bb20 | 355 | |
66c65d90 | 356 | if (!current_enabled) { |
8b68bb20 MH |
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 | ¤t->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", ¤t->index); | |
390 | fclose(sysfsfp); | |
391 | free(filename); | |
392 | /* Find the scale */ | |
393 | ret = iioutils_get_param_float(¤t->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(¤t->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(¤t->is_signed, | |
408 | ¤t->bytes, | |
409 | ¤t->bits_used, | |
52615d47 | 410 | ¤t->shift, |
e58537cc | 411 | ¤t->mask, |
117cf8b7 | 412 | ¤t->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 | ||
425 | error_cleanup_array: | |
267024a9 | 426 | for (i = count - 1; i >= 0; i--) |
e58537cc JC |
427 | free((*ci_array)[i].name); |
428 | free(*ci_array); | |
429 | error_close_dir: | |
430 | closedir(dp); | |
431 | error_free_name: | |
432 | free(scan_el_dir); | |
433 | error_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 | **/ | |
444 | inline 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 | 503 | inline 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 | } | |
537 | error_free: | |
538 | free(temp); | |
539 | return ret; | |
540 | } | |
541 | ||
542 | int write_sysfs_int(char *filename, char *basedir, int val) | |
543 | { | |
544 | return _write_sysfs_int(filename, basedir, val, 0); | |
c57f1ba7 JC |
545 | } |
546 | ||
eaf86ff9 | 547 | int 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 | ||
552 | int _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 |
590 | error_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 | **/ | |
602 | int 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 |
607 | int write_sysfs_string(char *filename, char *basedir, char *val) |
608 | { | |
609 | return _write_sysfs_string(filename, basedir, val, 0); | |
c57f1ba7 JC |
610 | } |
611 | ||
612 | int 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 |
629 | error_free: |
630 | free(temp); | |
631 | return ret; | |
632 | } | |
633 | ||
634 | int 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); | |
651 | error_free: | |
652 | free(temp); | |
c57f1ba7 JC |
653 | return ret; |
654 | } |