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