aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pcmcia/cs_internal.h2
-rw-r--r--drivers/pcmcia/ds.c15
-rw-r--r--drivers/pcmcia/pcmcia_resource.c214
-rw-r--r--include/pcmcia/ds.h3
4 files changed, 140 insertions, 94 deletions
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index f95864c2191..74d91c8849b 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -149,6 +149,8 @@ extern struct resource *pcmcia_find_mem_region(u_long base,
149 int low, 149 int low,
150 struct pcmcia_socket *s); 150 struct pcmcia_socket *s);
151 151
152void pcmcia_cleanup_irq(struct pcmcia_socket *s);
153int pcmcia_setup_irq(struct pcmcia_device *p_dev);
152 154
153/* cistpl.c */ 155/* cistpl.c */
154extern struct bin_attribute pccard_cis_attr; 156extern struct bin_attribute pccard_cis_attr;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 041eee43fd8..5fd2948c7ed 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -546,26 +546,32 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
546 p_dev->function_config = tmp_dev->function_config; 546 p_dev->function_config = tmp_dev->function_config;
547 p_dev->io = tmp_dev->io; 547 p_dev->io = tmp_dev->io;
548 p_dev->irq = tmp_dev->irq; 548 p_dev->irq = tmp_dev->irq;
549 p_dev->irq_v = tmp_dev->irq_v;
549 kref_get(&p_dev->function_config->ref); 550 kref_get(&p_dev->function_config->ref);
550 } 551 }
551 552
552 /* Add to the list in pcmcia_bus_socket */ 553 /* Add to the list in pcmcia_bus_socket */
553 list_add(&p_dev->socket_device_list, &s->devices_list); 554 list_add(&p_dev->socket_device_list, &s->devices_list);
554 555
555 mutex_unlock(&s->ops_mutex); 556 if (pcmcia_setup_irq(p_dev))
557 dev_warn(&p_dev->dev,
558 "IRQ setup failed -- device might not work\n");
556 559
557 if (!p_dev->function_config) { 560 if (!p_dev->function_config) {
558 dev_dbg(&p_dev->dev, "creating config_t\n"); 561 dev_dbg(&p_dev->dev, "creating config_t\n");
559 p_dev->function_config = kzalloc(sizeof(struct config_t), 562 p_dev->function_config = kzalloc(sizeof(struct config_t),
560 GFP_KERNEL); 563 GFP_KERNEL);
561 if (!p_dev->function_config) 564 if (!p_dev->function_config) {
565 mutex_unlock(&s->ops_mutex);
562 goto err_unreg; 566 goto err_unreg;
567 }
563 kref_init(&p_dev->function_config->ref); 568 kref_init(&p_dev->function_config->ref);
564 } 569 }
570 mutex_unlock(&s->ops_mutex);
565 571
566 dev_printk(KERN_NOTICE, &p_dev->dev, 572 dev_printk(KERN_NOTICE, &p_dev->dev,
567 "pcmcia: registering new device %s\n", 573 "pcmcia: registering new device %s (IRQ: %d)\n",
568 p_dev->devname); 574 p_dev->devname, p_dev->irq_v);
569 575
570 pcmcia_device_query(p_dev); 576 pcmcia_device_query(p_dev);
571 577
@@ -1258,6 +1264,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
1258 handle_event(skt, event); 1264 handle_event(skt, event);
1259 mutex_lock(&s->ops_mutex); 1265 mutex_lock(&s->ops_mutex);
1260 destroy_cis_cache(s); 1266 destroy_cis_cache(s);
1267 pcmcia_cleanup_irq(s);
1261 mutex_unlock(&s->ops_mutex); 1268 mutex_unlock(&s->ops_mutex);
1262 break; 1269 break;
1263 1270
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index ba82cb3b194..ff9c0bcb7e3 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
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index aab3c13dc31..52ebe75664e 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -95,6 +95,9 @@ struct pcmcia_device {
95 config_req_t conf; 95 config_req_t conf;
96 window_handle_t win; 96 window_handle_t win;
97 97
98 /* device setup */
99 unsigned int irq_v; /* do not use directly yet */
100
98 /* Is the device suspended? */ 101 /* Is the device suspended? */
99 u16 suspended:1; 102 u16 suspended:1;
100 103