Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[linux-2.6] / drivers / pnp / resource.c
1 /*
2  * resource.c - Contains functions for registering and analyzing resource information
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/module.h>
10 #include <linux/errno.h>
11 #include <linux/interrupt.h>
12 #include <linux/kernel.h>
13 #include <asm/io.h>
14 #include <asm/dma.h>
15 #include <asm/irq.h>
16 #include <linux/pci.h>
17 #include <linux/ioport.h>
18 #include <linux/init.h>
19
20 #include <linux/pnp.h>
21 #include "base.h"
22
23 static int pnp_reserve_irq[16] = { [0 ... 15] = -1 };   /* reserve (don't use) some IRQ */
24 static int pnp_reserve_dma[8] = { [0 ... 7] = -1 };     /* reserve (don't use) some DMA */
25 static int pnp_reserve_io[16] = { [0 ... 15] = -1 };    /* reserve (don't use) some I/O region */
26 static int pnp_reserve_mem[16] = { [0 ... 15] = -1 };   /* reserve (don't use) some memory region */
27
28
29 /*
30  * option registration
31  */
32
33 static struct pnp_option * pnp_build_option(int priority)
34 {
35         struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
36
37         /* check if pnp_alloc ran out of memory */
38         if (!option)
39                 return NULL;
40
41         option->priority = priority & 0xff;
42         /* make sure the priority is valid */
43         if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
44                 option->priority = PNP_RES_PRIORITY_INVALID;
45
46         return option;
47 }
48
49 struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev)
50 {
51         struct pnp_option *option;
52         if (!dev)
53                 return NULL;
54
55         option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
56
57         /* this should never happen but if it does we'll try to continue */
58         if (dev->independent)
59                 pnp_err("independent resource already registered");
60         dev->independent = option;
61         return option;
62 }
63
64 struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority)
65 {
66         struct pnp_option *option;
67         if (!dev)
68                 return NULL;
69
70         option = pnp_build_option(priority);
71
72         if (dev->dependent) {
73                 struct pnp_option *parent = dev->dependent;
74                 while (parent->next)
75                         parent = parent->next;
76                 parent->next = option;
77         } else
78                 dev->dependent = option;
79         return option;
80 }
81
82 int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
83 {
84         struct pnp_irq *ptr;
85         if (!option)
86                 return -EINVAL;
87         if (!data)
88                 return -EINVAL;
89
90         ptr = option->irq;
91         while (ptr && ptr->next)
92                 ptr = ptr->next;
93         if (ptr)
94                 ptr->next = data;
95         else
96                 option->irq = data;
97
98 #ifdef CONFIG_PCI
99         {
100                 int i;
101
102                 for (i = 0; i < 16; i++)
103                         if (test_bit(i, data->map))
104                                 pcibios_penalize_isa_irq(i, 0);
105         }
106 #endif
107         return 0;
108 }
109
110 int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
111 {
112         struct pnp_dma *ptr;
113         if (!option)
114                 return -EINVAL;
115         if (!data)
116                 return -EINVAL;
117
118         ptr = option->dma;
119         while (ptr && ptr->next)
120                 ptr = ptr->next;
121         if (ptr)
122                 ptr->next = data;
123         else
124                 option->dma = data;
125
126         return 0;
127 }
128
129 int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
130 {
131         struct pnp_port *ptr;
132         if (!option)
133                 return -EINVAL;
134         if (!data)
135                 return -EINVAL;
136
137         ptr = option->port;
138         while (ptr && ptr->next)
139                 ptr = ptr->next;
140         if (ptr)
141                 ptr->next = data;
142         else
143                 option->port = data;
144
145         return 0;
146 }
147
148 int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
149 {
150         struct pnp_mem *ptr;
151         if (!option)
152                 return -EINVAL;
153         if (!data)
154                 return -EINVAL;
155
156         ptr = option->mem;
157         while (ptr && ptr->next)
158                 ptr = ptr->next;
159         if (ptr)
160                 ptr->next = data;
161         else
162                 option->mem = data;
163         return 0;
164 }
165
166 static void pnp_free_port(struct pnp_port *port)
167 {
168         struct pnp_port *next;
169
170         while (port) {
171                 next = port->next;
172                 kfree(port);
173                 port = next;
174         }
175 }
176
177 static void pnp_free_irq(struct pnp_irq *irq)
178 {
179         struct pnp_irq *next;
180
181         while (irq) {
182                 next = irq->next;
183                 kfree(irq);
184                 irq = next;
185         }
186 }
187
188 static void pnp_free_dma(struct pnp_dma *dma)
189 {
190         struct pnp_dma *next;
191
192         while (dma) {
193                 next = dma->next;
194                 kfree(dma);
195                 dma = next;
196         }
197 }
198
199 static void pnp_free_mem(struct pnp_mem *mem)
200 {
201         struct pnp_mem *next;
202
203         while (mem) {
204                 next = mem->next;
205                 kfree(mem);
206                 mem = next;
207         }
208 }
209
210 void pnp_free_option(struct pnp_option *option)
211 {
212         struct pnp_option *next;
213
214         while (option) {
215                 next = option->next;
216                 pnp_free_port(option->port);
217                 pnp_free_irq(option->irq);
218                 pnp_free_dma(option->dma);
219                 pnp_free_mem(option->mem);
220                 kfree(option);
221                 option = next;
222         }
223 }
224
225
226 /*
227  * resource validity checking
228  */
229
230 #define length(start, end) (*(end) - *(start) + 1)
231
232 /* Two ranges conflict if one doesn't end before the other starts */
233 #define ranged_conflict(starta, enda, startb, endb) \
234         !((*(enda) < *(startb)) || (*(endb) < *(starta)))
235
236 #define cannot_compare(flags) \
237 ((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
238
239 int pnp_check_port(struct pnp_dev * dev, int idx)
240 {
241         int tmp;
242         struct pnp_dev *tdev;
243         resource_size_t *port, *end, *tport, *tend;
244         port = &dev->res.port_resource[idx].start;
245         end = &dev->res.port_resource[idx].end;
246
247         /* if the resource doesn't exist, don't complain about it */
248         if (cannot_compare(dev->res.port_resource[idx].flags))
249                 return 1;
250
251         /* check if the resource is already in use, skip if the
252          * device is active because it itself may be in use */
253         if(!dev->active) {
254                 if (__check_region(&ioport_resource, *port, length(port,end)))
255                         return 0;
256         }
257
258         /* check if the resource is reserved */
259         for (tmp = 0; tmp < 8; tmp++) {
260                 int rport = pnp_reserve_io[tmp << 1];
261                 int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
262                 if (ranged_conflict(port,end,&rport,&rend))
263                         return 0;
264         }
265
266         /* check for internal conflicts */
267         for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
268                 if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
269                         tport = &dev->res.port_resource[tmp].start;
270                         tend = &dev->res.port_resource[tmp].end;
271                         if (ranged_conflict(port,end,tport,tend))
272                                 return 0;
273                 }
274         }
275
276         /* check for conflicts with other pnp devices */
277         pnp_for_each_dev(tdev) {
278                 if (tdev == dev)
279                         continue;
280                 for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
281                         if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
282                                 if (cannot_compare(tdev->res.port_resource[tmp].flags))
283                                         continue;
284                                 tport = &tdev->res.port_resource[tmp].start;
285                                 tend = &tdev->res.port_resource[tmp].end;
286                                 if (ranged_conflict(port,end,tport,tend))
287                                         return 0;
288                         }
289                 }
290         }
291
292         return 1;
293 }
294
295 int pnp_check_mem(struct pnp_dev * dev, int idx)
296 {
297         int tmp;
298         struct pnp_dev *tdev;
299         resource_size_t *addr, *end, *taddr, *tend;
300         addr = &dev->res.mem_resource[idx].start;
301         end = &dev->res.mem_resource[idx].end;
302
303         /* if the resource doesn't exist, don't complain about it */
304         if (cannot_compare(dev->res.mem_resource[idx].flags))
305                 return 1;
306
307         /* check if the resource is already in use, skip if the
308          * device is active because it itself may be in use */
309         if(!dev->active) {
310                 if (check_mem_region(*addr, length(addr,end)))
311                         return 0;
312         }
313
314         /* check if the resource is reserved */
315         for (tmp = 0; tmp < 8; tmp++) {
316                 int raddr = pnp_reserve_mem[tmp << 1];
317                 int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
318                 if (ranged_conflict(addr,end,&raddr,&rend))
319                         return 0;
320         }
321
322         /* check for internal conflicts */
323         for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
324                 if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
325                         taddr = &dev->res.mem_resource[tmp].start;
326                         tend = &dev->res.mem_resource[tmp].end;
327                         if (ranged_conflict(addr,end,taddr,tend))
328                                 return 0;
329                 }
330         }
331
332         /* check for conflicts with other pnp devices */
333         pnp_for_each_dev(tdev) {
334                 if (tdev == dev)
335                         continue;
336                 for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
337                         if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
338                                 if (cannot_compare(tdev->res.mem_resource[tmp].flags))
339                                         continue;
340                                 taddr = &tdev->res.mem_resource[tmp].start;
341                                 tend = &tdev->res.mem_resource[tmp].end;
342                                 if (ranged_conflict(addr,end,taddr,tend))
343                                         return 0;
344                         }
345                 }
346         }
347
348         return 1;
349 }
350
351 static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs)
352 {
353         return IRQ_HANDLED;
354 }
355
356 int pnp_check_irq(struct pnp_dev * dev, int idx)
357 {
358         int tmp;
359         struct pnp_dev *tdev;
360         resource_size_t * irq = &dev->res.irq_resource[idx].start;
361
362         /* if the resource doesn't exist, don't complain about it */
363         if (cannot_compare(dev->res.irq_resource[idx].flags))
364                 return 1;
365
366         /* check if the resource is valid */
367         if (*irq < 0 || *irq > 15)
368                 return 0;
369
370         /* check if the resource is reserved */
371         for (tmp = 0; tmp < 16; tmp++) {
372                 if (pnp_reserve_irq[tmp] == *irq)
373                         return 0;
374         }
375
376         /* check for internal conflicts */
377         for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
378                 if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
379                         if (dev->res.irq_resource[tmp].start == *irq)
380                                 return 0;
381                 }
382         }
383
384 #ifdef CONFIG_PCI
385         /* check if the resource is being used by a pci device */
386         {
387                 struct pci_dev *pci = NULL;
388                 for_each_pci_dev(pci) {
389                         if (pci->irq == *irq)
390                                 return 0;
391                 }
392         }
393 #endif
394
395         /* check if the resource is already in use, skip if the
396          * device is active because it itself may be in use */
397         if(!dev->active) {
398                 if (request_irq(*irq, pnp_test_handler,
399                                 IRQF_DISABLED|IRQF_PROBE_SHARED, "pnp", NULL))
400                         return 0;
401                 free_irq(*irq, NULL);
402         }
403
404         /* check for conflicts with other pnp devices */
405         pnp_for_each_dev(tdev) {
406                 if (tdev == dev)
407                         continue;
408                 for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
409                         if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
410                                 if (cannot_compare(tdev->res.irq_resource[tmp].flags))
411                                         continue;
412                                 if ((tdev->res.irq_resource[tmp].start == *irq))
413                                         return 0;
414                         }
415                 }
416         }
417
418         return 1;
419 }
420
421 int pnp_check_dma(struct pnp_dev * dev, int idx)
422 {
423 #ifndef CONFIG_IA64
424         int tmp;
425         struct pnp_dev *tdev;
426         resource_size_t * dma = &dev->res.dma_resource[idx].start;
427
428         /* if the resource doesn't exist, don't complain about it */
429         if (cannot_compare(dev->res.dma_resource[idx].flags))
430                 return 1;
431
432         /* check if the resource is valid */
433         if (*dma < 0 || *dma == 4 || *dma > 7)
434                 return 0;
435
436         /* check if the resource is reserved */
437         for (tmp = 0; tmp < 8; tmp++) {
438                 if (pnp_reserve_dma[tmp] == *dma)
439                         return 0;
440         }
441
442         /* check for internal conflicts */
443         for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
444                 if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
445                         if (dev->res.dma_resource[tmp].start == *dma)
446                                 return 0;
447                 }
448         }
449
450         /* check if the resource is already in use, skip if the
451          * device is active because it itself may be in use */
452         if(!dev->active) {
453                 if (request_dma(*dma, "pnp"))
454                         return 0;
455                 free_dma(*dma);
456         }
457
458         /* check for conflicts with other pnp devices */
459         pnp_for_each_dev(tdev) {
460                 if (tdev == dev)
461                         continue;
462                 for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
463                         if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
464                                 if (cannot_compare(tdev->res.dma_resource[tmp].flags))
465                                         continue;
466                                 if ((tdev->res.dma_resource[tmp].start == *dma))
467                                         return 0;
468                         }
469                 }
470         }
471
472         return 1;
473 #else
474         /* IA64 hasn't legacy DMA */
475         return 0;
476 #endif
477 }
478
479
480 #if 0
481 EXPORT_SYMBOL(pnp_register_dependent_option);
482 EXPORT_SYMBOL(pnp_register_independent_option);
483 EXPORT_SYMBOL(pnp_register_irq_resource);
484 EXPORT_SYMBOL(pnp_register_dma_resource);
485 EXPORT_SYMBOL(pnp_register_port_resource);
486 EXPORT_SYMBOL(pnp_register_mem_resource);
487 #endif  /*  0  */
488
489
490 /* format is: pnp_reserve_irq=irq1[,irq2] .... */
491
492 static int __init pnp_setup_reserve_irq(char *str)
493 {
494         int i;
495
496         for (i = 0; i < 16; i++)
497                 if (get_option(&str,&pnp_reserve_irq[i]) != 2)
498                         break;
499         return 1;
500 }
501
502 __setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
503
504 /* format is: pnp_reserve_dma=dma1[,dma2] .... */
505
506 static int __init pnp_setup_reserve_dma(char *str)
507 {
508         int i;
509
510         for (i = 0; i < 8; i++)
511                 if (get_option(&str,&pnp_reserve_dma[i]) != 2)
512                         break;
513         return 1;
514 }
515
516 __setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
517
518 /* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
519
520 static int __init pnp_setup_reserve_io(char *str)
521 {
522         int i;
523
524         for (i = 0; i < 16; i++)
525                 if (get_option(&str,&pnp_reserve_io[i]) != 2)
526                         break;
527         return 1;
528 }
529
530 __setup("pnp_reserve_io=", pnp_setup_reserve_io);
531
532 /* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
533
534 static int __init pnp_setup_reserve_mem(char *str)
535 {
536         int i;
537
538         for (i = 0; i < 16; i++)
539                 if (get_option(&str,&pnp_reserve_mem[i]) != 2)
540                         break;
541         return 1;
542 }
543
544 __setup("pnp_reserve_mem=", pnp_setup_reserve_mem);