brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 52a0be4 Raw
226 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * lsgpio - example on how to list the GPIO lines on a system4 *5 * Copyright (C) 2015 Linus Walleij6 *7 * Usage:8 *	lsgpio <-n device-name>9 */10 11#include <unistd.h>12#include <stdlib.h>13#include <stdbool.h>14#include <stdio.h>15#include <dirent.h>16#include <errno.h>17#include <string.h>18#include <poll.h>19#include <fcntl.h>20#include <getopt.h>21#include <sys/ioctl.h>22#include <linux/gpio.h>23 24#include "gpio-utils.h"25 26struct gpio_flag {27	char *name;28	unsigned long long mask;29};30 31struct gpio_flag flagnames[] = {32	{33		.name = "used",34		.mask = GPIO_V2_LINE_FLAG_USED,35	},36	{37		.name = "input",38		.mask = GPIO_V2_LINE_FLAG_INPUT,39	},40	{41		.name = "output",42		.mask = GPIO_V2_LINE_FLAG_OUTPUT,43	},44	{45		.name = "active-low",46		.mask = GPIO_V2_LINE_FLAG_ACTIVE_LOW,47	},48	{49		.name = "open-drain",50		.mask = GPIO_V2_LINE_FLAG_OPEN_DRAIN,51	},52	{53		.name = "open-source",54		.mask = GPIO_V2_LINE_FLAG_OPEN_SOURCE,55	},56	{57		.name = "pull-up",58		.mask = GPIO_V2_LINE_FLAG_BIAS_PULL_UP,59	},60	{61		.name = "pull-down",62		.mask = GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN,63	},64	{65		.name = "bias-disabled",66		.mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED,67	},68	{69		.name = "clock-realtime",70		.mask = GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME,71	},72};73 74static void print_attributes(struct gpio_v2_line_info *info)75{76	int i;77	const char *field_format = "%s";78 79	for (i = 0; i < ARRAY_SIZE(flagnames); i++) {80		if (info->flags & flagnames[i].mask) {81			fprintf(stdout, field_format, flagnames[i].name);82			field_format = ", %s";83		}84	}85 86	if ((info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING) &&87	    (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING))88		fprintf(stdout, field_format, "both-edges");89	else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING)90		fprintf(stdout, field_format, "rising-edge");91	else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING)92		fprintf(stdout, field_format, "falling-edge");93 94	for (i = 0; i < info->num_attrs; i++) {95		if (info->attrs[i].id == GPIO_V2_LINE_ATTR_ID_DEBOUNCE)96			fprintf(stdout, ", debounce_period=%dusec",97				info->attrs[i].debounce_period_us);98	}99}100 101int list_device(const char *device_name)102{103	struct gpiochip_info cinfo;104	char *chrdev_name;105	int fd;106	int ret;107	int i;108 109	ret = asprintf(&chrdev_name, "/dev/%s", device_name);110	if (ret < 0)111		return -ENOMEM;112 113	fd = open(chrdev_name, 0);114	if (fd == -1) {115		ret = -errno;116		fprintf(stderr, "Failed to open %s\n", chrdev_name);117		goto exit_free_name;118	}119 120	/* Inspect this GPIO chip */121	ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo);122	if (ret == -1) {123		ret = -errno;124		perror("Failed to issue CHIPINFO IOCTL\n");125		goto exit_close_error;126	}127	fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n",128		cinfo.name, cinfo.label, cinfo.lines);129 130	/* Loop over the lines and print info */131	for (i = 0; i < cinfo.lines; i++) {132		struct gpio_v2_line_info linfo;133 134		memset(&linfo, 0, sizeof(linfo));135		linfo.offset = i;136 137		ret = ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &linfo);138		if (ret == -1) {139			ret = -errno;140			perror("Failed to issue LINEINFO IOCTL\n");141			goto exit_close_error;142		}143		fprintf(stdout, "\tline %2d:", linfo.offset);144		if (linfo.name[0])145			fprintf(stdout, " \"%s\"", linfo.name);146		else147			fprintf(stdout, " unnamed");148		if (linfo.consumer[0])149			fprintf(stdout, " \"%s\"", linfo.consumer);150		else151			fprintf(stdout, " unused");152		if (linfo.flags) {153			fprintf(stdout, " [");154			print_attributes(&linfo);155			fprintf(stdout, "]");156		}157		fprintf(stdout, "\n");158 159	}160 161exit_close_error:162	if (close(fd) == -1)163		perror("Failed to close GPIO character device file");164exit_free_name:165	free(chrdev_name);166	return ret;167}168 169void print_usage(void)170{171	fprintf(stderr, "Usage: lsgpio [options]...\n"172		"List GPIO chips, lines and states\n"173		"  -n <name>  List GPIOs on a named device\n"174		"  -?         This helptext\n"175	);176}177 178int main(int argc, char **argv)179{180	const char *device_name = NULL;181	int ret;182	int c;183 184	while ((c = getopt(argc, argv, "n:")) != -1) {185		switch (c) {186		case 'n':187			device_name = optarg;188			break;189		case '?':190			print_usage();191			return -1;192		}193	}194 195	if (device_name)196		ret = list_device(device_name);197	else {198		const struct dirent *ent;199		DIR *dp;200 201		/* List all GPIO devices one at a time */202		dp = opendir("/dev");203		if (!dp) {204			ret = -errno;205			goto error_out;206		}207 208		ret = -ENOENT;209		while (ent = readdir(dp), ent) {210			if (check_prefix(ent->d_name, "gpiochip")) {211				ret = list_device(ent->d_name);212				if (ret)213					break;214			}215		}216 217		ret = 0;218		if (closedir(dp) == -1) {219			perror("scanning devices: Failed to close directory");220			ret = -errno;221		}222	}223error_out:224	return ret;225}226