Blame view

drivers/pnp/resource.c 16.7 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
  /*
   * resource.c - Contains functions for registering and analyzing resource information
   *
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
5
   * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
   * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
7
8
   * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
   *	Bjorn Helgaas <bjorn.helgaas@hp.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
18
19
20
21
22
23
  #include <linux/errno.h>
  #include <linux/interrupt.h>
  #include <linux/kernel.h>
  #include <asm/io.h>
  #include <asm/dma.h>
  #include <asm/irq.h>
  #include <linux/pci.h>
  #include <linux/ioport.h>
  #include <linux/init.h>
  
  #include <linux/pnp.h>
  #include "base.h"
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
24
25
26
27
  static int pnp_reserve_irq[16] = {[0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
  static int pnp_reserve_dma[8] = {[0 ... 7] = -1 };	/* reserve (don't use) some DMA */
  static int pnp_reserve_io[16] = {[0 ... 15] = -1 };	/* reserve (don't use) some I/O region */
  static int pnp_reserve_mem[16] = {[0 ... 15] = -1 };	/* reserve (don't use) some memory region */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
  
  /*
   * option registration
   */
62c6dae02   Rashika Kheria   PNP: Mark the fun...
32
  static struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type,
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
33
  				    unsigned int option_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
35
  	struct pnp_option *option;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
37
  	option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
  	if (!option)
  		return NULL;
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
40
41
  	option->flags = option_flags;
  	option->type = type;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
42

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
43
  	list_add_tail(&option->list, &dev->options);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
  	return option;
  }
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
46
  int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
c227536b4   Bjorn Helgaas   PNP: centralize r...
47
  			      pnp_irq_mask_t *map, unsigned char flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
49
50
  	struct pnp_option *option;
  	struct pnp_irq *irq;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
51

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
52
53
  	option = pnp_build_option(dev, IORESOURCE_IRQ, option_flags);
  	if (!option)
c227536b4   Bjorn Helgaas   PNP: centralize r...
54
  		return -ENOMEM;
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
55
  	irq = &option->u.irq;
2d29a7a79   Bjorn Helgaas   PNP: rename pnp_r...
56
57
  	irq->map = *map;
  	irq->flags = flags;
