Commit | Line | Data |
---|---|---|
5ea81769 AV |
1 | #include <linux/module.h> |
2 | #include <linux/interrupt.h> | |
0af3678f | 3 | #include <linux/device.h> |
5ea81769 AV |
4 | |
5 | /* | |
6 | * Device resource management aware IRQ request/free implementation. | |
7 | */ | |
8 | struct irq_devres { | |
9 | unsigned int irq; | |
10 | void *dev_id; | |
11 | }; | |
12 | ||
13 | static void devm_irq_release(struct device *dev, void *res) | |
14 | { | |
15 | struct irq_devres *this = res; | |
16 | ||
17 | free_irq(this->irq, this->dev_id); | |
18 | } | |
19 | ||
20 | static int devm_irq_match(struct device *dev, void *res, void *data) | |
21 | { | |
22 | struct irq_devres *this = res, *match = data; | |
23 | ||
24 | return this->irq == match->irq && this->dev_id == match->dev_id; | |
25 | } | |
26 | ||
27 | /** | |
28 | * devm_request_irq - allocate an interrupt line for a managed device | |
29 | * @dev: device to request interrupt for | |
30 | * @irq: Interrupt line to allocate | |
31 | * @handler: Function to be called when the IRQ occurs | |
32 | * @irqflags: Interrupt type flags | |
33 | * @devname: An ascii name for the claiming device | |
34 | * @dev_id: A cookie passed back to the handler function | |
35 | * | |
36 | * Except for the extra @dev argument, this function takes the | |
37 | * same arguments and performs the same function as | |
38 | * request_irq(). IRQs requested with this function will be | |
39 | * automatically freed on driver detach. | |
40 | * | |
41 | * If an IRQ allocated with this function needs to be freed | |
42 | * separately, dev_free_irq() must be used. | |
43 | */ | |
44 | int devm_request_irq(struct device *dev, unsigned int irq, | |
45 | irq_handler_t handler, unsigned long irqflags, | |
46 | const char *devname, void *dev_id) | |
47 | { | |
48 | struct irq_devres *dr; | |
49 | int rc; | |
50 | ||
51 | dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), | |
52 | GFP_KERNEL); | |
53 | if (!dr) | |
54 | return -ENOMEM; | |
55 | ||
56 | rc = request_irq(irq, handler, irqflags, devname, dev_id); | |
57 | if (rc) { | |
7f30e49e | 58 | devres_free(dr); |
5ea81769 AV |
59 | return rc; |
60 | } | |
61 | ||
62 | dr->irq = irq; | |
63 | dr->dev_id = dev_id; | |
64 | devres_add(dev, dr); | |
65 | ||
66 | return 0; | |
67 | } | |
68 | EXPORT_SYMBOL(devm_request_irq); | |
69 | ||
70 | /** | |
71 | * devm_free_irq - free an interrupt | |
72 | * @dev: device to free interrupt for | |
73 | * @irq: Interrupt line to free | |
74 | * @dev_id: Device identity to free | |
75 | * | |
76 | * Except for the extra @dev argument, this function takes the | |
77 | * same arguments and performs the same function as free_irq(). | |
78 | * This function instead of free_irq() should be used to manually | |
79 | * free IRQs allocated with dev_request_irq(). | |
80 | */ | |
81 | void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) | |
82 | { | |
83 | struct irq_devres match_data = { irq, dev_id }; | |
84 | ||
85 | free_irq(irq, dev_id); | |
86 | WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, | |
87 | &match_data)); | |
88 | } | |
89 | EXPORT_SYMBOL(devm_free_irq); |