Module gpio.c ( How to schedule interrupts from GPIO (P19) associated with the I2C?)

Hello, everything you told me the last message I did in the time (already I added the application “gpio_test” in the kernel configuration screen that appeared to me to do “make xconfig”), so I’ll attach the files “gpio.c” and “gpio_test” to see if they are equal to yours. Because the application “gpio_test” works well, but the module “gpio.c” doesn’t work well either because of the compilation errors that I told you in the last message (error of libraries …). What do you think of what is happening to me?

Thank you very much LeonidM.

I can not attach the two files, so you show them here:

  1. GPIO.C
    /*
  • gpio.c
  • Copyright (C) 2006 by Digi International Inc.
  • All rights reserved.
  • This program is free software; you can redistribute it and/or modify it
  • under the terms of the GNU General Public License version 2 as published by
  • the Free Software Foundation.
    */

#include
#include
#include
#include
#include
#include
#include

#include /* copy_to_user and friends… /
#include
#include
#include /
processor_is_ns9360() and friends /
#include /
ns9xxx_request_gpio() prototype */
#include
#include
#include

#include “gpio.h”

/* Some constant values /
#define DRV_VERSION “V1.0”
#define DRV_NAME “gpio”
#define NS9360_MAX_GPIOS 72
#define NS9750_MAX_GPIOS 72 /
@TODO check this number */
#define GPIO_MAJOR_NUMBER 250

#if (NS9360_MAX_GPIOS > NS9750_MAX_GPIOS)

define NS9XXX_MAX_GPIOS NS9360_MAX_GPIOS

#else

define NS9XXX_MAX_GPIOS NS9750_MAX_GPIOS

#endif

/* Function prototypes */
static int ns9xxx_gpio_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg );
static unsigned int ns9xxx_gpio_poll( struct file *file, poll_table *wait );
static ssize_t ns9xxx_gpio_write( struct file * file, const char * buf, size_t count, loff_t * ppos );
static ssize_t ns9xxx_gpio_read( struct file * file, char * buf, size_t count, loff_t * ppos );
static int ns9xxx_gpio_open( struct inode * inode, struct file * file );
static int ns9xxx_gpio_release( struct inode * inode, struct file * file );

/* Driver file functions */
static struct file_operations ns9xxx_gpio_fops = {
.owner = THIS_MODULE,
.read = ns9xxx_gpio_read,
.write = ns9xxx_gpio_write,
.ioctl = ns9xxx_gpio_ioctl,
.poll = ns9xxx_gpio_poll,
.open = ns9xxx_gpio_open,
.release = ns9xxx_gpio_release,
};

/* Gpio settings /
struct gpio_conf {
int dev_id; /
minor /
int irqnum; /
irq number assigned /
wait_queue_head_t wait_q; /
A nice place to sleep a bit… /
int triggered; /
Just to avoid race conditions */
};

/* Device structure /
struct gpio_dev {
struct cdev cdev; /
Char device structure /
struct gpio_conf gpio[NS9XXX_MAX_GPIOS]; /
gpio structs */
};

/* GPIO pin list that can be used as interrupts */
static int gpio_to_irq[][3] = {
{ 1, IRQ_EXT0, GPIO_CFG_FUNC_2 },
{ 7, IRQ_EXT1, GPIO_CFG_FUNC_2 },
{ 11, IRQ_EXT2, GPIO_CFG_FUNC_1 },
{ 13, IRQ_EXT0, GPIO_CFG_FUNC_1 },
{ 18, IRQ_EXT3, GPIO_CFG_FUNC_2 },
{ 28, IRQ_EXT1, GPIO_CFG_FUNC_0 },
{ 32, IRQ_EXT2, GPIO_CFG_FUNC_0 },
{ 40, IRQ_EXT3, GPIO_CFG_FUNC_1 },
{ 68, IRQ_EXT0, GPIO_CFG_FUNC_2 },
{ 69, IRQ_EXT1, GPIO_CFG_FUNC_2 }
};

#define PINS_IRQ_CAPABLE (sizeof(gpio_to_irq)/(sizeof(int)*3))

static int ns9xxx_gpio_major = GPIO_MAJOR_NUMBER;
static int ns9xxx_gpio_minor = 0;
static int ns9xxx_gpio_nr_devs;
static struct gpio_dev *gpio_device = NULL;

