PNPACPI: keep disabled resources when parsing current config
[safe/jmp/linux-2.6] / drivers / pnp / manager.c
1 /*
2  * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
3  *
4  * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
5  * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
6  */
7
8 #include <linux/errno.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/kernel.h>
12 #include <linux/pnp.h>
13 #include <linux/slab.h>
14 #include <linux/bitmap.h>
15 #include <linux/mutex.h>
16 #include "base.h"
17
18 DEFINE_MUTEX(pnp_res_mutex);
19
20 static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
21 {
22         struct resource *res, local_res;
23
24         res = pnp_get_resource(dev, IORESOURCE_IO, idx);
25         if (res) {
26                 dev_dbg(&dev->dev, "  io %d already set to %#llx-%#llx "
27                         "flags %#lx\n", idx, (unsigned long long) res->start,
28                         (unsigned long long) res->end, res->flags);
29                 return 1;
30         }
31
32         res = &local_res;
33         res->flags = rule->flags | IORESOURCE_AUTO;
34         res->start = 0;
35         res->end = 0;
36
37         if (!rule->size) {
38                 res->flags |= IORESOURCE_DISABLED;
39                 dev_dbg(&dev->dev, "  io %d disabled\n", idx);
40                 goto __add;
41         }
42
43         res->start = rule->min;
44         res->end = res->start + rule->size - 1;
45
46         while (!pnp_check_port(dev, res)) {
47                 res->start += rule->align;
48                 res->end = res->start + rule->size - 1;
49                 if (res->start > rule->max || !rule->align) {
50                         dev_dbg(&dev->dev, "  couldn't assign io %d\n", idx);
51                         return 0;
52                 }
53         }
54
55 __add:
56         pnp_add_io_resource(dev, res->start, res->end, res->flags);
57         return 1;
58 }
59
60 static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
61 {
62         struct resource *res, local_res;
63
64         res = pnp_get_resource(dev, IORESOURCE_MEM, idx);
65         if (res) {
66                 dev_dbg(&dev->dev, "  mem %d already set to %#llx-%#llx "
67                         "flags %#lx\n", idx, (unsigned long long) res->start,
68                         (unsigned long long) res->end, res->flags);
69                 return 1;
70         }
71
72         res = &local_res;
73         res->flags = rule->flags | IORESOURCE_AUTO;
74         res->start = 0;
75         res->end = 0;
76
77         if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
78                 res->flags |= IORESOURCE_READONLY;
79         if (rule->flags & IORESOURCE_MEM_CACHEABLE)
80                 res->flags |= IORESOURCE_CACHEABLE;
81         if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
82                 res->flags |= IORESOURCE_RANGELENGTH;
83         if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
84                 res->flags |= IORESOURCE_SHADOWABLE;
85
86         if (!rule->size) {
87                 res->flags |= IORESOURCE_DISABLED;
88                 dev_dbg(&dev->dev, "  mem %d disabled\n", idx);
89                 goto __add;
90         }
91
92         res->start = rule->min;
93         res->end = res->start + rule->size - 1;
94
95         while (!pnp_check_mem(dev, res)) {
96                 res->start += rule->align;
97                 res->end = res->start + rule->size - 1;
98                 if (res->start > rule->max || !rule->align) {
99                         dev_dbg(&dev->dev, "  couldn't assign mem %d\n", idx);
100                         return 0;
101                 }
102         }
103
104 __add:
105         pnp_add_mem_resource(dev, res->start, res->end, res->flags);
106         return 1;
107 }
108
109 static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
110 {
111         struct resource *res, local_res;
112         int i;
113
114         /* IRQ priority: this table is good for i386 */
115         static unsigned short xtab[16] = {
116                 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
117         };
118
119         res = pnp_get_resource(dev, IORESOURCE_IRQ, idx);
120         if (res) {
121                 dev_dbg(&dev->dev, "  irq %d already set to %d flags %#lx\n",
122                         idx, (int) res->start, res->flags);
123                 return 1;
124         }
125
126         res = &local_res;
127         res->flags = rule->flags | IORESOURCE_AUTO;
128         res->start = -1;
129         res->end = -1;
130
131         if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
132                 res->flags |= IORESOURCE_DISABLED;
133                 dev_dbg(&dev->dev, "  irq %d disabled\n", idx);
134                 goto __add;
135         }
136
137         /* TBD: need check for >16 IRQ */
138         res->start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
139         if (res->start < PNP_IRQ_NR) {
140                 res->end = res->start;
141                 goto __add;
142         }
143         for (i = 0; i < 16; i++) {
144                 if (test_bit(xtab[i], rule->map)) {
145                         res->start = res->end = xtab[i];
146                         if (pnp_check_irq(dev, res))
147                                 goto __add;
148                 }
149         }
150         dev_dbg(&dev->dev, "  couldn't assign irq %d\n", idx);
151         return 0;
152
153 __add:
154         pnp_add_irq_resource(dev, res->start, res->flags);
155         return 1;
156 }
157
158 static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
159 {
160         struct resource *res, local_res;
161         int i;
162
163         /* DMA priority: this table is good for i386 */
164         static unsigned short xtab[8] = {
165                 1, 3, 5, 6, 7, 0, 2, 4
166         };
167
168         res = pnp_get_resource(dev, IORESOURCE_DMA, idx);
169         if (res) {
170                 dev_dbg(&dev->dev, "  dma %d already set to %d flags %#lx\n",
171                         idx, (int) res->start, res->flags);
172                 return;
173         }
174
175         res = &local_res;
176         res->flags = rule->flags | IORESOURCE_AUTO;
177         res->start = -1;
178         res->end = -1;
179
180         for (i = 0; i < 8; i++) {
181                 if (rule->map & (1 << xtab[i])) {
182                         res->start = res->end = xtab[i];
183                         if (pnp_check_dma(dev, res))
184                                 goto __add;
185                 }
186         }
187 #ifdef MAX_DMA_CHANNELS
188         res->start = res->end = MAX_DMA_CHANNELS;
189 #endif
190         res->flags |= IORESOURCE_DISABLED;
191         dev_dbg(&dev->dev, "  disable dma %d\n", idx);
192
193 __add:
194         pnp_add_dma_resource(dev, res->start, res->flags);
195 }
196
197 void pnp_init_resources(struct pnp_dev *dev)
198 {
199         pnp_free_resources(dev);
200 }
201
202 static void pnp_clean_resource_table(struct pnp_dev *dev)
203 {
204         struct pnp_resource *pnp_res, *tmp;
205
206         list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
207                 if (pnp_res->res.flags & IORESOURCE_AUTO)
208                         pnp_free_resource(pnp_res);
209         }
210 }
211
212 /**
213  * pnp_assign_resources - assigns resources to the device based on the specified dependent number
214  * @dev: pointer to the desired device
215  * @depnum: the dependent function number
216  *
217  * Only set depnum to 0 if the device does not have dependent options.
218  */
219 static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
220 {
221         struct pnp_port *port;
222         struct pnp_mem *mem;
223         struct pnp_irq *irq;
224         struct pnp_dma *dma;
225         int nport = 0, nmem = 0, nirq = 0, ndma = 0;
226
227         if (!pnp_can_configure(dev))
228                 return -ENODEV;
229
230         dbg_pnp_show_resources(dev, "before pnp_assign_resources");
231         mutex_lock(&pnp_res_mutex);
232         pnp_clean_resource_table(dev);
233         if (dev->independent) {
234                 dev_dbg(&dev->dev, "assigning independent options\n");
235                 port = dev->independent->port;
236                 mem = dev->independent->mem;
237                 irq = dev->independent->irq;
238                 dma = dev->independent->dma;
239                 while (port) {
240                         if (!pnp_assign_port(dev, port, nport))
241                                 goto fail;
242                         nport++;
243                         port = port->next;
244                 }
245                 while (mem) {
246                         if (!pnp_assign_mem(dev, mem, nmem))
247                                 goto fail;
248                         nmem++;
249                         mem = mem->next;
250                 }
251                 while (irq) {
252                         if (!pnp_assign_irq(dev, irq, nirq))
253                                 goto fail;
254                         nirq++;
255                         irq = irq->next;
256                 }
257                 while (dma) {
258                         pnp_assign_dma(dev, dma, ndma);
259                         ndma++;
260                         dma = dma->next;
261                 }
262         }
263
264         if (depnum) {
265                 struct pnp_option *dep;
266                 int i;
267
268                 dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum);
269                 for (i = 1, dep = dev->dependent; i < depnum;
270                      i++, dep = dep->next)
271                         if (!dep)
272                                 goto fail;
273                 port = dep->port;
274                 mem = dep->mem;
275                 irq = dep->irq;
276                 dma = dep->dma;
277                 while (port) {
278                         if (!pnp_assign_port(dev, port, nport))
279                                 goto fail;
280                         nport++;
281                         port = port->next;
282                 }
283                 while (mem) {
284                         if (!pnp_assign_mem(dev, mem, nmem))
285                                 goto fail;
286                         nmem++;
287                         mem = mem->next;
288                 }
289                 while (irq) {
290                         if (!pnp_assign_irq(dev, irq, nirq))
291                                 goto fail;
292                         nirq++;
293                         irq = irq->next;
294                 }
295                 while (dma) {
296                         pnp_assign_dma(dev, dma, ndma);
297                         ndma++;
298                         dma = dma->next;
299                 }
300         } else if (dev->dependent)
301                 goto fail;
302
303         mutex_unlock(&pnp_res_mutex);
304         dbg_pnp_show_resources(dev, "after pnp_assign_resources");
305         return 1;
306
307 fail:
308         pnp_clean_resource_table(dev);
309         mutex_unlock(&pnp_res_mutex);
310         dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)");
311         return 0;
312 }
313
314 /**
315  * pnp_auto_config_dev - automatically assigns resources to a device
316  * @dev: pointer to the desired device
317  */
318 int pnp_auto_config_dev(struct pnp_dev *dev)
319 {
320         struct pnp_option *dep;
321         int i = 1;
322
323         if (!pnp_can_configure(dev)) {
324                 dev_dbg(&dev->dev, "configuration not supported\n");
325                 return -ENODEV;
326         }
327
328         if (!dev->dependent) {
329                 if (pnp_assign_resources(dev, 0))
330                         return 0;
331         } else {
332                 dep = dev->dependent;
333                 do {
334                         if (pnp_assign_resources(dev, i))
335                                 return 0;
336                         dep = dep->next;
337                         i++;
338                 } while (dep);
339         }
340
341         dev_err(&dev->dev, "unable to assign resources\n");
342         return -EBUSY;
343 }
344
345 /**
346  * pnp_start_dev - low-level start of the PnP device
347  * @dev: pointer to the desired device
348  *
349  * assumes that resources have already been allocated
350  */
351 int pnp_start_dev(struct pnp_dev *dev)
352 {
353         if (!pnp_can_write(dev)) {
354                 dev_dbg(&dev->dev, "activation not supported\n");
355                 return -EINVAL;
356         }
357
358         dbg_pnp_show_resources(dev, "pnp_start_dev");
359         if (dev->protocol->set(dev) < 0) {
360                 dev_err(&dev->dev, "activation failed\n");
361                 return -EIO;
362         }
363
364         dev_info(&dev->dev, "activated\n");
365         return 0;
366 }
367
368 /**
369  * pnp_stop_dev - low-level disable of the PnP device
370  * @dev: pointer to the desired device
371  *
372  * does not free resources
373  */
374 int pnp_stop_dev(struct pnp_dev *dev)
375 {
376         if (!pnp_can_disable(dev)) {
377                 dev_dbg(&dev->dev, "disabling not supported\n");
378                 return -EINVAL;
379         }
380         if (dev->protocol->disable(dev) < 0) {
381                 dev_err(&dev->dev, "disable failed\n");
382                 return -EIO;
383         }
384
385         dev_info(&dev->dev, "disabled\n");
386         return 0;
387 }
388
389 /**
390  * pnp_activate_dev - activates a PnP device for use
391  * @dev: pointer to the desired device
392  *
393  * does not validate or set resources so be careful.
394  */
395 int pnp_activate_dev(struct pnp_dev *dev)
396 {
397         int error;
398
399         if (dev->active)
400                 return 0;
401
402         /* ensure resources are allocated */
403         if (pnp_auto_config_dev(dev))
404                 return -EBUSY;
405
406         error = pnp_start_dev(dev);
407         if (error)
408                 return error;
409
410         dev->active = 1;
411         return 0;
412 }
413
414 /**
415  * pnp_disable_dev - disables device
416  * @dev: pointer to the desired device
417  *
418  * inform the correct pnp protocol so that resources can be used by other devices
419  */
420 int pnp_disable_dev(struct pnp_dev *dev)
421 {
422         int error;
423
424         if (!dev->active)
425                 return 0;
426
427         error = pnp_stop_dev(dev);
428         if (error)
429                 return error;
430
431         dev->active = 0;
432
433         /* release the resources so that other devices can use them */
434         mutex_lock(&pnp_res_mutex);
435         pnp_clean_resource_table(dev);
436         mutex_unlock(&pnp_res_mutex);
437
438         return 0;
439 }
440
441 EXPORT_SYMBOL(pnp_start_dev);
442 EXPORT_SYMBOL(pnp_stop_dev);
443 EXPORT_SYMBOL(pnp_activate_dev);
444 EXPORT_SYMBOL(pnp_disable_dev);