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