aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/irq/manage.c86
-rw-r--r--kernel/resource.c62
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}
484EXPORT_SYMBOL(request_irq); 484EXPORT_SYMBOL(request_irq);
485
486/*
487 * Device resource management aware IRQ request/free implementation.
488 */
489struct irq_devres {
490 unsigned int irq;
491 void *dev_id;
492};
493
494static 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
501static 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 */
525int 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}
549EXPORT_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 */
562void 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}
570EXPORT_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,
618EXPORT_SYMBOL(__release_region); 619EXPORT_SYMBOL(__release_region);
619 620
620/* 621/*
622 * Managed region resource
623 */
624struct region_devres {
625 struct resource *parent;
626 resource_size_t start;
627 resource_size_t n;
628};
629
630static 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
637static 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
645struct 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}
669EXPORT_SYMBOL(__devm_request_region);
670
671void __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}
680EXPORT_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