2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-04-26 10:47:09 +02:00
/*
* gpio - hammer - example swiss army knife to shake GPIO lines on a system
*
* Copyright ( C ) 2016 Linus Walleij
*
* Usage :
* gpio - hammer - n < device - name > - o < offset1 > - o < offset2 >
*/
# 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>
2016-10-14 10:48:26 +08:00
# include "gpio-utils.h"
2016-04-26 10:47:09 +02:00
2020-09-28 08:28:03 +08:00
int hammer_device ( const char * device_name , unsigned int * lines , int num_lines ,
2016-04-26 10:47:09 +02:00
unsigned int loops )
{
2020-09-28 08:28:04 +08:00
struct gpio_v2_line_values values ;
struct gpio_v2_line_config config ;
2016-04-26 10:47:09 +02:00
char swirr [ ] = " - \\ |/ " ;
int fd ;
int ret ;
int i , j ;
unsigned int iteration = 0 ;
2020-09-28 08:28:04 +08:00
memset ( & config , 0 , sizeof ( config ) ) ;
config . flags = GPIO_V2_LINE_FLAG_OUTPUT ;
ret = gpiotools_request_line ( device_name , lines , num_lines ,
& config , " gpio-hammer " ) ;
2016-04-26 10:47:09 +02:00
if ( ret < 0 )
2016-10-14 10:48:26 +08:00
goto exit_error ;
else
fd = ret ;
2016-04-26 10:47:09 +02:00
2020-09-28 08:28:04 +08:00
values . mask = 0 ;
values . bits = 0 ;
for ( i = 0 ; i < num_lines ; i + + )
gpiotools_set_bit ( & values . mask , i ) ;
ret = gpiotools_get_values ( fd , & values ) ;
2016-10-14 10:48:26 +08:00
if ( ret < 0 )
2016-04-26 10:47:09 +02:00
goto exit_close_error ;
fprintf ( stdout , " Hammer lines [ " ) ;
2020-09-28 08:28:03 +08:00
for ( i = 0 ; i < num_lines ; i + + ) {
2016-04-26 10:47:09 +02:00
fprintf ( stdout , " %d " , lines [ i ] ) ;
2020-09-28 08:28:03 +08:00
if ( i ! = ( num_lines - 1 ) )
2016-04-26 10:47:09 +02:00
fprintf ( stdout , " , " ) ;
}
fprintf ( stdout , " ] on %s, initial states: [ " , device_name ) ;
2020-09-28 08:28:03 +08:00
for ( i = 0 ; i < num_lines ; i + + ) {
2020-09-28 08:28:04 +08:00
fprintf ( stdout , " %d " , gpiotools_test_bit ( values . bits , i ) ) ;
2020-09-28 08:28:03 +08:00
if ( i ! = ( num_lines - 1 ) )
2016-04-26 10:47:09 +02:00
fprintf ( stdout , " , " ) ;
}
fprintf ( stdout , " ] \n " ) ;
/* Hammertime! */
j = 0 ;
while ( 1 ) {
/* Invert all lines so we blink */
2020-09-28 08:28:03 +08:00
for ( i = 0 ; i < num_lines ; i + + )
2020-09-28 08:28:04 +08:00
gpiotools_change_bit ( & values . bits , i ) ;
2016-04-26 10:47:09 +02:00
2020-09-28 08:28:04 +08:00
ret = gpiotools_set_values ( fd , & values ) ;
2016-10-14 10:48:26 +08:00
if ( ret < 0 )
2016-04-26 10:47:09 +02:00
goto exit_close_error ;
2016-10-14 10:48:26 +08:00
2016-04-26 10:47:09 +02:00
/* Re-read values to get status */
2020-09-28 08:28:04 +08:00
ret = gpiotools_get_values ( fd , & values ) ;
2016-10-14 10:48:26 +08:00
if ( ret < 0 )
2016-04-26 10:47:09 +02:00
goto exit_close_error ;
fprintf ( stdout , " [%c] " , swirr [ j ] ) ;
j + + ;
2020-03-16 20:50:48 +01:00
if ( j = = sizeof ( swirr ) - 1 )
2016-04-26 10:47:09 +02:00
j = 0 ;
fprintf ( stdout , " [ " ) ;
2020-09-28 08:28:03 +08:00
for ( i = 0 ; i < num_lines ; i + + ) {
2020-09-28 08:28:04 +08:00
fprintf ( stdout , " %d: %d " , lines [ i ] ,
gpiotools_test_bit ( values . bits , i ) ) ;
2020-09-28 08:28:03 +08:00
if ( i ! = ( num_lines - 1 ) )
2016-04-26 10:47:09 +02:00
fprintf ( stdout , " , " ) ;
}
fprintf ( stdout , " ] \r " ) ;
fflush ( stdout ) ;
sleep ( 1 ) ;
iteration + + ;
if ( loops & & iteration = = loops )
break ;
}
fprintf ( stdout , " \n " ) ;
ret = 0 ;
exit_close_error :
2020-09-28 08:28:04 +08:00
gpiotools_release_line ( fd ) ;
2016-10-14 10:48:26 +08:00
exit_error :
2016-04-26 10:47:09 +02:00
return ret ;
}
void print_usage ( void )
{
fprintf ( stderr , " Usage: gpio-hammer [options]... \n "
" Hammer GPIO lines, 0->1->0->1... \n "
" -n <name> Hammer GPIOs on a named device (must be stated) \n "
" -o <n> Offset[s] to hammer, at least one, several can be stated \n "
" [-c <n>] Do <n> loops (optional, infinite loop if not stated) \n "
" -? This helptext \n "
" \n "
" Example: \n "
" gpio-hammer -n gpiochip0 -o 4 \n "
) ;
}
int main ( int argc , char * * argv )
{
const char * device_name = NULL ;
unsigned int lines [ GPIOHANDLES_MAX ] ;
unsigned int loops = 0 ;
2020-09-28 08:28:03 +08:00
int num_lines ;
2016-04-26 10:47:09 +02:00
int c ;
int i ;
i = 0 ;
while ( ( c = getopt ( argc , argv , " c:n:o:? " ) ) ! = - 1 ) {
switch ( c ) {
case ' c ' :
loops = strtoul ( optarg , NULL , 10 ) ;
break ;
case ' n ' :
device_name = optarg ;
break ;
case ' o ' :
2020-03-12 15:50:21 +01:00
/*
* Avoid overflow . Do not immediately error , we want to
* be able to accurately report on the amount of times
* ' - o ' was given to give an accurate error message
*/
if ( i < GPIOHANDLES_MAX )
lines [ i ] = strtoul ( optarg , NULL , 10 ) ;
2016-04-26 10:47:09 +02:00
i + + ;
break ;
case ' ? ' :
print_usage ( ) ;
return - 1 ;
}
}
2020-03-12 15:50:21 +01:00
if ( i > = GPIOHANDLES_MAX ) {
fprintf ( stderr ,
2020-03-16 09:23:40 +00:00
" Only %d occurrences of '-o' are allowed, %d were found \n " ,
2020-03-12 15:50:21 +01:00
GPIOHANDLES_MAX , i + 1 ) ;
return - 1 ;
}
2020-09-28 08:28:03 +08:00
num_lines = i ;
2016-04-26 10:47:09 +02:00
2020-09-28 08:28:03 +08:00
if ( ! device_name | | ! num_lines ) {
2016-04-26 10:47:09 +02:00
print_usage ( ) ;
return - 1 ;
}
2020-09-28 08:28:03 +08:00
return hammer_device ( device_name , lines , num_lines , loops ) ;
2016-04-26 10:47:09 +02:00
}