diff options
Diffstat (limited to 'drivers/pnp/system.c')
-rw-r--r-- | drivers/pnp/system.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c new file mode 100644 index 000000000000..d42015c382af --- /dev/null +++ b/drivers/pnp/system.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * system.c - a driver for reserving pnp system resources | ||
3 | * | ||
4 | * Some code is based on pnpbios_core.c | ||
5 | * Copyright 2002 Adam Belay <ambx1@neo.rr.com> | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <linux/pnp.h> | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/ioport.h> | ||
15 | |||
16 | static const struct pnp_device_id pnp_dev_table[] = { | ||
17 | /* General ID for reserving resources */ | ||
18 | { "PNP0c02", 0 }, | ||
19 | /* memory controller */ | ||
20 | { "PNP0c01", 0 }, | ||
21 | { "", 0 } | ||
22 | }; | ||
23 | |||
24 | static void reserve_ioport_range(char *pnpid, int start, int end) | ||
25 | { | ||
26 | struct resource *res; | ||
27 | char *regionid; | ||
28 | |||
29 | regionid = kmalloc(16, GFP_KERNEL); | ||
30 | if ( regionid == NULL ) | ||
31 | return; | ||
32 | snprintf(regionid, 16, "pnp %s", pnpid); | ||
33 | res = request_region(start,end-start+1,regionid); | ||
34 | if ( res == NULL ) | ||
35 | kfree( regionid ); | ||
36 | else | ||
37 | res->flags &= ~IORESOURCE_BUSY; | ||
38 | /* | ||
39 | * Failures at this point are usually harmless. pci quirks for | ||
40 | * example do reserve stuff they know about too, so we may well | ||
41 | * have double reservations. | ||
42 | */ | ||
43 | printk(KERN_INFO | ||
44 | "pnp: %s: ioport range 0x%x-0x%x %s reserved\n", | ||
45 | pnpid, start, end, | ||
46 | NULL != res ? "has been" : "could not be" | ||
47 | ); | ||
48 | |||
49 | return; | ||
50 | } | ||
51 | |||
52 | static void reserve_resources_of_dev( struct pnp_dev *dev ) | ||
53 | { | ||
54 | int i; | ||
55 | |||
56 | for (i=0;i<PNP_MAX_PORT;i++) { | ||
57 | if (!pnp_port_valid(dev, i)) | ||
58 | /* end of resources */ | ||
59 | continue; | ||
60 | if (pnp_port_start(dev, i) == 0) | ||
61 | /* disabled */ | ||
62 | /* Do nothing */ | ||
63 | continue; | ||
64 | if (pnp_port_start(dev, i) < 0x100) | ||
65 | /* | ||
66 | * Below 0x100 is only standard PC hardware | ||
67 | * (pics, kbd, timer, dma, ...) | ||
68 | * We should not get resource conflicts there, | ||
69 | * and the kernel reserves these anyway | ||
70 | * (see arch/i386/kernel/setup.c). | ||
71 | * So, do nothing | ||
72 | */ | ||
73 | continue; | ||
74 | if (pnp_port_end(dev, i) < pnp_port_start(dev, i)) | ||
75 | /* invalid endpoint */ | ||
76 | /* Do nothing */ | ||
77 | continue; | ||
78 | reserve_ioport_range( | ||
79 | dev->dev.bus_id, | ||
80 | pnp_port_start(dev, i), | ||
81 | pnp_port_end(dev, i) | ||
82 | ); | ||
83 | } | ||
84 | |||
85 | return; | ||
86 | } | ||
87 | |||
88 | static int system_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id) | ||
89 | { | ||
90 | reserve_resources_of_dev(dev); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static struct pnp_driver system_pnp_driver = { | ||
95 | .name = "system", | ||
96 | .id_table = pnp_dev_table, | ||
97 | .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, | ||
98 | .probe = system_pnp_probe, | ||
99 | .remove = NULL, | ||
100 | }; | ||
101 | |||
102 | static int __init pnp_system_init(void) | ||
103 | { | ||
104 | return pnp_register_driver(&system_pnp_driver); | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * Reserve motherboard resources after PCI claim BARs, | ||
109 | * but before PCI assign resources for uninitialized PCI devices | ||
110 | */ | ||
111 | fs_initcall(pnp_system_init); | ||