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