c227536b4   Bjorn Helgaas   PNP: centralize r...
58

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
62
63
  #ifdef CONFIG_PCI
  	{
  		int i;
  
  		for (i = 0; i < 16; i++)
2d29a7a79   Bjorn Helgaas   PNP: rename pnp_r...
64
  			if (test_bit(i, irq->map.bits))
c9c3e457d   David Shaohua Li   [ACPI] PNPACPI vs...
65
  				pcibios_penalize_isa_irq(i, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
  	}
  #endif
c1caf06cc   Bjorn Helgaas   PNP: add debug ou...
68

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
69
  	dbg_pnp_show_option(dev, option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  	return 0;
  }
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
72
  int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
c227536b4   Bjorn Helgaas   PNP: centralize r...
73
  			      unsigned char map, unsigned char flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
75
76
  	struct pnp_option *option;
  	struct pnp_dma *dma;
c227536b4   Bjorn Helgaas   PNP: centralize r...
77

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
78
79
  	option = pnp_build_option(dev, IORESOURCE_DMA, option_flags);
  	if (!option)
c227536b4   Bjorn Helgaas   PNP: centralize r...
80
  		return -ENOMEM;
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
81
  	dma = &option->u.dma;
2d29a7a79   Bjorn Helgaas   PNP: rename pnp_r...
82
83
  	dma->map = map;
  	dma->flags = flags;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
84

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
85
  	dbg_pnp_show_option(dev, option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
  	return 0;
  }
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
88
  int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
c227536b4   Bjorn Helgaas   PNP: centralize r...
89
90
91
  			       resource_size_t min, resource_size_t max,
  			       resource_size_t align, resource_size_t size,
  			       unsigned char flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
93
94
  	struct pnp_option *option;
  	struct pnp_port *port;
c227536b4   Bjorn Helgaas   PNP: centralize r...
95

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
96
97
  	option = pnp_build_option(dev, IORESOURCE_IO, option_flags);
  	if (!option)
c227536b4   Bjorn Helgaas   PNP: centralize r...
98
  		return -ENOMEM;
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
99
  	port = &option->u.port;
2d29a7a79   Bjorn Helgaas   PNP: rename pnp_r...
100
101
102
103
104
  	port->min = min;
  	port->max = max;
  	port->align = align;
  	port->size = size;
  	port->flags = flags;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
105

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
106
  	dbg_pnp_show_option(dev, option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
  	return 0;
  }
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
109
  int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
c227536b4   Bjorn Helgaas   PNP: centralize r...
110
111
112
  			      resource_size_t min, resource_size_t max,
  			      resource_size_t align, resource_size_t size,
  			      unsigned char flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
114
115
  	struct pnp_option *option;
  	struct pnp_mem *mem;
c227536b4   Bjorn Helgaas   PNP: centralize r...
116

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
117
118
  	option = pnp_build_option(dev, IORESOURCE_MEM, option_flags);
  	if (!option)
c227536b4   Bjorn Helgaas   PNP: centralize r...
119
  		return -ENOMEM;
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
120
  	mem = &option->u.mem;
2d29a7a79   Bjorn Helgaas   PNP: rename pnp_r...
121
122
123
124
125
  	mem->min = min;
  	mem->max = max;
  	mem->align = align;
  	mem->size = size;
  	mem->flags = flags;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
126

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
127
  	dbg_pnp_show_option(dev, option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
  	return 0;
  }
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
130
  void pnp_free_options(struct pnp_dev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
132
  	struct pnp_option *option, *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
134
135
  	list_for_each_entry_safe(option, tmp, &dev->options, list) {
  		list_del(&option->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  		kfree(option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
144
145
146
147
148
149
  /*
   * resource validity checking
   */
  
  #define length(start, end) (*(end) - *(start) + 1)
  
  /* Two ranges conflict if one doesn't end before the other starts */
  #define ranged_conflict(starta, enda, startb, endb) \
  	!((*(enda) < *(startb)) || (*(endb) < *(starta)))
  
  #define cannot_compare(flags) \
aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
150
  ((flags) & IORESOURCE_DISABLED)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151

f5d94ff01   Bjorn Helgaas   PNP: pass resourc...
152
  int pnp_check_port(struct pnp_dev *dev, struct resource *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  {
ecfa935a2   Bjorn Helgaas   PNP: use conventi...
154
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  	struct pnp_dev *tdev;
f5d94ff01   Bjorn Helgaas   PNP: pass resourc...
156
  	struct resource *tres;
b60ba8343   Greg Kroah-Hartman   [PATCH] 64bit res...
157
  	resource_size_t *port, *end, *tport, *tend;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
158

30c016a0c   Bjorn Helgaas   PNP: reduce redun...
159
160
  	port = &res->start;
  	end = &res->end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
  
  	/* if the resource doesn't exist, don't complain about it */
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
163
  	if (cannot_compare(res->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
  		return 1;
  
  	/* check if the resource is already in use, skip if the
  	 * device is active because it itself may be in use */
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
168
  	if (!dev->active) {
eeeb98bf0   Jakub Sitnicki   PNP: Switch from ...
169
  		if (!request_region(*port, length(port, end), "pnp"))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  			return 0;
eeeb98bf0   Jakub Sitnicki   PNP: Switch from ...
171
  		release_region(*port, length(port, end));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
  	}
  
  	/* check if the resource is reserved */
ecfa935a2   Bjorn Helgaas   PNP: use conventi...
175
176
177
  	for (i = 0; i < 8; i++) {
  		int rport = pnp_reserve_io[i << 1];
  		int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1;
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
178
  		if (ranged_conflict(port, end, &rport, &rend))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
  			return 0;
  	}
  
  	/* check for internal conflicts */
95ab3669f   Bjorn Helgaas   PNP: remove PNP_M...
183
184
  	for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
  		if (tres != res && tres->flags & IORESOURCE_IO) {
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
185
186
  			tport = &tres->start;
  			tend = &tres->end;
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
187
  			if (ranged_conflict(port, end, tport, tend))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
194
195
  				return 0;
  		}
  	}
  
  	/* check for conflicts with other pnp devices */
  	pnp_for_each_dev(tdev) {
  		if (tdev == dev)
  			continue;
95ab3669f   Bjorn Helgaas   PNP: remove PNP_M...
196
197
198
199
  		for (i = 0;
  		     (tres = pnp_get_resource(tdev, IORESOURCE_IO, i));
  		     i++) {
  			if (tres->flags & IORESOURCE_IO) {
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
200
  				if (cannot_compare(tres->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  					continue;
11439a6fd   Bjorn Helgaas   PNP: don't check ...
202
203
  				if (tres->flags & IORESOURCE_WINDOW)
  					continue;
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
204
205
  				tport = &tres->start;
  				tend = &tres->end;
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
206
  				if (ranged_conflict(port, end, tport, tend))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
212
213
  					return 0;
  			}
  		}
  	}
  
  	return 1;
  }
f5d94ff01   Bjorn Helgaas   PNP: pass resourc...
214
  int pnp_check_mem(struct pnp_dev *dev, struct resource *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  {
ecfa935a2   Bjorn Helgaas   PNP: use conventi...
216
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	struct pnp_dev *tdev;
f5d94ff01   Bjorn Helgaas   PNP: pass resourc...
218
  	struct resource *tres;
b60ba8343   Greg Kroah-Hartman   [PATCH] 64bit res...
219
  	resource_size_t *addr, *end, *taddr, *tend;
07d4e9af1   Bjorn Helgaas   PNP: fix up after...
220

30c016a0c   Bjorn Helgaas   PNP: reduce redun...
221
222
  	addr = &res->start;
  	end = &res->end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
  
  	/* if the resource doesn't exist, don't complain about it */
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
225
  	if (cannot_compare(res->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
  		return 1;
  
  	/* check if the resource is already in use, skip if the
  	 * device is active because it itself may be in use */
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
230
  	if (!dev->active) {
eeeb98bf0   Jakub Sitnicki   PNP: Switch from ...
231
  		if (!request_mem_region(*addr, length(addr, end), "pnp"))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  			return 0;
eeeb98bf0   Jakub Sitnicki   PNP: Switch from ...
233
  		release_mem_region(*addr, length(addr, end));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
  	}
  
  	/* check if the resource is reserved */
ecfa935a2   Bjorn Helgaas   PNP: use conventi...
237
238
239
  	for (i = 0; i < 8; i++) {
  		int raddr = pnp_reserve_mem[i << 1];
  		int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1;
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
240
  		if (ranged_conflict(addr, end, &raddr, &rend))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
  			return 0;
  	}
  
  	/* check for internal conflicts */
95ab3669f   Bjorn Helgaas   PNP: remove PNP_M...
245
246
  	for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
  		if (tres != res && tres->flags & IORESOURCE_MEM) {
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
247
248
  			taddr = &tres->start;
  			tend = &tres->end;
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
249
  			if (ranged_conflict(addr, end, taddr, tend))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
256
257
  				return 0;
  		}
  	}
  
  	/* check for conflicts with other pnp devices */
  	pnp_for_each_dev(tdev) {
  		if (tdev == dev)
  			continue;
95ab3669f   Bjorn Helgaas   PNP: remove PNP_M...
258
259
260
261
  		for (i = 0;
  		     (tres = pnp_get_resource(tdev, IORESOURCE_MEM, i));
  		     i++) {
  			if (tres->flags & IORESOURCE_MEM) {
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
262
  				if (cannot_compare(tres->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  					continue;
11439a6fd   Bjorn Helgaas   PNP: don't check ...
264
265
  				if (tres->flags & IORESOURCE_WINDOW)
  					continue;
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
266
267
  				taddr = &tres->start;
  				tend = &tres->end;
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
268
  				if (ranged_conflict(addr, end, taddr, tend))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
272
273
274
275
  					return 0;
  			}
  		}
  	}
  
  	return 1;
  }
7d12e780e   David Howells   IRQ: Maintain reg...
276
  static irqreturn_t pnp_test_handler(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
  {
  	return IRQ_HANDLED;
  }
84684c746   Bjorn Helgaas   PNP: avoid legacy...
280
281
282
283
284
285
286
287
  #ifdef CONFIG_PCI
  static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci,
  			    unsigned int irq)
  {
  	u32 class;
  	u8 progif;
  
  	if (pci->irq == irq) {
2f53432c2   Bjorn Helgaas   PNP: convert to u...
288
289
  		pnp_dbg(&pnp->dev, "  device %s using irq %d
  ",
84684c746   Bjorn Helgaas   PNP: avoid legacy...
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
  			pci_name(pci), irq);
  		return 1;
  	}
  
  	/*
  	 * See pci_setup_device() and ata_pci_sff_activate_host() for
  	 * similar IDE legacy detection.
  	 */
  	pci_read_config_dword(pci, PCI_CLASS_REVISION, &class);
  	class >>= 8;		/* discard revision ID */
  	progif = class & 0xff;
  	class >>= 8;
  
  	if (class == PCI_CLASS_STORAGE_IDE) {
  		/*
  		 * Unless both channels are native-PCI mode only,
  		 * treat the compatibility IRQs as busy.
  		 */
  		if ((progif & 0x5) != 0x5)
  			if (pci_get_legacy_ide_irq(pci, 0) == irq ||
  			    pci_get_legacy_ide_irq(pci, 1) == irq) {
2f53432c2   Bjorn Helgaas   PNP: convert to u...
311
  				pnp_dbg(&pnp->dev, "  legacy IDE device %s "
84684c746   Bjorn Helgaas   PNP: avoid legacy...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  					"using irq %d
  ", pci_name(pci), irq);
  				return 1;
  			}
  	}
  
  	return 0;
  }
  #endif
  
  static int pci_uses_irq(struct pnp_dev *pnp, unsigned int irq)
  {
  #ifdef CONFIG_PCI
  	struct pci_dev *pci = NULL;
  
  	for_each_pci_dev(pci) {
  		if (pci_dev_uses_irq(pnp, pci, irq)) {
  			pci_dev_put(pci);
  			return 1;
  		}
  	}
  #endif
  	return 0;
  }
f5d94ff01   Bjorn Helgaas   PNP: pass resourc...
336
  int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  {
ecfa935a2   Bjorn Helgaas   PNP: use conventi...
338
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  	struct pnp_dev *tdev;
f5d94ff01   Bjorn Helgaas   PNP: pass resourc...
340
  	struct resource *tres;
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
341
  	resource_size_t *irq;
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
342
  	irq = &res->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
  
  	/* if the resource doesn't exist, don't complain about it */
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
345
  	if (cannot_compare(res->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
348
  		return 1;
  
  	/* check if the resource is valid */
ff73b80d6   Fabian Frederick   PNP / resources: ...
349
  	if (*irq > 15)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
  		return 0;
  
  	/* check if the resource is reserved */
ecfa935a2   Bjorn Helgaas   PNP: use conventi...
353
354
  	for (i = 0; i < 16; i++) {
  		if (pnp_reserve_irq[i] == *irq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
  			return 0;
  	}
  
  	/* check for internal conflicts */
95ab3669f   Bjorn Helgaas   PNP: remove PNP_M...
359
360
  	for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
  		if (tres != res && tres->flags & IORESOURCE_IRQ) {
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
361
  			if (tres->start == *irq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
  				return 0;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  	/* check if the resource is being used by a pci device */
84684c746   Bjorn Helgaas   PNP: avoid legacy...
366
367
  	if (pci_uses_irq(dev, *irq))
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
  
  	/* check if the resource is already in use, skip if the
  	 * device is active because it itself may be in use */
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
371
  	if (!dev->active) {
0cadaf45b   Andrew Morton   [PATCH] pnp: supp...
372
  		if (request_irq(*irq, pnp_test_handler,
e1563769f   Michael Opdenacker   PNP: remove depre...
373
  				IRQF_PROBE_SHARED, "pnp", NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
379
380
381
  			return 0;
  		free_irq(*irq, NULL);
  	}
  
  	/* check for conflicts with other pnp devices */
  	pnp_for_each_dev(tdev) {
  		if (tdev == dev)
  			continue;
95ab3669f   Bjorn Helgaas   PNP: remove PNP_M...
382
383
384
385
  		for (i = 0;
  		     (tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i));
  		     i++) {
  			if (tres->flags & IORESOURCE_IRQ) {
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
386
  				if (cannot_compare(tres->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  					continue;
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
388
  				if (tres->start == *irq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
393
394
395
  					return 0;
  			}
  		}
  	}
  
  	return 1;
  }
586f83e2b   David Rientjes   pnp: only assign ...
396
  #ifdef CONFIG_ISA_DMA_API
f5d94ff01   Bjorn Helgaas   PNP: pass resourc...
397
  int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  {
ecfa935a2   Bjorn Helgaas   PNP: use conventi...
399
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  	struct pnp_dev *tdev;
f5d94ff01   Bjorn Helgaas   PNP: pass resourc...
401
  	struct resource *tres;
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
402
  	resource_size_t *dma;
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
403
  	dma = &res->start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  
  	/* if the resource doesn't exist, don't complain about it */
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
406
  	if (cannot_compare(res->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
  		return 1;
  
  	/* check if the resource is valid */
ff73b80d6   Fabian Frederick   PNP / resources: ...
410
  	if (*dma == 4 || *dma > 7)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
  		return 0;
  
  	/* check if the resource is reserved */
ecfa935a2   Bjorn Helgaas   PNP: use conventi...
414
415
  	for (i = 0; i < 8; i++) {
  		if (pnp_reserve_dma[i] == *dma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
419
  			return 0;
  	}
  
  	/* check for internal conflicts */
95ab3669f   Bjorn Helgaas   PNP: remove PNP_M...
420
421
  	for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
  		if (tres != res && tres->flags & IORESOURCE_DMA) {
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
422
  			if (tres->start == *dma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
427
428
  				return 0;
  		}
  	}
  
  	/* check if the resource is already in use, skip if the
  	 * device is active because it itself may be in use */
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
429
  	if (!dev->active) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
434
435
436
437
438
  		if (request_dma(*dma, "pnp"))
  			return 0;
  		free_dma(*dma);
  	}
  
  	/* check for conflicts with other pnp devices */
  	pnp_for_each_dev(tdev) {
  		if (tdev == dev)
  			continue;
95ab3669f   Bjorn Helgaas   PNP: remove PNP_M...
439
440
441
442
  		for (i = 0;
  		     (tres = pnp_get_resource(tdev, IORESOURCE_DMA, i));
  		     i++) {
  			if (tres->flags & IORESOURCE_DMA) {
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
443
  				if (cannot_compare(tres->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
  					continue;
30c016a0c   Bjorn Helgaas   PNP: reduce redun...
445
  				if (tres->start == *dma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
448
449
450
451
  					return 0;
  			}
  		}
  	}
  
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  }
586f83e2b   David Rientjes   pnp: only assign ...
453
  #endif /* CONFIG_ISA_DMA_API */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454

b563cf59c   Rene Herman   pnp: make the res...
455
  unsigned long pnp_resource_type(struct resource *res)
940e98dbc   Bjorn Helgaas   PNP: add pnp_reso...
456
457
  {
  	return res->flags & (IORESOURCE_IO  | IORESOURCE_MEM |
7e0e9c042   Bjorn Helgaas   PNPACPI: add bus ...
458
459
  			     IORESOURCE_IRQ | IORESOURCE_DMA |
  			     IORESOURCE_BUS);
940e98dbc   Bjorn Helgaas   PNP: add pnp_reso...
460
  }
0a977f154   Bjorn Helgaas   PNP: add pnp_get_...
461
  struct resource *pnp_get_resource(struct pnp_dev *dev,
b563cf59c   Rene Herman   pnp: make the res...
462
  				  unsigned long type, unsigned int num)
0a977f154   Bjorn Helgaas   PNP: add pnp_get_...
463
464
  {
  	struct pnp_resource *pnp_res;
aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
465
  	struct resource *res;
0a977f154   Bjorn Helgaas   PNP: add pnp_get_...
466

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
467
468
469
470
471
  	list_for_each_entry(pnp_res, &dev->resources, list) {
  		res = &pnp_res->res;
  		if (pnp_resource_type(res) == type && num-- == 0)
  			return res;
  	}
0a977f154   Bjorn Helgaas   PNP: add pnp_get_...
472
473
  	return NULL;
  }
b90eca0a6   Bjorn Helgaas   PNP: add pnp_get_...
474
  EXPORT_SYMBOL(pnp_get_resource);
aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
475
  static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
a50b6d7b8   Bjorn Helgaas   PNP: add pnp_new_...
476
477
  {
  	struct pnp_resource *pnp_res;
a50b6d7b8   Bjorn Helgaas   PNP: add pnp_new_...
478

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
479
480
481
482
483
484
  	pnp_res = kzalloc(sizeof(struct pnp_resource), GFP_KERNEL);
  	if (!pnp_res)
  		return NULL;
  
  	list_add_tail(&pnp_res->list, &dev->resources);
  	return pnp_res;
a50b6d7b8   Bjorn Helgaas   PNP: add pnp_new_...
485
  }
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
486
487
488
489
490
491
492
493
494
495
496
497
498
  struct pnp_resource *pnp_add_resource(struct pnp_dev *dev,
  				      struct resource *res)
  {
  	struct pnp_resource *pnp_res;
  
  	pnp_res = pnp_new_resource(dev);
  	if (!pnp_res) {
  		dev_err(&dev->dev, "can't add resource %pR
  ", res);
  		return NULL;
  	}
  
  	pnp_res->res = *res;
3c0fc0710   Liu ShuoX   PNP / ACPI: avoid...
499
  	pnp_res->res.name = dev->name;
046d9ce68   Rafael J. Wysocki   ACPI: Move device...
500
501
502
503
  	dev_dbg(&dev->dev, "%pR
  ", res);
  	return pnp_res;
  }
dbddd0383   Bjorn Helgaas   PNP: make generic...
504
505
506
507
508
  struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
  					  int flags)
  {
  	struct pnp_resource *pnp_res;
  	struct resource *res;
dbddd0383   Bjorn Helgaas   PNP: make generic...
509

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
510
  	pnp_res = pnp_new_resource(dev);
dbddd0383   Bjorn Helgaas   PNP: make generic...
511
  	if (!pnp_res) {
25d39c39d   Bjorn Helgaas   PNP: remove ratel...
512
513
  		dev_err(&dev->dev, "can't add resource for IRQ %d
  ", irq);
dbddd0383   Bjorn Helgaas   PNP: make generic...
514
515
516
517
518
519
520
  		return NULL;
  	}
  
  	res = &pnp_res->res;
  	res->flags = IORESOURCE_IRQ | flags;
  	res->start = irq;
  	res->end = irq;
c1f3f2819   Bjorn Helgaas   PNP: log PNP reso...
521
522
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
dbddd0383   Bjorn Helgaas   PNP: make generic...
523
524
  	return pnp_res;
  }
dc16f5f2e   Bjorn Helgaas   PNP: make generic...
525
526
527
528
529
  struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
  					  int flags)
  {
  	struct pnp_resource *pnp_res;
  	struct resource *res;
dc16f5f2e   Bjorn Helgaas   PNP: make generic...
530

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
531
  	pnp_res = pnp_new_resource(dev);
dc16f5f2e   Bjorn Helgaas   PNP: make generic...
532
  	if (!pnp_res) {
25d39c39d   Bjorn Helgaas   PNP: remove ratel...
533
534
  		dev_err(&dev->dev, "can't add resource for DMA %d
  ", dma);
dc16f5f2e   Bjorn Helgaas   PNP: make generic...
535
536
537
538
539
540
541
  		return NULL;
  	}
  
  	res = &pnp_res->res;
  	res->flags = IORESOURCE_DMA | flags;
  	res->start = dma;
  	res->end = dma;
c1f3f2819   Bjorn Helgaas   PNP: log PNP reso...
542
543
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
dc16f5f2e   Bjorn Helgaas   PNP: make generic...
544
545
  	return pnp_res;
  }
cc8c2e308   Bjorn Helgaas   PNP: make generic...
546
547
548
549
550
551
  struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
  					 resource_size_t start,
  					 resource_size_t end, int flags)
  {
  	struct pnp_resource *pnp_res;
  	struct resource *res;
cc8c2e308   Bjorn Helgaas   PNP: make generic...
552

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
553
  	pnp_res = pnp_new_resource(dev);
cc8c2e308   Bjorn Helgaas   PNP: make generic...
554
  	if (!pnp_res) {
25d39c39d   Bjorn Helgaas   PNP: remove ratel...
555
556
557
558
  		dev_err(&dev->dev, "can't add resource for IO %#llx-%#llx
  ",
  			(unsigned long long) start,
  			(unsigned long long) end);
cc8c2e308   Bjorn Helgaas   PNP: make generic...
559
560
561
562
563
564
565
  		return NULL;
  	}
  
  	res = &pnp_res->res;
  	res->flags = IORESOURCE_IO | flags;
  	res->start = start;
  	res->end = end;
c1f3f2819   Bjorn Helgaas   PNP: log PNP reso...
566
567
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
cc8c2e308   Bjorn Helgaas   PNP: make generic...
568
569
  	return pnp_res;
  }
d6180f366   Bjorn Helgaas   PNP: make generic...
570
571
572
573
574
575
  struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
  					  resource_size_t start,
  					  resource_size_t end, int flags)
  {
  	struct pnp_resource *pnp_res;
  	struct resource *res;
d6180f366   Bjorn Helgaas   PNP: make generic...
576

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
577
  	pnp_res = pnp_new_resource(dev);
d6180f366   Bjorn Helgaas   PNP: make generic...
578
  	if (!pnp_res) {
25d39c39d   Bjorn Helgaas   PNP: remove ratel...
579
580
581
582
  		dev_err(&dev->dev, "can't add resource for MEM %#llx-%#llx
  ",
  			(unsigned long long) start,
  			(unsigned long long) end);
d6180f366   Bjorn Helgaas   PNP: make generic...
583
584
585
586
587
588
589
  		return NULL;
  	}
  
  	res = &pnp_res->res;
  	res->flags = IORESOURCE_MEM | flags;
  	res->start = start;
  	res->end = end;
c1f3f2819   Bjorn Helgaas   PNP: log PNP reso...
590
591
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
d6180f366   Bjorn Helgaas   PNP: make generic...
592
593
  	return pnp_res;
  }
7e0e9c042   Bjorn Helgaas   PNPACPI: add bus ...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
  struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev,
  					  resource_size_t start,
  					  resource_size_t end)
  {
  	struct pnp_resource *pnp_res;
  	struct resource *res;
  
  	pnp_res = pnp_new_resource(dev);
  	if (!pnp_res) {
  		dev_err(&dev->dev, "can't add resource for BUS %#llx-%#llx
  ",
  			(unsigned long long) start,
  			(unsigned long long) end);
  		return NULL;
  	}
  
  	res = &pnp_res->res;
  	res->flags = IORESOURCE_BUS;
  	res->start = start;
  	res->end = end;
c1f3f2819   Bjorn Helgaas   PNP: log PNP reso...
614
615
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
7e0e9c042   Bjorn Helgaas   PNPACPI: add bus ...
616
617
  	return pnp_res;
  }
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
618
619
620
621
622
623
  /*
   * Determine whether the specified resource is a possible configuration
   * for this device.
   */
  int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
  			resource_size_t size)
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
624
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
625
  	struct pnp_option *option;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
626
627
628
629
  	struct pnp_port *port;
  	struct pnp_mem *mem;
  	struct pnp_irq *irq;
  	struct pnp_dma *dma;
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
630
631
632
  	list_for_each_entry(option, &dev->options, list) {
  		if (option->type != type)
  			continue;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
633

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
634
  		switch (option->type) {
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
635
  		case IORESOURCE_IO:
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
636
637
638
  			port = &option->u.port;
  			if (port->min == start && port->size == size)
  				return 1;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
639
640
  			break;
  		case IORESOURCE_MEM:
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
641
642
643
  			mem = &option->u.mem;
  			if (mem->min == start && mem->size == size)
  				return 1;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
644
645
  			break;
  		case IORESOURCE_IRQ:
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
646
647
648
649
  			irq = &option->u.irq;
  			if (start < PNP_IRQ_NR &&
  			    test_bit(start, irq->map.bits))
  				return 1;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
650
651
  			break;
  		case IORESOURCE_DMA:
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
652
653
654
  			dma = &option->u.dma;
  			if (dma->map & (1 << start))
  				return 1;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
655
656
657
658
659
660
  			break;
  		}
  	}
  
  	return 0;
  }
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
661
  EXPORT_SYMBOL(pnp_possible_config);
1b8e69662   Bjorn Helgaas   pnp: add PNP reso...
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
  int pnp_range_reserved(resource_size_t start, resource_size_t end)
  {
  	struct pnp_dev *dev;
  	struct pnp_resource *pnp_res;
  	resource_size_t *dev_start, *dev_end;
  
  	pnp_for_each_dev(dev) {
  		list_for_each_entry(pnp_res, &dev->resources, list) {
  			dev_start = &pnp_res->res.start;
  			dev_end   = &pnp_res->res.end;
  			if (ranged_conflict(&start, &end, dev_start, dev_end))
  				return 1;
  		}
  	}
  	return 0;
  }
  EXPORT_SYMBOL(pnp_range_reserved);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  /* format is: pnp_reserve_irq=irq1[,irq2] .... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
682
683
684
  static int __init pnp_setup_reserve_irq(char *str)
  {
  	int i;
  
  	for (i = 0; i < 16; i++)
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
685
  		if (get_option(&str, &pnp_reserve_irq[i]) != 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
688
689
690
691
692
  			break;
  	return 1;
  }
  
  __setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
  
  /* format is: pnp_reserve_dma=dma1[,dma2] .... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
696
697
  static int __init pnp_setup_reserve_dma(char *str)
  {
  	int i;
  
  	for (i = 0; i < 8; i++)
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
698
  		if (get_option(&str, &pnp_reserve_dma[i]) != 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
702
703
704
705
  			break;
  	return 1;
  }
  
  __setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
  
  /* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
708
709
710
  static int __init pnp_setup_reserve_io(char *str)
  {
  	int i;
  
  	for (i = 0; i < 16; i++)
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
711
  		if (get_option(&str, &pnp_reserve_io[i]) != 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
714
715
716
717
718
  			break;
  	return 1;
  }
  
  __setup("pnp_reserve_io=", pnp_setup_reserve_io);
  
  /* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
722
723
  static int __init pnp_setup_reserve_mem(char *str)
  {
  	int i;
  
  	for (i = 0; i < 16; i++)
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
724
  		if (get_option(&str, &pnp_reserve_mem[i]) != 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
727
728
729
  			break;
  	return 1;
  }
  
  __setup("pnp_reserve_mem=", pnp_setup_reserve_mem);