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 ;
unsigned long mask ;
} ;
struct gpio_flag flagnames [ ] = {
{
. name = " kernel " ,
. mask = GPIOLINE_FLAG_KERNEL ,
} ,
{
. name = " output " ,
. mask = GPIOLINE_FLAG_IS_OUT ,
} ,
{
. name = " active-low " ,
. mask = GPIOLINE_FLAG_ACTIVE_LOW ,
} ,
{
. name = " open-drain " ,
. mask = GPIOLINE_FLAG_OPEN_DRAIN ,
} ,
{
. name = " open-source " ,
. mask = GPIOLINE_FLAG_OPEN_SOURCE ,
} ,
} ;
void print_flags ( unsigned long flags )
{
int i ;
int printed = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( flagnames ) ; i + + ) {
if ( flags & flagnames [ i ] . mask ) {
if ( printed )
fprintf ( stdout , " " ) ;
fprintf ( stdout , " %s " , flagnames [ i ] . name ) ;
printed + + ;
}
}
}
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 ) ;
2016-02-13 00:25:22 +03:00
goto exit_close_error ;
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 + + ) {
struct gpioline_info linfo ;
memset ( & linfo , 0 , sizeof ( linfo ) ) ;
linfo . line_offset = i ;
ret = ioctl ( fd , GPIO_GET_LINEINFO_IOCTL , & linfo ) ;
if ( ret = = - 1 ) {
ret = - errno ;
perror ( " Failed to issue LINEINFO IOCTL \n " ) ;
goto exit_close_error ;
}
2016-02-23 10:54:46 +03:00
fprintf ( stdout , " \t line %2d: " , linfo . line_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 , " [ " ) ;
print_flags ( linfo . flags ) ;
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 " ) ;
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 ;
}