iio_utils.c 14.6 KB
Newer Older
1 2 3 4 5 6 7 8
/* IIO - useful set of util functionality
 *
 * Copyright (c) 2008 Jonathan Cameron
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 */
9 10
#ifndef _IIO_UTILS_H
#define _IIO_UTILS_H
11

12 13
#include <string.h>
#include <stdlib.h>
14 15
#include <stdio.h>
#include <stdint.h>
16
#include <dirent.h>
17
#include <errno.h>
18 19
#include <ctype.h>
#include "iio_utils.h"
20

21 22
const char *iio_dir = "/sys/bus/iio/devices/";

23 24 25 26 27
static char * const iio_direction[] = {
	"in",
	"out",
};

28 29 30 31 32
/**
 * iioutils_break_up_name() - extract generic name from full channel name
 * @full_name: the full channel name
 * @generic_name: the output generic channel name
 **/
33
int iioutils_break_up_name(const char *full_name,
34 35 36 37
				  char **generic_name)
{
	char *current;
	char *w, *r;
38 39 40 41 42 43 44 45 46
	char *working, *prefix = "";
	int i;

	for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++)
		if (!strncmp(full_name, iio_direction[i],
			     strlen(iio_direction[i]))) {
			prefix = iio_direction[i];
			break;
		}
47

48
	current = strdup(full_name + strlen(prefix) + 1);
49
	working = strtok(current, "_\0");
50

51 52 53
	w = working;
	r = working;

54
	while (*r != '\0') {
55 56 57 58 59 60 61
		if (!isdigit(*r)) {
			*w = *r;
			w++;
		}
		r++;
	}
	*w = '\0';
62
	asprintf(generic_name, "%s_%s", prefix, working);
63 64 65 66 67 68 69 70 71 72
	free(current);

	return 0;
}

/**
 * iioutils_get_type() - find and process _type attribute data
 * @is_signed: output whether channel is signed
 * @bytes: output how many bytes the channel storage occupies
 * @mask: output a bit mask for the raw data
73
 * @be: big endian
74 75 76 77
 * @device_dir: the iio device directory
 * @name: the channel name
 * @generic_name: the channel type name
 **/
78
int iioutils_get_type(unsigned *is_signed,
79 80
			     unsigned *bytes,
			     unsigned *bits_used,
81
			     unsigned *shift,
82
			     uint64_t *mask,
83
			     unsigned *be,
84 85 86 87 88 89 90 91
			     const char *device_dir,
			     const char *name,
			     const char *generic_name)
{
	FILE *sysfsfp;
	int ret;
	DIR *dp;
	char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;
92
	char signchar, endianchar;
93
	unsigned padint;
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
	const struct dirent *ent;

	ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
	if (ret < 0) {
		ret = -ENOMEM;
		goto error_ret;
	}
	ret = asprintf(&builtname, FORMAT_TYPE_FILE, name);
	if (ret < 0) {
		ret = -ENOMEM;
		goto error_free_scan_el_dir;
	}
	ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name);
	if (ret < 0) {
		ret = -ENOMEM;
		goto error_free_builtname;
	}

	dp = opendir(scan_el_dir);
	if (dp == NULL) {
		ret = -errno;
		goto error_free_builtname_generic;
	}
	while (ent = readdir(dp), ent != NULL)
		/*
		 * Do we allow devices to override a generic name with
		 * a specific one?
		 */
		if ((strcmp(builtname, ent->d_name) == 0) ||
		    (strcmp(builtname_generic, ent->d_name) == 0)) {
			ret = asprintf(&filename,
				       "%s/%s", scan_el_dir, ent->d_name);
			if (ret < 0) {
				ret = -ENOMEM;
				goto error_closedir;
			}
			sysfsfp = fopen(filename, "r");
			if (sysfsfp == NULL) {
				printf("failed to open %s\n", filename);
				ret = -errno;
				goto error_free_filename;
			}
136 137 138 139 140 141 142 143 144

			ret = fscanf(sysfsfp,
				     "%ce:%c%u/%u>>%u",
				     &endianchar,
				     &signchar,
				     bits_used,
				     &padint, shift);
			if (ret < 0) {
				printf("failed to pass scan type description\n");
145 146
				ret = -errno;
				goto error_close_sysfsfp;
147
			}
148
			*be = (endianchar == 'b');
149
			*bytes = padint / 8;
150
			if (*bits_used == 64)
151 152 153 154 155 156 157
				*mask = ~0;
			else
				*mask = (1 << *bits_used) - 1;
			if (signchar == 's')
				*is_signed = 1;
			else
				*is_signed = 0;
158 159 160 161
			fclose(sysfsfp);
			free(filename);

			filename = 0;
162
			sysfsfp = 0;
163
		}
