PNP: Lindent all source files
[powerpc.git] / 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  * option registration
30  */
31
32 static struct pnp_option *pnp_build_option(int priority)
33 {
34         struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
35
36         /* check if pnp_alloc ran out of memory */
37         if (!option)
38                 return NULL;
39
40         option->priority = priority & 0xff;
41         /* make sure the priority is valid */
42         if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
43                 option->priority = PNP_RES_PRIORITY_INVALID;
44
45         return option;
46 }
47
48 struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev)
49 {
50         struct pnp_option *option;
51         if (!dev)
52                 return NULL;
53
54         option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
55
56         /* this should never happen but if it does we'll try to continue */
57         if (dev->independent)
58                 pnp_err("independent resource already registered");
59         dev->independent = option;
60         return option;
61 }
62
63 struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
64                                                  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  * resource validity checking
227  */
228
229 #define length(start, end) (*(end) - *(start) + 1)
230
231 /* Two ranges conflict if one doesn't end before the other starts */
232 #define ranged_conflict(starta, enda, startb, endb) \
233         !((*(enda) < *(startb)) || (*(endb) < *(starta)))
234
235 #define cannot_compare(flags) \
236 ((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
237
238 int pnp_check_port(struct pnp_dev *dev, int idx)
239 {
240         int tmp;
241         struct pnp_dev *tdev;
242         resource_size_t *port, *end, *tport, *tend;
243         port = &dev->res.port_resource[idx].start;
244         end = &dev->res.port_resource[idx].end;
245
246         /* if the resource doesn't exist, don't complain about it */
247         if (cannot_compare(dev->res.port_resource[idx].flags))
248                 return 1;
249
250         /* check if the resource is already in use, skip if the
251          * device is active because it itself may be in use */
252         if (!dev->active) {
253                 if (__check_region(&ioport_resource, *port, length(port, end)))
254                         return 0;
255         }
256
257         /* check if the resource is reserved */
258         for (tmp = 0; tmp < 8; tmp++) {
259                 int rport = pnp_reserve_io[tmp << 1];
260                 int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
261                 if (ranged_conflict(port, end, &rport, &rend))
262                         return 0;
263         }
264
265         /* check for internal conflicts */
266         for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
267                 if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
268                         tport = &dev->res.port_resource[tmp].start;
269                         tend = &dev->res.port_resource[tmp].end;
270                         if (ranged_conflict(port, end, tport, tend))
271                                 return 0;
272                 }
273         }
274
275         /* check for conflicts with other pnp devices */
276         pnp_for_each_dev(tdev) {
277                 if (tdev == dev)
278                         continue;
279                 for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
280                         if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
281                                 if (cannot_compare
282                                     (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
339                                     (tdev->res.mem_resource[tmp].flags))
340                                         continue;
341                                 taddr = &tdev->res.mem_resource[tmp].start;
342                                 tend = &tdev->res.mem_resource[tmp].end;
343                                 if (ranged_conflict(addr, end, taddr, tend))
344                                         return 0;
345                         }
346                 }
347         }
348
349         return 1;
350 }
351
352 static irqreturn_t pnp_test_handler(int irq, void *dev_id)
353 {
354         return IRQ_HANDLED;
355 }
356
357 int pnp_check_irq(struct pnp_dev *dev, int idx)
358 {
359         int tmp;
360         struct pnp_dev *tdev;
361         resource_size_t *irq = &dev->res.irq_resource[idx].start;
362
363         /* if the resource doesn't exist, don't complain about it */
364         if (cannot_compare(dev->res.irq_resource[idx].flags))
365                 return 1;
366
367         /* check if the resource is valid */
368         if (*irq < 0 || *irq > 15)
369                 return 0;
370
371         /* check if the resource is reserved */
372         for (tmp = 0; tmp < 16; tmp++) {
373                 if (pnp_reserve_irq[tmp] == *irq)
374                         return 0;
375         }
376
377         /* check for internal conflicts */
378         for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
379                 if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
380                         if (dev->res.irq_resource[tmp].start == *irq)
381                                 return 0;
382                 }
383         }
384
385 #ifdef CONFIG_PCI
386         /* check if the resource is being used by a pci device */
387         {
388                 struct pci_dev *pci = NULL;
389                 for_each_pci_dev(pci) {
390                         if (pci->irq == *irq)
391                                 return 0;
392                 }
393         }
394 #endif
395
396         /* check if the resource is already in use, skip if the
397          * device is active because it itself may be in use */
398         if (!dev->active) {
399                 if (request_irq(*irq, pnp_test_handler,
400                                 IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
401                         return 0;
402                 free_irq(*irq, NULL);
403         }
404
405         /* check for conflicts with other pnp devices */
406         pnp_for_each_dev(tdev) {
407                 if (tdev == dev)
408                         continue;
409                 for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
410                         if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
411                                 if (cannot_compare
412                                     (tdev->res.irq_resource[tmp].flags))
413                                         continue;
414                                 if ((tdev->res.irq_resource[tmp].start == *irq))
415                                         return 0;
416                         }
417                 }
418         }
419
420         return 1;
421 }
422
423 int pnp_check_dma(struct pnp_dev *dev, int idx)
424 {
425 #ifndef CONFIG_IA64
426         int tmp;
427         struct pnp_dev *tdev;
428         resource_size_t *dma = &dev->res.dma_resource[idx].start;
429
430         /* if the resource doesn't exist, don't complain about it */
431         if (cannot_compare(dev->res.dma_resource[idx].flags))
432                 return 1;
433
434         /* check if the resource is valid */
435         if (*dma < 0 || *dma == 4 || *dma > 7)
436                 return 0;
437
438         /* check if the resource is reserved */
439         for (tmp = 0; tmp < 8; tmp++) {
440                 if (pnp_reserve_dma[tmp] == *dma)
441                         return 0;
442         }
443
444         /* check for internal conflicts */
445         for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
446                 if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
447                         if (dev->res.dma_resource[tmp].start == *dma)
448                                 return 0;
449                 }
450         }
451
452         /* check if the resource is already in use, skip if the
453          * device is active because it itself may be in use */
454         if (!dev->active) {
455                 if (request_dma(*dma, "pnp"))
456                         return 0;
457                 free_dma(*dma);
458         }
459
460         /* check for conflicts with other pnp devices */
461         pnp_for_each_dev(tdev) {
462                 if (tdev == dev)
463                         continue;
464                 for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
465                         if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
466                                 if (cannot_compare
467                                     (tdev->res.dma_resource[tmp].flags))
468                                         continue;
469                                 if ((tdev->res.dma_resource[tmp].start == *dma))
470                                         return 0;
471                         }
472                 }
473         }
474
475         return 1;
476 #else
477         /* IA64 hasn't legacy DMA */
478         return 0;
479 #endif
480 }
481
482 #if 0
483 EXPORT_SYMBOL(pnp_register_dependent_option);
484 EXPORT_SYMBOL(pnp_register_independent_option);
485 EXPORT_SYMBOL(pnp_register_irq_resource);
486 EXPORT_SYMBOL(pnp_register_dma_resource);
487 EXPORT_SYMBOL(pnp_register_port_resource);
488 EXPORT_SYMBOL(pnp_register_mem_resource);
489 #endif /*  0  */
490
491 /* format is: pnp_reserve_irq=irq1[,irq2] .... */
492
493 static int __init pnp_setup_reserve_irq(char *str)
494 {
495         int i;
496
497         for (i = 0; i < 16; i++)
498                 if (get_option(&str, &pnp_reserve_irq[i]) != 2)
499                         break;
500         return 1;
501 }
502
503 __setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
504
505 /* format is: pnp_reserve_dma=dma1[,dma2] .... */
506
507 static int __init pnp_setup_reserve_dma(char *str)
508 {
509         int i;
510
511         for (i = 0; i < 8; i++)
512                 if (get_option(&str, &pnp_reserve_dma[i]) != 2)
513                         break;
514         return 1;
515 }
516
517 __setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
518
519 /* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
520
521 static int __init pnp_setup_reserve_io(char *str)
522 {
523         int i;
524
525         for (i = 0; i < 16; i++)
526                 if (get_option(&str, &pnp_reserve_io[i]) != 2)
527                         break;
528         return 1;
529 }
530
531 __setup("pnp_reserve_io=", pnp_setup_reserve_io);
532
533 /* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
534
535 static int __init pnp_setup_reserve_mem(char *str)
536 {
537         int i;
538
539         for (i = 0; i < 16; i++)
540                 if (get_option(&str, &pnp_reserve_mem[i]) != 2)
541                         break;
542         return 1;
543 }
544
545 __setup("pnp_reserve_mem=", pnp_setup_reserve_mem);