Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
[pandora-kernel.git] / 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@suse.cz>
5  * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
6  *
7  */
8
9 #include <linux/config.h>
10 #include <linux/errno.h>
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/pnp.h>
15 #include "base.h"
16
17 DECLARE_MUTEX(pnp_res_mutex);
18
19 static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
20 {
21         unsigned long *start, *end, *flags;
22
23         if (!dev || !rule)
24                 return -EINVAL;
25
26         if (idx >= PNP_MAX_PORT) {
27                 pnp_err("More than 4 ports is incompatible with pnp specifications.");
28                 /* pretend we were successful so at least the manager won't try again */
29                 return 1;
30         }
31
32         /* check if this resource has been manually set, if so skip */
33         if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
34                 return 1;
35
36         start = &dev->res.port_resource[idx].start;
37         end = &dev->res.port_resource[idx].end;
38         flags = &dev->res.port_resource[idx].flags;
39
40         /* set the initial values */
41         *flags |= rule->flags | IORESOURCE_IO;
42         *flags &=  ~IORESOURCE_UNSET;
43
44         if (!rule->size) {
45                 *flags |= IORESOURCE_DISABLED;
46                 return 1; /* skip disabled resource requests */
47         }
48
49         *start = rule->min;
50         *end = *start + rule->size - 1;
51
52         /* run through until pnp_check_port is happy */
53         while (!pnp_check_port(dev, idx)) {
54                 *start += rule->align;
55                 *end = *start + rule->size - 1;
56                 if (*start > rule->max || !rule->align)
57                         return 0;
58         }
59         return 1;
60 }
61
62 static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
63 {
64         unsigned long *start, *end, *flags;
65
66         if (!dev || !rule)
67                 return -EINVAL;
68
69         if (idx >= PNP_MAX_MEM) {
70                 pnp_err("More than 8 mems is incompatible with pnp specifications.");
71                 /* pretend we were successful so at least the manager won't try again */
72                 return 1;
73         }
74
75         /* check if this resource has been manually set, if so skip */
76         if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
77                 return 1;
78
79         start = &dev->res.mem_resource[idx].start;
80         end = &dev->res.mem_resource[idx].end;
81         flags = &dev->res.mem_resource[idx].flags;
82
83         /* set the initial values */
84         *flags |= rule->flags | IORESOURCE_MEM;
85         *flags &=  ~IORESOURCE_UNSET;
86
87         /* convert pnp flags to standard Linux flags */
88         if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
89                 *flags |= IORESOURCE_READONLY;
90         if (rule->flags & IORESOURCE_MEM_CACHEABLE)
91                 *flags |= IORESOURCE_CACHEABLE;
92         if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
93                 *flags |= IORESOURCE_RANGELENGTH;
94         if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
95                 *flags |= IORESOURCE_SHADOWABLE;
96
97         if (!rule->size) {
98                 *flags |= IORESOURCE_DISABLED;
99                 return 1; /* skip disabled resource requests */
100         }
101
102         *start = rule->min;
103         *end = *start + rule->size -1;
104
105         /* run through until pnp_check_mem is happy */
106         while (!pnp_check_mem(dev, idx)) {
107                 *start += rule->align;
108                 *end = *start + rule->size - 1;
109                 if (*start > rule->max || !rule->align)
110                         return 0;
111         }
112         return 1;
113 }
114
115 static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
116 {
117         unsigned long *start, *end, *flags;
118         int i;
119
120         /* IRQ priority: this table is good for i386 */
121         static unsigned short xtab[16] = {
122                 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
123         };
124
125         if (!dev || !rule)
126                 return -EINVAL;
127
128         if (idx >= PNP_MAX_IRQ) {
129                 pnp_err("More than 2 irqs is incompatible with pnp specifications.");
130                 /* pretend we were successful so at least the manager won't try again */
131                 return 1;
132         }
133
134         /* check if this resource has been manually set, if so skip */
135         if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
136                 return 1;
137
138         start = &dev->res.irq_resource[idx].start;
139         end = &dev->res.irq_resource[idx].end;
140         flags = &dev->res.irq_resource[idx].flags;
141
142         /* set the initial values */
143         *flags |= rule->flags | IORESOURCE_IRQ;
144         *flags &=  ~IORESOURCE_UNSET;
145
146         if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
147                 *flags |= IORESOURCE_DISABLED;
148                 return 1; /* skip disabled resource requests */
149         }
150
151         /* TBD: need check for >16 IRQ */
152         *start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
153         if (*start < PNP_IRQ_NR) {
154                 *end = *start;
155                 return 1;
156         }
157         for (i = 0; i < 16; i++) {
158                 if(test_bit(xtab[i], rule->map)) {
159                         *start = *end = xtab[i];
160                         if(pnp_check_irq(dev, idx))
161                                 return 1;
162                 }
163         }
164         return 0;
165 }
166
167 static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
168 {
169         unsigned long *start, *end, *flags;
170         int i;
171
172         /* DMA priority: this table is good for i386 */
173         static unsigned short xtab[8] = {
174                 1, 3, 5, 6, 7, 0, 2, 4
175         };
176
177         if (!dev || !rule)
178                 return -EINVAL;
179
180         if (idx >= PNP_MAX_DMA) {
181                 pnp_err("More than 2 dmas is incompatible with pnp specifications.");
182                 /* pretend we were successful so at least the manager won't try again */
183                 return 1;
184         }
185
186         /* check if this resource has been manually set, if so skip */
187         if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
188                 return 1;
189
190         start = &dev->res.dma_resource[idx].start;
191         end = &dev->res.dma_resource[idx].end;
192         flags = &dev->res.dma_resource[idx].flags;
193
194         /* set the initial values */
195         *flags |= rule->flags | IORESOURCE_DMA;
196         *flags &=  ~IORESOURCE_UNSET;
197
198         if (!rule->map) {
199                 *flags |= IORESOURCE_DISABLED;
200                 return 1; /* skip disabled resource requests */
201         }
202
203         for (i = 0; i < 8; i++) {
204                 if(rule->map & (1<<xtab[i])) {
205                         *start = *end = xtab[i];
206                         if(pnp_check_dma(dev, idx))
207                                 return 1;
208                 }
209         }
210         return 0;
211 }
212
213 /**
214  * pnp_init_resources - Resets a resource table to default values.
215  * @table: pointer to the desired resource table
216  *
217  */
218 void pnp_init_resource_table(struct pnp_resource_table *table)
219 {
220         int idx;
221         for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
222                 table->irq_resource[idx].name = NULL;
223                 table->irq_resource[idx].start = -1;
224                 table->irq_resource[idx].end = -1;
225                 table->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
226         }
227         for (idx = 0; idx < PNP_MAX_DMA; idx++) {
228                 table->dma_resource[idx].name = NULL;
229                 table->dma_resource[idx].start = -1;
230                 table->dma_resource[idx].end = -1;
231                 table->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
232         }
233         for (idx = 0; idx < PNP_MAX_PORT; idx++) {
234                 table->port_resource[idx].name = NULL;
235                 table->port_resource[idx].start = 0;
236                 table->port_resource[idx].end = 0;
237                 table->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
238         }
239         for (idx = 0; idx < PNP_MAX_MEM; idx++) {
240                 table->mem_resource[idx].name = NULL;
241                 table->mem_resource[idx].start = 0;
242                 table->mem_resource[idx].end = 0;
243                 table->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
244         }
245 }
246
247 /**
248  * pnp_clean_resources - clears resources that were not manually set
249  * @res: the resources to clean
250  *
251  */
252 static void pnp_clean_resource_table(struct pnp_resource_table * res)
253 {
254         int idx;
255         for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
256                 if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
257                         continue;
258                 res->irq_resource[idx].start = -1;
259                 res->irq_resource[idx].end = -1;
260                 res->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
261         }
262         for (idx = 0; idx < PNP_MAX_DMA; idx++) {
263                 if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
264                         continue;
265                 res->dma_resource[idx].start = -1;
266                 res->dma_resource[idx].end = -1;
267                 res->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
268         }
269         for (idx = 0; idx < PNP_MAX_PORT; idx++) {
270                 if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
271                         continue;
272                 res->port_resource[idx].start = 0;
273                 res->port_resource[idx].end = 0;
274                 res->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
275         }
276         for (idx = 0; idx < PNP_MAX_MEM; idx++) {
277                 if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
278                         continue;
279                 res->mem_resource[idx].start = 0;
280                 res->mem_resource[idx].end = 0;
281                 res->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
282         }
283 }
284
285 /**
286  * pnp_assign_resources - assigns resources to the device based on the specified dependent number
287  * @dev: pointer to the desired device
288  * @depnum: the dependent function number
289  *
290  * Only set depnum to 0 if the device does not have dependent options.
291  */
292 static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
293 {
294         struct pnp_port *port;
295         struct pnp_mem *mem;
296         struct pnp_irq *irq;
297         struct pnp_dma *dma;
298         int nport = 0, nmem = 0, nirq = 0, ndma = 0;
299
300         if (!pnp_can_configure(dev))
301                 return -ENODEV;
302
303         down(&pnp_res_mutex);
304         pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
305         if (dev->independent) {
306                 port = dev->independent->port;
307                 mem = dev->independent->mem;
308                 irq = dev->independent->irq;
309                 dma = dev->independent->dma;
310                 while (port) {
311                         if (!pnp_assign_port(dev, port, nport))
312                                 goto fail;
313                         nport++;
314                         port = port->next;
315                 }
316                 while (mem) {
317                         if (!pnp_assign_mem(dev, mem, nmem))
318                                 goto fail;
319                         nmem++;
320                         mem = mem->next;
321                 }
322                 while (irq) {
323                         if (!pnp_assign_irq(dev, irq, nirq))
324                                 goto fail;
325                         nirq++;
326                         irq = irq->next;
327                 }
328                 while (dma) {
329                         if (!pnp_assign_dma(dev, dma, ndma))
330                                 goto fail;
331                         ndma++;
332                         dma = dma->next;
333                 }
334         }
335
336         if (depnum) {
337                 struct pnp_option *dep;
338                 int i;
339                 for (i=1,dep=dev->dependent; i<depnum; i++, dep=dep->next)
340                         if(!dep)
341                                 goto fail;
342                 port =dep->port;
343                 mem = dep->mem;
344                 irq = dep->irq;
345                 dma = dep->dma;
346                 while (port) {
347                         if (!pnp_assign_port(dev, port, nport))
348                                 goto fail;
349                         nport++;
350                         port = port->next;
351                 }
352                 while (mem) {
353                         if (!pnp_assign_mem(dev, mem, nmem))
354                                 goto fail;
355                         nmem++;
356                         mem = mem->next;
357                 }
358                 while (irq) {
359                         if (!pnp_assign_irq(dev, irq, nirq))
360                                 goto fail;
361                         nirq++;
362                         irq = irq->next;
363                 }
364                 while (dma) {
365                         if (!pnp_assign_dma(dev, dma, ndma))
366                                 goto fail;
367                         ndma++;
368                         dma = dma->next;
369                 }
370         } else if (dev->dependent)
371                 goto fail;
372
373         up(&pnp_res_mutex);
374         return 1;
375
376 fail:
377         pnp_clean_resource_table(&dev->res);
378         up(&pnp_res_mutex);
379         return 0;
380 }
381
382 /**
383  * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
384  * @dev: pointer to the desired device
385  * @res: pointer to the new resource config
386  * @mode: 0 or PNP_CONFIG_FORCE
387  *
388  * This function can be used by drivers that want to manually set thier resources.
389  */
390 int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode)
391 {
392         int i;
393         struct pnp_resource_table * bak;
394         if (!dev || !res)
395                 return -EINVAL;
396         if (!pnp_can_configure(dev))
397                 return -ENODEV;
398         bak = pnp_alloc(sizeof(struct pnp_resource_table));
399         if (!bak)
400                 return -ENOMEM;
401         *bak = dev->res;
402
403         down(&pnp_res_mutex);
404         dev->res = *res;
405         if (!(mode & PNP_CONFIG_FORCE)) {
406                 for (i = 0; i < PNP_MAX_PORT; i++) {
407                         if(!pnp_check_port(dev,i))
408                                 goto fail;
409                 }
410                 for (i = 0; i < PNP_MAX_MEM; i++) {
411                         if(!pnp_check_mem(dev,i))
412                                 goto fail;
413                 }
414                 for (i = 0; i < PNP_MAX_IRQ; i++) {
415                         if(!pnp_check_irq(dev,i))
416                                 goto fail;
417                 }
418                 for (i = 0; i < PNP_MAX_DMA; i++) {
419                         if(!pnp_check_dma(dev,i))
420                                 goto fail;
421                 }
422         }
423         up(&pnp_res_mutex);
424
425         kfree(bak);
426         return 0;
427
428 fail:
429         dev->res = *bak;
430         up(&pnp_res_mutex);
431         kfree(bak);
432         return -EINVAL;
433 }
434
435 /**
436  * pnp_auto_config_dev - automatically assigns resources to a device
437  * @dev: pointer to the desired device
438  *
439  */
440 int pnp_auto_config_dev(struct pnp_dev *dev)
441 {
442         struct pnp_option *dep;
443         int i = 1;
444
445         if(!dev)
446                 return -EINVAL;
447
448         if(!pnp_can_configure(dev)) {
449                 pnp_info("Device %s does not support resource configuration.", dev->dev.bus_id);
450                 return -ENODEV;
451         }
452
453         if (!dev->dependent) {
454                 if (pnp_assign_resources(dev, 0))
455                         return 0;
456         } else {
457                 dep = dev->dependent;
458                 do {
459                         if (pnp_assign_resources(dev, i))
460                                 return 0;
461                         dep = dep->next;
462                         i++;
463                 } while (dep);
464         }
465
466         pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id);
467         return -EBUSY;
468 }
469
470 /**
471  * pnp_activate_dev - activates a PnP device for use
472  * @dev: pointer to the desired device
473  *
474  * does not validate or set resources so be careful.
475  */
476 int pnp_activate_dev(struct pnp_dev *dev)
477 {
478         if (!dev)
479                 return -EINVAL;
480         if (dev->active) {
481                 return 0; /* the device is already active */
482         }
483
484         /* ensure resources are allocated */
485         if (pnp_auto_config_dev(dev))
486                 return -EBUSY;
487
488         if (!pnp_can_write(dev)) {
489                 pnp_info("Device %s does not supported activation.", dev->dev.bus_id);
490                 return -EINVAL;
491         }
492
493         if (dev->protocol->set(dev, &dev->res)<0) {
494                 pnp_err("Failed to activate device %s.", dev->dev.bus_id);
495                 return -EIO;
496         }
497
498         dev->active = 1;
499         pnp_info("Device %s activated.", dev->dev.bus_id);
500
501         return 1;
502 }
503
504 /**
505  * pnp_disable_dev - disables device
506  * @dev: pointer to the desired device
507  *
508  * inform the correct pnp protocol so that resources can be used by other devices
509  */
510 int pnp_disable_dev(struct pnp_dev *dev)
511 {
512         if (!dev)
513                 return -EINVAL;
514         if (!dev->active) {
515                 return 0; /* the device is already disabled */
516         }
517
518         if (!pnp_can_disable(dev)) {
519                 pnp_info("Device %s does not supported disabling.", dev->dev.bus_id);
520                 return -EINVAL;
521         }
522         if (dev->protocol->disable(dev)<0) {
523                 pnp_err("Failed to disable device %s.", dev->dev.bus_id);
524                 return -EIO;
525         }
526
527         dev->active = 0;
528         pnp_info("Device %s disabled.", dev->dev.bus_id);
529
530         /* release the resources so that other devices can use them */
531         down(&pnp_res_mutex);
532         pnp_clean_resource_table(&dev->res);
533         up(&pnp_res_mutex);
534
535         return 1;
536 }
537
538 /**
539  * pnp_resource_change - change one resource
540  * @resource: pointer to resource to be changed
541  * @start: start of region
542  * @size: size of region
543  *
544  */
545 void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size)
546 {
547         if (resource == NULL)
548                 return;
549         resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
550         resource->start = start;
551         resource->end = start + size - 1;
552 }
553
554
555 EXPORT_SYMBOL(pnp_manual_config_dev);
556 EXPORT_SYMBOL(pnp_auto_config_dev);
557 EXPORT_SYMBOL(pnp_activate_dev);
558 EXPORT_SYMBOL(pnp_disable_dev);
559 EXPORT_SYMBOL(pnp_resource_change);
560 EXPORT_SYMBOL(pnp_init_resource_table);