/***********************************************************************

  • @Function: ns9xxx_get_irq_index
  • @Return: Returns the index of the pin in the gpio_to_irq array
  • @Descr: Searchs in the gpio_to_irq array for a pin and returns the
  •     index. If the gpio is not in the array, returns -1
    

***********************************************************************/
static int ns9xxx_get_irq_index( unsigned int pin )
{
int i;

for( i = 0; i < PINS_IRQ_CAPABLE; i++ ) {
	if( gpio_to_irq[i][0] == ((int)pin ) )
		return i;
}

return -1;

}

/***********************************************************************

  • @Function: ns9xxx_get_irq_from_pin
  • @Return: The external interrupt number asociated with a pin
  • @Descr: Returns the irq number, as defined in irqs.h, associated with
  •     an external interrupt pin.
    

***********************************************************************/
static int ns9xxx_get_irq_from_pin( unsigned int pin )
{
int index = ns9xxx_get_irq_index( pin );

if( index < 0 )
	return NO_IRQ;

return gpio_to_irq[index][1];

}

/***********************************************************************

  • @Function: ns9xxx_config_pin_ext_irq

  • @Return: The value returned by ns9xxx_gpio_cfgpin()

  • @Descr: Configures a gpio pin for external interrupt
    ***********************************************************************/
    static int ns9xxx_config_pin_ext_irq( unsigned int pin )
    {
    int index = ns9xxx_get_irq_index( pin );

    if( index < 0 )
    return -EINVAL;

    return ns9xxx_gpio_cfgpin( pin, gpio_to_irq[index][2] );
    }

/***********************************************************************

  • @Function: ns9xxx_clear_eic
  • @Return: Nothing
  • @Descr: Clear the edge detection flag of the external interrupt.
    ***********************************************************************/
    static inline void ns9xxx_clear_eic( int irqnum )
    {
    SYS_EIC(irqnum - IRQ_EXT0) |= SYS_EIC_CLR;
    SYS_EIC(irqnum - IRQ_EXT0) &= ~SYS_EIC_CLR;
    }

/***********************************************************************

  • @Function: ns9xxx_gpio_irq_handler

  • @Return: IRQ_HANDLED

  • @Descr: GPIO interrupt handler.
    ***********************************************************************/
    static irqreturn_t ns9xxx_gpio_irq_handler( int irq, void *dev_id, struct pt_regs *regs )
    {
    struct gpio_conf *gpio = (struct gpio_conf *)dev_id;

    /* Sanity check /
    if( gpio != NULL) {
    /
    Clear the edge detection flag, even if configured as level irq */
    ns9xxx_clear_eic( gpio->irqnum );

     /* Awake those processes waiting... */
     gpio-&gt;triggered = 1;
     wake_up_interruptible( &amp;gpio-&gt;wait_q );
    

    }

    return IRQ_HANDLED;
    }

