xref: /openbmc/linux/tools/gpio/lsgpio.c (revision 214338e3)
16d591c46SLinus Walleij /*
26d591c46SLinus Walleij  * lsgpio - example on how to list the GPIO lines on a system
36d591c46SLinus Walleij  *
46d591c46SLinus Walleij  * Copyright (C) 2015 Linus Walleij
56d591c46SLinus Walleij  *
66d591c46SLinus Walleij  * This program is free software; you can redistribute it and/or modify it
76d591c46SLinus Walleij  * under the terms of the GNU General Public License version 2 as published by
86d591c46SLinus Walleij  * the Free Software Foundation.
96d591c46SLinus Walleij  *
106d591c46SLinus Walleij  * Usage:
116d591c46SLinus Walleij  *	lsgpio <-n device-name>
126d591c46SLinus Walleij  */
136d591c46SLinus Walleij 
146d591c46SLinus Walleij #include <unistd.h>
156d591c46SLinus Walleij #include <stdlib.h>
166d591c46SLinus Walleij #include <stdbool.h>
176d591c46SLinus Walleij #include <stdio.h>
186d591c46SLinus Walleij #include <dirent.h>
196d591c46SLinus Walleij #include <errno.h>
206d591c46SLinus Walleij #include <string.h>
216d591c46SLinus Walleij #include <poll.h>
226d591c46SLinus Walleij #include <fcntl.h>
236d591c46SLinus Walleij #include <getopt.h>
246d591c46SLinus Walleij #include <sys/ioctl.h>
256d591c46SLinus Walleij #include <linux/gpio.h>
266d591c46SLinus Walleij 
276d591c46SLinus Walleij #include "gpio-utils.h"
286d591c46SLinus Walleij 
29521a2ad6SLinus Walleij struct gpio_flag {
30521a2ad6SLinus Walleij 	char *name;
31521a2ad6SLinus Walleij 	unsigned long mask;
32521a2ad6SLinus Walleij };
33521a2ad6SLinus Walleij 
34521a2ad6SLinus Walleij struct gpio_flag flagnames[] = {
35521a2ad6SLinus Walleij 	{
36521a2ad6SLinus Walleij 		.name = "kernel",
37521a2ad6SLinus Walleij 		.mask = GPIOLINE_FLAG_KERNEL,
38521a2ad6SLinus Walleij 	},
39521a2ad6SLinus Walleij 	{
40521a2ad6SLinus Walleij 		.name = "output",
41521a2ad6SLinus Walleij 		.mask = GPIOLINE_FLAG_IS_OUT,
42521a2ad6SLinus Walleij 	},
43521a2ad6SLinus Walleij 	{
44521a2ad6SLinus Walleij 		.name = "active-low",
45521a2ad6SLinus Walleij 		.mask = GPIOLINE_FLAG_ACTIVE_LOW,
46521a2ad6SLinus Walleij 	},
47521a2ad6SLinus Walleij 	{
48521a2ad6SLinus Walleij 		.name = "open-drain",
49521a2ad6SLinus Walleij 		.mask = GPIOLINE_FLAG_OPEN_DRAIN,
50521a2ad6SLinus Walleij 	},
51521a2ad6SLinus Walleij 	{
52521a2ad6SLinus Walleij 		.name = "open-source",
53521a2ad6SLinus Walleij 		.mask = GPIOLINE_FLAG_OPEN_SOURCE,
54521a2ad6SLinus Walleij 	},
55521a2ad6SLinus Walleij };
56521a2ad6SLinus Walleij 
57521a2ad6SLinus Walleij void print_flags(unsigned long flags)
58521a2ad6SLinus Walleij {
59521a2ad6SLinus Walleij 	int i;
60521a2ad6SLinus Walleij 	int printed = 0;
61521a2ad6SLinus Walleij 
62521a2ad6SLinus Walleij 	for (i = 0; i < ARRAY_SIZE(flagnames); i++) {
63521a2ad6SLinus Walleij 		if (flags & flagnames[i].mask) {
64521a2ad6SLinus Walleij 			if (printed)
65521a2ad6SLinus Walleij 				fprintf(stdout, " ");
66521a2ad6SLinus Walleij 			fprintf(stdout, "%s", flagnames[i].name);
67521a2ad6SLinus Walleij 			printed++;
68521a2ad6SLinus Walleij 		}
69521a2ad6SLinus Walleij 	}
70521a2ad6SLinus Walleij }
71521a2ad6SLinus Walleij 
726d591c46SLinus Walleij int list_device(const char *device_name)
736d591c46SLinus Walleij {
746d591c46SLinus Walleij 	struct gpiochip_info cinfo;
756d591c46SLinus Walleij 	char *chrdev_name;
766d591c46SLinus Walleij 	int fd;
776d591c46SLinus Walleij 	int ret;
78521a2ad6SLinus Walleij 	int i;
796d591c46SLinus Walleij 
806d591c46SLinus Walleij 	ret = asprintf(&chrdev_name, "/dev/%s", device_name);
816d591c46SLinus Walleij 	if (ret < 0)
826d591c46SLinus Walleij 		return -ENOMEM;
836d591c46SLinus Walleij 
846d591c46SLinus Walleij 	fd = open(chrdev_name, 0);
856d591c46SLinus Walleij 	if (fd == -1) {
866d591c46SLinus Walleij 		ret = -errno;
876d591c46SLinus Walleij 		fprintf(stderr, "Failed to open %s\n", chrdev_name);
88521a2ad6SLinus Walleij 		goto exit_close_error;
896d591c46SLinus Walleij 	}
906d591c46SLinus Walleij 
916d591c46SLinus Walleij 	/* Inspect this GPIO chip */
926d591c46SLinus Walleij 	ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo);
936d591c46SLinus Walleij 	if (ret == -1) {
946d591c46SLinus Walleij 		ret = -errno;
95521a2ad6SLinus Walleij 		perror("Failed to issue CHIPINFO IOCTL\n");
96521a2ad6SLinus Walleij 		goto exit_close_error;
976d591c46SLinus Walleij 	}
98df4878e9SLinus Walleij 	fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n",
99df4878e9SLinus Walleij 		cinfo.name, cinfo.label, cinfo.lines);
1006d591c46SLinus Walleij 
101521a2ad6SLinus Walleij 	/* Loop over the lines and print info */
102521a2ad6SLinus Walleij 	for (i = 0; i < cinfo.lines; i++) {
103521a2ad6SLinus Walleij 		struct gpioline_info linfo;
104521a2ad6SLinus Walleij 
105521a2ad6SLinus Walleij 		memset(&linfo, 0, sizeof(linfo));
106521a2ad6SLinus Walleij 		linfo.line_offset = i;
107521a2ad6SLinus Walleij 
108521a2ad6SLinus Walleij 		ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &linfo);
109521a2ad6SLinus Walleij 		if (ret == -1) {
1106d591c46SLinus Walleij 			ret = -errno;
111521a2ad6SLinus Walleij 			perror("Failed to issue LINEINFO IOCTL\n");
112521a2ad6SLinus Walleij 			goto exit_close_error;
113521a2ad6SLinus Walleij 		}
114bb91d345SMarkus Pargmann 		fprintf(stdout, "\tline %2d:", linfo.line_offset);
115521a2ad6SLinus Walleij 		if (linfo.name[0])
116bb91d345SMarkus Pargmann 			fprintf(stdout, " \"%s\"", linfo.name);
117521a2ad6SLinus Walleij 		else
118521a2ad6SLinus Walleij 			fprintf(stdout, " unnamed");
119214338e3SLinus Walleij 		if (linfo.consumer[0])
120214338e3SLinus Walleij 			fprintf(stdout, " \"%s\"", linfo.consumer);
121521a2ad6SLinus Walleij 		else
122214338e3SLinus Walleij 			fprintf(stdout, " unused");
123521a2ad6SLinus Walleij 		if (linfo.flags) {
124521a2ad6SLinus Walleij 			fprintf(stdout, " [");
125521a2ad6SLinus Walleij 			print_flags(linfo.flags);
126521a2ad6SLinus Walleij 			fprintf(stdout, "]");
127521a2ad6SLinus Walleij 		}
128521a2ad6SLinus Walleij 		fprintf(stdout, "\n");
129521a2ad6SLinus Walleij 
1306d591c46SLinus Walleij 	}
1316d591c46SLinus Walleij 
132521a2ad6SLinus Walleij exit_close_error:
133521a2ad6SLinus Walleij 	if (close(fd) == -1)
134521a2ad6SLinus Walleij 		perror("Failed to close GPIO character device file");
1356d591c46SLinus Walleij 	free(chrdev_name);
1366d591c46SLinus Walleij 	return ret;
1376d591c46SLinus Walleij }
1386d591c46SLinus Walleij 
1396d591c46SLinus Walleij void print_usage(void)
1406d591c46SLinus Walleij {
1416d591c46SLinus Walleij 	fprintf(stderr, "Usage: lsgpio [options]...\n"
1426d591c46SLinus Walleij 		"List GPIO chips, lines and states\n"
1436d591c46SLinus Walleij 		"  -n <name>  List GPIOs on a named device\n"
1446d591c46SLinus Walleij 		"  -?         This helptext\n"
1456d591c46SLinus Walleij 	);
1466d591c46SLinus Walleij }
1476d591c46SLinus Walleij 
1486d591c46SLinus Walleij int main(int argc, char **argv)
1496d591c46SLinus Walleij {
1506d591c46SLinus Walleij 	const char *device_name;
1516d591c46SLinus Walleij 	int ret;
1526d591c46SLinus Walleij 	int c;
1536d591c46SLinus Walleij 
1546d591c46SLinus Walleij 	while ((c = getopt(argc, argv, "n:")) != -1) {
1556d591c46SLinus Walleij 		switch (c) {
1566d591c46SLinus Walleij 		case 'n':
1576d591c46SLinus Walleij 			device_name = optarg;
1586d591c46SLinus Walleij 			break;
1596d591c46SLinus Walleij 		case '?':
1606d591c46SLinus Walleij 			print_usage();
1616d591c46SLinus Walleij 			return -1;
1626d591c46SLinus Walleij 		}
1636d591c46SLinus Walleij 	}
1646d591c46SLinus Walleij 
1656d591c46SLinus Walleij 	if (device_name)
1666d591c46SLinus Walleij 		ret = list_device(device_name);
1676d591c46SLinus Walleij 	else {
1686d591c46SLinus Walleij 		const struct dirent *ent;
1696d591c46SLinus Walleij 		DIR *dp;
1706d591c46SLinus Walleij 
1716d591c46SLinus Walleij 		/* List all GPIO devices one at a time */
1726d591c46SLinus Walleij 		dp = opendir("/dev");
1736d591c46SLinus Walleij 		if (!dp) {
1746d591c46SLinus Walleij 			ret = -errno;
1756d591c46SLinus Walleij 			goto error_out;
1766d591c46SLinus Walleij 		}
1776d591c46SLinus Walleij 
1786d591c46SLinus Walleij 		ret = -ENOENT;
1796d591c46SLinus Walleij 		while (ent = readdir(dp), ent) {
1806d591c46SLinus Walleij 			if (check_prefix(ent->d_name, "gpiochip")) {
1816d591c46SLinus Walleij 				ret = list_device(ent->d_name);
1826d591c46SLinus Walleij 				if (ret)
1836d591c46SLinus Walleij 					break;
1846d591c46SLinus Walleij 			}
1856d591c46SLinus Walleij 		}
1866d591c46SLinus Walleij 
1876d591c46SLinus Walleij 		ret = 0;
1886d591c46SLinus Walleij 		if (closedir(dp) == -1) {
1896d591c46SLinus Walleij 			perror("scanning devices: Failed to close directory");
1906d591c46SLinus Walleij 			ret = -errno;
1916d591c46SLinus Walleij 		}
1926d591c46SLinus Walleij 	}
1936d591c46SLinus Walleij error_out:
1946d591c46SLinus Walleij 	return ret;
1956d591c46SLinus Walleij }
196