diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/irq/Makefile | 2 | ||||
-rw-r--r-- | kernel/irq/devres.c | 88 | ||||
-rw-r--r-- | kernel/irq/manage.c | 86 |
3 files changed, 89 insertions, 87 deletions
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 1dab0ac3f797..681c52dbfe22 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | 1 | ||
2 | obj-y := handle.o manage.o spurious.o resend.o chip.o | 2 | obj-y := handle.o manage.o spurious.o resend.o chip.o devres.o |
3 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o | 3 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o |
4 | obj-$(CONFIG_PROC_FS) += proc.o | 4 | obj-$(CONFIG_PROC_FS) += proc.o |
5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o | 5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o |
diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c new file mode 100644 index 000000000000..85a430da0fb6 --- /dev/null +++ b/kernel/irq/devres.c | |||
@@ -0,0 +1,88 @@ | |||
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); | ||
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index c4b7ed1cebf7..8b961adc3bd2 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -482,89 +482,3 @@ int request_irq(unsigned int irq, irq_handler_t handler, | |||
482 | return retval; | 482 | return retval; |
483 | } | 483 | } |
484 | EXPORT_SYMBOL(request_irq); | 484 | EXPORT_SYMBOL(request_irq); |
485 | |||
486 | /* | ||
487 | * Device resource management aware IRQ request/free implementation. | ||
488 | */ | ||
489 | struct irq_devres { | ||
490 | unsigned int irq; | ||
491 | void *dev_id; | ||
492 | }; | ||
493 | |||
494 | static void devm_irq_release(struct device *dev, void *res) | ||
495 | { | ||
496 | struct irq_devres *this = res; | ||
497 | |||
498 | free_irq(this->irq, this->dev_id); | ||
499 | } | ||
500 | |||
501 | static int devm_irq_match(struct device *dev, void *res, void *data) | ||
502 | { | ||
503 | struct irq_devres *this = res, *match = data; | ||
504 | |||
505 | return this->irq == match->irq && this->dev_id == match->dev_id; | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * devm_request_irq - allocate an interrupt line for a managed device | ||
510 | * @dev: device to request interrupt for | ||
511 | * @irq: Interrupt line to allocate | ||
512 | * @handler: Function to be called when the IRQ occurs | ||
513 | * @irqflags: Interrupt type flags | ||
514 | * @devname: An ascii name for the claiming device | ||
515 | * @dev_id: A cookie passed back to the handler function | ||
516 | * | ||
517 | * Except for the extra @dev argument, this function takes the | ||
518 | * same arguments and performs the same function as | ||
519 | * request_irq(). IRQs requested with this function will be | ||
520 | * automatically freed on driver detach. | ||
521 | * | ||
522 | * If an IRQ allocated with this function needs to be freed | ||
523 | * separately, dev_free_irq() must be used. | ||
524 | */ | ||
525 | int devm_request_irq(struct device *dev, unsigned int irq, | ||
526 | irq_handler_t handler, unsigned long irqflags, | ||
527 | const char *devname, void *dev_id) | ||
528 | { | ||
529 | struct irq_devres *dr; | ||
530 | int rc; | ||
531 | |||
532 | dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), | ||
533 | GFP_KERNEL); | ||
534 | if (!dr) | ||
535 | return -ENOMEM; | ||
536 | |||
537 | rc = request_irq(irq, handler, irqflags, devname, dev_id); | ||
538 | if (rc) { | ||
539 | kfree(dr); | ||
540 | return rc; | ||
541 | } | ||
542 | |||
543 | dr->irq = irq; | ||
544 | dr->dev_id = dev_id; | ||
545 | devres_add(dev, dr); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | EXPORT_SYMBOL(devm_request_irq); | ||
550 | |||
551 | /** | ||
552 | * devm_free_irq - free an interrupt | ||
553 | * @dev: device to free interrupt for | ||
554 | * @irq: Interrupt line to free | ||
555 | * @dev_id: Device identity to free | ||
556 | * | ||
557 | * Except for the extra @dev argument, this function takes the | ||
558 | * same arguments and performs the same function as free_irq(). | ||
559 | * This function instead of free_irq() should be used to manually | ||
560 | * free IRQs allocated with dev_request_irq(). | ||
561 | */ | ||
562 | void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) | ||
563 | { | ||
564 | struct irq_devres match_data = { irq, dev_id }; | ||
565 | |||
566 | free_irq(irq, dev_id); | ||
567 | WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, | ||
568 | &match_data)); | ||
569 | } | ||
570 | EXPORT_SYMBOL(devm_free_irq); | ||