]>
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 | /** | |
29 | * devm_request_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 | * @irqflags: Interrupt type flags | |
34 | * @devname: An ascii name for the claiming device | |
35 | * @dev_id: A cookie passed back to the handler function | |
36 | * | |
37 | * Except for the extra @dev argument, this function takes the | |
38 | * same arguments and performs the same function as | |
39 | * request_irq(). IRQs requested with this function will be | |
40 | * automatically freed on driver detach. | |
41 | * | |
42 | * If an IRQ allocated with this function needs to be freed | |
43 | * separately, dev_free_irq() must be used. | |
44 | */ | |
45 | int devm_request_irq(struct device *dev, unsigned int irq, | |
46 | irq_handler_t handler, unsigned long irqflags, | |
47 | const char *devname, void *dev_id) | |
48 | { | |
49 | struct irq_devres *dr; | |
50 | int rc; | |
51 | ||
52 | dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), | |
53 | GFP_KERNEL); | |
54 | if (!dr) | |
55 | return -ENOMEM; | |
56 | ||
57 | rc = request_irq(irq, handler, irqflags, devname, dev_id); | |
58 | if (rc) { | |
7f30e49e | 59 | devres_free(dr); |
5ea81769 AV |
60 | return rc; |
61 | } | |
62 | ||
63 | dr->irq = irq; | |
64 | dr->dev_id = dev_id; | |
65 | devres_add(dev, dr); | |
66 | ||
67 | return 0; | |
68 | } | |
69 | EXPORT_SYMBOL(devm_request_irq); | |
70 | ||
71 | /** | |
72 | * devm_free_irq - free an interrupt | |
73 | * @dev: device to free interrupt for | |
74 | * @irq: Interrupt line to free | |
75 | * @dev_id: Device identity to free | |
76 | * | |
77 | * Except for the extra @dev argument, this function takes the | |
78 | * same arguments and performs the same function as free_irq(). | |
79 | * This function instead of free_irq() should be used to manually | |
80 | * free IRQs allocated with dev_request_irq(). | |
81 | */ | |
82 | void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) | |
83 | { | |
84 | struct irq_devres match_data = { irq, dev_id }; | |
85 | ||
86 | free_irq(irq, dev_id); | |
87 | WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, | |
88 | &match_data)); | |
89 | } | |
90 | EXPORT_SYMBOL(devm_free_irq); |