summaryrefslogtreecommitdiff
path: root/drivers/pnp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pnp')
-rw-r--r--drivers/pnp/base.h1
-rw-r--r--drivers/pnp/interface.c2
-rw-r--r--drivers/pnp/quirks.c132
-rw-r--r--drivers/pnp/resource.c2
-rw-r--r--drivers/pnp/support.c8
5 files changed, 127 insertions, 18 deletions
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 4fe7c58f57e9..886dac823ed6 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -19,6 +19,7 @@ void pnp_remove_card(struct pnp_card *card);
int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev);
void pnp_remove_card_device(struct pnp_dev *dev);
+struct pnp_option *pnp_build_option(int priority);
struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
int priority);
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 5d9301de1778..5695a79f3a52 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -424,7 +424,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
start = simple_strtoul(buf, &buf, 0);
pnp_res = pnp_add_irq_resource(dev, start, 0);
if (pnp_res)
- nirq++;
+ pnp_res->index = nirq++;
continue;
}
if (!strnicmp(buf, "dma", 3)) {
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index d049a2279fea..ffdb12a59c40 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -111,6 +111,113 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
dev_info(&dev->dev, "SB audio device quirk - increased port range\n");
}
+static struct pnp_option *quirk_isapnp_mpu_options(struct pnp_dev *dev)
+{
+ struct pnp_option *head = NULL;
+ struct pnp_option *prev = NULL;
+ struct pnp_option *res;
+
+ /*
+ * Build a functional IRQ-less variant of each MPU option.
+ */
+
+ for (res = dev->dependent; res; res = res->next) {
+ struct pnp_option *curr;
+ struct pnp_port *port;
+ struct pnp_port *copy;
+
+ port = res->port;
+ if (!port || !res->irq)
+ continue;
+
+ copy = pnp_alloc(sizeof *copy);
+ if (!copy)
+ break;
+
+ copy->min = port->min;
+ copy->max = port->max;
+ copy->align = port->align;
+ copy->size = port->size;
+ copy->flags = port->flags;
+
+ curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL);
+ if (!curr) {
+ kfree(copy);
+ break;
+ }
+ curr->port = copy;
+
+ if (prev)
+ prev->next = curr;
+ else
+ head = curr;
+ prev = curr;
+ }
+ if (head)
+ dev_info(&dev->dev, "adding IRQ-less MPU options\n");
+
+ return head;
+}
+
+static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
+{
+ struct pnp_option *res;
+ struct pnp_irq *irq;
+
+ /*
+ * Distribute the independent IRQ over the dependent options
+ */
+
+ res = dev->independent;
+ if (!res)
+ return;
+
+ irq = res->irq;
+ if (!irq || irq->next)
+ return;
+
+ res = dev->dependent;
+ if (!res)
+ return;
+
+ while (1) {
+ struct pnp_irq *copy;
+
+ copy = pnp_alloc(sizeof *copy);
+ if (!copy)
+ break;
+
+ memcpy(copy->map, irq->map, sizeof copy->map);
+ copy->flags = irq->flags;
+
+ copy->next = res->irq; /* Yes, this is NULL */
+ res->irq = copy;
+
+ if (!res->next)
+ break;
+ res = res->next;
+ }
+ kfree(irq);
+
+ res->next = quirk_isapnp_mpu_options(dev);
+
+ res = dev->independent;
+ res->irq = NULL;
+}
+
+static void quirk_isapnp_mpu_resources(struct pnp_dev *dev)
+{
+ struct pnp_option *res;
+
+ res = dev->dependent;
+ if (!res)
+ return;
+
+ while (res->next)
+ res = res->next;
+
+ res->next = quirk_isapnp_mpu_options(dev);
+}
#include <linux/pci.h>
@@ -205,6 +312,11 @@ static struct pnp_fixup pnp_fixups[] = {
{"CTL0043", quirk_sb16audio_resources},
{"CTL0044", quirk_sb16audio_resources},
{"CTL0045", quirk_sb16audio_resources},
+ /* Add IRQ-less MPU options */
+ {"ADS7151", quirk_ad1815_mpu_resources},
+ {"ADS7181", quirk_isapnp_mpu_resources},
+ {"AZT0002", quirk_isapnp_mpu_resources},
+ /* PnP resources that might overlap PCI BARs */
{"PNP0c01", quirk_system_pci_resources},
{"PNP0c02", quirk_system_pci_resources},
{""}
@@ -212,20 +324,16 @@ static struct pnp_fixup pnp_fixups[] = {
void pnp_fixup_device(struct pnp_dev *dev)
{
- int i = 0;
- void (*quirk)(struct pnp_dev *);
-
- while (*pnp_fixups[i].id) {
- if (compare_pnp_id(dev->id, pnp_fixups[i].id)) {
- quirk = pnp_fixups[i].quirk_function;
+ struct pnp_fixup *f;
+ for (f = pnp_fixups; *f->id; f++) {
+ if (!compare_pnp_id(dev->id, f->id))
+ continue;
#ifdef DEBUG
- dev_dbg(&dev->dev, "calling ");
- print_fn_descriptor_symbol("%s()\n",
- (unsigned long) *quirk);
+ dev_dbg(&dev->dev, "%s: calling ", f->id);
+ print_fn_descriptor_symbol("%s\n",
+ (unsigned long) f->quirk_function);
#endif
- (*quirk)(dev);
- }
- i++;
+ f->quirk_function(dev);
}
}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 2041620d5682..390b50096e30 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -28,7 +28,7 @@ static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some
* option registration
*/
-static struct pnp_option *pnp_build_option(int priority)
+struct pnp_option *pnp_build_option(int priority)
{
struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 3eba85ed729c..95b076c18c07 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -45,10 +45,10 @@ void pnp_eisa_id_to_string(u32 id, char *str)
str[0] = 'A' + ((id >> 26) & 0x3f) - 1;
str[1] = 'A' + ((id >> 21) & 0x1f) - 1;
str[2] = 'A' + ((id >> 16) & 0x1f) - 1;
- str[3] = hex_asc((id >> 12) & 0xf);
- str[4] = hex_asc((id >> 8) & 0xf);
- str[5] = hex_asc((id >> 4) & 0xf);
- str[6] = hex_asc((id >> 0) & 0xf);
+ str[3] = hex_asc_hi(id >> 8);
+ str[4] = hex_asc_lo(id >> 8);
+ str[5] = hex_asc_hi(id);
+ str[6] = hex_asc_lo(id);
str[7] = '\0';
}