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