Commit d89c83be authored by Adam Belay's avatar Adam Belay

[PNP]: Resource flags update

This patch reorganizes resource flags to ensure that manual resource
settings are properly recognized.  This fix is necessary for many ALSA
drivers.  It also prevents comparisons between unset resource
structures.  The bug was discovered by Rene Herman
<rene.herman@keyaccess.nl>, who also wrote an initial version of this
patch.  I made further improvements to ensure that the pnp subsystem 
was compatible with this initial change.
parent 7bc01bc6
...@@ -1039,17 +1039,17 @@ static int isapnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table * ...@@ -1039,17 +1039,17 @@ static int isapnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table *
isapnp_cfg_begin(dev->card->number, dev->number); isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1; dev->active = 1;
for (tmp = 0; tmp < PNP_MAX_PORT && res->port_resource[tmp].flags & IORESOURCE_IO; tmp++) for (tmp = 0; tmp < PNP_MAX_PORT && (res->port_resource[tmp].flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO; tmp++)
isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), res->port_resource[tmp].start); isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), res->port_resource[tmp].start);
for (tmp = 0; tmp < PNP_MAX_IRQ && res->irq_resource[tmp].flags & IORESOURCE_IRQ; tmp++) { for (tmp = 0; tmp < PNP_MAX_IRQ && (res->irq_resource[tmp].flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ; tmp++) {
int irq = res->irq_resource[tmp].start; int irq = res->irq_resource[tmp].start;
if (irq == 2) if (irq == 2)
irq = 9; irq = 9;
isapnp_write_byte(ISAPNP_CFG_IRQ+(tmp<<1), irq); isapnp_write_byte(ISAPNP_CFG_IRQ+(tmp<<1), irq);
} }
for (tmp = 0; tmp < PNP_MAX_DMA && res->dma_resource[tmp].flags & IORESOURCE_DMA; tmp++) for (tmp = 0; tmp < PNP_MAX_DMA && (res->dma_resource[tmp].flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA; tmp++)
isapnp_write_byte(ISAPNP_CFG_DMA+tmp, res->dma_resource[tmp].start); isapnp_write_byte(ISAPNP_CFG_DMA+tmp, res->dma_resource[tmp].start);
for (tmp = 0; tmp < PNP_MAX_MEM && res->mem_resource[tmp].flags & IORESOURCE_MEM; tmp++) for (tmp = 0; tmp < PNP_MAX_MEM && (res->mem_resource[tmp].flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM; tmp++)
isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<2), (res->mem_resource[tmp].start >> 8) & 0xffff); isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<2), (res->mem_resource[tmp].start >> 8) & 0xffff);
/* FIXME: We aren't handling 32bit mems properly here */ /* FIXME: We aren't handling 32bit mems properly here */
isapnp_activate(dev->number); isapnp_activate(dev->number);
......
...@@ -223,25 +223,25 @@ void pnp_init_resource_table(struct pnp_resource_table *table) ...@@ -223,25 +223,25 @@ void pnp_init_resource_table(struct pnp_resource_table *table)
table->irq_resource[idx].name = NULL; table->irq_resource[idx].name = NULL;
table->irq_resource[idx].start = -1; table->irq_resource[idx].start = -1;
table->irq_resource[idx].end = -1; table->irq_resource[idx].end = -1;
table->irq_resource[idx].flags = IORESOURCE_AUTO | IORESOURCE_UNSET; table->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
} }
for (idx = 0; idx < PNP_MAX_DMA; idx++) { for (idx = 0; idx < PNP_MAX_DMA; idx++) {
table->dma_resource[idx].name = NULL; table->dma_resource[idx].name = NULL;
table->dma_resource[idx].start = -1; table->dma_resource[idx].start = -1;
table->dma_resource[idx].end = -1; table->dma_resource[idx].end = -1;
table->dma_resource[idx].flags = IORESOURCE_AUTO | IORESOURCE_UNSET; table->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
} }
for (idx = 0; idx < PNP_MAX_PORT; idx++) { for (idx = 0; idx < PNP_MAX_PORT; idx++) {
table->port_resource[idx].name = NULL; table->port_resource[idx].name = NULL;
table->port_resource[idx].start = 0; table->port_resource[idx].start = 0;
table->port_resource[idx].end = 0; table->port_resource[idx].end = 0;
table->port_resource[idx].flags = IORESOURCE_AUTO | IORESOURCE_UNSET; table->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
} }
for (idx = 0; idx < PNP_MAX_MEM; idx++) { for (idx = 0; idx < PNP_MAX_MEM; idx++) {
table->mem_resource[idx].name = NULL; table->mem_resource[idx].name = NULL;
table->mem_resource[idx].start = 0; table->mem_resource[idx].start = 0;
table->mem_resource[idx].end = 0; table->mem_resource[idx].end = 0;
table->mem_resource[idx].flags = IORESOURCE_AUTO | IORESOURCE_UNSET; table->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
} }
} }
...@@ -258,28 +258,28 @@ static void pnp_clean_resource_table(struct pnp_resource_table * res) ...@@ -258,28 +258,28 @@ static void pnp_clean_resource_table(struct pnp_resource_table * res)
continue; continue;
res->irq_resource[idx].start = -1; res->irq_resource[idx].start = -1;
res->irq_resource[idx].end = -1; res->irq_resource[idx].end = -1;
res->irq_resource[idx].flags = IORESOURCE_AUTO | IORESOURCE_UNSET; res->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
} }
for (idx = 0; idx < PNP_MAX_DMA; idx++) { for (idx = 0; idx < PNP_MAX_DMA; idx++) {
if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO)) if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
continue; continue;
res->dma_resource[idx].start = -1; res->dma_resource[idx].start = -1;
res->dma_resource[idx].end = -1; res->dma_resource[idx].end = -1;
res->dma_resource[idx].flags = IORESOURCE_AUTO | IORESOURCE_UNSET; res->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
} }
for (idx = 0; idx < PNP_MAX_PORT; idx++) { for (idx = 0; idx < PNP_MAX_PORT; idx++) {
if (!(res->port_resource[idx].flags & IORESOURCE_AUTO)) if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
continue; continue;
res->port_resource[idx].start = 0; res->port_resource[idx].start = 0;
res->port_resource[idx].end = 0; res->port_resource[idx].end = 0;
res->port_resource[idx].flags = IORESOURCE_AUTO | IORESOURCE_UNSET; res->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
} }
for (idx = 0; idx < PNP_MAX_MEM; idx++) { for (idx = 0; idx < PNP_MAX_MEM; idx++) {
if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO)) if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
continue; continue;
res->mem_resource[idx].start = 0; res->mem_resource[idx].start = 0;
res->mem_resource[idx].end = 0; res->mem_resource[idx].end = 0;
res->mem_resource[idx].flags = IORESOURCE_AUTO | IORESOURCE_UNSET; res->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
} }
} }
...@@ -550,7 +550,7 @@ void pnp_resource_change(struct resource *resource, unsigned long start, unsigne ...@@ -550,7 +550,7 @@ void pnp_resource_change(struct resource *resource, unsigned long start, unsigne
{ {
if (resource == NULL) if (resource == NULL)
return; return;
resource->flags &= ~IORESOURCE_AUTO; resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
resource->start = start; resource->start = start;
resource->end = start + size - 1; resource->end = start + size - 1;
} }
......
...@@ -49,7 +49,7 @@ static void ...@@ -49,7 +49,7 @@ static void
pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq) pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
{ {
int i = 0; int i = 0;
while ((res->irq_resource[i].flags & IORESOURCE_IRQ) && i < PNP_MAX_IRQ) i++; while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_IRQ) i++;
if (i < PNP_MAX_IRQ) { if (i < PNP_MAX_IRQ) {
res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
if (irq == -1) { if (irq == -1) {
...@@ -65,7 +65,7 @@ static void ...@@ -65,7 +65,7 @@ static void
pnpbios_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma) pnpbios_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
{ {
int i = 0; int i = 0;
while ((res->dma_resource[i].flags & IORESOURCE_DMA) && i < PNP_MAX_DMA) i++; while (!(res->dma_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_DMA) i++;
if (i < PNP_MAX_DMA) { if (i < PNP_MAX_DMA) {
res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
if (dma == -1) { if (dma == -1) {
...@@ -81,7 +81,7 @@ static void ...@@ -81,7 +81,7 @@ static void
pnpbios_parse_allocated_ioresource(struct pnp_resource_table * res, int io, int len) pnpbios_parse_allocated_ioresource(struct pnp_resource_table * res, int io, int len)
{ {
int i = 0; int i = 0;
while ((res->port_resource[i].flags & IORESOURCE_IO) && i < PNP_MAX_PORT) i++; while (!(res->port_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_PORT) i++;
if (i < PNP_MAX_PORT) { if (i < PNP_MAX_PORT) {
res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
if (len <= 0 || (io + len -1) >= 0x10003) { if (len <= 0 || (io + len -1) >= 0x10003) {
...@@ -97,7 +97,7 @@ static void ...@@ -97,7 +97,7 @@ static void
pnpbios_parse_allocated_memresource(struct pnp_resource_table * res, int mem, int len) pnpbios_parse_allocated_memresource(struct pnp_resource_table * res, int mem, int len)
{ {
int i = 0; int i = 0;
while ((res->mem_resource[i].flags & IORESOURCE_MEM) && i < PNP_MAX_MEM) i++; while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_MEM) i++;
if (i < PNP_MAX_MEM) { if (i < PNP_MAX_MEM) {
res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
if (len <= 0) { if (len <= 0) {
......
...@@ -241,6 +241,9 @@ void pnp_free_option(struct pnp_option *option) ...@@ -241,6 +241,9 @@ void pnp_free_option(struct pnp_option *option)
(*(enda) >= *(startb) && *(enda) <= *(endb)) || \ (*(enda) >= *(startb) && *(enda) <= *(endb)) || \
(*(starta) < *(startb) && *(enda) > *(endb))) (*(starta) < *(startb) && *(enda) > *(endb)))
#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, int idx)
{ {
int tmp; int tmp;
...@@ -250,7 +253,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx) ...@@ -250,7 +253,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
end = &dev->res.port_resource[idx].end; end = &dev->res.port_resource[idx].end;
/* if the resource doesn't exist, don't complain about it */ /* if the resource doesn't exist, don't complain about it */
if (dev->res.port_resource[idx].flags & IORESOURCE_UNSET) if (cannot_compare(dev->res.port_resource[idx].flags))
return 1; return 1;
/* check if the resource is already in use, skip if the /* check if the resource is already in use, skip if the
...@@ -284,7 +287,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx) ...@@ -284,7 +287,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
continue; continue;
for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
if (pnp_port_flags(dev, tmp) & IORESOURCE_DISABLED) if (cannot_compare(tdev->res.port_resource[tmp].flags))
continue; continue;
tport = &tdev->res.port_resource[tmp].start; tport = &tdev->res.port_resource[tmp].start;
tend = &tdev->res.port_resource[tmp].end; tend = &tdev->res.port_resource[tmp].end;
...@@ -306,7 +309,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx) ...@@ -306,7 +309,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
end = &dev->res.mem_resource[idx].end; end = &dev->res.mem_resource[idx].end;
/* if the resource doesn't exist, don't complain about it */ /* if the resource doesn't exist, don't complain about it */
if (dev->res.mem_resource[idx].flags & IORESOURCE_UNSET) if (cannot_compare(dev->res.mem_resource[idx].flags))
return 1; return 1;
/* check if the resource is already in use, skip if the /* check if the resource is already in use, skip if the
...@@ -340,7 +343,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx) ...@@ -340,7 +343,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
continue; continue;
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
if (pnp_mem_flags(dev, tmp) & IORESOURCE_DISABLED) if (cannot_compare(tdev->res.mem_resource[tmp].flags))
continue; continue;
taddr = &tdev->res.mem_resource[tmp].start; taddr = &tdev->res.mem_resource[tmp].start;
tend = &tdev->res.mem_resource[tmp].end; tend = &tdev->res.mem_resource[tmp].end;
...@@ -365,7 +368,7 @@ int pnp_check_irq(struct pnp_dev * dev, int idx) ...@@ -365,7 +368,7 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
unsigned long * irq = &dev->res.irq_resource[idx].start; unsigned long * irq = &dev->res.irq_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */ /* if the resource doesn't exist, don't complain about it */
if (dev->res.irq_resource[idx].flags & IORESOURCE_UNSET) if (cannot_compare(dev->res.irq_resource[idx].flags))
return 1; return 1;
/* check if the resource is valid */ /* check if the resource is valid */
...@@ -411,7 +414,7 @@ int pnp_check_irq(struct pnp_dev * dev, int idx) ...@@ -411,7 +414,7 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
continue; continue;
for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if (pnp_irq_flags(dev, tmp) & IORESOURCE_DISABLED) if (cannot_compare(tdev->res.irq_resource[tmp].flags))
continue; continue;
if ((tdev->res.irq_resource[tmp].start == *irq)) if ((tdev->res.irq_resource[tmp].start == *irq))
return 0; return 0;
...@@ -429,7 +432,7 @@ int pnp_check_dma(struct pnp_dev * dev, int idx) ...@@ -429,7 +432,7 @@ int pnp_check_dma(struct pnp_dev * dev, int idx)
unsigned long * dma = &dev->res.dma_resource[idx].start; unsigned long * dma = &dev->res.dma_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */ /* if the resource doesn't exist, don't complain about it */
if (dev->res.dma_resource[idx].flags & IORESOURCE_UNSET) if (cannot_compare(dev->res.dma_resource[idx].flags))
return 1; return 1;
/* check if the resource is valid */ /* check if the resource is valid */
...@@ -464,7 +467,7 @@ int pnp_check_dma(struct pnp_dev * dev, int idx) ...@@ -464,7 +467,7 @@ int pnp_check_dma(struct pnp_dev * dev, int idx)
continue; continue;
for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (pnp_dma_flags(dev, tmp) & IORESOURCE_DISABLED) if (cannot_compare(tdev->res.dma_resource[tmp].flags))
continue; continue;
if ((tdev->res.dma_resource[tmp].start == *dma)) if ((tdev->res.dma_resource[tmp].start == *dma))
return 0; return 0;
......
...@@ -33,7 +33,9 @@ struct pnp_dev; ...@@ -33,7 +33,9 @@ struct pnp_dev;
#define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start) #define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start)
#define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end) #define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end)
#define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags) #define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags)
#define pnp_port_valid(dev,bar) (pnp_port_flags((dev),(bar)) & IORESOURCE_IO) #define pnp_port_valid(dev,bar) \
((pnp_port_flags((dev),(bar)) & (IORESOURCE_IO | IORESOURCE_UNSET)) \
== IORESOURCE_IO)
#define pnp_port_len(dev,bar) \ #define pnp_port_len(dev,bar) \
((pnp_port_start((dev),(bar)) == 0 && \ ((pnp_port_start((dev),(bar)) == 0 && \
pnp_port_end((dev),(bar)) == \ pnp_port_end((dev),(bar)) == \
...@@ -45,7 +47,9 @@ struct pnp_dev; ...@@ -45,7 +47,9 @@ struct pnp_dev;
#define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start) #define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start)
#define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end) #define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end)
#define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags) #define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags)
#define pnp_mem_valid(dev,bar) (pnp_mem_flags((dev),(bar)) & IORESOURCE_MEM) #define pnp_mem_valid(dev,bar) \
((pnp_mem_flags((dev),(bar)) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \
== IORESOURCE_MEM)
#define pnp_mem_len(dev,bar) \ #define pnp_mem_len(dev,bar) \
((pnp_mem_start((dev),(bar)) == 0 && \ ((pnp_mem_start((dev),(bar)) == 0 && \
pnp_mem_end((dev),(bar)) == \ pnp_mem_end((dev),(bar)) == \
...@@ -56,11 +60,15 @@ struct pnp_dev; ...@@ -56,11 +60,15 @@ struct pnp_dev;
#define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start) #define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start)
#define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags) #define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags)
#define pnp_irq_valid(dev,bar) (pnp_irq_flags((dev),(bar)) & IORESOURCE_IRQ) #define pnp_irq_valid(dev,bar) \
((pnp_irq_flags((dev),(bar)) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \
== IORESOURCE_IRQ)
#define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start) #define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start)
#define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags) #define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags)
#define pnp_dma_valid(dev,bar) (pnp_dma_flags((dev),(bar)) & IORESOURCE_DMA) #define pnp_dma_valid(dev,bar) \
((pnp_dma_flags((dev),(bar)) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \
== IORESOURCE_DMA)
#define PNP_PORT_FLAG_16BITADDR (1<<0) #define PNP_PORT_FLAG_16BITADDR (1<<0)
#define PNP_PORT_FLAG_FIXED (1<<1) #define PNP_PORT_FLAG_FIXED (1<<1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment