2007-02-11 18:41:31 +03:00
# include <linux/module.h>
# include <linux/interrupt.h>
2007-07-27 17:24:33 +04:00
# include <linux/device.h>
2008-04-29 11:59:25 +04:00
# include <linux/gfp.h>
2007-02-11 18:41:31 +03:00
/*
* Device resource management aware IRQ request / free implementation .
*/
struct irq_devres {
unsigned int irq ;
void * dev_id ;
} ;
static void devm_irq_release ( struct device * dev , void * res )
{
struct irq_devres * this = res ;
free_irq ( this - > irq , this - > dev_id ) ;
}
static int devm_irq_match ( struct device * dev , void * res , void * data )
{
struct irq_devres * this = res , * match = data ;
return this - > irq = = match - > irq & & this - > dev_id = = match - > dev_id ;
}
/**
2009-03-23 20:28:16 +03:00
* devm_request_threaded_irq - allocate an interrupt line for a managed device
2007-02-11 18:41:31 +03:00
* @ dev : device to request interrupt for
* @ irq : Interrupt line to allocate
* @ handler : Function to be called when the IRQ occurs
2009-03-23 20:28:16 +03:00
* @ thread_fn : function to be called in a threaded interrupt context . NULL
* for devices which handle everything in @ handler
2007-02-11 18:41:31 +03:00
* @ irqflags : Interrupt type flags
* @ devname : An ascii name for the claiming device
* @ dev_id : A cookie passed back to the handler function
*
* Except for the extra @ dev argument , this function takes the
* same arguments and performs the same function as
2014-07-01 23:47:35 +04:00
* request_threaded_irq ( ) . IRQs requested with this function will be
2007-02-11 18:41:31 +03:00
* automatically freed on driver detach .
*
* If an IRQ allocated with this function needs to be freed
2010-02-11 17:04:36 +03:00
* separately , devm_free_irq ( ) must be used .
2007-02-11 18:41:31 +03:00
*/
2009-03-23 20:28:16 +03:00
int devm_request_threaded_irq ( struct device * dev , unsigned int irq ,
irq_handler_t handler , irq_handler_t thread_fn ,
unsigned long irqflags , const char * devname ,
void * dev_id )
2007-02-11 18:41:31 +03:00
{
struct irq_devres * dr ;
int rc ;
dr = devres_alloc ( devm_irq_release , sizeof ( struct irq_devres ) ,
GFP_KERNEL ) ;
if ( ! dr )
return - ENOMEM ;
2009-03-23 20:28:16 +03:00
rc = request_threaded_irq ( irq , handler , thread_fn , irqflags , devname ,
dev_id ) ;
2007-02-11 18:41:31 +03:00
if ( rc ) {
2007-04-07 09:59:41 +04:00
devres_free ( dr ) ;
2007-02-11 18:41:31 +03:00
return rc ;
}
dr - > irq = irq ;
dr - > dev_id = dev_id ;
devres_add ( dev , dr ) ;
return 0 ;
}
2009-03-23 20:28:16 +03:00
EXPORT_SYMBOL ( devm_request_threaded_irq ) ;
2007-02-11 18:41:31 +03:00
2014-01-03 04:37:32 +04:00
/**
* devm_request_any_context_irq - allocate an interrupt line for a managed device
* @ dev : device to request interrupt for
* @ irq : Interrupt line to allocate
* @ handler : Function to be called when the IRQ occurs
* @ thread_fn : function to be called in a threaded interrupt context . NULL
* for devices which handle everything in @ handler
* @ irqflags : Interrupt type flags
* @ devname : An ascii name for the claiming device
* @ dev_id : A cookie passed back to the handler function
*
* Except for the extra @ dev argument , this function takes the
* same arguments and performs the same function as
* request_any_context_irq ( ) . IRQs requested with this function will be
* automatically freed on driver detach .
*
* If an IRQ allocated with this function needs to be freed
* separately , devm_free_irq ( ) must be used .
*/
int devm_request_any_context_irq ( struct device * dev , unsigned int irq ,
irq_handler_t handler , unsigned long irqflags ,
const char * devname , void * dev_id )
{
struct irq_devres * dr ;
int rc ;
dr = devres_alloc ( devm_irq_release , sizeof ( struct irq_devres ) ,
GFP_KERNEL ) ;
if ( ! dr )
return - ENOMEM ;
rc = request_any_context_irq ( irq , handler , irqflags , devname , dev_id ) ;
2015-05-11 12:02:58 +03:00
if ( rc < 0 ) {
2014-01-03 04:37:32 +04:00
devres_free ( dr ) ;
return rc ;
}
dr - > irq = irq ;
dr - > dev_id = dev_id ;
devres_add ( dev , dr ) ;
2015-05-11 12:02:58 +03:00
return rc ;
2014-01-03 04:37:32 +04:00
}
EXPORT_SYMBOL ( devm_request_any_context_irq ) ;
2007-02-11 18:41:31 +03:00
/**
* devm_free_irq - free an interrupt
* @ dev : device to free interrupt for
* @ irq : Interrupt line to free
* @ dev_id : Device identity to free
*
* Except for the extra @ dev argument , this function takes the
* same arguments and performs the same function as free_irq ( ) .
* This function instead of free_irq ( ) should be used to manually
2010-02-02 09:54:51 +03:00
* free IRQs allocated with devm_request_irq ( ) .
2007-02-11 18:41:31 +03:00
*/
void devm_free_irq ( struct device * dev , unsigned int irq , void * dev_id )
{
struct irq_devres match_data = { irq , dev_id } ;
WARN_ON ( devres_destroy ( dev , devm_irq_release , devm_irq_match ,
& match_data ) ) ;
2011-07-26 04:12:59 +04:00
free_irq ( irq , dev_id ) ;
2007-02-11 18:41:31 +03:00
}
EXPORT_SYMBOL ( devm_free_irq ) ;