iio_utils.c 21 KB

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