]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * resource.c - Contains functions for registering and analyzing resource information | |
3 | * | |
c1017a4c | 4 | * based on isapnp.c resource management (c) Jaroslav Kysela <[email protected]> |
1da177e4 | 5 | * Copyright 2003 Adam Belay <[email protected]> |
1f32ca31 BH |
6 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. |
7 | * Bjorn Helgaas <[email protected]> | |
1da177e4 LT |
8 | */ |
9 | ||
1da177e4 | 10 | #include <linux/module.h> |
5a0e3ad6 | 11 | #include <linux/slab.h> |
1da177e4 LT |
12 | #include <linux/errno.h> |
13 | #include <linux/interrupt.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <asm/io.h> | |
16 | #include <asm/dma.h> | |
17 | #include <asm/irq.h> | |
18 | #include <linux/pci.h> | |
19 | #include <linux/ioport.h> | |
20 | #include <linux/init.h> | |
21 | ||
22 | #include <linux/pnp.h> | |
23 | #include "base.h" | |
24 | ||
07d4e9af BH |
25 | static int pnp_reserve_irq[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some IRQ */ |
26 | static int pnp_reserve_dma[8] = {[0 ... 7] = -1 }; /* reserve (don't use) some DMA */ | |
27 | static int pnp_reserve_io[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some I/O region */ | |
28 | static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some memory region */ | |
1da177e4 LT |
29 | |
30 | /* | |
31 | * option registration | |
32 | */ | |
33 | ||
62c6dae0 | 34 | static struct pnp_option *pnp_build_option(struct pnp_dev *dev, unsigned long type, |
1f32ca31 | 35 | unsigned int option_flags) |
1da177e4 | 36 | { |
1f32ca31 | 37 | struct pnp_option *option; |
1da177e4 | 38 | |
1f32ca31 | 39 | option = kzalloc(sizeof(struct pnp_option), GFP_KERNEL); |
1da177e4 LT |
40 | if (!option) |
41 | return NULL; | |
42 | ||
1f32ca31 BH |
43 | option->flags = option_flags; |
44 | option->type = type; | |
07d4e9af | 45 | |
1f32ca31 | 46 | list_add_tail(&option->list, &dev->options); |
1da177e4 LT |
47 | return option; |
48 | } | |
49 | ||
1f32ca31 | 50 | int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags, |
c227536b | 51 | pnp_irq_mask_t *map, unsigned char flags) |
1da177e4 | 52 | { |
1f32ca31 BH |
53 | struct pnp_option *option; |
54 | struct pnp_irq *irq; | |
07d4e9af | 55 | |
1f32ca31 BH |
56 | option = pnp_build_option(dev, IORESOURCE_IRQ, option_flags); |
57 | if (!option) | |
c227536b BH |
58 | return -ENOMEM; |
59 | ||
1f32ca31 | 60 | irq = &option->u.irq; |
2d29a7a7 BH |
61 | irq->map = *map; |
62 | irq->flags = flags; | |
c227536b | 63 | |
1da177e4 LT |
64 | #ifdef CONFIG_PCI |
65 | { | |
66 | int i; | |
67 | ||
68 | for (i = 0; i < 16; i++) | |
2d29a7a7 | 69 | if (test_bit(i, irq->map.bits)) |
c9c3e457 | 70 | pcibios_penalize_isa_irq(i, 0); |
1da177e4 LT |
71 | } |
72 | #endif | |
c1caf06c | 73 | |
1f32ca31 | 74 | dbg_pnp_show_option(dev, option); |
1da177e4 LT |
75 | return 0; |
76 | } | |
77 | ||
1f32ca31 | 78 | int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags, |
c227536b | 79 | unsigned char map, unsigned char flags) |
1da177e4 | 80 | { |
1f32ca31 BH |
81 | struct pnp_option *option; |
82 | struct pnp_dma *dma; | |
c227536b | 83 | |
1f32ca31 BH |
84 | option = pnp_build_option(dev, IORESOURCE_DMA, option_flags); |
85 | if (!option) | |
c227536b BH |
86 | return -ENOMEM; |
87 | ||
1f32ca31 | 88 | dma = &option->u.dma; |
2d29a7a7 BH |
89 | dma->map = map; |
90 | dma->flags = flags; | |
07d4e9af | 91 | |
1f32ca31 | 92 | dbg_pnp_show_option(dev, option); |
1da177e4 LT |
93 | return 0; |
94 | } | |
95 | ||
1f32ca31 | 96 | int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags, |
c227536b BH |
97 | resource_size_t min, resource_size_t max, |
98 | resource_size_t align, resource_size_t size, | |
99 | unsigned char flags) | |
1da177e4 | 100 | { |
1f32ca31 BH |
101 | struct pnp_option *option; |
102 | struct pnp_port *port; | |
c227536b | 103 | |
1f32ca31 BH |
104 | option = pnp_build_option(dev, IORESOURCE_IO, option_flags); |
105 | if (!option) | |
c227536b BH |
106 | return -ENOMEM; |
107 | ||
1f32ca31 | 108 | port = &option->u.port; |
2d29a7a7 BH |
109 | port->min = min; |
110 | port->max = max; | |
111 | port->align = align; | |
112 | port->size = size; | |
113 | port->flags = flags; | |
07d4e9af | 114 | |
1f32ca31 | 115 | dbg_pnp_show_option(dev, option); |
1da177e4 LT |
116 | return 0; |
117 | } | |
118 | ||
1f32ca31 | 119 | int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags, |
c227536b BH |
120 | resource_size_t min, resource_size_t max, |
121 | resource_size_t align, resource_size_t size, | |
122 | unsigned char flags) | |
1da177e4 | 123 | { |
1f32ca31 BH |
124 | struct pnp_option *option; |
125 | struct pnp_mem *mem; | |
c227536b | 126 | |
1f32ca31 BH |
127 | option = pnp_build_option(dev, IORESOURCE_MEM, option_flags); |
128 | if (!option) | |
c227536b BH |
129 | return -ENOMEM; |
130 | ||
1f32ca31 | 131 | mem = &option->u.mem; |
2d29a7a7 BH |
132 | mem->min = min; |
133 | mem->max = max; | |
134 | mem->align = align; | |
135 | mem->size = size; | |
136 | mem->flags = flags; | |
07d4e9af | 137 | |
1f32ca31 | 138 | dbg_pnp_show_option(dev, option); |
1da177e4 LT |
139 | return 0; |
140 | } | |
141 | ||
1f32ca31 | 142 | void pnp_free_options(struct pnp_dev *dev) |
1da177e4 | 143 | { |
1f32ca31 | 144 | struct pnp_option *option, *tmp; |
1da177e4 | 145 | |
1f32ca31 BH |
146 | list_for_each_entry_safe(option, tmp, &dev->options, list) { |
147 | list_del(&option->list); | |
1da177e4 | 148 | kfree(option); |
1da177e4 LT |
149 | } |
150 | } | |
151 | ||
1da177e4 LT |
152 | /* |
153 | * resource validity checking | |
154 | */ | |
155 | ||
156 | #define length(start, end) (*(end) - *(start) + 1) | |
157 | ||
158 | /* Two ranges conflict if one doesn't end before the other starts */ | |
159 | #define ranged_conflict(starta, enda, startb, endb) \ | |
160 | !((*(enda) < *(startb)) || (*(endb) < *(starta))) | |
161 | ||
162 | #define cannot_compare(flags) \ | |
aee3ad81 | 163 | ((flags) & IORESOURCE_DISABLED) |
1da177e4 | 164 | |
f5d94ff0 | 165 | int pnp_check_port(struct pnp_dev *dev, struct resource *res) |
1da177e4 | 166 | { |
ecfa935a | 167 | int i; |
1da177e4 | 168 | struct pnp_dev *tdev; |
f5d94ff0 | 169 | struct resource *tres; |
b60ba834 | 170 | resource_size_t *port, *end, *tport, *tend; |
07d4e9af | 171 | |
30c016a0 BH |
172 | port = &res->start; |
173 | end = &res->end; | |
1da177e4 LT |
174 | |
175 | /* if the resource doesn't exist, don't complain about it */ | |
30c016a0 | 176 | if (cannot_compare(res->flags)) |
1da177e4 LT |
177 | return 1; |
178 | ||
179 | /* check if the resource is already in use, skip if the | |
180 | * device is active because it itself may be in use */ | |
9dd78466 BH |
181 | if (!dev->active) { |
182 | if (__check_region(&ioport_resource, *port, length(port, end))) | |
1da177e4 LT |
183 | return 0; |
184 | } | |
185 | ||
186 | /* check if the resource is reserved */ | |
ecfa935a BH |
187 | for (i = 0; i < 8; i++) { |
188 | int rport = pnp_reserve_io[i << 1]; | |
189 | int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1; | |
9dd78466 | 190 | if (ranged_conflict(port, end, &rport, &rend)) |
1da177e4 LT |
191 | return 0; |
192 | } | |
193 | ||
194 | /* check for internal conflicts */ | |
95ab3669 BH |
195 | for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) { |
196 | if (tres != res && tres->flags & IORESOURCE_IO) { | |
30c016a0 BH |
197 | tport = &tres->start; |
198 | tend = &tres->end; | |
9dd78466 | 199 | if (ranged_conflict(port, end, tport, tend)) |
1da177e4 LT |
200 | return 0; |
201 | } | |
202 | } | |
203 | ||
204 | /* check for conflicts with other pnp devices */ | |
205 | pnp_for_each_dev(tdev) { | |
206 | if (tdev == dev) | |
207 | continue; | |
95ab3669 BH |
208 | for (i = 0; |
209 | (tres = pnp_get_resource(tdev, IORESOURCE_IO, i)); | |
210 | i++) { | |
211 | if (tres->flags & IORESOURCE_IO) { | |
30c016a0 | 212 | if (cannot_compare(tres->flags)) |
1da177e4 | 213 | continue; |
11439a6f BH |
214 | if (tres->flags & IORESOURCE_WINDOW) |
215 | continue; | |
30c016a0 BH |
216 | tport = &tres->start; |
217 | tend = &tres->end; | |
9dd78466 | 218 | if (ranged_conflict(port, end, tport, tend)) |
1da177e4 LT |
219 | return 0; |
220 | } | |
221 | } | |
222 | } | |
223 | ||
224 | return 1; | |
225 | } | |
226 | ||
f5d94ff0 | 227 | int pnp_check_mem(struct pnp_dev *dev, struct resource *res) |
1da177e4 | 228 | { |
ecfa935a | 229 | int i; |
1da177e4 | 230 | struct pnp_dev *tdev; |
f5d94ff0 | 231 | struct resource *tres; |
b60ba834 | 232 | resource_size_t *addr, *end, *taddr, *tend; |
07d4e9af | 233 | |
30c016a0 BH |
234 | addr = &res->start; |
235 | end = &res->end; | |
1da177e4 LT |
236 | |
237 | /* if the resource doesn't exist, don't complain about it */ | |
30c016a0 | 238 | if (cannot_compare(res->flags)) |
1da177e4 LT |
239 | return 1; |
240 | ||
241 | /* check if the resource is already in use, skip if the | |
242 | * device is active because it itself may be in use */ | |
9dd78466 BH |
243 | if (!dev->active) { |
244 | if (check_mem_region(*addr, length(addr, end))) | |
1da177e4 LT |
245 | return 0; |
246 | } | |
247 | ||
248 | /* check if the resource is reserved */ | |
ecfa935a BH |
249 | for (i = 0; i < 8; i++) { |
250 | int raddr = pnp_reserve_mem[i << 1]; | |
251 | int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1; | |
9dd78466 | 252 | if (ranged_conflict(addr, end, &raddr, &rend)) |
1da177e4 LT |
253 | return 0; |
254 | } | |
255 | ||
256 | /* check for internal conflicts */ | |
95ab3669 BH |
257 | for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) { |
258 | if (tres != res && tres->flags & IORESOURCE_MEM) { | |
30c016a0 BH |
259 | taddr = &tres->start; |
260 | tend = &tres->end; | |
9dd78466 | 261 | if (ranged_conflict(addr, end, taddr, tend)) |
1da177e4 LT |
262 | return 0; |
263 | } | |
264 | } | |
265 | ||
266 | /* check for conflicts with other pnp devices */ | |
267 | pnp_for_each_dev(tdev) { | |
268 | if (tdev == dev) | |
269 | continue; | |
95ab3669 BH |
270 | for (i = 0; |
271 | (tres = pnp_get_resource(tdev, IORESOURCE_MEM, i)); | |
272 | i++) { | |
273 | if (tres->flags & IORESOURCE_MEM) { | |
30c016a0 | 274 | if (cannot_compare(tres->flags)) |
1da177e4 | 275 | continue; |
11439a6f BH |
276 | if (tres->flags & IORESOURCE_WINDOW) |
277 | continue; | |
30c016a0 BH |
278 | taddr = &tres->start; |
279 | tend = &tres->end; | |
9dd78466 | 280 | if (ranged_conflict(addr, end, taddr, tend)) |
1da177e4 LT |
281 | return 0; |
282 | } | |
283 | } | |
284 | } | |
285 | ||
286 | return 1; | |
287 | } | |
288 | ||
7d12e780 | 289 | static irqreturn_t pnp_test_handler(int irq, void *dev_id) |
1da177e4 LT |
290 | { |
291 | return IRQ_HANDLED; | |
292 | } | |
293 | ||
84684c74 BH |
294 | #ifdef CONFIG_PCI |
295 | static int pci_dev_uses_irq(struct pnp_dev *pnp, struct pci_dev *pci, | |
296 | unsigned int irq) | |
297 | { | |
298 | u32 class; | |
299 | u8 progif; | |
300 | ||
301 | if (pci->irq == irq) { | |
2f53432c | 302 | pnp_dbg(&pnp->dev, " device %s using irq %d\n", |
84684c74 BH |
303 | pci_name(pci), irq); |
304 | return 1; | |
305 | } | |
306 | ||
307 | /* | |
308 | * See pci_setup_device() and ata_pci_sff_activate_host() for | |
309 | * similar IDE legacy detection. | |
310 | */ | |
311 | pci_read_config_dword(pci, PCI_CLASS_REVISION, &class); | |
312 | class >>= 8; /* discard revision ID */ | |
313 | progif = class & 0xff; | |
314 | class >>= 8; | |
315 | ||
316 | if (class == PCI_CLASS_STORAGE_IDE) { | |
317 | /* | |
318 | * Unless both channels are native-PCI mode only, | |
319 | * treat the compatibility IRQs as busy. | |
320 | */ | |
321 | if ((progif & 0x5) != 0x5) | |
322 | if (pci_get_legacy_ide_irq(pci, 0) == irq || | |
323 | pci_get_legacy_ide_irq(pci, 1) == irq) { | |
2f53432c | 324 | pnp_dbg(&pnp->dev, " legacy IDE device %s " |
84684c74 BH |
325 | "using irq %d\n", pci_name(pci), irq); |
326 | return 1; | |
327 | } | |
328 | } | |
329 | ||
330 | return 0; | |
331 | } | |
332 | #endif | |
333 | ||
334 | static int pci_uses_irq(struct pnp_dev *pnp, unsigned int irq) | |
335 | { | |
336 | #ifdef CONFIG_PCI | |
337 | struct pci_dev *pci = NULL; | |
338 | ||
339 | for_each_pci_dev(pci) { | |
340 | if (pci_dev_uses_irq(pnp, pci, irq)) { | |
341 | pci_dev_put(pci); | |
342 | return 1; | |
343 | } | |
344 | } | |
345 | #endif | |
346 | return 0; | |
347 | } | |
348 | ||
f5d94ff0 | 349 | int pnp_check_irq(struct pnp_dev *dev, struct resource *res) |
1da177e4 | 350 | { |
ecfa935a | 351 | int i; |
1da177e4 | 352 | struct pnp_dev *tdev; |
f5d94ff0 | 353 | struct resource *tres; |
30c016a0 BH |
354 | resource_size_t *irq; |
355 | ||
30c016a0 | 356 | irq = &res->start; |
1da177e4 LT |
357 | |
358 | /* if the resource doesn't exist, don't complain about it */ | |
30c016a0 | 359 | if (cannot_compare(res->flags)) |
1da177e4 LT |
360 | return 1; |
361 | ||
362 | /* check if the resource is valid */ | |
363 | if (*irq < 0 || *irq > 15) | |
364 | return 0; | |
365 | ||
366 | /* check if the resource is reserved */ | |
ecfa935a BH |
367 | for (i = 0; i < 16; i++) { |
368 | if (pnp_reserve_irq[i] == *irq) | |
1da177e4 LT |
369 | return 0; |
370 | } | |
371 | ||
372 | /* check for internal conflicts */ | |
95ab3669 BH |
373 | for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) { |
374 | if (tres != res && tres->flags & IORESOURCE_IRQ) { | |
30c016a0 | 375 | if (tres->start == *irq) |
1da177e4 LT |
376 | return 0; |
377 | } | |
378 | } | |
379 | ||
1da177e4 | 380 | /* check if the resource is being used by a pci device */ |
84684c74 BH |
381 | if (pci_uses_irq(dev, *irq)) |
382 | return 0; | |
1da177e4 LT |
383 | |
384 | /* check if the resource is already in use, skip if the | |
385 | * device is active because it itself may be in use */ | |
9dd78466 | 386 | if (!dev->active) { |
0cadaf45 | 387 | if (request_irq(*irq, pnp_test_handler, |
9dd78466 | 388 | IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL)) |
1da177e4 LT |
389 | return 0; |
390 | free_irq(*irq, NULL); | |
391 | } | |
392 | ||
393 | /* check for conflicts with other pnp devices */ | |
394 | pnp_for_each_dev(tdev) { | |
395 | if (tdev == dev) | |
396 | continue; | |
95ab3669 BH |
397 | for (i = 0; |
398 | (tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i)); | |
399 | i++) { | |
400 | if (tres->flags & IORESOURCE_IRQ) { | |
30c016a0 | 401 | if (cannot_compare(tres->flags)) |
1da177e4 | 402 | continue; |
30c016a0 | 403 | if (tres->start == *irq) |
1da177e4 LT |
404 | return 0; |
405 | } | |
406 | } | |
407 | } | |
408 | ||
409 | return 1; | |
410 | } | |
411 | ||
586f83e2 | 412 | #ifdef CONFIG_ISA_DMA_API |
f5d94ff0 | 413 | int pnp_check_dma(struct pnp_dev *dev, struct resource *res) |
1da177e4 | 414 | { |
ecfa935a | 415 | int i; |
1da177e4 | 416 | struct pnp_dev *tdev; |
f5d94ff0 | 417 | struct resource *tres; |
30c016a0 BH |
418 | resource_size_t *dma; |
419 | ||
30c016a0 | 420 | dma = &res->start; |
1da177e4 LT |
421 | |
422 | /* if the resource doesn't exist, don't complain about it */ | |
30c016a0 | 423 | if (cannot_compare(res->flags)) |
1da177e4 LT |
424 | return 1; |
425 | ||
426 | /* check if the resource is valid */ | |
427 | if (*dma < 0 || *dma == 4 || *dma > 7) | |
428 | return 0; | |
429 | ||
430 | /* check if the resource is reserved */ | |
ecfa935a BH |
431 | for (i = 0; i < 8; i++) { |
432 | if (pnp_reserve_dma[i] == *dma) | |
1da177e4 LT |
433 | return 0; |
434 | } | |
435 | ||
436 | /* check for internal conflicts */ | |
95ab3669 BH |
437 | for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) { |
438 | if (tres != res && tres->flags & IORESOURCE_DMA) { | |
30c016a0 | 439 | if (tres->start == *dma) |
1da177e4 LT |
440 | return 0; |
441 | } | |
442 | } | |
443 | ||
444 | /* check if the resource is already in use, skip if the | |
445 | * device is active because it itself may be in use */ | |
9dd78466 | 446 | if (!dev->active) { |
1da177e4 LT |
447 | if (request_dma(*dma, "pnp")) |
448 | return 0; | |
449 | free_dma(*dma); | |
450 | } | |
451 | ||
452 | /* check for conflicts with other pnp devices */ | |
453 | pnp_for_each_dev(tdev) { | |
454 | if (tdev == dev) | |
455 | continue; | |
95ab3669 BH |
456 | for (i = 0; |
457 | (tres = pnp_get_resource(tdev, IORESOURCE_DMA, i)); | |
458 | i++) { | |
459 | if (tres->flags & IORESOURCE_DMA) { | |
30c016a0 | 460 | if (cannot_compare(tres->flags)) |
1da177e4 | 461 | continue; |
30c016a0 | 462 | if (tres->start == *dma) |
1da177e4 LT |
463 | return 0; |
464 | } | |
465 | } | |
466 | } | |
467 | ||
468 | return 1; | |
1da177e4 | 469 | } |
586f83e2 | 470 | #endif /* CONFIG_ISA_DMA_API */ |
1da177e4 | 471 | |
b563cf59 | 472 | unsigned long pnp_resource_type(struct resource *res) |
940e98db BH |
473 | { |
474 | return res->flags & (IORESOURCE_IO | IORESOURCE_MEM | | |
7e0e9c04 BH |
475 | IORESOURCE_IRQ | IORESOURCE_DMA | |
476 | IORESOURCE_BUS); | |
940e98db BH |
477 | } |
478 | ||
0a977f15 | 479 | struct resource *pnp_get_resource(struct pnp_dev *dev, |
b563cf59 | 480 | unsigned long type, unsigned int num) |
0a977f15 BH |
481 | { |
482 | struct pnp_resource *pnp_res; | |
aee3ad81 | 483 | struct resource *res; |
0a977f15 | 484 | |
aee3ad81 BH |
485 | list_for_each_entry(pnp_res, &dev->resources, list) { |
486 | res = &pnp_res->res; | |
487 | if (pnp_resource_type(res) == type && num-- == 0) | |
488 | return res; | |
489 | } | |
0a977f15 BH |
490 | return NULL; |
491 | } | |
b90eca0a BH |
492 | EXPORT_SYMBOL(pnp_get_resource); |
493 | ||
aee3ad81 | 494 | static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev) |
a50b6d7b BH |
495 | { |
496 | struct pnp_resource *pnp_res; | |
a50b6d7b | 497 | |
aee3ad81 BH |
498 | pnp_res = kzalloc(sizeof(struct pnp_resource), GFP_KERNEL); |
499 | if (!pnp_res) | |
500 | return NULL; | |
501 | ||
502 | list_add_tail(&pnp_res->list, &dev->resources); | |
503 | return pnp_res; | |
a50b6d7b BH |
504 | } |
505 | ||
046d9ce6 RW |
506 | struct pnp_resource *pnp_add_resource(struct pnp_dev *dev, |
507 | struct resource *res) | |
508 | { | |
509 | struct pnp_resource *pnp_res; | |
510 | ||
511 | pnp_res = pnp_new_resource(dev); | |
512 | if (!pnp_res) { | |
513 | dev_err(&dev->dev, "can't add resource %pR\n", res); | |
514 | return NULL; | |
515 | } | |
516 | ||
517 | pnp_res->res = *res; | |
3c0fc071 | 518 | pnp_res->res.name = dev->name; |
046d9ce6 RW |
519 | dev_dbg(&dev->dev, "%pR\n", res); |
520 | return pnp_res; | |
521 | } | |
522 | ||
dbddd038 BH |
523 | struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, |
524 | int flags) | |
525 | { | |
526 | struct pnp_resource *pnp_res; | |
527 | struct resource *res; | |
dbddd038 | 528 | |
aee3ad81 | 529 | pnp_res = pnp_new_resource(dev); |
dbddd038 | 530 | if (!pnp_res) { |
25d39c39 | 531 | dev_err(&dev->dev, "can't add resource for IRQ %d\n", irq); |
dbddd038 BH |
532 | return NULL; |
533 | } | |
534 | ||
535 | res = &pnp_res->res; | |
536 | res->flags = IORESOURCE_IRQ | flags; | |
537 | res->start = irq; | |
538 | res->end = irq; | |
539 | ||
c1f3f281 | 540 | dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); |
dbddd038 BH |
541 | return pnp_res; |
542 | } | |
543 | ||
dc16f5f2 BH |
544 | struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, |
545 | int flags) | |
546 | { | |
547 | struct pnp_resource *pnp_res; | |
548 | struct resource *res; | |
dc16f5f2 | 549 | |
aee3ad81 | 550 | pnp_res = pnp_new_resource(dev); |
dc16f5f2 | 551 | if (!pnp_res) { |
25d39c39 | 552 | dev_err(&dev->dev, "can't add resource for DMA %d\n", dma); |
dc16f5f2 BH |
553 | return NULL; |
554 | } | |
555 | ||
556 | res = &pnp_res->res; | |
557 | res->flags = IORESOURCE_DMA | flags; | |
558 | res->start = dma; | |
559 | res->end = dma; | |
560 | ||
c1f3f281 | 561 | dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); |
dc16f5f2 BH |
562 | return pnp_res; |
563 | } | |
564 | ||
cc8c2e30 BH |
565 | struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev, |
566 | resource_size_t start, | |
567 | resource_size_t end, int flags) | |
568 | { | |
569 | struct pnp_resource *pnp_res; | |
570 | struct resource *res; | |
cc8c2e30 | 571 | |
aee3ad81 | 572 | pnp_res = pnp_new_resource(dev); |
cc8c2e30 | 573 | if (!pnp_res) { |
25d39c39 BH |
574 | dev_err(&dev->dev, "can't add resource for IO %#llx-%#llx\n", |
575 | (unsigned long long) start, | |
576 | (unsigned long long) end); | |
cc8c2e30 BH |
577 | return NULL; |
578 | } | |
579 | ||
580 | res = &pnp_res->res; | |
581 | res->flags = IORESOURCE_IO | flags; | |
582 | res->start = start; | |
583 | res->end = end; | |
584 | ||
c1f3f281 | 585 | dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); |
cc8c2e30 BH |
586 | return pnp_res; |
587 | } | |
588 | ||
d6180f36 BH |
589 | struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev, |
590 | resource_size_t start, | |
591 | resource_size_t end, int flags) | |
592 | { | |
593 | struct pnp_resource *pnp_res; | |
594 | struct resource *res; | |
d6180f36 | 595 | |
aee3ad81 | 596 | pnp_res = pnp_new_resource(dev); |
d6180f36 | 597 | if (!pnp_res) { |
25d39c39 BH |
598 | dev_err(&dev->dev, "can't add resource for MEM %#llx-%#llx\n", |
599 | (unsigned long long) start, | |
600 | (unsigned long long) end); | |
d6180f36 BH |
601 | return NULL; |
602 | } | |
603 | ||
604 | res = &pnp_res->res; | |
605 | res->flags = IORESOURCE_MEM | flags; | |
606 | res->start = start; | |
607 | res->end = end; | |
608 | ||
c1f3f281 | 609 | dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); |
d6180f36 BH |
610 | return pnp_res; |
611 | } | |
612 | ||
7e0e9c04 BH |
613 | struct pnp_resource *pnp_add_bus_resource(struct pnp_dev *dev, |
614 | resource_size_t start, | |
615 | resource_size_t end) | |
616 | { | |
617 | struct pnp_resource *pnp_res; | |
618 | struct resource *res; | |
619 | ||
620 | pnp_res = pnp_new_resource(dev); | |
621 | if (!pnp_res) { | |
622 | dev_err(&dev->dev, "can't add resource for BUS %#llx-%#llx\n", | |
623 | (unsigned long long) start, | |
624 | (unsigned long long) end); | |
625 | return NULL; | |
626 | } | |
627 | ||
628 | res = &pnp_res->res; | |
629 | res->flags = IORESOURCE_BUS; | |
630 | res->start = start; | |
631 | res->end = end; | |
632 | ||
c1f3f281 | 633 | dev_printk(KERN_DEBUG, &dev->dev, "%pR\n", res); |
7e0e9c04 BH |
634 | return pnp_res; |
635 | } | |
636 | ||
1f32ca31 BH |
637 | /* |
638 | * Determine whether the specified resource is a possible configuration | |
639 | * for this device. | |
640 | */ | |
641 | int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start, | |
642 | resource_size_t size) | |
57fd51a8 | 643 | { |
1f32ca31 | 644 | struct pnp_option *option; |
57fd51a8 BH |
645 | struct pnp_port *port; |
646 | struct pnp_mem *mem; | |
647 | struct pnp_irq *irq; | |
648 | struct pnp_dma *dma; | |
649 | ||
1f32ca31 BH |
650 | list_for_each_entry(option, &dev->options, list) { |
651 | if (option->type != type) | |
652 | continue; | |
57fd51a8 | 653 | |
1f32ca31 | 654 | switch (option->type) { |
57fd51a8 | 655 | case IORESOURCE_IO: |
1f32ca31 BH |
656 | port = &option->u.port; |
657 | if (port->min == start && port->size == size) | |
658 | return 1; | |
57fd51a8 BH |
659 | break; |
660 | case IORESOURCE_MEM: | |
1f32ca31 BH |
661 | mem = &option->u.mem; |
662 | if (mem->min == start && mem->size == size) | |
663 | return 1; | |
57fd51a8 BH |
664 | break; |
665 | case IORESOURCE_IRQ: | |
1f32ca31 BH |
666 | irq = &option->u.irq; |
667 | if (start < PNP_IRQ_NR && | |
668 | test_bit(start, irq->map.bits)) | |
669 | return 1; | |
57fd51a8 BH |
670 | break; |
671 | case IORESOURCE_DMA: | |
1f32ca31 BH |
672 | dma = &option->u.dma; |
673 | if (dma->map & (1 << start)) | |
674 | return 1; | |
57fd51a8 BH |
675 | break; |
676 | } | |
677 | } | |
678 | ||
679 | return 0; | |
680 | } | |
57fd51a8 BH |
681 | EXPORT_SYMBOL(pnp_possible_config); |
682 | ||
1b8e6966 BH |
683 | int pnp_range_reserved(resource_size_t start, resource_size_t end) |
684 | { | |
685 | struct pnp_dev *dev; | |
686 | struct pnp_resource *pnp_res; | |
687 | resource_size_t *dev_start, *dev_end; | |
688 | ||
689 | pnp_for_each_dev(dev) { | |
690 | list_for_each_entry(pnp_res, &dev->resources, list) { | |
691 | dev_start = &pnp_res->res.start; | |
692 | dev_end = &pnp_res->res.end; | |
693 | if (ranged_conflict(&start, &end, dev_start, dev_end)) | |
694 | return 1; | |
695 | } | |
696 | } | |
697 | return 0; | |
698 | } | |
699 | EXPORT_SYMBOL(pnp_range_reserved); | |
700 | ||
1da177e4 | 701 | /* format is: pnp_reserve_irq=irq1[,irq2] .... */ |
1da177e4 LT |
702 | static int __init pnp_setup_reserve_irq(char *str) |
703 | { | |
704 | int i; | |
705 | ||
706 | for (i = 0; i < 16; i++) | |
9dd78466 | 707 | if (get_option(&str, &pnp_reserve_irq[i]) != 2) |
1da177e4 LT |
708 | break; |
709 | return 1; | |
710 | } | |
711 | ||
712 | __setup("pnp_reserve_irq=", pnp_setup_reserve_irq); | |
713 | ||
714 | /* format is: pnp_reserve_dma=dma1[,dma2] .... */ | |
1da177e4 LT |
715 | static int __init pnp_setup_reserve_dma(char *str) |
716 | { | |
717 | int i; | |
718 | ||
719 | for (i = 0; i < 8; i++) | |
9dd78466 | 720 | if (get_option(&str, &pnp_reserve_dma[i]) != 2) |
1da177e4 LT |
721 | break; |
722 | return 1; | |
723 | } | |
724 | ||
725 | __setup("pnp_reserve_dma=", pnp_setup_reserve_dma); | |
726 | ||
727 | /* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */ | |
1da177e4 LT |
728 | static int __init pnp_setup_reserve_io(char *str) |
729 | { | |
730 | int i; | |
731 | ||
732 | for (i = 0; i < 16; i++) | |
9dd78466 | 733 | if (get_option(&str, &pnp_reserve_io[i]) != 2) |
1da177e4 LT |
734 | break; |
735 | return 1; | |
736 | } | |
737 | ||
738 | __setup("pnp_reserve_io=", pnp_setup_reserve_io); | |
739 | ||
740 | /* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */ | |
1da177e4 LT |
741 | static int __init pnp_setup_reserve_mem(char *str) |
742 | { | |
743 | int i; | |
744 | ||
745 | for (i = 0; i < 16; i++) | |
9dd78466 | 746 | if (get_option(&str, &pnp_reserve_mem[i]) != 2) |
1da177e4 LT |
747 | break; |
748 | return 1; | |
749 | } | |
750 | ||
751 | __setup("pnp_reserve_mem=", pnp_setup_reserve_mem); |