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