164 165 166
error_close_sysfsfp:
	if (sysfsfp)
		fclose(sysfsfp);
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
error_free_filename:
	if (filename)
		free(filename);
error_closedir:
	closedir(dp);
error_free_builtname_generic:
	free(builtname_generic);
error_free_builtname:
	free(builtname);
error_free_scan_el_dir:
	free(scan_el_dir);
error_ret:
	return ret;
}

182
int iioutils_get_param_float(float *output,
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
				    const char *param_name,
				    const char *device_dir,
				    const char *name,
				    const char *generic_name)
{
	FILE *sysfsfp;
	int ret;
	DIR *dp;
	char *builtname, *builtname_generic;
	char *filename = NULL;
	const struct dirent *ent;

	ret = asprintf(&builtname, "%s_%s", name, param_name);
	if (ret < 0) {
		ret = -ENOMEM;
		goto error_ret;
	}
	ret = asprintf(&builtname_generic,
		       "%s_%s", generic_name, param_name);
	if (ret < 0) {
		ret = -ENOMEM;
		goto error_free_builtname;
	}
	dp = opendir(device_dir);
	if (dp == NULL) {
		ret = -errno;
		goto error_free_builtname_generic;
	}
	while (ent = readdir(dp), ent != NULL)
		if ((strcmp(builtname, ent->d_name) == 0) ||
		    (strcmp(builtname_generic, ent->d_name) == 0)) {
			ret = asprintf(&filename,
				       "%s/%s", device_dir, ent->d_name);
			if (ret < 0) {
				ret = -ENOMEM;
				goto error_closedir;
			}
			sysfsfp = fopen(filename, "r");
			if (!sysfsfp) {
				ret = -errno;
				goto error_free_filename;
			}
			fscanf(sysfsfp, "%f", output);
			break;
		}
error_free_filename:
	if (filename)
		free(filename);
error_closedir:
	closedir(dp);
error_free_builtname_generic:
	free(builtname_generic);
error_free_builtname:
	free(builtname);
error_ret:
	return ret;
}

241 242 243 244 245
/**
 * bsort_channel_array_by_index() - reorder so that the array is in index order
 *
 **/

246
void bsort_channel_array_by_index(struct iio_channel_info **ci_array,
247 248 249 250 251 252 253 254 255 256 257 258 259 260
					 int cnt)
{

	struct iio_channel_info temp;
	int x, y;

	for (x = 0; x < cnt; x++)
		for (y = 0; y < (cnt - 1); y++)
			if ((*ci_array)[y].index > (*ci_array)[y+1].index) {
				temp = (*ci_array)[y + 1];
				(*ci_array)[y + 1] = (*ci_array)[y];
				(*ci_array)[y] = temp;
			}
}
261 262 263 264 265 266

/**
 * build_channel_array() - function to figure out what channels are present
 * @device_dir: the IIO device directory in sysfs
 * @
 **/
