Commit | Line | Data |
---|---|---|
5ea81769 AV |
1 | #include <linux/module.h> |
2 | #include <linux/interrupt.h> | |
0af3678f | 3 | #include <linux/device.h> |
1aeb272c | 4 | #include <linux/gfp.h> |
5ea81769 AV |
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 | /** | |
935bd5b9 | 29 | * devm_request_threaded_irq - allocate an interrupt line for a managed device |
5ea81769 AV |
30 | * @dev: device to request interrupt for |
31 | * @irq: Interrupt line to allocate | |
32 | * @handler: Function to be called when the IRQ occurs | |
935bd5b9 AV |
33 | * @thread_fn: function to be called in a threaded interrupt context. NULL |
34 | * for devices which handle everything in @handler | |
5ea81769 AV |
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_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, dev_free_irq() must be used. | |
46 | */ | |
935bd5b9 AV |
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) | |
5ea81769 AV |
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 | ||
935bd5b9 AV |
60 | rc = request_threaded_irq(irq, handler, thread_fn, irqflags, devname, |
61 | dev_id); | |
5ea81769 | 62 | if (rc) { |
7f30e49e | 63 | devres_free(dr); |
5ea81769 AV |
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 | } | |
935bd5b9 | 73 | EXPORT_SYMBOL(devm_request_threaded_irq); |
5ea81769 AV |
74 | |
75 | /** | |
76 | * devm_free_irq - free an interrupt | |
77 | * @dev: device to free interrupt for | |
78 | * @irq: Interrupt line to free | |
79 | * @dev_id: Device identity to free | |
80 | * | |
81 | * Except for the extra @dev argument, this function takes the | |
82 | * same arguments and performs the same function as free_irq(). | |
83 | * This function instead of free_irq() should be used to manually | |
84 | * free IRQs allocated with dev_request_irq(). | |
85 | */ | |
86 | void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) | |
87 | { | |
88 | struct irq_devres match_data = { irq, dev_id }; | |
89 | ||
90 | free_irq(irq, dev_id); | |
91 | WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, | |
92 | &match_data)); | |
93 | } | |
94 | EXPORT_SYMBOL(devm_free_irq); |