/***********************************************************************

  • @Function: ns9xxx_gpio_ioctl

  • @Return: 0 on success, error code otherwise.

  • @Descr: Ioctl system call.
    ***********************************************************************/
    static int ns9xxx_gpio_ioctl( struct inode *inode,
    struct file *file,
    unsigned int cmd,
    unsigned long arg )
    {
    struct gpio_conf *gpio = (struct gpio_conf *)file->private_data;
    int gpionum = MINOR(inode->i_rdev);
    char __user *argp = (char __user *)arg;
    int retval = 0;

    if( _IOC_TYPE(cmd) != GPIO_IOCTL_BASE ) return -ENOTTY;
    if( _IOC_NR(cmd) > GPIO_IOCTL_MAXNR ) return -ENOTTY;

    if (gpionum != gpio->dev_id)
    return -EINVAL;

    switch( cmd ) {
    case GPIO_CONFIG_AS_INP: /* config as input */
    if( gpio->irqnum >= 0 ) {
    free_irq( gpio->irqnum, gpio );
    gpio->irqnum = -1;
    }
    retval = ns9xxx_gpio_cfgpin((unsigned int)gpionum, GPIO_CFG_INPUT);
    break;

     case GPIO_CONFIG_AS_OUT:  /* config as output */
     	if( gpio-&gt;irqnum &gt;= 0 ) {
     		free_irq( gpio-&gt;irqnum, gpio );
     		gpio-&gt;irqnum = -1;
     	}
     	retval = ns9xxx_gpio_cfgpin((unsigned int)gpionum, GPIO_CFG_OUTPUT);
     	break;
    
     case GPIO_CONFIG_INV_PIN:  /* config invert */
     	retval = ns9xxx_gpio_invert((unsigned int)gpionum, *argp);
     	break;
    
     case GPIO_READ_PIN_VAL:  /* read value of the selected pin */
     	retval = ns9xxx_gpio_getpin((unsigned int)gpionum) ? 1 : 0;
     	if (copy_to_user(argp, &amp;retval, sizeof(int)))
     		return -EINVAL;
     	break;
    
     case GPIO_WRITE_PIN_VAL:  /* write value to the selected pin */
     	retval = ns9xxx_gpio_setpin((unsigned int)gpionum, *argp);
     	break;
    
     case GPIO_CONFIG_AS_IRQ:  /* Configure this pin as external interrupt line */
     	if( gpio-&gt;irqnum &gt;= 0 )
     		break;
     	retval = ns9xxx_config_pin_ext_irq( (unsigned int)gpionum );
     	if( !retval ) {
     		int irqtype = IRQT_NOEDGE;
    
     		gpio-&gt;irqnum = ns9xxx_get_irq_from_pin( (unsigned int)gpionum );
     		if( gpio-&gt;irqnum == NO_IRQ )
     			return -EINVAL;
    
     		switch( (ext_irq_type_t)*argp ) {
     			case IRQ_HIGH:		irqtype = IRQT_HIGH;	break;
     			case IRQ_LOW:		irqtype = IRQT_LOW;	break;
     			case IRQ_RISING:	irqtype = IRQT_RISING;	break;
     			case IRQ_FALLING:	irqtype = IRQT_FALLING;	break;
     			default:		return -EINVAL;
     		}
     		set_irq_type( gpio-&gt;irqnum, irqtype );
    
     		init_waitqueue_head( &amp;gpio-&gt;wait_q );
     		gpio-&gt;triggered = 0;
    
     		ns9xxx_clear_eic( gpio-&gt;irqnum ); /* start clean... */
    
     		if( ( retval = request_irq( gpio-&gt;irqnum, ns9xxx_gpio_irq_handler,
     					    SA_SHIRQ, DRV_NAME, gpio ) ) != 0 ) {
     			printk( KERN_ERR "Unable to request irq %d, ret %d
    

", gpio->irqnum, retval );
gpio->irqnum = -1;
return retval;
}
}
break;

	default:	return -ENOTTY;
} /* switch( cmd ) */

return retval;

}

/*******************************************************************************

  • @Function: ns9xxx_gpio_poll

  • @Return:

  • @Descr: poll system call
    *******************************************************************************/
    static unsigned int ns9xxx_gpio_poll( struct file *file, poll_table *wait )
    {
    unsigned int ret_val = 0;
    struct gpio_conf *gpio = (struct gpio_conf *)file->private_data;

    if( file->f_mode & FMODE_WRITE )
    ret_val |= POLLOUT | POLLWRNORM;

    if( file->f_mode & FMODE_READ ) {
    if( gpio->triggered == 1 )
    ret_val |= POLLOUT | POLLRDNORM;
    } else {
    poll_wait( file, &gpio->wait_q, wait );
    }
    return ret_val;
    }

/***********************************************************************

  • @Function: ns9xxx_gpio_write

  • @Return: The number of bytes written or error code.

  • @Descr: write driver function.
    ***********************************************************************/
    static ssize_t ns9xxx_gpio_write( struct file * file, const char * buf, size_t count,
    loff_t * ppos )
    {
    struct gpio_conf *gpio = (struct gpio_conf *)file->private_data;
    int gpionum = MINOR(file->f_dentry->d_inode->i_rdev);
    int ret;
    char outval;

    if ((gpionum != gpio->dev_id) || (count != sizeof(char)))
    return -EINVAL;

    if (((ns9xxx_gpio_getcfg(gpionum)>>(((gpionum) % 8) * 4)) & 0x0b) != GPIO_CFG_OUTPUT)
    return -EIO;

    if (copy_from_user( &outval, buf, sizeof(char)))
    return -EFAULT;

    if ((ret = ns9xxx_gpio_setpin( gpionum, (unsigned int)outval)) != 0)
    return ret;

    return count;
    }

/***********************************************************************

  • @Function: ns9xxx_gpio_read

  • @Return: The number of bytes read or error code.

  • @Descr: read driver functions.
    ***********************************************************************/
    static ssize_t ns9xxx_gpio_read( struct file * file, char * buf, size_t count,
    loff_t * ppos )
    {
    struct gpio_conf *gpio = (struct gpio_conf *)file->private_data;
    int gpionum = MINOR(file->f_dentry->d_inode->i_rdev);
    int ret;

    if ((gpionum != gpio->dev_id) || (count != sizeof(char)))
    return -EINVAL;

    /* Check if configured for interrupt operation… /
    if( gpio->irqnum >= 0 ) {
    /
    Wait for data */
    if( !(file->f_flags & O_NONBLOCK) ) {
    wait_event_interruptible( gpio->wait_q, gpio->triggered != 0 );
    if( signal_pending( current ) )
    return -ERESTARTSYS;
    }
    gpio->triggered = 0;
    }

    ret = ns9xxx_gpio_getpin((unsigned int)gpionum) ? 1 : 0;

    if (copy_to_user(buf, (char *)&ret, sizeof(char)))
    return -EFAULT;

    return count;
    }

