diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/irq/Makefile | 2 | ||||
-rw-r--r-- | kernel/irq/devres.c | 88 | ||||
-rw-r--r-- | kernel/irq/manage.c | 86 |
3 files changed, 89 insertions, 87 deletions
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 1dab0ac3f797..681c52dbfe22 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile @@ -1,5 +1,5 @@ -obj-y := handle.o manage.o spurious.o resend.o chip.o +obj-y := handle.o manage.o spurious.o resend.o chip.o devres.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c new file mode 100644 index 000000000000..85a430da0fb6 --- /dev/null +++ b/kernel/irq/devres.c @@ -0,0 +1,88 @@ +#include <linux/module.h> +#include <linux/interrupt.h> + +/* + * 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; +} + +/** + * devm_request_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 + * @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_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, dev_free_irq() must be used. + */ +int devm_request_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_irq(irq, handler, irqflags, devname, dev_id); + if (rc) { + kfree(dr); + return rc; + } + + dr->irq = irq; + dr->dev_id = dev_id; + devres_add(dev, dr); + + return 0; +} +EXPORT_SYMBOL(devm_request_irq); + +/** + * 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 + * free IRQs allocated with dev_request_irq(). + */ +void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) +{ + struct irq_devres match_data = { irq, dev_id }; + + free_irq(irq, dev_id); + WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, + &match_data)); +} +EXPORT_SYMBOL(devm_free_irq); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index c4b7ed1cebf7..8b961adc3bd2 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -482,89 +482,3 @@ int request_irq(unsigned int irq, irq_handler_t handler, return retval; } EXPORT_SYMBOL(request_irq); - -/* - * 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; -} - -/** - * devm_request_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 - * @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_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, dev_free_irq() must be used. - */ -int devm_request_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_irq(irq, handler, irqflags, devname, dev_id); - if (rc) { - kfree(dr); - return rc; - } - - dr->irq = irq; - dr->dev_id = dev_id; - devres_add(dev, dr); - - return 0; -} -EXPORT_SYMBOL(devm_request_irq); - -/** - * 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 - * free IRQs allocated with dev_request_irq(). - */ -void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) -{ - struct irq_devres match_data = { irq, dev_id }; - - free_irq(irq, dev_id); - WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, - &match_data)); -} -EXPORT_SYMBOL(devm_free_irq); |