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 #ifndef _IIO_UTILS_H 10 #define _IIO_UTILS_H 11 12 #include <string.h> 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <stdint.h> 16 #include <dirent.h> 17 #include <errno.h> 18 #include <ctype.h> 19 #include "iio_utils.h" 20 21 const char *iio_dir = "/sys/bus/iio/devices/"; 22 23 static char * const iio_direction[] = { 24 "in", 25 "out", 26 }; 27 28 /** 29 * iioutils_break_up_name() - extract generic name from full channel name 30 * @full_name: the full channel name 31 * @generic_name: the output generic channel name 32 **/ 33 int iioutils_break_up_name(const char *full_name, 34 char **generic_name) 35 { 36 char *current; 37 char *w, *r; 38 char *working, *prefix = ""; 39 int i; 40 41 for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++) 42 if (!strncmp(full_name, iio_direction[i], 43 strlen(iio_direction[i]))) { 44 prefix = iio_direction[i]; 45 break; 46 } 47 48 current = strdup(full_name + strlen(prefix) + 1); 49 working = strtok(current, "_\0"); 50 51 w = working; 52 r = working; 53 54 while (*r != '\0') { 55 if (!isdigit(*r)) { 56 *w = *r; 57 w++; 58 } 59 r++; 60 } 61 *w = '\0'; 62 asprintf(generic_name, "%s_%s", prefix, working); 63 free(current); 64 65 return 0; 66 } 67 68 /** 69 * iioutils_get_type() - find and process _type attribute data 70 * @is_signed: output whether channel is signed 71 * @bytes: output how many bytes the channel storage occupies 72 * @mask: output a bit mask for the raw data 73 * @be: big endian 74 * @device_dir: the iio device directory 75 * @name: the channel name 76 * @generic_name: the channel type name 77 **/ 78 int iioutils_get_type(unsigned *is_signed, 79 unsigned *bytes, 80 unsigned *bits_used, 81 unsigned *shift, 82 uint64_t *mask, 83 unsigned *be, 84 const char *device_dir, 85 const char *name, 86 const char *generic_name) 87 { 88 FILE *sysfsfp; 89 int ret; 90 DIR *dp; 91 char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; 92 char signchar, endianchar; 93 unsigned padint; 94 const struct dirent *ent; 95 96 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 97 if (ret < 0) { 98 ret = -ENOMEM; 99 goto error_ret; 100 } 101 ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); 102 if (ret < 0) { 103 ret = -ENOMEM; 104 goto error_free_scan_el_dir; 105 } 106 ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); 107 if (ret < 0) { 108 ret = -ENOMEM; 109 goto error_free_builtname; 110 } 111 112 dp = opendir(scan_el_dir); 113 if (dp == NULL) { 114 ret = -errno; 115 goto error_free_builtname_generic; 116 } 117 while (ent = readdir(dp), ent != NULL) 118 /* 119 * Do we allow devices to override a generic name with 120 * a specific one? 121 */ 122 if ((strcmp(builtname, ent->d_name) == 0) || 123 (strcmp(builtname_generic, ent->d_name) == 0)) { 124 ret = asprintf(&filename, 125 "%s/%s", scan_el_dir, ent->d_name); 126 if (ret < 0) { 127 ret = -ENOMEM; 128 goto error_closedir; 129 } 130 sysfsfp = fopen(filename, "r"); 131 if (sysfsfp == NULL) { 132 printf("failed to open %s\n", filename); 133 ret = -errno; 134 goto error_free_filename; 135 } 136 137 ret = fscanf(sysfsfp, 138 "%ce:%c%u/%u>>%u", 139 &endianchar, 140 &signchar, 141 bits_used, 142 &padint, shift); 143 if (ret < 0) { 144 printf("failed to pass scan type description\n"); 145 ret = -errno; 146 goto error_close_sysfsfp; 147 } 148 *be = (endianchar == 'b'); 149 *bytes = padint / 8; 150 if (*bits_used == 64) 151 *mask = ~0; 152 else 153 *mask = (1 << *bits_used) - 1; 154 if (signchar == 's') 155 *is_signed = 1; 156 else 157 *is_signed = 0; 158 fclose(sysfsfp); 159 free(filename); 160 161 filename = 0; 162 sysfsfp = 0; 163 } 164 error_close_sysfsfp: 165 if (sysfsfp) 166 fclose(sysfsfp); 167 error_free_filename: 168 if (filename) 169 free(filename); 170 error_closedir: 171 closedir(dp); 172 error_free_builtname_generic: 173 free(builtname_generic); 174 error_free_builtname: 175 free(builtname); 176 error_free_scan_el_dir: 177 free(scan_el_dir); 178 error_ret: 179 return ret; 180 } 181 182 int iioutils_get_param_float(float *output, 183 const char *param_name, 184 const char *device_dir, 185 const char *name, 186 const char *generic_name) 187 { 188 FILE *sysfsfp; 189 int ret; 190 DIR *dp; 191 char *builtname, *builtname_generic; 192 char *filename = NULL; 193 const struct dirent *ent; 194 195 ret = asprintf(&builtname, "%s_%s", name, param_name); 196 if (ret < 0) { 197 ret = -ENOMEM; 198 goto error_ret; 199 } 200 ret = asprintf(&builtname_generic, 201 "%s_%s", generic_name, param_name); 202 if (ret < 0) { 203 ret = -ENOMEM; 204 goto error_free_builtname; 205 } 206 dp = opendir(device_dir); 207 if (dp == NULL) { 208 ret = -errno; 209 goto error_free_builtname_generic; 210 } 211 while (ent = readdir(dp), ent != NULL) 212 if ((strcmp(builtname, ent->d_name) == 0) || 213 (strcmp(builtname_generic, ent->d_name) == 0)) { 214 ret = asprintf(&filename, 215 "%s/%s", device_dir, ent->d_name); 216 if (ret < 0) { 217 ret = -ENOMEM; 218 goto error_closedir; 219 } 220 sysfsfp = fopen(filename, "r"); 221 if (!sysfsfp) { 222 ret = -errno; 223 goto error_free_filename; 224 } 225 fscanf(sysfsfp, "%f", output); 226 break; 227 } 228 error_free_filename: 229 if (filename) 230 free(filename); 231 error_closedir: 232 closedir(dp); 233 error_free_builtname_generic: 234 free(builtname_generic); 235 error_free_builtname: 236 free(builtname); 237 error_ret: 238 return ret; 239 } 240 241 /** 242 * bsort_channel_array_by_index() - reorder so that the array is in index order 243 * 244 **/ 245 246 void bsort_channel_array_by_index(struct iio_channel_info **ci_array, 247 int cnt) 248 { 249 250 struct iio_channel_info temp; 251 int x, y; 252 253 for (x = 0; x < cnt; x++) 254 for (y = 0; y < (cnt - 1); y++) 255 if ((*ci_array)[y].index > (*ci_array)[y+1].index) { 256 temp = (*ci_array)[y + 1]; 257 (*ci_array)[y + 1] = (*ci_array)[y]; 258 (*ci_array)[y] = temp; 259 } 260 } 261 262 /** 263 * build_channel_array() - function to figure out what channels are present 264 * @device_dir: the IIO device directory in sysfs 265 * @ 266 **/ 267 int build_channel_array(const char *device_dir, 268 struct iio_channel_info **ci_array, 269 int *counter) 270 { 271 DIR *dp; 272 FILE *sysfsfp; 273 int count, i; 274 struct iio_channel_info *current; 275 int ret; 276 const struct dirent *ent; 277 char *scan_el_dir; 278 char *filename; 279 280 *counter = 0; 281 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 282 if (ret < 0) { 283 ret = -ENOMEM; 284 goto error_ret; 285 } 286 dp = opendir(scan_el_dir); 287 if (dp == NULL) { 288 ret = -errno; 289 goto error_free_name; 290 } 291 while (ent = readdir(dp), ent != NULL) 292 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 293 "_en") == 0) { 294 ret = asprintf(&filename, 295 "%s/%s", scan_el_dir, ent->d_name); 296 if (ret < 0) { 297 ret = -ENOMEM; 298 goto error_close_dir; 299 } 300 sysfsfp = fopen(filename, "r"); 301 if (sysfsfp == NULL) { 302 ret = -errno; 303 free(filename); 304 goto error_close_dir; 305 } 306 fscanf(sysfsfp, "%i", &ret); 307 if (ret == 1) 308 (*counter)++; 309 fclose(sysfsfp); 310 free(filename); 311 } 312 *ci_array = malloc(sizeof(**ci_array) * (*counter)); 313 if (*ci_array == NULL) { 314 ret = -ENOMEM; 315 goto error_close_dir; 316 } 317 seekdir(dp, 0); 318 count = 0; 319 while (ent = readdir(dp), ent != NULL) { 320 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 321 "_en") == 0) { 322 int current_enabled = 0; 323 324 current = &(*ci_array)[count++]; 325 ret = asprintf(&filename, 326 "%s/%s", scan_el_dir, ent->d_name); 327 if (ret < 0) { 328 ret = -ENOMEM; 329 /* decrement count to avoid freeing name */ 330 count--; 331 goto error_cleanup_array; 332 } 333 sysfsfp = fopen(filename, "r"); 334 if (sysfsfp == NULL) { 335 free(filename); 336 ret = -errno; 337 goto error_cleanup_array; 338 } 339 fscanf(sysfsfp, "%i", ¤t_enabled); 340 fclose(sysfsfp); 341 342 if (!current_enabled) { 343 free(filename); 344 count--; 345 continue; 346 } 347 348 current->scale = 1.0; 349 current->offset = 0; 350 current->name = strndup(ent->d_name, 351 strlen(ent->d_name) - 352 strlen("_en")); 353 if (current->name == NULL) { 354 free(filename); 355 ret = -ENOMEM; 356 goto error_cleanup_array; 357 } 358 /* Get the generic and specific name elements */ 359 ret = iioutils_break_up_name(current->name, 360 ¤t->generic_name); 361 if (ret) { 362 free(filename); 363 goto error_cleanup_array; 364 } 365 ret = asprintf(&filename, 366 "%s/%s_index", 367 scan_el_dir, 368 current->name); 369 if (ret < 0) { 370 free(filename); 371 ret = -ENOMEM; 372 goto error_cleanup_array; 373 } 374 sysfsfp = fopen(filename, "r"); 375 fscanf(sysfsfp, "%u", ¤t->index); 376 fclose(sysfsfp); 377 free(filename); 378 /* Find the scale */ 379 ret = iioutils_get_param_float(¤t->scale, 380 "scale", 381 device_dir, 382 current->name, 383 current->generic_name); 384 if (ret < 0) 385 goto error_cleanup_array; 386 ret = iioutils_get_param_float(¤t->offset, 387 "offset", 388 device_dir, 389 current->name, 390 current->generic_name); 391 if (ret < 0) 392 goto error_cleanup_array; 393 ret = iioutils_get_type(¤t->is_signed, 394 ¤t->bytes, 395 ¤t->bits_used, 396 ¤t->shift, 397 ¤t->mask, 398 ¤t->be, 399 device_dir, 400 current->name, 401 current->generic_name); 402 } 403 } 404 405 closedir(dp); 406 /* reorder so that the array is in index order */ 407 bsort_channel_array_by_index(ci_array, *counter); 408 409 return 0; 410 411 error_cleanup_array: 412 for (i = count - 1; i >= 0; i--) 413 free((*ci_array)[i].name); 414 free(*ci_array); 415 error_close_dir: 416 closedir(dp); 417 error_free_name: 418 free(scan_el_dir); 419 error_ret: 420 return ret; 421 } 422 423 /** 424 * find_type_by_name() - function to match top level types by name 425 * @name: top level type instance name 426 * @type: the type of top level instance being sort 427 * 428 * Typical types this is used for are device and trigger. 429 **/ 430 int find_type_by_name(const char *name, const char *type) 431 { 432 const struct dirent *ent; 433 int number, numstrlen; 434 435 FILE *nameFile; 436 DIR *dp; 437 char thisname[IIO_MAX_NAME_LENGTH]; 438 char *filename; 439 440 dp = opendir(iio_dir); 441 if (dp == NULL) { 442 printf("No industrialio devices available\n"); 443 return -ENODEV; 444 } 445 446 while (ent = readdir(dp), ent != NULL) { 447 if (strcmp(ent->d_name, ".") != 0 && 448 strcmp(ent->d_name, "..") != 0 && 449 strlen(ent->d_name) > strlen(type) && 450 strncmp(ent->d_name, type, strlen(type)) == 0) { 451 numstrlen = sscanf(ent->d_name + strlen(type), 452 "%d", 453 &number); 454 /* verify the next character is not a colon */ 455 if (strncmp(ent->d_name + strlen(type) + numstrlen, 456 ":", 457 1) != 0) { 458 filename = malloc(strlen(iio_dir) 459 + strlen(type) 460 + numstrlen 461 + 6); 462 if (filename == NULL) { 463 closedir(dp); 464 return -ENOMEM; 465 } 466 sprintf(filename, "%s%s%d/name", 467 iio_dir, 468 type, 469 number); 470 nameFile = fopen(filename, "r"); 471 if (!nameFile) { 472 free(filename); 473 continue; 474 } 475 free(filename); 476 fscanf(nameFile, "%s", thisname); 477 fclose(nameFile); 478 if (strcmp(name, thisname) == 0) { 479 closedir(dp); 480 return number; 481 } 482 } 483 } 484 } 485 closedir(dp); 486 return -ENODEV; 487 } 488 489 int _write_sysfs_int(char *filename, char *basedir, int val, int verify) 490 { 491 int ret = 0; 492 FILE *sysfsfp; 493 int test; 494 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 495 496 if (temp == NULL) 497 return -ENOMEM; 498 sprintf(temp, "%s/%s", basedir, filename); 499 sysfsfp = fopen(temp, "w"); 500 if (sysfsfp == NULL) { 501 printf("failed to open %s\n", temp); 502 ret = -errno; 503 goto error_free; 504 } 505 fprintf(sysfsfp, "%d", val); 506 fclose(sysfsfp); 507 if (verify) { 508 sysfsfp = fopen(temp, "r"); 509 if (sysfsfp == NULL) { 510 printf("failed to open %s\n", temp); 511 ret = -errno; 512 goto error_free; 513 } 514 fscanf(sysfsfp, "%d", &test); 515 fclose(sysfsfp); 516 if (test != val) { 517 printf("Possible failure in int write %d to %s%s\n", 518 val, 519 basedir, 520 filename); 521 ret = -1; 522 } 523 } 524 error_free: 525 free(temp); 526 return ret; 527 } 528 529 int write_sysfs_int(char *filename, char *basedir, int val) 530 { 531 return _write_sysfs_int(filename, basedir, val, 0); 532 } 533 534 int write_sysfs_int_and_verify(char *filename, char *basedir, int val) 535 { 536 return _write_sysfs_int(filename, basedir, val, 1); 537 } 538 539 int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) 540 { 541 int ret = 0; 542 FILE *sysfsfp; 543 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 544 545 if (temp == NULL) { 546 printf("Memory allocation failed\n"); 547 return -ENOMEM; 548 } 549 sprintf(temp, "%s/%s", basedir, filename); 550 sysfsfp = fopen(temp, "w"); 551 if (sysfsfp == NULL) { 552 printf("Could not open %s\n", temp); 553 ret = -errno; 554 goto error_free; 555 } 556 fprintf(sysfsfp, "%s", val); 557 fclose(sysfsfp); 558 if (verify) { 559 sysfsfp = fopen(temp, "r"); 560 if (sysfsfp == NULL) { 561 printf("could not open file to verify\n"); 562 ret = -errno; 563 goto error_free; 564 } 565 fscanf(sysfsfp, "%s", temp); 566 fclose(sysfsfp); 567 if (strcmp(temp, val) != 0) { 568 printf("Possible failure in string write of %s " 569 "Should be %s " 570 "written to %s\%s\n", 571 temp, 572 val, 573 basedir, 574 filename); 575 ret = -1; 576 } 577 } 578 error_free: 579 free(temp); 580 581 return ret; 582 } 583 584 /** 585 * write_sysfs_string_and_verify() - string write, readback and verify 586 * @filename: name of file to write to 587 * @basedir: the sysfs directory in which the file is to be found 588 * @val: the string to write 589 **/ 590 int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) 591 { 592 return _write_sysfs_string(filename, basedir, val, 1); 593 } 594 595 int write_sysfs_string(char *filename, char *basedir, char *val) 596 { 597 return _write_sysfs_string(filename, basedir, val, 0); 598 } 599 600 int read_sysfs_posint(char *filename, char *basedir) 601 { 602 int ret; 603 FILE *sysfsfp; 604 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 605 606 if (temp == NULL) { 607 printf("Memory allocation failed"); 608 return -ENOMEM; 609 } 610 sprintf(temp, "%s/%s", basedir, filename); 611 sysfsfp = fopen(temp, "r"); 612 if (sysfsfp == NULL) { 613 ret = -errno; 614 goto error_free; 615 } 616 fscanf(sysfsfp, "%d\n", &ret); 617 fclose(sysfsfp); 618 error_free: 619 free(temp); 620 return ret; 621 } 622 623 int read_sysfs_float(char *filename, char *basedir, float *val) 624 { 625 int ret = 0; 626 FILE *sysfsfp; 627 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 628 629 if (temp == NULL) { 630 printf("Memory allocation failed"); 631 return -ENOMEM; 632 } 633 sprintf(temp, "%s/%s", basedir, filename); 634 sysfsfp = fopen(temp, "r"); 635 if (sysfsfp == NULL) { 636 ret = -errno; 637 goto error_free; 638 } 639 fscanf(sysfsfp, "%f\n", val); 640 fclose(sysfsfp); 641 error_free: 642 free(temp); 643 return ret; 644 } 645 646 int read_sysfs_string(const char *filename, const char *basedir, char *str) 647 { 648 int ret = 0; 649 FILE *sysfsfp; 650 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 651 652 if (temp == NULL) { 653 printf("Memory allocation failed"); 654 return -ENOMEM; 655 } 656 sprintf(temp, "%s/%s", basedir, filename); 657 sysfsfp = fopen(temp, "r"); 658 if (sysfsfp == NULL) { 659 ret = -errno; 660 goto error_free; 661 } 662 fscanf(sysfsfp, "%s\n", str); 663 fclose(sysfsfp); 664 error_free: 665 free(temp); 666 return ret; 667 } 668 669 #endif /* _IIO_UTILS_H */ 670