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