267
int build_channel_array(const char *device_dir,
268 269 270 271 272
			      struct iio_channel_info **ci_array,
			      int *counter)
{
	DIR *dp;
	FILE *sysfsfp;
273
	int count, i;
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
	struct iio_channel_info *current;
	int ret;
	const struct dirent *ent;
	char *scan_el_dir;
	char *filename;

	*counter = 0;
	ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
	if (ret < 0) {
		ret = -ENOMEM;
		goto error_ret;
	}
	dp = opendir(scan_el_dir);
	if (dp == NULL) {
		ret = -errno;
		goto error_free_name;
	}
	while (ent = readdir(dp), ent != NULL)
		if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
			   "_en") == 0) {
			ret = asprintf(&filename,
				       "%s/%s", scan_el_dir, ent->d_name);
			if (ret < 0) {
				ret = -ENOMEM;
				goto error_close_dir;
			}
			sysfsfp = fopen(filename, "r");
			if (sysfsfp == NULL) {
				ret = -errno;
				free(filename);
				goto error_close_dir;
			}
306
			fscanf(sysfsfp, "%i", &ret);
307 308 309 310 311
			if (ret == 1)
				(*counter)++;
			fclose(sysfsfp);
			free(filename);
		}
312
	*ci_array = malloc(sizeof(**ci_array) * (*counter));
313 314 315 316 317
	if (*ci_array == NULL) {
		ret = -ENOMEM;
		goto error_close_dir;
	}
	seekdir(dp, 0);
318
	count = 0;
319 320 321
	while (ent = readdir(dp), ent != NULL) {
		if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
			   "_en") == 0) {
322
			int current_enabled = 0;
323

324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
			current = &(*ci_array)[count++];
			ret = asprintf(&filename,
				       "%s/%s", scan_el_dir, ent->d_name);
			if (ret < 0) {
				ret = -ENOMEM;
				/* decrement count to avoid freeing name */
				count--;
				goto error_cleanup_array;
			}
			sysfsfp = fopen(filename, "r");
			if (sysfsfp == NULL) {
				free(filename);
				ret = -errno;
				goto error_cleanup_array;
			}
339
			fscanf(sysfsfp, "%i", &current_enabled);
340
			fclose(sysfsfp);
341

342
			if (!current_enabled) {
343 344 345 346 347
				free(filename);
				count--;
				continue;
			}

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
			current->scale = 1.0;
			current->offset = 0;
			current->name = strndup(ent->d_name,
						strlen(ent->d_name) -
						strlen("_en"));
			if (current->name == NULL) {
				free(filename);
				ret = -ENOMEM;
				goto error_cleanup_array;
			}
			/* Get the generic and specific name elements */
			ret = iioutils_break_up_name(current->name,
						     &current->generic_name);
			if (ret) {
				free(filename);
				goto error_cleanup_array;
			}
			ret = asprintf(&filename,
				       "%s/%s_index",
				       scan_el_dir,
				       current->name);
			if (ret < 0) {
				free(filename);
				ret = -ENOMEM;
				goto error_cleanup_array;
			}
			sysfsfp = fopen(filename, "r");
			fscanf(sysfsfp, "%u", &current->index);
			fclose(sysfsfp);
			free(filename);
			/* Find the scale */
			ret = iioutils_get_param_float(&current->scale,
						       "scale",
						       device_dir,
						       current->name,
						       current->generic_name);
			if (ret < 0)
				goto error_cleanup_array;
			ret = iioutils_get_param_float(&current->offset,
						       "offset",
						       device_dir,
						       current->name,
						       current->generic_name);
			if (ret < 0)
				goto error_cleanup_array;
			ret = iioutils_get_type(&current->is_signed,
						&current->bytes,
						&current->bits_used,
396
						&current->shift,
397
						&current->mask,
398
						&current->be,
399 400 401 402 403
						device_dir,
						current->name,
						current->generic_name);
		}
	}
404

405
	closedir(dp);
406
	free(scan_el_dir);
407 408
	/* reorder so that the array is in index order */
	bsort_channel_array_by_index(ci_array, *counter);
409 410 411 412

	return 0;

error_cleanup_array:
413
	for (i = count - 1;  i >= 0; i--)
