Hi,

This is a general linux question so hopefully so you hopefully you don't mind 
me posting it.  I have a trigger source that is hooked up to GPIO1; it triggers 
every 8ms.  How do I write a user space interrupt handler that "wakes" up every 
time the trigger occurs?  

This is how I currently implement it and I'm not sure if it's efficient; I'm 
missing some interrupt triggers some time.

I wrote a kernel module that installs a falling-edge-trigger interrupt handler 
to GPIO1 and communicates with the user application via a character device 
(/dev/gpio1irq).  The user application opens /dev/gpio1irq and loops blocking 
on a read; when the read returns, it processes some stuff, then blocks on the 
read again, and so on.  In the kernel module, the read (called from user space) 
blocks waiting for a semaphore.  When the interrupt occurs, the module 
interrupt handler gives the semaphore,  hence unblocking the read from the user 
application, allowing it to process stuff before it blocks on the read again, 
waiting for the next trigger.  Can some please provide some advice or a better 
way of implementing a user space interrupt handler?  Thanks.

Regards,
Andy



Here's a snippet of my code.

// kernel module

#define GPIO1IRQ_MAJOR     240
#define GPIO1IRQ_DEV_NAME  "gpio1irq"


/* ---- Private Variables ------------------------------------------------ */

static char gBanner[] __initdata = KERN_INFO "GPIO1 IRQ Driver";

static  int         gDebugTrace = 0;
static  int         gUserIrq = DAVINCI_GPIO_IRQ(1);
static  int         gIrq = 0;

DECLARE_MUTEX(gpio1irq_sem);


/* ---- Private Function Prototypes -------------------------------------- */
/* ---- Functions -------------------------------------------------------- */

/****************************************************************************
*
*  gpio1irq_interrupt
*
****************************************************************************/
static irqreturn_t gpio1irq_interrupt( int irq, void *dev_id, struct pt_regs 
*regs )
{
    (void)irq;
    (void)dev_id;
    (void)regs;

    up(&gpio1irq_sem);

    return IRQ_HANDLED;

} // gpio1irq_interrupt


/****************************************************************************
*
*   gpio1irq_ioctl
*
*   Called to process ioctl requests
*
*****************************************************************************/
int gpio1irq_ioctl( struct inode *inode, struct file *file, unsigned int cmd,
                    unsigned long arg )
{
    (void)inode;
    (void)file;
    (void)cmd;
    (void)arg;

    return 0;
} // gpio1irq_ioctl


/****************************************************************************
*
*  gpio1irq_open
*
****************************************************************************/
static int gpio1irq_open( struct inode *inode, struct file *file )
{
    DEBUG( Trace, "gpio1irq_open called, major = %d, minor = %d\n", 
           MAJOR( inode->i_rdev ),  MINOR( inode->i_rdev ));

    return 0;
} // gpio1irq_open


/****************************************************************************
*
*  gpio1irq_read
*
****************************************************************************/
static ssize_t gpio1irq_read( struct file *file, char *buffer, size_t count,
                              loff_t *ppos )
{
    int rc;

    if ( gIrq == 0 )
    {
        if (( gUserIrq >= 0 ) && ( gUserIrq < NR_IRQS ))
        {
            // Register an interrupt handler for the gpio1irq
            gIrq = gUserIrq;

            if (( rc = request_irq( gIrq, (irq_handler_t)gpio1irq_interrupt, 
                    IRQF_DISABLED | IRQF_TRIGGER_RISING, "gpio1irq", NULL )) != 
0 )
            {
                return rc;
            }
        }
    }

    down(&gpio1irq_sem);

    return 1;
} // gpio1irq_read


/****************************************************************************
*
*  gpio1irq_write
*
****************************************************************************/
static int gpio1irq_write(struct file *file, const char *buffer, size_t count,
                          loff_t * ppos)
{
    (void)file;
    (void)buffer;
    (void)count;
    (void)ppos;

    return 1;
}


/****************************************************************************
*
*  gpio1irq_release
*
****************************************************************************/
static int gpio1irq_release( struct inode *inode, struct file *file )
{
    DEBUG( Trace, "gpio1irq_release called\n" );

    if ( gIrq != 0 )
    {
        free_irq( gIrq, NULL );
        gIrq = 0;
    }

    return 0;
} // gpio1irq_release


/****************************************************************************
*
*   File Operations (these are the device driver entry points)
*
****************************************************************************/
struct file_operations gpio1irq_fops =
{
    owner:      THIS_MODULE,
    ioctl:      gpio1irq_ioctl,
    open:       gpio1irq_open,
    release:    gpio1irq_release,
    write:      gpio1irq_write,
    read:       gpio1irq_read,
};


/****************************************************************************
*
*  gpio1irq_init
*
*     Called to perform module initialization when the module is loaded
*
****************************************************************************/
static int __init gpio1irq_init( void )
{
    int result;

    DEBUG( Trace, "gpio1irq_init called\n" );

    printk( gBanner );
    /* Registering device */
    result = register_chrdev(GPIO1IRQ_MAJOR, "gpio1irq", &gpio1irq_fops);
    if (result < 0) {
        printk("<1>memory: cannot obtain major number %d\n", GPIO1IRQ_MAJOR);
        return result;
    }
 
    return 0;
} // gpio1irq_init


/****************************************************************************
*
*  gpio1irq_exit
*
*       Called to perform module cleanup when the module is unloaded.
*
****************************************************************************/
static void __exit gpio1irq_exit( void )
{
    DEBUG( Trace, "gpio1irq_exit called\n" );

    /* Freeing the major number */
    unregister_chrdev(GPIO1IRQ_MAJOR, "gpio1irq");

} // gpio1irq_exit

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

module_init(gpio1irq_init);
module_exit(gpio1irq_exit);




// user application code
int main( int argc, char **argv )
{
    int fd;

    if (( fd = open( "/dev/gpio1irq", O_RDONLY )) < 0 )
    {
        perror( "Unable to open /dev/gpio1irq" );
        exit( 1 );
    }

    while ( 1 )
    {
        read( fd, data, 1 );
        
        // process stuff
    }

    close( fd );
    exit( 0 );
    return 0;

} 



_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to