iio_utils.h revision 109379210eb57a252e245363659168a1f1ab8691
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 23const 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 **/ 30static 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 **/ 67struct 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 **/ 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 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 } 177error_free_filename: 178 if (filename) 179 free(filename); 180error_closedir: 181 closedir(dp); 182error_free_builtname_generic: 183 free(builtname_generic); 184error_free_builtname: 185 free(builtname); 186error_free_scan_el_dir: 187 free(scan_el_dir); 188error_ret: 189 return ret; 190} 191 192inline 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 } 238error_free_filename: 239 if (filename) 240 free(filename); 241error_closedir: 242 closedir(dp); 243error_free_builtname_generic: 244 free(builtname_generic); 245error_free_builtname: 246 free(builtname); 247error_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 256inline 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 **/ 277inline 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 if (ret == 1) 318 (*counter)++; 319 fclose(sysfsfp); 320 free(filename); 321 } 322 *ci_array = malloc(sizeof(**ci_array) * (*counter)); 323 if (*ci_array == NULL) { 324 ret = -ENOMEM; 325 goto error_close_dir; 326 } 327 seekdir(dp, 0); 328 count = 0; 329 while (ent = readdir(dp), ent != NULL) { 330 if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 331 "_en") == 0) { 332 current = &(*ci_array)[count++]; 333 ret = asprintf(&filename, 334 "%s/%s", scan_el_dir, ent->d_name); 335 if (ret < 0) { 336 ret = -ENOMEM; 337 /* decrement count to avoid freeing name */ 338 count--; 339 goto error_cleanup_array; 340 } 341 sysfsfp = fopen(filename, "r"); 342 if (sysfsfp == NULL) { 343 free(filename); 344 ret = -errno; 345 goto error_cleanup_array; 346 } 347 fscanf(sysfsfp, "%u", ¤t->enabled); 348 fclose(sysfsfp); 349 350 if (!current->enabled) { 351 free(filename); 352 count--; 353 continue; 354 } 355 356 current->scale = 1.0; 357 current->offset = 0; 358 current->name = strndup(ent->d_name, 359 strlen(ent->d_name) - 360 strlen("_en")); 361 if (current->name == NULL) { 362 free(filename); 363 ret = -ENOMEM; 364 goto error_cleanup_array; 365 } 366 /* Get the generic and specific name elements */ 367 ret = iioutils_break_up_name(current->name, 368 ¤t->generic_name); 369 if (ret) { 370 free(filename); 371 goto error_cleanup_array; 372 } 373 ret = asprintf(&filename, 374 "%s/%s_index", 375 scan_el_dir, 376 current->name); 377 if (ret < 0) { 378 free(filename); 379 ret = -ENOMEM; 380 goto error_cleanup_array; 381 } 382 sysfsfp = fopen(filename, "r"); 383 fscanf(sysfsfp, "%u", ¤t->index); 384 fclose(sysfsfp); 385 free(filename); 386 /* Find the scale */ 387 ret = iioutils_get_param_float(¤t->scale, 388 "scale", 389 device_dir, 390 current->name, 391 current->generic_name); 392 if (ret < 0) 393 goto error_cleanup_array; 394 ret = iioutils_get_param_float(¤t->offset, 395 "offset", 396 device_dir, 397 current->name, 398 current->generic_name); 399 if (ret < 0) 400 goto error_cleanup_array; 401 ret = iioutils_get_type(¤t->is_signed, 402 ¤t->bytes, 403 ¤t->bits_used, 404 ¤t->shift, 405 ¤t->mask, 406 ¤t->be, 407 device_dir, 408 current->name, 409 current->generic_name); 410 } 411 } 412 413 closedir(dp); 414 /* reorder so that the array is in index order */ 415 bsort_channel_array_by_index(ci_array, *counter); 416 417 return 0; 418 419error_cleanup_array: 420 for (i = count - 1; i >= 0; i--) 421 free((*ci_array)[i].name); 422 free(*ci_array); 423error_close_dir: 424 closedir(dp); 425error_free_name: 426 free(scan_el_dir); 427error_ret: 428 return ret; 429} 430 431/** 432 * find_type_by_name() - function to match top level types by name 433 * @name: top level type instance name 434 * @type: the type of top level instance being sort 435 * 436 * Typical types this is used for are device and trigger. 437 **/ 438inline int find_type_by_name(const char *name, const char *type) 439{ 440 const struct dirent *ent; 441 int number, numstrlen; 442 443 FILE *nameFile; 444 DIR *dp; 445 char thisname[IIO_MAX_NAME_LENGTH]; 446 char *filename; 447 448 dp = opendir(iio_dir); 449 if (dp == NULL) { 450 printf("No industrialio devices available"); 451 return -ENODEV; 452 } 453 454 while (ent = readdir(dp), ent != NULL) { 455 if (strcmp(ent->d_name, ".") != 0 && 456 strcmp(ent->d_name, "..") != 0 && 457 strlen(ent->d_name) > strlen(type) && 458 strncmp(ent->d_name, type, strlen(type)) == 0) { 459 numstrlen = sscanf(ent->d_name + strlen(type), 460 "%d", 461 &number); 462 /* verify the next character is not a colon */ 463 if (strncmp(ent->d_name + strlen(type) + numstrlen, 464 ":", 465 1) != 0) { 466 filename = malloc(strlen(iio_dir) 467 + strlen(type) 468 + numstrlen 469 + 6); 470 if (filename == NULL) 471 return -ENOMEM; 472 sprintf(filename, "%s%s%d/name", 473 iio_dir, 474 type, 475 number); 476 nameFile = fopen(filename, "r"); 477 if (!nameFile) 478 continue; 479 free(filename); 480 fscanf(nameFile, "%s", thisname); 481 if (strcmp(name, thisname) == 0) 482 return number; 483 fclose(nameFile); 484 } 485 } 486 } 487 return -ENODEV; 488} 489 490inline int _write_sysfs_int(char *filename, char *basedir, int val, int verify) 491{ 492 int ret; 493 FILE *sysfsfp; 494 int test; 495 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 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 if (test != val) { 516 printf("Possible failure in int write %d to %s%s\n", 517 val, 518 basedir, 519 filename); 520 ret = -1; 521 } 522 } 523error_free: 524 free(temp); 525 return ret; 526} 527 528int write_sysfs_int(char *filename, char *basedir, int val) 529{ 530 return _write_sysfs_int(filename, basedir, val, 0); 531} 532 533int write_sysfs_int_and_verify(char *filename, char *basedir, int val) 534{ 535 return _write_sysfs_int(filename, basedir, val, 1); 536} 537 538int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) 539{ 540 int ret = 0; 541 FILE *sysfsfp; 542 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 543 if (temp == NULL) { 544 printf("Memory allocation failed\n"); 545 return -ENOMEM; 546 } 547 sprintf(temp, "%s/%s", basedir, filename); 548 sysfsfp = fopen(temp, "w"); 549 if (sysfsfp == NULL) { 550 printf("Could not open %s\n", temp); 551 ret = -errno; 552 goto error_free; 553 } 554 fprintf(sysfsfp, "%s", val); 555 fclose(sysfsfp); 556 if (verify) { 557 sysfsfp = fopen(temp, "r"); 558 if (sysfsfp == NULL) { 559 printf("could not open file to verify\n"); 560 ret = -errno; 561 goto error_free; 562 } 563 fscanf(sysfsfp, "%s", temp); 564 if (strcmp(temp, val) != 0) { 565 printf("Possible failure in string write of %s " 566 "Should be %s " 567 "written to %s\%s\n", 568 temp, 569 val, 570 basedir, 571 filename); 572 ret = -1; 573 } 574 } 575error_free: 576 free(temp); 577 578 return ret; 579} 580 581/** 582 * write_sysfs_string_and_verify() - string write, readback and verify 583 * @filename: name of file to write to 584 * @basedir: the sysfs directory in which the file is to be found 585 * @val: the string to write 586 **/ 587int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) 588{ 589 return _write_sysfs_string(filename, basedir, val, 1); 590} 591 592int write_sysfs_string(char *filename, char *basedir, char *val) 593{ 594 return _write_sysfs_string(filename, basedir, val, 0); 595} 596 597int read_sysfs_posint(char *filename, char *basedir) 598{ 599 int ret; 600 FILE *sysfsfp; 601 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 602 if (temp == NULL) { 603 printf("Memory allocation failed"); 604 return -ENOMEM; 605 } 606 sprintf(temp, "%s/%s", basedir, filename); 607 sysfsfp = fopen(temp, "r"); 608 if (sysfsfp == NULL) { 609 ret = -errno; 610 goto error_free; 611 } 612 fscanf(sysfsfp, "%d\n", &ret); 613 fclose(sysfsfp); 614error_free: 615 free(temp); 616 return ret; 617} 618 619int read_sysfs_float(char *filename, char *basedir, float *val) 620{ 621 float ret = 0; 622 FILE *sysfsfp; 623 char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 624 if (temp == NULL) { 625 printf("Memory allocation failed"); 626 return -ENOMEM; 627 } 628 sprintf(temp, "%s/%s", basedir, filename); 629 sysfsfp = fopen(temp, "r"); 630 if (sysfsfp == NULL) { 631 ret = -errno; 632 goto error_free; 633 } 634 fscanf(sysfsfp, "%f\n", val); 635 fclose(sysfsfp); 636error_free: 637 free(temp); 638 return ret; 639} 640