414 415 416 417 418 419 420 421 422 423
		free((*ci_array)[i].name);
	free(*ci_array);
error_close_dir:
	closedir(dp);
error_free_name:
	free(scan_el_dir);
error_ret:
	return ret;
}

424 425 426 427 428 429 430
/**
 * find_type_by_name() - function to match top level types by name
 * @name: top level type instance name
 * @type: the type of top level instance being sort
 *
 * Typical types this is used for are device and trigger.
 **/
431
int find_type_by_name(const char *name, const char *type)
432 433
{
	const struct dirent *ent;
434
	int number, numstrlen;
435 436 437

	FILE *nameFile;
	DIR *dp;
438 439 440
	char thisname[IIO_MAX_NAME_LENGTH];
	char *filename;

441 442
	dp = opendir(iio_dir);
	if (dp == NULL) {
443
		printf("No industrialio devices available\n");
444
		return -ENODEV;
445
	}
446

447 448
	while (ent = readdir(dp), ent != NULL) {
		if (strcmp(ent->d_name, ".") != 0 &&
449 450 451 452 453 454 455 456 457 458 459 460 461
			strcmp(ent->d_name, "..") != 0 &&
			strlen(ent->d_name) > strlen(type) &&
			strncmp(ent->d_name, type, strlen(type)) == 0) {
			numstrlen = sscanf(ent->d_name + strlen(type),
					   "%d",
					   &number);
			/* verify the next character is not a colon */
			if (strncmp(ent->d_name + strlen(type) + numstrlen,
					":",
					1) != 0) {
				filename = malloc(strlen(iio_dir)
						+ strlen(type)
						+ numstrlen
462
						+ 6);
463 464
				if (filename == NULL) {
					closedir(dp);
465
					return -ENOMEM;
466
				}
467 468 469 470 471
				sprintf(filename, "%s%s%d/name",
					iio_dir,
					type,
					number);
				nameFile = fopen(filename, "r");
472 473
				if (!nameFile) {
					free(filename);
474
					continue;
475
				}
476
				free(filename);
477 478
				fscanf(nameFile, "%s", thisname);
				fclose(nameFile);
479 480 481 482
				if (strcmp(name, thisname) == 0) {
					closedir(dp);
					return number;
				}
483 484 485
			}
		}
	}
486
	closedir(dp);
487
	return -ENODEV;
488 489
}

490
int _write_sysfs_int(char *filename, char *basedir, int val, int verify)
491
{
492
	int ret = 0;
493 494 495
	FILE *sysfsfp;
	int test;
	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
496

497 498 499
	if (temp == NULL)
		return -ENOMEM;
	sprintf(temp, "%s/%s", basedir, filename);
500
	sysfsfp = fopen(temp, "w");
501 502 503 504 505
	if (sysfsfp == NULL) {
		printf("failed to open %s\n", temp);
		ret = -errno;
		goto error_free;
	}
506 507
	fprintf(sysfsfp, "%d", val);
	fclose(sysfsfp);
508 509 510 511 512 513 514 515
	if (verify) {
		sysfsfp = fopen(temp, "r");
		if (sysfsfp == NULL) {
			printf("failed to open %s\n", temp);
			ret = -errno;
			goto error_free;
		}
		fscanf(sysfsfp, "%d", &test);
516
		fclose(sysfsfp);
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
		if (test != val) {
			printf("Possible failure in int write %d to %s%s\n",
				val,
				basedir,
				filename);
			ret = -1;
		}
	}
error_free:
	free(temp);
	return ret;
}

int write_sysfs_int(char *filename, char *basedir, int val)
{
	return _write_sysfs_int(filename, basedir, val, 0);
533 534
}

535
int write_sysfs_int_and_verify(char *filename, char *basedir, int val)
536 537 538 539 540
{
	return _write_sysfs_int(filename, basedir, val, 1);
}

