aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia/pcmcia_resource.c
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2010-04-08 14:33:16 -0400
committerDominik Brodowski <linux@dominikbrodowski.net>2010-05-10 04:23:11 -0400
commit6f0f38c45a8f2f511c25893e33011ff32fc811db (patch)
treed44382f7b5c7db15e39ce7d5dc2b2feb7bd108a8 /drivers/pcmcia/pcmcia_resource.c
parent0cb3c49cdd275aa9ef4b1afd090117b1b86a16d4 (diff)
pcmcia: setup IRQ to be used by PCMCIA drivers at card insert
Setup the IRQ to be used by PCMCIA drivers already during the device registration stage, making use of a new function pcmcia_setup_irq(). This will allow us to get rid of quite a lot of indirection in the future. Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia/pcmcia_resource.c')
-rw-r--r--drivers/pcmcia/pcmcia_resource.c214
1 files changed, 124 insertions, 90 deletions
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index ba82cb3b1944..ff9c0bcb7e3a 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -23,6 +23,8 @@
23#include <linux/netdevice.h> 23#include <linux/netdevice.h>
24#include <linux/slab.h> 24#include <linux/slab.h>
25 25
26#include <asm/irq.h>
27
26#include <pcmcia/cs_types.h> 28#include <pcmcia/cs_types.h>
27#include <pcmcia/ss.h> 29#include <pcmcia/ss.h>
28#include <pcmcia/cs.h> 30#include <pcmcia/cs.h>
@@ -38,12 +40,6 @@ static int io_speed;
38module_param(io_speed, int, 0444); 40module_param(io_speed, int, 0444);
39 41
40 42
41#ifdef CONFIG_PCMCIA_PROBE
42#include <asm/irq.h>
43/* mask of IRQs already reserved by other cards, we should avoid using them */
44static u8 pcmcia_used_irq[NR_IRQS];
45#endif
46
47static int pcmcia_adjust_io_region(struct resource *res, unsigned long start, 43static int pcmcia_adjust_io_region(struct resource *res, unsigned long start,
48 unsigned long end, struct pcmcia_socket *s) 44 unsigned long end, struct pcmcia_socket *s)
49{ 45{
@@ -440,15 +436,11 @@ static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
440 } 436 }
441 if (--s->irq.Config == 0) { 437 if (--s->irq.Config == 0) {
442 c->state &= ~CONFIG_IRQ_REQ; 438 c->state &= ~CONFIG_IRQ_REQ;
443 s->irq.AssignedIRQ = 0;
444 } 439 }
445 440
446 if (req->Handler) 441 if (req->Handler)
447 free_irq(req->AssignedIRQ, p_dev->priv); 442 free_irq(req->AssignedIRQ, p_dev->priv);
448 443
449#ifdef CONFIG_PCMCIA_PROBE
450 pcmcia_used_irq[req->AssignedIRQ]--;
451#endif
452 ret = 0; 444 ret = 0;
453 445
454out: 446out:
@@ -699,26 +691,14 @@ EXPORT_SYMBOL(pcmcia_request_io);
699/** pcmcia_request_irq 691/** pcmcia_request_irq
700 * 692 *
701 * Request_irq() reserves an irq for this client. 693 * Request_irq() reserves an irq for this client.
702 *
703 * Also, since Linux only reserves irq's when they are actually
704 * hooked, we don't guarantee that an irq will still be available
705 * when the configuration is locked. Now that I think about it,
706 * there might be a way to fix this using a dummy handler.
707 */ 694 */
708 695
709#ifdef CONFIG_PCMCIA_PROBE
710static irqreturn_t test_action(int cpl, void *dev_id)
711{
712 return IRQ_NONE;
713}
714#endif
715
716int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) 696int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
717{ 697{
718 struct pcmcia_socket *s = p_dev->socket; 698 struct pcmcia_socket *s = p_dev->socket;
719 config_t *c; 699 config_t *c;
720 int ret = -EINVAL, irq = 0; 700 int ret = -EINVAL, irq = p_dev->irq_v;
721 int type; 701 int type = IRQF_SHARED;
722 702
723 mutex_lock(&s->ops_mutex); 703 mutex_lock(&s->ops_mutex);
724 704
@@ -736,63 +716,20 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
736 goto out; 716 goto out;
737 } 717 }
738 718
739 /* Decide what type of interrupt we are registering */
740 type = 0;
741 if (s->functions > 1) /* All of this ought to be handled higher up */
742 type = IRQF_SHARED;
743 else if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)
744 type = IRQF_SHARED;
745 else
746 printk(KERN_WARNING "pcmcia: Driver needs updating to support IRQ sharing.\n");
747
748 /* If the interrupt is already assigned, it must be the same */
749 if (s->irq.AssignedIRQ != 0)
750 irq = s->irq.AssignedIRQ;
751
752#ifdef CONFIG_PCMCIA_PROBE
753 if (!irq) { 719 if (!irq) {
754 int try; 720 dev_dbg(&s->dev, "no IRQ available\n");
755 u32 mask = s->irq_mask; 721 goto out;
756 void *data = p_dev; /* something unique to this device */
757
758 for (try = 0; try < 64; try++) {
759 irq = try % 32;
760
761 /* marked as available by driver, and not blocked by userspace? */
762 if (!((mask >> irq) & 1))
763 continue;
764
765 /* avoid an IRQ which is already used by a PCMCIA card */
766 if ((try < 32) && pcmcia_used_irq[irq])
767 continue;
768
769 /* register the correct driver, if possible, of check whether
770 * registering a dummy handle works, i.e. if the IRQ isn't
771 * marked as used by the kernel resource management core */
772 ret = request_irq(irq,
773 (req->Handler) ? req->Handler : test_action,
774 type,
775 p_dev->devname,
776 (req->Handler) ? p_dev->priv : data);
777 if (!ret) {
778 if (!req->Handler)
779 free_irq(irq, data);
780 break;
781 }
782 }
783 } 722 }
784#endif 723
785 /* only assign PCI irq if no IRQ already assigned */ 724 if (!(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) {
786 if (ret && !s->irq.AssignedIRQ) { 725 req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
787 if (!s->pci_irq) { 726 dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: "
788 dev_printk(KERN_INFO, &s->dev, "no IRQ found\n"); 727 "request for exclusive IRQ could not be fulfilled.\n");
789 goto out; 728 dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver "
790 } 729 "needs updating to supported shared IRQ lines.\n");
791 type = IRQF_SHARED;
792 irq = s->pci_irq;
793 } 730 }
794 731
795 if (ret && req->Handler) { 732 if (req->Handler) {
796 ret = request_irq(irq, req->Handler, type, 733 ret = request_irq(irq, req->Handler, type,
797 p_dev->devname, p_dev->priv); 734 p_dev->devname, p_dev->priv);
798 if (ret) { 735 if (ret) {
@@ -802,25 +739,13 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
802 } 739 }
803 } 740 }
804 741
805 /* Make sure the fact the request type was overridden is passed back */
806 if (type == IRQF_SHARED && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) {
807 req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
808 dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: "
809 "request for exclusive IRQ could not be fulfilled.\n");
810 dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver "
811 "needs updating to supported shared IRQ lines.\n");
812 }
813 c->irq.Attributes = req->Attributes; 742 c->irq.Attributes = req->Attributes;
814 s->irq.AssignedIRQ = req->AssignedIRQ = irq; 743 req->AssignedIRQ = irq;
815 s->irq.Config++; 744 s->irq.Config++;
816 745
817 c->state |= CONFIG_IRQ_REQ; 746 c->state |= CONFIG_IRQ_REQ;
818 p_dev->_irq = 1; 747 p_dev->_irq = 1;
819 748
820#ifdef CONFIG_PCMCIA_PROBE
821 pcmcia_used_irq[irq]++;
822#endif
823
824 ret = 0; 749 ret = 0;
825out: 750out:
826 mutex_unlock(&s->ops_mutex); 751 mutex_unlock(&s->ops_mutex);
@@ -829,6 +754,115 @@ out:
829EXPORT_SYMBOL(pcmcia_request_irq); 754EXPORT_SYMBOL(pcmcia_request_irq);
830 755
831 756
757#ifdef CONFIG_PCMCIA_PROBE
758
759/* mask of IRQs already reserved by other cards, we should avoid using them */
760static u8 pcmcia_used_irq[NR_IRQS];
761
762static irqreturn_t test_action(int cpl, void *dev_id)
763{
764 return IRQ_NONE;
765}
766
767/**
768 * pcmcia_setup_isa_irq() - determine whether an ISA IRQ can be used
769 * @p_dev - the associated PCMCIA device
770 *
771 * locking note: must be called with ops_mutex locked.
772 */
773static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type)
774{
775 struct pcmcia_socket *s = p_dev->socket;
776 unsigned int try, irq;
777 u32 mask = s->irq_mask;
778 int ret = -ENODEV;
779
780 for (try = 0; try < 64; try++) {
781 irq = try % 32;
782
783 /* marked as available by driver, not blocked by userspace? */
784 if (!((mask >> irq) & 1))
785 continue;
786
787 /* avoid an IRQ which is already used by another PCMCIA card */
788 if ((try < 32) && pcmcia_used_irq[irq])
789 continue;
790
791 /* register the correct driver, if possible, to check whether
792 * registering a dummy handle works, i.e. if the IRQ isn't
793 * marked as used by the kernel resource management core */
794 ret = request_irq(irq, test_action, type, p_dev->devname,
795 p_dev);
796 if (!ret) {
797 free_irq(irq, p_dev);
798 p_dev->irq_v = s->irq.AssignedIRQ = irq;
799 pcmcia_used_irq[irq]++;
800 break;
801 }
802 }
803
804 return ret;
805}
806
807void pcmcia_cleanup_irq(struct pcmcia_socket *s)
808{
809 pcmcia_used_irq[s->irq.AssignedIRQ]--;
810 s->irq.AssignedIRQ = 0;
811}
812
813#else /* CONFIG_PCMCIA_PROBE */
814
815static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type)
816{
817 return -EINVAL;
818}
819
820void pcmcia_cleanup_irq(struct pcmcia_socket *s)
821{
822 s->irq.AssignedIRQ = 0;
823 return;
824}
825
826#endif /* CONFIG_PCMCIA_PROBE */
827
828
829/**
830 * pcmcia_setup_irq() - determine IRQ to be used for device
831 * @p_dev - the associated PCMCIA device
832 *
833 * locking note: must be called with ops_mutex locked.
834 */
835int pcmcia_setup_irq(struct pcmcia_device *p_dev)
836{
837 struct pcmcia_socket *s = p_dev->socket;
838
839 if (p_dev->irq_v)
840 return 0;
841
842 /* already assigned? */
843 if (s->irq.AssignedIRQ) {
844 p_dev->irq_v = s->irq.AssignedIRQ;
845 return 0;
846 }
847
848 /* prefer an exclusive ISA irq */
849 if (!pcmcia_setup_isa_irq(p_dev, 0))
850 return 0;
851
852 /* but accept a shared ISA irq */
853 if (!pcmcia_setup_isa_irq(p_dev, IRQF_SHARED))
854 return 0;
855
856 /* but use the PCI irq otherwise */
857 if (s->pci_irq) {
858 p_dev->irq_v = s->irq.AssignedIRQ = s->pci_irq;
859 return 0;
860 }
861
862 return -EINVAL;
863}
864
865
832/** pcmcia_request_window 866/** pcmcia_request_window
833 * 867 *
834 * Request_window() establishes a mapping between card memory space 868 * Request_window() establishes a mapping between card memory space