18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Industrial I/O utilities - lsiio.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2010 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <string.h>
98c2ecf20Sopenharmony_ci#include <dirent.h>
108c2ecf20Sopenharmony_ci#include <stdio.h>
118c2ecf20Sopenharmony_ci#include <errno.h>
128c2ecf20Sopenharmony_ci#include <stdint.h>
138c2ecf20Sopenharmony_ci#include <stdlib.h>
148c2ecf20Sopenharmony_ci#include <unistd.h>
158c2ecf20Sopenharmony_ci#include <sys/types.h>
168c2ecf20Sopenharmony_ci#include <sys/stat.h>
178c2ecf20Sopenharmony_ci#include <sys/dir.h>
188c2ecf20Sopenharmony_ci#include "iio_utils.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic enum verbosity {
218c2ecf20Sopenharmony_ci	VERBLEVEL_DEFAULT,	/* 0 gives lspci behaviour */
228c2ecf20Sopenharmony_ci	VERBLEVEL_SENSORS,	/* 1 lists sensors */
238c2ecf20Sopenharmony_ci} verblevel = VERBLEVEL_DEFAULT;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciconst char *type_device = "iio:device";
268c2ecf20Sopenharmony_ciconst char *type_trigger = "trigger";
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic inline int check_prefix(const char *str, const char *prefix)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	return strlen(str) > strlen(prefix) &&
318c2ecf20Sopenharmony_ci	       strncmp(str, prefix, strlen(prefix)) == 0;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic inline int check_postfix(const char *str, const char *postfix)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	return strlen(str) > strlen(postfix) &&
378c2ecf20Sopenharmony_ci	       strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic int dump_channels(const char *dev_dir_name)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	DIR *dp;
438c2ecf20Sopenharmony_ci	const struct dirent *ent;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	dp = opendir(dev_dir_name);
468c2ecf20Sopenharmony_ci	if (!dp)
478c2ecf20Sopenharmony_ci		return -errno;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	while (ent = readdir(dp), ent)
508c2ecf20Sopenharmony_ci		if (check_prefix(ent->d_name, "in_") &&
518c2ecf20Sopenharmony_ci		   (check_postfix(ent->d_name, "_raw") ||
528c2ecf20Sopenharmony_ci		    check_postfix(ent->d_name, "_input")))
538c2ecf20Sopenharmony_ci			printf("   %-10s\n", ent->d_name);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return (closedir(dp) == -1) ? -errno : 0;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int dump_one_device(const char *dev_dir_name)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	char name[IIO_MAX_NAME_LENGTH];
618c2ecf20Sopenharmony_ci	int dev_idx;
628c2ecf20Sopenharmony_ci	int ret;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	ret = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device), "%i",
658c2ecf20Sopenharmony_ci		     &dev_idx);
668c2ecf20Sopenharmony_ci	if (ret != 1)
678c2ecf20Sopenharmony_ci		return -EINVAL;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	ret = read_sysfs_string("name", dev_dir_name, name);
708c2ecf20Sopenharmony_ci	if (ret < 0)
718c2ecf20Sopenharmony_ci		return ret;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	printf("Device %03d: %s\n", dev_idx, name);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (verblevel >= VERBLEVEL_SENSORS)
768c2ecf20Sopenharmony_ci		return dump_channels(dev_dir_name);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return 0;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic int dump_one_trigger(const char *dev_dir_name)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	char name[IIO_MAX_NAME_LENGTH];
848c2ecf20Sopenharmony_ci	int dev_idx;
858c2ecf20Sopenharmony_ci	int ret;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	ret = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger),
888c2ecf20Sopenharmony_ci		     "%i", &dev_idx);
898c2ecf20Sopenharmony_ci	if (ret != 1)
908c2ecf20Sopenharmony_ci		return -EINVAL;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	ret = read_sysfs_string("name", dev_dir_name, name);
938c2ecf20Sopenharmony_ci	if (ret < 0)
948c2ecf20Sopenharmony_ci		return ret;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	printf("Trigger %03d: %s\n", dev_idx, name);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return 0;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic int dump_devices(void)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	const struct dirent *ent;
1048c2ecf20Sopenharmony_ci	int ret;
1058c2ecf20Sopenharmony_ci	DIR *dp;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	dp = opendir(iio_dir);
1088c2ecf20Sopenharmony_ci	if (!dp) {
1098c2ecf20Sopenharmony_ci		fprintf(stderr, "No industrial I/O devices available\n");
1108c2ecf20Sopenharmony_ci		return -ENODEV;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	while (ent = readdir(dp), ent) {
1148c2ecf20Sopenharmony_ci		if (check_prefix(ent->d_name, type_device)) {
1158c2ecf20Sopenharmony_ci			char *dev_dir_name;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci			if (asprintf(&dev_dir_name, "%s%s", iio_dir,
1188c2ecf20Sopenharmony_ci				     ent->d_name) < 0) {
1198c2ecf20Sopenharmony_ci				ret = -ENOMEM;
1208c2ecf20Sopenharmony_ci				goto error_close_dir;
1218c2ecf20Sopenharmony_ci			}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci			ret = dump_one_device(dev_dir_name);
1248c2ecf20Sopenharmony_ci			if (ret) {
1258c2ecf20Sopenharmony_ci				free(dev_dir_name);
1268c2ecf20Sopenharmony_ci				goto error_close_dir;
1278c2ecf20Sopenharmony_ci			}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci			free(dev_dir_name);
1308c2ecf20Sopenharmony_ci			if (verblevel >= VERBLEVEL_SENSORS)
1318c2ecf20Sopenharmony_ci				printf("\n");
1328c2ecf20Sopenharmony_ci		}
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci	rewinddir(dp);
1358c2ecf20Sopenharmony_ci	while (ent = readdir(dp), ent) {
1368c2ecf20Sopenharmony_ci		if (check_prefix(ent->d_name, type_trigger)) {
1378c2ecf20Sopenharmony_ci			char *dev_dir_name;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci			if (asprintf(&dev_dir_name, "%s%s", iio_dir,
1408c2ecf20Sopenharmony_ci				     ent->d_name) < 0) {
1418c2ecf20Sopenharmony_ci				ret = -ENOMEM;
1428c2ecf20Sopenharmony_ci				goto error_close_dir;
1438c2ecf20Sopenharmony_ci			}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci			ret = dump_one_trigger(dev_dir_name);
1468c2ecf20Sopenharmony_ci			if (ret) {
1478c2ecf20Sopenharmony_ci				free(dev_dir_name);
1488c2ecf20Sopenharmony_ci				goto error_close_dir;
1498c2ecf20Sopenharmony_ci			}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci			free(dev_dir_name);
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return (closedir(dp) == -1) ? -errno : 0;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cierror_close_dir:
1588c2ecf20Sopenharmony_ci	if (closedir(dp) == -1)
1598c2ecf20Sopenharmony_ci		perror("dump_devices(): Failed to close directory");
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return ret;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ciint main(int argc, char **argv)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	int c, err = 0;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	while ((c = getopt(argc, argv, "v")) != EOF) {
1698c2ecf20Sopenharmony_ci		switch (c) {
1708c2ecf20Sopenharmony_ci		case 'v':
1718c2ecf20Sopenharmony_ci			verblevel++;
1728c2ecf20Sopenharmony_ci			break;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		case '?':
1758c2ecf20Sopenharmony_ci		default:
1768c2ecf20Sopenharmony_ci			err++;
1778c2ecf20Sopenharmony_ci			break;
1788c2ecf20Sopenharmony_ci		}
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci	if (err || argc > optind) {
1818c2ecf20Sopenharmony_ci		fprintf(stderr, "Usage: lsiio [options]...\n"
1828c2ecf20Sopenharmony_ci			"List industrial I/O devices\n"
1838c2ecf20Sopenharmony_ci			"  -v  Increase verbosity (may be given multiple times)\n");
1848c2ecf20Sopenharmony_ci		exit(1);
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	return dump_devices();
1888c2ecf20Sopenharmony_ci}
189