1/*
2 * Industrial I/O utilities - lsiio.c
3 *
4 * Copyright (c) 2010 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#include <string.h>
12#include <dirent.h>
13#include <stdio.h>
14#include <errno.h>
15#include <stdint.h>
16#include <stdlib.h>
17#include <unistd.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/dir.h>
21#include "iio_utils.h"
22
23
24static enum verbosity {
25	VERBLEVEL_DEFAULT,	/* 0 gives lspci behaviour */
26	VERBLEVEL_SENSORS,	/* 1 lists sensors */
27} verblevel = VERBLEVEL_DEFAULT;
28
29const char *type_device = "iio:device";
30const char *type_trigger = "trigger";
31
32
33static inline int check_prefix(const char *str, const char *prefix)
34{
35	return strlen(str) > strlen(prefix) &&
36		strncmp(str, prefix, strlen(prefix)) == 0;
37}
38
39static inline int check_postfix(const char *str, const char *postfix)
40{
41	return strlen(str) > strlen(postfix) &&
42		strcmp(str + strlen(str) - strlen(postfix), postfix) == 0;
43}
44
45static int dump_channels(const char *dev_dir_name)
46{
47	DIR *dp;
48	const struct dirent *ent;
49
50	dp = opendir(dev_dir_name);
51	if (dp == NULL)
52		return -errno;
53	while (ent = readdir(dp), ent != NULL)
54		if (check_prefix(ent->d_name, "in_") &&
55		    check_postfix(ent->d_name, "_raw")) {
56			printf("   %-10s\n", ent->d_name);
57		}
58
59	return 0;
60}
61
62static int dump_one_device(const char *dev_dir_name)
63{
64	char name[IIO_MAX_NAME_LENGTH];
65	int dev_idx;
66	int retval;
67
68	retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device),
69			"%i", &dev_idx);
70	if (retval != 1)
71		return -EINVAL;
72	read_sysfs_string("name", dev_dir_name, name);
73	printf("Device %03d: %s\n", dev_idx, name);
74
75	if (verblevel >= VERBLEVEL_SENSORS)
76		return dump_channels(dev_dir_name);
77	return 0;
78}
79
80static int dump_one_trigger(const char *dev_dir_name)
81{
82	char name[IIO_MAX_NAME_LENGTH];
83	int dev_idx;
84	int retval;
85
86	retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger),
87			"%i", &dev_idx);
88	if (retval != 1)
89		return -EINVAL;
90	read_sysfs_string("name", dev_dir_name, name);
91	printf("Trigger %03d: %s\n", dev_idx, name);
92	return 0;
93}
94
95static void dump_devices(void)
96{
97	const struct dirent *ent;
98	DIR *dp;
99
100	dp = opendir(iio_dir);
101	if (dp == NULL) {
102		printf("No industrial I/O devices available\n");
103		return;
104	}
105
106	while (ent = readdir(dp), ent != NULL) {
107		if (check_prefix(ent->d_name, type_device)) {
108			char *dev_dir_name;
109
110			asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name);
111			dump_one_device(dev_dir_name);
112			free(dev_dir_name);
113			if (verblevel >= VERBLEVEL_SENSORS)
114				printf("\n");
115		}
116	}
117	rewinddir(dp);
118	while (ent = readdir(dp), ent != NULL) {
119		if (check_prefix(ent->d_name, type_trigger)) {
120			char *dev_dir_name;
121
122			asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name);
123			dump_one_trigger(dev_dir_name);
124			free(dev_dir_name);
125		}
126	}
127	closedir(dp);
128}
129
130int main(int argc, char **argv)
131{
132	int c, err = 0;
133
134	while ((c = getopt(argc, argv, "d:D:v")) != EOF) {
135		switch (c) {
136		case 'v':
137			verblevel++;
138			break;
139
140		case '?':
141		default:
142			err++;
143			break;
144		}
145	}
146	if (err || argc > optind) {
147		fprintf(stderr, "Usage: lsiio [options]...\n"
148			"List industrial I/O devices\n"
149			"  -v, --verbose\n"
150			"      Increase verbosity (may be given multiple times)\n"
151			);
152		exit(1);
153	}
154
155	dump_devices();
156
157	return 0;
158}
159