diff options
Diffstat (limited to 'drivers/pnp/manager.c')
-rw-r--r-- | drivers/pnp/manager.c | 220 |
1 files changed, 55 insertions, 165 deletions
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index 90bd9cb65563..165b624081ad 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c | |||
@@ -19,40 +19,30 @@ DEFINE_MUTEX(pnp_res_mutex); | |||
19 | 19 | ||
20 | static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) | 20 | static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) |
21 | { | 21 | { |
22 | struct pnp_resource *pnp_res; | 22 | struct resource *res, local_res; |
23 | struct resource *res; | ||
24 | 23 | ||
25 | pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, idx); | 24 | res = pnp_get_resource(dev, IORESOURCE_IO, idx); |
26 | if (!pnp_res) { | 25 | if (res) { |
27 | dev_err(&dev->dev, "too many I/O port resources\n"); | ||
28 | /* pretend we were successful so at least the manager won't try again */ | ||
29 | return 1; | ||
30 | } | ||
31 | |||
32 | res = &pnp_res->res; | ||
33 | |||
34 | /* check if this resource has been manually set, if so skip */ | ||
35 | if (!(res->flags & IORESOURCE_AUTO)) { | ||
36 | dev_dbg(&dev->dev, " io %d already set to %#llx-%#llx " | 26 | dev_dbg(&dev->dev, " io %d already set to %#llx-%#llx " |
37 | "flags %#lx\n", idx, (unsigned long long) res->start, | 27 | "flags %#lx\n", idx, (unsigned long long) res->start, |
38 | (unsigned long long) res->end, res->flags); | 28 | (unsigned long long) res->end, res->flags); |
39 | return 1; | 29 | return 1; |
40 | } | 30 | } |
41 | 31 | ||
42 | /* set the initial values */ | 32 | res = &local_res; |
43 | res->flags |= rule->flags | IORESOURCE_IO; | 33 | res->flags = rule->flags | IORESOURCE_AUTO; |
44 | res->flags &= ~IORESOURCE_UNSET; | 34 | res->start = 0; |
35 | res->end = 0; | ||
45 | 36 | ||
46 | if (!rule->size) { | 37 | if (!rule->size) { |
47 | res->flags |= IORESOURCE_DISABLED; | 38 | res->flags |= IORESOURCE_DISABLED; |
48 | dev_dbg(&dev->dev, " io %d disabled\n", idx); | 39 | dev_dbg(&dev->dev, " io %d disabled\n", idx); |
49 | return 1; /* skip disabled resource requests */ | 40 | goto __add; |
50 | } | 41 | } |
51 | 42 | ||
52 | res->start = rule->min; | 43 | res->start = rule->min; |
53 | res->end = res->start + rule->size - 1; | 44 | res->end = res->start + rule->size - 1; |
54 | 45 | ||
55 | /* run through until pnp_check_port is happy */ | ||
56 | while (!pnp_check_port(dev, res)) { | 46 | while (!pnp_check_port(dev, res)) { |
57 | res->start += rule->align; | 47 | res->start += rule->align; |
58 | res->end = res->start + rule->size - 1; | 48 | res->end = res->start + rule->size - 1; |
@@ -61,38 +51,29 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) | |||
61 | return 0; | 51 | return 0; |
62 | } | 52 | } |
63 | } | 53 | } |
64 | dev_dbg(&dev->dev, " assign io %d %#llx-%#llx\n", idx, | 54 | |
65 | (unsigned long long) res->start, (unsigned long long) res->end); | 55 | __add: |
56 | pnp_add_io_resource(dev, res->start, res->end, res->flags); | ||
66 | return 1; | 57 | return 1; |
67 | } | 58 | } |
68 | 59 | ||
69 | static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) | 60 | static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) |
70 | { | 61 | { |
71 | struct pnp_resource *pnp_res; | 62 | struct resource *res, local_res; |
72 | struct resource *res; | ||
73 | 63 | ||
74 | pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, idx); | 64 | res = pnp_get_resource(dev, IORESOURCE_MEM, idx); |
75 | if (!pnp_res) { | 65 | if (res) { |
76 | dev_err(&dev->dev, "too many memory resources\n"); | ||
77 | /* pretend we were successful so at least the manager won't try again */ | ||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | res = &pnp_res->res; | ||
82 | |||
83 | /* check if this resource has been manually set, if so skip */ | ||
84 | if (!(res->flags & IORESOURCE_AUTO)) { | ||
85 | dev_dbg(&dev->dev, " mem %d already set to %#llx-%#llx " | 66 | dev_dbg(&dev->dev, " mem %d already set to %#llx-%#llx " |
86 | "flags %#lx\n", idx, (unsigned long long) res->start, | 67 | "flags %#lx\n", idx, (unsigned long long) res->start, |
87 | (unsigned long long) res->end, res->flags); | 68 | (unsigned long long) res->end, res->flags); |
88 | return 1; | 69 | return 1; |
89 | } | 70 | } |
90 | 71 | ||
91 | /* set the initial values */ | 72 | res = &local_res; |
92 | res->flags |= rule->flags | IORESOURCE_MEM; | 73 | res->flags = rule->flags | IORESOURCE_AUTO; |
93 | res->flags &= ~IORESOURCE_UNSET; | 74 | res->start = 0; |
75 | res->end = 0; | ||
94 | 76 | ||
95 | /* convert pnp flags to standard Linux flags */ | ||
96 | if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) | 77 | if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) |
97 | res->flags |= IORESOURCE_READONLY; | 78 | res->flags |= IORESOURCE_READONLY; |
98 | if (rule->flags & IORESOURCE_MEM_CACHEABLE) | 79 | if (rule->flags & IORESOURCE_MEM_CACHEABLE) |
@@ -105,13 +86,12 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) | |||
105 | if (!rule->size) { | 86 | if (!rule->size) { |
106 | res->flags |= IORESOURCE_DISABLED; | 87 | res->flags |= IORESOURCE_DISABLED; |
107 | dev_dbg(&dev->dev, " mem %d disabled\n", idx); | 88 | dev_dbg(&dev->dev, " mem %d disabled\n", idx); |
108 | return 1; /* skip disabled resource requests */ | 89 | goto __add; |
109 | } | 90 | } |
110 | 91 | ||
111 | res->start = rule->min; | 92 | res->start = rule->min; |
112 | res->end = res->start + rule->size - 1; | 93 | res->end = res->start + rule->size - 1; |
113 | 94 | ||
114 | /* run through until pnp_check_mem is happy */ | ||
115 | while (!pnp_check_mem(dev, res)) { | 95 | while (!pnp_check_mem(dev, res)) { |
116 | res->start += rule->align; | 96 | res->start += rule->align; |
117 | res->end = res->start + rule->size - 1; | 97 | res->end = res->start + rule->size - 1; |
@@ -120,15 +100,15 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) | |||
120 | return 0; | 100 | return 0; |
121 | } | 101 | } |
122 | } | 102 | } |
123 | dev_dbg(&dev->dev, " assign mem %d %#llx-%#llx\n", idx, | 103 | |
124 | (unsigned long long) res->start, (unsigned long long) res->end); | 104 | __add: |
105 | pnp_add_mem_resource(dev, res->start, res->end, res->flags); | ||
125 | return 1; | 106 | return 1; |
126 | } | 107 | } |
127 | 108 | ||
128 | static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) | 109 | static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) |
129 | { | 110 | { |
130 | struct pnp_resource *pnp_res; | 111 | struct resource *res, local_res; |
131 | struct resource *res; | ||
132 | int i; | 112 | int i; |
133 | 113 | ||
134 | /* IRQ priority: this table is good for i386 */ | 114 | /* IRQ priority: this table is good for i386 */ |
@@ -136,58 +116,48 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) | |||
136 | 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 | 116 | 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 |
137 | }; | 117 | }; |
138 | 118 | ||
139 | pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, idx); | 119 | res = pnp_get_resource(dev, IORESOURCE_IRQ, idx); |
140 | if (!pnp_res) { | 120 | if (res) { |
141 | dev_err(&dev->dev, "too many IRQ resources\n"); | ||
142 | /* pretend we were successful so at least the manager won't try again */ | ||
143 | return 1; | ||
144 | } | ||
145 | |||
146 | res = &pnp_res->res; | ||
147 | |||
148 | /* check if this resource has been manually set, if so skip */ | ||
149 | if (!(res->flags & IORESOURCE_AUTO)) { | ||
150 | dev_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n", | 121 | dev_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n", |
151 | idx, (int) res->start, res->flags); | 122 | idx, (int) res->start, res->flags); |
152 | return 1; | 123 | return 1; |
153 | } | 124 | } |
154 | 125 | ||
155 | /* set the initial values */ | 126 | res = &local_res; |
156 | res->flags |= rule->flags | IORESOURCE_IRQ; | 127 | res->flags = rule->flags | IORESOURCE_AUTO; |
157 | res->flags &= ~IORESOURCE_UNSET; | 128 | res->start = -1; |
129 | res->end = -1; | ||
158 | 130 | ||
159 | if (bitmap_empty(rule->map, PNP_IRQ_NR)) { | 131 | if (bitmap_empty(rule->map, PNP_IRQ_NR)) { |
160 | res->flags |= IORESOURCE_DISABLED; | 132 | res->flags |= IORESOURCE_DISABLED; |
161 | dev_dbg(&dev->dev, " irq %d disabled\n", idx); | 133 | dev_dbg(&dev->dev, " irq %d disabled\n", idx); |
162 | return 1; /* skip disabled resource requests */ | 134 | goto __add; |
163 | } | 135 | } |
164 | 136 | ||
165 | /* TBD: need check for >16 IRQ */ | 137 | /* TBD: need check for >16 IRQ */ |
166 | res->start = find_next_bit(rule->map, PNP_IRQ_NR, 16); | 138 | res->start = find_next_bit(rule->map, PNP_IRQ_NR, 16); |
167 | if (res->start < PNP_IRQ_NR) { | 139 | if (res->start < PNP_IRQ_NR) { |
168 | res->end = res->start; | 140 | res->end = res->start; |
169 | dev_dbg(&dev->dev, " assign irq %d %d\n", idx, | 141 | goto __add; |
170 | (int) res->start); | ||
171 | return 1; | ||
172 | } | 142 | } |
173 | for (i = 0; i < 16; i++) { | 143 | for (i = 0; i < 16; i++) { |
174 | if (test_bit(xtab[i], rule->map)) { | 144 | if (test_bit(xtab[i], rule->map)) { |
175 | res->start = res->end = xtab[i]; | 145 | res->start = res->end = xtab[i]; |
176 | if (pnp_check_irq(dev, res)) { | 146 | if (pnp_check_irq(dev, res)) |
177 | dev_dbg(&dev->dev, " assign irq %d %d\n", idx, | 147 | goto __add; |
178 | (int) res->start); | ||
179 | return 1; | ||
180 | } | ||
181 | } | 148 | } |
182 | } | 149 | } |
183 | dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx); | 150 | dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx); |
184 | return 0; | 151 | return 0; |
152 | |||
153 | __add: | ||
154 | pnp_add_irq_resource(dev, res->start, res->flags); | ||
155 | return 1; | ||
185 | } | 156 | } |
186 | 157 | ||
187 | static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) | 158 | static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) |
188 | { | 159 | { |
189 | struct pnp_resource *pnp_res; | 160 | struct resource *res, local_res; |
190 | struct resource *res; | ||
191 | int i; | 161 | int i; |
192 | 162 | ||
193 | /* DMA priority: this table is good for i386 */ | 163 | /* DMA priority: this table is good for i386 */ |
@@ -195,127 +165,47 @@ static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) | |||
195 | 1, 3, 5, 6, 7, 0, 2, 4 | 165 | 1, 3, 5, 6, 7, 0, 2, 4 |
196 | }; | 166 | }; |
197 | 167 | ||
198 | pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, idx); | 168 | res = pnp_get_resource(dev, IORESOURCE_DMA, idx); |
199 | if (!pnp_res) { | 169 | if (res) { |
200 | dev_err(&dev->dev, "too many DMA resources\n"); | ||
201 | return; | ||
202 | } | ||
203 | |||
204 | res = &pnp_res->res; | ||
205 | |||
206 | /* check if this resource has been manually set, if so skip */ | ||
207 | if (!(res->flags & IORESOURCE_AUTO)) { | ||
208 | dev_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n", | 170 | dev_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n", |
209 | idx, (int) res->start, res->flags); | 171 | idx, (int) res->start, res->flags); |
210 | return; | 172 | return; |
211 | } | 173 | } |
212 | 174 | ||
213 | /* set the initial values */ | 175 | res = &local_res; |
214 | res->flags |= rule->flags | IORESOURCE_DMA; | 176 | res->flags = rule->flags | IORESOURCE_AUTO; |
215 | res->flags &= ~IORESOURCE_UNSET; | 177 | res->start = -1; |
178 | res->end = -1; | ||
216 | 179 | ||
217 | for (i = 0; i < 8; i++) { | 180 | for (i = 0; i < 8; i++) { |
218 | if (rule->map & (1 << xtab[i])) { | 181 | if (rule->map & (1 << xtab[i])) { |
219 | res->start = res->end = xtab[i]; | 182 | res->start = res->end = xtab[i]; |
220 | if (pnp_check_dma(dev, res)) { | 183 | if (pnp_check_dma(dev, res)) |
221 | dev_dbg(&dev->dev, " assign dma %d %d\n", idx, | 184 | goto __add; |
222 | (int) res->start); | ||
223 | return; | ||
224 | } | ||
225 | } | 185 | } |
226 | } | 186 | } |
227 | #ifdef MAX_DMA_CHANNELS | 187 | #ifdef MAX_DMA_CHANNELS |
228 | res->start = res->end = MAX_DMA_CHANNELS; | 188 | res->start = res->end = MAX_DMA_CHANNELS; |
229 | #endif | 189 | #endif |
230 | res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; | 190 | res->flags |= IORESOURCE_DISABLED; |
231 | dev_dbg(&dev->dev, " disable dma %d\n", idx); | 191 | dev_dbg(&dev->dev, " disable dma %d\n", idx); |
232 | } | ||
233 | 192 | ||
234 | void pnp_init_resource(struct resource *res) | 193 | __add: |
235 | { | 194 | pnp_add_dma_resource(dev, res->start, res->flags); |
236 | unsigned long type; | ||
237 | |||
238 | type = res->flags & (IORESOURCE_IO | IORESOURCE_MEM | | ||
239 | IORESOURCE_IRQ | IORESOURCE_DMA); | ||
240 | |||
241 | res->name = NULL; | ||
242 | res->flags = type | IORESOURCE_AUTO | IORESOURCE_UNSET; | ||
243 | if (type == IORESOURCE_IRQ || type == IORESOURCE_DMA) { | ||
244 | res->start = -1; | ||
245 | res->end = -1; | ||
246 | } else { | ||
247 | res->start = 0; | ||
248 | res->end = 0; | ||
249 | } | ||
250 | } | 195 | } |
251 | 196 | ||
252 | /** | ||
253 | * pnp_init_resources - Resets a resource table to default values. | ||
254 | * @table: pointer to the desired resource table | ||
255 | */ | ||
256 | void pnp_init_resources(struct pnp_dev *dev) | 197 | void pnp_init_resources(struct pnp_dev *dev) |
257 | { | 198 | { |
258 | struct resource *res; | 199 | pnp_free_resources(dev); |
259 | int idx; | ||
260 | |||
261 | for (idx = 0; idx < PNP_MAX_IRQ; idx++) { | ||
262 | res = &dev->res->irq[idx].res; | ||
263 | res->flags = IORESOURCE_IRQ; | ||
264 | pnp_init_resource(res); | ||
265 | } | ||
266 | for (idx = 0; idx < PNP_MAX_DMA; idx++) { | ||
267 | res = &dev->res->dma[idx].res; | ||
268 | res->flags = IORESOURCE_DMA; | ||
269 | pnp_init_resource(res); | ||
270 | } | ||
271 | for (idx = 0; idx < PNP_MAX_PORT; idx++) { | ||
272 | res = &dev->res->port[idx].res; | ||
273 | res->flags = IORESOURCE_IO; | ||
274 | pnp_init_resource(res); | ||
275 | } | ||
276 | for (idx = 0; idx < PNP_MAX_MEM; idx++) { | ||
277 | res = &dev->res->mem[idx].res; | ||
278 | res->flags = IORESOURCE_MEM; | ||
279 | pnp_init_resource(res); | ||
280 | } | ||
281 | } | 200 | } |
282 | 201 | ||
283 | /** | ||
284 | * pnp_clean_resources - clears resources that were not manually set | ||
285 | * @res: the resources to clean | ||
286 | */ | ||
287 | static void pnp_clean_resource_table(struct pnp_dev *dev) | 202 | static void pnp_clean_resource_table(struct pnp_dev *dev) |
288 | { | 203 | { |
289 | struct resource *res; | 204 | struct pnp_resource *pnp_res, *tmp; |
290 | int idx; | 205 | |
291 | 206 | list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) { | |
292 | for (idx = 0; idx < PNP_MAX_IRQ; idx++) { | 207 | if (pnp_res->res.flags & IORESOURCE_AUTO) |
293 | res = &dev->res->irq[idx].res; | 208 | pnp_free_resource(pnp_res); |
294 | if (res->flags & IORESOURCE_AUTO) { | ||
295 | res->flags = IORESOURCE_IRQ; | ||
296 | pnp_init_resource(res); | ||
297 | } | ||
298 | } | ||
299 | for (idx = 0; idx < PNP_MAX_DMA; idx++) { | ||
300 | res = &dev->res->dma[idx].res; | ||
301 | if (res->flags & IORESOURCE_AUTO) { | ||
302 | res->flags = IORESOURCE_DMA; | ||
303 | pnp_init_resource(res); | ||
304 | } | ||
305 | } | ||
306 | for (idx = 0; idx < PNP_MAX_PORT; idx++) { | ||
307 | res = &dev->res->port[idx].res; | ||
308 | if (res->flags & IORESOURCE_AUTO) { | ||
309 | res->flags = IORESOURCE_IO; | ||
310 | pnp_init_resource(res); | ||
311 | } | ||
312 | } | ||
313 | for (idx = 0; idx < PNP_MAX_MEM; idx++) { | ||
314 | res = &dev->res->mem[idx].res; | ||
315 | if (res->flags & IORESOURCE_AUTO) { | ||
316 | res->flags = IORESOURCE_MEM; | ||
317 | pnp_init_resource(res); | ||
318 | } | ||
319 | } | 209 | } |
320 | } | 210 | } |
321 | 211 | ||