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