/***********************************************************************

  • @Function: ns9xxx_gpio_open

  • @Return: 0 on success, error code otherwise.

  • @Descr: open driver functions.
    ***********************************************************************/
    static int ns9xxx_gpio_open( struct inode * inode, struct file * file )
    {
    struct gpio_dev *dev;
    int gpionum = MINOR(inode->i_rdev);
    int ret;

    dev = container_of( inode->i_cdev, struct gpio_dev, cdev );

    /* Sanity checks */
    if (gpionum < 0 || gpionum >= ns9xxx_gpio_nr_devs)
    return -ENODEV;
    if (gpionum != dev->gpio[gpionum].dev_id)
    return -EINVAL;

    ret = ns9xxx_request_gpio( gpionum, DRV_NAME );
    if (ret != 0)
    return ret;

    file->private_data = &dev->gpio[gpionum];

    return 0;
    }

/***********************************************************************

  • @Function: ns9xxx_gpio_release

  • @Return: 0 on success, error code otherwise.

  • @Descr: close driver functions.
    ***********************************************************************/
    static int ns9xxx_gpio_release( struct inode * inode, struct file * file )
    {
    struct gpio_conf *gpio = (struct gpio_conf *)file->private_data;
    int gpionum = MINOR(inode->i_rdev);

    if (gpionum != gpio->dev_id)
    return -EINVAL;

    if( gpio->irqnum >= 0 ) {
    free_irq( gpio->irqnum, gpio );
    gpio->irqnum = -1;
    }

    ns9xxx_release_gpio( gpionum );

    return 0;
    }

/***********************************************************************

  • @Function: ns9xxx_gpio_exit

  • @Return: Nothing.

  • @Descr: Module unload function.
    ***********************************************************************/
    static void ns9xxx_gpio_exit( void )
    {
    int i;
    dev_t devno = MKDEV( ns9xxx_gpio_major, ns9xxx_gpio_minor );

    if (gpio_device) {
    for( i = 0; i < ns9xxx_gpio_nr_devs; i++ ) {
    if( gpio_device->gpio[i].irqnum != -1 )
    free_irq( gpio_device->gpio[i].irqnum, &gpio_device->gpio[i] );
    cdev_del( &gpio_device->cdev );
    }
    kfree( gpio_device );
    }
    unregister_chrdev_region( devno, ns9xxx_gpio_nr_devs );
    }

