diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/irq/manage.c | 86 | ||||
-rw-r--r-- | kernel/resource.c | 62 |
2 files changed, 148 insertions, 0 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 8b961adc3bd2..c4b7ed1cebf7 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -482,3 +482,89 @@ 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); | ||
diff --git a/kernel/resource.c b/kernel/resource.c index 7b9a497419d9..2a3f88636580 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/proc_fs.h> | 18 | #include <linux/proc_fs.h> |
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | #include <linux/device.h> | ||
20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
21 | 22 | ||
22 | 23 | ||
@@ -618,6 +619,67 @@ void __release_region(struct resource *parent, resource_size_t start, | |||
618 | EXPORT_SYMBOL(__release_region); | 619 | EXPORT_SYMBOL(__release_region); |
619 | 620 | ||
620 | /* | 621 | /* |
622 | * Managed region resource | ||
623 | */ | ||
624 | struct region_devres { | ||
625 | struct resource *parent; | ||
626 | resource_size_t start; | ||
627 | resource_size_t n; | ||
628 | }; | ||
629 | |||
630 | static void devm_region_release(struct device *dev, void *res) | ||
631 | { | ||
632 | struct region_devres *this = res; | ||
633 | |||
634 | __release_region(this->parent, this->start, this->n); | ||
635 | } | ||
636 | |||
637 | static int devm_region_match(struct device *dev, void *res, void *match_data) | ||
638 | { | ||
639 | struct region_devres *this = res, *match = match_data; | ||
640 | |||
641 | return this->parent == match->parent && | ||
642 | this->start == match->start && this->n == match->n; | ||
643 | } | ||
644 | |||
645 | struct resource * __devm_request_region(struct device *dev, | ||
646 | struct resource *parent, resource_size_t start, | ||
647 | resource_size_t n, const char *name) | ||
648 | { | ||
649 | struct region_devres *dr = NULL; | ||
650 | struct resource *res; | ||
651 | |||
652 | dr = devres_alloc(devm_region_release, sizeof(struct region_devres), | ||
653 | GFP_KERNEL); | ||
654 | if (!dr) | ||
655 | return NULL; | ||
656 | |||
657 | dr->parent = parent; | ||
658 | dr->start = start; | ||
659 | dr->n = n; | ||
660 | |||
661 | res = __request_region(parent, start, n, name); | ||
662 | if (res) | ||
663 | devres_add(dev, dr); | ||
664 | else | ||
665 | devres_free(dr); | ||
666 | |||
667 | return res; | ||
668 | } | ||
669 | EXPORT_SYMBOL(__devm_request_region); | ||
670 | |||
671 | void __devm_release_region(struct device *dev, struct resource *parent, | ||
672 | resource_size_t start, resource_size_t n) | ||
673 | { | ||
674 | struct region_devres match_data = { parent, start, n }; | ||
675 | |||
676 | __release_region(parent, start, n); | ||
677 | WARN_ON(devres_destroy(dev, devm_region_release, devm_region_match, | ||
678 | &match_data)); | ||
679 | } | ||
680 | EXPORT_SYMBOL(__devm_release_region); | ||
681 | |||
682 | /* | ||
621 | * Called from init/main.c to reserve IO ports. | 683 | * Called from init/main.c to reserve IO ports. |
622 | */ | 684 | */ |
623 | #define MAXRESERVE 4 | 685 | #define MAXRESERVE 4 |