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