diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-03-07 06:21:16 -0500 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-05-10 04:23:13 -0400 |
commit | eb14120f743d29744d9475bffec56ff4ad43a749 (patch) | |
tree | 56857094d2b0cfc0ecbd1685f18d6edbe78e140f /drivers/pcmcia/pcmcia_resource.c | |
parent | a7debe789dfcaee9c4d81e5738b0be8c5d93930b (diff) |
pcmcia: re-work pcmcia_request_irq()
Instead of the old pcmcia_request_irq() interface, drivers may now
choose between:
- calling request_irq/free_irq directly. Use the IRQ from *p_dev->irq.
- use pcmcia_request_irq(p_dev, handler_t); the PCMCIA core will
clean up automatically on calls to pcmcia_disable_device() or
device ejection.
- drivers still not capable of IRQF_SHARED (or not telling us so) may
use the deprecated pcmcia_request_exclusive_irq() for the time
being; they might receive a shared IRQ nonetheless.
CC: linux-bluetooth@vger.kernel.org
CC: netdev@vger.kernel.org
CC: linux-wireless@vger.kernel.org
CC: linux-serial@vger.kernel.org
CC: alsa-devel@alsa-project.org
CC: linux-usb@vger.kernel.org
CC: linux-ide@vger.kernel.org
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia/pcmcia_resource.c')
-rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 137 |
1 files changed, 54 insertions, 83 deletions
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 8dce223f3f44..f355c5ac407b 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c | |||
@@ -408,41 +408,6 @@ out: | |||
408 | } /* pcmcia_release_io */ | 408 | } /* pcmcia_release_io */ |
409 | 409 | ||
410 | 410 | ||
411 | static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) | ||
412 | { | ||
413 | struct pcmcia_socket *s = p_dev->socket; | ||
414 | config_t *c; | ||
415 | int ret = -EINVAL; | ||
416 | |||
417 | mutex_lock(&s->ops_mutex); | ||
418 | |||
419 | c = p_dev->function_config; | ||
420 | |||
421 | if (!p_dev->_irq) | ||
422 | goto out; | ||
423 | |||
424 | p_dev->_irq = 0; | ||
425 | |||
426 | if (c->state & CONFIG_LOCKED) | ||
427 | goto out; | ||
428 | |||
429 | if (s->pcmcia_irq != req->AssignedIRQ) { | ||
430 | dev_dbg(&s->dev, "IRQ must match assigned one\n"); | ||
431 | goto out; | ||
432 | } | ||
433 | |||
434 | if (req->Handler) | ||
435 | free_irq(req->AssignedIRQ, p_dev->priv); | ||
436 | |||
437 | ret = 0; | ||
438 | |||
439 | out: | ||
440 | mutex_unlock(&s->ops_mutex); | ||
441 | |||
442 | return ret; | ||
443 | } /* pcmcia_release_irq */ | ||
444 | |||
445 | |||
446 | int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) | 411 | int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t wh) |
447 | { | 412 | { |
448 | struct pcmcia_socket *s = p_dev->socket; | 413 | struct pcmcia_socket *s = p_dev->socket; |
@@ -681,61 +646,66 @@ out: | |||
681 | EXPORT_SYMBOL(pcmcia_request_io); | 646 | EXPORT_SYMBOL(pcmcia_request_io); |
682 | 647 | ||
683 | 648 | ||
684 | /** pcmcia_request_irq | 649 | /** |
650 | * pcmcia_request_irq() - attempt to request a IRQ for a PCMCIA device | ||
685 | * | 651 | * |
686 | * Request_irq() reserves an irq for this client. | 652 | * pcmcia_request_irq() is a wrapper around request_irq which will allow |
653 | * the PCMCIA core to clean up the registration in pcmcia_disable_device(). | ||
654 | * Drivers are free to use request_irq() directly, but then they need to | ||
655 | * call free_irq themselfves, too. Also, only IRQF_SHARED capable IRQ | ||
656 | * handlers are allowed. | ||
687 | */ | 657 | */ |
688 | 658 | int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev, | |
689 | int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) | 659 | irq_handler_t handler) |
690 | { | 660 | { |
691 | struct pcmcia_socket *s = p_dev->socket; | 661 | int ret; |
692 | config_t *c; | ||
693 | int ret = -EINVAL, irq = p_dev->irq_v; | ||
694 | int type = IRQF_SHARED; | ||
695 | 662 | ||
696 | mutex_lock(&s->ops_mutex); | 663 | if (!p_dev->irq) |
664 | return -EINVAL; | ||
697 | 665 | ||
698 | if (!(s->state & SOCKET_PRESENT)) { | 666 | ret = request_irq(p_dev->irq, handler, IRQF_SHARED, |
699 | dev_dbg(&s->dev, "No card present\n"); | 667 | p_dev->devname, p_dev->priv); |
700 | goto out; | 668 | if (!ret) |
701 | } | 669 | p_dev->_irq = 1; |
702 | c = p_dev->function_config; | ||
703 | if (c->state & CONFIG_LOCKED) { | ||
704 | dev_dbg(&s->dev, "Configuration is locked\n"); | ||
705 | goto out; | ||
706 | } | ||
707 | 670 | ||
708 | if (!irq) { | 671 | return ret; |
709 | dev_dbg(&s->dev, "no IRQ available\n"); | 672 | } |
710 | goto out; | 673 | EXPORT_SYMBOL(pcmcia_request_irq); |
711 | } | ||
712 | 674 | ||
713 | if (!(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) { | ||
714 | req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING; | ||
715 | dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver " | ||
716 | "needs updating to supported shared IRQ lines.\n"); | ||
717 | } | ||
718 | 675 | ||
719 | if (req->Handler) { | 676 | /** |
720 | ret = request_irq(irq, req->Handler, type, | 677 | * pcmcia_request_exclusive_irq() - attempt to request an exclusive IRQ first |
721 | p_dev->devname, p_dev->priv); | 678 | * |
722 | if (ret) { | 679 | * pcmcia_request_exclusive_irq() is a wrapper around request_irq which |
723 | dev_printk(KERN_INFO, &s->dev, | 680 | * attempts first to request an exclusive IRQ. If it fails, it also accepts |
724 | "request_irq() failed\n"); | 681 | * a shared IRQ, but prints out a warning. PCMCIA drivers should allow for |
725 | goto out; | 682 | * IRQ sharing and either use request_irq directly (then they need to call |
726 | } | 683 | * free_irq themselves, too), or the pcmcia_request_irq() function. |
727 | } | 684 | */ |
685 | int __must_check | ||
686 | pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev, irq_handler_t handler) | ||
687 | { | ||
688 | int ret; | ||
728 | 689 | ||
729 | req->AssignedIRQ = irq; | 690 | if (!p_dev->irq) |
691 | return -EINVAL; | ||
730 | 692 | ||
731 | p_dev->_irq = 1; | 693 | ret = request_irq(p_dev->irq, handler, 0, p_dev->devname, p_dev->priv); |
694 | if (ret) { | ||
695 | ret = pcmcia_request_irq(p_dev, handler); | ||
696 | dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: " | ||
697 | "request for exclusive IRQ could not be fulfilled.\n"); | ||
698 | dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver " | ||
699 | "needs updating to supported shared IRQ lines.\n"); | ||
700 | } | ||
701 | if (ret) | ||
702 | dev_printk(KERN_INFO, &p_dev->dev, "request_irq() failed\n"); | ||
703 | else | ||
704 | p_dev->_irq = 1; | ||
732 | 705 | ||
733 | ret = 0; | ||
734 | out: | ||
735 | mutex_unlock(&s->ops_mutex); | ||
736 | return ret; | 706 | return ret; |
737 | } /* pcmcia_request_irq */ | 707 | } /* pcmcia_request_exclusive_irq */ |
738 | EXPORT_SYMBOL(pcmcia_request_irq); | 708 | EXPORT_SYMBOL(pcmcia_request_exclusive_irq); |
739 | 709 | ||
740 | 710 | ||
741 | #ifdef CONFIG_PCMCIA_PROBE | 711 | #ifdef CONFIG_PCMCIA_PROBE |
@@ -779,7 +749,7 @@ static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type) | |||
779 | p_dev); | 749 | p_dev); |
780 | if (!ret) { | 750 | if (!ret) { |
781 | free_irq(irq, p_dev); | 751 | free_irq(irq, p_dev); |
782 | p_dev->irq_v = s->pcmcia_irq = irq; | 752 | p_dev->irq = s->pcmcia_irq = irq; |
783 | pcmcia_used_irq[irq]++; | 753 | pcmcia_used_irq[irq]++; |
784 | break; | 754 | break; |
785 | } | 755 | } |
@@ -820,12 +790,12 @@ int pcmcia_setup_irq(struct pcmcia_device *p_dev) | |||
820 | { | 790 | { |
821 | struct pcmcia_socket *s = p_dev->socket; | 791 | struct pcmcia_socket *s = p_dev->socket; |
822 | 792 | ||
823 | if (p_dev->irq_v) | 793 | if (p_dev->irq) |
824 | return 0; | 794 | return 0; |
825 | 795 | ||
826 | /* already assigned? */ | 796 | /* already assigned? */ |
827 | if (s->pcmcia_irq) { | 797 | if (s->pcmcia_irq) { |
828 | p_dev->irq_v = s->pcmcia_irq; | 798 | p_dev->irq = s->pcmcia_irq; |
829 | return 0; | 799 | return 0; |
830 | } | 800 | } |
831 | 801 | ||
@@ -839,7 +809,7 @@ int pcmcia_setup_irq(struct pcmcia_device *p_dev) | |||
839 | 809 | ||
840 | /* but use the PCI irq otherwise */ | 810 | /* but use the PCI irq otherwise */ |
841 | if (s->pci_irq) { | 811 | if (s->pci_irq) { |
842 | p_dev->irq_v = s->pcmcia_irq = s->pci_irq; | 812 | p_dev->irq = s->pcmcia_irq = s->pci_irq; |
843 | return 0; | 813 | return 0; |
844 | } | 814 | } |
845 | 815 | ||
@@ -947,7 +917,8 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev) | |||
947 | { | 917 | { |
948 | pcmcia_release_configuration(p_dev); | 918 | pcmcia_release_configuration(p_dev); |
949 | pcmcia_release_io(p_dev, &p_dev->io); | 919 | pcmcia_release_io(p_dev, &p_dev->io); |
950 | pcmcia_release_irq(p_dev, &p_dev->irq); | 920 | if (p_dev->_irq) |
921 | free_irq(p_dev->irq, p_dev->priv); | ||
951 | if (p_dev->win) | 922 | if (p_dev->win) |
952 | pcmcia_release_window(p_dev, p_dev->win); | 923 | pcmcia_release_window(p_dev, p_dev->win); |
953 | } | 924 | } |