int _write_sysfs_string(char *filename, char *basedir, char *val, int verify)
541
{
542
	int ret = 0;
543
	FILE  *sysfsfp;
544
	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
545

546 547 548 549 550
	if (temp == NULL) {
		printf("Memory allocation failed\n");
		return -ENOMEM;
	}
	sprintf(temp, "%s/%s", basedir, filename);
551
	sysfsfp = fopen(temp, "w");
552 553 554 555 556 557
	if (sysfsfp == NULL) {
		printf("Could not open %s\n", temp);
		ret = -errno;
		goto error_free;
	}
	fprintf(sysfsfp, "%s", val);
558
	fclose(sysfsfp);
559 560 561
	if (verify) {
		sysfsfp = fopen(temp, "r");
		if (sysfsfp == NULL) {
562
			printf("could not open file to verify\n");
563 564 565 566
			ret = -errno;
			goto error_free;
		}
		fscanf(sysfsfp, "%s", temp);
567
		fclose(sysfsfp);
568 569 570
		if (strcmp(temp, val) != 0) {
			printf("Possible failure in string write of %s "
				"Should be %s "
L
Lucas De Marchi 已提交
571
				"written to %s\%s\n",
572 573 574 575 576 577
				temp,
				val,
				basedir,
				filename);
			ret = -1;
		}
578
	}
579 580
error_free:
	free(temp);
581

582
	return ret;
583
}
584

585 586 587 588 589 590 591 592
/**
 * write_sysfs_string_and_verify() - string write, readback and verify
 * @filename: name of file to write to
 * @basedir: the sysfs directory in which the file is to be found
 * @val: the string to write
 **/
int write_sysfs_string_and_verify(char *filename, char *basedir, char *val)
{
593 594
	return _write_sysfs_string(filename, basedir, val, 1);
}
595

596 597 598
int write_sysfs_string(char *filename, char *basedir, char *val)
{
	return _write_sysfs_string(filename, basedir, val, 0);
599 600 601 602 603 604
}

int read_sysfs_posint(char *filename, char *basedir)
{
	int ret;
	FILE  *sysfsfp;
605
	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
606

607 608 609 610 611
	if (temp == NULL) {
		printf("Memory allocation failed");
		return -ENOMEM;
	}
	sprintf(temp, "%s/%s", basedir, filename);
612
	sysfsfp = fopen(temp, "r");
613 614 615 616
	if (sysfsfp == NULL) {
		ret = -errno;
		goto error_free;
	}
617 618
	fscanf(sysfsfp, "%d\n", &ret);
	fclose(sysfsfp);
619 620 621 622 623 624 625
error_free:
	free(temp);
	return ret;
}

int read_sysfs_float(char *filename, char *basedir, float *val)
{
626
	int ret = 0;
627 628
	FILE  *sysfsfp;
	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
629

630 631 632 633 634 635 636 637 638 639 640 641 642 643
	if (temp == NULL) {
		printf("Memory allocation failed");
		return -ENOMEM;
	}
	sprintf(temp, "%s/%s", basedir, filename);
	sysfsfp = fopen(temp, "r");
	if (sysfsfp == NULL) {
		ret = -errno;
		goto error_free;
	}
	fscanf(sysfsfp, "%f\n", val);
	fclose(sysfsfp);
error_free:
	free(temp);
644 645
	return ret;
}
646

647
int read_sysfs_string(const char *filename, const char *basedir, char *str)
648
{
649
	int ret = 0;
650 651
	FILE  *sysfsfp;
	char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
652

653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
	if (temp == NULL) {
		printf("Memory allocation failed");
		return -ENOMEM;
	}
	sprintf(temp, "%s/%s", basedir, filename);
	sysfsfp = fopen(temp, "r");
	if (sysfsfp == NULL) {
		ret = -errno;
		goto error_free;
	}
	fscanf(sysfsfp, "%s\n", str);
	fclose(sysfsfp);
error_free:
	free(temp);
	return ret;
}
669 670

#endif /* _IIO_UTILS_H */