/***********************************************************************

  • @Function: ns9xxx_gpio_init

  • @Return: 0 on success, error code otherwise.

  • @Descr: Module load function.
    ***********************************************************************/
    static int ns9xxx_gpio_init( void )
    {
    int ret, i;
    dev_t dev;

    if (processor_is_ns9360())
    ns9xxx_gpio_nr_devs = NS9360_MAX_GPIOS + 1;
    /* else if (processor_is_ns9750)
    ns9xxx_gpio_nr_devs = NS9750_MAX_GPIOS;*/
    else {
    printk( KERN_WARNING DRV_NAME ": this driver only works with NS9360 or NS9750
    " );
    return ENODEV;
    }

    if (ns9xxx_gpio_major) {
    dev = MKDEV( ns9xxx_gpio_major, ns9xxx_gpio_minor );
    ret = register_chrdev_region( dev, ns9xxx_gpio_nr_devs, DRV_NAME );
    } else {
    ret = alloc_chrdev_region( &dev, ns9xxx_gpio_minor, ns9xxx_gpio_nr_devs, DRV_NAME );
    ns9xxx_gpio_major = MAJOR( dev );
    }

    if (ret < 0) {
    printk( KERN_WARNING DRV_NAME ": can’t get major %d
    ", ns9xxx_gpio_major );
    return ret;
    }

    /* Allocate memory for the devices */
    gpio_device = kmalloc( sizeof( struct gpio_dev ), GFP_KERNEL );
    if (!gpio_device) {
    ret = -ENOMEM;
    goto fail;
    }

    memset( gpio_device, 0, sizeof( struct gpio_dev ) );

    cdev_init( &gpio_device->cdev, &ns9xxx_gpio_fops );
    gpio_device->cdev.owner = THIS_MODULE;
    gpio_device->cdev.ops = &ns9xxx_gpio_fops;
    if (cdev_add( &gpio_device->cdev, dev, ns9xxx_gpio_nr_devs ))
    printk( KERN_NOTICE DRV_NAME ": Error adding cdev
    " );

    /* Initialize each device */
    for( i = 0; i < ns9xxx_gpio_nr_devs; i++ ) {
    gpio_device->gpio[i].dev_id = i;
    gpio_device->gpio[i].irqnum = -1;
    }

    /* All ok… */
    printk( KERN_INFO DRV_NAME ": NS9XXX GPIO driver " DRV_VERSION "
    " );
    return 0;

fail:
ns9xxx_gpio_exit();
return ret;
}

MODULE_AUTHOR( “Digi International Inc.” );
MODULE_DESCRIPTION( “GPIO driver for the NS9XXX processor” );
MODULE_LICENSE( “GPL” );

module_init(ns9xxx_gpio_init);
module_exit(ns9xxx_gpio_exit);


  1. GPIO_TEST.C

/*

  • gpio_test.c
  • Copyright (C) 2006 by Digi International Inc.
  • All rights reserved.
  • This program is free software; you can redistribute it and/or modify it
  • under the terms of the GNU General Public License version 2 as published by
  • the Free Software Foundation.
    */

#include
#include
#include
#include
#include
#include

#include “gpio.h”

#define PROGRAM “gpio_test”
#define VERSION “$Revision: 1.0”
#define BUTTON_LABEL “BUTTON2”
#define LED_LABEL “LED2”

#ifdef CONFIG_DEL_CC9P9360JS

define GPIO_PIN_DEVICE_BUT “/dev/gpio/68”

define GPIO_PIN_DEVICE_LED “/dev/gpio/66”

#else

define GPIO_PIN_DEVICE_BUT “/dev/gpio/69”

define GPIO_PIN_DEVICE_LED “/dev/gpio/49”

#endif /* CONFIG_DEL_CC9P9360JS */

/***********************************************************************

  • @Function: show_banner
  • @Return: Nothing
  • @Descr: shows some simple information.
    ***********************************************************************/
    static void show_banner( void )
    {
    fprintf( stdout, "%s %s Copyright Digi International Inc.

"
"Test the GPIOs using a simple button and a led. The gpio driver has to be loaded
"
"prior to run this test and the device nodes %s and %s
"
"has to be created.

",
PROGRAM, VERSION, GPIO_PIN_DEVICE_LED, GPIO_PIN_DEVICE_BUT );
}

/***********************************************************************

  • @Function: main

  • @Return: EXIT_SUCCESS or EXIT_FAILURE

  • @Descr: main applications function
    **********************************************************************/
    int main( int argc, char
    argv[] )
    {
    int inval = 1, lastinval, outval = 0, loops;
    int ret_val;
    int fd_button;
    int fd_led;
    ext_irq_type_t irqtype = IRQ_FALLING;

    show_banner();

    if( ( fd_button = open( GPIO_PIN_DEVICE_BUT, O_RDWR ) ) < 0 ) {
    perror( "open: " GPIO_PIN_DEVICE_BUT );
    exit( EXIT_FAILURE );
    }
    if( ( fd_led = open( GPIO_PIN_DEVICE_LED, O_RDWR ) ) < 0 ) {
    close( fd_button );
    perror( "open: " GPIO_PIN_DEVICE_LED );
    exit( EXIT_FAILURE );
    }

    fprintf( stdout, "Configuring %s as input and %s as output
    "
    "Press the button %s 10 times and check the led %s

",
GPIO_PIN_DEVICE_BUT, GPIO_PIN_DEVICE_LED, BUTTON_LABEL, LED_LABEL );

if( ioctl( fd_button, GPIO_CONFIG_AS_INP ) &lt; 0 ) {
	close( fd_button );
	close( fd_led );
	perror( "ioctl: " GPIO_PIN_DEVICE_BUT );
	exit( EXIT_FAILURE );
}

if( ioctl( fd_led, GPIO_CONFIG_AS_OUT ) &lt; 0 ) {
	close( fd_button );
	close( fd_led );
	perror( "ioctl: " GPIO_PIN_DEVICE_LED );
	exit( EXIT_FAILURE );
}

fprintf( stdout, "Using ioctl system call to control the GPIOs

" );

loops = 10;
while( loops ) {

	do {
		lastinval = inval;
		if( ( ret_val = ioctl( fd_button, GPIO_READ_PIN_VAL, &amp;inval ) ) &lt; 0 ) {
			perror( "ioctl: " GPIO_PIN_DEVICE_BUT );
			close( fd_button );
			close( fd_led );
			exit( EXIT_FAILURE );
		}
		usleep( 1000 );
	} while( !((lastinval == 1 ) &amp;&amp; ( inval == 0 )) );

	fprintf( stdout, "%s pressed

", BUTTON_LABEL );

	outval = outval ? 0 : 1;

	if( ( ret_val = ioctl( fd_led, GPIO_WRITE_PIN_VAL, &amp;outval ) ) &lt; 0 ) {
		perror( "ioctl: " GPIO_PIN_DEVICE_LED );
		close( fd_button );
		close( fd_led );
	        exit( EXIT_FAILURE );
	}
	loops--;
}

fprintf( stdout, "Using read/write system calls to control the GPIOs

"
"Press the button %s 10 times and check the led %s

", BUTTON_LABEL, LED_LABEL );

loops = 10;
while( loops ) {

	do {
		lastinval = inval;
		if( ( ret_val = read( fd_button, (char *)&amp;inval, sizeof( char ) ) ) != sizeof( char ) ) {
			perror( "read: " GPIO_PIN_DEVICE_BUT );
			close( fd_button );
			close( fd_led );
			exit( EXIT_FAILURE );
		}
		usleep( 1000 );
	} while( !((lastinval == 1 ) &amp;&amp; ( inval == 0 )) );

	fprintf( stdout, "%s pressed

", BUTTON_LABEL );

	outval = outval ? 0 : 1;

	if( ( ret_val = write( fd_led, (char *)&amp;outval, sizeof( char) ) ) != sizeof( char ) ) {
		perror( "write: " GPIO_PIN_DEVICE_LED );
		close( fd_button );
		close( fd_led );
	        exit( EXIT_FAILURE );
	}
	loops--;
}

fprintf( stdout, "Checking ioctl GPIO_CONFIG_INV_PIN

"
"Check the led %s

", LED_LABEL );

loops = 10;
while( loops ) {

	fprintf( stdout, "Inverting %s GPIO

", LED_LABEL );

	outval = loops &amp; 0x01;

	if( ( ret_val = ioctl( fd_led, GPIO_CONFIG_INV_PIN, &amp;outval ) ) &lt; 0 ) {
		perror( "ioctl: " GPIO_PIN_DEVICE_LED );
		close( fd_button );
		close( fd_led );
	        exit( EXIT_FAILURE );
	}
	sleep( 1 );
	loops--;
}

fprintf( stdout, "Configuring %s as IRQ input

"
"Press the button %s 10 times and check the led %s

",
GPIO_PIN_DEVICE_BUT, BUTTON_LABEL, LED_LABEL );

if( ioctl( fd_button, GPIO_CONFIG_AS_IRQ, &amp;irqtype ) &lt; 0 ) {
	close( fd_button );
	close( fd_led );
	perror( "ioctl " GPIO_PIN_DEVICE_BUT );
	exit( EXIT_FAILURE );
}

loops = 10;
while( loops ) {

	if( ( ret_val = read( fd_button, (char *)&amp;inval, sizeof( char ) ) ) != sizeof( char ) ) {
		perror( "read: " GPIO_PIN_DEVICE_BUT );
		close( fd_button );
		close( fd_led );
		exit( EXIT_FAILURE );
	}

	fprintf( stdout, "%s pressed

", BUTTON_LABEL );

	outval = outval ? 0 : 1;

	if( ( ret_val = write( fd_led, (char *)&amp;outval, sizeof( char) ) ) != 1 ) {
		perror( "write: " GPIO_PIN_DEVICE_LED );
		close( fd_button );
		close( fd_led );
	        exit( EXIT_FAILURE );
	}
	loops--;
}

fprintf( stdout, "

Test completed
" );

close( fd_button );
close( fd_led );

return 0;

}