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 f95864c2191e..74d91c8849ba 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 041eee43fd8d..5fd2948c7ed9 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 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