iio_utils.h revision bb23378c0b1c9a410d40adea74276544a00fb94e
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 enabled; 81 unsigned location; 82}; 83 84/** 85 * iioutils_get_type() - find and process _type attribute data 86 * @is_signed: output whether channel is signed 87 * @bytes: output how many bytes the channel storage occupies 88 * @mask: output a bit mask for the raw data 89 * @be: big endian 90 * @device_dir: the iio device directory 91 * @name: the channel name 92 * @generic_name: the channel type name 93 **/ 94inline int iioutils_get_type(unsigned *is_signed, 95 unsigned *bytes, 96 unsigned *bits_used, 97 unsigned *shift, 98 uint64_t *mask, 99 unsigned *be, 100 const char *device_dir, 101 const char *name, 102 const char *generic_name) 103{ 104 FILE *sysfsfp; 105 int ret; 106 DIR *dp; 107 char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; 108 char signchar, endianchar; 109 unsigned padint; 110 const struct dirent *ent; 111 112 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 113 if (ret < 0) { 114 ret = -ENOMEM; 115 goto error_ret; 116 } 117 ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); 118 if (ret < 0) { 119 ret = -ENOMEM; 120 goto error_free_scan_el_dir; 121 } 122 ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); 123 if (ret < 0) { 124 ret = -ENOMEM; 125 goto error_free_builtname; 126 } 127 128 dp = opendir(scan_el_dir); 129 if (dp == NULL) { 130 ret = -errno; 131 goto error_free_builtname_generic; 132 } 133 while (ent = readdir(dp), ent != NULL) 134 /* 135 * Do we allow devices to override a generic name with 136 * a specific one? 137 */ 138 if ((strcmp(builtname, ent->d_name) == 0) || 139 (strcmp(builtname_generic, ent->d_name) == 0)) { 140 ret = asprintf(&filename, 141 "%s/%s", scan_el_dir, ent->d_name); 142 if (ret < 0) { 143 ret = -ENOMEM; 144 goto error_closedir; 145 } 146 sysfsfp = fopen(filename, "r"); 147 if (sysfsfp == NULL) { 148 printf("failed to open %s\n", filename); 149 ret = -errno; 150 goto error_free_filename; 151 } 152 153 ret = fscanf(sysfsfp, 154 "%ce:%c%u/%u>>%u", 155 &endianchar, 156 &signchar, 157 bits_used, 158 &padint, shift); 159 if (ret < 0) { 160 printf("failed to pass scan type description\n"); 161 return ret; 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 } 178error_free_filename: 179 if (filename) 180 free(filename); 181error_closedir: 182 closedir(dp); 183error_free_builtname_generic: 184 free(builtname_generic); 185error_free_builtname: 186 free(builtname); 187error_free_scan_el_dir: 188 free(scan_el_dir); 189error_ret: 190 return ret; 191} 192 193inline int iioutils_get_param_float(float *output, 194 const char *param_name, 195 const char *device_dir, 196 const char *name, 197 const char *generic_name) 198{ 199 FILE *sysfsfp; 200 int ret; 201 DIR *dp; 202 char *builtname, *builtname_generic; 203 char *filename = NULL; 204 const struct dirent *ent; 205 206 ret = asprintf(&builtname, "%s_%s", name, param_name); 207 if (ret < 0) { 208 ret = -ENOMEM; 209 goto error_ret; 210 } 211 ret = asprintf(&builtname_generic, 212 "%s_%s", generic_name, param_name); 213 if (ret < 0) { 214 ret = -ENOMEM; 215 goto error_free_builtname; 216 } 217 dp = opendir(device_dir); 218 if (dp == NULL) { 219 ret = -errno; 220 goto error_free_builtname_generic; 221 } 222 while (ent = readdir(dp), ent != NULL) 223 if ((strcmp(builtname, ent->d_name) == 0) || 224 (strcmp(builtname_generic, ent->d_name) == 0)) { 225 ret = asprintf(&filename, 226 "%s/%s", device_dir, ent->d_name); 227 if (ret < 0) { 228 ret = -ENOMEM; 229 goto error_closedir; 230 } 231 sysfsfp = fopen(filename, "r"); 232 if (!sysfsfp) { 233 ret = -errno; 234 goto error_free_filename; 235 } 236 fscanf(sysfsfp, "%f", output); 237 break; 238 } 239error_free_filename: 240 if (filename) 241 free(filename); 242error_closedir: 243 closedir(dp); 244error_free_builtname_generic: 245 free(builtname_generic); 246error_free_builtname: 247 free(builtname); 248error_ret: 249 return ret; 250} 251 252/** 253 * bsort_channel_array_by_index() - reorder so that the array is in index order 254 * 255 **/ 256 257inline void bsort_channel_array_by_index(struct iio_channel_info **ci_array, 258 int cnt) 259{ 260 261 struct iio_channel_info temp; 262 int x, y; 263 264 for (x = 0; x < cnt; x++) 265 for (y = 0; y < (cnt - 1); y++) 266 if ((*ci_array)[y].index > (*ci_array)[y+1].index) { 267 temp = (*ci_array)[y + 1]; 268 (*ci_array)[y + 1] = (*ci_array)[y]; 269 (*ci_array)[y] = temp; 270 } 271} 272 273/** 274 * build_channel_array() - function to figure out what channels are present 275 * @device_dir: the IIO device directory in sysfs 276 * @ 277 **/ 278inline int build_channel_array(const char *device_dir, 279 struct iio_channel_info **ci_array, 280 int *counter) 281{ 282 DIR *dp; 283 FILE *sysfsfp; 284 int count, i; 285 struct iio_channel_info *current; 286 int ret; 287 const struct dirent *ent; 288 char *scan_el_dir; 289 char *filename; 290 291 *counter = 0; 292 ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 293 if (ret < 0) { 294 ret = -ENOMEM; 295 goto error_ret; 296 } 297 dp = opendir(scan_el_dir); 298 if (dp == NULL) { 299 ret = -errno; 300 goto error_free_name; 301 } 302 while (ent = readdir(dp), ent != NULL) 303 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 304 "_en") == 0) { 305 ret = asprintf(&filename, 306 "%s/%s", scan_el_dir, ent->d_name); 307 if (ret < 0) { 308 ret = -ENOMEM; 309 goto error_close_dir; 310 } 311 sysfsfp = fopen(filename, "r"); 312 if (sysfsfp == NULL) { 313 ret = -errno; 314 free(filename); 315 goto error_close_dir; 316 } 317 fscanf(sysfsfp, "%u", &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 seekdir(dp, 0); 329 count = 0; 330 while (ent = readdir(dp), ent != NULL) { 331 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 332 "_en") == 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 if (sysfsfp == NULL) { 344 free(filename); 345 ret = -errno; 346 goto error_cleanup_array; 347 } 348 fscanf(sysfsfp, "%u", ¤t->enabled); 349 fclose(sysfsfp); 350 351 if (!current->enabled) { 352 free(filename); 353 count--; 354 continue; 355 } 356 357 current->scale = 1.0; 358 current->offset = 0; 359 current->name = strndup(ent->d_name, 360 strlen(ent->d_name) - 361 strlen("_en")); 362 if (current->name == NULL) { 363 free(filename); 364 ret = -ENOMEM; 365 goto error_cleanup_array; 366 } 367 /* Get the generic and specific name elements */ 368 ret = iioutils_break_up_name(current->name, 369 ¤t->generic_name); 370 if (ret) { 371 free(filename); 372 goto error_cleanup_array; 373 } 374 ret = asprintf(&filename, 375 "%s/%s_index", 376 scan_el_dir, 377 current->name); 378 if (ret < 0) { 379 free(filename); 380 ret = -ENOMEM; 381 goto error_cleanup_array; 382 } 383 sysfsfp = fopen(filename, "r"); 384 fscanf(sysfsfp, "%u", ¤t->index); 385 fclose(sysfsfp); 386 free(filename); 387 /* Find the scale */ 388 ret = iioutils_get_param_float(¤t->scale, 389 "scale", 390 device_dir, 391 current->name, 392 current->generic_name); 393 if (ret < 0) 394 goto error_cleanup_array; 395 ret = iioutils_get_param_float(¤t->offset, 396 "offset", 397 device_dir, 398 current->name, 399 current->generic_name); 400 if (ret < 0) 401 goto error_cleanup_array; 402 ret = iioutils_get_type(¤t->is_signed, 403 ¤t->bytes, 404 ¤t->bits_used, 405 ¤t->shift, 406 ¤t->mask, 407 ¤t->be, 408 device_dir, 409 current->name, 410 current->generic_name); 411 } 412 } 413 414 closedir(dp); 415 /* reorder so that the array is in index order */ 416 bsort_channel_array_by_index(ci_array, *counter); 417 418 return 0; 419 420error_cleanup_array: 421 for (i = count - 1; i >= 0; i--) 422 free((*ci_array)[i].name); 423 free(*ci_array); 424error_close_dir: 425 closedir(dp); 426error_free_name: 427 free(scan_el_dir); 428error_ret: 429 return ret; 430} 431 432/** 433 * find_type_by_name() - function to match top level types by name 434 * @name: top level type instance name 435 * @type: the type of top level instance being sort 436 * 437 * Typical types this is used for are device and trigger. 438 **/ 439inline int find_type_by_name(const char *name, const char *type) 440{ 441 const struct dirent *ent; 442 int number, numstrlen; 443 444 FILE *nameFile; 445 DIR *dp; 446 char thisname[IIO_MAX_NAME_LENGTH]; 447 char *filename; 448 449 dp = opendir(iio_dir); 450 if (dp == NULL) { 451 printf("No industrialio devices available"); 452 return -ENODEV; 453 } 454 455 while (ent = readdir(dp), ent != NULL) { 456 if (strcmp(ent->d_name, ".") != 0 && 457 strcmp(ent->d_name, "..") != 0 && 458 strlen(ent->d_name) > strlen(type) && 459 strncmp(ent->d_name, type, strlen(type)) == 0) { 460 numstrlen = sscanf(ent->d_name + strlen(type), 461 "%d", 462 &number); 463 /* verify the next character is not a colon */ 464 if (strncmp(ent->d_name + strlen(type) + numstrlen, 465 ":", 466 1) != 0) { 467 filename = malloc(strlen(iio_dir) 468 + strlen(type) 469 + numstrlen 470 + 6); 471 if (filename == NULL) 472 return -ENOMEM; 473 sprintf(filename, "%s%s%d/name", 474 iio_dir, 475 type, 476 number); 477 nameFile = fopen(filename, "r"); 478 if (!nameFile) 479 continue; 480 free(filename); 481 fscanf(nameFile, "%s", thisname); 482 if (strcmp(name, thisname) == 0) 483 return number; 484 fclose(nameFile); 485 } 486 } 487 } 488 return -ENODEV; 489} 490 491inline int _write_sysfs_int(char *filename, char *basedir, int val, int verify) 492{ 493 int ret; 494 FILE *sysfsfp; 495 int test; 496 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 497 if (temp == NULL) 498 return -ENOMEM; 499 sprintf(temp, "%s/%s", basedir, filename); 500 sysfsfp = fopen(temp, "w"); 501 if (sysfsfp == NULL) { 502 printf("failed to open %s\n", temp); 503 ret = -errno; 504 goto error_free; 505 } 506 fprintf(sysfsfp, "%d", val); 507 fclose(sysfsfp); 508 if (verify) { 509 sysfsfp = fopen(temp, "r"); 510 if (sysfsfp == NULL) { 511 printf("failed to open %s\n", temp); 512 ret = -errno; 513 goto error_free; 514 } 515 fscanf(sysfsfp, "%d", &test); 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 } 524error_free: 525 free(temp); 526 return ret; 527} 528 529int write_sysfs_int(char *filename, char *basedir, int val) 530{ 531 return _write_sysfs_int(filename, basedir, val, 0); 532} 533 534int write_sysfs_int_and_verify(char *filename, char *basedir, int val) 535{ 536 return _write_sysfs_int(filename, basedir, val, 1); 537} 538 539int _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 if (temp == NULL) { 545 printf("Memory allocation failed\n"); 546 return -ENOMEM; 547 } 548 sprintf(temp, "%s/%s", basedir, filename); 549 sysfsfp = fopen(temp, "w"); 550 if (sysfsfp == NULL) { 551 printf("Could not open %s\n", temp); 552 ret = -errno; 553 goto error_free; 554 } 555 fprintf(sysfsfp, "%s", val); 556 fclose(sysfsfp); 557 if (verify) { 558 sysfsfp = fopen(temp, "r"); 559 if (sysfsfp == NULL) { 560 printf("could not open file to verify\n"); 561 ret = -errno; 562 goto error_free; 563 } 564 fscanf(sysfsfp, "%s", temp); 565 if (strcmp(temp, val) != 0) { 566 printf("Possible failure in string write of %s " 567 "Should be %s " 568 "written to %s\%s\n", 569 temp, 570 val, 571 basedir, 572 filename); 573 ret = -1; 574 } 575 } 576error_free: 577 free(temp); 578 579 return ret; 580} 581 582/** 583 * write_sysfs_string_and_verify() - string write, readback and verify 584 * @filename: name of file to write to 585 * @basedir: the sysfs directory in which the file is to be found 586 * @val: the string to write 587 **/ 588int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) 589{ 590 return _write_sysfs_string(filename, basedir, val, 1); 591} 592 593int write_sysfs_string(char *filename, char *basedir, char *val) 594{ 595 return _write_sysfs_string(filename, basedir, val, 0); 596} 597 598int read_sysfs_posint(char *filename, char *basedir) 599{ 600 int 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, "%d\n", &ret); 614 fclose(sysfsfp); 615error_free: 616 free(temp); 617 return ret; 618} 619 620int 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); 637error_free: 638 free(temp); 639 return ret; 640} 641