2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-06-02 12:38:33 +03:00
/*
2016-07-27 08:41:49 +03:00
* gpio - event - mon - monitor GPIO line events from userspace
2016-06-02 12:38:33 +03:00
*
* Copyright ( C ) 2016 Linus Walleij
*
* Usage :
* gpio - event - mon - n < device - name > - o < offset >
*/
# include <unistd.h>
# include <stdlib.h>
# include <stdbool.h>
2017-12-14 23:26:08 +03:00
# include <stdint.h>
2016-06-02 12:38:33 +03:00
# include <stdio.h>
# include <dirent.h>
# include <errno.h>
# include <string.h>
# include <poll.h>
# include <fcntl.h>
# include <getopt.h>
# include <inttypes.h>
# include <sys/ioctl.h>
2017-12-21 03:41:31 +03:00
# include <sys/types.h>
2016-06-02 12:38:33 +03:00
# include <linux/gpio.h>
2020-09-28 03:28:05 +03:00
# include "gpio-utils.h"
2016-06-02 12:38:33 +03:00
int monitor_device ( const char * device_name ,
unsigned int line ,
2020-09-28 03:28:05 +03:00
struct gpio_v2_line_config * config ,
2016-06-02 12:38:33 +03:00
unsigned int loops )
{
2020-09-28 03:28:05 +03:00
struct gpio_v2_line_values values ;
2016-06-02 12:38:33 +03:00
char * chrdev_name ;
2020-09-28 03:28:05 +03:00
int cfd , lfd ;
2016-06-02 12:38:33 +03:00
int ret ;
int i = 0 ;
ret = asprintf ( & chrdev_name , " /dev/%s " , device_name ) ;
if ( ret < 0 )
return - ENOMEM ;
2020-09-28 03:28:05 +03:00
cfd = open ( chrdev_name , 0 ) ;
if ( cfd = = - 1 ) {
2016-06-02 12:38:33 +03:00
ret = - errno ;
fprintf ( stderr , " Failed to open %s \n " , chrdev_name ) ;
2020-07-08 07:16:00 +03:00
goto exit_free_name ;
2016-06-02 12:38:33 +03:00
}
2020-09-28 03:28:05 +03:00
ret = gpiotools_request_line ( device_name , & line , 1 , config ,
" gpio-event-mon " ) ;
if ( ret < 0 )
goto exit_device_close ;
else
lfd = ret ;
2016-06-02 12:38:33 +03:00
/* Read initial states */
2020-09-28 03:28:05 +03:00
values . mask = 1 ;
values . bits = 0 ;
ret = gpiotools_get_values ( lfd , & values ) ;
if ( ret < 0 ) {
fprintf ( stderr ,
" Failed to issue GPIO LINE GET VALUES IOCTL (%d) \n " ,
2016-06-02 12:38:33 +03:00
ret ) ;
2020-09-28 03:28:05 +03:00
goto exit_line_close ;
2016-06-02 12:38:33 +03:00
}
fprintf ( stdout , " Monitoring line %d on %s \n " , line , device_name ) ;
2020-09-28 03:28:05 +03:00
fprintf ( stdout , " Initial line value: %d \n " ,
gpiotools_test_bit ( values . bits , 0 ) ) ;
2016-06-02 12:38:33 +03:00
while ( 1 ) {
2020-09-28 03:28:05 +03:00
struct gpio_v2_line_event event ;
2016-06-02 12:38:33 +03:00
2020-09-28 03:28:05 +03:00
ret = read ( lfd , & event , sizeof ( event ) ) ;
2016-06-02 12:38:33 +03:00
if ( ret = = - 1 ) {
if ( errno = = - EAGAIN ) {
fprintf ( stderr , " nothing available \n " ) ;
continue ;
} else {
ret = - errno ;
fprintf ( stderr , " Failed to read event (%d) \n " ,
ret ) ;
break ;
}
}
if ( ret ! = sizeof ( event ) ) {
fprintf ( stderr , " Reading event failed \n " ) ;
ret = - EIO ;
break ;
}
2020-09-28 03:28:05 +03:00
fprintf ( stdout , " GPIO EVENT at %llu on line %d (%d|%d) " ,
event . timestamp_ns , event . offset , event . line_seqno ,
event . seqno ) ;
2016-06-02 12:38:33 +03:00
switch ( event . id ) {
2020-09-28 03:28:05 +03:00
case GPIO_V2_LINE_EVENT_RISING_EDGE :
2016-06-02 12:38:33 +03:00
fprintf ( stdout , " rising edge " ) ;
break ;
2020-09-28 03:28:05 +03:00
case GPIO_V2_LINE_EVENT_FALLING_EDGE :
2016-06-02 12:38:33 +03:00
fprintf ( stdout , " falling edge " ) ;
break ;
default :
fprintf ( stdout , " unknown event " ) ;
}
fprintf ( stdout , " \n " ) ;
i + + ;
if ( i = = loops )
break ;
}
2020-09-28 03:28:05 +03:00
exit_line_close :
if ( close ( lfd ) = = - 1 )
perror ( " Failed to close line file " ) ;
exit_device_close :
if ( close ( cfd ) = = - 1 )
2016-06-02 12:38:33 +03:00
perror ( " Failed to close GPIO character device file " ) ;
2020-07-08 07:16:00 +03:00
exit_free_name :
2016-06-02 12:38:33 +03:00
free ( chrdev_name ) ;
return ret ;
}
void print_usage ( void )
{
fprintf ( stderr , " Usage: gpio-event-mon [options]... \n "
" Listen to events on GPIO lines, 0->1 1->0 \n "
" -n <name> Listen on GPIOs on a named device (must be stated) \n "
" -o <n> Offset to monitor \n "
" -d Set line as open drain \n "
" -s Set line as open source \n "
" -r Listen for rising edges \n "
" -f Listen for falling edges \n "
" [-c <n>] Do <n> loops (optional, infinite loop if not stated) \n "
" -? This helptext \n "
" \n "
" Example: \n "
" gpio-event-mon -n gpiochip0 -o 4 -r -f \n "
) ;
}
2020-09-28 03:28:05 +03:00
# define EDGE_FLAGS \
( GPIO_V2_LINE_FLAG_EDGE_RISING | \
GPIO_V2_LINE_FLAG_EDGE_FALLING )
2016-06-02 12:38:33 +03:00
int main ( int argc , char * * argv )
{
const char * device_name = NULL ;
unsigned int line = - 1 ;
unsigned int loops = 0 ;
2020-09-28 03:28:05 +03:00
struct gpio_v2_line_config config ;
2016-06-02 12:38:33 +03:00
int c ;
2020-09-28 03:28:05 +03:00
memset ( & config , 0 , sizeof ( config ) ) ;
config . flags = GPIO_V2_LINE_FLAG_INPUT ;
2016-06-02 12:38:33 +03:00
while ( ( c = getopt ( argc , argv , " c:n:o:dsrf? " ) ) ! = - 1 ) {
switch ( c ) {
case ' c ' :
loops = strtoul ( optarg , NULL , 10 ) ;
break ;
case ' n ' :
device_name = optarg ;
break ;
case ' o ' :
line = strtoul ( optarg , NULL , 10 ) ;
break ;
case ' d ' :
2020-09-28 03:28:05 +03:00
config . flags | = GPIO_V2_LINE_FLAG_OPEN_DRAIN ;
2016-06-02 12:38:33 +03:00
break ;
case ' s ' :
2020-09-28 03:28:05 +03:00
config . flags | = GPIO_V2_LINE_FLAG_OPEN_SOURCE ;
2016-06-02 12:38:33 +03:00
break ;
case ' r ' :
2020-09-28 03:28:05 +03:00
config . flags | = GPIO_V2_LINE_FLAG_EDGE_RISING ;
2016-06-02 12:38:33 +03:00
break ;
case ' f ' :
2020-09-28 03:28:05 +03:00
config . flags | = GPIO_V2_LINE_FLAG_EDGE_FALLING ;
2016-06-02 12:38:33 +03:00
break ;
case ' ? ' :
print_usage ( ) ;
return - 1 ;
}
}
if ( ! device_name | | line = = - 1 ) {
print_usage ( ) ;
return - 1 ;
}
2020-09-28 03:28:05 +03:00
if ( ! ( config . flags & EDGE_FLAGS ) ) {
2016-06-02 12:38:33 +03:00
printf ( " No flags specified, listening on both rising and "
" falling edges \n " ) ;
2020-09-28 03:28:05 +03:00
config . flags | = EDGE_FLAGS ;
2016-06-02 12:38:33 +03:00
}
2020-09-28 03:28:05 +03:00
return monitor_device ( device_name , line , & config , loops ) ;
2016-06-02 12:38:33 +03:00
}