xref: /linux/drivers/pnp/resource.c (revision 14b42963f64b98ab61fa9723c03d71aa5ef4f862)
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);
545