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
23static int pnp_reserve_irq[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
24static int pnp_reserve_dma[8] = { [0 ... 7] = -1 };	/* reserve (don't use) some DMA */
25static int pnp_reserve_io[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some I/O region */
26static int pnp_reserve_mem[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some memory region */
27
28
29/*
30 * option registration
31 */
32
33static 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
49struct 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
64struct 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
82int 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
110int 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
129int 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
148int 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
166static 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
177static 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
188static 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
199static 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
210void 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
239int 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
295int 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
351static irqreturn_t pnp_test_handler(int irq, void *dev_id)
352{
353	return IRQ_HANDLED;
354}
355
356int 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
421int 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
481
482/* format is: pnp_reserve_irq=irq1[,irq2] .... */
483
484static int __init pnp_setup_reserve_irq(char *str)
485{
486	int i;
487
488	for (i = 0; i < 16; i++)
489		if (get_option(&str,&pnp_reserve_irq[i]) != 2)
490			break;
491	return 1;
492}
493
494__setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
495
496/* format is: pnp_reserve_dma=dma1[,dma2] .... */
497
498static int __init pnp_setup_reserve_dma(char *str)
499{
500	int i;
501
502	for (i = 0; i < 8; i++)
503		if (get_option(&str,&pnp_reserve_dma[i]) != 2)
504			break;
505	return 1;
506}
507
508__setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
509
510/* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
511
512static int __init pnp_setup_reserve_io(char *str)
513{
514	int i;
515
516	for (i = 0; i < 16; i++)
517		if (get_option(&str,&pnp_reserve_io[i]) != 2)
518			break;
519	return 1;
520}
521
522__setup("pnp_reserve_io=", pnp_setup_reserve_io);
523
524/* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
525
526static int __init pnp_setup_reserve_mem(char *str)
527{
528	int i;
529
530	for (i = 0; i < 16; i++)
531		if (get_option(&str,&pnp_reserve_mem[i]) != 2)
532			break;
533	return 1;
534}
535
536__setup("pnp_reserve_mem=", pnp_setup_reserve_mem);
537