2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-10-21 16:45:54 +03:00
/*
* lsgpio - example on how to list the GPIO lines on a system
*
* Copyright ( C ) 2015 Linus Walleij
*
* Usage :
* lsgpio < - n device - name >
*/
# include <unistd.h>
# include <stdlib.h>
# include <stdbool.h>
# include <stdio.h>
# include <dirent.h>
# include <errno.h>
# include <string.h>
# include <poll.h>
# include <fcntl.h>
# include <getopt.h>
# include <sys/ioctl.h>
# include <linux/gpio.h>
# include "gpio-utils.h"
2016-02-13 00:25:22 +03:00
struct gpio_flag {
char * name ;
2020-09-28 03:28:01 +03:00
unsigned long long mask ;
2016-02-13 00:25:22 +03:00
} ;
struct gpio_flag flagnames [ ] = {
{
2020-09-28 03:28:01 +03:00
. name = " used " ,
. mask = GPIO_V2_LINE_FLAG_USED ,
} ,
{
. name = " input " ,
. mask = GPIO_V2_LINE_FLAG_INPUT ,
2016-02-13 00:25:22 +03:00
} ,
{
. name = " output " ,
2020-09-28 03:28:01 +03:00
. mask = GPIO_V2_LINE_FLAG_OUTPUT ,
2016-02-13 00:25:22 +03:00
} ,
{
. name = " active-low " ,
2020-09-28 03:28:01 +03:00
. mask = GPIO_V2_LINE_FLAG_ACTIVE_LOW ,
2016-02-13 00:25:22 +03:00
} ,
{
. name = " open-drain " ,
2020-09-28 03:28:01 +03:00
. mask = GPIO_V2_LINE_FLAG_OPEN_DRAIN ,
2016-02-13 00:25:22 +03:00
} ,
{
. name = " open-source " ,
2020-09-28 03:28:01 +03:00
. mask = GPIO_V2_LINE_FLAG_OPEN_SOURCE ,
2016-02-13 00:25:22 +03:00
} ,
2020-04-30 03:09:16 +03:00
{
. name = " pull-up " ,
2020-09-28 03:28:01 +03:00
. mask = GPIO_V2_LINE_FLAG_BIAS_PULL_UP ,
2020-04-30 03:09:16 +03:00
} ,
{
. name = " pull-down " ,
2020-09-28 03:28:01 +03:00
. mask = GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN ,
2020-04-30 03:09:16 +03:00
} ,
{
. name = " bias-disabled " ,
2020-09-28 03:28:01 +03:00
. mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED ,
2020-04-30 03:09:16 +03:00
} ,
2020-10-15 02:11:57 +03:00
{
. name = " clock-realtime " ,
. mask = GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME ,
} ,
2016-02-13 00:25:22 +03:00
} ;
2020-09-28 03:28:01 +03:00
static void print_attributes ( struct gpio_v2_line_info * info )
2016-02-13 00:25:22 +03:00
{
int i ;
2020-09-28 03:28:01 +03:00
const char * field_format = " %s " ;
2016-02-13 00:25:22 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( flagnames ) ; i + + ) {
2020-09-28 03:28:01 +03:00
if ( info - > flags & flagnames [ i ] . mask ) {
fprintf ( stdout , field_format , flagnames [ i ] . name ) ;
field_format = " , %s " ;
2016-02-13 00:25:22 +03:00
}
}
2020-09-28 03:28:01 +03:00
if ( ( info - > flags & GPIO_V2_LINE_FLAG_EDGE_RISING ) & &
( info - > flags & GPIO_V2_LINE_FLAG_EDGE_FALLING ) )
fprintf ( stdout , field_format , " both-edges " ) ;
else if ( info - > flags & GPIO_V2_LINE_FLAG_EDGE_RISING )
fprintf ( stdout , field_format , " rising-edge " ) ;
else if ( info - > flags & GPIO_V2_LINE_FLAG_EDGE_FALLING )
fprintf ( stdout , field_format , " falling-edge " ) ;
for ( i = 0 ; i < info - > num_attrs ; i + + ) {
if ( info - > attrs [ i ] . id = = GPIO_V2_LINE_ATTR_ID_DEBOUNCE )
fprintf ( stdout , " , debounce_period=%dusec " ,
2023-05-08 16:18:48 +03:00
info - > attrs [ i ] . debounce_period_us ) ;
2020-09-28 03:28:01 +03:00
}
2016-02-13 00:25:22 +03:00
}
2015-10-21 16:45:54 +03:00
int list_device ( const char * device_name )
{
struct gpiochip_info cinfo ;
char * chrdev_name ;
int fd ;
int ret ;
2016-02-13 00:25:22 +03:00
int i ;
2015-10-21 16:45:54 +03:00
ret = asprintf ( & chrdev_name , " /dev/%s " , device_name ) ;
if ( ret < 0 )
return - ENOMEM ;
fd = open ( chrdev_name , 0 ) ;
if ( fd = = - 1 ) {
ret = - errno ;
fprintf ( stderr , " Failed to open %s \n " , chrdev_name ) ;
2020-07-08 07:15:58 +03:00
goto exit_free_name ;
2015-10-21 16:45:54 +03:00
}
/* Inspect this GPIO chip */
ret = ioctl ( fd , GPIO_GET_CHIPINFO_IOCTL , & cinfo ) ;
if ( ret = = - 1 ) {
ret = - errno ;
2016-02-13 00:25:22 +03:00
perror ( " Failed to issue CHIPINFO IOCTL \n " ) ;
goto exit_close_error ;
2015-10-21 16:45:54 +03:00
}
2016-02-12 16:48:23 +03:00
fprintf ( stdout , " GPIO chip: %s, \" %s \" , %u GPIO lines \n " ,
cinfo . name , cinfo . label , cinfo . lines ) ;
2015-10-21 16:45:54 +03:00
2016-02-13 00:25:22 +03:00
/* Loop over the lines and print info */
for ( i = 0 ; i < cinfo . lines ; i + + ) {
2020-09-28 03:28:01 +03:00
struct gpio_v2_line_info linfo ;
2016-02-13 00:25:22 +03:00
memset ( & linfo , 0 , sizeof ( linfo ) ) ;
2020-09-28 03:28:01 +03:00
linfo . offset = i ;
2016-02-13 00:25:22 +03:00
2020-09-28 03:28:01 +03:00
ret = ioctl ( fd , GPIO_V2_GET_LINEINFO_IOCTL , & linfo ) ;
2016-02-13 00:25:22 +03:00
if ( ret = = - 1 ) {
ret = - errno ;
perror ( " Failed to issue LINEINFO IOCTL \n " ) ;
goto exit_close_error ;
}
2020-09-28 03:28:01 +03:00
fprintf ( stdout , " \t line %2d: " , linfo . offset ) ;
2016-02-13 00:25:22 +03:00
if ( linfo . name [ 0 ] )
2016-02-23 10:54:46 +03:00
fprintf ( stdout , " \" %s \" " , linfo . name ) ;
2016-02-13 00:25:22 +03:00
else
fprintf ( stdout , " unnamed " ) ;
2016-02-25 23:01:48 +03:00
if ( linfo . consumer [ 0 ] )
fprintf ( stdout , " \" %s \" " , linfo . consumer ) ;
2016-02-13 00:25:22 +03:00
else
2016-02-25 23:01:48 +03:00
fprintf ( stdout , " unused " ) ;
2016-02-13 00:25:22 +03:00
if ( linfo . flags ) {
fprintf ( stdout , " [ " ) ;
2020-09-28 03:28:01 +03:00
print_attributes ( & linfo ) ;
2016-02-13 00:25:22 +03:00
fprintf ( stdout , " ] " ) ;
}
fprintf ( stdout , " \n " ) ;
2015-10-21 16:45:54 +03:00
}
2016-02-13 00:25:22 +03:00
exit_close_error :
if ( close ( fd ) = = - 1 )
perror ( " Failed to close GPIO character device file " ) ;
2020-07-08 07:15:58 +03:00
exit_free_name :
2015-10-21 16:45:54 +03:00
free ( chrdev_name ) ;
return ret ;
}
void print_usage ( void )
{
fprintf ( stderr , " Usage: lsgpio [options]... \n "
" List GPIO chips, lines and states \n "
" -n <name> List GPIOs on a named device \n "
" -? This helptext \n "
) ;
}
int main ( int argc , char * * argv )
{
2016-03-25 15:36:30 +03:00
const char * device_name = NULL ;
2015-10-21 16:45:54 +03:00
int ret ;
int c ;
while ( ( c = getopt ( argc , argv , " n: " ) ) ! = - 1 ) {
switch ( c ) {
case ' n ' :
device_name = optarg ;
break ;
case ' ? ' :
print_usage ( ) ;
return - 1 ;
}
}
if ( device_name )
ret = list_device ( device_name ) ;
else {
const struct dirent * ent ;
DIR * dp ;
/* List all GPIO devices one at a time */
dp = opendir ( " /dev " ) ;
if ( ! dp ) {
ret = - errno ;
goto error_out ;
}
ret = - ENOENT ;
while ( ent = readdir ( dp ) , ent ) {
if ( check_prefix ( ent - > d_name , " gpiochip " ) ) {
ret = list_device ( ent - > d_name ) ;
if ( ret )
break ;
}
}
ret = 0 ;
if ( closedir ( dp ) = = - 1 ) {
perror ( " scanning devices: Failed to close directory " ) ;
ret = - errno ;
}
}
error_out :
return ret ;
}