diff options
Diffstat (limited to 'drivers/pnp/resource.c')
-rw-r--r-- | drivers/pnp/resource.c | 361 |
1 files changed, 293 insertions, 68 deletions
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index e50ebcffb96..2041620d568 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -53,6 +53,8 @@ struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev) if (dev->independent) dev_err(&dev->dev, "independent resource already registered\n"); dev->independent = option; + + dev_dbg(&dev->dev, "new independent option\n"); return option; } @@ -70,12 +72,18 @@ struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, parent->next = option; } else dev->dependent = option; + + dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority); return option; } -int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) +int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_irq *data) { struct pnp_irq *ptr; +#ifdef DEBUG + char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */ +#endif ptr = option->irq; while (ptr && ptr->next) @@ -94,10 +102,17 @@ int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) pcibios_penalize_isa_irq(i, 0); } #endif + +#ifdef DEBUG + bitmap_scnprintf(buf, sizeof(buf), data->map, PNP_IRQ_NR); + dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf, + data->flags); +#endif return 0; } -int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) +int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_dma *data) { struct pnp_dma *ptr; @@ -109,10 +124,13 @@ int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) else option->dma = data; + dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", data->map, + data->flags); return 0; } -int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) +int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_port *data) { struct pnp_port *ptr; @@ -124,10 +142,14 @@ int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) else option->port = data; + dev_dbg(&dev->dev, " io " + "min %#x max %#x align %d size %d flags %#x\n", + data->min, data->max, data->align, data->size, data->flags); return 0; } -int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) +int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, + struct pnp_mem *data) { struct pnp_mem *ptr; @@ -138,6 +160,10 @@ int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) ptr->next = data; else option->mem = data; + + dev_dbg(&dev->dev, " mem " + "min %#x max %#x align %d size %d flags %#x\n", + data->min, data->max, data->align, data->size, data->flags); return 0; } @@ -213,17 +239,18 @@ void pnp_free_option(struct pnp_option *option) #define cannot_compare(flags) \ ((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED)) -int pnp_check_port(struct pnp_dev *dev, int idx) +int pnp_check_port(struct pnp_dev *dev, struct resource *res) { - int tmp; + int i; struct pnp_dev *tdev; + struct resource *tres; resource_size_t *port, *end, *tport, *tend; - port = &dev->res.port_resource[idx].start; - end = &dev->res.port_resource[idx].end; + port = &res->start; + end = &res->end; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.port_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is already in use, skip if the @@ -234,18 +261,18 @@ int pnp_check_port(struct pnp_dev *dev, int idx) } /* check if the resource is reserved */ - for (tmp = 0; tmp < 8; tmp++) { - int rport = pnp_reserve_io[tmp << 1]; - int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1; + for (i = 0; i < 8; i++) { + int rport = pnp_reserve_io[i << 1]; + int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1; if (ranged_conflict(port, end, &rport, &rend)) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) { - if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) { - tport = &dev->res.port_resource[tmp].start; - tend = &dev->res.port_resource[tmp].end; + for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) { + if (tres != res && tres->flags & IORESOURCE_IO) { + tport = &tres->start; + tend = &tres->end; if (ranged_conflict(port, end, tport, tend)) return 0; } @@ -255,13 +282,14 @@ int pnp_check_port(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { - if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { - if (cannot_compare - (tdev->res.port_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(tdev, IORESOURCE_IO, i)); + i++) { + if (tres->flags & IORESOURCE_IO) { + if (cannot_compare(tres->flags)) continue; - tport = &tdev->res.port_resource[tmp].start; - tend = &tdev->res.port_resource[tmp].end; + tport = &tres->start; + tend = &tres->end; if (ranged_conflict(port, end, tport, tend)) return 0; } @@ -271,17 +299,18 @@ int pnp_check_port(struct pnp_dev *dev, int idx) return 1; } -int pnp_check_mem(struct pnp_dev *dev, int idx) +int pnp_check_mem(struct pnp_dev *dev, struct resource *res) { - int tmp; + int i; struct pnp_dev *tdev; + struct resource *tres; resource_size_t *addr, *end, *taddr, *tend; - addr = &dev->res.mem_resource[idx].start; - end = &dev->res.mem_resource[idx].end; + addr = &res->start; + end = &res->end; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.mem_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is already in use, skip if the @@ -292,18 +321,18 @@ int pnp_check_mem(struct pnp_dev *dev, int idx) } /* check if the resource is reserved */ - for (tmp = 0; tmp < 8; tmp++) { - int raddr = pnp_reserve_mem[tmp << 1]; - int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1; + for (i = 0; i < 8; i++) { + int raddr = pnp_reserve_mem[i << 1]; + int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1; if (ranged_conflict(addr, end, &raddr, &rend)) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) { - if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { - taddr = &dev->res.mem_resource[tmp].start; - tend = &dev->res.mem_resource[tmp].end; + for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) { + if (tres != res && tres->flags & IORESOURCE_MEM) { + taddr = &tres->start; + tend = &tres->end; if (ranged_conflict(addr, end, taddr, tend)) return 0; } @@ -313,13 +342,14 @@ int pnp_check_mem(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { - if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { - if (cannot_compare - (tdev->res.mem_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(tdev, IORESOURCE_MEM, i)); + i++) { + if (tres->flags & IORESOURCE_MEM) { + if (cannot_compare(tres->flags)) continue; - taddr = &tdev->res.mem_resource[tmp].start; - tend = &tdev->res.mem_resource[tmp].end; + taddr = &tres->start; + tend = &tres->end; if (ranged_conflict(addr, end, taddr, tend)) return 0; } @@ -334,14 +364,17 @@ static irqreturn_t pnp_test_handler(int irq, void *dev_id) return IRQ_HANDLED; } -int pnp_check_irq(struct pnp_dev *dev, int idx) +int pnp_check_irq(struct pnp_dev *dev, struct resource *res) { - int tmp; + int i; struct pnp_dev *tdev; - resource_size_t *irq = &dev->res.irq_resource[idx].start; + struct resource *tres; + resource_size_t *irq; + + irq = &res->start; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.irq_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is valid */ @@ -349,15 +382,15 @@ int pnp_check_irq(struct pnp_dev *dev, int idx) return 0; /* check if the resource is reserved */ - for (tmp = 0; tmp < 16; tmp++) { - if (pnp_reserve_irq[tmp] == *irq) + for (i = 0; i < 16; i++) { + if (pnp_reserve_irq[i] == *irq) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) { - if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { - if (dev->res.irq_resource[tmp].start == *irq) + for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) { + if (tres != res && tres->flags & IORESOURCE_IRQ) { + if (tres->start == *irq) return 0; } } @@ -388,12 +421,13 @@ int pnp_check_irq(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { - if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { - if (cannot_compare - (tdev->res.irq_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i)); + i++) { + if (tres->flags & IORESOURCE_IRQ) { + if (cannot_compare(tres->flags)) continue; - if ((tdev->res.irq_resource[tmp].start == *irq)) + if (tres->start == *irq) return 0; } } @@ -402,15 +436,18 @@ int pnp_check_irq(struct pnp_dev *dev, int idx) return 1; } -int pnp_check_dma(struct pnp_dev *dev, int idx) +int pnp_check_dma(struct pnp_dev *dev, struct resource *res) { #ifndef CONFIG_IA64 - int tmp; + int i; struct pnp_dev *tdev; - resource_size_t *dma = &dev->res.dma_resource[idx].start; + struct resource *tres; + resource_size_t *dma; + + dma = &res->start; /* if the resource doesn't exist, don't complain about it */ - if (cannot_compare(dev->res.dma_resource[idx].flags)) + if (cannot_compare(res->flags)) return 1; /* check if the resource is valid */ @@ -418,15 +455,15 @@ int pnp_check_dma(struct pnp_dev *dev, int idx) return 0; /* check if the resource is reserved */ - for (tmp = 0; tmp < 8; tmp++) { - if (pnp_reserve_dma[tmp] == *dma) + for (i = 0; i < 8; i++) { + if (pnp_reserve_dma[i] == *dma) return 0; } /* check for internal conflicts */ - for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) { - if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { - if (dev->res.dma_resource[tmp].start == *dma) + for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) { + if (tres != res && tres->flags & IORESOURCE_DMA) { + if (tres->start == *dma) return 0; } } @@ -443,12 +480,13 @@ int pnp_check_dma(struct pnp_dev *dev, int idx) pnp_for_each_dev(tdev) { if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { - if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { - if (cannot_compare - (tdev->res.dma_resource[tmp].flags)) + for (i = 0; + (tres = pnp_get_resource(tdev, IORESOURCE_DMA, i)); + i++) { + if (tres->flags & IORESOURCE_DMA) { + if (cannot_compare(tres->flags)) continue; - if ((tdev->res.dma_resource[tmp].start == *dma)) + if (tres->start == *dma) return 0; } } @@ -461,6 +499,193 @@ int pnp_check_dma(struct pnp_dev *dev, int idx) #endif } +struct pnp_resource *pnp_get_pnp_resource(struct pnp_dev *dev, + unsigned int type, unsigned int num) +{ + struct pnp_resource_table *res = dev->res; + + switch (type) { + case IORESOURCE_IO: + if (num >= PNP_MAX_PORT) + return NULL; + return &res->port[num]; + case IORESOURCE_MEM: + if (num >= PNP_MAX_MEM) + return NULL; + return &res->mem[num]; + case IORESOURCE_IRQ: + if (num >= PNP_MAX_IRQ) + return NULL; + return &res->irq[num]; + case IORESOURCE_DMA: + if (num >= PNP_MAX_DMA) + return NULL; + return &res->dma[num]; + } + return NULL; +} + +struct resource *pnp_get_resource(struct pnp_dev *dev, + unsigned int type, unsigned int num) +{ + struct pnp_resource *pnp_res; + + pnp_res = pnp_get_pnp_resource(dev, type, num); + if (pnp_res) + return &pnp_res->res; + + return NULL; +} +EXPORT_SYMBOL(pnp_get_resource); + +static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev, int type) +{ + struct pnp_resource *pnp_res; + int i; + + switch (type) { + case IORESOURCE_IO: + for (i = 0; i < PNP_MAX_PORT; i++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, i); + if (pnp_res && !pnp_resource_valid(&pnp_res->res)) + return pnp_res; + } + break; + case IORESOURCE_MEM: + for (i = 0; i < PNP_MAX_MEM; i++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, i); + if (pnp_res && !pnp_resource_valid(&pnp_res->res)) + return pnp_res; + } + break; + case IORESOURCE_IRQ: + for (i = 0; i < PNP_MAX_IRQ; i++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, i); + if (pnp_res && !pnp_resource_valid(&pnp_res->res)) + return pnp_res; + } + break; + case IORESOURCE_DMA: + for (i = 0; i < PNP_MAX_DMA; i++) { + pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, i); + if (pnp_res && !pnp_resource_valid(&pnp_res->res)) + return pnp_res; + } + break; + } + return NULL; +} + +struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, + int flags) +{ + struct pnp_resource *pnp_res; + struct resource *res; + static unsigned char warned; + + pnp_res = pnp_new_resource(dev, IORESOURCE_IRQ); + if (!pnp_res) { + if (!warned) { + dev_err(&dev->dev, "can't add resource for IRQ %d\n", + irq); + warned = 1; + } + return NULL; + } + + res = &pnp_res->res; + res->flags = IORESOURCE_IRQ | flags; + res->start = irq; + res->end = irq; + + dev_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags); + return pnp_res; +} + +struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, + int flags) +{ + struct pnp_resource *pnp_res; + struct resource *res; + static unsigned char warned; + + pnp_res = pnp_new_resource(dev, IORESOURCE_DMA); + if (!pnp_res) { + if (!warned) { + dev_err(&dev->dev, "can't add resource for DMA %d\n", + dma); + warned = 1; + } + return NULL; + } + + res = &pnp_res->res; + res->flags = IORESOURCE_DMA | flags; + res->start = dma; + res->end = dma; + + dev_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags); + return pnp_res; +} + +struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev, + resource_size_t start, + resource_size_t end, int flags) +{ + struct pnp_resource *pnp_res; + struct resource *res; + static unsigned char warned; + + pnp_res = pnp_new_resource(dev, IORESOURCE_IO); + if (!pnp_res) { + if (!warned) { + dev_err(&dev->dev, "can't add resource for IO " + "%#llx-%#llx\n",(unsigned long long) start, + (unsigned long long) end); + warned = 1; + } + return NULL; + } + + res = &pnp_res->res; + res->flags = IORESOURCE_IO | flags; + res->start = start; + res->end = end; + + dev_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n", + (unsigned long long) start, (unsigned long long) end, flags); + return pnp_res; +} + +struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev, + resource_size_t start, + resource_size_t end, int flags) +{ + struct pnp_resource *pnp_res; + struct resource *res; + static unsigned char warned; + + pnp_res = pnp_new_resource(dev, IORESOURCE_MEM); + if (!pnp_res) { + if (!warned) { + dev_err(&dev->dev, "can't add resource for MEM " + "%#llx-%#llx\n",(unsigned long long) start, + (unsigned long long) end); + warned = 1; + } + return NULL; + } + + res = &pnp_res->res; + res->flags = IORESOURCE_MEM | flags; + res->start = start; + res->end = end; + + dev_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n", + (unsigned long long) start, (unsigned long long) end, flags); + return pnp_res; +} + /* format is: pnp_reserve_irq=irq1[,irq2] .... */ static int __init pnp_setup_reserve_irq(char *str) { |