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