1 #include <linux/module.h> 2 #include <linux/interrupt.h> 3 #include <linux/device.h> 4 #include <linux/gfp.h> 5 6 /* 7 * Device resource management aware IRQ request/free implementation. 8 */ 9 struct irq_devres { 10 unsigned int irq; 11 void *dev_id; 12 }; 13 14 static void devm_irq_release(struct device *dev, void *res) 15 { 16 struct irq_devres *this = res; 17 18 free_irq(this->irq, this->dev_id); 19 } 20 21 static int devm_irq_match(struct device *dev, void *res, void *data) 22 { 23 struct irq_devres *this = res, *match = data; 24 25 return this->irq == match->irq && this->dev_id == match->dev_id; 26 } 27 28 /** 29 * devm_request_threaded_irq - allocate an interrupt line for a managed device 30 * @dev: device to request interrupt for 31 * @irq: Interrupt line to allocate 32 * @handler: Function to be called when the IRQ occurs 33 * @thread_fn: function to be called in a threaded interrupt context. NULL 34 * for devices which handle everything in @handler 35 * @irqflags: Interrupt type flags 36 * @devname: An ascii name for the claiming device 37 * @dev_id: A cookie passed back to the handler function 38 * 39 * Except for the extra @dev argument, this function takes the 40 * same arguments and performs the same function as 41 * request_threaded_irq(). IRQs requested with this function will be 42 * automatically freed on driver detach. 43 * 44 * If an IRQ allocated with this function needs to be freed 45 * separately, devm_free_irq() must be used. 46 */ 47 int devm_request_threaded_irq(struct device *dev, unsigned int irq, 48 irq_handler_t handler, irq_handler_t thread_fn, 49 unsigned long irqflags, const char *devname, 50 void *dev_id) 51 { 52 struct irq_devres *dr; 53 int rc; 54 55 dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), 56 GFP_KERNEL); 57 if (!dr) 58 return -ENOMEM; 59 60 rc = request_threaded_irq(irq, handler, thread_fn, irqflags, devname, 61 dev_id); 62 if (rc) { 63 devres_free(dr); 64 return rc; 65 } 66 67 dr->irq = irq; 68 dr->dev_id = dev_id; 69 devres_add(dev, dr); 70 71 return 0; 72 } 73 EXPORT_SYMBOL(devm_request_threaded_irq); 74 75 /** 76 * devm_request_any_context_irq - allocate an interrupt line for a managed device 77 * @dev: device to request interrupt for 78 * @irq: Interrupt line to allocate 79 * @handler: Function to be called when the IRQ occurs 80 * @thread_fn: function to be called in a threaded interrupt context. NULL 81 * for devices which handle everything in @handler 82 * @irqflags: Interrupt type flags 83 * @devname: An ascii name for the claiming device 84 * @dev_id: A cookie passed back to the handler function 85 * 86 * Except for the extra @dev argument, this function takes the 87 * same arguments and performs the same function as 88 * request_any_context_irq(). IRQs requested with this function will be 89 * automatically freed on driver detach. 90 * 91 * If an IRQ allocated with this function needs to be freed 92 * separately, devm_free_irq() must be used. 93 */ 94 int devm_request_any_context_irq(struct device *dev, unsigned int irq, 95 irq_handler_t handler, unsigned long irqflags, 96 const char *devname, void *dev_id) 97 { 98 struct irq_devres *dr; 99 int rc; 100 101 dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), 102 GFP_KERNEL); 103 if (!dr) 104 return -ENOMEM; 105 106 rc = request_any_context_irq(irq, handler, irqflags, devname, dev_id); 107 if (rc < 0) { 108 devres_free(dr); 109 return rc; 110 } 111 112 dr->irq = irq; 113 dr->dev_id = dev_id; 114 devres_add(dev, dr); 115 116 return rc; 117 } 118 EXPORT_SYMBOL(devm_request_any_context_irq); 119 120 /** 121 * devm_free_irq - free an interrupt 122 * @dev: device to free interrupt for 123 * @irq: Interrupt line to free 124 * @dev_id: Device identity to free 125 * 126 * Except for the extra @dev argument, this function takes the 127 * same arguments and performs the same function as free_irq(). 128 * This function instead of free_irq() should be used to manually 129 * free IRQs allocated with devm_request_irq(). 130 */ 131 void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) 132 { 133 struct irq_devres match_data = { irq, dev_id }; 134 135 WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, 136 &match_data)); 137 free_irq(irq, dev_id); 138 } 139 EXPORT_SYMBOL(devm_free_irq); 140