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 if (temp == NULL) 441 return -ENOMEM; 442 sprintf(temp, "%s/%s", basedir, filename); 443 sysfsfp = fopen(temp, "w"); 444 if (sysfsfp == NULL) { 445 printf("failed to open %s\n", temp); 446 ret = -errno; 447 goto error_free; 448 } 449 fprintf(sysfsfp, "%d", val); 450 fclose(sysfsfp); 451 if (verify) { 452 sysfsfp = fopen(temp, "r"); 453 if (sysfsfp == NULL) { 454 printf("failed to open %s\n", temp); 455 ret = -errno; 456 goto error_free; 457 } 458 fscanf(sysfsfp, "%d", &test); 459 if (test != val) { 460 printf("Possible failure in int write %d to %s%s\n", 461 val, 462 basedir, 463 filename); 464 ret = -1; 465 } 466 } 467 error_free: 468 free(temp); 469 return ret; 470 } 471 472 int write_sysfs_int(char *filename, char *basedir, int val) 473 { 474 return _write_sysfs_int(filename, basedir, val, 0); 475 } 476 477 int write_sysfs_int_and_verify(char *filename, char *basedir, int val) 478 { 479 return _write_sysfs_int(filename, basedir, val, 1); 480 } 481 482 int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) 483 { 484 int ret = 0; 485 FILE *sysfsfp; 486 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 487 if (temp == NULL) { 488 printf("Memory allocation failed\n"); 489 return -ENOMEM; 490 } 491 sprintf(temp, "%s/%s", basedir, filename); 492 sysfsfp = fopen(temp, "w"); 493 if (sysfsfp == NULL) { 494 printf("Could not open %s\n", temp); 495 ret = -errno; 496 goto error_free; 497 } 498 fprintf(sysfsfp, "%s", val); 499 fclose(sysfsfp); 500 if (verify) { 501 sysfsfp = fopen(temp, "r"); 502 if (sysfsfp == NULL) { 503 printf("could not open file to verify\n"); 504 ret = -errno; 505 goto error_free; 506 } 507 fscanf(sysfsfp, "%s", temp); 508 if (strcmp(temp, val) != 0) { 509 printf("Possible failure in string write of %s " 510 "Should be %s " 511 "written to %s\%s\n", 512 temp, 513 val, 514 basedir, 515 filename); 516 ret = -1; 517 } 518 } 519 error_free: 520 free(temp); 521 522 return ret; 523 } 524 525 /** 526 * write_sysfs_string_and_verify() - string write, readback and verify 527 * @filename: name of file to write to 528 * @basedir: the sysfs directory in which the file is to be found 529 * @val: the string to write 530 **/ 531 int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) 532 { 533 return _write_sysfs_string(filename, basedir, val, 1); 534 } 535 536 int write_sysfs_string(char *filename, char *basedir, char *val) 537 { 538 return _write_sysfs_string(filename, basedir, val, 0); 539 } 540 541 int read_sysfs_posint(char *filename, char *basedir) 542 { 543 int ret; 544 FILE *sysfsfp; 545 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 546 if (temp == NULL) { 547 printf("Memory allocation failed"); 548 return -ENOMEM; 549 } 550 sprintf(temp, "%s/%s", basedir, filename); 551 sysfsfp = fopen(temp, "r"); 552 if (sysfsfp == NULL) { 553 ret = -errno; 554 goto error_free; 555 } 556 fscanf(sysfsfp, "%d\n", &ret); 557 fclose(sysfsfp); 558 error_free: 559 free(temp); 560 return ret; 561 } 562 563 int read_sysfs_float(char *filename, char *basedir, float *val) 564 { 565 float ret = 0; 566 FILE *sysfsfp; 567 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 568 if (temp == NULL) { 569 printf("Memory allocation failed"); 570 return -ENOMEM; 571 } 572 sprintf(temp, "%s/%s", basedir, filename); 573 sysfsfp = fopen(temp, "r"); 574 if (sysfsfp == NULL) { 575 ret = -errno; 576 goto error_free; 577 } 578 fscanf(sysfsfp, "%f\n", val); 579 fclose(sysfsfp); 580 error_free: 581 free(temp); 582 return ret; 583 } 584 int enable(const char *device_dir, 585 struct iio_channel_info **ci_array, 586 int *counter) 587 { 588 DIR *dp; 589 int ret; 590 const struct dirent *ent; 591 char *scan_el_dir; 592 593 *counter = 0; 594 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 595 if (ret < 0) { 596 ret = -ENOMEM; 597 goto error_ret; 598 } 599 dp = opendir(scan_el_dir); 600 if (dp == NULL) { 601 ret = -errno; 602 goto error_free_name; 603 } 604 while (ent = readdir(dp), ent != NULL) 605 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 606 "_en") == 0) { 607 write_sysfs_int_and_verify((char *)ent->d_name, scan_el_dir, 1); 608 } 609 return 0; 610 error_ret: 611 error_free_name: 612 return -1; 613 } 614 int disable_q_out(const char *device_dir, 615 struct iio_channel_info **ci_array, 616 int *counter) { 617 DIR *dp; 618 int ret; 619 const struct dirent *ent; 620 char *scan_el_dir; 621 622 *counter = 0; 623 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 624 if (ret < 0) { 625 ret = -ENOMEM; 626 goto error_ret; 627 } 628 dp = opendir(scan_el_dir); 629 if (dp == NULL) { 630 ret = -errno; 631 goto error_free_name; 632 } 633 while (ent = readdir(dp), ent != NULL) 634 if (strncmp(ent->d_name, "in_quaternion", strlen("in_quaternion")) == 0) { 635 write_sysfs_int_and_verify((char *)ent->d_name, scan_el_dir, 0); 636 } 637 return 0; 638 error_ret: 639 error_free_name: 640 return -1; 641 642 } 643 644