Blame view

drivers/pnp/resource.c 16.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * resource.c - Contains functions for registering and analyzing resource information
   *
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
4
   * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
6
7
   * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
   *	Bjorn Helgaas <bjorn.helgaas@hp.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
10
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
17
18
19
20
21
22
  #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...
23
24
25
26
  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
27
28
29
30
  
  /*
   * option registration
   */
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
31
32
  struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type,
  				    unsigned int option_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
34
  	struct pnp_option *option;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

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

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

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

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

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

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

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
84
  	dbg_pnp_show_option(dev, option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
  	return 0;
  }
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
87
  int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
c227536b4   Bjorn Helgaas   PNP: centralize r...
88
89
90
  			       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
91
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
92
93
  	struct pnp_option *option;
  	struct pnp_port *port;
c227536b4   Bjorn Helgaas   PNP: centralize r...
94

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

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
105
  	dbg_pnp_show_option(dev, option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
  	return 0;
  }
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
108
  int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
c227536b4   Bjorn Helgaas   PNP: centralize r...
109
110
111
  			      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
112
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
113
114
  	struct pnp_option *option;
  	struct pnp_mem *mem;
c227536b4   Bjorn Helgaas   PNP: centralize r...
115

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

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

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
133
134
  	list_for_each_entry_safe(option, tmp, &dev->options, list) {
  		list_del(&option->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  		kfree(option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
141
142
143
144
145
146
147
148
  /*
   * 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_...
149
  ((flags) & IORESOURCE_DISABLED)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150

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

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

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

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

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
464
465
466
467
468
  	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_...
469
470
  	return NULL;
  }
b90eca0a6   Bjorn Helgaas   PNP: add pnp_get_...
471
  EXPORT_SYMBOL(pnp_get_resource);
aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
472
  static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
a50b6d7b8   Bjorn Helgaas   PNP: add pnp_new_...
473
474
  {
  	struct pnp_resource *pnp_res;
a50b6d7b8   Bjorn Helgaas   PNP: add pnp_new_...
475

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
476
477
478
479
480
481
  	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_...
482
  }
dbddd0383   Bjorn Helgaas   PNP: make generic...
483
484
485
486
487
  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...
488

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
489
  	pnp_res = pnp_new_resource(dev);
dbddd0383   Bjorn Helgaas   PNP: make generic...
490
  	if (!pnp_res) {
25d39c39d   Bjorn Helgaas   PNP: remove ratel...
491
492
  		dev_err(&dev->dev, "can't add resource for IRQ %d
  ", irq);
dbddd0383   Bjorn Helgaas   PNP: make generic...
493
494
495
496
497
498
499
  		return NULL;
  	}
  
  	res = &pnp_res->res;
  	res->flags = IORESOURCE_IRQ | flags;
  	res->start = irq;
  	res->end = irq;
c1f3f2819   Bjorn Helgaas   PNP: log PNP reso...
500
501
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
dbddd0383   Bjorn Helgaas   PNP: make generic...
502
503
  	return pnp_res;
  }
dc16f5f2e   Bjorn Helgaas   PNP: make generic...
504
505
506
507
508
  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...
509

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
510
  	pnp_res = pnp_new_resource(dev);
dc16f5f2e   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 DMA %d
  ", dma);
dc16f5f2e   Bjorn Helgaas   PNP: make generic...
514
515
516
517
518
519
520
  		return NULL;
  	}
  
  	res = &pnp_res->res;
  	res->flags = IORESOURCE_DMA | flags;
  	res->start = dma;
  	res->end = dma;
c1f3f2819   Bjorn Helgaas   PNP: log PNP reso...
521
522
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
dc16f5f2e   Bjorn Helgaas   PNP: make generic...
523
524
  	return pnp_res;
  }
cc8c2e308   Bjorn Helgaas   PNP: make generic...
525
526
527
528
529
530
  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...
531

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
532
  	pnp_res = pnp_new_resource(dev);
cc8c2e308   Bjorn Helgaas   PNP: make generic...
533
  	if (!pnp_res) {
25d39c39d   Bjorn Helgaas   PNP: remove ratel...
534
535
536
537
  		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...
538
539
540
541
542
543
544
  		return NULL;
  	}
  
  	res = &pnp_res->res;
  	res->flags = IORESOURCE_IO | flags;
  	res->start = start;
  	res->end = end;
c1f3f2819   Bjorn Helgaas   PNP: log PNP reso...
545
546
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
cc8c2e308   Bjorn Helgaas   PNP: make generic...
547
548
  	return pnp_res;
  }
d6180f366   Bjorn Helgaas   PNP: make generic...
549
550
551
552
553
554
  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...
555

aee3ad815   Bjorn Helgaas   PNP: replace pnp_...
556
  	pnp_res = pnp_new_resource(dev);
d6180f366   Bjorn Helgaas   PNP: make generic...
557
  	if (!pnp_res) {
25d39c39d   Bjorn Helgaas   PNP: remove ratel...
558
559
560
561
  		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...
562
563
564
565
566
567
568
  		return NULL;
  	}
  
  	res = &pnp_res->res;
  	res->flags = IORESOURCE_MEM | flags;
  	res->start = start;
  	res->end = end;
c1f3f2819   Bjorn Helgaas   PNP: log PNP reso...
569
570
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
d6180f366   Bjorn Helgaas   PNP: make generic...
571
572
  	return pnp_res;
  }
7e0e9c042   Bjorn Helgaas   PNPACPI: add bus ...
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  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...
593
594
  	dev_printk(KERN_DEBUG, &dev->dev, "%pR
  ", res);
7e0e9c042   Bjorn Helgaas   PNPACPI: add bus ...
595
596
  	return pnp_res;
  }
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
597
598
599
600
601
602
  /*
   * 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...
603
  {
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
604
  	struct pnp_option *option;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
605
606
607
608
  	struct pnp_port *port;
  	struct pnp_mem *mem;
  	struct pnp_irq *irq;
  	struct pnp_dma *dma;
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
609
610
611
  	list_for_each_entry(option, &dev->options, list) {
  		if (option->type != type)
  			continue;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
612

1f32ca31e   Bjorn Helgaas   PNP: convert reso...
613
  		switch (option->type) {
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
614
  		case IORESOURCE_IO:
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
615
616
617
  			port = &option->u.port;
  			if (port->min == start && port->size == size)
  				return 1;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
618
619
  			break;
  		case IORESOURCE_MEM:
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
620
621
622
  			mem = &option->u.mem;
  			if (mem->min == start && mem->size == size)
  				return 1;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
623
624
  			break;
  		case IORESOURCE_IRQ:
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
625
626
627
628
  			irq = &option->u.irq;
  			if (start < PNP_IRQ_NR &&
  			    test_bit(start, irq->map.bits))
  				return 1;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
629
630
  			break;
  		case IORESOURCE_DMA:
1f32ca31e   Bjorn Helgaas   PNP: convert reso...
631
632
633
  			dma = &option->u.dma;
  			if (dma->map & (1 << start))
  				return 1;
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
634
635
636
637
638
639
  			break;
  		}
  	}
  
  	return 0;
  }
57fd51a8b   Bjorn Helgaas   PNP: add pnp_poss...
640
  EXPORT_SYMBOL(pnp_possible_config);
1b8e69662   Bjorn Helgaas   pnp: add PNP reso...
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
  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
658
  /* format is: pnp_reserve_irq=irq1[,irq2] .... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
663
  static int __init pnp_setup_reserve_irq(char *str)
  {
  	int i;
  
  	for (i = 0; i < 16; i++)
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
664
  		if (get_option(&str, &pnp_reserve_irq[i]) != 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
667
668
669
670
671
  			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
672
673
674
675
676
  static int __init pnp_setup_reserve_dma(char *str)
  {
  	int i;
  
  	for (i = 0; i < 8; i++)
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
677
  		if (get_option(&str, &pnp_reserve_dma[i]) != 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
683
684
  			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
685
686
687
688
689
  static int __init pnp_setup_reserve_io(char *str)
  {
  	int i;
  
  	for (i = 0; i < 16; i++)
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
690
  		if (get_option(&str, &pnp_reserve_io[i]) != 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
692
693
694
695
696
697
  			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
698
699
700
701
702
  static int __init pnp_setup_reserve_mem(char *str)
  {
  	int i;
  
  	for (i = 0; i < 16; i++)
9dd78466c   Bjorn Helgaas   PNP: Lindent all ...
703
  		if (get_option(&str, &pnp_reserve_mem[i]) != 2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
  			break;
  	return 1;
  }
  
  __setup("pnp_reserve_mem=", pnp_setup_reserve_mem);