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:
- 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->triggered = 1; wake_up_interruptible( &gpio->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->irqnum >= 0 ) { free_irq( gpio->irqnum, gpio ); gpio->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, &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->irqnum >= 0 ) break; retval = ns9xxx_config_pin_ext_irq( (unsigned int)gpionum ); if( !retval ) { int irqtype = IRQT_NOEDGE; gpio->irqnum = ns9xxx_get_irq_from_pin( (unsigned int)gpionum ); if( gpio->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->irqnum, irqtype ); init_waitqueue_head( &gpio->wait_q ); gpio->triggered = 0; ns9xxx_clear_eic( gpio->irqnum ); /* start clean... */ if( ( retval = request_irq( gpio->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);
- 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 ) < 0 ) {
close( fd_button );
close( fd_led );
perror( "ioctl: " GPIO_PIN_DEVICE_BUT );
exit( EXIT_FAILURE );
}
if( ioctl( fd_led, GPIO_CONFIG_AS_OUT ) < 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, &inval ) ) < 0 ) {
perror( "ioctl: " GPIO_PIN_DEVICE_BUT );
close( fd_button );
close( fd_led );
exit( EXIT_FAILURE );
}
usleep( 1000 );
} while( !((lastinval == 1 ) && ( inval == 0 )) );
fprintf( stdout, "%s pressed
", BUTTON_LABEL );
outval = outval ? 0 : 1;
if( ( ret_val = ioctl( fd_led, GPIO_WRITE_PIN_VAL, &outval ) ) < 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 *)&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 ) && ( inval == 0 )) );
fprintf( stdout, "%s pressed
", BUTTON_LABEL );
outval = outval ? 0 : 1;
if( ( ret_val = write( fd_led, (char *)&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 & 0x01;
if( ( ret_val = ioctl( fd_led, GPIO_CONFIG_INV_PIN, &outval ) ) < 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, &irqtype ) < 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 *)&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 *)&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;
}