diff options
| -rw-r--r-- | drivers/pcmcia/cs_internal.h | 2 | ||||
| -rw-r--r-- | drivers/pcmcia/ds.c | 15 | ||||
| -rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 214 | ||||
| -rw-r--r-- | include/pcmcia/ds.h | 3 |
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 | ||
| 152 | void pcmcia_cleanup_irq(struct pcmcia_socket *s); | ||
| 153 | int pcmcia_setup_irq(struct pcmcia_device *p_dev); | ||
| 152 | 154 | ||
| 153 | /* cistpl.c */ | 155 | /* cistpl.c */ |
| 154 | extern struct bin_attribute pccard_cis_attr; | 156 | extern 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; | |||
| 38 | module_param(io_speed, int, 0444); | 40 | module_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 */ | ||
| 44 | static u8 pcmcia_used_irq[NR_IRQS]; | ||
| 45 | #endif | ||
| 46 | |||
| 47 | static int pcmcia_adjust_io_region(struct resource *res, unsigned long start, | 43 | static 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 | ||
| 454 | out: | 446 | out: |
| @@ -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 | ||
| 710 | static irqreturn_t test_action(int cpl, void *dev_id) | ||
| 711 | { | ||
| 712 | return IRQ_NONE; | ||
| 713 | } | ||
| 714 | #endif | ||
| 715 | |||
| 716 | int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) | 696 | int 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 | |||
