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