Merge tag 'docs-4.9-2' of git://git.lwn.net/linux
[sfrench/cifs-2.6.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 = ~0;
163                         else
164                                 *mask = (1ULL << *bits_used) - 1;
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                         break;
269                 }
270 error_free_filename:
271         if (filename)
272                 free(filename);
273
274 error_closedir:
275         if (closedir(dp) == -1)
276                 perror("iioutils_get_param_float(): Failed to close directory");
277
278 error_free_builtname_generic:
279         free(builtname_generic);
280 error_free_builtname:
281         free(builtname);
282
283         return ret;
284 }
285
286 /**
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
290  **/
291
292 void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt)
293 {
294         struct iio_channel_info temp;
295         int x, y;
296
297         for (x = 0; x < cnt; x++)
298                 for (y = 0; y < (cnt - 1); y++)
299                         if (ci_array[y].index > ci_array[y + 1].index) {
300                                 temp = ci_array[y + 1];
301                                 ci_array[y + 1] = ci_array[y];
302                                 ci_array[y] = temp;
303                         }
304 }
305
306 /**
307  * build_channel_array() - function to figure out what channels are present
308  * @device_dir: the IIO device directory in sysfs
309  * @ci_array: output the resulting array of iio_channel_info
310  * @counter: output the amount of array elements
311  *
312  * Returns 0 on success, otherwise a negative error code.
313  **/
314 int build_channel_array(const char *device_dir,
315                         struct iio_channel_info **ci_array, int *counter)
316 {
317         DIR *dp;
318         FILE *sysfsfp;
319         int count = 0, i;
320         struct iio_channel_info *current;
321         int ret;
322         const struct dirent *ent;
323         char *scan_el_dir;
324         char *filename;
325
326         *counter = 0;
327         ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
328         if (ret < 0)
329                 return -ENOMEM;
330
331         dp = opendir(scan_el_dir);
332         if (!dp) {
333                 ret = -errno;
334                 goto error_free_name;
335         }
336
337         while (ent = readdir(dp), ent)
338                 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
339                            "_en") == 0) {
340                         ret = asprintf(&filename,
341                                        "%s/%s", scan_el_dir, ent->d_name);
342                         if (ret < 0) {
343                                 ret = -ENOMEM;
344                                 goto error_close_dir;
345                         }
346
347                         sysfsfp = fopen(filename, "r");
348                         if (!sysfsfp) {
349                                 ret = -errno;
350                                 free(filename);
351                                 goto error_close_dir;
352                         }
353
354                         errno = 0;
355                         if (fscanf(sysfsfp, "%i", &ret) != 1) {
356                                 ret = errno ? -errno : -ENODATA;
357                                 if (fclose(sysfsfp))
358                                         perror("build_channel_array(): Failed to close file");
359
360                                 free(filename);
361                                 goto error_close_dir;
362                         }
363                         if (ret == 1)
364                                 (*counter)++;
365
366                         if (fclose(sysfsfp)) {
367                                 ret = -errno;
368                                 free(filename);
369                                 goto error_close_dir;
370                         }
371
372                         free(filename);
373                 }
374
375         *ci_array = malloc(sizeof(**ci_array) * (*counter));
376         if (!*ci_array) {
377                 ret = -ENOMEM;
378                 goto error_close_dir;
379         }
380
381         seekdir(dp, 0);
382         while (ent = readdir(dp), ent) {
383                 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
384                            "_en") == 0) {
385                         int current_enabled = 0;
386
387                         current = &(*ci_array)[count++];
388                         ret = asprintf(&filename,
389                                        "%s/%s", scan_el_dir, ent->d_name);
390                         if (ret < 0) {
391                                 ret = -ENOMEM;
392                                 /* decrement count to avoid freeing name */
393                                 count--;
394                                 goto error_cleanup_array;
395                         }
396
397                         sysfsfp = fopen(filename, "r");
398                         if (!sysfsfp) {
399                                 ret = -errno;
400                                 free(filename);
401                                 count--;
402                                 goto error_cleanup_array;
403                         }
404
405                         errno = 0;
406                         if (fscanf(sysfsfp, "%i", &current_enabled) != 1) {
407                                 ret = errno ? -errno : -ENODATA;
408                                 free(filename);
409                                 count--;
410                                 goto error_cleanup_array;
411                         }
412
413                         if (fclose(sysfsfp)) {
414                                 ret = -errno;
415                                 free(filename);
416                                 count--;
417                                 goto error_cleanup_array;
418                         }
419
420                         if (!current_enabled) {
421                                 free(filename);
422                                 count--;
423                                 continue;
424                         }
425
426                         current->scale = 1.0;
427                         current->offset = 0;
428                         current->name = strndup(ent->d_name,
429                                                 strlen(ent->d_name) -
430                                                 strlen("_en"));
431                         if (!current->name) {
432                                 free(filename);
433                                 ret = -ENOMEM;
434                                 count--;
435                                 goto error_cleanup_array;
436                         }
437
438                         /* Get the generic and specific name elements */
439                         ret = iioutils_break_up_name(current->name,
440                                                      &current->generic_name);
441                         if (ret) {
442                                 free(filename);
443                                 free(current->name);
444                                 count--;
445                                 goto error_cleanup_array;
446                         }
447
448                         ret = asprintf(&filename,
449                                        "%s/%s_index",
450                                        scan_el_dir,
451                                        current->name);
452                         if (ret < 0) {
453                                 free(filename);
454                                 ret = -ENOMEM;
455                                 goto error_cleanup_array;
456                         }
457
458                         sysfsfp = fopen(filename, "r");
459                         if (!sysfsfp) {
460                                 ret = -errno;
461                                 fprintf(stderr, "failed to open %s\n",
462                                         filename);
463                                 free(filename);
464                                 goto error_cleanup_array;
465                         }
466
467                         errno = 0;
468                         if (fscanf(sysfsfp, "%u", &current->index) != 1) {
469                                 ret = errno ? -errno : -ENODATA;
470                                 if (fclose(sysfsfp))
471                                         perror("build_channel_array(): Failed to close file");
472
473                                 free(filename);
474                                 goto error_cleanup_array;
475                         }
476
477                         if (fclose(sysfsfp)) {
478                                 ret = -errno;
479                                 free(filename);
480                                 goto error_cleanup_array;
481                         }
482
483                         free(filename);
484                         /* Find the scale */
485                         ret = iioutils_get_param_float(&current->scale,
486                                                        "scale",
487                                                        device_dir,
488                                                        current->name,
489                                                        current->generic_name);
490                         if ((ret < 0) && (ret != -ENOENT))
491                                 goto error_cleanup_array;
492
493                         ret = iioutils_get_param_float(&current->offset,
494                                                        "offset",
495                                                        device_dir,
496                                                        current->name,
497                                                        current->generic_name);
498                         if ((ret < 0) && (ret != -ENOENT))
499                                 goto error_cleanup_array;
500
501                         ret = iioutils_get_type(&current->is_signed,
502                                                 &current->bytes,
503                                                 &current->bits_used,
504                                                 &current->shift,
505                                                 &current->mask,
506                                                 &current->be,
507                                                 device_dir,
508                                                 current->name,
509                                                 current->generic_name);
510                         if (ret < 0)
511                                 goto error_cleanup_array;
512                 }
513         }
514
515         if (closedir(dp) == -1) {
516                 ret = -errno;
517                 goto error_cleanup_array;
518         }
519
520         free(scan_el_dir);
521         /* reorder so that the array is in index order */
522         bsort_channel_array_by_index(*ci_array, *counter);
523
524         return 0;
525
526 error_cleanup_array:
527         for (i = count - 1;  i >= 0; i--) {
528                 free((*ci_array)[i].name);
529                 free((*ci_array)[i].generic_name);
530         }
531         free(*ci_array);
532         *ci_array = NULL;
533         *counter = 0;
534 error_close_dir:
535         if (dp)
536                 if (closedir(dp) == -1)
537                         perror("build_channel_array(): Failed to close dir");
538
539 error_free_name:
540         free(scan_el_dir);
541
542         return ret;
543 }
544
545 static int calc_digits(int num)
546 {
547         int count = 0;
548
549         while (num != 0) {
550                 num /= 10;
551                 count++;
552         }
553
554         return count;
555 }
556
557 /**
558  * find_type_by_name() - function to match top level types by name
559  * @name: top level type instance name
560  * @type: the type of top level instance being searched
561  *
562  * Returns the device number of a matched IIO device on success, otherwise a
563  * negative error code.
564  * Typical types this is used for are device and trigger.
565  **/
566 int find_type_by_name(const char *name, const char *type)
567 {
568         const struct dirent *ent;
569         int number, numstrlen, ret;
570
571         FILE *namefp;
572         DIR *dp;
573         char thisname[IIO_MAX_NAME_LENGTH];
574         char *filename;
575
576         dp = opendir(iio_dir);
577         if (!dp) {
578                 fprintf(stderr, "No industrialio devices available\n");
579                 return -ENODEV;
580         }
581
582         while (ent = readdir(dp), ent) {
583                 if (strcmp(ent->d_name, ".") != 0 &&
584                     strcmp(ent->d_name, "..") != 0 &&
585                     strlen(ent->d_name) > strlen(type) &&
586                     strncmp(ent->d_name, type, strlen(type)) == 0) {
587                         errno = 0;
588                         ret = sscanf(ent->d_name + strlen(type), "%d", &number);
589                         if (ret < 0) {
590                                 ret = -errno;
591                                 fprintf(stderr,
592                                         "failed to read element number\n");
593                                 goto error_close_dir;
594                         } else if (ret != 1) {
595                                 ret = -EIO;
596                                 fprintf(stderr,
597                                         "failed to match element number\n");
598                                 goto error_close_dir;
599                         }
600
601                         numstrlen = calc_digits(number);
602                         /* verify the next character is not a colon */
603                         if (strncmp(ent->d_name + strlen(type) + numstrlen,
604                             ":", 1) != 0) {
605                                 filename = malloc(strlen(iio_dir) + strlen(type)
606                                                   + numstrlen + 6);
607                                 if (!filename) {
608                                         ret = -ENOMEM;
609                                         goto error_close_dir;
610                                 }
611
612                                 ret = sprintf(filename, "%s%s%d/name", iio_dir,
613                                               type, number);
614                                 if (ret < 0) {
615                                         free(filename);
616                                         goto error_close_dir;
617                                 }
618
619                                 namefp = fopen(filename, "r");
620                                 if (!namefp) {
621                                         free(filename);
622                                         continue;
623                                 }
624
625                                 free(filename);
626                                 errno = 0;
627                                 if (fscanf(namefp, "%s", thisname) != 1) {
628                                         ret = errno ? -errno : -ENODATA;
629                                         goto error_close_dir;
630                                 }
631
632                                 if (fclose(namefp)) {
633                                         ret = -errno;
634                                         goto error_close_dir;
635                                 }
636
637                                 if (strcmp(name, thisname) == 0) {
638                                         if (closedir(dp) == -1)
639                                                 return -errno;
640
641                                         return number;
642                                 }
643                         }
644                 }
645         }
646         if (closedir(dp) == -1)
647                 return -errno;
648
649         return -ENODEV;
650
651 error_close_dir:
652         if (closedir(dp) == -1)
653                 perror("find_type_by_name(): Failed to close directory");
654
655         return ret;
656 }
657
658 static int _write_sysfs_int(const char *filename, const char *basedir, int val,
659                             int verify)
660 {
661         int ret = 0;
662         FILE *sysfsfp;
663         int test;
664         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
665
666         if (!temp)
667                 return -ENOMEM;
668
669         ret = sprintf(temp, "%s/%s", basedir, filename);
670         if (ret < 0)
671                 goto error_free;
672
673         sysfsfp = fopen(temp, "w");
674         if (!sysfsfp) {
675                 ret = -errno;
676                 fprintf(stderr, "failed to open %s\n", temp);
677                 goto error_free;
678         }
679
680         ret = fprintf(sysfsfp, "%d", val);
681         if (ret < 0) {
682                 if (fclose(sysfsfp))
683                         perror("_write_sysfs_int(): Failed to close dir");
684
685                 goto error_free;
686         }
687
688         if (fclose(sysfsfp)) {
689                 ret = -errno;
690                 goto error_free;
691         }
692
693         if (verify) {
694                 sysfsfp = fopen(temp, "r");
695                 if (!sysfsfp) {
696                         ret = -errno;
697                         fprintf(stderr, "failed to open %s\n", temp);
698                         goto error_free;
699                 }
700
701                 if (fscanf(sysfsfp, "%d", &test) != 1) {
702                         ret = errno ? -errno : -ENODATA;
703                         if (fclose(sysfsfp))
704                                 perror("_write_sysfs_int(): Failed to close dir");
705
706                         goto error_free;
707                 }
708
709                 if (fclose(sysfsfp)) {
710                         ret = -errno;
711                         goto error_free;
712                 }
713
714                 if (test != val) {
715                         fprintf(stderr,
716                                 "Possible failure in int write %d to %s/%s\n",
717                                 val, basedir, filename);
718                         ret = -1;
719                 }
720         }
721
722 error_free:
723         free(temp);
724         return ret;
725 }
726
727 /**
728  * write_sysfs_int() - write an integer value to a sysfs file
729  * @filename: name of the file to write to
730  * @basedir: the sysfs directory in which the file is to be found
731  * @val: integer value to write to file
732  *
733  * Returns a value >= 0 on success, otherwise a negative error code.
734  **/
735 int write_sysfs_int(const char *filename, const char *basedir, int val)
736 {
737         return _write_sysfs_int(filename, basedir, val, 0);
738 }
739
740 /**
741  * write_sysfs_int_and_verify() - write an integer value to a sysfs file
742  *                                and verify
743  * @filename: name of the file to write to
744  * @basedir: the sysfs directory in which the file is to be found
745  * @val: integer value to write to file
746  *
747  * Returns a value >= 0 on success, otherwise a negative error code.
748  **/
749 int write_sysfs_int_and_verify(const char *filename, const char *basedir,
750                                int val)
751 {
752         return _write_sysfs_int(filename, basedir, val, 1);
753 }
754
755 static int _write_sysfs_string(const char *filename, const char *basedir,
756                                const char *val, int verify)
757 {
758         int ret = 0;
759         FILE  *sysfsfp;
760         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
761
762         if (!temp) {
763                 fprintf(stderr, "Memory allocation failed\n");
764                 return -ENOMEM;
765         }
766
767         ret = sprintf(temp, "%s/%s", basedir, filename);
768         if (ret < 0)
769                 goto error_free;
770
771         sysfsfp = fopen(temp, "w");
772         if (!sysfsfp) {
773                 ret = -errno;
774                 fprintf(stderr, "Could not open %s\n", temp);
775                 goto error_free;
776         }
777
778         ret = fprintf(sysfsfp, "%s", val);
779         if (ret < 0) {
780                 if (fclose(sysfsfp))
781                         perror("_write_sysfs_string(): Failed to close dir");
782
783                 goto error_free;
784         }
785
786         if (fclose(sysfsfp)) {
787                 ret = -errno;
788                 goto error_free;
789         }
790
791         if (verify) {
792                 sysfsfp = fopen(temp, "r");
793                 if (!sysfsfp) {
794                         ret = -errno;
795                         fprintf(stderr, "Could not open file to verify\n");
796                         goto error_free;
797                 }
798
799                 if (fscanf(sysfsfp, "%s", temp) != 1) {
800                         ret = errno ? -errno : -ENODATA;
801                         if (fclose(sysfsfp))
802                                 perror("_write_sysfs_string(): Failed to close dir");
803
804                         goto error_free;
805                 }
806
807                 if (fclose(sysfsfp)) {
808                         ret = -errno;
809                         goto error_free;
810                 }
811
812                 if (strcmp(temp, val) != 0) {
813                         fprintf(stderr,
814                                 "Possible failure in string write of %s "
815                                 "Should be %s written to %s/%s\n", temp, val,
816                                 basedir, filename);
817                         ret = -1;
818                 }
819         }
820
821 error_free:
822         free(temp);
823
824         return ret;
825 }
826
827 /**
828  * write_sysfs_string_and_verify() - string write, readback and verify
829  * @filename: name of file to write to
830  * @basedir: the sysfs directory in which the file is to be found
831  * @val: the string to write
832  *
833  * Returns a value >= 0 on success, otherwise a negative error code.
834  **/
835 int write_sysfs_string_and_verify(const char *filename, const char *basedir,
836                                   const char *val)
837 {
838         return _write_sysfs_string(filename, basedir, val, 1);
839 }
840
841 /**
842  * write_sysfs_string() - write string to a sysfs file
843  * @filename: name of file to write to
844  * @basedir: the sysfs directory in which the file is to be found
845  * @val: the string to write
846  *
847  * Returns a value >= 0 on success, otherwise a negative error code.
848  **/
849 int write_sysfs_string(const char *filename, const char *basedir,
850                        const char *val)
851 {
852         return _write_sysfs_string(filename, basedir, val, 0);
853 }
854
855 /**
856  * read_sysfs_posint() - read an integer value from file
857  * @filename: name of file to read from
858  * @basedir: the sysfs directory in which the file is to be found
859  *
860  * Returns the read integer value >= 0 on success, otherwise a negative error
861  * code.
862  **/
863 int read_sysfs_posint(const char *filename, const char *basedir)
864 {
865         int ret;
866         FILE  *sysfsfp;
867         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
868
869         if (!temp) {
870                 fprintf(stderr, "Memory allocation failed");
871                 return -ENOMEM;
872         }
873
874         ret = sprintf(temp, "%s/%s", basedir, filename);
875         if (ret < 0)
876                 goto error_free;
877
878         sysfsfp = fopen(temp, "r");
879         if (!sysfsfp) {
880                 ret = -errno;
881                 goto error_free;
882         }
883
884         errno = 0;
885         if (fscanf(sysfsfp, "%d\n", &ret) != 1) {
886                 ret = errno ? -errno : -ENODATA;
887                 if (fclose(sysfsfp))
888                         perror("read_sysfs_posint(): Failed to close dir");
889
890                 goto error_free;
891         }
892
893         if (fclose(sysfsfp))
894                 ret = -errno;
895
896 error_free:
897         free(temp);
898
899         return ret;
900 }
901
902 /**
903  * read_sysfs_float() - read a float value from file
904  * @filename: name of file to read from
905  * @basedir: the sysfs directory in which the file is to be found
906  * @val: output the read float value
907  *
908  * Returns a value >= 0 on success, otherwise a negative error code.
909  **/
910 int read_sysfs_float(const char *filename, const char *basedir, float *val)
911 {
912         int ret = 0;
913         FILE  *sysfsfp;
914         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
915
916         if (!temp) {
917                 fprintf(stderr, "Memory allocation failed");
918                 return -ENOMEM;
919         }
920
921         ret = sprintf(temp, "%s/%s", basedir, filename);
922         if (ret < 0)
923                 goto error_free;
924
925         sysfsfp = fopen(temp, "r");
926         if (!sysfsfp) {
927                 ret = -errno;
928                 goto error_free;
929         }
930
931         errno = 0;
932         if (fscanf(sysfsfp, "%f\n", val) != 1) {
933                 ret = errno ? -errno : -ENODATA;
934                 if (fclose(sysfsfp))
935                         perror("read_sysfs_float(): Failed to close dir");
936
937                 goto error_free;
938         }
939
940         if (fclose(sysfsfp))
941                 ret = -errno;
942
943 error_free:
944         free(temp);
945
946         return ret;
947 }
948
949 /**
950  * read_sysfs_string() - read a string from file
951  * @filename: name of file to read from
952  * @basedir: the sysfs directory in which the file is to be found
953  * @str: output the read string
954  *
955  * Returns a value >= 0 on success, otherwise a negative error code.
956  **/
957 int read_sysfs_string(const char *filename, const char *basedir, char *str)
958 {
959         int ret = 0;
960         FILE  *sysfsfp;
961         char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
962
963         if (!temp) {
964                 fprintf(stderr, "Memory allocation failed");
965                 return -ENOMEM;
966         }
967
968         ret = sprintf(temp, "%s/%s", basedir, filename);
969         if (ret < 0)
970                 goto error_free;
971
972         sysfsfp = fopen(temp, "r");
973         if (!sysfsfp) {
974                 ret = -errno;
975                 goto error_free;
976         }
977
978         errno = 0;
979         if (fscanf(sysfsfp, "%s\n", str) != 1) {
980                 ret = errno ? -errno : -ENODATA;
981                 if (fclose(sysfsfp))
982                         perror("read_sysfs_string(): Failed to close dir");
983
984                 goto error_free;
985         }
986
987         if (fclose(sysfsfp))
988                 ret = -errno;
989
990 error_free:
991         free(temp);
992
993         return ret;
994 }