diff options
-rw-r--r-- | drivers/pnp/base.h | 93 | ||||
-rw-r--r-- | drivers/pnp/core.c | 4 | ||||
-rw-r--r-- | drivers/pnp/interface.c | 75 | ||||
-rw-r--r-- | drivers/pnp/isapnp/core.c | 72 | ||||
-rw-r--r-- | drivers/pnp/manager.c | 145 | ||||
-rw-r--r-- | drivers/pnp/pnpacpi/rsparser.c | 93 | ||||
-rw-r--r-- | drivers/pnp/pnpbios/rsparser.c | 67 | ||||
-rw-r--r-- | drivers/pnp/quirks.c | 290 | ||||
-rw-r--r-- | drivers/pnp/resource.c | 268 | ||||
-rw-r--r-- | drivers/pnp/support.c | 92 | ||||
-rw-r--r-- | include/linux/pnp.h | 6 |
11 files changed, 571 insertions, 634 deletions
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index 360c6385686c..e3fa9a2d9a3d 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h | |||
@@ -1,3 +1,8 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
3 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
4 | */ | ||
5 | |||
1 | extern spinlock_t pnp_lock; | 6 | extern spinlock_t pnp_lock; |
2 | void *pnp_alloc(long size); | 7 | void *pnp_alloc(long size); |
3 | 8 | ||
@@ -25,8 +30,6 @@ struct pnp_port { | |||
25 | resource_size_t align; /* align boundary */ | 30 | resource_size_t align; /* align boundary */ |
26 | resource_size_t size; /* size of range */ | 31 | resource_size_t size; /* size of range */ |
27 | unsigned char flags; /* port flags */ | 32 | unsigned char flags; /* port flags */ |
28 | unsigned char pad; /* pad */ | ||
29 | struct pnp_port *next; /* next port */ | ||
30 | }; | 33 | }; |
31 | 34 | ||
32 | #define PNP_IRQ_NR 256 | 35 | #define PNP_IRQ_NR 256 |
@@ -35,14 +38,11 @@ typedef struct { DECLARE_BITMAP(bits, PNP_IRQ_NR); } pnp_irq_mask_t; | |||
35 | struct pnp_irq { | 38 | struct pnp_irq { |
36 | pnp_irq_mask_t map; /* bitmap for IRQ lines */ | 39 | pnp_irq_mask_t map; /* bitmap for IRQ lines */ |
37 | unsigned char flags; /* IRQ flags */ | 40 | unsigned char flags; /* IRQ flags */ |
38 | unsigned char pad; /* pad */ | ||
39 | struct pnp_irq *next; /* next IRQ */ | ||
40 | }; | 41 | }; |
41 | 42 | ||
42 | struct pnp_dma { | 43 | struct pnp_dma { |
43 | unsigned char map; /* bitmask for DMA channels */ | 44 | unsigned char map; /* bitmask for DMA channels */ |
44 | unsigned char flags; /* DMA flags */ | 45 | unsigned char flags; /* DMA flags */ |
45 | struct pnp_dma *next; /* next port */ | ||
46 | }; | 46 | }; |
47 | 47 | ||
48 | struct pnp_mem { | 48 | struct pnp_mem { |
@@ -51,44 +51,91 @@ struct pnp_mem { | |||
51 | resource_size_t align; /* align boundary */ | 51 | resource_size_t align; /* align boundary */ |
52 | resource_size_t size; /* size of range */ | 52 | resource_size_t size; /* size of range */ |
53 | unsigned char flags; /* memory flags */ | 53 | unsigned char flags; /* memory flags */ |
54 | unsigned char pad; /* pad */ | ||
55 | struct pnp_mem *next; /* next memory resource */ | ||
56 | }; | 54 | }; |
57 | 55 | ||
56 | #define PNP_OPTION_DEPENDENT 0x80000000 | ||
57 | #define PNP_OPTION_SET_MASK 0xffff | ||
58 | #define PNP_OPTION_SET_SHIFT 12 | ||
59 | #define PNP_OPTION_PRIORITY_MASK 0xfff | ||
60 | #define PNP_OPTION_PRIORITY_SHIFT 0 | ||
61 | |||
58 | #define PNP_RES_PRIORITY_PREFERRED 0 | 62 | #define PNP_RES_PRIORITY_PREFERRED 0 |
59 | #define PNP_RES_PRIORITY_ACCEPTABLE 1 | 63 | #define PNP_RES_PRIORITY_ACCEPTABLE 1 |
60 | #define PNP_RES_PRIORITY_FUNCTIONAL 2 | 64 | #define PNP_RES_PRIORITY_FUNCTIONAL 2 |
61 | #define PNP_RES_PRIORITY_INVALID 65535 | 65 | #define PNP_RES_PRIORITY_INVALID PNP_OPTION_PRIORITY_MASK |
62 | 66 | ||
63 | struct pnp_option { | 67 | struct pnp_option { |
64 | unsigned short priority; /* priority */ | 68 | struct list_head list; |
65 | struct pnp_port *port; /* first port */ | 69 | unsigned int flags; /* independent/dependent, set, priority */ |
66 | struct pnp_irq *irq; /* first IRQ */ | 70 | |
67 | struct pnp_dma *dma; /* first DMA */ | 71 | unsigned long type; /* IORESOURCE_{IO,MEM,IRQ,DMA} */ |
68 | struct pnp_mem *mem; /* first memory resource */ | 72 | union { |
69 | struct pnp_option *next; /* used to chain dependent resources */ | 73 | struct pnp_port port; |
74 | struct pnp_irq irq; | ||
75 | struct pnp_dma dma; | ||
76 | struct pnp_mem mem; | ||
77 | } u; | ||
70 | }; | 78 | }; |
71 | 79 | ||
72 | struct pnp_option *pnp_build_option(int priority); | 80 | int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags, |
73 | struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev); | ||
74 | struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, | ||
75 | int priority); | ||
76 | int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, | ||
77 | pnp_irq_mask_t *map, unsigned char flags); | 81 | pnp_irq_mask_t *map, unsigned char flags); |
78 | int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, | 82 | int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags, |
79 | unsigned char map, unsigned char flags); | 83 | unsigned char map, unsigned char flags); |
80 | int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, | 84 | int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags, |
81 | resource_size_t min, resource_size_t max, | 85 | resource_size_t min, resource_size_t max, |
82 | resource_size_t align, resource_size_t size, | 86 | resource_size_t align, resource_size_t size, |
83 | unsigned char flags); | 87 | unsigned char flags); |
84 | int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, | 88 | int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags, |
85 | resource_size_t min, resource_size_t max, | 89 | resource_size_t min, resource_size_t max, |
86 | resource_size_t align, resource_size_t size, | 90 | resource_size_t align, resource_size_t size, |
87 | unsigned char flags); | 91 | unsigned char flags); |
92 | |||
93 | static inline int pnp_option_is_dependent(struct pnp_option *option) | ||
94 | { | ||
95 | return option->flags & PNP_OPTION_DEPENDENT ? 1 : 0; | ||
96 | } | ||
97 | |||
98 | static inline unsigned int pnp_option_set(struct pnp_option *option) | ||
99 | { | ||
100 | return (option->flags >> PNP_OPTION_SET_SHIFT) & PNP_OPTION_SET_MASK; | ||
101 | } | ||
102 | |||
103 | static inline unsigned int pnp_option_priority(struct pnp_option *option) | ||
104 | { | ||
105 | return (option->flags >> PNP_OPTION_PRIORITY_SHIFT) & | ||
106 | PNP_OPTION_PRIORITY_MASK; | ||
107 | } | ||
108 | |||
109 | static inline unsigned int pnp_new_dependent_set(struct pnp_dev *dev, | ||
110 | int priority) | ||
111 | { | ||
112 | unsigned int flags; | ||
113 | |||
114 | if (priority > PNP_RES_PRIORITY_FUNCTIONAL) { | ||
115 | dev_warn(&dev->dev, "invalid dependent option priority %d " | ||
116 | "clipped to %d", priority, | ||
117 | PNP_RES_PRIORITY_INVALID); | ||
118 | priority = PNP_RES_PRIORITY_INVALID; | ||
119 | } | ||
120 | |||
121 | flags = PNP_OPTION_DEPENDENT | | ||
122 | ((dev->num_dependent_sets & PNP_OPTION_SET_MASK) << | ||
123 | PNP_OPTION_SET_SHIFT) | | ||
124 | ((priority & PNP_OPTION_PRIORITY_MASK) << | ||
125 | PNP_OPTION_PRIORITY_SHIFT); | ||
126 | |||
127 | dev->num_dependent_sets++; | ||
128 | |||
129 | return flags; | ||
130 | } | ||
131 | |||
132 | char *pnp_option_priority_name(struct pnp_option *option); | ||
133 | void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option); | ||
134 | |||
88 | void pnp_init_resources(struct pnp_dev *dev); | 135 | void pnp_init_resources(struct pnp_dev *dev); |
89 | 136 | ||
90 | void pnp_fixup_device(struct pnp_dev *dev); | 137 | void pnp_fixup_device(struct pnp_dev *dev); |
91 | void pnp_free_option(struct pnp_option *option); | 138 | void pnp_free_options(struct pnp_dev *dev); |
92 | int __pnp_add_device(struct pnp_dev *dev); | 139 | int __pnp_add_device(struct pnp_dev *dev); |
93 | void __pnp_remove_device(struct pnp_dev *dev); | 140 | void __pnp_remove_device(struct pnp_dev *dev); |
94 | 141 | ||
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 7182da92aec3..a411582bcd72 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c | |||
@@ -118,10 +118,9 @@ static void pnp_release_device(struct device *dmdev) | |||
118 | { | 118 | { |
119 | struct pnp_dev *dev = to_pnp_dev(dmdev); | 119 | struct pnp_dev *dev = to_pnp_dev(dmdev); |
120 | 120 | ||
121 | pnp_free_option(dev->independent); | ||
122 | pnp_free_option(dev->dependent); | ||
123 | pnp_free_ids(dev); | 121 | pnp_free_ids(dev); |
124 | pnp_free_resources(dev); | 122 | pnp_free_resources(dev); |
123 | pnp_free_options(dev); | ||
125 | kfree(dev); | 124 | kfree(dev); |
126 | } | 125 | } |
127 | 126 | ||
@@ -135,6 +134,7 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid | |||
135 | return NULL; | 134 | return NULL; |
136 | 135 | ||
137 | INIT_LIST_HEAD(&dev->resources); | 136 | INIT_LIST_HEAD(&dev->resources); |
137 | INIT_LIST_HEAD(&dev->options); | ||
138 | dev->protocol = protocol; | 138 | dev->protocol = protocol; |
139 | dev->number = id; | 139 | dev->number = id; |
140 | dev->dma_mask = DMA_24BIT_MASK; | 140 | dev->dma_mask = DMA_24BIT_MASK; |
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 7a9fb5544b80..a876ecf7028c 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c | |||
@@ -3,6 +3,8 @@ | |||
3 | * | 3 | * |
4 | * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz> | 4 | * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz> |
5 | * Copyright 2002 Adam Belay <ambx1@neo.rr.com> | 5 | * Copyright 2002 Adam Belay <ambx1@neo.rr.com> |
6 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
7 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
6 | */ | 8 | */ |
7 | 9 | ||
8 | #include <linux/pnp.h> | 10 | #include <linux/pnp.h> |
@@ -184,39 +186,22 @@ static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space, | |||
184 | } | 186 | } |
185 | 187 | ||
186 | static void pnp_print_option(pnp_info_buffer_t * buffer, char *space, | 188 | static void pnp_print_option(pnp_info_buffer_t * buffer, char *space, |
187 | struct pnp_option *option, int dep) | 189 | struct pnp_option *option) |
188 | { | 190 | { |
189 | char *s; | 191 | switch (option->type) { |
190 | struct pnp_port *port; | 192 | case IORESOURCE_IO: |
191 | struct pnp_irq *irq; | 193 | pnp_print_port(buffer, space, &option->u.port); |
192 | struct pnp_dma *dma; | 194 | break; |
193 | struct pnp_mem *mem; | 195 | case IORESOURCE_MEM: |
194 | 196 | pnp_print_mem(buffer, space, &option->u.mem); | |
195 | if (dep) { | 197 | break; |
196 | switch (option->priority) { | 198 | case IORESOURCE_IRQ: |
197 | case PNP_RES_PRIORITY_PREFERRED: | 199 | pnp_print_irq(buffer, space, &option->u.irq); |
198 | s = "preferred"; | 200 | break; |
199 | break; | 201 | case IORESOURCE_DMA: |
200 | case PNP_RES_PRIORITY_ACCEPTABLE: | 202 | pnp_print_dma(buffer, space, &option->u.dma); |
201 | s = "acceptable"; | 203 | break; |
202 | break; | ||
203 | case PNP_RES_PRIORITY_FUNCTIONAL: | ||
204 | s = "functional"; | ||
205 | break; | ||
206 | default: | ||
207 | s = "invalid"; | ||
208 | } | ||
209 | pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s); | ||
210 | } | 204 | } |
211 | |||
212 | for (port = option->port; port; port = port->next) | ||
213 | pnp_print_port(buffer, space, port); | ||
214 | for (irq = option->irq; irq; irq = irq->next) | ||
215 | pnp_print_irq(buffer, space, irq); | ||
216 | for (dma = option->dma; dma; dma = dma->next) | ||
217 | pnp_print_dma(buffer, space, dma); | ||
218 | for (mem = option->mem; mem; mem = mem->next) | ||
219 | pnp_print_mem(buffer, space, mem); | ||
220 | } | 205 | } |
221 | 206 | ||
222 | static ssize_t pnp_show_options(struct device *dmdev, | 207 | static ssize_t pnp_show_options(struct device *dmdev, |
@@ -224,9 +209,9 @@ static ssize_t pnp_show_options(struct device *dmdev, | |||
224 | { | 209 | { |
225 | struct pnp_dev *dev = to_pnp_dev(dmdev); | 210 | struct pnp_dev *dev = to_pnp_dev(dmdev); |
226 | pnp_info_buffer_t *buffer; | 211 | pnp_info_buffer_t *buffer; |
227 | struct pnp_option *independent = dev->independent; | 212 | struct pnp_option *option; |
228 | struct pnp_option *dependent = dev->dependent; | 213 | int ret, dep = 0, set = 0; |
229 | int ret, dep = 1; | 214 | char *indent; |
230 | 215 | ||
231 | buffer = pnp_alloc(sizeof(pnp_info_buffer_t)); | 216 | buffer = pnp_alloc(sizeof(pnp_info_buffer_t)); |
232 | if (!buffer) | 217 | if (!buffer) |
@@ -235,14 +220,24 @@ static ssize_t pnp_show_options(struct device *dmdev, | |||
235 | buffer->len = PAGE_SIZE; | 220 | buffer->len = PAGE_SIZE; |
236 | buffer->buffer = buf; | 221 | buffer->buffer = buf; |
237 | buffer->curr = buffer->buffer; | 222 | buffer->curr = buffer->buffer; |
238 | if (independent) | ||
239 | pnp_print_option(buffer, "", independent, 0); | ||
240 | 223 | ||
241 | while (dependent) { | 224 | list_for_each_entry(option, &dev->options, list) { |
242 | pnp_print_option(buffer, " ", dependent, dep); | 225 | if (pnp_option_is_dependent(option)) { |
243 | dependent = dependent->next; | 226 | indent = " "; |
244 | dep++; | 227 | if (!dep || pnp_option_set(option) != set) { |
228 | set = pnp_option_set(option); | ||
229 | dep = 1; | ||
230 | pnp_printf(buffer, "Dependent: %02i - " | ||
231 | "Priority %s\n", set, | ||
232 | pnp_option_priority_name(option)); | ||
233 | } | ||
234 | } else { | ||
235 | dep = 0; | ||
236 | indent = ""; | ||
237 | } | ||
238 | pnp_print_option(buffer, indent, option); | ||
245 | } | 239 | } |
240 | |||
246 | ret = (buffer->curr - buf); | 241 | ret = (buffer->curr - buf); |
247 | kfree(buffer); | 242 | kfree(buffer); |
248 | return ret; | 243 | return ret; |
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index 53cc4d6133e6..101a835e8759 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c | |||
@@ -429,7 +429,7 @@ static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card, | |||
429 | * Add IRQ resource to resources list. | 429 | * Add IRQ resource to resources list. |
430 | */ | 430 | */ |
431 | static void __init isapnp_parse_irq_resource(struct pnp_dev *dev, | 431 | static void __init isapnp_parse_irq_resource(struct pnp_dev *dev, |
432 | struct pnp_option *option, | 432 | unsigned int option_flags, |
433 | int size) | 433 | int size) |
434 | { | 434 | { |
435 | unsigned char tmp[3]; | 435 | unsigned char tmp[3]; |
@@ -446,27 +446,27 @@ static void __init isapnp_parse_irq_resource(struct pnp_dev *dev, | |||
446 | if (size > 2) | 446 | if (size > 2) |
447 | flags = tmp[2]; | 447 | flags = tmp[2]; |
448 | 448 | ||
449 | pnp_register_irq_resource(dev, option, &map, flags); | 449 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
450 | } | 450 | } |
451 | 451 | ||
452 | /* | 452 | /* |
453 | * Add DMA resource to resources list. | 453 | * Add DMA resource to resources list. |
454 | */ | 454 | */ |
455 | static void __init isapnp_parse_dma_resource(struct pnp_dev *dev, | 455 | static void __init isapnp_parse_dma_resource(struct pnp_dev *dev, |
456 | struct pnp_option *option, | 456 | unsigned int option_flags, |
457 | int size) | 457 | int size) |
458 | { | 458 | { |
459 | unsigned char tmp[2]; | 459 | unsigned char tmp[2]; |
460 | 460 | ||
461 | isapnp_peek(tmp, size); | 461 | isapnp_peek(tmp, size); |
462 | pnp_register_dma_resource(dev, option, tmp[0], tmp[1]); | 462 | pnp_register_dma_resource(dev, option_flags, tmp[0], tmp[1]); |
463 | } | 463 | } |
464 | 464 | ||
465 | /* | 465 | /* |
466 | * Add port resource to resources list. | 466 | * Add port resource to resources list. |
467 | */ | 467 | */ |
468 | static void __init isapnp_parse_port_resource(struct pnp_dev *dev, | 468 | static void __init isapnp_parse_port_resource(struct pnp_dev *dev, |
469 | struct pnp_option *option, | 469 | unsigned int option_flags, |
470 | int size) | 470 | int size) |
471 | { | 471 | { |
472 | unsigned char tmp[7]; | 472 | unsigned char tmp[7]; |
@@ -479,14 +479,15 @@ static void __init isapnp_parse_port_resource(struct pnp_dev *dev, | |||
479 | align = tmp[5]; | 479 | align = tmp[5]; |
480 | len = tmp[6]; | 480 | len = tmp[6]; |
481 | flags = tmp[0] ? IORESOURCE_IO_16BIT_ADDR : 0; | 481 | flags = tmp[0] ? IORESOURCE_IO_16BIT_ADDR : 0; |
482 | pnp_register_port_resource(dev, option, min, max, align, len, flags); | 482 | pnp_register_port_resource(dev, option_flags, |
483 | min, max, align, len, flags); | ||
483 | } | 484 | } |
484 | 485 | ||
485 | /* | 486 | /* |
486 | * Add fixed port resource to resources list. | 487 | * Add fixed port resource to resources list. |
487 | */ | 488 | */ |
488 | static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev, | 489 | static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev, |
489 | struct pnp_option *option, | 490 | unsigned int option_flags, |
490 | int size) | 491 | int size) |
491 | { | 492 | { |
492 | unsigned char tmp[3]; | 493 | unsigned char tmp[3]; |
@@ -495,7 +496,7 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev, | |||
495 | isapnp_peek(tmp, size); | 496 | isapnp_peek(tmp, size); |
496 | base = (tmp[1] << 8) | tmp[0]; | 497 | base = (tmp[1] << 8) | tmp[0]; |
497 | len = tmp[2]; | 498 | len = tmp[2]; |
498 | pnp_register_port_resource(dev, option, base, base, 0, len, | 499 | pnp_register_port_resource(dev, option_flags, base, base, 0, len, |
499 | IORESOURCE_IO_FIXED); | 500 | IORESOURCE_IO_FIXED); |
500 | } | 501 | } |
501 | 502 | ||
@@ -503,7 +504,7 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev, | |||
503 | * Add memory resource to resources list. | 504 | * Add memory resource to resources list. |
504 | */ | 505 | */ |
505 | static void __init isapnp_parse_mem_resource(struct pnp_dev *dev, | 506 | static void __init isapnp_parse_mem_resource(struct pnp_dev *dev, |
506 | struct pnp_option *option, | 507 | unsigned int option_flags, |
507 | int size) | 508 | int size) |
508 | { | 509 | { |
509 | unsigned char tmp[9]; | 510 | unsigned char tmp[9]; |
@@ -516,14 +517,15 @@ static void __init isapnp_parse_mem_resource(struct pnp_dev *dev, | |||
516 | align = (tmp[6] << 8) | tmp[5]; | 517 | align = (tmp[6] << 8) | tmp[5]; |
517 | len = ((tmp[8] << 8) | tmp[7]) << 8; | 518 | len = ((tmp[8] << 8) | tmp[7]) << 8; |
518 | flags = tmp[0]; | 519 | flags = tmp[0]; |
519 | pnp_register_mem_resource(dev, option, min, max, align, len, flags); | 520 | pnp_register_mem_resource(dev, option_flags, |
521 | min, max, align, len, flags); | ||
520 | } | 522 | } |
521 | 523 | ||
522 | /* | 524 | /* |
523 | * Add 32-bit memory resource to resources list. | 525 | * Add 32-bit memory resource to resources list. |
524 | */ | 526 | */ |
525 | static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev, | 527 | static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev, |
526 | struct pnp_option *option, | 528 | unsigned int option_flags, |
527 | int size) | 529 | int size) |
528 | { | 530 | { |
529 | unsigned char tmp[17]; | 531 | unsigned char tmp[17]; |
@@ -536,14 +538,15 @@ static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev, | |||
536 | align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9]; | 538 | align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9]; |
537 | len = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13]; | 539 | len = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13]; |
538 | flags = tmp[0]; | 540 | flags = tmp[0]; |
539 | pnp_register_mem_resource(dev, option, min, max, align, len, flags); | 541 | pnp_register_mem_resource(dev, option_flags, |
542 | min, max, align, len, flags); | ||
540 | } | 543 | } |
541 | 544 | ||
542 | /* | 545 | /* |
543 | * Add 32-bit fixed memory resource to resources list. | 546 | * Add 32-bit fixed memory resource to resources list. |
544 | */ | 547 | */ |
545 | static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev, | 548 | static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev, |
546 | struct pnp_option *option, | 549 | unsigned int option_flags, |
547 | int size) | 550 | int size) |
548 | { | 551 | { |
549 | unsigned char tmp[9]; | 552 | unsigned char tmp[9]; |
@@ -554,7 +557,7 @@ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev, | |||
554 | base = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1]; | 557 | base = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1]; |
555 | len = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; | 558 | len = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; |
556 | flags = tmp[0]; | 559 | flags = tmp[0]; |
557 | pnp_register_mem_resource(dev, option, base, base, 0, len, flags); | 560 | pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags); |
558 | } | 561 | } |
559 | 562 | ||
560 | /* | 563 | /* |
@@ -584,18 +587,14 @@ static int __init isapnp_create_device(struct pnp_card *card, | |||
584 | { | 587 | { |
585 | int number = 0, skip = 0, priority, compat = 0; | 588 | int number = 0, skip = 0, priority, compat = 0; |
586 | unsigned char type, tmp[17]; | 589 | unsigned char type, tmp[17]; |
587 | struct pnp_option *option, *option_independent; | 590 | unsigned int option_flags; |
588 | struct pnp_dev *dev; | 591 | struct pnp_dev *dev; |
589 | u32 eisa_id; | 592 | u32 eisa_id; |
590 | char id[8]; | 593 | char id[8]; |
591 | 594 | ||
592 | if ((dev = isapnp_parse_device(card, size, number++)) == NULL) | 595 | if ((dev = isapnp_parse_device(card, size, number++)) == NULL) |
593 | return 1; | 596 | return 1; |
594 | option_independent = option = pnp_register_independent_option(dev); | 597 | option_flags = 0; |
595 | if (!option) { | ||
596 | kfree(dev); | ||
597 | return 1; | ||
598 | } | ||
599 | pnp_add_card_device(card, dev); | 598 | pnp_add_card_device(card, dev); |
600 | 599 | ||
601 | while (1) { | 600 | while (1) { |
@@ -612,12 +611,7 @@ static int __init isapnp_create_device(struct pnp_card *card, | |||
612 | return 1; | 611 | return 1; |
613 | size = 0; | 612 | size = 0; |
614 | skip = 0; | 613 | skip = 0; |
615 | option = pnp_register_independent_option(dev); | 614 | option_flags = 0; |
616 | option_independent = option; | ||
617 | if (!option) { | ||
618 | kfree(dev); | ||
619 | return 1; | ||
620 | } | ||
621 | pnp_add_card_device(card, dev); | 615 | pnp_add_card_device(card, dev); |
622 | } else { | 616 | } else { |
623 | skip = 1; | 617 | skip = 1; |
@@ -638,13 +632,13 @@ static int __init isapnp_create_device(struct pnp_card *card, | |||
638 | case _STAG_IRQ: | 632 | case _STAG_IRQ: |
639 | if (size < 2 || size > 3) | 633 | if (size < 2 || size > 3) |
640 | goto __skip; | 634 | goto __skip; |
641 | isapnp_parse_irq_resource(dev, option, size); | 635 | isapnp_parse_irq_resource(dev, option_flags, size); |
642 | size = 0; | 636 | size = 0; |
643 | break; | 637 | break; |
644 | case _STAG_DMA: | 638 | case _STAG_DMA: |
645 | if (size != 2) | 639 | if (size != 2) |
646 | goto __skip; | 640 | goto __skip; |
647 | isapnp_parse_dma_resource(dev, option, size); | 641 | isapnp_parse_dma_resource(dev, option_flags, size); |
648 | size = 0; | 642 | size = 0; |
649 | break; | 643 | break; |
650 | case _STAG_STARTDEP: | 644 | case _STAG_STARTDEP: |
@@ -656,29 +650,24 @@ static int __init isapnp_create_device(struct pnp_card *card, | |||
656 | priority = tmp[0]; | 650 | priority = tmp[0]; |
657 | size = 0; | 651 | size = 0; |
658 | } | 652 | } |
659 | option = pnp_register_dependent_option(dev, priority); | 653 | option_flags = pnp_new_dependent_set(dev, priority); |
660 | if (!option) | ||
661 | return 1; | ||
662 | break; | 654 | break; |
663 | case _STAG_ENDDEP: | 655 | case _STAG_ENDDEP: |
664 | if (size != 0) | 656 | if (size != 0) |
665 | goto __skip; | 657 | goto __skip; |
666 | if (option_independent == option) | 658 | option_flags = 0; |
667 | dev_warn(&dev->dev, "missing " | ||
668 | "_STAG_STARTDEP tag\n"); | ||
669 | option = option_independent; | ||
670 | dev_dbg(&dev->dev, "end dependent options\n"); | ||
671 | break; | 659 | break; |
672 | case _STAG_IOPORT: | 660 | case _STAG_IOPORT: |
673 | if (size != 7) | 661 | if (size != 7) |
674 | goto __skip; | 662 | goto __skip; |
675 | isapnp_parse_port_resource(dev, option, size); | 663 | isapnp_parse_port_resource(dev, option_flags, size); |
676 | size = 0; | 664 | size = 0; |
677 | break; | 665 | break; |
678 | case _STAG_FIXEDIO: | 666 | case _STAG_FIXEDIO: |
679 | if (size != 3) | 667 | if (size != 3) |
680 | goto __skip; | 668 | goto __skip; |
681 | isapnp_parse_fixed_port_resource(dev, option, size); | 669 | isapnp_parse_fixed_port_resource(dev, option_flags, |
670 | size); | ||
682 | size = 0; | 671 | size = 0; |
683 | break; | 672 | break; |
684 | case _STAG_VENDOR: | 673 | case _STAG_VENDOR: |
@@ -686,7 +675,7 @@ static int __init isapnp_create_device(struct pnp_card *card, | |||
686 | case _LTAG_MEMRANGE: | 675 | case _LTAG_MEMRANGE: |
687 | if (size != 9) | 676 | if (size != 9) |
688 | goto __skip; | 677 | goto __skip; |
689 | isapnp_parse_mem_resource(dev, option, size); | 678 | isapnp_parse_mem_resource(dev, option_flags, size); |
690 | size = 0; | 679 | size = 0; |
691 | break; | 680 | break; |
692 | case _LTAG_ANSISTR: | 681 | case _LTAG_ANSISTR: |
@@ -701,13 +690,14 @@ static int __init isapnp_create_device(struct pnp_card *card, | |||
701 | case _LTAG_MEM32RANGE: | 690 | case _LTAG_MEM32RANGE: |
702 | if (size != 17) | 691 | if (size != 17) |
703 | goto __skip; | 692 | goto __skip; |
704 | isapnp_parse_mem32_resource(dev, option, size); | 693 | isapnp_parse_mem32_resource(dev, option_flags, size); |
705 | size = 0; | 694 | size = 0; |
706 | break; | 695 | break; |
707 | case _LTAG_FIXEDMEM32RANGE: | 696 | case _LTAG_FIXEDMEM32RANGE: |
708 | if (size != 9) | 697 | if (size != 9) |
709 | goto __skip; | 698 | goto __skip; |
710 | isapnp_parse_fixed_mem32_resource(dev, option, size); | 699 | isapnp_parse_fixed_mem32_resource(dev, option_flags, |
700 | size); | ||
711 | size = 0; | 701 | size = 0; |
712 | break; | 702 | break; |
713 | case _STAG_END: | 703 | case _STAG_END: |
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index a20accb5ef8f..b526eaad3f6c 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c | |||
@@ -3,6 +3,8 @@ | |||
3 | * | 3 | * |
4 | * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> | 4 | * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> |
5 | * Copyright 2003 Adam Belay <ambx1@neo.rr.com> | 5 | * Copyright 2003 Adam Belay <ambx1@neo.rr.com> |
6 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
7 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
6 | */ | 8 | */ |
7 | 9 | ||
8 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
@@ -228,102 +230,51 @@ static void pnp_clean_resource_table(struct pnp_dev *dev) | |||
228 | /** | 230 | /** |
229 | * pnp_assign_resources - assigns resources to the device based on the specified dependent number | 231 | * pnp_assign_resources - assigns resources to the device based on the specified dependent number |
230 | * @dev: pointer to the desired device | 232 | * @dev: pointer to the desired device |
231 | * @depnum: the dependent function number | 233 | * @set: the dependent function number |
232 | * | ||
233 | * Only set depnum to 0 if the device does not have dependent options. | ||
234 | */ | 234 | */ |
235 | static int pnp_assign_resources(struct pnp_dev *dev, int depnum) | 235 | static int pnp_assign_resources(struct pnp_dev *dev, int set) |
236 | { | 236 | { |
237 | struct pnp_port *port; | 237 | struct pnp_option *option; |
238 | struct pnp_mem *mem; | ||
239 | struct pnp_irq *irq; | ||
240 | struct pnp_dma *dma; | ||
241 | int nport = 0, nmem = 0, nirq = 0, ndma = 0; | 238 | int nport = 0, nmem = 0, nirq = 0, ndma = 0; |
239 | int ret = 0; | ||
242 | 240 | ||
243 | dbg_pnp_show_resources(dev, "before pnp_assign_resources"); | 241 | dev_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set); |
244 | mutex_lock(&pnp_res_mutex); | 242 | mutex_lock(&pnp_res_mutex); |
245 | pnp_clean_resource_table(dev); | 243 | pnp_clean_resource_table(dev); |
246 | if (dev->independent) { | ||
247 | dev_dbg(&dev->dev, "assigning independent options\n"); | ||
248 | port = dev->independent->port; | ||
249 | mem = dev->independent->mem; | ||
250 | irq = dev->independent->irq; | ||
251 | dma = dev->independent->dma; | ||
252 | while (port) { | ||
253 | if (pnp_assign_port(dev, port, nport) < 0) | ||
254 | goto fail; | ||
255 | nport++; | ||
256 | port = port->next; | ||
257 | } | ||
258 | while (mem) { | ||
259 | if (pnp_assign_mem(dev, mem, nmem) < 0) | ||
260 | goto fail; | ||
261 | nmem++; | ||
262 | mem = mem->next; | ||
263 | } | ||
264 | while (irq) { | ||
265 | if (pnp_assign_irq(dev, irq, nirq) < 0) | ||
266 | goto fail; | ||
267 | nirq++; | ||
268 | irq = irq->next; | ||
269 | } | ||
270 | while (dma) { | ||
271 | if (pnp_assign_dma(dev, dma, ndma) < 0) | ||
272 | goto fail; | ||
273 | ndma++; | ||
274 | dma = dma->next; | ||
275 | } | ||
276 | } | ||
277 | 244 | ||
278 | if (depnum) { | 245 | list_for_each_entry(option, &dev->options, list) { |
279 | struct pnp_option *dep; | 246 | if (pnp_option_is_dependent(option) && |
280 | int i; | 247 | pnp_option_set(option) != set) |
281 | 248 | continue; | |
282 | dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum); | 249 | |
283 | for (i = 1, dep = dev->dependent; i < depnum; | 250 | switch (option->type) { |
284 | i++, dep = dep->next) | 251 | case IORESOURCE_IO: |
285 | if (!dep) | 252 | ret = pnp_assign_port(dev, &option->u.port, nport++); |
286 | goto fail; | 253 | break; |
287 | port = dep->port; | 254 | case IORESOURCE_MEM: |
288 | mem = dep->mem; | 255 | ret = pnp_assign_mem(dev, &option->u.mem, nmem++); |
289 | irq = dep->irq; | 256 | break; |
290 | dma = dep->dma; | 257 | case IORESOURCE_IRQ: |
291 | while (port) { | 258 | ret = pnp_assign_irq(dev, &option->u.irq, nirq++); |
292 | if (pnp_assign_port(dev, port, nport) < 0) | 259 | break; |
293 | goto fail; | 260 | case IORESOURCE_DMA: |
294 | nport++; | 261 | ret = pnp_assign_dma(dev, &option->u.dma, ndma++); |
295 | port = port->next; | 262 | break; |
296 | } | 263 | default: |
297 | while (mem) { | 264 | ret = -EINVAL; |
298 | if (pnp_assign_mem(dev, mem, nmem) < 0) | 265 | break; |
299 | goto fail; | ||
300 | nmem++; | ||
301 | mem = mem->next; | ||
302 | } | ||
303 | while (irq) { | ||
304 | if (pnp_assign_irq(dev, irq, nirq) < 0) | ||
305 | goto fail; | ||
306 | nirq++; | ||
307 | irq = irq->next; | ||
308 | } | ||
309 | while (dma) { | ||
310 | if (pnp_assign_dma(dev, dma, ndma) < 0) | ||
311 | goto fail; | ||
312 | ndma++; | ||
313 | dma = dma->next; | ||
314 | } | 266 | } |
315 | } else if (dev->dependent) | 267 | if (ret < 0) |
316 | goto fail; | 268 | break; |
317 | 269 | } | |
318 | mutex_unlock(&pnp_res_mutex); | ||
319 | dbg_pnp_show_resources(dev, "after pnp_assign_resources"); | ||
320 | return 1; | ||
321 | 270 | ||
322 | fail: | ||
323 | pnp_clean_resource_table(dev); | ||
324 | mutex_unlock(&pnp_res_mutex); | 271 | mutex_unlock(&pnp_res_mutex); |
325 | dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)"); | 272 | if (ret < 0) { |
326 | return 0; | 273 | dev_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret); |
274 | pnp_clean_resource_table(dev); | ||
275 | } else | ||
276 | dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded"); | ||
277 | return ret; | ||
327 | } | 278 | } |
328 | 279 | ||
329 | /** | 280 | /** |
@@ -332,29 +283,25 @@ fail: | |||
332 | */ | 283 | */ |
333 | int pnp_auto_config_dev(struct pnp_dev *dev) | 284 | int pnp_auto_config_dev(struct pnp_dev *dev) |
334 | { | 285 | { |
335 | struct pnp_option *dep; | 286 | int i, ret; |
336 | int i = 1; | ||
337 | 287 | ||
338 | if (!pnp_can_configure(dev)) { | 288 | if (!pnp_can_configure(dev)) { |
339 | dev_dbg(&dev->dev, "configuration not supported\n"); | 289 | dev_dbg(&dev->dev, "configuration not supported\n"); |
340 | return -ENODEV; | 290 | return -ENODEV; |
341 | } | 291 | } |
342 | 292 | ||
343 | if (!dev->dependent) { | 293 | ret = pnp_assign_resources(dev, 0); |
344 | if (pnp_assign_resources(dev, 0)) | 294 | if (ret == 0) |
295 | return 0; | ||
296 | |||
297 | for (i = 1; i < dev->num_dependent_sets; i++) { | ||
298 | ret = pnp_assign_resources(dev, i); | ||
299 | if (ret == 0) | ||
345 | return 0; | 300 | return 0; |
346 | } else { | ||
347 | dep = dev->dependent; | ||
348 | do { | ||
349 | if (pnp_assign_resources(dev, i)) | ||
350 | return 0; | ||
351 | dep = dep->next; | ||
352 | i++; | ||
353 | } while (dep); | ||
354 | } | 301 | } |
355 | 302 | ||
356 | dev_err(&dev->dev, "unable to assign resources\n"); | 303 | dev_err(&dev->dev, "unable to assign resources\n"); |
357 | return -EBUSY; | 304 | return ret; |
358 | } | 305 | } |
359 | 306 | ||
360 | /** | 307 | /** |
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index e114b3d2b933..c2f59f4d20bc 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
@@ -407,7 +407,7 @@ int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) | |||
407 | } | 407 | } |
408 | 408 | ||
409 | static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, | 409 | static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, |
410 | struct pnp_option *option, | 410 | unsigned int option_flags, |
411 | struct acpi_resource_dma *p) | 411 | struct acpi_resource_dma *p) |
412 | { | 412 | { |
413 | int i; | 413 | int i; |
@@ -420,11 +420,11 @@ static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, | |||
420 | map |= 1 << p->channels[i]; | 420 | map |= 1 << p->channels[i]; |
421 | 421 | ||
422 | flags = dma_flags(p->type, p->bus_master, p->transfer); | 422 | flags = dma_flags(p->type, p->bus_master, p->transfer); |
423 | pnp_register_dma_resource(dev, option, map, flags); | 423 | pnp_register_dma_resource(dev, option_flags, map, flags); |
424 | } | 424 | } |
425 | 425 | ||
426 | static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, | 426 | static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, |
427 | struct pnp_option *option, | 427 | unsigned int option_flags, |
428 | struct acpi_resource_irq *p) | 428 | struct acpi_resource_irq *p) |
429 | { | 429 | { |
430 | int i; | 430 | int i; |
@@ -440,11 +440,11 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, | |||
440 | __set_bit(p->interrupts[i], map.bits); | 440 | __set_bit(p->interrupts[i], map.bits); |
441 | 441 | ||
442 | flags = irq_flags(p->triggering, p->polarity, p->sharable); | 442 | flags = irq_flags(p->triggering, p->polarity, p->sharable); |
443 | pnp_register_irq_resource(dev, option, &map, flags); | 443 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
444 | } | 444 | } |
445 | 445 | ||
446 | static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, | 446 | static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, |
447 | struct pnp_option *option, | 447 | unsigned int option_flags, |
448 | struct acpi_resource_extended_irq *p) | 448 | struct acpi_resource_extended_irq *p) |
449 | { | 449 | { |
450 | int i; | 450 | int i; |
@@ -467,11 +467,11 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, | |||
467 | } | 467 | } |
468 | 468 | ||
469 | flags = irq_flags(p->triggering, p->polarity, p->sharable); | 469 | flags = irq_flags(p->triggering, p->polarity, p->sharable); |
470 | pnp_register_irq_resource(dev, option, &map, flags); | 470 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
471 | } | 471 | } |
472 | 472 | ||
473 | static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, | 473 | static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, |
474 | struct pnp_option *option, | 474 | unsigned int option_flags, |
475 | struct acpi_resource_io *io) | 475 | struct acpi_resource_io *io) |
476 | { | 476 | { |
477 | unsigned char flags = 0; | 477 | unsigned char flags = 0; |
@@ -481,23 +481,23 @@ static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, | |||
481 | 481 | ||
482 | if (io->io_decode == ACPI_DECODE_16) | 482 | if (io->io_decode == ACPI_DECODE_16) |
483 | flags = IORESOURCE_IO_16BIT_ADDR; | 483 | flags = IORESOURCE_IO_16BIT_ADDR; |
484 | pnp_register_port_resource(dev, option, io->minimum, io->maximum, | 484 | pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, |
485 | io->alignment, io->address_length, flags); | 485 | io->alignment, io->address_length, flags); |
486 | } | 486 | } |
487 | 487 | ||
488 | static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, | 488 | static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, |
489 | struct pnp_option *option, | 489 | unsigned int option_flags, |
490 | struct acpi_resource_fixed_io *io) | 490 | struct acpi_resource_fixed_io *io) |
491 | { | 491 | { |
492 | if (io->address_length == 0) | 492 | if (io->address_length == 0) |
493 | return; | 493 | return; |
494 | 494 | ||
495 | pnp_register_port_resource(dev, option, io->address, io->address, 0, | 495 | pnp_register_port_resource(dev, option_flags, io->address, io->address, |
496 | io->address_length, IORESOURCE_IO_FIXED); | 496 | 0, io->address_length, IORESOURCE_IO_FIXED); |
497 | } | 497 | } |
498 | 498 | ||
499 | static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, | 499 | static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, |
500 | struct pnp_option *option, | 500 | unsigned int option_flags, |
501 | struct acpi_resource_memory24 *p) | 501 | struct acpi_resource_memory24 *p) |
502 | { | 502 | { |
503 | unsigned char flags = 0; | 503 | unsigned char flags = 0; |
@@ -507,12 +507,12 @@ static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, | |||
507 | 507 | ||
508 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) | 508 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
509 | flags = IORESOURCE_MEM_WRITEABLE; | 509 | flags = IORESOURCE_MEM_WRITEABLE; |
510 | pnp_register_mem_resource(dev, option, p->minimum, p->maximum, | 510 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, |
511 | p->alignment, p->address_length, flags); | 511 | p->alignment, p->address_length, flags); |
512 | } | 512 | } |
513 | 513 | ||
514 | static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, | 514 | static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, |
515 | struct pnp_option *option, | 515 | unsigned int option_flags, |
516 | struct acpi_resource_memory32 *p) | 516 | struct acpi_resource_memory32 *p) |
517 | { | 517 | { |
518 | unsigned char flags = 0; | 518 | unsigned char flags = 0; |
@@ -522,12 +522,12 @@ static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, | |||
522 | 522 | ||
523 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) | 523 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
524 | flags = IORESOURCE_MEM_WRITEABLE; | 524 | flags = IORESOURCE_MEM_WRITEABLE; |
525 | pnp_register_mem_resource(dev, option, p->minimum, p->maximum, | 525 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, |
526 | p->alignment, p->address_length, flags); | 526 | p->alignment, p->address_length, flags); |
527 | } | 527 | } |
528 | 528 | ||
529 | static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, | 529 | static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, |
530 | struct pnp_option *option, | 530 | unsigned int option_flags, |
531 | struct acpi_resource_fixed_memory32 *p) | 531 | struct acpi_resource_fixed_memory32 *p) |
532 | { | 532 | { |
533 | unsigned char flags = 0; | 533 | unsigned char flags = 0; |
@@ -537,12 +537,12 @@ static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, | |||
537 | 537 | ||
538 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) | 538 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
539 | flags = IORESOURCE_MEM_WRITEABLE; | 539 | flags = IORESOURCE_MEM_WRITEABLE; |
540 | pnp_register_mem_resource(dev, option, p->address, p->address, | 540 | pnp_register_mem_resource(dev, option_flags, p->address, p->address, |
541 | 0, p->address_length, flags); | 541 | 0, p->address_length, flags); |
542 | } | 542 | } |
543 | 543 | ||
544 | static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, | 544 | static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, |
545 | struct pnp_option *option, | 545 | unsigned int option_flags, |
546 | struct acpi_resource *r) | 546 | struct acpi_resource *r) |
547 | { | 547 | { |
548 | struct acpi_resource_address64 addr, *p = &addr; | 548 | struct acpi_resource_address64 addr, *p = &addr; |
@@ -562,18 +562,18 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, | |||
562 | if (p->resource_type == ACPI_MEMORY_RANGE) { | 562 | if (p->resource_type == ACPI_MEMORY_RANGE) { |
563 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) | 563 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) |
564 | flags = IORESOURCE_MEM_WRITEABLE; | 564 | flags = IORESOURCE_MEM_WRITEABLE; |
565 | pnp_register_mem_resource(dev, option, p->minimum, p->minimum, | 565 | pnp_register_mem_resource(dev, option_flags, p->minimum, |
566 | 0, p->address_length, flags); | 566 | p->minimum, 0, p->address_length, |
567 | flags); | ||
567 | } else if (p->resource_type == ACPI_IO_RANGE) | 568 | } else if (p->resource_type == ACPI_IO_RANGE) |
568 | pnp_register_port_resource(dev, option, p->minimum, p->minimum, | 569 | pnp_register_port_resource(dev, option_flags, p->minimum, |
569 | 0, p->address_length, | 570 | p->minimum, 0, p->address_length, |
570 | IORESOURCE_IO_FIXED); | 571 | IORESOURCE_IO_FIXED); |
571 | } | 572 | } |
572 | 573 | ||
573 | struct acpipnp_parse_option_s { | 574 | struct acpipnp_parse_option_s { |
574 | struct pnp_option *option; | ||
575 | struct pnp_option *option_independent; | ||
576 | struct pnp_dev *dev; | 575 | struct pnp_dev *dev; |
576 | unsigned int option_flags; | ||
577 | }; | 577 | }; |
578 | 578 | ||
579 | static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, | 579 | static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, |
@@ -582,15 +582,15 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, | |||
582 | int priority; | 582 | int priority; |
583 | struct acpipnp_parse_option_s *parse_data = data; | 583 | struct acpipnp_parse_option_s *parse_data = data; |
584 | struct pnp_dev *dev = parse_data->dev; | 584 | struct pnp_dev *dev = parse_data->dev; |
585 | struct pnp_option *option = parse_data->option; | 585 | unsigned int option_flags = parse_data->option_flags; |
586 | 586 | ||
587 | switch (res->type) { | 587 | switch (res->type) { |
588 | case ACPI_RESOURCE_TYPE_IRQ: | 588 | case ACPI_RESOURCE_TYPE_IRQ: |
589 | pnpacpi_parse_irq_option(dev, option, &res->data.irq); | 589 | pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq); |
590 | break; | 590 | break; |
591 | 591 | ||
592 | case ACPI_RESOURCE_TYPE_DMA: | 592 | case ACPI_RESOURCE_TYPE_DMA: |
593 | pnpacpi_parse_dma_option(dev, option, &res->data.dma); | 593 | pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma); |
594 | break; | 594 | break; |
595 | 595 | ||
596 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | 596 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
@@ -610,31 +610,19 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, | |||
610 | priority = PNP_RES_PRIORITY_INVALID; | 610 | priority = PNP_RES_PRIORITY_INVALID; |
611 | break; | 611 | break; |
612 | } | 612 | } |
613 | /* TBD: Consider performance/robustness bits */ | 613 | parse_data->option_flags = pnp_new_dependent_set(dev, priority); |
614 | option = pnp_register_dependent_option(dev, priority); | ||
615 | if (!option) | ||
616 | return AE_ERROR; | ||
617 | parse_data->option = option; | ||
618 | break; | 614 | break; |
619 | 615 | ||
620 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | 616 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: |
621 | /*only one EndDependentFn is allowed */ | 617 | parse_data->option_flags = 0; |
622 | if (!parse_data->option_independent) { | ||
623 | dev_warn(&dev->dev, "more than one EndDependentFn " | ||
624 | "in _PRS\n"); | ||
625 | return AE_ERROR; | ||
626 | } | ||
627 | parse_data->option = parse_data->option_independent; | ||
628 | parse_data->option_independent = NULL; | ||
629 | dev_dbg(&dev->dev, "end dependent options\n"); | ||
630 | break; | 618 | break; |
631 | 619 | ||
632 | case ACPI_RESOURCE_TYPE_IO: | 620 | case ACPI_RESOURCE_TYPE_IO: |
633 | pnpacpi_parse_port_option(dev, option, &res->data.io); | 621 | pnpacpi_parse_port_option(dev, option_flags, &res->data.io); |
634 | break; | 622 | break; |
635 | 623 | ||
636 | case ACPI_RESOURCE_TYPE_FIXED_IO: | 624 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
637 | pnpacpi_parse_fixed_port_option(dev, option, | 625 | pnpacpi_parse_fixed_port_option(dev, option_flags, |
638 | &res->data.fixed_io); | 626 | &res->data.fixed_io); |
639 | break; | 627 | break; |
640 | 628 | ||
@@ -643,29 +631,31 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, | |||
643 | break; | 631 | break; |
644 | 632 | ||
645 | case ACPI_RESOURCE_TYPE_MEMORY24: | 633 | case ACPI_RESOURCE_TYPE_MEMORY24: |
646 | pnpacpi_parse_mem24_option(dev, option, &res->data.memory24); | 634 | pnpacpi_parse_mem24_option(dev, option_flags, |
635 | &res->data.memory24); | ||
647 | break; | 636 | break; |
648 | 637 | ||
649 | case ACPI_RESOURCE_TYPE_MEMORY32: | 638 | case ACPI_RESOURCE_TYPE_MEMORY32: |
650 | pnpacpi_parse_mem32_option(dev, option, &res->data.memory32); | 639 | pnpacpi_parse_mem32_option(dev, option_flags, |
640 | &res->data.memory32); | ||
651 | break; | 641 | break; |
652 | 642 | ||
653 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | 643 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
654 | pnpacpi_parse_fixed_mem32_option(dev, option, | 644 | pnpacpi_parse_fixed_mem32_option(dev, option_flags, |
655 | &res->data.fixed_memory32); | 645 | &res->data.fixed_memory32); |
656 | break; | 646 | break; |
657 | 647 | ||
658 | case ACPI_RESOURCE_TYPE_ADDRESS16: | 648 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
659 | case ACPI_RESOURCE_TYPE_ADDRESS32: | 649 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
660 | case ACPI_RESOURCE_TYPE_ADDRESS64: | 650 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
661 | pnpacpi_parse_address_option(dev, option, res); | 651 | pnpacpi_parse_address_option(dev, option_flags, res); |
662 | break; | 652 | break; |
663 | 653 | ||
664 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: | 654 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: |
665 | break; | 655 | break; |
666 | 656 | ||
667 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: | 657 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
668 | pnpacpi_parse_ext_irq_option(dev, option, | 658 | pnpacpi_parse_ext_irq_option(dev, option_flags, |
669 | &res->data.extended_irq); | 659 | &res->data.extended_irq); |
670 | break; | 660 | break; |
671 | 661 | ||
@@ -689,12 +679,9 @@ int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) | |||
689 | 679 | ||
690 | dev_dbg(&dev->dev, "parse resource options\n"); | 680 | dev_dbg(&dev->dev, "parse resource options\n"); |
691 | 681 | ||
692 | parse_data.option = pnp_register_independent_option(dev); | ||
693 | if (!parse_data.option) | ||
694 | return -ENOMEM; | ||
695 | |||
696 | parse_data.option_independent = parse_data.option; | ||
697 | parse_data.dev = dev; | 682 | parse_data.dev = dev; |
683 | parse_data.option_flags = 0; | ||
684 | |||
698 | status = acpi_walk_resources(handle, METHOD_NAME__PRS, | 685 | status = acpi_walk_resources(handle, METHOD_NAME__PRS, |
699 | pnpacpi_option_resource, &parse_data); | 686 | pnpacpi_option_resource, &parse_data); |
700 | 687 | ||
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index db23ba78d39c..ca567671379e 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c | |||
@@ -216,7 +216,7 @@ len_err: | |||
216 | 216 | ||
217 | static __init void pnpbios_parse_mem_option(struct pnp_dev *dev, | 217 | static __init void pnpbios_parse_mem_option(struct pnp_dev *dev, |
218 | unsigned char *p, int size, | 218 | unsigned char *p, int size, |
219 | struct pnp_option *option) | 219 | unsigned int option_flags) |
220 | { | 220 | { |
221 | resource_size_t min, max, align, len; | 221 | resource_size_t min, max, align, len; |
222 | unsigned char flags; | 222 | unsigned char flags; |
@@ -226,12 +226,13 @@ static __init void pnpbios_parse_mem_option(struct pnp_dev *dev, | |||
226 | align = (p[9] << 8) | p[8]; | 226 | align = (p[9] << 8) | p[8]; |
227 | len = ((p[11] << 8) | p[10]) << 8; | 227 | len = ((p[11] << 8) | p[10]) << 8; |
228 | flags = p[3]; | 228 | flags = p[3]; |
229 | pnp_register_mem_resource(dev, option, min, max, align, len, flags); | 229 | pnp_register_mem_resource(dev, option_flags, min, max, align, len, |
230 | flags); | ||
230 | } | 231 | } |
231 | 232 | ||
232 | static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev, | 233 | static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev, |
233 | unsigned char *p, int size, | 234 | unsigned char *p, int size, |
234 | struct pnp_option *option) | 235 | unsigned int option_flags) |
235 | { | 236 | { |
236 | resource_size_t min, max, align, len; | 237 | resource_size_t min, max, align, len; |
237 | unsigned char flags; | 238 | unsigned char flags; |
@@ -241,12 +242,13 @@ static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev, | |||
241 | align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; | 242 | align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; |
242 | len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; | 243 | len = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; |
243 | flags = p[3]; | 244 | flags = p[3]; |
244 | pnp_register_mem_resource(dev, option, min, max, align, len, flags); | 245 | pnp_register_mem_resource(dev, option_flags, min, max, align, len, |
246 | flags); | ||
245 | } | 247 | } |
246 | 248 | ||
247 | static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev, | 249 | static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev, |
248 | unsigned char *p, int size, | 250 | unsigned char *p, int size, |
249 | struct pnp_option *option) | 251 | unsigned int option_flags) |
250 | { | 252 | { |
251 | resource_size_t base, len; | 253 | resource_size_t base, len; |
252 | unsigned char flags; | 254 | unsigned char flags; |
@@ -254,12 +256,12 @@ static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev, | |||
254 | base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; | 256 | base = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; |
255 | len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; | 257 | len = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; |
256 | flags = p[3]; | 258 | flags = p[3]; |
257 | pnp_register_mem_resource(dev, option, base, base, 0, len, flags); | 259 | pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags); |
258 | } | 260 | } |
259 | 261 | ||
260 | static __init void pnpbios_parse_irq_option(struct pnp_dev *dev, | 262 | static __init void pnpbios_parse_irq_option(struct pnp_dev *dev, |
261 | unsigned char *p, int size, | 263 | unsigned char *p, int size, |
262 | struct pnp_option *option) | 264 | unsigned int option_flags) |
263 | { | 265 | { |
264 | unsigned long bits; | 266 | unsigned long bits; |
265 | pnp_irq_mask_t map; | 267 | pnp_irq_mask_t map; |
@@ -273,19 +275,19 @@ static __init void pnpbios_parse_irq_option(struct pnp_dev *dev, | |||
273 | if (size > 2) | 275 | if (size > 2) |
274 | flags = p[3]; | 276 | flags = p[3]; |
275 | 277 | ||
276 | pnp_register_irq_resource(dev, option, &map, flags); | 278 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
277 | } | 279 | } |
278 | 280 | ||
279 | static __init void pnpbios_parse_dma_option(struct pnp_dev *dev, | 281 | static __init void pnpbios_parse_dma_option(struct pnp_dev *dev, |
280 | unsigned char *p, int size, | 282 | unsigned char *p, int size, |
281 | struct pnp_option *option) | 283 | unsigned int option_flags) |
282 | { | 284 | { |
283 | pnp_register_dma_resource(dev, option, p[1], p[2]); | 285 | pnp_register_dma_resource(dev, option_flags, p[1], p[2]); |
284 | } | 286 | } |
285 | 287 | ||
286 | static __init void pnpbios_parse_port_option(struct pnp_dev *dev, | 288 | static __init void pnpbios_parse_port_option(struct pnp_dev *dev, |
287 | unsigned char *p, int size, | 289 | unsigned char *p, int size, |
288 | struct pnp_option *option) | 290 | unsigned int option_flags) |
289 | { | 291 | { |
290 | resource_size_t min, max, align, len; | 292 | resource_size_t min, max, align, len; |
291 | unsigned char flags; | 293 | unsigned char flags; |
@@ -295,38 +297,35 @@ static __init void pnpbios_parse_port_option(struct pnp_dev *dev, | |||
295 | align = p[6]; | 297 | align = p[6]; |
296 | len = p[7]; | 298 | len = p[7]; |
297 | flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0; | 299 | flags = p[1] ? IORESOURCE_IO_16BIT_ADDR : 0; |
298 | pnp_register_port_resource(dev, option, min, max, align, len, flags); | 300 | pnp_register_port_resource(dev, option_flags, min, max, align, len, |
301 | flags); | ||
299 | } | 302 | } |
300 | 303 | ||
301 | static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev, | 304 | static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev, |
302 | unsigned char *p, int size, | 305 | unsigned char *p, int size, |
303 | struct pnp_option *option) | 306 | unsigned int option_flags) |
304 | { | 307 | { |
305 | resource_size_t base, len; | 308 | resource_size_t base, len; |
306 | 309 | ||
307 | base = (p[2] << 8) | p[1]; | 310 | base = (p[2] << 8) | p[1]; |
308 | len = p[3]; | 311 | len = p[3]; |
309 | pnp_register_port_resource(dev, option, base, base, 0, len, | 312 | pnp_register_port_resource(dev, option_flags, base, base, 0, len, |
310 | IORESOURCE_IO_FIXED); | 313 | IORESOURCE_IO_FIXED); |
311 | } | 314 | } |
312 | 315 | ||
313 | static __init unsigned char * | 316 | static __init unsigned char * |
314 | pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, | 317 | pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, |
315 | struct pnp_dev *dev) | 318 | struct pnp_dev *dev) |
316 | { | 319 | { |
317 | unsigned int len, tag; | 320 | unsigned int len, tag; |
318 | int priority; | 321 | int priority; |
319 | struct pnp_option *option, *option_independent; | 322 | unsigned int option_flags; |
320 | 323 | ||
321 | if (!p) | 324 | if (!p) |
322 | return NULL; | 325 | return NULL; |
323 | 326 | ||
324 | dev_dbg(&dev->dev, "parse resource options\n"); | 327 | dev_dbg(&dev->dev, "parse resource options\n"); |
325 | 328 | option_flags = 0; | |
326 | option_independent = option = pnp_register_independent_option(dev); | ||
327 | if (!option) | ||
328 | return NULL; | ||
329 | |||
330 | while ((char *)p < (char *)end) { | 329 | while ((char *)p < (char *)end) { |
331 | 330 | ||
332 | /* determine the type of tag */ | 331 | /* determine the type of tag */ |
@@ -343,37 +342,38 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, | |||
343 | case LARGE_TAG_MEM: | 342 | case LARGE_TAG_MEM: |
344 | if (len != 9) | 343 | if (len != 9) |
345 | goto len_err; | 344 | goto len_err; |
346 | pnpbios_parse_mem_option(dev, p, len, option); | 345 | pnpbios_parse_mem_option(dev, p, len, option_flags); |
347 | break; | 346 | break; |
348 | 347 | ||
349 | case LARGE_TAG_MEM32: | 348 | case LARGE_TAG_MEM32: |
350 | if (len != 17) | 349 | if (len != 17) |
351 | goto len_err; | 350 | goto len_err; |
352 | pnpbios_parse_mem32_option(dev, p, len, option); | 351 | pnpbios_parse_mem32_option(dev, p, len, option_flags); |
353 | break; | 352 | break; |
354 | 353 | ||
355 | case LARGE_TAG_FIXEDMEM32: | 354 | case LARGE_TAG_FIXEDMEM32: |
356 | if (len != 9) | 355 | if (len != 9) |
357 | goto len_err; | 356 | goto len_err; |
358 | pnpbios_parse_fixed_mem32_option(dev, p, len, option); | 357 | pnpbios_parse_fixed_mem32_option(dev, p, len, |
358 | option_flags); | ||
359 | break; | 359 | break; |
360 | 360 | ||
361 | case SMALL_TAG_IRQ: | 361 | case SMALL_TAG_IRQ: |
362 | if (len < 2 || len > 3) | 362 | if (len < 2 || len > 3) |
363 | goto len_err; | 363 | goto len_err; |
364 | pnpbios_parse_irq_option(dev, p, len, option); | 364 | pnpbios_parse_irq_option(dev, p, len, option_flags); |
365 | break; | 365 | break; |
366 | 366 | ||
367 | case SMALL_TAG_DMA: | 367 | case SMALL_TAG_DMA: |
368 | if (len != 2) | 368 | if (len != 2) |
369 | goto len_err; | 369 | goto len_err; |
370 | pnpbios_parse_dma_option(dev, p, len, option); | 370 | pnpbios_parse_dma_option(dev, p, len, option_flags); |
371 | break; | 371 | break; |
372 | 372 | ||
373 | case SMALL_TAG_PORT: | 373 | case SMALL_TAG_PORT: |
374 | if (len != 7) | 374 | if (len != 7) |
375 | goto len_err; | 375 | goto len_err; |
376 | pnpbios_parse_port_option(dev, p, len, option); | 376 | pnpbios_parse_port_option(dev, p, len, option_flags); |
377 | break; | 377 | break; |
378 | 378 | ||
379 | case SMALL_TAG_VENDOR: | 379 | case SMALL_TAG_VENDOR: |
@@ -383,7 +383,8 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, | |||
383 | case SMALL_TAG_FIXEDPORT: | 383 | case SMALL_TAG_FIXEDPORT: |
384 | if (len != 3) | 384 | if (len != 3) |
385 | goto len_err; | 385 | goto len_err; |
386 | pnpbios_parse_fixed_port_option(dev, p, len, option); | 386 | pnpbios_parse_fixed_port_option(dev, p, len, |
387 | option_flags); | ||
387 | break; | 388 | break; |
388 | 389 | ||
389 | case SMALL_TAG_STARTDEP: | 390 | case SMALL_TAG_STARTDEP: |
@@ -392,19 +393,13 @@ pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, | |||
392 | priority = PNP_RES_PRIORITY_ACCEPTABLE; | 393 | priority = PNP_RES_PRIORITY_ACCEPTABLE; |
393 | if (len > 0) | 394 | if (len > 0) |
394 | priority = p[1]; | 395 | priority = p[1]; |
395 | option = pnp_register_dependent_option(dev, priority); | 396 | option_flags = pnp_new_dependent_set(dev, priority); |
396 | if (!option) | ||
397 | return NULL; | ||
398 | break; | 397 | break; |
399 | 398 | ||
400 | case SMALL_TAG_ENDDEP: | 399 | case SMALL_TAG_ENDDEP: |
401 | if (len != 0) | 400 | if (len != 0) |
402 | goto len_err; | 401 | goto len_err; |
403 | if (option_independent == option) | 402 | option_flags = 0; |
404 | dev_warn(&dev->dev, "missing " | ||
405 | "SMALL_TAG_STARTDEP tag\n"); | ||
406 | option = option_independent; | ||
407 | dev_dbg(&dev->dev, "end dependent options\n"); | ||
408 | break; | 403 | break; |
409 | 404 | ||
410 | case SMALL_TAG_END: | 405 | case SMALL_TAG_END: |
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index e8515ce0d296..55f55ed72dc7 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c | |||
@@ -5,6 +5,8 @@ | |||
5 | * when building up the resource structure for the first time. | 5 | * when building up the resource structure for the first time. |
6 | * | 6 | * |
7 | * Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk> | 7 | * Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk> |
8 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
9 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
8 | * | 10 | * |
9 | * Heavily based on PCI quirks handling which is | 11 | * Heavily based on PCI quirks handling which is |
10 | * | 12 | * |
@@ -20,189 +22,207 @@ | |||
20 | #include <linux/kallsyms.h> | 22 | #include <linux/kallsyms.h> |
21 | #include "base.h" | 23 | #include "base.h" |
22 | 24 | ||
25 | static void quirk_awe32_add_ports(struct pnp_dev *dev, | ||
26 | struct pnp_option *option, | ||
27 | unsigned int offset) | ||
28 | { | ||
29 | struct pnp_option *new_option; | ||
30 | |||
31 | new_option = kmalloc(sizeof(struct pnp_option), GFP_KERNEL); | ||
32 | if (!new_option) { | ||
33 | dev_err(&dev->dev, "couldn't add ioport region to option set " | ||
34 | "%d\n", pnp_option_set(option)); | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | *new_option = *option; | ||
39 | new_option->u.port.min += offset; | ||
40 | new_option->u.port.max += offset; | ||
41 | list_add(&new_option->list, &option->list); | ||
42 | |||
43 | dev_info(&dev->dev, "added ioport region %#llx-%#llx to set %d\n", | ||
44 | (unsigned long long) new_option->u.port.min, | ||
45 | (unsigned long long) new_option->u.port.max, | ||
46 | pnp_option_set(option)); | ||
47 | } | ||
48 | |||
23 | static void quirk_awe32_resources(struct pnp_dev *dev) | 49 | static void quirk_awe32_resources(struct pnp_dev *dev) |
24 | { | 50 | { |
25 | struct pnp_port *port, *port2, *port3; | 51 | struct pnp_option *option; |
26 | struct pnp_option *res = dev->dependent; | 52 | unsigned int set = ~0; |
27 | 53 | ||
28 | /* | 54 | /* |
29 | * Unfortunately the isapnp_add_port_resource is too tightly bound | 55 | * Add two extra ioport regions (at offset 0x400 and 0x800 from the |
30 | * into the PnP discovery sequence, and cannot be used. Link in the | 56 | * one given) to every dependent option set. |
31 | * two extra ports (at offset 0x400 and 0x800 from the one given) by | ||
32 | * hand. | ||
33 | */ | 57 | */ |
34 | for (; res; res = res->next) { | 58 | list_for_each_entry(option, &dev->options, list) { |
35 | port2 = pnp_alloc(sizeof(struct pnp_port)); | 59 | if (pnp_option_is_dependent(option) && |
36 | if (!port2) | 60 | pnp_option_set(option) != set) { |
37 | return; | 61 | set = pnp_option_set(option); |
38 | port3 = pnp_alloc(sizeof(struct pnp_port)); | 62 | quirk_awe32_add_ports(dev, option, 0x800); |
39 | if (!port3) { | 63 | quirk_awe32_add_ports(dev, option, 0x400); |
40 | kfree(port2); | ||
41 | return; | ||
42 | } | 64 | } |
43 | port = res->port; | ||
44 | memcpy(port2, port, sizeof(struct pnp_port)); | ||
45 | memcpy(port3, port, sizeof(struct pnp_port)); | ||
46 | port->next = port2; | ||
47 | port2->next = port3; | ||
48 | port2->min += 0x400; | ||
49 | port2->max += 0x400; | ||
50 | port3->min += 0x800; | ||
51 | port3->max += 0x800; | ||
52 | dev_info(&dev->dev, | ||
53 | "AWE32 quirk - added ioports 0x%lx and 0x%lx\n", | ||
54 | (unsigned long)port2->min, | ||
55 | (unsigned long)port3->min); | ||
56 | } | 65 | } |
57 | } | 66 | } |
58 | 67 | ||
59 | static void quirk_cmi8330_resources(struct pnp_dev *dev) | 68 | static void quirk_cmi8330_resources(struct pnp_dev *dev) |
60 | { | 69 | { |
61 | struct pnp_option *res = dev->dependent; | 70 | struct pnp_option *option; |
62 | unsigned long tmp; | 71 | struct pnp_irq *irq; |
63 | 72 | struct pnp_dma *dma; | |
64 | for (; res; res = res->next) { | ||
65 | |||
66 | struct pnp_irq *irq; | ||
67 | struct pnp_dma *dma; | ||
68 | 73 | ||
69 | for (irq = res->irq; irq; irq = irq->next) { | 74 | list_for_each_entry(option, &dev->options, list) { |
70 | /* Valid irqs are 5, 7, 10 */ | 75 | if (!pnp_option_is_dependent(option)) |
71 | tmp = 0x04A0; | 76 | continue; |
72 | bitmap_copy(irq->map.bits, &tmp, 16); | ||
73 | } | ||
74 | 77 | ||
75 | for (dma = res->dma; dma; dma = dma->next) { | 78 | if (option->type == IORESOURCE_IRQ) { |
76 | /* Valid 8bit dma channels are 1,3 */ | 79 | irq = &option->u.irq; |
80 | bitmap_zero(irq->map.bits, PNP_IRQ_NR); | ||
81 | __set_bit(5, irq->map.bits); | ||
82 | __set_bit(7, irq->map.bits); | ||
83 | __set_bit(10, irq->map.bits); | ||
84 | dev_info(&dev->dev, "set possible IRQs in " | ||
85 | "option set %d to 5, 7, 10\n", | ||
86 | pnp_option_set(option)); | ||
87 | } else if (option->type == IORESOURCE_DMA) { | ||
88 | dma = &option->u.dma; | ||
77 | if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) == | 89 | if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) == |
78 | IORESOURCE_DMA_8BIT) | 90 | IORESOURCE_DMA_8BIT && |
79 | dma->map = 0x000A; | 91 | dma->map != 0x0A) { |
92 | dev_info(&dev->dev, "changing possible " | ||
93 | "DMA channel mask in option set %d " | ||
94 | "from %#02x to 0x0A (1, 3)\n", | ||
95 | pnp_option_set(option), dma->map); | ||
96 | dma->map = 0x0A; | ||
97 | } | ||
80 | } | 98 | } |
81 | } | 99 | } |
82 | dev_info(&dev->dev, "CMI8330 quirk - forced possible IRQs to 5, 7, 10 " | ||
83 | "and DMA channels to 1, 3\n"); | ||
84 | } | 100 | } |
85 | 101 | ||
86 | static void quirk_sb16audio_resources(struct pnp_dev *dev) | 102 | static void quirk_sb16audio_resources(struct pnp_dev *dev) |
87 | { | 103 | { |
104 | struct pnp_option *option; | ||
105 | unsigned int prev_option_flags = ~0, n = 0; | ||
88 | struct pnp_port *port; | 106 | struct pnp_port *port; |
89 | struct pnp_option *res = dev->dependent; | ||
90 | int changed = 0; | ||
91 | 107 | ||
92 | /* | 108 | /* |
93 | * The default range on the mpu port for these devices is 0x388-0x388. | 109 | * The default range on the OPL port for these devices is 0x388-0x388. |
94 | * Here we increase that range so that two such cards can be | 110 | * Here we increase that range so that two such cards can be |
95 | * auto-configured. | 111 | * auto-configured. |
96 | */ | 112 | */ |
113 | list_for_each_entry(option, &dev->options, list) { | ||
114 | if (prev_option_flags != option->flags) { | ||
115 | prev_option_flags = option->flags; | ||
116 | n = 0; | ||
117 | } | ||
97 | 118 | ||
98 | for (; res; res = res->next) { | 119 | if (pnp_option_is_dependent(option) && |
99 | port = res->port; | 120 | option->type == IORESOURCE_IO) { |
100 | if (!port) | 121 | n++; |
101 | continue; | 122 | port = &option->u.port; |
102 | port = port->next; | 123 | if (n == 3 && port->min == port->max) { |
103 | if (!port) | 124 | port->max += 0x70; |
104 | continue; | 125 | dev_info(&dev->dev, "increased option port " |
105 | port = port->next; | 126 | "range from %#llx-%#llx to " |
106 | if (!port) | 127 | "%#llx-%#llx\n", |
107 | continue; | 128 | (unsigned long long) port->min, |
108 | if (port->min != port->max) | 129 | (unsigned long long) port->min, |
109 | continue; | 130 | (unsigned long long) port->min, |
110 | port->max += 0x70; | 131 | (unsigned long long) port->max); |
111 | changed = 1; | 132 | } |
133 | } | ||
112 | } | 134 | } |
113 | if (changed) | ||
114 | dev_info(&dev->dev, "SB audio device quirk - increased port range\n"); | ||
115 | } | 135 | } |
116 | 136 | ||
117 | static struct pnp_option *quirk_isapnp_mpu_options(struct pnp_dev *dev) | 137 | static struct pnp_option *pnp_clone_dependent_set(struct pnp_dev *dev, |
138 | unsigned int set) | ||
118 | { | 139 | { |
119 | struct pnp_option *head = NULL; | 140 | struct pnp_option *tail = NULL, *first_new_option = NULL; |
120 | struct pnp_option *prev = NULL; | 141 | struct pnp_option *option, *new_option; |
121 | struct pnp_option *res; | 142 | unsigned int flags; |
122 | |||
123 | /* | ||
124 | * Build a functional IRQ-optional variant of each MPU option. | ||
125 | */ | ||
126 | |||
127 | for (res = dev->dependent; res; res = res->next) { | ||
128 | struct pnp_option *curr; | ||
129 | struct pnp_port *port; | ||
130 | struct pnp_port *copy_port; | ||
131 | struct pnp_irq *irq; | ||
132 | struct pnp_irq *copy_irq; | ||
133 | |||
134 | port = res->port; | ||
135 | irq = res->irq; | ||
136 | if (!port || !irq) | ||
137 | continue; | ||
138 | 143 | ||
139 | copy_port = pnp_alloc(sizeof *copy_port); | 144 | list_for_each_entry(option, &dev->options, list) { |
140 | if (!copy_port) | 145 | if (pnp_option_is_dependent(option)) |
141 | break; | 146 | tail = option; |
142 | 147 | } | |
143 | copy_irq = pnp_alloc(sizeof *copy_irq); | 148 | if (!tail) { |
144 | if (!copy_irq) { | 149 | dev_err(&dev->dev, "no dependent option sets\n"); |
145 | kfree(copy_port); | 150 | return NULL; |
146 | break; | 151 | } |
147 | } | ||
148 | 152 | ||
149 | *copy_port = *port; | 153 | flags = pnp_new_dependent_set(dev, PNP_RES_PRIORITY_FUNCTIONAL); |
150 | copy_port->next = NULL; | 154 | list_for_each_entry(option, &dev->options, list) { |
155 | if (pnp_option_is_dependent(option) && | ||
156 | pnp_option_set(option) == set) { | ||
157 | new_option = kmalloc(sizeof(struct pnp_option), | ||
158 | GFP_KERNEL); | ||
159 | if (!new_option) { | ||
160 | dev_err(&dev->dev, "couldn't clone dependent " | ||
161 | "set %d\n", set); | ||
162 | return NULL; | ||
163 | } | ||
151 | 164 | ||
152 | *copy_irq = *irq; | 165 | *new_option = *option; |
153 | copy_irq->flags |= IORESOURCE_IRQ_OPTIONAL; | 166 | new_option->flags = flags; |
154 | copy_irq->next = NULL; | 167 | if (!first_new_option) |
168 | first_new_option = new_option; | ||
155 | 169 | ||
156 | curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL); | 170 | list_add(&new_option->list, &tail->list); |
157 | if (!curr) { | 171 | tail = new_option; |
158 | kfree(copy_port); | ||
159 | kfree(copy_irq); | ||
160 | break; | ||
161 | } | 172 | } |
162 | curr->port = copy_port; | ||
163 | curr->irq = copy_irq; | ||
164 | |||
165 | if (prev) | ||
166 | prev->next = curr; | ||
167 | else | ||
168 | head = curr; | ||
169 | prev = curr; | ||
170 | } | 173 | } |
171 | if (head) | ||
172 | dev_info(&dev->dev, "adding IRQ-optional MPU options\n"); | ||
173 | 174 | ||
174 | return head; | 175 | return first_new_option; |
175 | } | 176 | } |
176 | 177 | ||
177 | static void quirk_ad1815_mpu_resources(struct pnp_dev *dev) | 178 | |
179 | static void quirk_add_irq_optional_dependent_sets(struct pnp_dev *dev) | ||
178 | { | 180 | { |
179 | struct pnp_option *res; | 181 | struct pnp_option *new_option; |
182 | unsigned int num_sets, i, set; | ||
180 | struct pnp_irq *irq; | 183 | struct pnp_irq *irq; |
181 | 184 | ||
182 | res = dev->independent; | 185 | num_sets = dev->num_dependent_sets; |
183 | if (!res) | 186 | for (i = 0; i < num_sets; i++) { |
184 | return; | 187 | new_option = pnp_clone_dependent_set(dev, i); |
188 | if (!new_option) | ||
189 | return; | ||
185 | 190 | ||
186 | irq = res->irq; | 191 | set = pnp_option_set(new_option); |
187 | if (!irq || irq->next) | 192 | while (new_option && pnp_option_set(new_option) == set) { |
188 | return; | 193 | if (new_option->type == IORESOURCE_IRQ) { |
194 | irq = &new_option->u.irq; | ||
195 | irq->flags |= IORESOURCE_IRQ_OPTIONAL; | ||
196 | } | ||
197 | dbg_pnp_show_option(dev, new_option); | ||
198 | new_option = list_entry(new_option->list.next, | ||
199 | struct pnp_option, list); | ||
200 | } | ||
189 | 201 | ||
190 | irq->flags |= IORESOURCE_IRQ_OPTIONAL; | 202 | dev_info(&dev->dev, "added dependent option set %d (same as " |
191 | dev_info(&dev->dev, "made independent IRQ optional\n"); | 203 | "set %d except IRQ optional)\n", set, i); |
204 | } | ||
192 | } | 205 | } |
193 | 206 | ||
194 | static void quirk_isapnp_mpu_resources(struct pnp_dev *dev) | 207 | static void quirk_ad1815_mpu_resources(struct pnp_dev *dev) |
195 | { | 208 | { |
196 | struct pnp_option *res; | 209 | struct pnp_option *option; |
210 | struct pnp_irq *irq = NULL; | ||
211 | unsigned int independent_irqs = 0; | ||
212 | |||
213 | list_for_each_entry(option, &dev->options, list) { | ||
214 | if (option->type == IORESOURCE_IRQ && | ||
215 | !pnp_option_is_dependent(option)) { | ||
216 | independent_irqs++; | ||
217 | irq = &option->u.irq; | ||
218 | } | ||
219 | } | ||
197 | 220 | ||
198 | res = dev->dependent; | 221 | if (independent_irqs != 1) |
199 | if (!res) | ||
200 | return; | 222 | return; |
201 | 223 | ||
202 | while (res->next) | 224 | irq->flags |= IORESOURCE_IRQ_OPTIONAL; |
203 | res = res->next; | 225 | dev_info(&dev->dev, "made independent IRQ optional\n"); |
204 | |||
205 | res->next = quirk_isapnp_mpu_options(dev); | ||
206 | } | 226 | } |
207 | 227 | ||
208 | #include <linux/pci.h> | 228 | #include <linux/pci.h> |
@@ -297,10 +317,10 @@ static struct pnp_fixup pnp_fixups[] = { | |||
297 | {"CTL0043", quirk_sb16audio_resources}, | 317 | {"CTL0043", quirk_sb16audio_resources}, |
298 | {"CTL0044", quirk_sb16audio_resources}, | 318 | {"CTL0044", quirk_sb16audio_resources}, |
299 | {"CTL0045", quirk_sb16audio_resources}, | 319 | {"CTL0045", quirk_sb16audio_resources}, |
300 | /* Add IRQ-less MPU options */ | 320 | /* Add IRQ-optional MPU options */ |
301 | {"ADS7151", quirk_ad1815_mpu_resources}, | 321 | {"ADS7151", quirk_ad1815_mpu_resources}, |
302 | {"ADS7181", quirk_isapnp_mpu_resources}, | 322 | {"ADS7181", quirk_add_irq_optional_dependent_sets}, |
303 | {"AZT0002", quirk_isapnp_mpu_resources}, | 323 | {"AZT0002", quirk_add_irq_optional_dependent_sets}, |
304 | /* PnP resources that might overlap PCI BARs */ | 324 | /* PnP resources that might overlap PCI BARs */ |
305 | {"PNP0c01", quirk_system_pci_resources}, | 325 | {"PNP0c01", quirk_system_pci_resources}, |
306 | {"PNP0c02", quirk_system_pci_resources}, | 326 | {"PNP0c02", quirk_system_pci_resources}, |
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index a795864dc695..d6388970a1a4 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c | |||
@@ -3,6 +3,8 @@ | |||
3 | * | 3 | * |
4 | * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> | 4 | * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> |
5 | * Copyright 2003 Adam Belay <ambx1@neo.rr.com> | 5 | * Copyright 2003 Adam Belay <ambx1@neo.rr.com> |
6 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
7 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
6 | */ | 8 | */ |
7 | 9 | ||
8 | #include <linux/module.h> | 10 | #include <linux/module.h> |
@@ -28,78 +30,36 @@ static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some | |||
28 | * option registration | 30 | * option registration |
29 | */ | 31 | */ |
30 | 32 | ||
31 | struct pnp_option *pnp_build_option(int priority) | 33 | struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type, |
34 | unsigned int option_flags) | ||
32 | { | 35 | { |
33 | struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); | 36 | struct pnp_option *option; |
34 | 37 | ||
38 | option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL); | ||
35 | if (!option) | 39 | if (!option) |
36 | return NULL; | 40 | return NULL; |
37 | 41 | ||
38 | option->priority = priority & 0xff; | 42 | option->flags = option_flags; |
39 | /* make sure the priority is valid */ | 43 | option->type = type; |
40 | if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL) | ||
41 | option->priority = PNP_RES_PRIORITY_INVALID; | ||
42 | |||
43 | return option; | ||
44 | } | ||
45 | |||
46 | struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev) | ||
47 | { | ||
48 | struct pnp_option *option; | ||
49 | |||
50 | option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED); | ||
51 | |||
52 | /* this should never happen but if it does we'll try to continue */ | ||
53 | if (dev->independent) | ||
54 | dev_err(&dev->dev, "independent resource already registered\n"); | ||
55 | dev->independent = option; | ||
56 | |||
57 | dev_dbg(&dev->dev, "new independent option\n"); | ||
58 | return option; | ||
59 | } | ||
60 | |||
61 | struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, | ||
62 | int priority) | ||
63 | { | ||
64 | struct pnp_option *option; | ||
65 | 44 | ||
66 | option = pnp_build_option(priority); | 45 | list_add_tail(&option->list, &dev->options); |
67 | |||
68 | if (dev->dependent) { | ||
69 | struct pnp_option *parent = dev->dependent; | ||
70 | while (parent->next) | ||
71 | parent = parent->next; | ||
72 | parent->next = option; | ||
73 | } else | ||
74 | dev->dependent = option; | ||
75 | |||
76 | dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority); | ||
77 | return option; | 46 | return option; |
78 | } | 47 | } |
79 | 48 | ||
80 | int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, | 49 | int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags, |
81 | pnp_irq_mask_t *map, unsigned char flags) | 50 | pnp_irq_mask_t *map, unsigned char flags) |
82 | { | 51 | { |
83 | struct pnp_irq *irq, *ptr; | 52 | struct pnp_option *option; |
84 | #ifdef DEBUG | 53 | struct pnp_irq *irq; |
85 | char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */ | ||
86 | #endif | ||
87 | 54 | ||
88 | irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL); | 55 | option = pnp_build_option(dev, IORESOURCE_IRQ, option_flags); |
89 | if (!irq) | 56 | if (!option) |
90 | return -ENOMEM; | 57 | return -ENOMEM; |
91 | 58 | ||
59 | irq = &option->u.irq; | ||
92 | irq->map = *map; | 60 | irq->map = *map; |
93 | irq->flags = flags; | 61 | irq->flags = flags; |
94 | 62 | ||
95 | ptr = option->irq; | ||
96 | while (ptr && ptr->next) | ||
97 | ptr = ptr->next; | ||
98 | if (ptr) | ||
99 | ptr->next = irq; | ||
100 | else | ||
101 | option->irq = irq; | ||
102 | |||
103 | #ifdef CONFIG_PCI | 63 | #ifdef CONFIG_PCI |
104 | { | 64 | { |
105 | int i; | 65 | int i; |
@@ -110,163 +70,81 @@ int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, | |||
110 | } | 70 | } |
111 | #endif | 71 | #endif |
112 | 72 | ||
113 | #ifdef DEBUG | 73 | dbg_pnp_show_option(dev, option); |
114 | bitmap_scnprintf(buf, sizeof(buf), irq->map.bits, PNP_IRQ_NR); | ||
115 | dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf, | ||
116 | irq->flags); | ||
117 | #endif | ||
118 | return 0; | 74 | return 0; |
119 | } | 75 | } |
120 | 76 | ||
121 | int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, | 77 | int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags, |
122 | unsigned char map, unsigned char flags) | 78 | unsigned char map, unsigned char flags) |
123 | { | 79 | { |
124 | struct pnp_dma *dma, *ptr; | 80 | struct pnp_option *option; |
81 | struct pnp_dma *dma; | ||
125 | 82 | ||
126 | dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL); | 83 | option = pnp_build_option(dev, IORESOURCE_DMA, option_flags); |
127 | if (!dma) | 84 | if (!option) |
128 | return -ENOMEM; | 85 | return -ENOMEM; |
129 | 86 | ||
87 | dma = &option->u.dma; | ||
130 | dma->map = map; | 88 | dma->map = map; |
131 | dma->flags = flags; | 89 | dma->flags = flags; |
132 | 90 | ||
133 | ptr = option->dma; | 91 | dbg_pnp_show_option(dev, option); |
134 | while (ptr && ptr->next) | ||
135 | ptr = ptr->next; | ||
136 | if (ptr) | ||
137 | ptr->next = dma; | ||
138 | else | ||
139 | option->dma = dma; | ||
140 | |||
141 | dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", dma->map, | ||
142 | dma->flags); | ||
143 | return 0; | 92 | return 0; |
144 | } | 93 | } |
145 | 94 | ||
146 | int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, | 95 | int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags, |
147 | resource_size_t min, resource_size_t max, | 96 | resource_size_t min, resource_size_t max, |
148 | resource_size_t align, resource_size_t size, | 97 | resource_size_t align, resource_size_t size, |
149 | unsigned char flags) | 98 | unsigned char flags) |
150 | { | 99 | { |
151 | struct pnp_port *port, *ptr; | 100 | struct pnp_option *option; |
101 | struct pnp_port *port; | ||
152 | 102 | ||
153 | port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL); | 103 | option = pnp_build_option(dev, IORESOURCE_IO, option_flags); |
154 | if (!port) | 104 | if (!option) |
155 | return -ENOMEM; | 105 | return -ENOMEM; |
156 | 106 | ||
107 | port = &option->u.port; | ||
157 | port->min = min; | 108 | port->min = min; |
158 | port->max = max; | 109 | port->max = max; |
159 | port->align = align; | 110 | port->align = align; |
160 | port->size = size; | 111 | port->size = size; |
161 | port->flags = flags; | 112 | port->flags = flags; |
162 | 113 | ||
163 | ptr = option->port; | 114 | dbg_pnp_show_option(dev, option); |
164 | while (ptr && ptr->next) | ||
165 | ptr = ptr->next; | ||
166 | if (ptr) | ||
167 | ptr->next = port; | ||
168 | else | ||
169 | option->port = port; | ||
170 | |||
171 | dev_dbg(&dev->dev, " io " | ||
172 | "min %#llx max %#llx align %lld size %lld flags %#x\n", | ||
173 | (unsigned long long) port->min, | ||
174 | (unsigned long long) port->max, | ||
175 | (unsigned long long) port->align, | ||
176 | (unsigned long long) port->size, port->flags); | ||
177 | return 0; | 115 | return 0; |
178 | } | 116 | } |
179 | 117 | ||
180 | int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, | 118 | int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags, |
181 | resource_size_t min, resource_size_t max, | 119 | resource_size_t min, resource_size_t max, |
182 | resource_size_t align, resource_size_t size, | 120 | resource_size_t align, resource_size_t size, |
183 | unsigned char flags) | 121 | unsigned char flags) |
184 | { | 122 | { |
185 | struct pnp_mem *mem, *ptr; | 123 | struct pnp_option *option; |
124 | struct pnp_mem *mem; | ||
186 | 125 | ||
187 | mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL); | 126 | option = pnp_build_option(dev, IORESOURCE_MEM, option_flags); |
188 | if (!mem) | 127 | if (!option) |
189 | return -ENOMEM; | 128 | return -ENOMEM; |
190 | 129 | ||
130 | mem = &option->u.mem; | ||
191 | mem->min = min; | 131 | mem->min = min; |
192 | mem->max = max; | 132 | mem->max = max; |
193 | mem->align = align; | 133 | mem->align = align; |
194 | mem->size = size; | 134 | mem->size = size; |
195 | mem->flags = flags; | 135 | mem->flags = flags; |
196 | 136 | ||
197 | ptr = option->mem; | 137 | dbg_pnp_show_option(dev, option); |
198 | while (ptr && ptr->next) | ||
199 | ptr = ptr->next; | ||
200 | if (ptr) | ||
201 | ptr->next = mem; | ||
202 | else | ||
203 | option->mem = mem; | ||
204 | |||
205 | dev_dbg(&dev->dev, " mem " | ||
206 | "min %#llx max %#llx align %lld size %lld flags %#x\n", | ||
207 | (unsigned long long) mem->min, | ||
208 | (unsigned long long) mem->max, | ||
209 | (unsigned long long) mem->align, | ||
210 | (unsigned long long) mem->size, mem->flags); | ||
211 | return 0; | 138 | return 0; |
212 | } | 139 | } |
213 | 140 | ||
214 | static void pnp_free_port(struct pnp_port *port) | 141 | void pnp_free_options(struct pnp_dev *dev) |
215 | { | ||
216 | struct pnp_port *next; | ||
217 | |||
218 | while (port) { | ||
219 | next = port->next; | ||
220 | kfree(port); | ||
221 | port = next; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static void pnp_free_irq(struct pnp_irq *irq) | ||
226 | { | ||
227 | struct pnp_irq *next; | ||
228 | |||
229 | while (irq) { | ||
230 | next = irq->next; | ||
231 | kfree(irq); | ||
232 | irq = next; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | static void pnp_free_dma(struct pnp_dma *dma) | ||
237 | { | ||
238 | struct pnp_dma *next; | ||
239 | |||
240 | while (dma) { | ||
241 | next = dma->next; | ||
242 | kfree(dma); | ||
243 | dma = next; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | static void pnp_free_mem(struct pnp_mem *mem) | ||
248 | { | 142 | { |
249 | struct pnp_mem *next; | 143 | struct pnp_option *option, *tmp; |
250 | |||
251 | while (mem) { | ||
252 | next = mem->next; | ||
253 | kfree(mem); | ||
254 | mem = next; | ||
255 | } | ||
256 | } | ||
257 | 144 | ||
258 | void pnp_free_option(struct pnp_option *option) | 145 | list_for_each_entry_safe(option, tmp, &dev->options, list) { |
259 | { | 146 | list_del(&option->list); |
260 | struct pnp_option *next; | ||
261 | |||
262 | while (option) { | ||
263 | next = option->next; | ||
264 | pnp_free_port(option->port); | ||
265 | pnp_free_irq(option->irq); | ||
266 | pnp_free_dma(option->dma); | ||
267 | pnp_free_mem(option->mem); | ||
268 | kfree(option); | 147 | kfree(option); |
269 | option = next; | ||
270 | } | 148 | } |
271 | } | 149 | } |
272 | 150 | ||
@@ -668,66 +546,50 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev, | |||
668 | return pnp_res; | 546 | return pnp_res; |
669 | } | 547 | } |
670 | 548 | ||
671 | static int pnp_possible_option(struct pnp_option *option, int type, | 549 | /* |
672 | resource_size_t start, resource_size_t size) | 550 | * Determine whether the specified resource is a possible configuration |
551 | * for this device. | ||
552 | */ | ||
553 | int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start, | ||
554 | resource_size_t size) | ||
673 | { | 555 | { |
674 | struct pnp_option *tmp; | 556 | struct pnp_option *option; |
675 | struct pnp_port *port; | 557 | struct pnp_port *port; |
676 | struct pnp_mem *mem; | 558 | struct pnp_mem *mem; |
677 | struct pnp_irq *irq; | 559 | struct pnp_irq *irq; |
678 | struct pnp_dma *dma; | 560 | struct pnp_dma *dma; |
679 | 561 | ||
680 | if (!option) | 562 | list_for_each_entry(option, &dev->options, list) { |
681 | return 0; | 563 | if (option->type != type) |
564 | continue; | ||
682 | 565 | ||
683 | for (tmp = option; tmp; tmp = tmp->next) { | 566 | switch (option->type) { |
684 | switch (type) { | ||
685 | case IORESOURCE_IO: | 567 | case IORESOURCE_IO: |
686 | for (port = tmp->port; port; port = port->next) { | 568 | port = &option->u.port; |
687 | if (port->min == start && port->size == size) | 569 | if (port->min == start && port->size == size) |
688 | return 1; | 570 | return 1; |
689 | } | ||
690 | break; | 571 | break; |
691 | case IORESOURCE_MEM: | 572 | case IORESOURCE_MEM: |
692 | for (mem = tmp->mem; mem; mem = mem->next) { | 573 | mem = &option->u.mem; |
693 | if (mem->min == start && mem->size == size) | 574 | if (mem->min == start && mem->size == size) |
694 | return 1; | 575 | return 1; |
695 | } | ||
696 | break; | 576 | break; |
697 | case IORESOURCE_IRQ: | 577 | case IORESOURCE_IRQ: |
698 | for (irq = tmp->irq; irq; irq = irq->next) { | 578 | irq = &option->u.irq; |
699 | if (start < PNP_IRQ_NR && | 579 | if (start < PNP_IRQ_NR && |
700 | test_bit(start, irq->map.bits)) | 580 | test_bit(start, irq->map.bits)) |
701 | return 1; | 581 | return 1; |
702 | } | ||
703 | break; | 582 | break; |
704 | case IORESOURCE_DMA: | 583 | case IORESOURCE_DMA: |
705 | for (dma = tmp->dma; dma; dma = dma->next) { | 584 | dma = &option->u.dma; |
706 | if (dma->map & (1 << start)) | 585 | if (dma->map & (1 << start)) |
707 | return 1; | 586 | return 1; |
708 | } | ||
709 | break; | 587 | break; |
710 | } | 588 | } |
711 | } | 589 | } |
712 | 590 | ||
713 | return 0; | 591 | return 0; |
714 | } | 592 | } |
715 | |||
716 | /* | ||
717 | * Determine whether the specified resource is a possible configuration | ||
718 | * for this device. | ||
719 | */ | ||
720 | int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start, | ||
721 | resource_size_t size) | ||
722 | { | ||
723 | if (pnp_possible_option(dev->independent, type, start, size)) | ||
724 | return 1; | ||
725 | |||
726 | if (pnp_possible_option(dev->dependent, type, start, size)) | ||
727 | return 1; | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | EXPORT_SYMBOL(pnp_possible_config); | 593 | EXPORT_SYMBOL(pnp_possible_config); |
732 | 594 | ||
733 | /* format is: pnp_reserve_irq=irq1[,irq2] .... */ | 595 | /* format is: pnp_reserve_irq=irq1[,irq2] .... */ |
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c index 0ad42db94884..bbf78ef4ba02 100644 --- a/drivers/pnp/support.c +++ b/drivers/pnp/support.c | |||
@@ -2,6 +2,8 @@ | |||
2 | * support.c - standard functions for the use of pnp protocol drivers | 2 | * support.c - standard functions for the use of pnp protocol drivers |
3 | * | 3 | * |
4 | * Copyright 2003 Adam Belay <ambx1@neo.rr.com> | 4 | * Copyright 2003 Adam Belay <ambx1@neo.rr.com> |
5 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
6 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
5 | */ | 7 | */ |
6 | 8 | ||
7 | #include <linux/module.h> | 9 | #include <linux/module.h> |
@@ -117,3 +119,93 @@ void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc) | |||
117 | } | 119 | } |
118 | #endif | 120 | #endif |
119 | } | 121 | } |
122 | |||
123 | char *pnp_option_priority_name(struct pnp_option *option) | ||
124 | { | ||
125 | switch (pnp_option_priority(option)) { | ||
126 | case PNP_RES_PRIORITY_PREFERRED: | ||
127 | return "preferred"; | ||
128 | case PNP_RES_PRIORITY_ACCEPTABLE: | ||
129 | return "acceptable"; | ||
130 | case PNP_RES_PRIORITY_FUNCTIONAL: | ||
131 | return "functional"; | ||
132 | } | ||
133 | return "invalid"; | ||
134 | } | ||
135 | |||
136 | void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option) | ||
137 | { | ||
138 | #ifdef DEBUG | ||
139 | char buf[128]; | ||
140 | int len = 0, i; | ||
141 | struct pnp_port *port; | ||
142 | struct pnp_mem *mem; | ||
143 | struct pnp_irq *irq; | ||
144 | struct pnp_dma *dma; | ||
145 | |||
146 | if (pnp_option_is_dependent(option)) | ||
147 | len += snprintf(buf + len, sizeof(buf) - len, | ||
148 | " dependent set %d (%s) ", | ||
149 | pnp_option_set(option), | ||
150 | pnp_option_priority_name(option)); | ||
151 | else | ||
152 | len += snprintf(buf + len, sizeof(buf) - len, " independent "); | ||
153 | |||
154 | switch (option->type) { | ||
155 | case IORESOURCE_IO: | ||
156 | port = &option->u.port; | ||
157 | len += snprintf(buf + len, sizeof(buf) - len, "io min %#llx " | ||
158 | "max %#llx align %lld size %lld flags %#x", | ||
159 | (unsigned long long) port->min, | ||
160 | (unsigned long long) port->max, | ||
161 | (unsigned long long) port->align, | ||
162 | (unsigned long long) port->size, port->flags); | ||
163 | break; | ||
164 | case IORESOURCE_MEM: | ||
165 | mem = &option->u.mem; | ||
166 | len += snprintf(buf + len, sizeof(buf) - len, "mem min %#llx " | ||
167 | "max %#llx align %lld size %lld flags %#x", | ||
168 | (unsigned long long) mem->min, | ||
169 | (unsigned long long) mem->max, | ||
170 | (unsigned long long) mem->align, | ||
171 | (unsigned long long) mem->size, mem->flags); | ||
172 | break; | ||
173 | case IORESOURCE_IRQ: | ||
174 | irq = &option->u.irq; | ||
175 | len += snprintf(buf + len, sizeof(buf) - len, "irq"); | ||
176 | if (bitmap_empty(irq->map.bits, PNP_IRQ_NR)) | ||
177 | len += snprintf(buf + len, sizeof(buf) - len, | ||
178 | " <none>"); | ||
179 | else { | ||
180 | for (i = 0; i < PNP_IRQ_NR; i++) | ||
181 | if (test_bit(i, irq->map.bits)) | ||
182 | len += snprintf(buf + len, | ||
183 | sizeof(buf) - len, | ||
184 | " %d", i); | ||
185 | } | ||
186 | len += snprintf(buf + len, sizeof(buf) - len, " flags %#x", | ||
187 | irq->flags); | ||
188 | if (irq->flags & IORESOURCE_IRQ_OPTIONAL) | ||
189 | len += snprintf(buf + len, sizeof(buf) - len, | ||
190 | " (optional)"); | ||
191 | break; | ||
192 | case IORESOURCE_DMA: | ||
193 | dma = &option->u.dma; | ||
194 | len += snprintf(buf + len, sizeof(buf) - len, "dma"); | ||
195 | if (!dma->map) | ||
196 | len += snprintf(buf + len, sizeof(buf) - len, | ||
197 | " <none>"); | ||
198 | else { | ||
199 | for (i = 0; i < 8; i++) | ||
200 | if (dma->map & (1 << i)) | ||
201 | len += snprintf(buf + len, | ||
202 | sizeof(buf) - len, | ||
203 | " %d", i); | ||
204 | } | ||
205 | len += snprintf(buf + len, sizeof(buf) - len, " (bitmask %#x) " | ||
206 | "flags %#x", dma->map, dma->flags); | ||
207 | break; | ||
208 | } | ||
209 | dev_dbg(&dev->dev, "%s\n", buf); | ||
210 | #endif | ||
211 | } | ||
diff --git a/include/linux/pnp.h b/include/linux/pnp.h index 785126ffcc11..1ce54b63085d 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h | |||
@@ -1,6 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Linux Plug and Play Support | 2 | * Linux Plug and Play Support |
3 | * Copyright by Adam Belay <ambx1@neo.rr.com> | 3 | * Copyright by Adam Belay <ambx1@neo.rr.com> |
4 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
5 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | ||
4 | */ | 6 | */ |
5 | 7 | ||
6 | #ifndef _LINUX_PNP_H | 8 | #ifndef _LINUX_PNP_H |
@@ -249,9 +251,9 @@ struct pnp_dev { | |||
249 | 251 | ||
250 | int active; | 252 | int active; |
251 | int capabilities; | 253 | int capabilities; |
252 | struct pnp_option *independent; | 254 | unsigned int num_dependent_sets; |
253 | struct pnp_option *dependent; | ||
254 | struct list_head resources; | 255 | struct list_head resources; |
256 | struct list_head options; | ||
255 | 257 | ||
256 | char name[PNP_NAME_LEN]; /* contains a human-readable name */ | 258 | char name[PNP_NAME_LEN]; /* contains a human-readable name */ |
257 | int flags; /* used by protocols */ | 259 | int flags; /* used by protocols */ |