aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pnp
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/pnp
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/pnp')
-rw-r--r--drivers/pnp/Kconfig41
-rw-r--r--drivers/pnp/Makefile9
-rw-r--r--drivers/pnp/base.h13
-rw-r--r--drivers/pnp/card.c391
-rw-r--r--drivers/pnp/core.c180
-rw-r--r--drivers/pnp/driver.c222
-rw-r--r--drivers/pnp/interface.c468
-rw-r--r--drivers/pnp/isapnp/Kconfig11
-rw-r--r--drivers/pnp/isapnp/Makefile7
-rw-r--r--drivers/pnp/isapnp/compat.c91
-rw-r--r--drivers/pnp/isapnp/core.c1156
-rw-r--r--drivers/pnp/isapnp/proc.c171
-rw-r--r--drivers/pnp/manager.c566
-rw-r--r--drivers/pnp/pnpacpi/Kconfig18
-rw-r--r--drivers/pnp/pnpacpi/Makefile5
-rw-r--r--drivers/pnp/pnpacpi/core.c269
-rw-r--r--drivers/pnp/pnpacpi/pnpacpi.h13
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c821
-rw-r--r--drivers/pnp/pnpbios/Kconfig42
-rw-r--r--drivers/pnp/pnpbios/Makefile7
-rw-r--r--drivers/pnp/pnpbios/bioscalls.c544
-rw-r--r--drivers/pnp/pnpbios/core.c644
-rw-r--r--drivers/pnp/pnpbios/pnpbios.h47
-rw-r--r--drivers/pnp/pnpbios/proc.c292
-rw-r--r--drivers/pnp/pnpbios/rsparser.c795
-rw-r--r--drivers/pnp/quirks.c152
-rw-r--r--drivers/pnp/resource.c542
-rw-r--r--drivers/pnp/support.c40
-rw-r--r--drivers/pnp/system.c111
29 files changed, 7668 insertions, 0 deletions
diff --git a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig
new file mode 100644
index 000000000000..6776308a1fe5
--- /dev/null
+++ b/drivers/pnp/Kconfig
@@ -0,0 +1,41 @@
1#
2# Plug and Play configuration
3#
4
5menu "Plug and Play support"
6
7config PNP
8 bool "Plug and Play support"
9 depends on ISA || ACPI_BUS
10 ---help---
11 Plug and Play (PnP) is a standard for peripherals which allows those
12 peripherals to be configured by software, e.g. assign IRQ's or other
13 parameters. No jumpers on the cards are needed, instead the values
14 are provided to the cards from the BIOS, from the operating system,
15 or using a user-space utility.
16
17 Say Y here if you would like Linux to configure your Plug and Play
18 devices. You should then also say Y to all of the protocols below.
19 Alternatively, you can say N here and configure your PnP devices
20 using user space utilities such as the isapnptools package.
21
22 If unsure, say Y.
23
24config PNP_DEBUG
25 bool "PnP Debug Messages"
26 depends on PNP
27 help
28 Say Y if you want the Plug and Play Layer to print debug messages.
29 This is useful if you are developing a PnP driver or troubleshooting.
30
31comment "Protocols"
32 depends on PNP
33
34source "drivers/pnp/isapnp/Kconfig"
35
36source "drivers/pnp/pnpbios/Kconfig"
37
38source "drivers/pnp/pnpacpi/Kconfig"
39
40endmenu
41
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile
new file mode 100644
index 000000000000..a381a92fd1b6
--- /dev/null
+++ b/drivers/pnp/Makefile
@@ -0,0 +1,9 @@
1#
2# Makefile for the Linux Plug-and-Play Support.
3#
4
5obj-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o system.o
6
7obj-$(CONFIG_PNPACPI) += pnpacpi/
8obj-$(CONFIG_PNPBIOS) += pnpbios/
9obj-$(CONFIG_ISAPNP) += isapnp/
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
new file mode 100644
index 000000000000..6b8c4cfd02a6
--- /dev/null
+++ b/drivers/pnp/base.h
@@ -0,0 +1,13 @@
1extern struct bus_type pnp_bus_type;
2extern spinlock_t pnp_lock;
3void *pnp_alloc(long size);
4int pnp_interface_attach_device(struct pnp_dev *dev);
5void pnp_fixup_device(struct pnp_dev *dev);
6void pnp_free_option(struct pnp_option *option);
7int __pnp_add_device(struct pnp_dev *dev);
8void __pnp_remove_device(struct pnp_dev *dev);
9
10int pnp_check_port(struct pnp_dev * dev, int idx);
11int pnp_check_mem(struct pnp_dev * dev, int idx);
12int pnp_check_irq(struct pnp_dev * dev, int idx);
13int pnp_check_dma(struct pnp_dev * dev, int idx);
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
new file mode 100644
index 000000000000..97eeecfaef1b
--- /dev/null
+++ b/drivers/pnp/card.c
@@ -0,0 +1,391 @@
1/*
2 * card.c - contains functions for managing groups of PnP devices
3 *
4 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
5 *
6 */
7
8#include <linux/config.h>
9#include <linux/module.h>
10#include <linux/slab.h>
11
12#ifdef CONFIG_PNP_DEBUG
13 #define DEBUG
14#else
15 #undef DEBUG
16#endif
17
18#include <linux/pnp.h>
19#include "base.h"
20
21LIST_HEAD(pnp_cards);
22LIST_HEAD(pnp_card_drivers);
23
24
25static const struct pnp_card_device_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card)
26{
27 const struct pnp_card_device_id * drv_id = drv->id_table;
28 while (*drv_id->id){
29 if (compare_pnp_id(card->id,drv_id->id)) {
30 int i = 0;
31 for (;;) {
32 int found;
33 struct pnp_dev *dev;
34 if (i == PNP_MAX_DEVICES || ! *drv_id->devs[i].id)
35 return drv_id;
36 found = 0;
37 card_for_each_dev(card, dev) {
38 if (compare_pnp_id(dev->id, drv_id->devs[i].id)) {
39 found = 1;
40 break;
41 }
42 }
43 if (! found)
44 break;
45 i++;
46 }
47 }
48 drv_id++;
49 }
50 return NULL;
51}
52
53static void card_remove(struct pnp_dev * dev)
54{
55 dev->card_link = NULL;
56}
57
58static void card_remove_first(struct pnp_dev * dev)
59{
60 struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver);
61 if (!dev->card || !drv)
62 return;
63 if (drv->remove)
64 drv->remove(dev->card_link);
65 drv->link.remove = &card_remove;
66 kfree(dev->card_link);
67 card_remove(dev);
68}
69
70static int card_probe(struct pnp_card * card, struct pnp_card_driver * drv)
71{
72 const struct pnp_card_device_id *id = match_card(drv,card);
73 if (id) {
74 struct pnp_card_link * clink = pnp_alloc(sizeof(struct pnp_card_link));
75 if (!clink)
76 return 0;
77 clink->card = card;
78 clink->driver = drv;
79 if (drv->probe) {
80 if (drv->probe(clink, id)>=0)
81 return 1;
82 else {
83 struct pnp_dev * dev;
84 card_for_each_dev(card, dev) {
85 if (dev->card_link == clink)
86 pnp_release_card_device(dev);
87 }
88 kfree(clink);
89 }
90 } else
91 return 1;
92 }
93 return 0;
94}
95
96/**
97 * pnp_add_card_id - adds an EISA id to the specified card
98 * @id: pointer to a pnp_id structure
99 * @card: pointer to the desired card
100 *
101 */
102
103int pnp_add_card_id(struct pnp_id *id, struct pnp_card * card)
104{
105 struct pnp_id * ptr;
106 if (!id)
107 return -EINVAL;
108 if (!card)
109 return -EINVAL;
110 id->next = NULL;
111 ptr = card->id;
112 while (ptr && ptr->next)
113 ptr = ptr->next;
114 if (ptr)
115 ptr->next = id;
116 else
117 card->id = id;
118 return 0;
119}
120
121static void pnp_free_card_ids(struct pnp_card * card)
122{
123 struct pnp_id * id;
124 struct pnp_id *next;
125 if (!card)
126 return;
127 id = card->id;
128 while (id) {
129 next = id->next;
130 kfree(id);
131 id = next;
132 }
133}
134
135static void pnp_release_card(struct device *dmdev)
136{
137 struct pnp_card * card = to_pnp_card(dmdev);
138 pnp_free_card_ids(card);
139 kfree(card);
140}
141
142
143static ssize_t pnp_show_card_name(struct device *dmdev, char *buf)
144{
145 char *str = buf;
146 struct pnp_card *card = to_pnp_card(dmdev);
147 str += sprintf(str,"%s\n", card->name);
148 return (str - buf);
149}
150
151static DEVICE_ATTR(name,S_IRUGO,pnp_show_card_name,NULL);
152
153static ssize_t pnp_show_card_ids(struct device *dmdev, char *buf)
154{
155 char *str = buf;
156 struct pnp_card *card = to_pnp_card(dmdev);
157 struct pnp_id * pos = card->id;
158
159 while (pos) {
160 str += sprintf(str,"%s\n", pos->id);
161 pos = pos->next;
162 }
163 return (str - buf);
164}
165
166static DEVICE_ATTR(card_id,S_IRUGO,pnp_show_card_ids,NULL);
167
168static int pnp_interface_attach_card(struct pnp_card *card)
169{
170 device_create_file(&card->dev,&dev_attr_name);
171 device_create_file(&card->dev,&dev_attr_card_id);
172 return 0;
173}
174
175/**
176 * pnp_add_card - adds a PnP card to the PnP Layer
177 * @card: pointer to the card to add
178 */
179
180int pnp_add_card(struct pnp_card * card)
181{
182 int error;
183 struct list_head * pos, * temp;
184 if (!card || !card->protocol)
185 return -EINVAL;
186
187 sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, card->number);
188 card->dev.parent = &card->protocol->dev;
189 card->dev.bus = NULL;
190 card->dev.release = &pnp_release_card;
191 error = device_register(&card->dev);
192
193 if (error == 0) {
194 pnp_interface_attach_card(card);
195 spin_lock(&pnp_lock);
196 list_add_tail(&card->global_list, &pnp_cards);
197 list_add_tail(&card->protocol_list, &card->protocol->cards);
198 spin_unlock(&pnp_lock);
199
200 /* we wait until now to add devices in order to ensure the drivers
201 * will be able to use all of the related devices on the card
202 * without waiting any unresonable length of time */
203 list_for_each(pos,&card->devices){
204 struct pnp_dev *dev = card_to_pnp_dev(pos);
205 __pnp_add_device(dev);
206 }
207
208 /* match with card drivers */
209 list_for_each_safe(pos,temp,&pnp_card_drivers){
210 struct pnp_card_driver * drv = list_entry(pos, struct pnp_card_driver, global_list);
211 card_probe(card,drv);
212 }
213 } else
214 pnp_err("sysfs failure, card '%s' will be unavailable", card->dev.bus_id);
215 return error;
216}
217
218/**
219 * pnp_remove_card - removes a PnP card from the PnP Layer
220 * @card: pointer to the card to remove
221 */
222
223void pnp_remove_card(struct pnp_card * card)
224{
225 struct list_head *pos, *temp;
226 if (!card)
227 return;
228 device_unregister(&card->dev);
229 spin_lock(&pnp_lock);
230 list_del(&card->global_list);
231 list_del(&card->protocol_list);
232 spin_unlock(&pnp_lock);
233 list_for_each_safe(pos,temp,&card->devices){
234 struct pnp_dev *dev = card_to_pnp_dev(pos);
235 pnp_remove_card_device(dev);
236 }
237}
238
239/**
240 * pnp_add_card_device - adds a device to the specified card
241 * @card: pointer to the card to add to
242 * @dev: pointer to the device to add
243 */
244
245int pnp_add_card_device(struct pnp_card * card, struct pnp_dev * dev)
246{
247 if (!card || !dev || !dev->protocol)
248 return -EINVAL;
249 dev->dev.parent = &card->dev;
250 dev->card_link = NULL;
251 snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%02x:%02x.%02x", dev->protocol->number,
252 card->number,dev->number);
253 spin_lock(&pnp_lock);
254 dev->card = card;
255 list_add_tail(&dev->card_list, &card->devices);
256 spin_unlock(&pnp_lock);
257 return 0;
258}
259
260/**
261 * pnp_remove_card_device- removes a device from the specified card
262 * @card: pointer to the card to remove from
263 * @dev: pointer to the device to remove
264 */
265
266void pnp_remove_card_device(struct pnp_dev * dev)
267{
268 spin_lock(&pnp_lock);
269 dev->card = NULL;
270 list_del(&dev->card_list);
271 spin_unlock(&pnp_lock);
272 __pnp_remove_device(dev);
273}
274
275/**
276 * pnp_request_card_device - Searches for a PnP device under the specified card
277 * @lcard: pointer to the card link, cannot be NULL
278 * @id: pointer to a PnP ID structure that explains the rules for finding the device
279 * @from: Starting place to search from. If NULL it will start from the begining.
280 */
281
282struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char * id, struct pnp_dev * from)
283{
284 struct list_head * pos;
285 struct pnp_dev * dev;
286 struct pnp_card_driver * drv;
287 struct pnp_card * card;
288 if (!clink || !id)
289 goto done;
290 card = clink->card;
291 drv = clink->driver;
292 if (!from) {
293 pos = card->devices.next;
294 } else {
295 if (from->card != card)
296 goto done;
297 pos = from->card_list.next;
298 }
299 while (pos != &card->devices) {
300 dev = card_to_pnp_dev(pos);
301 if ((!dev->card_link) && compare_pnp_id(dev->id,id))
302 goto found;
303 pos = pos->next;
304 }
305
306done:
307 return NULL;
308
309found:
310 down_write(&dev->dev.bus->subsys.rwsem);
311 dev->card_link = clink;
312 dev->dev.driver = &drv->link.driver;
313 if (drv->link.driver.probe) {
314 if (drv->link.driver.probe(&dev->dev)) {
315 dev->dev.driver = NULL;
316 return NULL;
317 }
318 }
319 device_bind_driver(&dev->dev);
320 up_write(&dev->dev.bus->subsys.rwsem);
321
322 return dev;
323}
324
325/**
326 * pnp_release_card_device - call this when the driver no longer needs the device
327 * @dev: pointer to the PnP device stucture
328 */
329
330void pnp_release_card_device(struct pnp_dev * dev)
331{
332 struct pnp_card_driver * drv = dev->card_link->driver;
333 if (!drv)
334 return;
335 down_write(&dev->dev.bus->subsys.rwsem);
336 drv->link.remove = &card_remove;
337 device_release_driver(&dev->dev);
338 drv->link.remove = &card_remove_first;
339 up_write(&dev->dev.bus->subsys.rwsem);
340}
341
342/**
343 * pnp_register_card_driver - registers a PnP card driver with the PnP Layer
344 * @drv: pointer to the driver to register
345 */
346
347int pnp_register_card_driver(struct pnp_card_driver * drv)
348{
349 int count = 0;
350 struct list_head *pos, *temp;
351
352 drv->link.name = drv->name;
353 drv->link.id_table = NULL; /* this will disable auto matching */
354 drv->link.flags = drv->flags;
355 drv->link.probe = NULL;
356 drv->link.remove = &card_remove_first;
357
358 spin_lock(&pnp_lock);
359 list_add_tail(&drv->global_list, &pnp_card_drivers);
360 spin_unlock(&pnp_lock);
361 pnp_register_driver(&drv->link);
362
363 list_for_each_safe(pos,temp,&pnp_cards){
364 struct pnp_card *card = list_entry(pos, struct pnp_card, global_list);
365 count += card_probe(card,drv);
366 }
367 return count;
368}
369
370/**
371 * pnp_unregister_card_driver - unregisters a PnP card driver from the PnP Layer
372 * @drv: pointer to the driver to unregister
373 */
374
375void pnp_unregister_card_driver(struct pnp_card_driver * drv)
376{
377 spin_lock(&pnp_lock);
378 list_del(&drv->global_list);
379 spin_unlock(&pnp_lock);
380 pnp_unregister_driver(&drv->link);
381}
382
383EXPORT_SYMBOL(pnp_add_card);
384EXPORT_SYMBOL(pnp_remove_card);
385EXPORT_SYMBOL(pnp_add_card_device);
386EXPORT_SYMBOL(pnp_remove_card_device);
387EXPORT_SYMBOL(pnp_add_card_id);
388EXPORT_SYMBOL(pnp_request_card_device);
389EXPORT_SYMBOL(pnp_release_card_device);
390EXPORT_SYMBOL(pnp_register_card_driver);
391EXPORT_SYMBOL(pnp_unregister_card_driver);
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
new file mode 100644
index 000000000000..deed92459bc5
--- /dev/null
+++ b/drivers/pnp/core.c
@@ -0,0 +1,180 @@
1/*
2 * core.c - contains all core device and protocol registration functions
3 *
4 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
5 *
6 */
7
8#include <linux/pnp.h>
9#include <linux/types.h>
10#include <linux/list.h>
11#include <linux/device.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/string.h>
15#include <linux/slab.h>
16#include <linux/errno.h>
17
18#include "base.h"
19
20
21static LIST_HEAD(pnp_protocols);
22LIST_HEAD(pnp_global);
23DEFINE_SPINLOCK(pnp_lock);
24
25void *pnp_alloc(long size)
26{
27 void *result;
28
29 result = kmalloc(size, GFP_KERNEL);
30 if (!result){
31 printk(KERN_ERR "pnp: Out of Memory\n");
32 return NULL;
33 }
34 memset(result, 0, size);
35 return result;
36}
37
38/**
39 * pnp_protocol_register - adds a pnp protocol to the pnp layer
40 * @protocol: pointer to the corresponding pnp_protocol structure
41 *
42 * Ex protocols: ISAPNP, PNPBIOS, etc
43 */
44
45int pnp_register_protocol(struct pnp_protocol *protocol)
46{
47 int nodenum;
48 struct list_head * pos;
49
50 if (!protocol)
51 return -EINVAL;
52
53 INIT_LIST_HEAD(&protocol->devices);
54 INIT_LIST_HEAD(&protocol->cards);
55 nodenum = 0;
56 spin_lock(&pnp_lock);
57
58 /* assign the lowest unused number */
59 list_for_each(pos,&pnp_protocols) {
60 struct pnp_protocol * cur = to_pnp_protocol(pos);
61 if (cur->number == nodenum){
62 pos = &pnp_protocols;
63 nodenum++;
64 }
65 }
66
67 list_add_tail(&protocol->protocol_list, &pnp_protocols);
68 spin_unlock(&pnp_lock);
69
70 protocol->number = nodenum;
71 sprintf(protocol->dev.bus_id, "pnp%d", nodenum);
72 return device_register(&protocol->dev);
73}
74
75/**
76 * pnp_protocol_unregister - removes a pnp protocol from the pnp layer
77 * @protocol: pointer to the corresponding pnp_protocol structure
78 *
79 */
80void pnp_unregister_protocol(struct pnp_protocol *protocol)
81{
82 spin_lock(&pnp_lock);
83 list_del(&protocol->protocol_list);
84 spin_unlock(&pnp_lock);
85 device_unregister(&protocol->dev);
86}
87
88
89static void pnp_free_ids(struct pnp_dev *dev)
90{
91 struct pnp_id * id;
92 struct pnp_id * next;
93 if (!dev)
94 return;
95 id = dev->id;
96 while (id) {
97 next = id->next;
98 kfree(id);
99 id = next;
100 }
101}
102
103static void pnp_release_device(struct device *dmdev)
104{
105 struct pnp_dev * dev = to_pnp_dev(dmdev);
106 pnp_free_option(dev->independent);
107 pnp_free_option(dev->dependent);
108 pnp_free_ids(dev);
109 kfree(dev);
110}
111
112int __pnp_add_device(struct pnp_dev *dev)
113{
114 int ret;
115 pnp_fixup_device(dev);
116 dev->dev.bus = &pnp_bus_type;
117 dev->dev.release = &pnp_release_device;
118 dev->status = PNP_READY;
119 spin_lock(&pnp_lock);
120 list_add_tail(&dev->global_list, &pnp_global);
121 list_add_tail(&dev->protocol_list, &dev->protocol->devices);
122 spin_unlock(&pnp_lock);
123
124 ret = device_register(&dev->dev);
125 if (ret == 0)
126 pnp_interface_attach_device(dev);
127 return ret;
128}
129
130/*
131 * pnp_add_device - adds a pnp device to the pnp layer
132 * @dev: pointer to dev to add
133 *
134 * adds to driver model, name database, fixups, interface, etc.
135 */
136
137int pnp_add_device(struct pnp_dev *dev)
138{
139 if (!dev || !dev->protocol || dev->card)
140 return -EINVAL;
141 dev->dev.parent = &dev->protocol->dev;
142 sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, dev->number);
143 return __pnp_add_device(dev);
144}
145
146void __pnp_remove_device(struct pnp_dev *dev)
147{
148 spin_lock(&pnp_lock);
149 list_del(&dev->global_list);
150 list_del(&dev->protocol_list);
151 spin_unlock(&pnp_lock);
152 device_unregister(&dev->dev);
153}
154
155/**
156 * pnp_remove_device - removes a pnp device from the pnp layer
157 * @dev: pointer to dev to add
158 *
159 * this function will free all mem used by dev
160 */
161
162void pnp_remove_device(struct pnp_dev *dev)
163{
164 if (!dev || dev->card)
165 return;
166 __pnp_remove_device(dev);
167}
168
169static int __init pnp_init(void)
170{
171 printk(KERN_INFO "Linux Plug and Play Support v0.97 (c) Adam Belay\n");
172 return bus_register(&pnp_bus_type);
173}
174
175subsys_initcall(pnp_init);
176
177EXPORT_SYMBOL(pnp_register_protocol);
178EXPORT_SYMBOL(pnp_unregister_protocol);
179EXPORT_SYMBOL(pnp_add_device);
180EXPORT_SYMBOL(pnp_remove_device);
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
new file mode 100644
index 000000000000..d64c1ca4fa76
--- /dev/null
+++ b/drivers/pnp/driver.c
@@ -0,0 +1,222 @@
1/*
2 * driver.c - device id matching, driver model, etc.
3 *
4 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
5 *
6 */
7
8#include <linux/config.h>
9#include <linux/string.h>
10#include <linux/list.h>
11#include <linux/module.h>
12#include <linux/ctype.h>
13#include <linux/slab.h>
14
15#ifdef CONFIG_PNP_DEBUG
16 #define DEBUG
17#else
18 #undef DEBUG
19#endif
20
21#include <linux/pnp.h>
22#include "base.h"
23
24static int compare_func(const char *ida, const char *idb)
25{
26 int i;
27 /* we only need to compare the last 4 chars */
28 for (i=3; i<7; i++)
29 {
30 if (ida[i] != 'X' &&
31 idb[i] != 'X' &&
32 toupper(ida[i]) != toupper(idb[i]))
33 return 0;
34 }
35 return 1;
36}
37
38int compare_pnp_id(struct pnp_id *pos, const char *id)
39{
40 if (!pos || !id || (strlen(id) != 7))
41 return 0;
42 if (memcmp(id,"ANYDEVS",7)==0)
43 return 1;
44 while (pos){
45 if (memcmp(pos->id,id,3)==0)
46 if (compare_func(pos->id,id)==1)
47 return 1;
48 pos = pos->next;
49 }
50 return 0;
51}
52
53static const struct pnp_device_id * match_device(struct pnp_driver *drv, struct pnp_dev *dev)
54{
55 const struct pnp_device_id *drv_id = drv->id_table;
56 if (!drv_id)
57 return NULL;
58
59 while (*drv_id->id) {
60 if (compare_pnp_id(dev->id, drv_id->id))
61 return drv_id;
62 drv_id++;
63 }
64 return NULL;
65}
66
67int pnp_device_attach(struct pnp_dev *pnp_dev)
68{
69 spin_lock(&pnp_lock);
70 if(pnp_dev->status != PNP_READY){
71 spin_unlock(&pnp_lock);
72 return -EBUSY;
73 }
74 pnp_dev->status = PNP_ATTACHED;
75 spin_unlock(&pnp_lock);
76 return 0;
77}
78
79void pnp_device_detach(struct pnp_dev *pnp_dev)
80{
81 spin_lock(&pnp_lock);
82 if (pnp_dev->status == PNP_ATTACHED)
83 pnp_dev->status = PNP_READY;
84 spin_unlock(&pnp_lock);
85 pnp_disable_dev(pnp_dev);
86}
87
88static int pnp_device_probe(struct device *dev)
89{
90 int error;
91 struct pnp_driver *pnp_drv;
92 struct pnp_dev *pnp_dev;
93 const struct pnp_device_id *dev_id = NULL;
94 pnp_dev = to_pnp_dev(dev);
95 pnp_drv = to_pnp_driver(dev->driver);
96
97 pnp_dbg("match found with the PnP device '%s' and the driver '%s'", dev->bus_id,pnp_drv->name);
98
99 error = pnp_device_attach(pnp_dev);
100 if (error < 0)
101 return error;
102
103 if (pnp_dev->active == 0) {
104 if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
105 error = pnp_activate_dev(pnp_dev);
106 if (error < 0)
107 return error;
108 }
109 } else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE)
110 == PNP_DRIVER_RES_DISABLE) {
111 error = pnp_disable_dev(pnp_dev);
112 if (error < 0)
113 return error;
114 }
115 error = 0;
116 if (pnp_drv->probe) {
117 dev_id = match_device(pnp_drv, pnp_dev);
118 if (dev_id != NULL)
119 error = pnp_drv->probe(pnp_dev, dev_id);
120 }
121 if (error >= 0){
122 pnp_dev->driver = pnp_drv;
123 error = 0;
124 } else
125 goto fail;
126 return error;
127
128fail:
129 pnp_device_detach(pnp_dev);
130 return error;
131}
132
133static int pnp_device_remove(struct device *dev)
134{
135 struct pnp_dev * pnp_dev = to_pnp_dev(dev);
136 struct pnp_driver * drv = pnp_dev->driver;
137
138 if (drv) {
139 if (drv->remove)
140 drv->remove(pnp_dev);
141 pnp_dev->driver = NULL;
142 }
143 pnp_device_detach(pnp_dev);
144 return 0;
145}
146
147static int pnp_bus_match(struct device *dev, struct device_driver *drv)
148{
149 struct pnp_dev * pnp_dev = to_pnp_dev(dev);
150 struct pnp_driver * pnp_drv = to_pnp_driver(drv);
151 if (match_device(pnp_drv, pnp_dev) == NULL)
152 return 0;
153 return 1;
154}
155
156
157struct bus_type pnp_bus_type = {
158 .name = "pnp",
159 .match = pnp_bus_match,
160};
161
162
163int pnp_register_driver(struct pnp_driver *drv)
164{
165 int count;
166 struct list_head *pos;
167
168 pnp_dbg("the driver '%s' has been registered", drv->name);
169
170 drv->driver.name = drv->name;
171 drv->driver.bus = &pnp_bus_type;
172 drv->driver.probe = pnp_device_probe;
173 drv->driver.remove = pnp_device_remove;
174
175 count = driver_register(&drv->driver);
176
177 /* get the number of initial matches */
178 if (count >= 0){
179 count = 0;
180 list_for_each(pos,&drv->driver.devices){
181 count++;
182 }
183 }
184 return count;
185}
186
187void pnp_unregister_driver(struct pnp_driver *drv)
188{
189 driver_unregister(&drv->driver);
190 pnp_dbg("the driver '%s' has been unregistered", drv->name);
191}
192
193/**
194 * pnp_add_id - adds an EISA id to the specified device
195 * @id: pointer to a pnp_id structure
196 * @dev: pointer to the desired device
197 *
198 */
199
200int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev)
201{
202 struct pnp_id *ptr;
203 if (!id)
204 return -EINVAL;
205 if (!dev)
206 return -EINVAL;
207 id->next = NULL;
208 ptr = dev->id;
209 while (ptr && ptr->next)
210 ptr = ptr->next;
211 if (ptr)
212 ptr->next = id;
213 else
214 dev->id = id;
215 return 0;
216}
217
218EXPORT_SYMBOL(pnp_register_driver);
219EXPORT_SYMBOL(pnp_unregister_driver);
220EXPORT_SYMBOL(pnp_add_id);
221EXPORT_SYMBOL(pnp_device_attach);
222EXPORT_SYMBOL(pnp_device_detach);
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
new file mode 100644
index 000000000000..53fac8ba5d5c
--- /dev/null
+++ b/drivers/pnp/interface.c
@@ -0,0 +1,468 @@
1/*
2 * interface.c - contains everything related to the user interface
3 *
4 * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@suse.cz>
5 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
6 *
7 */
8
9#include <linux/pnp.h>
10#include <linux/string.h>
11#include <linux/errno.h>
12#include <linux/list.h>
13#include <linux/types.h>
14#include <linux/stat.h>
15#include <linux/ctype.h>
16#include <linux/slab.h>
17#include <asm/uaccess.h>
18
19#include "base.h"
20
21struct pnp_info_buffer {
22 char *buffer; /* pointer to begin of buffer */
23 char *curr; /* current position in buffer */
24 unsigned long size; /* current size */
25 unsigned long len; /* total length of buffer */
26 int stop; /* stop flag */
27 int error; /* error code */
28};
29
30typedef struct pnp_info_buffer pnp_info_buffer_t;
31
32static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt,...)
33{
34 va_list args;
35 int res;
36
37 if (buffer->stop || buffer->error)
38 return 0;
39 va_start(args, fmt);
40 res = vsnprintf(buffer->curr, buffer->len - buffer->size, fmt, args);
41 va_end(args);
42 if (buffer->size + res >= buffer->len) {
43 buffer->stop = 1;
44 return 0;
45 }
46 buffer->curr += res;
47 buffer->size += res;
48 return res;
49}
50
51static void pnp_print_port(pnp_info_buffer_t *buffer, char *space, struct pnp_port *port)
52{
53 pnp_printf(buffer, "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
54 space, port->min, port->max, port->align ? (port->align-1) : 0, port->size,
55 port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
56}
57
58static void pnp_print_irq(pnp_info_buffer_t *buffer, char *space, struct pnp_irq *irq)
59{
60 int first = 1, i;
61
62 pnp_printf(buffer, "%sirq ", space);
63 for (i = 0; i < PNP_IRQ_NR; i++)
64 if (test_bit(i, irq->map)) {
65 if (!first) {
66 pnp_printf(buffer, ",");
67 } else {
68 first = 0;
69 }
70 if (i == 2 || i == 9)
71 pnp_printf(buffer, "2/9");
72 else
73 pnp_printf(buffer, "%i", i);
74 }
75 if (bitmap_empty(irq->map, PNP_IRQ_NR))
76 pnp_printf(buffer, "<none>");
77 if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
78 pnp_printf(buffer, " High-Edge");
79 if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
80 pnp_printf(buffer, " Low-Edge");
81 if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)
82 pnp_printf(buffer, " High-Level");
83 if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
84 pnp_printf(buffer, " Low-Level");
85 pnp_printf(buffer, "\n");
86}
87
88static void pnp_print_dma(pnp_info_buffer_t *buffer, char *space, struct pnp_dma *dma)
89{
90 int first = 1, i;
91 char *s;
92
93 pnp_printf(buffer, "%sdma ", space);
94 for (i = 0; i < 8; i++)
95 if (dma->map & (1<<i)) {
96 if (!first) {
97 pnp_printf(buffer, ",");
98 } else {
99 first = 0;
100 }
101 pnp_printf(buffer, "%i", i);
102 }
103 if (!dma->map)
104 pnp_printf(buffer, "<none>");
105 switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
106 case IORESOURCE_DMA_8BIT:
107 s = "8-bit";
108 break;
109 case IORESOURCE_DMA_8AND16BIT:
110 s = "8-bit&16-bit";
111 break;
112 default:
113 s = "16-bit";
114 }
115 pnp_printf(buffer, " %s", s);
116 if (dma->flags & IORESOURCE_DMA_MASTER)
117 pnp_printf(buffer, " master");
118 if (dma->flags & IORESOURCE_DMA_BYTE)
119 pnp_printf(buffer, " byte-count");
120 if (dma->flags & IORESOURCE_DMA_WORD)
121 pnp_printf(buffer, " word-count");
122 switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
123 case IORESOURCE_DMA_TYPEA:
124 s = "type-A";
125 break;
126 case IORESOURCE_DMA_TYPEB:
127 s = "type-B";
128 break;
129 case IORESOURCE_DMA_TYPEF:
130 s = "type-F";
131 break;
132 default:
133 s = "compatible";
134 break;
135 }
136 pnp_printf(buffer, " %s\n", s);
137}
138
139static void pnp_print_mem(pnp_info_buffer_t *buffer, char *space, struct pnp_mem *mem)
140{
141 char *s;
142
143 pnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
144 space, mem->min, mem->max, mem->align, mem->size);
145 if (mem->flags & IORESOURCE_MEM_WRITEABLE)
146 pnp_printf(buffer, ", writeable");
147 if (mem->flags & IORESOURCE_MEM_CACHEABLE)
148 pnp_printf(buffer, ", cacheable");
149 if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
150 pnp_printf(buffer, ", range-length");
151 if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
152 pnp_printf(buffer, ", shadowable");
153 if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)
154 pnp_printf(buffer, ", expansion ROM");
155 switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
156 case IORESOURCE_MEM_8BIT:
157 s = "8-bit";
158 break;
159 case IORESOURCE_MEM_8AND16BIT:
160 s = "8-bit&16-bit";
161 break;
162 case IORESOURCE_MEM_32BIT:
163 s = "32-bit";
164 break;
165 default:
166 s = "16-bit";
167 }
168 pnp_printf(buffer, ", %s\n", s);
169}
170
171static void pnp_print_option(pnp_info_buffer_t *buffer, char *space,
172 struct pnp_option *option, int dep)
173{
174 char *s;
175 struct pnp_port *port;
176 struct pnp_irq *irq;
177 struct pnp_dma *dma;
178 struct pnp_mem *mem;
179
180 if (dep) {
181 switch (option->priority) {
182 case PNP_RES_PRIORITY_PREFERRED:
183 s = "preferred";
184 break;
185 case PNP_RES_PRIORITY_ACCEPTABLE:
186 s = "acceptable";
187 break;
188 case PNP_RES_PRIORITY_FUNCTIONAL:
189 s = "functional";
190 break;
191 default:
192 s = "invalid";
193 }
194 pnp_printf(buffer, "Dependent: %02i - Priority %s\n",dep, s);
195 }
196
197 for (port = option->port; port; port = port->next)
198 pnp_print_port(buffer, space, port);
199 for (irq = option->irq; irq; irq = irq->next)
200 pnp_print_irq(buffer, space, irq);
201 for (dma = option->dma; dma; dma = dma->next)
202 pnp_print_dma(buffer, space, dma);
203 for (mem = option->mem; mem; mem = mem->next)
204 pnp_print_mem(buffer, space, mem);
205}
206
207
208static ssize_t pnp_show_options(struct device *dmdev, char *buf)
209{
210 struct pnp_dev *dev = to_pnp_dev(dmdev);
211 struct pnp_option * independent = dev->independent;
212 struct pnp_option * dependent = dev->dependent;
213 int ret, dep = 1;
214
215 pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
216 pnp_alloc(sizeof(pnp_info_buffer_t));
217 if (!buffer)
218 return -ENOMEM;
219
220 buffer->len = PAGE_SIZE;
221 buffer->buffer = buf;
222 buffer->curr = buffer->buffer;
223 if (independent)
224 pnp_print_option(buffer, "", independent, 0);
225
226 while (dependent){
227 pnp_print_option(buffer, " ", dependent, dep);
228 dependent = dependent->next;
229 dep++;
230 }
231 ret = (buffer->curr - buf);
232 kfree(buffer);
233 return ret;
234}
235
236static DEVICE_ATTR(options,S_IRUGO,pnp_show_options,NULL);
237
238
239static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf)
240{
241 struct pnp_dev *dev = to_pnp_dev(dmdev);
242 int i, ret;
243 pnp_info_buffer_t *buffer;
244
245 if (!dev)
246 return -EINVAL;
247
248 buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t));
249 if (!buffer)
250 return -ENOMEM;
251 buffer->len = PAGE_SIZE;
252 buffer->buffer = buf;
253 buffer->curr = buffer->buffer;
254
255 pnp_printf(buffer,"state = ");
256 if (dev->active)
257 pnp_printf(buffer,"active\n");
258 else
259 pnp_printf(buffer,"disabled\n");
260
261 for (i = 0; i < PNP_MAX_PORT; i++) {
262 if (pnp_port_valid(dev, i)) {
263 pnp_printf(buffer,"io");
264 if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
265 pnp_printf(buffer," disabled\n");
266 else
267 pnp_printf(buffer," 0x%lx-0x%lx\n",
268 pnp_port_start(dev, i),
269 pnp_port_end(dev, i));
270 }
271 }
272 for (i = 0; i < PNP_MAX_MEM; i++) {
273 if (pnp_mem_valid(dev, i)) {
274 pnp_printf(buffer,"mem");
275 if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
276 pnp_printf(buffer," disabled\n");
277 else
278 pnp_printf(buffer," 0x%lx-0x%lx\n",
279 pnp_mem_start(dev, i),
280 pnp_mem_end(dev, i));
281 }
282 }
283 for (i = 0; i < PNP_MAX_IRQ; i++) {
284 if (pnp_irq_valid(dev, i)) {
285 pnp_printf(buffer,"irq");
286 if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
287 pnp_printf(buffer," disabled\n");
288 else
289 pnp_printf(buffer," %ld\n",
290 pnp_irq(dev, i));
291 }
292 }
293 for (i = 0; i < PNP_MAX_DMA; i++) {
294 if (pnp_dma_valid(dev, i)) {
295 pnp_printf(buffer,"dma");
296 if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
297 pnp_printf(buffer," disabled\n");
298 else
299 pnp_printf(buffer," %ld\n",
300 pnp_dma(dev, i));
301 }
302 }
303 ret = (buffer->curr - buf);
304 kfree(buffer);
305 return ret;
306}
307
308extern struct semaphore pnp_res_mutex;
309
310static ssize_t
311pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count)
312{
313 struct pnp_dev *dev = to_pnp_dev(dmdev);
314 char *buf = (void *)ubuf;
315 int retval = 0;
316
317 if (dev->status & PNP_ATTACHED) {
318 retval = -EBUSY;
319 pnp_info("Device %s cannot be configured because it is in use.", dev->dev.bus_id);
320 goto done;
321 }
322
323 while (isspace(*buf))
324 ++buf;
325 if (!strnicmp(buf,"disable",7)) {
326 retval = pnp_disable_dev(dev);
327 goto done;
328 }
329 if (!strnicmp(buf,"activate",8)) {
330 retval = pnp_activate_dev(dev);
331 goto done;
332 }
333 if (!strnicmp(buf,"fill",4)) {
334 if (dev->active)
335 goto done;
336 retval = pnp_auto_config_dev(dev);
337 goto done;
338 }
339 if (!strnicmp(buf,"auto",4)) {
340 if (dev->active)
341 goto done;
342 pnp_init_resource_table(&dev->res);
343 retval = pnp_auto_config_dev(dev);
344 goto done;
345 }
346 if (!strnicmp(buf,"clear",5)) {
347 if (dev->active)
348 goto done;
349 pnp_init_resource_table(&dev->res);
350 goto done;
351 }
352 if (!strnicmp(buf,"get",3)) {
353 down(&pnp_res_mutex);
354 if (pnp_can_read(dev))
355 dev->protocol->get(dev, &dev->res);
356 up(&pnp_res_mutex);
357 goto done;
358 }
359 if (!strnicmp(buf,"set",3)) {
360 int nport = 0, nmem = 0, nirq = 0, ndma = 0;
361 if (dev->active)
362 goto done;
363 buf += 3;
364 pnp_init_resource_table(&dev->res);
365 down(&pnp_res_mutex);
366 while (1) {
367 while (isspace(*buf))
368 ++buf;
369 if (!strnicmp(buf,"io",2)) {
370 buf += 2;
371 while (isspace(*buf))
372 ++buf;
373 dev->res.port_resource[nport].start = simple_strtoul(buf,&buf,0);
374 while (isspace(*buf))
375 ++buf;
376 if(*buf == '-') {
377 buf += 1;
378 while (isspace(*buf))
379 ++buf;
380 dev->res.port_resource[nport].end = simple_strtoul(buf,&buf,0);
381 } else
382 dev->res.port_resource[nport].end = dev->res.port_resource[nport].start;
383 dev->res.port_resource[nport].flags = IORESOURCE_IO;
384 nport++;
385 if (nport >= PNP_MAX_PORT)
386 break;
387 continue;
388 }
389 if (!strnicmp(buf,"mem",3)) {
390 buf += 3;
391 while (isspace(*buf))
392 ++buf;
393 dev->res.mem_resource[nmem].start = simple_strtoul(buf,&buf,0);
394 while (isspace(*buf))
395 ++buf;
396 if(*buf == '-') {
397 buf += 1;
398 while (isspace(*buf))
399 ++buf;
400 dev->res.mem_resource[nmem].end = simple_strtoul(buf,&buf,0);
401 } else
402 dev->res.mem_resource[nmem].end = dev->res.mem_resource[nmem].start;
403 dev->res.mem_resource[nmem].flags = IORESOURCE_MEM;
404 nmem++;
405 if (nmem >= PNP_MAX_MEM)
406 break;
407 continue;
408 }
409 if (!strnicmp(buf,"irq",3)) {
410 buf += 3;
411 while (isspace(*buf))
412 ++buf;
413 dev->res.irq_resource[nirq].start =
414 dev->res.irq_resource[nirq].end = simple_strtoul(buf,&buf,0);
415 dev->res.irq_resource[nirq].flags = IORESOURCE_IRQ;
416 nirq++;
417 if (nirq >= PNP_MAX_IRQ)
418 break;
419 continue;
420 }
421 if (!strnicmp(buf,"dma",3)) {
422 buf += 3;
423 while (isspace(*buf))
424 ++buf;
425 dev->res.dma_resource[ndma].start =
426 dev->res.dma_resource[ndma].end = simple_strtoul(buf,&buf,0);
427 dev->res.dma_resource[ndma].flags = IORESOURCE_DMA;
428 ndma++;
429 if (ndma >= PNP_MAX_DMA)
430 break;
431 continue;
432 }
433 break;
434 }
435 up(&pnp_res_mutex);
436 goto done;
437 }
438 done:
439 if (retval < 0)
440 return retval;
441 return count;
442}
443
444static DEVICE_ATTR(resources,S_IRUGO | S_IWUSR,
445 pnp_show_current_resources,pnp_set_current_resources);
446
447static ssize_t pnp_show_current_ids(struct device *dmdev, char *buf)
448{
449 char *str = buf;
450 struct pnp_dev *dev = to_pnp_dev(dmdev);
451 struct pnp_id * pos = dev->id;
452
453 while (pos) {
454 str += sprintf(str,"%s\n", pos->id);
455 pos = pos->next;
456 }
457 return (str - buf);
458}
459
460static DEVICE_ATTR(id,S_IRUGO,pnp_show_current_ids,NULL);
461
462int pnp_interface_attach_device(struct pnp_dev *dev)
463{
464 device_create_file(&dev->dev,&dev_attr_options);
465 device_create_file(&dev->dev,&dev_attr_resources);
466 device_create_file(&dev->dev,&dev_attr_id);
467 return 0;
468}
diff --git a/drivers/pnp/isapnp/Kconfig b/drivers/pnp/isapnp/Kconfig
new file mode 100644
index 000000000000..578651eeb4b0
--- /dev/null
+++ b/drivers/pnp/isapnp/Kconfig
@@ -0,0 +1,11 @@
1#
2# ISA Plug and Play configuration
3#
4config ISAPNP
5 bool "ISA Plug and Play support"
6 depends on PNP && ISA
7 help
8 Say Y here if you would like support for ISA Plug and Play devices.
9 Some information is in <file:Documentation/isapnp.txt>.
10
11 If unsure, say Y.
diff --git a/drivers/pnp/isapnp/Makefile b/drivers/pnp/isapnp/Makefile
new file mode 100644
index 000000000000..cac18bbfb817
--- /dev/null
+++ b/drivers/pnp/isapnp/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the kernel ISAPNP driver.
3#
4
5isapnp-proc-$(CONFIG_PROC_FS) = proc.o
6
7obj-y := core.o compat.o $(isapnp-proc-y)
diff --git a/drivers/pnp/isapnp/compat.c b/drivers/pnp/isapnp/compat.c
new file mode 100644
index 000000000000..3ff7e76b33bd
--- /dev/null
+++ b/drivers/pnp/isapnp/compat.c
@@ -0,0 +1,91 @@
1/*
2 * compat.c - A series of functions to make it easier to convert drivers that use
3 * the old isapnp APIs. If possible use the new APIs instead.
4 *
5 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
6 *
7 */
8
9/* TODO: see if more isapnp functions are needed here */
10
11#include <linux/config.h>
12#include <linux/module.h>
13#include <linux/isapnp.h>
14#include <linux/string.h>
15
16static void pnp_convert_id(char *buf, unsigned short vendor, unsigned short device)
17{
18 sprintf(buf, "%c%c%c%x%x%x%x",
19 'A' + ((vendor >> 2) & 0x3f) - 1,
20 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
21 'A' + ((vendor >> 8) & 0x1f) - 1,
22 (device >> 4) & 0x0f,
23 device & 0x0f,
24 (device >> 12) & 0x0f,
25 (device >> 8) & 0x0f);
26}
27
28struct pnp_card *pnp_find_card(unsigned short vendor,
29 unsigned short device,
30 struct pnp_card *from)
31{
32 char id[8];
33 char any[8];
34 struct list_head *list;
35 pnp_convert_id(id, vendor, device);
36 pnp_convert_id(any, ISAPNP_ANY_ID, ISAPNP_ANY_ID);
37
38 list = from ? from->global_list.next : pnp_cards.next;
39
40 while (list != &pnp_cards) {
41 struct pnp_card *card = global_to_pnp_card(list);
42 if (compare_pnp_id(card->id,id) || (memcmp(id,any,7)==0))
43 return card;
44 list = list->next;
45 }
46 return NULL;
47}
48
49struct pnp_dev *pnp_find_dev(struct pnp_card *card,
50 unsigned short vendor,
51 unsigned short function,
52 struct pnp_dev *from)
53{
54 char id[8];
55 char any[8];
56 pnp_convert_id(id, vendor, function);
57 pnp_convert_id(any, ISAPNP_ANY_ID, ISAPNP_ANY_ID);
58 if (card == NULL) { /* look for a logical device from all cards */
59 struct list_head *list;
60
61 list = pnp_global.next;
62 if (from)
63 list = from->global_list.next;
64
65 while (list != &pnp_global) {
66 struct pnp_dev *dev = global_to_pnp_dev(list);
67 if (compare_pnp_id(dev->id,id) || (memcmp(id,any,7)==0))
68 return dev;
69 list = list->next;
70 }
71 } else {
72 struct list_head *list;
73
74 list = card->devices.next;
75 if (from) {
76 list = from->card_list.next;
77 if (from->card != card) /* something is wrong */
78 return NULL;
79 }
80 while (list != &card->devices) {
81 struct pnp_dev *dev = card_to_pnp_dev(list);
82 if (compare_pnp_id(dev->id,id))
83 return dev;
84 list = list->next;
85 }
86 }
87 return NULL;
88}
89
90EXPORT_SYMBOL(pnp_find_card);
91EXPORT_SYMBOL(pnp_find_dev);
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
new file mode 100644
index 000000000000..82c5edd5b9ee
--- /dev/null
+++ b/drivers/pnp/isapnp/core.c
@@ -0,0 +1,1156 @@
1/*
2 * ISA Plug & Play support
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * Changelog:
21 * 2000-01-01 Added quirks handling for buggy hardware
22 * Peter Denison <peterd@pnd-pc.demon.co.uk>
23 * 2000-06-14 Added isapnp_probe_devs() and isapnp_activate_dev()
24 * Christoph Hellwig <hch@infradead.org>
25 * 2001-06-03 Added release_region calls to correspond with
26 * request_region calls when a failure occurs. Also
27 * added KERN_* constants to printk() calls.
28 * 2001-11-07 Added isapnp_{,un}register_driver calls along the lines
29 * of the pci driver interface
30 * Kai Germaschewski <kai.germaschewski@gmx.de>
31 * 2002-06-06 Made the use of dma channel 0 configurable
32 * Gerald Teschl <gerald.teschl@univie.ac.at>
33 * 2002-10-06 Ported to PnP Layer - Adam Belay <ambx1@neo.rr.com>
34 * 2003-08-11 Resource Management Updates - Adam Belay <ambx1@neo.rr.com>
35 */
36
37#include <linux/config.h>
38#include <linux/module.h>
39#include <linux/kernel.h>
40#include <linux/errno.h>
41#include <linux/slab.h>
42#include <linux/delay.h>
43#include <linux/init.h>
44#include <linux/isapnp.h>
45#include <asm/io.h>
46
47#if 0
48#define ISAPNP_REGION_OK
49#endif
50#if 0
51#define ISAPNP_DEBUG
52#endif
53
54int isapnp_disable; /* Disable ISA PnP */
55static int isapnp_rdp; /* Read Data Port */
56static int isapnp_reset = 1; /* reset all PnP cards (deactivate) */
57static int isapnp_verbose = 1; /* verbose mode */
58
59MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
60MODULE_DESCRIPTION("Generic ISA Plug & Play support");
61module_param(isapnp_disable, int, 0);
62MODULE_PARM_DESC(isapnp_disable, "ISA Plug & Play disable");
63module_param(isapnp_rdp, int, 0);
64MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port");
65module_param(isapnp_reset, int, 0);
66MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards");
67module_param(isapnp_verbose, int, 0);
68MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
69MODULE_LICENSE("GPL");
70
71#define _PIDXR 0x279
72#define _PNPWRP 0xa79
73
74/* short tags */
75#define _STAG_PNPVERNO 0x01
76#define _STAG_LOGDEVID 0x02
77#define _STAG_COMPATDEVID 0x03
78#define _STAG_IRQ 0x04
79#define _STAG_DMA 0x05
80#define _STAG_STARTDEP 0x06
81#define _STAG_ENDDEP 0x07
82#define _STAG_IOPORT 0x08
83#define _STAG_FIXEDIO 0x09
84#define _STAG_VENDOR 0x0e
85#define _STAG_END 0x0f
86/* long tags */
87#define _LTAG_MEMRANGE 0x81
88#define _LTAG_ANSISTR 0x82
89#define _LTAG_UNICODESTR 0x83
90#define _LTAG_VENDOR 0x84
91#define _LTAG_MEM32RANGE 0x85
92#define _LTAG_FIXEDMEM32RANGE 0x86
93
94static unsigned char isapnp_checksum_value;
95static DECLARE_MUTEX(isapnp_cfg_mutex);
96static int isapnp_detected;
97static int isapnp_csn_count;
98
99/* some prototypes */
100
101static inline void write_data(unsigned char x)
102{
103 outb(x, _PNPWRP);
104}
105
106static inline void write_address(unsigned char x)
107{
108 outb(x, _PIDXR);
109 udelay(20);
110}
111
112static inline unsigned char read_data(void)
113{
114 unsigned char val = inb(isapnp_rdp);
115 return val;
116}
117
118unsigned char isapnp_read_byte(unsigned char idx)
119{
120 write_address(idx);
121 return read_data();
122}
123
124static unsigned short isapnp_read_word(unsigned char idx)
125{
126 unsigned short val;
127
128 val = isapnp_read_byte(idx);
129 val = (val << 8) + isapnp_read_byte(idx+1);
130 return val;
131}
132
133void isapnp_write_byte(unsigned char idx, unsigned char val)
134{
135 write_address(idx);
136 write_data(val);
137}
138
139static void isapnp_write_word(unsigned char idx, unsigned short val)
140{
141 isapnp_write_byte(idx, val >> 8);
142 isapnp_write_byte(idx+1, val);
143}
144
145static void *isapnp_alloc(long size)
146{
147 void *result;
148
149 result = kmalloc(size, GFP_KERNEL);
150 if (!result)
151 return NULL;
152 memset(result, 0, size);
153 return result;
154}
155
156static void isapnp_key(void)
157{
158 unsigned char code = 0x6a, msb;
159 int i;
160
161 mdelay(1);
162 write_address(0x00);
163 write_address(0x00);
164
165 write_address(code);
166
167 for (i = 1; i < 32; i++) {
168 msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
169 code = (code >> 1) | msb;
170 write_address(code);
171 }
172}
173
174/* place all pnp cards in wait-for-key state */
175static void isapnp_wait(void)
176{
177 isapnp_write_byte(0x02, 0x02);
178}
179
180static void isapnp_wake(unsigned char csn)
181{
182 isapnp_write_byte(0x03, csn);
183}
184
185static void isapnp_device(unsigned char logdev)
186{
187 isapnp_write_byte(0x07, logdev);
188}
189
190static void isapnp_activate(unsigned char logdev)
191{
192 isapnp_device(logdev);
193 isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 1);
194 udelay(250);
195}
196
197static void isapnp_deactivate(unsigned char logdev)
198{
199 isapnp_device(logdev);
200 isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 0);
201 udelay(500);
202}
203
204static void __init isapnp_peek(unsigned char *data, int bytes)
205{
206 int i, j;
207 unsigned char d=0;
208
209 for (i = 1; i <= bytes; i++) {
210 for (j = 0; j < 20; j++) {
211 d = isapnp_read_byte(0x05);
212 if (d & 1)
213 break;
214 udelay(100);
215 }
216 if (!(d & 1)) {
217 if (data != NULL)
218 *data++ = 0xff;
219 continue;
220 }
221 d = isapnp_read_byte(0x04); /* PRESDI */
222 isapnp_checksum_value += d;
223 if (data != NULL)
224 *data++ = d;
225 }
226}
227
228#define RDP_STEP 32 /* minimum is 4 */
229
230static int isapnp_next_rdp(void)
231{
232 int rdp = isapnp_rdp;
233 static int old_rdp = 0;
234
235 if(old_rdp)
236 {
237 release_region(old_rdp, 1);
238 old_rdp = 0;
239 }
240 while (rdp <= 0x3ff) {
241 /*
242 * We cannot use NE2000 probe spaces for ISAPnP or we
243 * will lock up machines.
244 */
245 if ((rdp < 0x280 || rdp > 0x380) && request_region(rdp, 1, "ISAPnP"))
246 {
247 isapnp_rdp = rdp;
248 old_rdp = rdp;
249 return 0;
250 }
251 rdp += RDP_STEP;
252 }
253 return -1;
254}
255
256/* Set read port address */
257static inline void isapnp_set_rdp(void)
258{
259 isapnp_write_byte(0x00, isapnp_rdp >> 2);
260 udelay(100);
261}
262
263/*
264 * Perform an isolation. The port selection code now tries to avoid
265 * "dangerous to read" ports.
266 */
267
268static int __init isapnp_isolate_rdp_select(void)
269{
270 isapnp_wait();
271 isapnp_key();
272
273 /* Control: reset CSN and conditionally everything else too */
274 isapnp_write_byte(0x02, isapnp_reset ? 0x05 : 0x04);
275 mdelay(2);
276
277 isapnp_wait();
278 isapnp_key();
279 isapnp_wake(0x00);
280
281 if (isapnp_next_rdp() < 0) {
282 isapnp_wait();
283 return -1;
284 }
285
286 isapnp_set_rdp();
287 udelay(1000);
288 write_address(0x01);
289 udelay(1000);
290 return 0;
291}
292
293/*
294 * Isolate (assign uniqued CSN) to all ISA PnP devices.
295 */
296
297static int __init isapnp_isolate(void)
298{
299 unsigned char checksum = 0x6a;
300 unsigned char chksum = 0x00;
301 unsigned char bit = 0x00;
302 int data;
303 int csn = 0;
304 int i;
305 int iteration = 1;
306
307 isapnp_rdp = 0x213;
308 if (isapnp_isolate_rdp_select() < 0)
309 return -1;
310
311 while (1) {
312 for (i = 1; i <= 64; i++) {
313 data = read_data() << 8;
314 udelay(250);
315 data = data | read_data();
316 udelay(250);
317 if (data == 0x55aa)
318 bit = 0x01;
319 checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
320 bit = 0x00;
321 }
322 for (i = 65; i <= 72; i++) {
323 data = read_data() << 8;
324 udelay(250);
325 data = data | read_data();
326 udelay(250);
327 if (data == 0x55aa)
328 chksum |= (1 << (i - 65));
329 }
330 if (checksum != 0x00 && checksum == chksum) {
331 csn++;
332
333 isapnp_write_byte(0x06, csn);
334 udelay(250);
335 iteration++;
336 isapnp_wake(0x00);
337 isapnp_set_rdp();
338 udelay(1000);
339 write_address(0x01);
340 udelay(1000);
341 goto __next;
342 }
343 if (iteration == 1) {
344 isapnp_rdp += RDP_STEP;
345 if (isapnp_isolate_rdp_select() < 0)
346 return -1;
347 } else if (iteration > 1) {
348 break;
349 }
350 __next:
351 if (csn == 255)
352 break;
353 checksum = 0x6a;
354 chksum = 0x00;
355 bit = 0x00;
356 }
357 isapnp_wait();
358 isapnp_csn_count = csn;
359 return csn;
360}
361
362/*
363 * Read one tag from stream.
364 */
365
366static int __init isapnp_read_tag(unsigned char *type, unsigned short *size)
367{
368 unsigned char tag, tmp[2];
369
370 isapnp_peek(&tag, 1);
371 if (tag == 0) /* invalid tag */
372 return -1;
373 if (tag & 0x80) { /* large item */
374 *type = tag;
375 isapnp_peek(tmp, 2);
376 *size = (tmp[1] << 8) | tmp[0];
377 } else {
378 *type = (tag >> 3) & 0x0f;
379 *size = tag & 0x07;
380 }
381#if 0
382 printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size);
383#endif
384 if (type == 0) /* wrong type */
385 return -1;
386 if (*type == 0xff && *size == 0xffff) /* probably invalid data */
387 return -1;
388 return 0;
389}
390
391/*
392 * Skip specified number of bytes from stream.
393 */
394
395static void __init isapnp_skip_bytes(int count)
396{
397 isapnp_peek(NULL, count);
398}
399
400/*
401 * Parse EISA id.
402 */
403
404static void isapnp_parse_id(struct pnp_dev * dev, unsigned short vendor, unsigned short device)
405{
406 struct pnp_id * id;
407 if (!dev)
408 return;
409 id = isapnp_alloc(sizeof(struct pnp_id));
410 if (!id)
411 return;
412 sprintf(id->id, "%c%c%c%x%x%x%x",
413 'A' + ((vendor >> 2) & 0x3f) - 1,
414 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
415 'A' + ((vendor >> 8) & 0x1f) - 1,
416 (device >> 4) & 0x0f,
417 device & 0x0f,
418 (device >> 12) & 0x0f,
419 (device >> 8) & 0x0f);
420 pnp_add_id(id, dev);
421}
422
423/*
424 * Parse logical device tag.
425 */
426
427static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int size, int number)
428{
429 unsigned char tmp[6];
430 struct pnp_dev *dev;
431
432 isapnp_peek(tmp, size);
433 dev = isapnp_alloc(sizeof(struct pnp_dev));
434 if (!dev)
435 return NULL;
436 dev->number = number;
437 isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]);
438 dev->regs = tmp[4];
439 dev->card = card;
440 if (size > 5)
441 dev->regs |= tmp[5] << 8;
442 dev->protocol = &isapnp_protocol;
443 dev->capabilities |= PNP_CONFIGURABLE;
444 dev->capabilities |= PNP_READ;
445 dev->capabilities |= PNP_WRITE;
446 dev->capabilities |= PNP_DISABLE;
447 pnp_init_resource_table(&dev->res);
448 return dev;
449}
450
451
452/*
453 * Add IRQ resource to resources list.
454 */
455
456static void __init isapnp_parse_irq_resource(struct pnp_option *option,
457 int size)
458{
459 unsigned char tmp[3];
460 struct pnp_irq *irq;
461 unsigned long bits;
462
463 isapnp_peek(tmp, size);
464 irq = isapnp_alloc(sizeof(struct pnp_irq));
465 if (!irq)
466 return;
467 bits = (tmp[1] << 8) | tmp[0];
468 bitmap_copy(irq->map, &bits, 16);
469 if (size > 2)
470 irq->flags = tmp[2];
471 else
472 irq->flags = IORESOURCE_IRQ_HIGHEDGE;
473 pnp_register_irq_resource(option, irq);
474 return;
475}
476
477/*
478 * Add DMA resource to resources list.
479 */
480
481static void __init isapnp_parse_dma_resource(struct pnp_option *option,
482 int size)
483{
484 unsigned char tmp[2];
485 struct pnp_dma *dma;
486
487 isapnp_peek(tmp, size);
488 dma = isapnp_alloc(sizeof(struct pnp_dma));
489 if (!dma)
490 return;
491 dma->map = tmp[0];
492 dma->flags = tmp[1];
493 pnp_register_dma_resource(option, dma);
494 return;
495}
496
497/*
498 * Add port resource to resources list.
499 */
500
501static void __init isapnp_parse_port_resource(struct pnp_option *option,
502 int size)
503{
504 unsigned char tmp[7];
505 struct pnp_port *port;
506
507 isapnp_peek(tmp, size);
508 port = isapnp_alloc(sizeof(struct pnp_port));
509 if (!port)
510 return;
511 port->min = (tmp[2] << 8) | tmp[1];
512 port->max = (tmp[4] << 8) | tmp[3];
513 port->align = tmp[5];
514 port->size = tmp[6];
515 port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;
516 pnp_register_port_resource(option,port);
517 return;
518}
519
520/*
521 * Add fixed port resource to resources list.
522 */
523
524static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
525 int size)
526{
527 unsigned char tmp[3];
528 struct pnp_port *port;
529
530 isapnp_peek(tmp, size);
531 port = isapnp_alloc(sizeof(struct pnp_port));
532 if (!port)
533 return;
534 port->min = port->max = (tmp[1] << 8) | tmp[0];
535 port->size = tmp[2];
536 port->align = 0;
537 port->flags = PNP_PORT_FLAG_FIXED;
538 pnp_register_port_resource(option,port);
539 return;
540}
541
542/*
543 * Add memory resource to resources list.
544 */
545
546static void __init isapnp_parse_mem_resource(struct pnp_option *option,
547 int size)
548{
549 unsigned char tmp[9];
550 struct pnp_mem *mem;
551
552 isapnp_peek(tmp, size);
553 mem = isapnp_alloc(sizeof(struct pnp_mem));
554 if (!mem)
555 return;
556 mem->min = ((tmp[2] << 8) | tmp[1]) << 8;
557 mem->max = ((tmp[4] << 8) | tmp[3]) << 8;
558 mem->align = (tmp[6] << 8) | tmp[5];
559 mem->size = ((tmp[8] << 8) | tmp[7]) << 8;
560 mem->flags = tmp[0];
561 pnp_register_mem_resource(option,mem);
562 return;
563}
564
565/*
566 * Add 32-bit memory resource to resources list.
567 */
568
569static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
570 int size)
571{
572 unsigned char tmp[17];
573 struct pnp_mem *mem;
574
575 isapnp_peek(tmp, size);
576 mem = isapnp_alloc(sizeof(struct pnp_mem));
577 if (!mem)
578 return;
579 mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
580 mem->max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
581 mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
582 mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
583 mem->flags = tmp[0];
584 pnp_register_mem_resource(option,mem);
585}
586
587/*
588 * Add 32-bit fixed memory resource to resources list.
589 */
590
591static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
592 int size)
593{
594 unsigned char tmp[9];
595 struct pnp_mem *mem;
596
597 isapnp_peek(tmp, size);
598 mem = isapnp_alloc(sizeof(struct pnp_mem));
599 if (!mem)
600 return;
601 mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
602 mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
603 mem->align = 0;
604 mem->flags = tmp[0];
605 pnp_register_mem_resource(option,mem);
606}
607
608/*
609 * Parse card name for ISA PnP device.
610 */
611
612static void __init
613isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
614{
615 if (name[0] == '\0') {
616 unsigned short size1 = *size >= name_max ? (name_max - 1) : *size;
617 isapnp_peek(name, size1);
618 name[size1] = '\0';
619 *size -= size1;
620
621 /* clean whitespace from end of string */
622 while (size1 > 0 && name[--size1] == ' ')
623 name[size1] = '\0';
624 }
625}
626
627/*
628 * Parse resource map for logical device.
629 */
630
631static int __init isapnp_create_device(struct pnp_card *card,
632 unsigned short size)
633{
634 int number = 0, skip = 0, priority = 0, compat = 0;
635 unsigned char type, tmp[17];
636 struct pnp_option *option;
637 struct pnp_dev *dev;
638 if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
639 return 1;
640 option = pnp_register_independent_option(dev);
641 if (!option) {
642 kfree(dev);
643 return 1;
644 }
645 pnp_add_card_device(card,dev);
646
647 while (1) {
648 if (isapnp_read_tag(&type, &size)<0)
649 return 1;
650 if (skip && type != _STAG_LOGDEVID && type != _STAG_END)
651 goto __skip;
652 switch (type) {
653 case _STAG_LOGDEVID:
654 if (size >= 5 && size <= 6) {
655 if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
656 return 1;
657 size = 0;
658 skip = 0;
659 option = pnp_register_independent_option(dev);
660 if (!option)
661 return 1;
662 pnp_add_card_device(card,dev);
663 } else {
664 skip = 1;
665 }
666 priority = 0;
667 compat = 0;
668 break;
669 case _STAG_COMPATDEVID:
670 if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) {
671 isapnp_peek(tmp, 4);
672 isapnp_parse_id(dev,(tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]);
673 compat++;
674 size = 0;
675 }
676 break;
677 case _STAG_IRQ:
678 if (size < 2 || size > 3)
679 goto __skip;
680 isapnp_parse_irq_resource(option, size);
681 size = 0;
682 break;
683 case _STAG_DMA:
684 if (size != 2)
685 goto __skip;
686 isapnp_parse_dma_resource(option, size);
687 size = 0;
688 break;
689 case _STAG_STARTDEP:
690 if (size > 1)
691 goto __skip;
692 priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
693 if (size > 0) {
694 isapnp_peek(tmp, size);
695 priority = 0x100 | tmp[0];
696 size = 0;
697 }
698 option = pnp_register_dependent_option(dev,priority);
699 if (!option)
700 return 1;
701 break;
702 case _STAG_ENDDEP:
703 if (size != 0)
704 goto __skip;
705 priority = 0;
706 break;
707 case _STAG_IOPORT:
708 if (size != 7)
709 goto __skip;
710 isapnp_parse_port_resource(option, size);
711 size = 0;
712 break;
713 case _STAG_FIXEDIO:
714 if (size != 3)
715 goto __skip;
716 isapnp_parse_fixed_port_resource(option, size);
717 size = 0;
718 break;
719 case _STAG_VENDOR:
720 break;
721 case _LTAG_MEMRANGE:
722 if (size != 9)
723 goto __skip;
724 isapnp_parse_mem_resource(option, size);
725 size = 0;
726 break;
727 case _LTAG_ANSISTR:
728 isapnp_parse_name(dev->name, sizeof(dev->name), &size);
729 break;
730 case _LTAG_UNICODESTR:
731 /* silently ignore */
732 /* who use unicode for hardware identification? */
733 break;
734 case _LTAG_VENDOR:
735 break;
736 case _LTAG_MEM32RANGE:
737 if (size != 17)
738 goto __skip;
739 isapnp_parse_mem32_resource(option, size);
740 size = 0;
741 break;
742 case _LTAG_FIXEDMEM32RANGE:
743 if (size != 9)
744 goto __skip;
745 isapnp_parse_fixed_mem32_resource(option, size);
746 size = 0;
747 break;
748 case _STAG_END:
749 if (size > 0)
750 isapnp_skip_bytes(size);
751 return 1;
752 default:
753 printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->number, card->number);
754 }
755 __skip:
756 if (size > 0)
757 isapnp_skip_bytes(size);
758 }
759 return 0;
760}
761
762/*
763 * Parse resource map for ISA PnP card.
764 */
765
766static void __init isapnp_parse_resource_map(struct pnp_card *card)
767{
768 unsigned char type, tmp[17];
769 unsigned short size;
770
771 while (1) {
772 if (isapnp_read_tag(&type, &size)<0)
773 return;
774 switch (type) {
775 case _STAG_PNPVERNO:
776 if (size != 2)
777 goto __skip;
778 isapnp_peek(tmp, 2);
779 card->pnpver = tmp[0];
780 card->productver = tmp[1];
781 size = 0;
782 break;
783 case _STAG_LOGDEVID:
784 if (size >= 5 && size <= 6) {
785 if (isapnp_create_device(card, size)==1)
786 return;
787 size = 0;
788 }
789 break;
790 case _STAG_VENDOR:
791 break;
792 case _LTAG_ANSISTR:
793 isapnp_parse_name(card->name, sizeof(card->name), &size);
794 break;
795 case _LTAG_UNICODESTR:
796 /* silently ignore */
797 /* who use unicode for hardware identification? */
798 break;
799 case _LTAG_VENDOR:
800 break;
801 case _STAG_END:
802 if (size > 0)
803 isapnp_skip_bytes(size);
804 return;
805 default:
806 printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", type, card->number);
807 }
808 __skip:
809 if (size > 0)
810 isapnp_skip_bytes(size);
811 }
812}
813
814/*
815 * Compute ISA PnP checksum for first eight bytes.
816 */
817
818static unsigned char __init isapnp_checksum(unsigned char *data)
819{
820 int i, j;
821 unsigned char checksum = 0x6a, bit, b;
822
823 for (i = 0; i < 8; i++) {
824 b = data[i];
825 for (j = 0; j < 8; j++) {
826 bit = 0;
827 if (b & (1 << j))
828 bit = 1;
829 checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
830 }
831 }
832 return checksum;
833}
834
835/*
836 * Parse EISA id for ISA PnP card.
837 */
838
839static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor, unsigned short device)
840{
841 struct pnp_id * id = isapnp_alloc(sizeof(struct pnp_id));
842 if (!id)
843 return;
844 sprintf(id->id, "%c%c%c%x%x%x%x",
845 'A' + ((vendor >> 2) & 0x3f) - 1,
846 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
847 'A' + ((vendor >> 8) & 0x1f) - 1,
848 (device >> 4) & 0x0f,
849 device & 0x0f,
850 (device >> 12) & 0x0f,
851 (device >> 8) & 0x0f);
852 pnp_add_card_id(id,card);
853}
854
855/*
856 * Build device list for all present ISA PnP devices.
857 */
858
859static int __init isapnp_build_device_list(void)
860{
861 int csn;
862 unsigned char header[9], checksum;
863 struct pnp_card *card;
864
865 isapnp_wait();
866 isapnp_key();
867 for (csn = 1; csn <= isapnp_csn_count; csn++) {
868 isapnp_wake(csn);
869 isapnp_peek(header, 9);
870 checksum = isapnp_checksum(header);
871#if 0
872 printk(KERN_DEBUG "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
873 header[0], header[1], header[2], header[3],
874 header[4], header[5], header[6], header[7], header[8]);
875 printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
876#endif
877 if ((card = isapnp_alloc(sizeof(struct pnp_card))) == NULL)
878 continue;
879
880 card->number = csn;
881 INIT_LIST_HEAD(&card->devices);
882 isapnp_parse_card_id(card, (header[1] << 8) | header[0], (header[3] << 8) | header[2]);
883 card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4];
884 isapnp_checksum_value = 0x00;
885 isapnp_parse_resource_map(card);
886 if (isapnp_checksum_value != 0x00)
887 printk(KERN_ERR "isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
888 card->checksum = isapnp_checksum_value;
889 card->protocol = &isapnp_protocol;
890
891 pnp_add_card(card);
892 }
893 isapnp_wait();
894 return 0;
895}
896
897/*
898 * Basic configuration routines.
899 */
900
901int isapnp_present(void)
902{
903 struct pnp_card *card;
904 pnp_for_each_card(card) {
905 if (card->protocol == &isapnp_protocol)
906 return 1;
907 }
908 return 0;
909}
910
911int isapnp_cfg_begin(int csn, int logdev)
912{
913 if (csn < 1 || csn > isapnp_csn_count || logdev > 10)
914 return -EINVAL;
915 down(&isapnp_cfg_mutex);
916 isapnp_wait();
917 isapnp_key();
918 isapnp_wake(csn);
919#if 0
920 /* to avoid malfunction when the isapnptools package is used */
921 /* we must set RDP to our value again */
922 /* it is possible to set RDP only in the isolation phase */
923 /* Jens Thoms Toerring <Jens.Toerring@physik.fu-berlin.de> */
924 isapnp_write_byte(0x02, 0x04); /* clear CSN of card */
925 mdelay(2); /* is this necessary? */
926 isapnp_wake(csn); /* bring card into sleep state */
927 isapnp_wake(0); /* bring card into isolation state */
928 isapnp_set_rdp(); /* reset the RDP port */
929 udelay(1000); /* delay 1000us */
930 isapnp_write_byte(0x06, csn); /* reset CSN to previous value */
931 udelay(250); /* is this necessary? */
932#endif
933 if (logdev >= 0)
934 isapnp_device(logdev);
935 return 0;
936}
937
938int isapnp_cfg_end(void)
939{
940 isapnp_wait();
941 up(&isapnp_cfg_mutex);
942 return 0;
943}
944
945
946/*
947 * Inititialization.
948 */
949
950
951EXPORT_SYMBOL(isapnp_protocol);
952EXPORT_SYMBOL(isapnp_present);
953EXPORT_SYMBOL(isapnp_cfg_begin);
954EXPORT_SYMBOL(isapnp_cfg_end);
955EXPORT_SYMBOL(isapnp_read_byte);
956EXPORT_SYMBOL(isapnp_write_byte);
957
958static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res)
959{
960 int tmp, ret;
961
962 dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
963 if (dev->active) {
964 for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
965 ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
966 if (!ret)
967 continue;
968 res->port_resource[tmp].start = ret;
969 res->port_resource[tmp].flags = IORESOURCE_IO;
970 }
971 for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
972 ret = isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
973 if (!ret)
974 continue;
975 res->mem_resource[tmp].start = ret;
976 res->mem_resource[tmp].flags = IORESOURCE_MEM;
977 }
978 for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
979 ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8);
980 if (!ret)
981 continue;
982 res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret;
983 res->irq_resource[tmp].flags = IORESOURCE_IRQ;
984 }
985 for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
986 ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
987 if (ret == 4)
988 continue;
989 res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret;
990 res->dma_resource[tmp].flags = IORESOURCE_DMA;
991 }
992 }
993 return 0;
994}
995
996static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
997{
998 int ret;
999 pnp_init_resource_table(res);
1000 isapnp_cfg_begin(dev->card->number, dev->number);
1001 ret = isapnp_read_resources(dev, res);
1002 isapnp_cfg_end();
1003 return ret;
1004}
1005
1006static int isapnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
1007{
1008 int tmp;
1009
1010 isapnp_cfg_begin(dev->card->number, dev->number);
1011 dev->active = 1;
1012 for (tmp = 0; tmp < PNP_MAX_PORT && (res->port_resource[tmp].flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO; tmp++)
1013 isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), res->port_resource[tmp].start);
1014 for (tmp = 0; tmp < PNP_MAX_IRQ && (res->irq_resource[tmp].flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ; tmp++) {
1015 int irq = res->irq_resource[tmp].start;
1016 if (irq == 2)
1017 irq = 9;
1018 isapnp_write_byte(ISAPNP_CFG_IRQ+(tmp<<1), irq);
1019 }
1020 for (tmp = 0; tmp < PNP_MAX_DMA && (res->dma_resource[tmp].flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA; tmp++)
1021 isapnp_write_byte(ISAPNP_CFG_DMA+tmp, res->dma_resource[tmp].start);
1022 for (tmp = 0; tmp < PNP_MAX_MEM && (res->mem_resource[tmp].flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM; tmp++)
1023 isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<3), (res->mem_resource[tmp].start >> 8) & 0xffff);
1024 /* FIXME: We aren't handling 32bit mems properly here */
1025 isapnp_activate(dev->number);
1026 isapnp_cfg_end();
1027 return 0;
1028}
1029
1030static int isapnp_disable_resources(struct pnp_dev *dev)
1031{
1032 if (!dev || !dev->active)
1033 return -EINVAL;
1034 isapnp_cfg_begin(dev->card->number, dev->number);
1035 isapnp_deactivate(dev->number);
1036 dev->active = 0;
1037 isapnp_cfg_end();
1038 return 0;
1039}
1040
1041struct pnp_protocol isapnp_protocol = {
1042 .name = "ISA Plug and Play",
1043 .get = isapnp_get_resources,
1044 .set = isapnp_set_resources,
1045 .disable = isapnp_disable_resources,
1046};
1047
1048static int __init isapnp_init(void)
1049{
1050 int cards;
1051 struct pnp_card *card;
1052 struct pnp_dev *dev;
1053
1054 if (isapnp_disable) {
1055 isapnp_detected = 0;
1056 printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");
1057 return 0;
1058 }
1059#ifdef ISAPNP_REGION_OK
1060 if (!request_region(_PIDXR, 1, "isapnp index")) {
1061 printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR);
1062 return -EBUSY;
1063 }
1064#endif
1065 if (!request_region(_PNPWRP, 1, "isapnp write")) {
1066 printk(KERN_ERR "isapnp: Write Data Register 0x%x already used\n", _PNPWRP);
1067#ifdef ISAPNP_REGION_OK
1068 release_region(_PIDXR, 1);
1069#endif
1070 return -EBUSY;
1071 }
1072
1073 if(pnp_register_protocol(&isapnp_protocol)<0)
1074 return -EBUSY;
1075
1076 /*
1077 * Print a message. The existing ISAPnP code is hanging machines
1078 * so let the user know where.
1079 */
1080
1081 printk(KERN_INFO "isapnp: Scanning for PnP cards...\n");
1082 if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {
1083 isapnp_rdp |= 3;
1084 if (!request_region(isapnp_rdp, 1, "isapnp read")) {
1085 printk(KERN_ERR "isapnp: Read Data Register 0x%x already used\n", isapnp_rdp);
1086#ifdef ISAPNP_REGION_OK
1087 release_region(_PIDXR, 1);
1088#endif
1089 release_region(_PNPWRP, 1);
1090 return -EBUSY;
1091 }
1092 isapnp_set_rdp();
1093 }
1094 isapnp_detected = 1;
1095 if (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff) {
1096 cards = isapnp_isolate();
1097 if (cards < 0 ||
1098 (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {
1099#ifdef ISAPNP_REGION_OK
1100 release_region(_PIDXR, 1);
1101#endif
1102 release_region(_PNPWRP, 1);
1103 isapnp_detected = 0;
1104 printk(KERN_INFO "isapnp: No Plug & Play device found\n");
1105 return 0;
1106 }
1107 request_region(isapnp_rdp, 1, "isapnp read");
1108 }
1109 isapnp_build_device_list();
1110 cards = 0;
1111
1112 protocol_for_each_card(&isapnp_protocol,card) {
1113 cards++;
1114 if (isapnp_verbose) {
1115 printk(KERN_INFO "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown");
1116 if (isapnp_verbose < 2)
1117 continue;
1118 card_for_each_dev(card,dev) {
1119 printk(KERN_INFO "isapnp: Device '%s'\n", dev->name[0]?dev->name:"Unknown");
1120 }
1121 }
1122 }
1123 if (cards) {
1124 printk(KERN_INFO "isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":"");
1125 } else {
1126 printk(KERN_INFO "isapnp: No Plug & Play card found\n");
1127 }
1128
1129 isapnp_proc_init();
1130 return 0;
1131}
1132
1133device_initcall(isapnp_init);
1134
1135/* format is: noisapnp */
1136
1137static int __init isapnp_setup_disable(char *str)
1138{
1139 isapnp_disable = 1;
1140 return 1;
1141}
1142
1143__setup("noisapnp", isapnp_setup_disable);
1144
1145/* format is: isapnp=rdp,reset,skip_pci_scan,verbose */
1146
1147static int __init isapnp_setup_isapnp(char *str)
1148{
1149 (void)((get_option(&str,&isapnp_rdp) == 2) &&
1150 (get_option(&str,&isapnp_reset) == 2) &&
1151 (get_option(&str,&isapnp_verbose) == 2));
1152 return 1;
1153}
1154
1155__setup("isapnp=", isapnp_setup_isapnp);
1156
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
new file mode 100644
index 000000000000..cf54b0a3628e
--- /dev/null
+++ b/drivers/pnp/isapnp/proc.c
@@ -0,0 +1,171 @@
1/*
2 * ISA Plug & Play support
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22#include <linux/config.h>
23#include <linux/module.h>
24#include <linux/isapnp.h>
25#include <linux/proc_fs.h>
26#include <linux/init.h>
27#include <linux/smp_lock.h>
28#include <asm/uaccess.h>
29
30extern struct pnp_protocol isapnp_protocol;
31
32static struct proc_dir_entry *isapnp_proc_bus_dir = NULL;
33
34static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
35{
36 loff_t new = -1;
37
38 lock_kernel();
39 switch (whence) {
40 case 0:
41 new = off;
42 break;
43 case 1:
44 new = file->f_pos + off;
45 break;
46 case 2:
47 new = 256 + off;
48 break;
49 }
50 if (new < 0 || new > 256) {
51 unlock_kernel();
52 return -EINVAL;
53 }
54 unlock_kernel();
55 return (file->f_pos = new);
56}
57
58static ssize_t isapnp_proc_bus_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
59{
60 struct inode *ino = file->f_dentry->d_inode;
61 struct proc_dir_entry *dp = PDE(ino);
62 struct pnp_dev *dev = dp->data;
63 int pos = *ppos;
64 int cnt, size = 256;
65
66 if (pos >= size)
67 return 0;
68 if (nbytes >= size)
69 nbytes = size;
70 if (pos + nbytes > size)
71 nbytes = size - pos;
72 cnt = nbytes;
73
74 if (!access_ok(VERIFY_WRITE, buf, cnt))
75 return -EINVAL;
76
77 isapnp_cfg_begin(dev->card->number, dev->number);
78 for ( ; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
79 unsigned char val;
80 val = isapnp_read_byte(pos);
81 __put_user(val, buf);
82 }
83 isapnp_cfg_end();
84
85 *ppos = pos;
86 return nbytes;
87}
88
89static struct file_operations isapnp_proc_bus_file_operations =
90{
91 .llseek = isapnp_proc_bus_lseek,
92 .read = isapnp_proc_bus_read,
93};
94
95static int isapnp_proc_attach_device(struct pnp_dev *dev)
96{
97 struct pnp_card *bus = dev->card;
98 struct proc_dir_entry *de, *e;
99 char name[16];
100
101 if (!(de = bus->procdir)) {
102 sprintf(name, "%02x", bus->number);
103 de = bus->procdir = proc_mkdir(name, isapnp_proc_bus_dir);
104 if (!de)
105 return -ENOMEM;
106 }
107 sprintf(name, "%02x", dev->number);
108 e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de);
109 if (!e)
110 return -ENOMEM;
111 e->proc_fops = &isapnp_proc_bus_file_operations;
112 e->owner = THIS_MODULE;
113 e->data = dev;
114 e->size = 256;
115 return 0;
116}
117
118#ifdef MODULE
119static int __exit isapnp_proc_detach_device(struct pnp_dev *dev)
120{
121 struct pnp_card *bus = dev->card;
122 struct proc_dir_entry *de;
123 char name[16];
124
125 if (!(de = bus->procdir))
126 return -EINVAL;
127 sprintf(name, "%02x", dev->number);
128 remove_proc_entry(name, de);
129 return 0;
130}
131
132static int __exit isapnp_proc_detach_bus(struct pnp_card *bus)
133{
134 struct proc_dir_entry *de;
135 char name[16];
136
137 if (!(de = bus->procdir))
138 return -EINVAL;
139 sprintf(name, "%02x", bus->number);
140 remove_proc_entry(name, isapnp_proc_bus_dir);
141 return 0;
142}
143#endif /* MODULE */
144
145int __init isapnp_proc_init(void)
146{
147 struct pnp_dev *dev;
148 isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
149 protocol_for_each_dev(&isapnp_protocol,dev) {
150 isapnp_proc_attach_device(dev);
151 }
152 return 0;
153}
154
155#ifdef MODULE
156int __exit isapnp_proc_done(void)
157{
158 struct pnp_dev *dev;
159 struct pnp_bus *card;
160
161 isapnp_for_each_dev(dev) {
162 isapnp_proc_detach_device(dev);
163 }
164 isapnp_for_each_card(card) {
165 isapnp_proc_detach_bus(card);
166 }
167 if (isapnp_proc_bus_dir)
168 remove_proc_entry("isapnp", proc_bus);
169 return 0;
170}
171#endif /* MODULE */
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
new file mode 100644
index 000000000000..639e04253482
--- /dev/null
+++ b/drivers/pnp/manager.c
@@ -0,0 +1,566 @@
1/*
2 * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
3 *
4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
6 *
7 */
8
9#include <linux/config.h>
10#include <linux/errno.h>
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/kernel.h>
14
15#ifdef CONFIG_PNP_DEBUG
16 #define DEBUG
17#else
18 #undef DEBUG
19#endif
20
21#include <linux/pnp.h>
22#include "base.h"
23
24DECLARE_MUTEX(pnp_res_mutex);
25
26static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
27{
28 unsigned long *start, *end, *flags;
29
30 if (!dev || !rule)
31 return -EINVAL;
32
33 if (idx >= PNP_MAX_PORT) {
34 pnp_err("More than 4 ports is incompatible with pnp specifications.");
35 /* pretend we were successful so at least the manager won't try again */
36 return 1;
37 }
38
39 /* check if this resource has been manually set, if so skip */
40 if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
41 return 1;
42
43 start = &dev->res.port_resource[idx].start;
44 end = &dev->res.port_resource[idx].end;
45 flags = &dev->res.port_resource[idx].flags;
46
47 /* set the initial values */
48 *flags |= rule->flags | IORESOURCE_IO;
49 *flags &= ~IORESOURCE_UNSET;
50
51 if (!rule->size) {
52 *flags |= IORESOURCE_DISABLED;
53 return 1; /* skip disabled resource requests */
54 }
55
56 *start = rule->min;
57 *end = *start + rule->size - 1;
58
59 /* run through until pnp_check_port is happy */
60 while (!pnp_check_port(dev, idx)) {
61 *start += rule->align;
62 *end = *start + rule->size - 1;
63 if (*start > rule->max || !rule->align)
64 return 0;
65 }
66 return 1;
67}
68
69static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
70{
71 unsigned long *start, *end, *flags;
72
73 if (!dev || !rule)
74 return -EINVAL;
75
76 if (idx >= PNP_MAX_MEM) {
77 pnp_err("More than 8 mems is incompatible with pnp specifications.");
78 /* pretend we were successful so at least the manager won't try again */
79 return 1;
80 }
81
82 /* check if this resource has been manually set, if so skip */
83 if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
84 return 1;
85
86 start = &dev->res.mem_resource[idx].start;
87 end = &dev->res.mem_resource[idx].end;
88 flags = &dev->res.mem_resource[idx].flags;
89
90 /* set the initial values */
91 *flags |= rule->flags | IORESOURCE_MEM;
92 *flags &= ~IORESOURCE_UNSET;
93
94 /* convert pnp flags to standard Linux flags */
95 if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
96 *flags |= IORESOURCE_READONLY;
97 if (rule->flags & IORESOURCE_MEM_CACHEABLE)
98 *flags |= IORESOURCE_CACHEABLE;
99 if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
100 *flags |= IORESOURCE_RANGELENGTH;
101 if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
102 *flags |= IORESOURCE_SHADOWABLE;
103
104 if (!rule->size) {
105 *flags |= IORESOURCE_DISABLED;
106 return 1; /* skip disabled resource requests */
107 }
108
109 *start = rule->min;
110 *end = *start + rule->size -1;
111
112 /* run through until pnp_check_mem is happy */
113 while (!pnp_check_mem(dev, idx)) {
114 *start += rule->align;
115 *end = *start + rule->size - 1;
116 if (*start > rule->max || !rule->align)
117 return 0;
118 }
119 return 1;
120}
121
122static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
123{
124 unsigned long *start, *end, *flags;
125 int i;
126
127 /* IRQ priority: this table is good for i386 */
128 static unsigned short xtab[16] = {
129 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
130 };
131
132 if (!dev || !rule)
133 return -EINVAL;
134
135 if (idx >= PNP_MAX_IRQ) {
136 pnp_err("More than 2 irqs is incompatible with pnp specifications.");
137 /* pretend we were successful so at least the manager won't try again */
138 return 1;
139 }
140
141 /* check if this resource has been manually set, if so skip */
142 if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
143 return 1;
144
145 start = &dev->res.irq_resource[idx].start;
146 end = &dev->res.irq_resource[idx].end;
147 flags = &dev->res.irq_resource[idx].flags;
148
149 /* set the initial values */
150 *flags |= rule->flags | IORESOURCE_IRQ;
151 *flags &= ~IORESOURCE_UNSET;
152
153 if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
154 *flags |= IORESOURCE_DISABLED;
155 return 1; /* skip disabled resource requests */
156 }
157
158 /* TBD: need check for >16 IRQ */
159 *start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
160 if (*start < PNP_IRQ_NR) {
161 *end = *start;
162 return 1;
163 }
164 for (i = 0; i < 16; i++) {
165 if(test_bit(xtab[i], rule->map)) {
166 *start = *end = xtab[i];
167 if(pnp_check_irq(dev, idx))
168 return 1;
169 }
170 }
171 return 0;
172}
173
174static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
175{
176 unsigned long *start, *end, *flags;
177 int i;
178
179 /* DMA priority: this table is good for i386 */
180 static unsigned short xtab[8] = {
181 1, 3, 5, 6, 7, 0, 2, 4
182 };
183
184 if (!dev || !rule)
185 return -EINVAL;
186
187 if (idx >= PNP_MAX_DMA) {
188 pnp_err("More than 2 dmas is incompatible with pnp specifications.");
189 /* pretend we were successful so at least the manager won't try again */
190 return 1;
191 }
192
193 /* check if this resource has been manually set, if so skip */
194 if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
195 return 1;
196
197 start = &dev->res.dma_resource[idx].start;
198 end = &dev->res.dma_resource[idx].end;
199 flags = &dev->res.dma_resource[idx].flags;
200
201 /* set the initial values */
202 *flags |= rule->flags | IORESOURCE_DMA;
203 *flags &= ~IORESOURCE_UNSET;
204
205 if (!rule->map) {
206 *flags |= IORESOURCE_DISABLED;
207 return 1; /* skip disabled resource requests */
208 }
209
210 for (i = 0; i < 8; i++) {
211 if(rule->map & (1<<xtab[i])) {
212 *start = *end = xtab[i];
213 if(pnp_check_dma(dev, idx))
214 return 1;
215 }
216 }
217 return 0;
218}
219
220/**
221 * pnp_init_resources - Resets a resource table to default values.
222 * @table: pointer to the desired resource table
223 *
224 */
225void pnp_init_resource_table(struct pnp_resource_table *table)
226{
227 int idx;
228 for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
229 table->irq_resource[idx].name = NULL;
230 table->irq_resource[idx].start = -1;
231 table->irq_resource[idx].end = -1;
232 table->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
233 }
234 for (idx = 0; idx < PNP_MAX_DMA; idx++) {
235 table->dma_resource[idx].name = NULL;
236 table->dma_resource[idx].start = -1;
237 table->dma_resource[idx].end = -1;
238 table->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
239 }
240 for (idx = 0; idx < PNP_MAX_PORT; idx++) {
241 table->port_resource[idx].name = NULL;
242 table->port_resource[idx].start = 0;
243 table->port_resource[idx].end = 0;
244 table->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
245 }
246 for (idx = 0; idx < PNP_MAX_MEM; idx++) {
247 table->mem_resource[idx].name = NULL;
248 table->mem_resource[idx].start = 0;
249 table->mem_resource[idx].end = 0;
250 table->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
251 }
252}
253
254/**
255 * pnp_clean_resources - clears resources that were not manually set
256 * @res - the resources to clean
257 *
258 */
259static void pnp_clean_resource_table(struct pnp_resource_table * res)
260{
261 int idx;
262 for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
263 if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
264 continue;
265 res->irq_resource[idx].start = -1;
266 res->irq_resource[idx].end = -1;
267 res->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
268 }
269 for (idx = 0; idx < PNP_MAX_DMA; idx++) {
270 if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
271 continue;
272 res->dma_resource[idx].start = -1;
273 res->dma_resource[idx].end = -1;
274 res->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
275 }
276 for (idx = 0; idx < PNP_MAX_PORT; idx++) {
277 if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
278 continue;
279 res->port_resource[idx].start = 0;
280 res->port_resource[idx].end = 0;
281 res->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
282 }
283 for (idx = 0; idx < PNP_MAX_MEM; idx++) {
284 if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
285 continue;
286 res->mem_resource[idx].start = 0;
287 res->mem_resource[idx].end = 0;
288 res->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
289 }
290}
291
292/**
293 * pnp_assign_resources - assigns resources to the device based on the specified dependent number
294 * @dev: pointer to the desired device
295 * @depnum: the dependent function number
296 *
297 * Only set depnum to 0 if the device does not have dependent options.
298 */
299static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
300{
301 struct pnp_port *port;
302 struct pnp_mem *mem;
303 struct pnp_irq *irq;
304 struct pnp_dma *dma;
305 int nport = 0, nmem = 0, nirq = 0, ndma = 0;
306
307 if (!pnp_can_configure(dev))
308 return -ENODEV;
309
310 down(&pnp_res_mutex);
311 pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
312 if (dev->independent) {
313 port = dev->independent->port;
314 mem = dev->independent->mem;
315 irq = dev->independent->irq;
316 dma = dev->independent->dma;
317 while (port) {
318 if (!pnp_assign_port(dev, port, nport))
319 goto fail;
320 nport++;
321 port = port->next;
322 }
323 while (mem) {
324 if (!pnp_assign_mem(dev, mem, nmem))
325 goto fail;
326 nmem++;
327 mem = mem->next;
328 }
329 while (irq) {
330 if (!pnp_assign_irq(dev, irq, nirq))
331 goto fail;
332 nirq++;
333 irq = irq->next;
334 }
335 while (dma) {
336 if (!pnp_assign_dma(dev, dma, ndma))
337 goto fail;
338 ndma++;
339 dma = dma->next;
340 }
341 }
342
343 if (depnum) {
344 struct pnp_option *dep;
345 int i;
346 for (i=1,dep=dev->dependent; i<depnum; i++, dep=dep->next)
347 if(!dep)
348 goto fail;
349 port =dep->port;
350 mem = dep->mem;
351 irq = dep->irq;
352 dma = dep->dma;
353 while (port) {
354 if (!pnp_assign_port(dev, port, nport))
355 goto fail;
356 nport++;
357 port = port->next;
358 }
359 while (mem) {
360 if (!pnp_assign_mem(dev, mem, nmem))
361 goto fail;
362 nmem++;
363 mem = mem->next;
364 }
365 while (irq) {
366 if (!pnp_assign_irq(dev, irq, nirq))
367 goto fail;
368 nirq++;
369 irq = irq->next;
370 }
371 while (dma) {
372 if (!pnp_assign_dma(dev, dma, ndma))
373 goto fail;
374 ndma++;
375 dma = dma->next;
376 }
377 } else if (dev->dependent)
378 goto fail;
379
380 up(&pnp_res_mutex);
381 return 1;
382
383fail:
384 pnp_clean_resource_table(&dev->res);
385 up(&pnp_res_mutex);
386 return 0;
387}
388
389/**
390 * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
391 * @dev: pointer to the desired device
392 * @res: pointer to the new resource config
393 *
394 * This function can be used by drivers that want to manually set thier resources.
395 */
396int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode)
397{
398 int i;
399 struct pnp_resource_table * bak;
400 if (!dev || !res)
401 return -EINVAL;
402 if (!pnp_can_configure(dev))
403 return -ENODEV;
404 bak = pnp_alloc(sizeof(struct pnp_resource_table));
405 if (!bak)
406 return -ENOMEM;
407 *bak = dev->res;
408
409 down(&pnp_res_mutex);
410 dev->res = *res;
411 if (!(mode & PNP_CONFIG_FORCE)) {
412 for (i = 0; i < PNP_MAX_PORT; i++) {
413 if(!pnp_check_port(dev,i))
414 goto fail;
415 }
416 for (i = 0; i < PNP_MAX_MEM; i++) {
417 if(!pnp_check_mem(dev,i))
418 goto fail;
419 }
420 for (i = 0; i < PNP_MAX_IRQ; i++) {
421 if(!pnp_check_irq(dev,i))
422 goto fail;
423 }
424 for (i = 0; i < PNP_MAX_DMA; i++) {
425 if(!pnp_check_dma(dev,i))
426 goto fail;
427 }
428 }
429 up(&pnp_res_mutex);
430
431 kfree(bak);
432 return 0;
433
434fail:
435 dev->res = *bak;
436 up(&pnp_res_mutex);
437 kfree(bak);
438 return -EINVAL;
439}
440
441/**
442 * pnp_auto_config_dev - automatically assigns resources to a device
443 * @dev: pointer to the desired device
444 *
445 */
446int pnp_auto_config_dev(struct pnp_dev *dev)
447{
448 struct pnp_option *dep;
449 int i = 1;
450
451 if(!dev)
452 return -EINVAL;
453
454 if(!pnp_can_configure(dev)) {
455 pnp_info("Device %s does not support resource configuration.", dev->dev.bus_id);
456 return -ENODEV;
457 }
458
459 if (!dev->dependent) {
460 if (pnp_assign_resources(dev, 0))
461 return 0;
462 } else {
463 dep = dev->dependent;
464 do {
465 if (pnp_assign_resources(dev, i))
466 return 0;
467 dep = dep->next;
468 i++;
469 } while (dep);
470 }
471
472 pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id);
473 return -EBUSY;
474}
475
476/**
477 * pnp_activate_dev - activates a PnP device for use
478 * @dev: pointer to the desired device
479 *
480 * does not validate or set resources so be careful.
481 */
482int pnp_activate_dev(struct pnp_dev *dev)
483{
484 if (!dev)
485 return -EINVAL;
486 if (dev->active) {
487 return 0; /* the device is already active */
488 }
489
490 /* ensure resources are allocated */
491 if (pnp_auto_config_dev(dev))
492 return -EBUSY;
493
494 if (!pnp_can_write(dev)) {
495 pnp_info("Device %s does not supported activation.", dev->dev.bus_id);
496 return -EINVAL;
497 }
498
499 if (dev->protocol->set(dev, &dev->res)<0) {
500 pnp_err("Failed to activate device %s.", dev->dev.bus_id);
501 return -EIO;
502 }
503
504 dev->active = 1;
505 pnp_info("Device %s activated.", dev->dev.bus_id);
506
507 return 1;
508}
509
510/**
511 * pnp_disable_dev - disables device
512 * @dev: pointer to the desired device
513 *
514 * inform the correct pnp protocol so that resources can be used by other devices
515 */
516int pnp_disable_dev(struct pnp_dev *dev)
517{
518 if (!dev)
519 return -EINVAL;
520 if (!dev->active) {
521 return 0; /* the device is already disabled */
522 }
523
524 if (!pnp_can_disable(dev)) {
525 pnp_info("Device %s does not supported disabling.", dev->dev.bus_id);
526 return -EINVAL;
527 }
528 if (dev->protocol->disable(dev)<0) {
529 pnp_err("Failed to disable device %s.", dev->dev.bus_id);
530 return -EIO;
531 }
532
533 dev->active = 0;
534 pnp_info("Device %s disabled.", dev->dev.bus_id);
535
536 /* release the resources so that other devices can use them */
537 down(&pnp_res_mutex);
538 pnp_clean_resource_table(&dev->res);
539 up(&pnp_res_mutex);
540
541 return 1;
542}
543
544/**
545 * pnp_resource_change - change one resource
546 * @resource: pointer to resource to be changed
547 * @start: start of region
548 * @size: size of region
549 *
550 */
551void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size)
552{
553 if (resource == NULL)
554 return;
555 resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
556 resource->start = start;
557 resource->end = start + size - 1;
558}
559
560
561EXPORT_SYMBOL(pnp_manual_config_dev);
562EXPORT_SYMBOL(pnp_auto_config_dev);
563EXPORT_SYMBOL(pnp_activate_dev);
564EXPORT_SYMBOL(pnp_disable_dev);
565EXPORT_SYMBOL(pnp_resource_change);
566EXPORT_SYMBOL(pnp_init_resource_table);
diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig
new file mode 100644
index 000000000000..0782cdc5009f
--- /dev/null
+++ b/drivers/pnp/pnpacpi/Kconfig
@@ -0,0 +1,18 @@
1#
2# Plug and Play ACPI configuration
3#
4config PNPACPI
5 bool "Plug and Play ACPI support (EXPERIMENTAL)"
6 depends on PNP && ACPI_BUS && EXPERIMENTAL
7 default y
8 ---help---
9 Linux uses the PNPACPI to autodetect built-in
10 mainboard resources (e.g. parallel port resources).
11
12 Some features (e.g. real hotplug) are not currently
13 implemented.
14
15 If you would like the kernel to detect and allocate resources to
16 your mainboard devices (on some systems they are disabled by the
17 BIOS) say Y here. Also the PNPACPI can help prevent resource
18 conflicts between mainboard devices and other bus devices.
diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile
new file mode 100644
index 000000000000..905326fcca85
--- /dev/null
+++ b/drivers/pnp/pnpacpi/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for the kernel PNPACPI driver.
3#
4
5obj-y := core.o rsparser.o
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
new file mode 100644
index 000000000000..8655dd2e5b83
--- /dev/null
+++ b/drivers/pnp/pnpacpi/core.c
@@ -0,0 +1,269 @@
1/*
2 * pnpacpi -- PnP ACPI driver
3 *
4 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
5 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <linux/acpi.h>
23#include <linux/pnp.h>
24#include <acpi/acpi_bus.h>
25#include "pnpacpi.h"
26
27static int num = 0;
28
29static char __initdata excluded_id_list[] =
30 "PNP0C0A," /* Battery */
31 "PNP0C0C,PNP0C0E,PNP0C0D," /* Button */
32 "PNP0C09," /* EC */
33 "PNP0C0B," /* Fan */
34 "PNP0A03," /* PCI root */
35 "PNP0C0F," /* Link device */
36 "PNP0000," /* PIC */
37 "PNP0100," /* Timer */
38 ;
39static inline int is_exclusive_device(struct acpi_device *dev)
40{
41 return (!acpi_match_ids(dev, excluded_id_list));
42}
43
44void *pnpacpi_kmalloc(size_t size, int f)
45{
46 void *p = kmalloc(size, f);
47 if (p)
48 memset(p, 0, size);
49 return p;
50}
51
52/*
53 * Compatible Device IDs
54 */
55#define TEST_HEX(c) \
56 if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \
57 return 0
58#define TEST_ALPHA(c) \
59 if (!('@' <= (c) || (c) <= 'Z')) \
60 return 0
61static int __init ispnpidacpi(char *id)
62{
63 TEST_ALPHA(id[0]);
64 TEST_ALPHA(id[1]);
65 TEST_ALPHA(id[2]);
66 TEST_HEX(id[3]);
67 TEST_HEX(id[4]);
68 TEST_HEX(id[5]);
69 TEST_HEX(id[6]);
70 if (id[7] != '\0')
71 return 0;
72 return 1;
73}
74
75static void __init pnpidacpi_to_pnpid(char *id, char *str)
76{
77 str[0] = id[0];
78 str[1] = id[1];
79 str[2] = id[2];
80 str[3] = tolower(id[3]);
81 str[4] = tolower(id[4]);
82 str[5] = tolower(id[5]);
83 str[6] = tolower(id[6]);
84 str[7] = '\0';
85}
86
87static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
88{
89 acpi_status status;
90 status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data,
91 &dev->res);
92 return ACPI_FAILURE(status) ? -ENODEV : 0;
93}
94
95static int pnpacpi_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
96{
97 acpi_handle handle = dev->data;
98 struct acpi_buffer buffer;
99 int ret = 0;
100 acpi_status status;
101
102 ret = pnpacpi_build_resource_template(handle, &buffer);
103 if (ret)
104 return ret;
105 ret = pnpacpi_encode_resources(res, &buffer);
106 if (ret) {
107 kfree(buffer.pointer);
108 return ret;
109 }
110 status = acpi_set_current_resources(handle, &buffer);
111 if (ACPI_FAILURE(status))
112 ret = -EINVAL;
113 kfree(buffer.pointer);
114 return ret;
115}
116
117static int pnpacpi_disable_resources(struct pnp_dev *dev)
118{
119 acpi_status status;
120
121 /* acpi_unregister_gsi(pnp_irq(dev, 0)); */
122 status = acpi_evaluate_object((acpi_handle)dev->data,
123 "_DIS", NULL, NULL);
124 return ACPI_FAILURE(status) ? -ENODEV : 0;
125}
126
127struct pnp_protocol pnpacpi_protocol = {
128 .name = "Plug and Play ACPI",
129 .get = pnpacpi_get_resources,
130 .set = pnpacpi_set_resources,
131 .disable = pnpacpi_disable_resources,
132};
133
134static int __init pnpacpi_add_device(struct acpi_device *device)
135{
136 acpi_handle temp = NULL;
137 acpi_status status;
138 struct pnp_id *dev_id;
139 struct pnp_dev *dev;
140
141 if (!ispnpidacpi(acpi_device_hid(device)) ||
142 is_exclusive_device(device))
143 return 0;
144
145 pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
146 dev = pnpacpi_kmalloc(sizeof(struct pnp_dev), GFP_KERNEL);
147 if (!dev) {
148 pnp_err("Out of memory");
149 return -ENOMEM;
150 }
151 dev->data = device->handle;
152 /* .enabled means if the device can decode the resources */
153 dev->active = device->status.enabled;
154 status = acpi_get_handle(device->handle, "_SRS", &temp);
155 if (ACPI_SUCCESS(status))
156 dev->capabilities |= PNP_CONFIGURABLE;
157 dev->capabilities |= PNP_READ;
158 if (device->flags.dynamic_status)
159 dev->capabilities |= PNP_WRITE;
160 if (device->flags.removable)
161 dev->capabilities |= PNP_REMOVABLE;
162 status = acpi_get_handle(device->handle, "_DIS", &temp);
163 if (ACPI_SUCCESS(status))
164 dev->capabilities |= PNP_DISABLE;
165
166 dev->protocol = &pnpacpi_protocol;
167
168 if (strlen(acpi_device_name(device)))
169 strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
170 else
171 strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
172
173 dev->number = num;
174
175 /* set the initial values for the PnP device */
176 dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
177 if (!dev_id)
178 goto err;
179 pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
180 pnp_add_id(dev_id, dev);
181
182 if(dev->active) {
183 /* parse allocated resource */
184 status = pnpacpi_parse_allocated_resource(device->handle, &dev->res);
185 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
186 pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s", dev_id->id);
187 goto err1;
188 }
189 }
190
191 if(dev->capabilities & PNP_CONFIGURABLE) {
192 status = pnpacpi_parse_resource_option_data(device->handle,
193 dev);
194 if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
195 pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id);
196 goto err1;
197 }
198 }
199
200 /* parse compatible ids */
201 if (device->flags.compatible_ids) {
202 struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
203 int i;
204
205 for (i = 0; i < cid_list->count; i++) {
206 if (!ispnpidacpi(cid_list->id[i].value))
207 continue;
208 dev_id = pnpacpi_kmalloc(sizeof(struct pnp_id),
209 GFP_KERNEL);
210 if (!dev_id)
211 continue;
212
213 pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id);
214 pnp_add_id(dev_id, dev);
215 }
216 }
217
218 /* clear out the damaged flags */
219 if (!dev->active)
220 pnp_init_resource_table(&dev->res);
221 pnp_add_device(dev);
222 num ++;
223
224 return AE_OK;
225err1:
226 kfree(dev_id);
227err:
228 kfree(dev);
229 return -EINVAL;
230}
231
232static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
233 u32 lvl, void *context, void **rv)
234{
235 struct acpi_device *device;
236
237 if (!acpi_bus_get_device(handle, &device))
238 pnpacpi_add_device(device);
239 else
240 return AE_CTRL_DEPTH;
241 return AE_OK;
242}
243
244int pnpacpi_disabled __initdata;
245int __init pnpacpi_init(void)
246{
247 if (acpi_disabled || pnpacpi_disabled) {
248 pnp_info("PnP ACPI: disabled");
249 return 0;
250 }
251 pnp_info("PnP ACPI init");
252 pnp_register_protocol(&pnpacpi_protocol);
253 acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
254 pnp_info("PnP ACPI: found %d devices", num);
255 return 0;
256}
257subsys_initcall(pnpacpi_init);
258
259static int __init pnpacpi_setup(char *str)
260{
261 if (str == NULL)
262 return 1;
263 if (!strncmp(str, "off", 3))
264 pnpacpi_disabled = 1;
265 return 1;
266}
267__setup("pnpacpi=", pnpacpi_setup);
268
269EXPORT_SYMBOL(pnpacpi_protocol);
diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h
new file mode 100644
index 000000000000..76f907e09ee6
--- /dev/null
+++ b/drivers/pnp/pnpacpi/pnpacpi.h
@@ -0,0 +1,13 @@
1#ifndef ACPI_PNP_H
2#define ACPI_PNP_H
3
4#include <acpi/acpi_bus.h>
5#include <linux/acpi.h>
6#include <linux/pnp.h>
7
8void *pnpacpi_kmalloc(size_t size, int f);
9acpi_status pnpacpi_parse_allocated_resource(acpi_handle, struct pnp_resource_table*);
10acpi_status pnpacpi_parse_resource_option_data(acpi_handle, struct pnp_dev*);
11int pnpacpi_encode_resources(struct pnp_resource_table *, struct acpi_buffer *);
12int pnpacpi_build_resource_template(acpi_handle, struct acpi_buffer*);
13#endif
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
new file mode 100644
index 000000000000..c0ddb1eb8c4d
--- /dev/null
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -0,0 +1,821 @@
1/*
2 * pnpacpi -- PnP ACPI driver
3 *
4 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
5 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/kernel.h>
22#include <linux/acpi.h>
23#include <linux/pci.h>
24#include "pnpacpi.h"
25
26#ifdef CONFIG_IA64
27#define valid_IRQ(i) (1)
28#else
29#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
30#endif
31
32/*
33 * Allocated Resources
34 */
35static int irq_flags(int edge_level, int active_high_low)
36{
37 int flag;
38 if (edge_level == ACPI_LEVEL_SENSITIVE) {
39 if(active_high_low == ACPI_ACTIVE_LOW)
40 flag = IORESOURCE_IRQ_LOWLEVEL;
41 else
42 flag = IORESOURCE_IRQ_HIGHLEVEL;
43 }
44 else {
45 if(active_high_low == ACPI_ACTIVE_LOW)
46 flag = IORESOURCE_IRQ_LOWEDGE;
47 else
48 flag = IORESOURCE_IRQ_HIGHEDGE;
49 }
50 return flag;
51}
52
53static void decode_irq_flags(int flag, int *edge_level, int *active_high_low)
54{
55 switch (flag) {
56 case IORESOURCE_IRQ_LOWLEVEL:
57 *edge_level = ACPI_LEVEL_SENSITIVE;
58 *active_high_low = ACPI_ACTIVE_LOW;
59 break;
60 case IORESOURCE_IRQ_HIGHLEVEL:
61 *edge_level = ACPI_LEVEL_SENSITIVE;
62 *active_high_low = ACPI_ACTIVE_HIGH;
63 break;
64 case IORESOURCE_IRQ_LOWEDGE:
65 *edge_level = ACPI_EDGE_SENSITIVE;
66 *active_high_low = ACPI_ACTIVE_LOW;
67 break;
68 case IORESOURCE_IRQ_HIGHEDGE:
69 *edge_level = ACPI_EDGE_SENSITIVE;
70 *active_high_low = ACPI_ACTIVE_HIGH;
71 break;
72 }
73}
74
75static void
76pnpacpi_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
77{
78 int i = 0;
79 while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
80 i < PNP_MAX_IRQ)
81 i++;
82 if (i < PNP_MAX_IRQ) {
83 res->irq_resource[i].flags = IORESOURCE_IRQ; //Also clears _UNSET flag
84 if (irq == -1) {
85 res->irq_resource[i].flags |= IORESOURCE_DISABLED;
86 return;
87 }
88 res->irq_resource[i].start =(unsigned long) irq;
89 res->irq_resource[i].end = (unsigned long) irq;
90 }
91}
92
93static void
94pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
95{
96 int i = 0;
97 while (!(res->dma_resource[i].flags & IORESOURCE_UNSET) &&
98 i < PNP_MAX_DMA)
99 i++;
100 if (i < PNP_MAX_DMA) {
101 res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
102 if (dma == -1) {
103 res->dma_resource[i].flags |= IORESOURCE_DISABLED;
104 return;
105 }
106 res->dma_resource[i].start =(unsigned long) dma;
107 res->dma_resource[i].end = (unsigned long) dma;
108 }
109}
110
111static void
112pnpacpi_parse_allocated_ioresource(struct pnp_resource_table * res,
113 int io, int len)
114{
115 int i = 0;
116 while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
117 i < PNP_MAX_PORT)
118 i++;
119 if (i < PNP_MAX_PORT) {
120 res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
121 if (len <= 0 || (io + len -1) >= 0x10003) {
122 res->port_resource[i].flags |= IORESOURCE_DISABLED;
123 return;
124 }
125 res->port_resource[i].start = (unsigned long) io;
126 res->port_resource[i].end = (unsigned long)(io + len - 1);
127 }
128}
129
130static void
131pnpacpi_parse_allocated_memresource(struct pnp_resource_table * res,
132 int mem, int len)
133{
134 int i = 0;
135 while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
136 (i < PNP_MAX_MEM))
137 i++;
138 if (i < PNP_MAX_MEM) {
139 res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
140 if (len <= 0) {
141 res->mem_resource[i].flags |= IORESOURCE_DISABLED;
142 return;
143 }
144 res->mem_resource[i].start = (unsigned long) mem;
145 res->mem_resource[i].end = (unsigned long)(mem + len - 1);
146 }
147}
148
149
150static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
151 void *data)
152{
153 struct pnp_resource_table * res_table = (struct pnp_resource_table *)data;
154
155 switch (res->id) {
156 case ACPI_RSTYPE_IRQ:
157 if ((res->data.irq.number_of_interrupts > 0) &&
158 valid_IRQ(res->data.irq.interrupts[0])) {
159 pnpacpi_parse_allocated_irqresource(res_table,
160 acpi_register_gsi(res->data.irq.interrupts[0],
161 res->data.irq.edge_level,
162 res->data.irq.active_high_low));
163 pcibios_penalize_isa_irq(res->data.irq.interrupts[0]);
164 }
165 break;
166
167 case ACPI_RSTYPE_EXT_IRQ:
168 if ((res->data.extended_irq.number_of_interrupts > 0) &&
169 valid_IRQ(res->data.extended_irq.interrupts[0])) {
170 pnpacpi_parse_allocated_irqresource(res_table,
171 acpi_register_gsi(res->data.extended_irq.interrupts[0],
172 res->data.extended_irq.edge_level,
173 res->data.extended_irq.active_high_low));
174 pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0]);
175 }
176 break;
177 case ACPI_RSTYPE_DMA:
178 if (res->data.dma.number_of_channels > 0)
179 pnpacpi_parse_allocated_dmaresource(res_table,
180 res->data.dma.channels[0]);
181 break;
182 case ACPI_RSTYPE_IO:
183 pnpacpi_parse_allocated_ioresource(res_table,
184 res->data.io.min_base_address,
185 res->data.io.range_length);
186 break;
187 case ACPI_RSTYPE_FIXED_IO:
188 pnpacpi_parse_allocated_ioresource(res_table,
189 res->data.fixed_io.base_address,
190 res->data.fixed_io.range_length);
191 break;
192 case ACPI_RSTYPE_MEM24:
193 pnpacpi_parse_allocated_memresource(res_table,
194 res->data.memory24.min_base_address,
195 res->data.memory24.range_length);
196 break;
197 case ACPI_RSTYPE_MEM32:
198 pnpacpi_parse_allocated_memresource(res_table,
199 res->data.memory32.min_base_address,
200 res->data.memory32.range_length);
201 break;
202 case ACPI_RSTYPE_FIXED_MEM32:
203 pnpacpi_parse_allocated_memresource(res_table,
204 res->data.fixed_memory32.range_base_address,
205 res->data.fixed_memory32.range_length);
206 break;
207 case ACPI_RSTYPE_ADDRESS16:
208 pnpacpi_parse_allocated_memresource(res_table,
209 res->data.address16.min_address_range,
210 res->data.address16.address_length);
211 break;
212 case ACPI_RSTYPE_ADDRESS32:
213 pnpacpi_parse_allocated_memresource(res_table,
214 res->data.address32.min_address_range,
215 res->data.address32.address_length);
216 break;
217 case ACPI_RSTYPE_ADDRESS64:
218 pnpacpi_parse_allocated_memresource(res_table,
219 res->data.address64.min_address_range,
220 res->data.address64.address_length);
221 break;
222 case ACPI_RSTYPE_VENDOR:
223 break;
224 default:
225 pnp_warn("PnPACPI: unknown resource type %d", res->id);
226 return AE_ERROR;
227 }
228
229 return AE_OK;
230}
231
232acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, struct pnp_resource_table * res)
233{
234 /* Blank the resource table values */
235 pnp_init_resource_table(res);
236
237 return acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_allocated_resource, res);
238}
239
240static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_resource_dma *p)
241{
242 int i;
243 struct pnp_dma * dma;
244
245 if (p->number_of_channels == 0)
246 return;
247 dma = pnpacpi_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
248 if (!dma)
249 return;
250
251 for(i = 0; i < p->number_of_channels; i++)
252 dma->map |= 1 << p->channels[i];
253 dma->flags = 0;
254 if (p->bus_master)
255 dma->flags |= IORESOURCE_DMA_MASTER;
256 switch (p->type) {
257 case ACPI_COMPATIBILITY:
258 dma->flags |= IORESOURCE_DMA_COMPATIBLE;
259 break;
260 case ACPI_TYPE_A:
261 dma->flags |= IORESOURCE_DMA_TYPEA;
262 break;
263 case ACPI_TYPE_B:
264 dma->flags |= IORESOURCE_DMA_TYPEB;
265 break;
266 case ACPI_TYPE_F:
267 dma->flags |= IORESOURCE_DMA_TYPEF;
268 break;
269 default:
270 /* Set a default value ? */
271 dma->flags |= IORESOURCE_DMA_COMPATIBLE;
272 pnp_err("Invalid DMA type");
273 }
274 switch (p->transfer) {
275 case ACPI_TRANSFER_8:
276 dma->flags |= IORESOURCE_DMA_8BIT;
277 break;
278 case ACPI_TRANSFER_8_16:
279 dma->flags |= IORESOURCE_DMA_8AND16BIT;
280 break;
281 case ACPI_TRANSFER_16:
282 dma->flags |= IORESOURCE_DMA_16BIT;
283 break;
284 default:
285 /* Set a default value ? */
286 dma->flags |= IORESOURCE_DMA_8AND16BIT;
287 pnp_err("Invalid DMA transfer type");
288 }
289
290 pnp_register_dma_resource(option,dma);
291 return;
292}
293
294
295static void pnpacpi_parse_irq_option(struct pnp_option *option,
296 struct acpi_resource_irq *p)
297{
298 int i;
299 struct pnp_irq * irq;
300
301 if (p->number_of_interrupts == 0)
302 return;
303 irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
304 if (!irq)
305 return;
306
307 for(i = 0; i < p->number_of_interrupts; i++)
308 if (p->interrupts[i])
309 __set_bit(p->interrupts[i], irq->map);
310 irq->flags = irq_flags(p->edge_level, p->active_high_low);
311
312 pnp_register_irq_resource(option, irq);
313 return;
314}
315
316static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
317 struct acpi_resource_ext_irq *p)
318{
319 int i;
320 struct pnp_irq * irq;
321
322 if (p->number_of_interrupts == 0)
323 return;
324 irq = pnpacpi_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
325 if (!irq)
326 return;
327
328 for(i = 0; i < p->number_of_interrupts; i++)
329 if (p->interrupts[i])
330 __set_bit(p->interrupts[i], irq->map);
331 irq->flags = irq_flags(p->edge_level, p->active_high_low);
332
333 pnp_register_irq_resource(option, irq);
334 return;
335}
336
337static void
338pnpacpi_parse_port_option(struct pnp_option *option,
339 struct acpi_resource_io *io)
340{
341 struct pnp_port * port;
342
343 if (io->range_length == 0)
344 return;
345 port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
346 if (!port)
347 return;
348 port->min = io->min_base_address;
349 port->max = io->max_base_address;
350 port->align = io->alignment;
351 port->size = io->range_length;
352 port->flags = ACPI_DECODE_16 == io->io_decode ?
353 PNP_PORT_FLAG_16BITADDR : 0;
354 pnp_register_port_resource(option,port);
355 return;
356}
357
358static void
359pnpacpi_parse_fixed_port_option(struct pnp_option *option,
360 struct acpi_resource_fixed_io *io)
361{
362 struct pnp_port * port;
363
364 if (io->range_length == 0)
365 return;
366 port = pnpacpi_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
367 if (!port)
368 return;
369 port->min = port->max = io->base_address;
370 port->size = io->range_length;
371 port->align = 0;
372 port->flags = PNP_PORT_FLAG_FIXED;
373 pnp_register_port_resource(option,port);
374 return;
375}
376
377static void
378pnpacpi_parse_mem24_option(struct pnp_option *option,
379 struct acpi_resource_mem24 *p)
380{
381 struct pnp_mem * mem;
382
383 if (p->range_length == 0)
384 return;
385 mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
386 if (!mem)
387 return;
388 mem->min = p->min_base_address;
389 mem->max = p->max_base_address;
390 mem->align = p->alignment;
391 mem->size = p->range_length;
392
393 mem->flags = (ACPI_READ_WRITE_MEMORY == p->read_write_attribute) ?
394 IORESOURCE_MEM_WRITEABLE : 0;
395
396 pnp_register_mem_resource(option,mem);
397 return;
398}
399
400static void
401pnpacpi_parse_mem32_option(struct pnp_option *option,
402 struct acpi_resource_mem32 *p)
403{
404 struct pnp_mem * mem;
405
406 if (p->range_length == 0)
407 return;
408 mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
409 if (!mem)
410 return;
411 mem->min = p->min_base_address;
412 mem->max = p->max_base_address;
413 mem->align = p->alignment;
414 mem->size = p->range_length;
415
416 mem->flags = (ACPI_READ_WRITE_MEMORY == p->read_write_attribute) ?
417 IORESOURCE_MEM_WRITEABLE : 0;
418
419 pnp_register_mem_resource(option,mem);
420 return;
421}
422
423static void
424pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
425 struct acpi_resource_fixed_mem32 *p)
426{
427 struct pnp_mem * mem;
428
429 if (p->range_length == 0)
430 return;
431 mem = pnpacpi_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
432 if (!mem)
433 return;
434 mem->min = mem->max = p->range_base_address;
435 mem->size = p->range_length;
436 mem->align = 0;
437
438 mem->flags = (ACPI_READ_WRITE_MEMORY == p->read_write_attribute) ?
439 IORESOURCE_MEM_WRITEABLE : 0;
440
441 pnp_register_mem_resource(option,mem);
442 return;
443}
444
445struct acpipnp_parse_option_s {
446 struct pnp_option *option;
447 struct pnp_dev *dev;
448};
449
450static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
451 void *data)
452{
453 int priority = 0;
454 struct acpipnp_parse_option_s *parse_data = (struct acpipnp_parse_option_s *)data;
455 struct pnp_dev *dev = parse_data->dev;
456 struct pnp_option *option = parse_data->option;
457
458 switch (res->id) {
459 case ACPI_RSTYPE_IRQ:
460 pnpacpi_parse_irq_option(option, &res->data.irq);
461 break;
462 case ACPI_RSTYPE_EXT_IRQ:
463 pnpacpi_parse_ext_irq_option(option,
464 &res->data.extended_irq);
465 break;
466 case ACPI_RSTYPE_DMA:
467 pnpacpi_parse_dma_option(option, &res->data.dma);
468 break;
469 case ACPI_RSTYPE_IO:
470 pnpacpi_parse_port_option(option, &res->data.io);
471 break;
472 case ACPI_RSTYPE_FIXED_IO:
473 pnpacpi_parse_fixed_port_option(option,
474 &res->data.fixed_io);
475 break;
476 case ACPI_RSTYPE_MEM24:
477 pnpacpi_parse_mem24_option(option, &res->data.memory24);
478 break;
479 case ACPI_RSTYPE_MEM32:
480 pnpacpi_parse_mem32_option(option, &res->data.memory32);
481 break;
482 case ACPI_RSTYPE_FIXED_MEM32:
483 pnpacpi_parse_fixed_mem32_option(option,
484 &res->data.fixed_memory32);
485 break;
486 case ACPI_RSTYPE_START_DPF:
487 switch (res->data.start_dpf.compatibility_priority) {
488 case ACPI_GOOD_CONFIGURATION:
489 priority = PNP_RES_PRIORITY_PREFERRED;
490 break;
491
492 case ACPI_ACCEPTABLE_CONFIGURATION:
493 priority = PNP_RES_PRIORITY_ACCEPTABLE;
494 break;
495
496 case ACPI_SUB_OPTIMAL_CONFIGURATION:
497 priority = PNP_RES_PRIORITY_FUNCTIONAL;
498 break;
499 default:
500 priority = PNP_RES_PRIORITY_INVALID;
501 break;
502 }
503 /* TBD: Considering performace/robustness bits */
504 option = pnp_register_dependent_option(dev, priority);
505 if (!option)
506 return AE_ERROR;
507 parse_data->option = option;
508 break;
509 case ACPI_RSTYPE_END_DPF:
510 return AE_CTRL_TERMINATE;
511 default:
512 pnp_warn("PnPACPI: unknown resource type %d", res->id);
513 return AE_ERROR;
514 }
515
516 return AE_OK;
517}
518
519acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
520 struct pnp_dev *dev)
521{
522 acpi_status status;
523 struct acpipnp_parse_option_s parse_data;
524
525 parse_data.option = pnp_register_independent_option(dev);
526 if (!parse_data.option)
527 return AE_ERROR;
528 parse_data.dev = dev;
529 status = acpi_walk_resources(handle, METHOD_NAME__PRS,
530 pnpacpi_option_resource, &parse_data);
531
532 return status;
533}
534
535/*
536 * Set resource
537 */
538static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
539 void *data)
540{
541 int *res_cnt = (int *)data;
542 switch (res->id) {
543 case ACPI_RSTYPE_IRQ:
544 case ACPI_RSTYPE_EXT_IRQ:
545 case ACPI_RSTYPE_DMA:
546 case ACPI_RSTYPE_IO:
547 case ACPI_RSTYPE_FIXED_IO:
548 case ACPI_RSTYPE_MEM24:
549 case ACPI_RSTYPE_MEM32:
550 case ACPI_RSTYPE_FIXED_MEM32:
551#if 0
552 case ACPI_RSTYPE_ADDRESS16:
553 case ACPI_RSTYPE_ADDRESS32:
554 case ACPI_RSTYPE_ADDRESS64:
555#endif
556 (*res_cnt) ++;
557 default:
558 return AE_OK;
559 }
560 return AE_OK;
561}
562
563static acpi_status pnpacpi_type_resources(struct acpi_resource *res,
564 void *data)
565{
566 struct acpi_resource **resource = (struct acpi_resource **)data;
567 switch (res->id) {
568 case ACPI_RSTYPE_IRQ:
569 case ACPI_RSTYPE_EXT_IRQ:
570 case ACPI_RSTYPE_DMA:
571 case ACPI_RSTYPE_IO:
572 case ACPI_RSTYPE_FIXED_IO:
573 case ACPI_RSTYPE_MEM24:
574 case ACPI_RSTYPE_MEM32:
575 case ACPI_RSTYPE_FIXED_MEM32:
576#if 0
577 case ACPI_RSTYPE_ADDRESS16:
578 case ACPI_RSTYPE_ADDRESS32:
579 case ACPI_RSTYPE_ADDRESS64:
580#endif
581 (*resource)->id = res->id;
582 (*resource)++;
583 default:
584 return AE_OK;
585 }
586
587 return AE_OK;
588}
589
590int pnpacpi_build_resource_template(acpi_handle handle,
591 struct acpi_buffer *buffer)
592{
593 struct acpi_resource *resource;
594 int res_cnt = 0;
595 acpi_status status;
596
597 status = acpi_walk_resources(handle, METHOD_NAME__CRS,
598 pnpacpi_count_resources, &res_cnt);
599 if (ACPI_FAILURE(status)) {
600 pnp_err("Evaluate _CRS failed");
601 return -EINVAL;
602 }
603 if (!res_cnt)
604 return -EINVAL;
605 buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
606 buffer->pointer = pnpacpi_kmalloc(buffer->length - 1, GFP_KERNEL);
607 if (!buffer->pointer)
608 return -ENOMEM;
609 pnp_dbg("Res cnt %d", res_cnt);
610 resource = (struct acpi_resource *)buffer->pointer;
611 status = acpi_walk_resources(handle, METHOD_NAME__CRS,
612 pnpacpi_type_resources, &resource);
613 if (ACPI_FAILURE(status)) {
614 kfree(buffer->pointer);
615 pnp_err("Evaluate _CRS failed");
616 return -EINVAL;
617 }
618 /* resource will pointer the end resource now */
619 resource->id = ACPI_RSTYPE_END_TAG;
620
621 return 0;
622}
623
624static void pnpacpi_encode_irq(struct acpi_resource *resource,
625 struct resource *p)
626{
627 int edge_level, active_high_low;
628
629 decode_irq_flags(p->flags & IORESOURCE_BITS, &edge_level,
630 &active_high_low);
631 resource->id = ACPI_RSTYPE_IRQ;
632 resource->length = sizeof(struct acpi_resource);
633 resource->data.irq.edge_level = edge_level;
634 resource->data.irq.active_high_low = active_high_low;
635 if (edge_level == ACPI_EDGE_SENSITIVE)
636 resource->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
637 else
638 resource->data.irq.shared_exclusive = ACPI_SHARED;
639 resource->data.irq.number_of_interrupts = 1;
640 resource->data.irq.interrupts[0] = p->start;
641}
642
643static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
644 struct resource *p)
645{
646 int edge_level, active_high_low;
647
648 decode_irq_flags(p->flags & IORESOURCE_BITS, &edge_level,
649 &active_high_low);
650 resource->id = ACPI_RSTYPE_EXT_IRQ;
651 resource->length = sizeof(struct acpi_resource);
652 resource->data.extended_irq.producer_consumer = ACPI_CONSUMER;
653 resource->data.extended_irq.edge_level = edge_level;
654 resource->data.extended_irq.active_high_low = active_high_low;
655 if (edge_level == ACPI_EDGE_SENSITIVE)
656 resource->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
657 else
658 resource->data.irq.shared_exclusive = ACPI_SHARED;
659 resource->data.extended_irq.number_of_interrupts = 1;
660 resource->data.extended_irq.interrupts[0] = p->start;
661}
662
663static void pnpacpi_encode_dma(struct acpi_resource *resource,
664 struct resource *p)
665{
666 resource->id = ACPI_RSTYPE_DMA;
667 resource->length = sizeof(struct acpi_resource);
668 /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
669 if (p->flags & IORESOURCE_DMA_COMPATIBLE)
670 resource->data.dma.type = ACPI_COMPATIBILITY;
671 else if (p->flags & IORESOURCE_DMA_TYPEA)
672 resource->data.dma.type = ACPI_TYPE_A;
673 else if (p->flags & IORESOURCE_DMA_TYPEB)
674 resource->data.dma.type = ACPI_TYPE_B;
675 else if (p->flags & IORESOURCE_DMA_TYPEF)
676 resource->data.dma.type = ACPI_TYPE_F;
677 if (p->flags & IORESOURCE_DMA_8BIT)
678 resource->data.dma.transfer = ACPI_TRANSFER_8;
679 else if (p->flags & IORESOURCE_DMA_8AND16BIT)
680 resource->data.dma.transfer = ACPI_TRANSFER_8_16;
681 else if (p->flags & IORESOURCE_DMA_16BIT)
682 resource->data.dma.transfer = ACPI_TRANSFER_16;
683 resource->data.dma.bus_master = p->flags & IORESOURCE_DMA_MASTER;
684 resource->data.dma.number_of_channels = 1;
685 resource->data.dma.channels[0] = p->start;
686}
687
688static void pnpacpi_encode_io(struct acpi_resource *resource,
689 struct resource *p)
690{
691 resource->id = ACPI_RSTYPE_IO;
692 resource->length = sizeof(struct acpi_resource);
693 /* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
694 resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR)?
695 ACPI_DECODE_16 : ACPI_DECODE_10;
696 resource->data.io.min_base_address = p->start;
697 resource->data.io.max_base_address = p->end;
698 resource->data.io.alignment = 0; /* Correct? */
699 resource->data.io.range_length = p->end - p->start + 1;
700}
701
702static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
703 struct resource *p)
704{
705 resource->id = ACPI_RSTYPE_FIXED_IO;
706 resource->length = sizeof(struct acpi_resource);
707 resource->data.fixed_io.base_address = p->start;
708 resource->data.fixed_io.range_length = p->end - p->start + 1;
709}
710
711static void pnpacpi_encode_mem24(struct acpi_resource *resource,
712 struct resource *p)
713{
714 resource->id = ACPI_RSTYPE_MEM24;
715 resource->length = sizeof(struct acpi_resource);
716 /* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
717 resource->data.memory24.read_write_attribute =
718 (p->flags & IORESOURCE_MEM_WRITEABLE) ?
719 ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
720 resource->data.memory24.min_base_address = p->start;
721 resource->data.memory24.max_base_address = p->end;
722 resource->data.memory24.alignment = 0;
723 resource->data.memory24.range_length = p->end - p->start + 1;
724}
725
726static void pnpacpi_encode_mem32(struct acpi_resource *resource,
727 struct resource *p)
728{
729 resource->id = ACPI_RSTYPE_MEM32;
730 resource->length = sizeof(struct acpi_resource);
731 resource->data.memory32.read_write_attribute =
732 (p->flags & IORESOURCE_MEM_WRITEABLE) ?
733 ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
734 resource->data.memory32.min_base_address = p->start;
735 resource->data.memory32.max_base_address = p->end;
736 resource->data.memory32.alignment = 0;
737 resource->data.memory32.range_length = p->end - p->start + 1;
738}
739
740static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
741 struct resource *p)
742{
743 resource->id = ACPI_RSTYPE_FIXED_MEM32;
744 resource->length = sizeof(struct acpi_resource);
745 resource->data.fixed_memory32.read_write_attribute =
746 (p->flags & IORESOURCE_MEM_WRITEABLE) ?
747 ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
748 resource->data.fixed_memory32.range_base_address = p->start;
749 resource->data.fixed_memory32.range_length = p->end - p->start + 1;
750}
751
752int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
753 struct acpi_buffer *buffer)
754{
755 int i = 0;
756 /* pnpacpi_build_resource_template allocates extra mem */
757 int res_cnt = (buffer->length - 1)/sizeof(struct acpi_resource) - 1;
758 struct acpi_resource *resource = (struct acpi_resource*)buffer->pointer;
759 int port = 0, irq = 0, dma = 0, mem = 0;
760
761 pnp_dbg("res cnt %d", res_cnt);
762 while (i < res_cnt) {
763 switch(resource->id) {
764 case ACPI_RSTYPE_IRQ:
765 pnp_dbg("Encode irq");
766 pnpacpi_encode_irq(resource,
767 &res_table->irq_resource[irq]);
768 irq++;
769 break;
770
771 case ACPI_RSTYPE_EXT_IRQ:
772 pnp_dbg("Encode ext irq");
773 pnpacpi_encode_ext_irq(resource,
774 &res_table->irq_resource[irq]);
775 irq++;
776 break;
777 case ACPI_RSTYPE_DMA:
778 pnp_dbg("Encode dma");
779 pnpacpi_encode_dma(resource,
780 &res_table->dma_resource[dma]);
781 dma ++;
782 break;
783 case ACPI_RSTYPE_IO:
784 pnp_dbg("Encode io");
785 pnpacpi_encode_io(resource,
786 &res_table->port_resource[port]);
787 port ++;
788 break;
789 case ACPI_RSTYPE_FIXED_IO:
790 pnp_dbg("Encode fixed io");
791 pnpacpi_encode_fixed_io(resource,
792 &res_table->port_resource[port]);
793 port ++;
794 break;
795 case ACPI_RSTYPE_MEM24:
796 pnp_dbg("Encode mem24");
797 pnpacpi_encode_mem24(resource,
798 &res_table->mem_resource[mem]);
799 mem ++;
800 break;
801 case ACPI_RSTYPE_MEM32:
802 pnp_dbg("Encode mem32");
803 pnpacpi_encode_mem32(resource,
804 &res_table->mem_resource[mem]);
805 mem ++;
806 break;
807 case ACPI_RSTYPE_FIXED_MEM32:
808 pnp_dbg("Encode fixed mem32");
809 pnpacpi_encode_fixed_mem32(resource,
810 &res_table->mem_resource[mem]);
811 mem ++;
812 break;
813 default: /* other type */
814 pnp_warn("unknown resource type %d", resource->id);
815 return -EINVAL;
816 }
817 resource ++;
818 i ++;
819 }
820 return 0;
821}
diff --git a/drivers/pnp/pnpbios/Kconfig b/drivers/pnp/pnpbios/Kconfig
new file mode 100644
index 000000000000..fab848cae89d
--- /dev/null
+++ b/drivers/pnp/pnpbios/Kconfig
@@ -0,0 +1,42 @@
1#
2# Plug and Play BIOS configuration
3#
4config PNPBIOS
5 bool "Plug and Play BIOS support (EXPERIMENTAL)"
6 depends on PNP && ISA && X86 && EXPERIMENTAL
7 default n
8 ---help---
9 Linux uses the PNPBIOS as defined in "Plug and Play BIOS
10 Specification Version 1.0A May 5, 1994" to autodetect built-in
11 mainboard resources (e.g. parallel port resources).
12
13 Some features (e.g. event notification, docking station information,
14 ISAPNP services) are not currently implemented.
15
16 If you would like the kernel to detect and allocate resources to
17 your mainboard devices (on some systems they are disabled by the
18 BIOS) say Y here. Also the PNPBIOS can help prevent resource
19 conflicts between mainboard devices and other bus devices.
20
21 Note: ACPI is expected to supersede PNPBIOS some day, currently it
22 co-exists nicely. If you have a non-ISA system that supports ACPI,
23 you probably don't need PNPBIOS support.
24
25config PNPBIOS_PROC_FS
26 bool "Plug and Play BIOS /proc interface"
27 depends on PNPBIOS && PROC_FS
28 ---help---
29 If you say Y here and to "/proc file system support", you will be
30 able to directly access the PNPBIOS. This includes resource
31 allocation, ESCD, and other PNPBIOS services. Using this
32 interface is potentially dangerous because the PNPBIOS driver will
33 not be notified of any resource changes made by writing directly.
34 Also some buggy systems will fault when accessing certain features
35 in the PNPBIOS /proc interface (e.g. "boot" configs).
36
37 See the latest pcmcia-cs (stand-alone package) for a nice set of
38 PNPBIOS /proc interface tools (lspnp and setpnp).
39
40 Unless you are debugging or have other specific reasons, it is
41 recommended that you say N here.
42
diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile
new file mode 100644
index 000000000000..3cd3ed760605
--- /dev/null
+++ b/drivers/pnp/pnpbios/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the kernel PNPBIOS driver.
3#
4
5pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o
6
7obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y)
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
new file mode 100644
index 000000000000..6b7583f497d0
--- /dev/null
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -0,0 +1,544 @@
1/*
2 * bioscalls.c - the lowlevel layer of the PnPBIOS driver
3 *
4 */
5
6#include <linux/types.h>
7#include <linux/module.h>
8#include <linux/init.h>
9#include <linux/linkage.h>
10#include <linux/kernel.h>
11#include <linux/pnpbios.h>
12#include <linux/device.h>
13#include <linux/pnp.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
16#include <linux/slab.h>
17#include <linux/kmod.h>
18#include <linux/completion.h>
19#include <linux/spinlock.h>
20
21#include <asm/page.h>
22#include <asm/desc.h>
23#include <asm/system.h>
24#include <asm/byteorder.h>
25
26#include "pnpbios.h"
27
28static struct {
29 u16 offset;
30 u16 segment;
31} pnp_bios_callpoint;
32
33
34/* The PnP BIOS entries in the GDT */
35#define PNP_GDT (GDT_ENTRY_PNPBIOS_BASE * 8)
36
37#define PNP_CS32 (PNP_GDT+0x00) /* segment for calling fn */
38#define PNP_CS16 (PNP_GDT+0x08) /* code segment for BIOS */
39#define PNP_DS (PNP_GDT+0x10) /* data segment for BIOS */
40#define PNP_TS1 (PNP_GDT+0x18) /* transfer data segment */
41#define PNP_TS2 (PNP_GDT+0x20) /* another data segment */
42
43/*
44 * These are some opcodes for a "static asmlinkage"
45 * As this code is *not* executed inside the linux kernel segment, but in a
46 * alias at offset 0, we need a far return that can not be compiled by
47 * default (please, prove me wrong! this is *really* ugly!)
48 * This is the only way to get the bios to return into the kernel code,
49 * because the bios code runs in 16 bit protected mode and therefore can only
50 * return to the caller if the call is within the first 64kB, and the linux
51 * kernel begins at offset 3GB...
52 */
53
54asmlinkage void pnp_bios_callfunc(void);
55
56__asm__(
57 ".text \n"
58 __ALIGN_STR "\n"
59 "pnp_bios_callfunc:\n"
60 " pushl %edx \n"
61 " pushl %ecx \n"
62 " pushl %ebx \n"
63 " pushl %eax \n"
64 " lcallw *pnp_bios_callpoint\n"
65 " addl $16, %esp \n"
66 " lret \n"
67 ".previous \n"
68);
69
70#define Q_SET_SEL(cpu, selname, address, size) \
71do { \
72set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], __va((u32)(address))); \
73set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \
74} while(0)
75
76#define Q2_SET_SEL(cpu, selname, address, size) \
77do { \
78set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], (u32)(address)); \
79set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \
80} while(0)
81
82static struct desc_struct bad_bios_desc = { 0, 0x00409200 };
83
84/*
85 * At some point we want to use this stack frame pointer to unwind
86 * after PnP BIOS oopses.
87 */
88
89u32 pnp_bios_fault_esp;
90u32 pnp_bios_fault_eip;
91u32 pnp_bios_is_utter_crap = 0;
92
93static spinlock_t pnp_bios_lock;
94
95
96/*
97 * Support Functions
98 */
99
100static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
101 u16 arg4, u16 arg5, u16 arg6, u16 arg7,
102 void *ts1_base, u32 ts1_size,
103 void *ts2_base, u32 ts2_size)
104{
105 unsigned long flags;
106 u16 status;
107 struct desc_struct save_desc_40;
108 int cpu;
109
110 /*
111 * PnP BIOSes are generally not terribly re-entrant.
112 * Also, don't rely on them to save everything correctly.
113 */
114 if(pnp_bios_is_utter_crap)
115 return PNP_FUNCTION_NOT_SUPPORTED;
116
117 cpu = get_cpu();
118 save_desc_40 = per_cpu(cpu_gdt_table,cpu)[0x40 / 8];
119 per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = bad_bios_desc;
120
121 /* On some boxes IRQ's during PnP BIOS calls are deadly. */
122 spin_lock_irqsave(&pnp_bios_lock, flags);
123
124 /* The lock prevents us bouncing CPU here */
125 if (ts1_size)
126 Q2_SET_SEL(smp_processor_id(), PNP_TS1, ts1_base, ts1_size);
127 if (ts2_size)
128 Q2_SET_SEL(smp_processor_id(), PNP_TS2, ts2_base, ts2_size);
129
130 __asm__ __volatile__(
131 "pushl %%ebp\n\t"
132 "pushl %%edi\n\t"
133 "pushl %%esi\n\t"
134 "pushl %%ds\n\t"
135 "pushl %%es\n\t"
136 "pushl %%fs\n\t"
137 "pushl %%gs\n\t"
138 "pushfl\n\t"
139 "movl %%esp, pnp_bios_fault_esp\n\t"
140 "movl $1f, pnp_bios_fault_eip\n\t"
141 "lcall %5,%6\n\t"
142 "1:popfl\n\t"
143 "popl %%gs\n\t"
144 "popl %%fs\n\t"
145 "popl %%es\n\t"
146 "popl %%ds\n\t"
147 "popl %%esi\n\t"
148 "popl %%edi\n\t"
149 "popl %%ebp\n\t"
150 : "=a" (status)
151 : "0" ((func) | (((u32)arg1) << 16)),
152 "b" ((arg2) | (((u32)arg3) << 16)),
153 "c" ((arg4) | (((u32)arg5) << 16)),
154 "d" ((arg6) | (((u32)arg7) << 16)),
155 "i" (PNP_CS32),
156 "i" (0)
157 : "memory"
158 );
159 spin_unlock_irqrestore(&pnp_bios_lock, flags);
160
161 per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = save_desc_40;
162 put_cpu();
163
164 /* If we get here and this is set then the PnP BIOS faulted on us. */
165 if(pnp_bios_is_utter_crap)
166 {
167 printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
168 printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably\n");
169 printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
170 }
171
172 return status;
173}
174
175void pnpbios_print_status(const char * module, u16 status)
176{
177 switch(status) {
178 case PNP_SUCCESS:
179 printk(KERN_ERR "PnPBIOS: %s: function successful\n", module);
180 break;
181 case PNP_NOT_SET_STATICALLY:
182 printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n", module);
183 break;
184 case PNP_UNKNOWN_FUNCTION:
185 printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n", module);
186 break;
187 case PNP_FUNCTION_NOT_SUPPORTED:
188 printk(KERN_ERR "PnPBIOS: %s: function not supported on this system\n", module);
189 break;
190 case PNP_INVALID_HANDLE:
191 printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module);
192 break;
193 case PNP_BAD_PARAMETER:
194 printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n", module);
195 break;
196 case PNP_SET_FAILED:
197 printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n", module);
198 break;
199 case PNP_EVENTS_NOT_PENDING:
200 printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module);
201 break;
202 case PNP_SYSTEM_NOT_DOCKED:
203 printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n", module);
204 break;
205 case PNP_NO_ISA_PNP_CARDS:
206 printk(KERN_ERR "PnPBIOS: %s: no isapnp cards are installed on this system\n", module);
207 break;
208 case PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES:
209 printk(KERN_ERR "PnPBIOS: %s: cannot determine the capabilities of the docking station\n", module);
210 break;
211 case PNP_CONFIG_CHANGE_FAILED_NO_BATTERY:
212 printk(KERN_ERR "PnPBIOS: %s: unable to undock, the system does not have a battery\n", module);
213 break;
214 case PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT:
215 printk(KERN_ERR "PnPBIOS: %s: could not dock due to resource conflicts\n", module);
216 break;
217 case PNP_BUFFER_TOO_SMALL:
218 printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n", module);
219 break;
220 case PNP_USE_ESCD_SUPPORT:
221 printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module);
222 break;
223 case PNP_MESSAGE_NOT_SUPPORTED:
224 printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n", module);
225 break;
226 case PNP_HARDWARE_ERROR:
227 printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", module);
228 break;
229 default:
230 printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module, status);
231 break;
232 }
233}
234
235
236/*
237 * PnP BIOS Low Level Calls
238 */
239
240#define PNP_GET_NUM_SYS_DEV_NODES 0x00
241#define PNP_GET_SYS_DEV_NODE 0x01
242#define PNP_SET_SYS_DEV_NODE 0x02
243#define PNP_GET_EVENT 0x03
244#define PNP_SEND_MESSAGE 0x04
245#define PNP_GET_DOCKING_STATION_INFORMATION 0x05
246#define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09
247#define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a
248#define PNP_GET_APM_ID_TABLE 0x0b
249#define PNP_GET_PNP_ISA_CONFIG_STRUC 0x40
250#define PNP_GET_ESCD_INFO 0x41
251#define PNP_READ_ESCD 0x42
252#define PNP_WRITE_ESCD 0x43
253
254/*
255 * Call PnP BIOS with function 0x00, "get number of system device nodes"
256 */
257static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
258{
259 u16 status;
260 if (!pnp_bios_present())
261 return PNP_FUNCTION_NOT_SUPPORTED;
262 status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0,
263 data, sizeof(struct pnp_dev_node_info), NULL, 0);
264 data->no_nodes &= 0xff;
265 return status;
266}
267
268int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
269{
270 int status = __pnp_bios_dev_node_info( data );
271 if ( status )
272 pnpbios_print_status( "dev_node_info", status );
273 return status;
274}
275
276/*
277 * Note that some PnP BIOSes (e.g., on Sony Vaio laptops) die a horrible
278 * death if they are asked to access the "current" configuration.
279 * Therefore, if it's a matter of indifference, it's better to call
280 * get_dev_node() and set_dev_node() with boot=1 rather than with boot=0.
281 */
282
283/*
284 * Call PnP BIOS with function 0x01, "get system device node"
285 * Input: *nodenum = desired node,
286 * boot = whether to get nonvolatile boot (!=0)
287 * or volatile current (0) config
288 * Output: *nodenum=next node or 0xff if no more nodes
289 */
290static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
291{
292 u16 status;
293 if (!pnp_bios_present())
294 return PNP_FUNCTION_NOT_SUPPORTED;
295 if ( !boot && pnpbios_dont_use_current_config )
296 return PNP_FUNCTION_NOT_SUPPORTED;
297 status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0,
298 nodenum, sizeof(char), data, 65536);
299 return status;
300}
301
302int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
303{
304 int status;
305 status = __pnp_bios_get_dev_node( nodenum, boot, data );
306 if ( status )
307 pnpbios_print_status( "get_dev_node", status );
308 return status;
309}
310
311
312/*
313 * Call PnP BIOS with function 0x02, "set system device node"
314 * Input: *nodenum = desired node,
315 * boot = whether to set nonvolatile boot (!=0)
316 * or volatile current (0) config
317 */
318static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
319{
320 u16 status;
321 if (!pnp_bios_present())
322 return PNP_FUNCTION_NOT_SUPPORTED;
323 if ( !boot && pnpbios_dont_use_current_config )
324 return PNP_FUNCTION_NOT_SUPPORTED;
325 status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0,
326 data, 65536, NULL, 0);
327 return status;
328}
329
330int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
331{
332 int status;
333 status = __pnp_bios_set_dev_node( nodenum, boot, data );
334 if ( status ) {
335 pnpbios_print_status( "set_dev_node", status );
336 return status;
337 }
338 if ( !boot ) { /* Update devlist */
339 status = pnp_bios_get_dev_node( &nodenum, boot, data );
340 if ( status )
341 return status;
342 }
343 return status;
344}
345
346#if needed
347/*
348 * Call PnP BIOS with function 0x03, "get event"
349 */
350static int pnp_bios_get_event(u16 *event)
351{
352 u16 status;
353 if (!pnp_bios_present())
354 return PNP_FUNCTION_NOT_SUPPORTED;
355 status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0,
356 event, sizeof(u16), NULL, 0);
357 return status;
358}
359#endif
360
361#if needed
362/*
363 * Call PnP BIOS with function 0x04, "send message"
364 */
365static int pnp_bios_send_message(u16 message)
366{
367 u16 status;
368 if (!pnp_bios_present())
369 return PNP_FUNCTION_NOT_SUPPORTED;
370 status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0, 0, 0, 0, 0);
371 return status;
372}
373#endif
374
375/*
376 * Call PnP BIOS with function 0x05, "get docking station information"
377 */
378int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
379{
380 u16 status;
381 if (!pnp_bios_present())
382 return PNP_FUNCTION_NOT_SUPPORTED;
383 status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
384 data, sizeof(struct pnp_docking_station_info), NULL, 0);
385 return status;
386}
387
388#if needed
389/*
390 * Call PnP BIOS with function 0x09, "set statically allocated resource
391 * information"
392 */
393static int pnp_bios_set_stat_res(char *info)
394{
395 u16 status;
396 if (!pnp_bios_present())
397 return PNP_FUNCTION_NOT_SUPPORTED;
398 status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
399 info, *((u16 *) info), 0, 0);
400 return status;
401}
402#endif
403
404/*
405 * Call PnP BIOS with function 0x0a, "get statically allocated resource
406 * information"
407 */
408static int __pnp_bios_get_stat_res(char *info)
409{
410 u16 status;
411 if (!pnp_bios_present())
412 return PNP_FUNCTION_NOT_SUPPORTED;
413 status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
414 info, 65536, NULL, 0);
415 return status;
416}
417
418int pnp_bios_get_stat_res(char *info)
419{
420 int status;
421 status = __pnp_bios_get_stat_res( info );
422 if ( status )
423 pnpbios_print_status( "get_stat_res", status );
424 return status;
425}
426
427#if needed
428/*
429 * Call PnP BIOS with function 0x0b, "get APM id table"
430 */
431static int pnp_bios_apm_id_table(char *table, u16 *size)
432{
433 u16 status;
434 if (!pnp_bios_present())
435 return PNP_FUNCTION_NOT_SUPPORTED;
436 status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0,
437 table, *size, size, sizeof(u16));
438 return status;
439}
440#endif
441
442/*
443 * Call PnP BIOS with function 0x40, "get isa pnp configuration structure"
444 */
445static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
446{
447 u16 status;
448 if (!pnp_bios_present())
449 return PNP_FUNCTION_NOT_SUPPORTED;
450 status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
451 data, sizeof(struct pnp_isa_config_struc), NULL, 0);
452 return status;
453}
454
455int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
456{
457 int status;
458 status = __pnp_bios_isapnp_config( data );
459 if ( status )
460 pnpbios_print_status( "isapnp_config", status );
461 return status;
462}
463
464/*
465 * Call PnP BIOS with function 0x41, "get ESCD info"
466 */
467static int __pnp_bios_escd_info(struct escd_info_struc *data)
468{
469 u16 status;
470 if (!pnp_bios_present())
471 return ESCD_FUNCTION_NOT_SUPPORTED;
472 status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS,
473 data, sizeof(struct escd_info_struc), NULL, 0);
474 return status;
475}
476
477int pnp_bios_escd_info(struct escd_info_struc *data)
478{
479 int status;
480 status = __pnp_bios_escd_info( data );
481 if ( status )
482 pnpbios_print_status( "escd_info", status );
483 return status;
484}
485
486/*
487 * Call PnP BIOS function 0x42, "read ESCD"
488 * nvram_base is determined by calling escd_info
489 */
490static int __pnp_bios_read_escd(char *data, u32 nvram_base)
491{
492 u16 status;
493 if (!pnp_bios_present())
494 return ESCD_FUNCTION_NOT_SUPPORTED;
495 status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
496 data, 65536, __va(nvram_base), 65536);
497 return status;
498}
499
500int pnp_bios_read_escd(char *data, u32 nvram_base)
501{
502 int status;
503 status = __pnp_bios_read_escd( data, nvram_base );
504 if ( status )
505 pnpbios_print_status( "read_escd", status );
506 return status;
507}
508
509#if needed
510/*
511 * Call PnP BIOS function 0x43, "write ESCD"
512 */
513static int pnp_bios_write_escd(char *data, u32 nvram_base)
514{
515 u16 status;
516 if (!pnp_bios_present())
517 return ESCD_FUNCTION_NOT_SUPPORTED;
518 status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
519 data, 65536, __va(nvram_base), 65536);
520 return status;
521}
522#endif
523
524
525/*
526 * Initialization
527 */
528
529void pnpbios_calls_init(union pnp_bios_install_struct *header)
530{
531 int i;
532 spin_lock_init(&pnp_bios_lock);
533 pnp_bios_callpoint.offset = header->fields.pm16offset;
534 pnp_bios_callpoint.segment = PNP_CS16;
535
536 set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
537 _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
538 for(i=0; i < NR_CPUS; i++)
539 {
540 Q2_SET_SEL(i, PNP_CS32, &pnp_bios_callfunc, 64 * 1024);
541 Q_SET_SEL(i, PNP_CS16, header->fields.pm16cseg, 64 * 1024);
542 Q_SET_SEL(i, PNP_DS, header->fields.pm16dseg, 64 * 1024);
543 }
544}
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
new file mode 100644
index 000000000000..0f6330b3af12
--- /dev/null
+++ b/drivers/pnp/pnpbios/core.c
@@ -0,0 +1,644 @@
1/*
2 * pnpbios -- PnP BIOS driver
3 *
4 * This driver provides access to Plug-'n'-Play services provided by
5 * the PnP BIOS firmware, described in the following documents:
6 * Plug and Play BIOS Specification, Version 1.0A, 5 May 1994
7 * Plug and Play BIOS Clarification Paper, 6 October 1994
8 * Compaq Computer Corporation, Phoenix Technologies Ltd., Intel Corp.
9 *
10 * Originally (C) 1998 Christian Schmidt <schmidt@digadd.de>
11 * Modifications (C) 1998 Tom Lees <tom@lpsg.demon.co.uk>
12 * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
13 * Further modifications (C) 2001, 2002 by:
14 * Alan Cox <alan@redhat.com>
15 * Thomas Hood
16 * Brian Gerst <bgerst@didntduck.org>
17 *
18 * Ported to the PnP Layer and several additional improvements (C) 2002
19 * by Adam Belay <ambx1@neo.rr.com>
20 *
21 * This program is free software; you can redistribute it and/or modify it
22 * under the terms of the GNU General Public License as published by the
23 * Free Software Foundation; either version 2, or (at your option) any
24 * later version.
25 *
26 * This program is distributed in the hope that it will be useful, but
27 * WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 * General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 */
35
36/* Change Log
37 *
38 * Adam Belay - <ambx1@neo.rr.com> - March 16, 2003
39 * rev 1.01 Only call pnp_bios_dev_node_info once
40 * Added pnpbios_print_status
41 * Added several new error messages and info messages
42 * Added pnpbios_interface_attach_device
43 * integrated core and proc init system
44 * Introduced PNPMODE flags
45 * Removed some useless includes
46 */
47
48#include <linux/types.h>
49#include <linux/module.h>
50#include <linux/init.h>
51#include <linux/linkage.h>
52#include <linux/kernel.h>
53#include <linux/pnpbios.h>
54#include <linux/device.h>
55#include <linux/pnp.h>
56#include <linux/mm.h>
57#include <linux/smp.h>
58#include <linux/slab.h>
59#include <linux/kobject_uevent.h>
60#include <linux/completion.h>
61#include <linux/spinlock.h>
62#include <linux/dmi.h>
63#include <linux/delay.h>
64#include <linux/acpi.h>
65
66#include <asm/page.h>
67#include <asm/desc.h>
68#include <asm/system.h>
69#include <asm/byteorder.h>
70
71#include "pnpbios.h"
72
73
74/*
75 *
76 * PnP BIOS INTERFACE
77 *
78 */
79
80static union pnp_bios_install_struct * pnp_bios_install = NULL;
81
82int pnp_bios_present(void)
83{
84 return (pnp_bios_install != NULL);
85}
86
87struct pnp_dev_node_info node_info;
88
89void *pnpbios_kmalloc(size_t size, int f)
90{
91 void *p = kmalloc( size, f );
92 if ( p == NULL )
93 printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
94 else
95 memset(p, 0, size);
96 return p;
97}
98
99/*
100 *
101 * DOCKING FUNCTIONS
102 *
103 */
104
105#ifdef CONFIG_HOTPLUG
106
107static int unloading = 0;
108static struct completion unload_sem;
109
110/*
111 * (Much of this belongs in a shared routine somewhere)
112 */
113
114static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
115{
116 char *argv [3], **envp, *buf, *scratch;
117 int i = 0, value;
118
119 if (!hotplug_path [0])
120 return -ENOENT;
121 if (!current->fs->root) {
122 return -EAGAIN;
123 }
124 if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
125 return -ENOMEM;
126 }
127 if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
128 kfree (envp);
129 return -ENOMEM;
130 }
131
132 /* only one standardized param to hotplug command: type */
133 argv [0] = hotplug_path;
134 argv [1] = "dock";
135 argv [2] = NULL;
136
137 /* minimal command environment */
138 envp [i++] = "HOME=/";
139 envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
140
141#ifdef DEBUG
142 /* hint that policy agent should enter no-stdout debug mode */
143 envp [i++] = "DEBUG=kernel";
144#endif
145 /* extensible set of named bus-specific parameters,
146 * supporting multiple driver selection algorithms.
147 */
148 scratch = buf;
149
150 /* action: add, remove */
151 envp [i++] = scratch;
152 scratch += sprintf (scratch, "ACTION=%s", dock?"add":"remove") + 1;
153
154 /* Report the ident for the dock */
155 envp [i++] = scratch;
156 scratch += sprintf (scratch, "DOCK=%x/%x/%x",
157 info->location_id, info->serial, info->capabilities);
158 envp[i] = NULL;
159
160 value = call_usermodehelper (argv [0], argv, envp, 0);
161 kfree (buf);
162 kfree (envp);
163 return 0;
164}
165
166/*
167 * Poll the PnP docking at regular intervals
168 */
169static int pnp_dock_thread(void * unused)
170{
171 static struct pnp_docking_station_info now;
172 int docked = -1, d = 0;
173 daemonize("kpnpbiosd");
174 allow_signal(SIGKILL);
175 while(!unloading && !signal_pending(current))
176 {
177 int status;
178
179 /*
180 * Poll every 2 seconds
181 */
182 msleep_interruptible(2000);
183
184 if(signal_pending(current)) {
185 if (try_to_freeze(PF_FREEZE))
186 continue;
187 break;
188 }
189
190 status = pnp_bios_dock_station_info(&now);
191
192 switch(status)
193 {
194 /*
195 * No dock to manage
196 */
197 case PNP_FUNCTION_NOT_SUPPORTED:
198 complete_and_exit(&unload_sem, 0);
199 case PNP_SYSTEM_NOT_DOCKED:
200 d = 0;
201 break;
202 case PNP_SUCCESS:
203 d = 1;
204 break;
205 default:
206 pnpbios_print_status( "pnp_dock_thread", status );
207 continue;
208 }
209 if(d != docked)
210 {
211 if(pnp_dock_event(d, &now)==0)
212 {
213 docked = d;
214#if 0
215 printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de");
216#endif
217 }
218 }
219 }
220 complete_and_exit(&unload_sem, 0);
221}
222
223#endif /* CONFIG_HOTPLUG */
224
225static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
226{
227 u8 nodenum = dev->number;
228 struct pnp_bios_node * node;
229
230 /* just in case */
231 if(!pnpbios_is_dynamic(dev))
232 return -EPERM;
233
234 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
235 if (!node)
236 return -1;
237 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
238 kfree(node);
239 return -ENODEV;
240 }
241 pnpbios_read_resources_from_node(res, node);
242 dev->active = pnp_is_active(dev);
243 kfree(node);
244 return 0;
245}
246
247static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
248{
249 u8 nodenum = dev->number;
250 struct pnp_bios_node * node;
251 int ret;
252
253 /* just in case */
254 if (!pnpbios_is_dynamic(dev))
255 return -EPERM;
256
257 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
258 if (!node)
259 return -1;
260 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
261 kfree(node);
262 return -ENODEV;
263 }
264 if(pnpbios_write_resources_to_node(res, node)<0) {
265 kfree(node);
266 return -1;
267 }
268 ret = pnp_bios_set_dev_node(node->handle, (char)PNPMODE_DYNAMIC, node);
269 kfree(node);
270 if (ret > 0)
271 ret = -1;
272 return ret;
273}
274
275static void pnpbios_zero_data_stream(struct pnp_bios_node * node)
276{
277 unsigned char * p = (char *)node->data;
278 unsigned char * end = (char *)(node->data + node->size);
279 unsigned int len;
280 int i;
281 while ((char *)p < (char *)end) {
282 if(p[0] & 0x80) { /* large tag */
283 len = (p[2] << 8) | p[1];
284 p += 3;
285 } else {
286 if (((p[0]>>3) & 0x0f) == 0x0f)
287 return;
288 len = p[0] & 0x07;
289 p += 1;
290 }
291 for (i = 0; i < len; i++)
292 p[i] = 0;
293 p += len;
294 }
295 printk(KERN_ERR "PnPBIOS: Resource structure did not contain an end tag.\n");
296}
297
298static int pnpbios_disable_resources(struct pnp_dev *dev)
299{
300 struct pnp_bios_node * node;
301 u8 nodenum = dev->number;
302 int ret;
303
304 /* just in case */
305 if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
306 return -EPERM;
307
308 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
309 if (!node)
310 return -ENOMEM;
311
312 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
313 kfree(node);
314 return -ENODEV;
315 }
316 pnpbios_zero_data_stream(node);
317
318 ret = pnp_bios_set_dev_node(dev->number, (char)PNPMODE_DYNAMIC, node);
319 kfree(node);
320 if (ret > 0)
321 ret = -1;
322 return ret;
323}
324
325/* PnP Layer support */
326
327struct pnp_protocol pnpbios_protocol = {
328 .name = "Plug and Play BIOS",
329 .get = pnpbios_get_resources,
330 .set = pnpbios_set_resources,
331 .disable = pnpbios_disable_resources,
332};
333
334static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
335{
336 struct list_head * pos;
337 struct pnp_dev * pnp_dev;
338 struct pnp_id *dev_id;
339 char id[8];
340
341 /* check if the device is already added */
342 dev->number = node->handle;
343 list_for_each (pos, &pnpbios_protocol.devices){
344 pnp_dev = list_entry(pos, struct pnp_dev, protocol_list);
345 if (dev->number == pnp_dev->number)
346 return -1;
347 }
348
349 /* set the initial values for the PnP device */
350 dev_id = pnpbios_kmalloc(sizeof(struct pnp_id), GFP_KERNEL);
351 if (!dev_id)
352 return -1;
353 pnpid32_to_pnpid(node->eisa_id,id);
354 memcpy(dev_id->id,id,7);
355 pnp_add_id(dev_id, dev);
356 pnpbios_parse_data_stream(dev, node);
357 dev->active = pnp_is_active(dev);
358 dev->flags = node->flags;
359 if (!(dev->flags & PNPBIOS_NO_CONFIG))
360 dev->capabilities |= PNP_CONFIGURABLE;
361 if (!(dev->flags & PNPBIOS_NO_DISABLE))
362 dev->capabilities |= PNP_DISABLE;
363 dev->capabilities |= PNP_READ;
364 if (pnpbios_is_dynamic(dev))
365 dev->capabilities |= PNP_WRITE;
366 if (dev->flags & PNPBIOS_REMOVABLE)
367 dev->capabilities |= PNP_REMOVABLE;
368 dev->protocol = &pnpbios_protocol;
369
370 /* clear out the damaged flags */
371 if (!dev->active)
372 pnp_init_resource_table(&dev->res);
373
374 pnp_add_device(dev);
375 pnpbios_interface_attach_device(node);
376
377 return 0;
378}
379
380static void __init build_devlist(void)
381{
382 u8 nodenum;
383 unsigned int nodes_got = 0;
384 unsigned int devs = 0;
385 struct pnp_bios_node *node;
386 struct pnp_dev *dev;
387
388 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
389 if (!node)
390 return;
391
392 for(nodenum=0; nodenum<0xff; ) {
393 u8 thisnodenum = nodenum;
394 /* eventually we will want to use PNPMODE_STATIC here but for now
395 * dynamic will help us catch buggy bioses to add to the blacklist.
396 */
397 if (!pnpbios_dont_use_current_config) {
398 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node))
399 break;
400 } else {
401 if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_STATIC, node))
402 break;
403 }
404 nodes_got++;
405 dev = pnpbios_kmalloc(sizeof (struct pnp_dev), GFP_KERNEL);
406 if (!dev)
407 break;
408 if(insert_device(dev,node)<0)
409 kfree(dev);
410 else
411 devs++;
412 if (nodenum <= thisnodenum) {
413 printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum);
414 break;
415 }
416 }
417 kfree(node);
418
419 printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
420 nodes_got, nodes_got != 1 ? "s" : "", devs);
421}
422
423/*
424 *
425 * INIT AND EXIT
426 *
427 */
428
429static int pnpbios_disabled; /* = 0 */
430int pnpbios_dont_use_current_config; /* = 0 */
431
432#ifndef MODULE
433static int __init pnpbios_setup(char *str)
434{
435 int invert;
436
437 while ((str != NULL) && (*str != '\0')) {
438 if (strncmp(str, "off", 3) == 0)
439 pnpbios_disabled=1;
440 if (strncmp(str, "on", 2) == 0)
441 pnpbios_disabled=0;
442 invert = (strncmp(str, "no-", 3) == 0);
443 if (invert)
444 str += 3;
445 if (strncmp(str, "curr", 4) == 0)
446 pnpbios_dont_use_current_config = invert;
447 str = strchr(str, ',');
448 if (str != NULL)
449 str += strspn(str, ", \t");
450 }
451
452 return 1;
453}
454
455__setup("pnpbios=", pnpbios_setup);
456#endif
457
458/* PnP BIOS signature: "$PnP" */
459#define PNP_SIGNATURE (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
460
461static int __init pnpbios_probe_system(void)
462{
463 union pnp_bios_install_struct *check;
464 u8 sum;
465 int length, i;
466
467 printk(KERN_INFO "PnPBIOS: Scanning system for PnP BIOS support...\n");
468
469 /*
470 * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
471 * structure and, if one is found, sets up the selectors and
472 * entry points
473 */
474 for (check = (union pnp_bios_install_struct *) __va(0xf0000);
475 check < (union pnp_bios_install_struct *) __va(0xffff0);
476 check = (void *)check + 16) {
477 if (check->fields.signature != PNP_SIGNATURE)
478 continue;
479 printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check);
480 length = check->fields.length;
481 if (!length) {
482 printk(KERN_ERR "PnPBIOS: installation structure is invalid, skipping\n");
483 continue;
484 }
485 for (sum = 0, i = 0; i < length; i++)
486 sum += check->chars[i];
487 if (sum) {
488 printk(KERN_ERR "PnPBIOS: installation structure is corrupted, skipping\n");
489 continue;
490 }
491 if (check->fields.version < 0x10) {
492 printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
493 check->fields.version >> 4,
494 check->fields.version & 15);
495 continue;
496 }
497 printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
498 check->fields.version >> 4, check->fields.version & 15,
499 check->fields.pm16cseg, check->fields.pm16offset,
500 check->fields.pm16dseg);
501 pnp_bios_install = check;
502 return 1;
503 }
504
505 printk(KERN_INFO "PnPBIOS: PnP BIOS support was not detected.\n");
506 return 0;
507}
508
509static int __init exploding_pnp_bios(struct dmi_system_id *d)
510{
511 printk(KERN_WARNING "%s detected. Disabling PnPBIOS\n", d->ident);
512 return 0;
513}
514
515static struct dmi_system_id pnpbios_dmi_table[] = {
516 { /* PnPBIOS GPF on boot */
517 .callback = exploding_pnp_bios,
518 .ident = "Higraded P14H",
519 .matches = {
520 DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
521 DMI_MATCH(DMI_BIOS_VERSION, "07.00T"),
522 DMI_MATCH(DMI_SYS_VENDOR, "Higraded"),
523 DMI_MATCH(DMI_PRODUCT_NAME, "P14H"),
524 },
525 },
526 { /* PnPBIOS GPF on boot */
527 .callback = exploding_pnp_bios,
528 .ident = "ASUS P4P800",
529 .matches = {
530 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
531 DMI_MATCH(DMI_BOARD_NAME, "P4P800"),
532 },
533 },
534 { }
535};
536
537static int __init pnpbios_init(void)
538{
539 int ret;
540
541 if (pnpbios_disabled || dmi_check_system(pnpbios_dmi_table)) {
542 printk(KERN_INFO "PnPBIOS: Disabled\n");
543 return -ENODEV;
544 }
545
546#ifdef CONFIG_PNPACPI
547 if (!acpi_disabled && !pnpacpi_disabled) {
548 pnpbios_disabled = 1;
549 printk(KERN_INFO "PnPBIOS: Disabled by ACPI PNP\n");
550 return -ENODEV;
551 }
552#endif /* CONFIG_ACPI */
553
554 /* scan the system for pnpbios support */
555 if (!pnpbios_probe_system())
556 return -ENODEV;
557
558 /* make preparations for bios calls */
559 pnpbios_calls_init(pnp_bios_install);
560
561 /* read the node info */
562 ret = pnp_bios_dev_node_info(&node_info);
563 if (ret) {
564 printk(KERN_ERR "PnPBIOS: Unable to get node info. Aborting.\n");
565 return ret;
566 }
567
568 /* register with the pnp layer */
569 ret = pnp_register_protocol(&pnpbios_protocol);
570 if (ret) {
571 printk(KERN_ERR "PnPBIOS: Unable to register driver. Aborting.\n");
572 return ret;
573 }
574
575 /* start the proc interface */
576 ret = pnpbios_proc_init();
577 if (ret)
578 printk(KERN_ERR "PnPBIOS: Failed to create proc interface.\n");
579
580 /* scan for pnpbios devices */
581 build_devlist();
582
583 return 0;
584}
585
586subsys_initcall(pnpbios_init);
587
588static int __init pnpbios_thread_init(void)
589{
590 if (pnpbios_disabled)
591 return 0;
592#ifdef CONFIG_HOTPLUG
593 init_completion(&unload_sem);
594 if (kernel_thread(pnp_dock_thread, NULL, CLONE_KERNEL) > 0)
595 unloading = 0;
596#endif
597 return 0;
598}
599
600#ifndef MODULE
601
602/* init/main.c calls pnpbios_init early */
603
604/* Start the kernel thread later: */
605module_init(pnpbios_thread_init);
606
607#else
608
609/*
610 * N.B.: Building pnpbios as a module hasn't been fully implemented
611 */
612
613MODULE_LICENSE("GPL");
614
615static int __init pnpbios_init_all(void)
616{
617 int r;
618
619 r = pnpbios_init();
620 if (r)
621 return r;
622 r = pnpbios_thread_init();
623 if (r)
624 return r;
625 return 0;
626}
627
628static void __exit pnpbios_exit(void)
629{
630#ifdef CONFIG_HOTPLUG
631 unloading = 1;
632 wait_for_completion(&unload_sem);
633#endif
634 pnpbios_proc_exit();
635 /* We ought to free resources here */
636 return;
637}
638
639module_init(pnpbios_init_all);
640module_exit(pnpbios_exit);
641
642#endif
643
644EXPORT_SYMBOL(pnpbios_protocol);
diff --git a/drivers/pnp/pnpbios/pnpbios.h b/drivers/pnp/pnpbios/pnpbios.h
new file mode 100644
index 000000000000..01896e705ed4
--- /dev/null
+++ b/drivers/pnp/pnpbios/pnpbios.h
@@ -0,0 +1,47 @@
1/*
2 * pnpbios.h - contains local definitions
3 */
4
5#pragma pack(1)
6union pnp_bios_install_struct {
7 struct {
8 u32 signature; /* "$PnP" */
9 u8 version; /* in BCD */
10 u8 length; /* length in bytes, currently 21h */
11 u16 control; /* system capabilities */
12 u8 checksum; /* all bytes must add up to 0 */
13
14 u32 eventflag; /* phys. address of the event flag */
15 u16 rmoffset; /* real mode entry point */
16 u16 rmcseg;
17 u16 pm16offset; /* 16 bit protected mode entry */
18 u32 pm16cseg;
19 u32 deviceID; /* EISA encoded system ID or 0 */
20 u16 rmdseg; /* real mode data segment */
21 u32 pm16dseg; /* 16 bit pm data segment base */
22 } fields;
23 char chars[0x21]; /* To calculate the checksum */
24};
25#pragma pack()
26
27extern int pnp_bios_present(void);
28extern int pnpbios_dont_use_current_config;
29extern void *pnpbios_kmalloc(size_t size, int f);
30
31extern int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node);
32extern int pnpbios_read_resources_from_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
33extern int pnpbios_write_resources_to_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
34extern void pnpid32_to_pnpid(u32 id, char *str);
35
36extern void pnpbios_print_status(const char * module, u16 status);
37extern void pnpbios_calls_init(union pnp_bios_install_struct * header);
38
39#ifdef CONFIG_PNPBIOS_PROC_FS
40extern int pnpbios_interface_attach_device(struct pnp_bios_node * node);
41extern int pnpbios_proc_init (void);
42extern void pnpbios_proc_exit (void);
43#else
44static inline int pnpbios_interface_attach_device(struct pnp_bios_node * node) { return 0; }
45static inline int pnpbios_proc_init (void) { return 0; }
46static inline void pnpbios_proc_exit (void) { ; }
47#endif /* CONFIG_PNPBIOS_PROC_FS */
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
new file mode 100644
index 000000000000..6bb8e1973fd4
--- /dev/null
+++ b/drivers/pnp/pnpbios/proc.c
@@ -0,0 +1,292 @@
1/*
2 * /proc/bus/pnp interface for Plug and Play devices
3 *
4 * Written by David Hinds, dahinds@users.sourceforge.net
5 * Modified by Thomas Hood
6 *
7 * The .../devices and .../<node> and .../boot/<node> files are
8 * utilized by the lspnp and setpnp utilities, supplied with the
9 * pcmcia-cs package.
10 * http://pcmcia-cs.sourceforge.net
11 *
12 * The .../escd file is utilized by the lsescd utility written by
13 * Gunther Mayer.
14 * http://home.t-online.de/home/gunther.mayer/lsescd
15 *
16 * The .../legacy_device_resources file is not used yet.
17 *
18 * The other files are human-readable.
19 */
20
21//#include <pcmcia/config.h>
22//#include <pcmcia/k_compat.h>
23
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/slab.h>
27#include <linux/types.h>
28#include <linux/proc_fs.h>
29#include <linux/pnpbios.h>
30#include <linux/init.h>
31
32#include <asm/uaccess.h>
33
34#include "pnpbios.h"
35
36static struct proc_dir_entry *proc_pnp = NULL;
37static struct proc_dir_entry *proc_pnp_boot = NULL;
38
39static int proc_read_pnpconfig(char *buf, char **start, off_t pos,
40 int count, int *eof, void *data)
41{
42 struct pnp_isa_config_struc pnps;
43
44 if (pnp_bios_isapnp_config(&pnps))
45 return -EIO;
46 return snprintf(buf, count,
47 "structure_revision %d\n"
48 "number_of_CSNs %d\n"
49 "ISA_read_data_port 0x%x\n",
50 pnps.revision,
51 pnps.no_csns,
52 pnps.isa_rd_data_port
53 );
54}
55
56static int proc_read_escdinfo(char *buf, char **start, off_t pos,
57 int count, int *eof, void *data)
58{
59 struct escd_info_struc escd;
60
61 if (pnp_bios_escd_info(&escd))
62 return -EIO;
63 return snprintf(buf, count,
64 "min_ESCD_write_size %d\n"
65 "ESCD_size %d\n"
66 "NVRAM_base 0x%x\n",
67 escd.min_escd_write_size,
68 escd.escd_size,
69 escd.nv_storage_base
70 );
71}
72
73#define MAX_SANE_ESCD_SIZE (32*1024)
74static int proc_read_escd(char *buf, char **start, off_t pos,
75 int count, int *eof, void *data)
76{
77 struct escd_info_struc escd;
78 char *tmpbuf;
79 int escd_size, escd_left_to_read, n;
80
81 if (pnp_bios_escd_info(&escd))
82 return -EIO;
83
84 /* sanity check */
85 if (escd.escd_size > MAX_SANE_ESCD_SIZE) {
86 printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n");
87 return -EFBIG;
88 }
89
90 tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL);
91 if (!tmpbuf) return -ENOMEM;
92
93 if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
94 kfree(tmpbuf);
95 return -EIO;
96 }
97
98 escd_size = (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1])*256;
99
100 /* sanity check */
101 if (escd_size > MAX_SANE_ESCD_SIZE) {
102 printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n");
103 return -EFBIG;
104 }
105
106 escd_left_to_read = escd_size - pos;
107 if (escd_left_to_read < 0) escd_left_to_read = 0;
108 if (escd_left_to_read == 0) *eof = 1;
109 n = min(count,escd_left_to_read);
110 memcpy(buf, tmpbuf + pos, n);
111 kfree(tmpbuf);
112 *start = buf;
113 return n;
114}
115
116static int proc_read_legacyres(char *buf, char **start, off_t pos,
117 int count, int *eof, void *data)
118{
119 /* Assume that the following won't overflow the buffer */
120 if (pnp_bios_get_stat_res(buf))
121 return -EIO;
122
123 return count; // FIXME: Return actual length
124}
125
126static int proc_read_devices(char *buf, char **start, off_t pos,
127 int count, int *eof, void *data)
128{
129 struct pnp_bios_node *node;
130 u8 nodenum;
131 char *p = buf;
132
133 if (pos >= 0xff)
134 return 0;
135
136 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
137 if (!node) return -ENOMEM;
138
139 for (nodenum=pos; nodenum<0xff; ) {
140 u8 thisnodenum = nodenum;
141 /* 26 = the number of characters per line sprintf'ed */
142 if ((p - buf + 26) > count)
143 break;
144 if (pnp_bios_get_dev_node(&nodenum, PNPMODE_DYNAMIC, node))
145 break;
146 p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
147 node->handle, node->eisa_id,
148 node->type_code[0], node->type_code[1],
149 node->type_code[2], node->flags);
150 if (nodenum <= thisnodenum) {
151 printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum);
152 *eof = 1;
153 break;
154 }
155 }
156 kfree(node);
157 if (nodenum == 0xff)
158 *eof = 1;
159 *start = (char *)((off_t)nodenum - pos);
160 return p - buf;
161}
162
163static int proc_read_node(char *buf, char **start, off_t pos,
164 int count, int *eof, void *data)
165{
166 struct pnp_bios_node *node;
167 int boot = (long)data >> 8;
168 u8 nodenum = (long)data;
169 int len;
170
171 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
172 if (!node) return -ENOMEM;
173 if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
174 kfree(node);
175 return -EIO;
176 }
177 len = node->size - sizeof(struct pnp_bios_node);
178 memcpy(buf, node->data, len);
179 kfree(node);
180 return len;
181}
182
183static int proc_write_node(struct file *file, const char __user *buf,
184 unsigned long count, void *data)
185{
186 struct pnp_bios_node *node;
187 int boot = (long)data >> 8;
188 u8 nodenum = (long)data;
189 int ret = count;
190
191 node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
192 if (!node)
193 return -ENOMEM;
194 if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
195 ret = -EIO;
196 goto out;
197 }
198 if (count != node->size - sizeof(struct pnp_bios_node)) {
199 ret = -EINVAL;
200 goto out;
201 }
202 if (copy_from_user(node->data, buf, count)) {
203 ret = -EFAULT;
204 goto out;
205 }
206 if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) {
207 ret = -EINVAL;
208 goto out;
209 }
210 ret = count;
211out:
212 kfree(node);
213 return ret;
214}
215
216int pnpbios_interface_attach_device(struct pnp_bios_node * node)
217{
218 char name[3];
219 struct proc_dir_entry *ent;
220
221 sprintf(name, "%02x", node->handle);
222
223 if (!proc_pnp)
224 return -EIO;
225 if ( !pnpbios_dont_use_current_config ) {
226 ent = create_proc_entry(name, 0, proc_pnp);
227 if (ent) {
228 ent->read_proc = proc_read_node;
229 ent->write_proc = proc_write_node;
230 ent->data = (void *)(long)(node->handle);
231 }
232 }
233
234 if (!proc_pnp_boot)
235 return -EIO;
236 ent = create_proc_entry(name, 0, proc_pnp_boot);
237 if (ent) {
238 ent->read_proc = proc_read_node;
239 ent->write_proc = proc_write_node;
240 ent->data = (void *)(long)(node->handle+0x100);
241 return 0;
242 }
243
244 return -EIO;
245}
246
247/*
248 * When this is called, pnpbios functions are assumed to
249 * work and the pnpbios_dont_use_current_config flag
250 * should already have been set to the appropriate value
251 */
252int __init pnpbios_proc_init( void )
253{
254 proc_pnp = proc_mkdir("pnp", proc_bus);
255 if (!proc_pnp)
256 return -EIO;
257 proc_pnp_boot = proc_mkdir("boot", proc_pnp);
258 if (!proc_pnp_boot)
259 return -EIO;
260 create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
261 create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL);
262 create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL);
263 create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL);
264 create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
265
266 return 0;
267}
268
269void __exit pnpbios_proc_exit(void)
270{
271 int i;
272 char name[3];
273
274 if (!proc_pnp)
275 return;
276
277 for (i=0; i<0xff; i++) {
278 sprintf(name, "%02x", i);
279 if ( !pnpbios_dont_use_current_config )
280 remove_proc_entry(name, proc_pnp);
281 remove_proc_entry(name, proc_pnp_boot);
282 }
283 remove_proc_entry("legacy_device_resources", proc_pnp);
284 remove_proc_entry("escd", proc_pnp);
285 remove_proc_entry("escd_info", proc_pnp);
286 remove_proc_entry("configuration_info", proc_pnp);
287 remove_proc_entry("devices", proc_pnp);
288 remove_proc_entry("boot", proc_pnp);
289 remove_proc_entry("pnp", proc_bus);
290
291 return;
292}
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
new file mode 100644
index 000000000000..618ac15a9e90
--- /dev/null
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -0,0 +1,795 @@
1/*
2 * rsparser.c - parses and encodes pnpbios resource data streams
3 *
4 */
5
6#include <linux/config.h>
7#include <linux/ctype.h>
8#include <linux/pnp.h>
9#include <linux/pnpbios.h>
10
11#ifdef CONFIG_PCI
12#include <linux/pci.h>
13#else
14inline void pcibios_penalize_isa_irq(int irq) {}
15#endif /* CONFIG_PCI */
16
17#include "pnpbios.h"
18
19/* standard resource tags */
20#define SMALL_TAG_PNPVERNO 0x01
21#define SMALL_TAG_LOGDEVID 0x02
22#define SMALL_TAG_COMPATDEVID 0x03
23#define SMALL_TAG_IRQ 0x04
24#define SMALL_TAG_DMA 0x05
25#define SMALL_TAG_STARTDEP 0x06
26#define SMALL_TAG_ENDDEP 0x07
27#define SMALL_TAG_PORT 0x08
28#define SMALL_TAG_FIXEDPORT 0x09
29#define SMALL_TAG_VENDOR 0x0e
30#define SMALL_TAG_END 0x0f
31#define LARGE_TAG 0x80
32#define LARGE_TAG_MEM 0x81
33#define LARGE_TAG_ANSISTR 0x82
34#define LARGE_TAG_UNICODESTR 0x83
35#define LARGE_TAG_VENDOR 0x84
36#define LARGE_TAG_MEM32 0x85
37#define LARGE_TAG_FIXEDMEM32 0x86
38
39/*
40 * Resource Data Stream Format:
41 *
42 * Allocated Resources (required)
43 * end tag ->
44 * Resource Configuration Options (optional)
45 * end tag ->
46 * Compitable Device IDs (optional)
47 * final end tag ->
48 */
49
50/*
51 * Allocated Resources
52 */
53
54static void
55pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
56{
57 int i = 0;
58 while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_IRQ) i++;
59 if (i < PNP_MAX_IRQ) {
60 res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
61 if (irq == -1) {
62 res->irq_resource[i].flags |= IORESOURCE_DISABLED;
63 return;
64 }
65 res->irq_resource[i].start =
66 res->irq_resource[i].end = (unsigned long) irq;
67 pcibios_penalize_isa_irq(irq);
68 }
69}
70
71static void
72pnpbios_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
73{
74 int i = 0;
75 while (!(res->dma_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_DMA) i++;
76 if (i < PNP_MAX_DMA) {
77 res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
78 if (dma == -1) {
79 res->dma_resource[i].flags |= IORESOURCE_DISABLED;
80 return;
81 }
82 res->dma_resource[i].start =
83 res->dma_resource[i].end = (unsigned long) dma;
84 }
85}
86
87static void
88pnpbios_parse_allocated_ioresource(struct pnp_resource_table * res, int io, int len)
89{
90 int i = 0;
91 while (!(res->port_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_PORT) i++;
92 if (i < PNP_MAX_PORT) {
93 res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
94 if (len <= 0 || (io + len -1) >= 0x10003) {
95 res->port_resource[i].flags |= IORESOURCE_DISABLED;
96 return;
97 }
98 res->port_resource[i].start = (unsigned long) io;
99 res->port_resource[i].end = (unsigned long)(io + len - 1);
100 }
101}
102
103static void
104pnpbios_parse_allocated_memresource(struct pnp_resource_table * res, int mem, int len)
105{
106 int i = 0;
107 while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_MEM) i++;
108 if (i < PNP_MAX_MEM) {
109 res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
110 if (len <= 0) {
111 res->mem_resource[i].flags |= IORESOURCE_DISABLED;
112 return;
113 }
114 res->mem_resource[i].start = (unsigned long) mem;
115 res->mem_resource[i].end = (unsigned long)(mem + len - 1);
116 }
117}
118
119static unsigned char *
120pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
121{
122 unsigned int len, tag;
123 int io, size, mask, i;
124
125 if (!p)
126 return NULL;
127
128 /* Blank the resource table values */
129 pnp_init_resource_table(res);
130
131 while ((char *)p < (char *)end) {
132
133 /* determine the type of tag */
134 if (p[0] & LARGE_TAG) { /* large tag */
135 len = (p[2] << 8) | p[1];
136 tag = p[0];
137 } else { /* small tag */
138 len = p[0] & 0x07;
139 tag = ((p[0]>>3) & 0x0f);
140 }
141
142 switch (tag) {
143
144 case LARGE_TAG_MEM:
145 if (len != 9)
146 goto len_err;
147 io = *(short *) &p[4];
148 size = *(short *) &p[10];
149 pnpbios_parse_allocated_memresource(res, io, size);
150 break;
151
152 case LARGE_TAG_ANSISTR:
153 /* ignore this for now */
154 break;
155
156 case LARGE_TAG_VENDOR:
157 /* do nothing */
158 break;
159
160 case LARGE_TAG_MEM32:
161 if (len != 17)
162 goto len_err;
163 io = *(int *) &p[4];
164 size = *(int *) &p[16];
165 pnpbios_parse_allocated_memresource(res, io, size);
166 break;
167
168 case LARGE_TAG_FIXEDMEM32:
169 if (len != 9)
170 goto len_err;
171 io = *(int *) &p[4];
172 size = *(int *) &p[8];
173 pnpbios_parse_allocated_memresource(res, io, size);
174 break;
175
176 case SMALL_TAG_IRQ:
177 if (len < 2 || len > 3)
178 goto len_err;
179 io = -1;
180 mask= p[1] + p[2]*256;
181 for (i=0;i<16;i++, mask=mask>>1)
182 if(mask & 0x01) io=i;
183 pnpbios_parse_allocated_irqresource(res, io);
184 break;
185
186 case SMALL_TAG_DMA:
187 if (len != 2)
188 goto len_err;
189 io = -1;
190 mask = p[1];
191 for (i=0;i<8;i++, mask = mask>>1)
192 if(mask & 0x01) io=i;
193 pnpbios_parse_allocated_dmaresource(res, io);
194 break;
195
196 case SMALL_TAG_PORT:
197 if (len != 7)
198 goto len_err;
199 io = p[2] + p[3] *256;
200 size = p[7];
201 pnpbios_parse_allocated_ioresource(res, io, size);
202 break;
203
204 case SMALL_TAG_VENDOR:
205 /* do nothing */
206 break;
207
208 case SMALL_TAG_FIXEDPORT:
209 if (len != 3)
210 goto len_err;
211 io = p[1] + p[2] * 256;
212 size = p[3];
213 pnpbios_parse_allocated_ioresource(res, io, size);
214 break;
215
216 case SMALL_TAG_END:
217 p = p + 2;
218 return (unsigned char *)p;
219 break;
220
221 default: /* an unkown tag */
222 len_err:
223 printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
224 break;
225 }
226
227 /* continue to the next tag */
228 if (p[0] & LARGE_TAG)
229 p += len + 3;
230 else
231 p += len + 1;
232 }
233
234 printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
235
236 return NULL;
237}
238
239
240/*
241 * Resource Configuration Options
242 */
243
244static void
245pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
246{
247 struct pnp_mem * mem;
248 mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
249 if (!mem)
250 return;
251 mem->min = ((p[5] << 8) | p[4]) << 8;
252 mem->max = ((p[7] << 8) | p[6]) << 8;
253 mem->align = (p[9] << 8) | p[8];
254 mem->size = ((p[11] << 8) | p[10]) << 8;
255 mem->flags = p[3];
256 pnp_register_mem_resource(option,mem);
257 return;
258}
259
260static void
261pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option)
262{
263 struct pnp_mem * mem;
264 mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
265 if (!mem)
266 return;
267 mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
268 mem->max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
269 mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
270 mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
271 mem->flags = p[3];
272 pnp_register_mem_resource(option,mem);
273 return;
274}
275
276static void
277pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *option)
278{
279 struct pnp_mem * mem;
280 mem = pnpbios_kmalloc(sizeof(struct pnp_mem), GFP_KERNEL);
281 if (!mem)
282 return;
283 mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
284 mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
285 mem->align = 0;
286 mem->flags = p[3];
287 pnp_register_mem_resource(option,mem);
288 return;
289}
290
291static void
292pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
293{
294 struct pnp_irq * irq;
295 unsigned long bits;
296
297 irq = pnpbios_kmalloc(sizeof(struct pnp_irq), GFP_KERNEL);
298 if (!irq)
299 return;
300 bits = (p[2] << 8) | p[1];
301 bitmap_copy(irq->map, &bits, 16);
302 if (size > 2)
303 irq->flags = p[3];
304 else
305 irq->flags = IORESOURCE_IRQ_HIGHEDGE;
306 pnp_register_irq_resource(option,irq);
307 return;
308}
309
310static void
311pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option)
312{
313 struct pnp_dma * dma;
314 dma = pnpbios_kmalloc(sizeof(struct pnp_dma), GFP_KERNEL);
315 if (!dma)
316 return;
317 dma->map = p[1];
318 dma->flags = p[2];
319 pnp_register_dma_resource(option,dma);
320 return;
321}
322
323static void
324pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
325{
326 struct pnp_port * port;
327 port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
328 if (!port)
329 return;
330 port->min = (p[3] << 8) | p[2];
331 port->max = (p[5] << 8) | p[4];
332 port->align = p[6];
333 port->size = p[7];
334 port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
335 pnp_register_port_resource(option,port);
336 return;
337}
338
339static void
340pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *option)
341{
342 struct pnp_port * port;
343 port = pnpbios_kmalloc(sizeof(struct pnp_port), GFP_KERNEL);
344 if (!port)
345 return;
346 port->min = port->max = (p[2] << 8) | p[1];
347 port->size = p[3];
348 port->align = 0;
349 port->flags = PNP_PORT_FLAG_FIXED;
350 pnp_register_port_resource(option,port);
351 return;
352}
353
354static unsigned char *
355pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struct pnp_dev *dev)
356{
357 unsigned int len, tag;
358 int priority = 0;
359 struct pnp_option *option, *option_independent;
360
361 if (!p)
362 return NULL;
363
364 option_independent = option = pnp_register_independent_option(dev);
365 if (!option)
366 return NULL;
367
368 while ((char *)p < (char *)end) {
369
370 /* determine the type of tag */
371 if (p[0] & LARGE_TAG) { /* large tag */
372 len = (p[2] << 8) | p[1];
373 tag = p[0];
374 } else { /* small tag */
375 len = p[0] & 0x07;
376 tag = ((p[0]>>3) & 0x0f);
377 }
378
379 switch (tag) {
380
381 case LARGE_TAG_MEM:
382 if (len != 9)
383 goto len_err;
384 pnpbios_parse_mem_option(p, len, option);
385 break;
386
387 case LARGE_TAG_MEM32:
388 if (len != 17)
389 goto len_err;
390 pnpbios_parse_mem32_option(p, len, option);
391 break;
392
393 case LARGE_TAG_FIXEDMEM32:
394 if (len != 9)
395 goto len_err;
396 pnpbios_parse_fixed_mem32_option(p, len, option);
397 break;
398
399 case SMALL_TAG_IRQ:
400 if (len < 2 || len > 3)
401 goto len_err;
402 pnpbios_parse_irq_option(p, len, option);
403 break;
404
405 case SMALL_TAG_DMA:
406 if (len != 2)
407 goto len_err;
408 pnpbios_parse_dma_option(p, len, option);
409 break;
410
411 case SMALL_TAG_PORT:
412 if (len != 7)
413 goto len_err;
414 pnpbios_parse_port_option(p, len, option);
415 break;
416
417 case SMALL_TAG_VENDOR:
418 /* do nothing */
419 break;
420
421 case SMALL_TAG_FIXEDPORT:
422 if (len != 3)
423 goto len_err;
424 pnpbios_parse_fixed_port_option(p, len, option);
425 break;
426
427 case SMALL_TAG_STARTDEP:
428 if (len > 1)
429 goto len_err;
430 priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
431 if (len > 0)
432 priority = 0x100 | p[1];
433 option = pnp_register_dependent_option(dev, priority);
434 if (!option)
435 return NULL;
436 break;
437
438 case SMALL_TAG_ENDDEP:
439 if (len != 0)
440 goto len_err;
441 if (option_independent == option)
442 printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n");
443 option = option_independent;
444 break;
445
446 case SMALL_TAG_END:
447 if (option_independent != option)
448 printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_ENDDEP tag\n");
449 p = p + 2;
450 return (unsigned char *)p;
451 break;
452
453 default: /* an unkown tag */
454 len_err:
455 printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
456 break;
457 }
458
459 /* continue to the next tag */
460 if (p[0] & LARGE_TAG)
461 p += len + 3;
462 else
463 p += len + 1;
464 }
465
466 printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
467
468 return NULL;
469}
470
471
472/*
473 * Compatible Device IDs
474 */
475
476#define HEX(id,a) hex[((id)>>a) & 15]
477#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
478//
479
480void pnpid32_to_pnpid(u32 id, char *str)
481{
482 const char *hex = "0123456789abcdef";
483
484 id = be32_to_cpu(id);
485 str[0] = CHAR(id, 26);
486 str[1] = CHAR(id, 21);
487 str[2] = CHAR(id,16);
488 str[3] = HEX(id, 12);
489 str[4] = HEX(id, 8);
490 str[5] = HEX(id, 4);
491 str[6] = HEX(id, 0);
492 str[7] = '\0';
493
494 return;
495}
496//
497#undef CHAR
498#undef HEX
499
500static unsigned char *
501pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_dev *dev)
502{
503 int len, tag;
504 char id[8];
505 struct pnp_id *dev_id;
506
507 if (!p)
508 return NULL;
509
510 while ((char *)p < (char *)end) {
511
512 /* determine the type of tag */
513 if (p[0] & LARGE_TAG) { /* large tag */
514 len = (p[2] << 8) | p[1];
515 tag = p[0];
516 } else { /* small tag */
517 len = p[0] & 0x07;
518 tag = ((p[0]>>3) & 0x0f);
519 }
520
521 switch (tag) {
522
523 case LARGE_TAG_ANSISTR:
524 strncpy(dev->name, p + 3, len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len);
525 dev->name[len >= PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0';
526 break;
527
528 case SMALL_TAG_COMPATDEVID: /* compatible ID */
529 if (len != 4)
530 goto len_err;
531 dev_id = pnpbios_kmalloc(sizeof (struct pnp_id), GFP_KERNEL);
532 if (!dev_id)
533 return NULL;
534 memset(dev_id, 0, sizeof(struct pnp_id));
535 pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24,id);
536 memcpy(&dev_id->id, id, 7);
537 pnp_add_id(dev_id, dev);
538 break;
539
540 case SMALL_TAG_END:
541 p = p + 2;
542 return (unsigned char *)p;
543 break;
544
545 default: /* an unkown tag */
546 len_err:
547 printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
548 break;
549 }
550
551 /* continue to the next tag */
552 if (p[0] & LARGE_TAG)
553 p += len + 3;
554 else
555 p += len + 1;
556 }
557
558 printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
559
560 return NULL;
561}
562
563
564/*
565 * Allocated Resource Encoding
566 */
567
568static void pnpbios_encode_mem(unsigned char *p, struct resource * res)
569{
570 unsigned long base = res->start;
571 unsigned long len = res->end - res->start + 1;
572 p[4] = (base >> 8) & 0xff;
573 p[5] = ((base >> 8) >> 8) & 0xff;
574 p[6] = (base >> 8) & 0xff;
575 p[7] = ((base >> 8) >> 8) & 0xff;
576 p[10] = (len >> 8) & 0xff;
577 p[11] = ((len >> 8) >> 8) & 0xff;
578 return;
579}
580
581static void pnpbios_encode_mem32(unsigned char *p, struct resource * res)
582{
583 unsigned long base = res->start;
584 unsigned long len = res->end - res->start + 1;
585 p[4] = base & 0xff;
586 p[5] = (base >> 8) & 0xff;
587 p[6] = (base >> 16) & 0xff;
588 p[7] = (base >> 24) & 0xff;
589 p[8] = base & 0xff;
590 p[9] = (base >> 8) & 0xff;
591 p[10] = (base >> 16) & 0xff;
592 p[11] = (base >> 24) & 0xff;
593 p[16] = len & 0xff;
594 p[17] = (len >> 8) & 0xff;
595 p[18] = (len >> 16) & 0xff;
596 p[19] = (len >> 24) & 0xff;
597 return;
598}
599
600static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource * res)
601{ unsigned long base = res->start;
602 unsigned long len = res->end - res->start + 1;
603 p[4] = base & 0xff;
604 p[5] = (base >> 8) & 0xff;
605 p[6] = (base >> 16) & 0xff;
606 p[7] = (base >> 24) & 0xff;
607 p[8] = len & 0xff;
608 p[9] = (len >> 8) & 0xff;
609 p[10] = (len >> 16) & 0xff;
610 p[11] = (len >> 24) & 0xff;
611 return;
612}
613
614static void pnpbios_encode_irq(unsigned char *p, struct resource * res)
615{
616 unsigned long map = 0;
617 map = 1 << res->start;
618 p[1] = map & 0xff;
619 p[2] = (map >> 8) & 0xff;
620 return;
621}
622
623static void pnpbios_encode_dma(unsigned char *p, struct resource * res)
624{
625 unsigned long map = 0;
626 map = 1 << res->start;
627 p[1] = map & 0xff;
628 return;
629}
630
631static void pnpbios_encode_port(unsigned char *p, struct resource * res)
632{
633 unsigned long base = res->start;
634 unsigned long len = res->end - res->start + 1;
635 p[2] = base & 0xff;
636 p[3] = (base >> 8) & 0xff;
637 p[4] = base & 0xff;
638 p[5] = (base >> 8) & 0xff;
639 p[7] = len & 0xff;
640 return;
641}
642
643static void pnpbios_encode_fixed_port(unsigned char *p, struct resource * res)
644{
645 unsigned long base = res->start;
646 unsigned long len = res->end - res->start + 1;
647 p[1] = base & 0xff;
648 p[2] = (base >> 8) & 0xff;
649 p[3] = len & 0xff;
650 return;
651}
652
653static unsigned char *
654pnpbios_encode_allocated_resource_data(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
655{
656 unsigned int len, tag;
657 int port = 0, irq = 0, dma = 0, mem = 0;
658
659 if (!p)
660 return NULL;
661
662 while ((char *)p < (char *)end) {
663
664 /* determine the type of tag */
665 if (p[0] & LARGE_TAG) { /* large tag */
666 len = (p[2] << 8) | p[1];
667 tag = p[0];
668 } else { /* small tag */
669 len = p[0] & 0x07;
670 tag = ((p[0]>>3) & 0x0f);
671 }
672
673 switch (tag) {
674
675 case LARGE_TAG_MEM:
676 if (len != 9)
677 goto len_err;
678 pnpbios_encode_mem(p, &res->mem_resource[mem]);
679 mem++;
680 break;
681
682 case LARGE_TAG_MEM32:
683 if (len != 17)
684 goto len_err;
685 pnpbios_encode_mem32(p, &res->mem_resource[mem]);
686 mem++;
687 break;
688
689 case LARGE_TAG_FIXEDMEM32:
690 if (len != 9)
691 goto len_err;
692 pnpbios_encode_fixed_mem32(p, &res->mem_resource[mem]);
693 mem++;
694 break;
695
696 case SMALL_TAG_IRQ:
697 if (len < 2 || len > 3)
698 goto len_err;
699 pnpbios_encode_irq(p, &res->irq_resource[irq]);
700 irq++;
701 break;
702
703 case SMALL_TAG_DMA:
704 if (len != 2)
705 goto len_err;
706 pnpbios_encode_dma(p, &res->dma_resource[dma]);
707 dma++;
708 break;
709
710 case SMALL_TAG_PORT:
711 if (len != 7)
712 goto len_err;
713 pnpbios_encode_port(p, &res->port_resource[port]);
714 port++;
715 break;
716
717 case SMALL_TAG_VENDOR:
718 /* do nothing */
719 break;
720
721 case SMALL_TAG_FIXEDPORT:
722 if (len != 3)
723 goto len_err;
724 pnpbios_encode_fixed_port(p, &res->port_resource[port]);
725 port++;
726 break;
727
728 case SMALL_TAG_END:
729 p = p + 2;
730 return (unsigned char *)p;
731 break;
732
733 default: /* an unkown tag */
734 len_err:
735 printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
736 break;
737 }
738
739 /* continue to the next tag */
740 if (p[0] & LARGE_TAG)
741 p += len + 3;
742 else
743 p += len + 1;
744 }
745
746 printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
747
748 return NULL;
749}
750
751
752/*
753 * Core Parsing Functions
754 */
755
756int
757pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node)
758{
759 unsigned char * p = (char *)node->data;
760 unsigned char * end = (char *)(node->data + node->size);
761 p = pnpbios_parse_allocated_resource_data(p,end,&dev->res);
762 if (!p)
763 return -EIO;
764 p = pnpbios_parse_resource_option_data(p,end,dev);
765 if (!p)
766 return -EIO;
767 p = pnpbios_parse_compatible_ids(p,end,dev);
768 if (!p)
769 return -EIO;
770 return 0;
771}
772
773int
774pnpbios_read_resources_from_node(struct pnp_resource_table *res,
775 struct pnp_bios_node * node)
776{
777 unsigned char * p = (char *)node->data;
778 unsigned char * end = (char *)(node->data + node->size);
779 p = pnpbios_parse_allocated_resource_data(p,end,res);
780 if (!p)
781 return -EIO;
782 return 0;
783}
784
785int
786pnpbios_write_resources_to_node(struct pnp_resource_table *res,
787 struct pnp_bios_node * node)
788{
789 unsigned char * p = (char *)node->data;
790 unsigned char * end = (char *)(node->data + node->size);
791 p = pnpbios_encode_allocated_resource_data(p,end,res);
792 if (!p)
793 return -EIO;
794 return 0;
795}
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
new file mode 100644
index 000000000000..596a02d7e03d
--- /dev/null
+++ b/drivers/pnp/quirks.c
@@ -0,0 +1,152 @@
1/*
2 * This file contains quirk handling code for PnP devices
3 * Some devices do not report all their resources, and need to have extra
4 * resources added. This is most easily accomplished at initialisation time
5 * when building up the resource structure for the first time.
6 *
7 * Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk>
8 *
9 * Heavily based on PCI quirks handling which is
10 *
11 * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
12 */
13
14#include <linux/config.h>
15#include <linux/types.h>
16#include <linux/kernel.h>
17#include <linux/string.h>
18#include <linux/slab.h>
19
20#ifdef CONFIG_PNP_DEBUG
21 #define DEBUG
22#else
23 #undef DEBUG
24#endif
25
26#include <linux/pnp.h>
27#include "base.h"
28
29
30static void quirk_awe32_resources(struct pnp_dev *dev)
31{
32 struct pnp_port *port, *port2, *port3;
33 struct pnp_option *res = dev->dependent;
34
35 /*
36 * Unfortunately the isapnp_add_port_resource is too tightly bound
37 * into the PnP discovery sequence, and cannot be used. Link in the
38 * two extra ports (at offset 0x400 and 0x800 from the one given) by
39 * hand.
40 */
41 for ( ; res ; res = res->next ) {
42 port2 = pnp_alloc(sizeof(struct pnp_port));
43 if (!port2)
44 return;
45 port3 = pnp_alloc(sizeof(struct pnp_port));
46 if (!port3) {
47 kfree(port2);
48 return;
49 }
50 port = res->port;
51 memcpy(port2, port, sizeof(struct pnp_port));
52 memcpy(port3, port, sizeof(struct pnp_port));
53 port->next = port2;
54 port2->next = port3;
55 port2->min += 0x400;
56 port2->max += 0x400;
57 port3->min += 0x800;
58 port3->max += 0x800;
59 }
60 printk(KERN_INFO "pnp: AWE32 quirk - adding two ports\n");
61}
62
63static void quirk_cmi8330_resources(struct pnp_dev *dev)
64{
65 struct pnp_option *res = dev->dependent;
66 unsigned long tmp;
67
68 for ( ; res ; res = res->next ) {
69
70 struct pnp_irq *irq;
71 struct pnp_dma *dma;
72
73 for( irq = res->irq; irq; irq = irq->next ) { // Valid irqs are 5, 7, 10
74 tmp = 0x04A0;
75 bitmap_copy(irq->map, &tmp, 16); // 0000 0100 1010 0000
76 }
77
78 for( dma = res->dma; dma; dma = dma->next ) // Valid 8bit dma channels are 1,3
79 if( ( dma->flags & IORESOURCE_DMA_TYPE_MASK ) == IORESOURCE_DMA_8BIT )
80 dma->map = 0x000A;
81 }
82 printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n");
83}
84
85static void quirk_sb16audio_resources(struct pnp_dev *dev)
86{
87 struct pnp_port *port;
88 struct pnp_option *res = dev->dependent;
89 int changed = 0;
90
91 /*
92 * The default range on the mpu port for these devices is 0x388-0x388.
93 * Here we increase that range so that two such cards can be
94 * auto-configured.
95 */
96
97 for( ; res ; res = res->next ) {
98 port = res->port;
99 if(!port)
100 continue;
101 port = port->next;
102 if(!port)
103 continue;
104 port = port->next;
105 if(!port)
106 continue;
107 if(port->min != port->max)
108 continue;
109 port->max += 0x70;
110 changed = 1;
111 }
112 if(changed)
113 printk(KERN_INFO "pnp: SB audio device quirk - increasing port range\n");
114 return;
115}
116
117/*
118 * PnP Quirks
119 * Cards or devices that need some tweaking due to incomplete resource info
120 */
121
122static struct pnp_fixup pnp_fixups[] = {
123 /* Soundblaster awe io port quirk */
124 { "CTL0021", quirk_awe32_resources },
125 { "CTL0022", quirk_awe32_resources },
126 { "CTL0023", quirk_awe32_resources },
127 /* CMI 8330 interrupt and dma fix */
128 { "@X@0001", quirk_cmi8330_resources },
129 /* Soundblaster audio device io port range quirk */
130 { "CTL0001", quirk_sb16audio_resources },
131 { "CTL0031", quirk_sb16audio_resources },
132 { "CTL0041", quirk_sb16audio_resources },
133 { "CTL0042", quirk_sb16audio_resources },
134 { "CTL0043", quirk_sb16audio_resources },
135 { "CTL0044", quirk_sb16audio_resources },
136 { "CTL0045", quirk_sb16audio_resources },
137 { "" }
138};
139
140void pnp_fixup_device(struct pnp_dev *dev)
141{
142 int i = 0;
143
144 while (*pnp_fixups[i].id) {
145 if (compare_pnp_id(dev->id,pnp_fixups[i].id)) {
146 pnp_dbg("Calling quirk for %s",
147 dev->dev.bus_id);
148 pnp_fixups[i].quirk_function(dev);
149 }
150 i++;
151 }
152}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
new file mode 100644
index 000000000000..2d1322dd7e19
--- /dev/null
+++ b/drivers/pnp/resource.c
@@ -0,0 +1,542 @@
1/*
2 * resource.c - Contains functions for registering and analyzing resource information
3 *
4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
6 *
7 */
8
9#include <linux/config.h>
10#include <linux/module.h>
11#include <linux/errno.h>
12#include <linux/interrupt.h>
13#include <linux/kernel.h>
14#include <asm/io.h>
15#include <asm/dma.h>
16#include <asm/irq.h>
17#include <linux/pci.h>
18#include <linux/ioport.h>
19#include <linux/init.h>
20
21#include <linux/pnp.h>
22#include "base.h"
23
24static int pnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */
25static int pnp_reserve_dma[8] = { [0 ... 7] = -1 }; /* reserve (don't use) some DMA */
26static int pnp_reserve_io[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some I/O region */
27static int pnp_reserve_mem[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some memory region */
28
29
30/*
31 * option registration
32 */
33
34static struct pnp_option * pnp_build_option(int priority)
35{
36 struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
37
38 /* check if pnp_alloc ran out of memory */
39 if (!option)
40 return NULL;
41
42 option->priority = priority & 0xff;
43 /* make sure the priority is valid */
44 if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
45 option->priority = PNP_RES_PRIORITY_INVALID;
46
47 return option;
48}
49
50struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev)
51{
52 struct pnp_option *option;
53 if (!dev)
54 return NULL;
55
56 option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
57
58 /* this should never happen but if it does we'll try to continue */
59 if (dev->independent)
60 pnp_err("independent resource already registered");
61 dev->independent = option;
62 return option;
63}
64
65struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority)
66{
67 struct pnp_option *option;
68 if (!dev)
69 return NULL;
70
71 option = pnp_build_option(priority);
72
73 if (dev->dependent) {
74 struct pnp_option *parent = dev->dependent;
75 while (parent->next)
76 parent = parent->next;
77 parent->next = option;
78 } else
79 dev->dependent = option;
80 return option;
81}
82
83int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
84{
85 struct pnp_irq *ptr;
86 if (!option)
87 return -EINVAL;
88 if (!data)
89 return -EINVAL;
90
91 ptr = option->irq;
92 while (ptr && ptr->next)
93 ptr = ptr->next;
94 if (ptr)
95 ptr->next = data;
96 else
97 option->irq = data;
98
99#ifdef CONFIG_PCI
100 {
101 int i;
102
103 for (i = 0; i < 16; i++)
104 if (test_bit(i, data->map))
105 pcibios_penalize_isa_irq(i);
106 }
107#endif
108 return 0;
109}
110
111int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
112{
113 struct pnp_dma *ptr;
114 if (!option)
115 return -EINVAL;
116 if (!data)
117 return -EINVAL;
118
119 ptr = option->dma;
120 while (ptr && ptr->next)
121 ptr = ptr->next;
122 if (ptr)
123 ptr->next = data;
124 else
125 option->dma = data;
126
127 return 0;
128}
129
130int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
131{
132 struct pnp_port *ptr;
133 if (!option)
134 return -EINVAL;
135 if (!data)
136 return -EINVAL;
137
138 ptr = option->port;
139 while (ptr && ptr->next)
140 ptr = ptr->next;
141 if (ptr)
142 ptr->next = data;
143 else
144 option->port = data;
145
146 return 0;
147}
148
149int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
150{
151 struct pnp_mem *ptr;
152 if (!option)
153 return -EINVAL;
154 if (!data)
155 return -EINVAL;
156
157 ptr = option->mem;
158 while (ptr && ptr->next)
159 ptr = ptr->next;
160 if (ptr)
161 ptr->next = data;
162 else
163 option->mem = data;
164 return 0;
165}
166
167static void pnp_free_port(struct pnp_port *port)
168{
169 struct pnp_port *next;
170
171 while (port) {
172 next = port->next;
173 kfree(port);
174 port = next;
175 }
176}
177
178static void pnp_free_irq(struct pnp_irq *irq)
179{
180 struct pnp_irq *next;
181
182 while (irq) {
183 next = irq->next;
184 kfree(irq);
185 irq = next;
186 }
187}
188
189static void pnp_free_dma(struct pnp_dma *dma)
190{
191 struct pnp_dma *next;
192
193 while (dma) {
194 next = dma->next;
195 kfree(dma);
196 dma = next;
197 }
198}
199
200static void pnp_free_mem(struct pnp_mem *mem)
201{
202 struct pnp_mem *next;
203
204 while (mem) {
205 next = mem->next;
206 kfree(mem);
207 mem = next;
208 }
209}
210
211void pnp_free_option(struct pnp_option *option)
212{
213 struct pnp_option *next;
214
215 while (option) {
216 next = option->next;
217 pnp_free_port(option->port);
218 pnp_free_irq(option->irq);
219 pnp_free_dma(option->dma);
220 pnp_free_mem(option->mem);
221 kfree(option);
222 option = next;
223 }
224}
225
226
227/*
228 * resource validity checking
229 */
230
231#define length(start, end) (*(end) - *(start) + 1)
232
233/* Two ranges conflict if one doesn't end before the other starts */
234#define ranged_conflict(starta, enda, startb, endb) \
235 !((*(enda) < *(startb)) || (*(endb) < *(starta)))
236
237#define cannot_compare(flags) \
238((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
239
240int pnp_check_port(struct pnp_dev * dev, int idx)
241{
242 int tmp;
243 struct pnp_dev *tdev;
244 unsigned long *port, *end, *tport, *tend;
245 port = &dev->res.port_resource[idx].start;
246 end = &dev->res.port_resource[idx].end;
247
248 /* if the resource doesn't exist, don't complain about it */
249 if (cannot_compare(dev->res.port_resource[idx].flags))
250 return 1;
251
252 /* check if the resource is already in use, skip if the
253 * device is active because it itself may be in use */
254 if(!dev->active) {
255 if (__check_region(&ioport_resource, *port, length(port,end)))
256 return 0;
257 }
258
259 /* check if the resource is reserved */
260 for (tmp = 0; tmp < 8; tmp++) {
261 int rport = pnp_reserve_io[tmp << 1];
262 int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
263 if (ranged_conflict(port,end,&rport,&rend))
264 return 0;
265 }
266
267 /* check for internal conflicts */
268 for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
269 if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
270 tport = &dev->res.port_resource[tmp].start;
271 tend = &dev->res.port_resource[tmp].end;
272 if (ranged_conflict(port,end,tport,tend))
273 return 0;
274 }
275 }
276
277 /* check for conflicts with other pnp devices */
278 pnp_for_each_dev(tdev) {
279 if (tdev == dev)
280 continue;
281 for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
282 if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
283 if (cannot_compare(tdev->res.port_resource[tmp].flags))
284 continue;
285 tport = &tdev->res.port_resource[tmp].start;
286 tend = &tdev->res.port_resource[tmp].end;
287 if (ranged_conflict(port,end,tport,tend))
288 return 0;
289 }
290 }
291 }
292
293 return 1;
294}
295
296int pnp_check_mem(struct pnp_dev * dev, int idx)
297{
298 int tmp;
299 struct pnp_dev *tdev;
300 unsigned long *addr, *end, *taddr, *tend;
301 addr = &dev->res.mem_resource[idx].start;
302 end = &dev->res.mem_resource[idx].end;
303
304 /* if the resource doesn't exist, don't complain about it */
305 if (cannot_compare(dev->res.mem_resource[idx].flags))
306 return 1;
307
308 /* check if the resource is already in use, skip if the
309 * device is active because it itself may be in use */
310 if(!dev->active) {
311 if (check_mem_region(*addr, length(addr,end)))
312 return 0;
313 }
314
315 /* check if the resource is reserved */
316 for (tmp = 0; tmp < 8; tmp++) {
317 int raddr = pnp_reserve_mem[tmp << 1];
318 int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
319 if (ranged_conflict(addr,end,&raddr,&rend))
320 return 0;
321 }
322
323 /* check for internal conflicts */
324 for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
325 if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
326 taddr = &dev->res.mem_resource[tmp].start;
327 tend = &dev->res.mem_resource[tmp].end;
328 if (ranged_conflict(addr,end,taddr,tend))
329 return 0;
330 }
331 }
332
333 /* check for conflicts with other pnp devices */
334 pnp_for_each_dev(tdev) {
335 if (tdev == dev)
336 continue;
337 for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
338 if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
339 if (cannot_compare(tdev->res.mem_resource[tmp].flags))
340 continue;
341 taddr = &tdev->res.mem_resource[tmp].start;
342 tend = &tdev->res.mem_resource[tmp].end;
343 if (ranged_conflict(addr,end,taddr,tend))
344 return 0;
345 }
346 }
347 }
348
349 return 1;
350}
351
352static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs)
353{
354 return IRQ_HANDLED;
355}
356
357int pnp_check_irq(struct pnp_dev * dev, int idx)
358{
359 int tmp;
360 struct pnp_dev *tdev;
361 unsigned long * irq = &dev->res.irq_resource[idx].start;
362
363 /* if the resource doesn't exist, don't complain about it */
364 if (cannot_compare(dev->res.irq_resource[idx].flags))
365 return 1;
366
367 /* check if the resource is valid */
368 if (*irq < 0 || *irq > 15)
369 return 0;
370
371 /* check if the resource is reserved */
372 for (tmp = 0; tmp < 16; tmp++) {
373 if (pnp_reserve_irq[tmp] == *irq)
374 return 0;
375 }
376
377 /* check for internal conflicts */
378 for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
379 if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
380 if (dev->res.irq_resource[tmp].start == *irq)
381 return 0;
382 }
383 }
384
385#ifdef CONFIG_PCI
386 /* check if the resource is being used by a pci device */
387 {
388 struct pci_dev *pci = NULL;
389 for_each_pci_dev(pci) {
390 if (pci->irq == *irq)
391 return 0;
392 }
393 }
394#endif
395
396 /* check if the resource is already in use, skip if the
397 * device is active because it itself may be in use */
398 if(!dev->active) {
399 if (request_irq(*irq, pnp_test_handler, SA_INTERRUPT, "pnp", NULL))
400 return 0;
401 free_irq(*irq, NULL);
402 }
403
404 /* check for conflicts with other pnp devices */
405 pnp_for_each_dev(tdev) {
406 if (tdev == dev)
407 continue;
408 for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
409 if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
410 if (cannot_compare(tdev->res.irq_resource[tmp].flags))
411 continue;
412 if ((tdev->res.irq_resource[tmp].start == *irq))
413 return 0;
414 }
415 }
416 }
417
418 return 1;
419}
420
421int pnp_check_dma(struct pnp_dev * dev, int idx)
422{
423#ifndef CONFIG_IA64
424 int tmp;
425 struct pnp_dev *tdev;
426 unsigned long * dma = &dev->res.dma_resource[idx].start;
427
428 /* if the resource doesn't exist, don't complain about it */
429 if (cannot_compare(dev->res.dma_resource[idx].flags))
430 return 1;
431
432 /* check if the resource is valid */
433 if (*dma < 0 || *dma == 4 || *dma > 7)
434 return 0;
435
436 /* check if the resource is reserved */
437 for (tmp = 0; tmp < 8; tmp++) {
438 if (pnp_reserve_dma[tmp] == *dma)
439 return 0;
440 }
441
442 /* check for internal conflicts */
443 for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
444 if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
445 if (dev->res.dma_resource[tmp].start == *dma)
446 return 0;
447 }
448 }
449
450 /* check if the resource is already in use, skip if the
451 * device is active because it itself may be in use */
452 if(!dev->active) {
453 if (request_dma(*dma, "pnp"))
454 return 0;
455 free_dma(*dma);
456 }
457
458 /* check for conflicts with other pnp devices */
459 pnp_for_each_dev(tdev) {
460 if (tdev == dev)
461 continue;
462 for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
463 if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
464 if (cannot_compare(tdev->res.dma_resource[tmp].flags))
465 continue;
466 if ((tdev->res.dma_resource[tmp].start == *dma))
467 return 0;
468 }
469 }
470 }
471
472 return 1;
473#else
474 /* IA64 hasn't legacy DMA */
475 return 0;
476#endif
477}
478
479
480EXPORT_SYMBOL(pnp_register_dependent_option);
481EXPORT_SYMBOL(pnp_register_independent_option);
482EXPORT_SYMBOL(pnp_register_irq_resource);
483EXPORT_SYMBOL(pnp_register_dma_resource);
484EXPORT_SYMBOL(pnp_register_port_resource);
485EXPORT_SYMBOL(pnp_register_mem_resource);
486
487
488/* format is: pnp_reserve_irq=irq1[,irq2] .... */
489
490static int __init pnp_setup_reserve_irq(char *str)
491{
492 int i;
493
494 for (i = 0; i < 16; i++)
495 if (get_option(&str,&pnp_reserve_irq[i]) != 2)
496 break;
497 return 1;
498}
499
500__setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
501
502/* format is: pnp_reserve_dma=dma1[,dma2] .... */
503
504static int __init pnp_setup_reserve_dma(char *str)
505{
506 int i;
507
508 for (i = 0; i < 8; i++)
509 if (get_option(&str,&pnp_reserve_dma[i]) != 2)
510 break;
511 return 1;
512}
513
514__setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
515
516/* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
517
518static int __init pnp_setup_reserve_io(char *str)
519{
520 int i;
521
522 for (i = 0; i < 16; i++)
523 if (get_option(&str,&pnp_reserve_io[i]) != 2)
524 break;
525 return 1;
526}
527
528__setup("pnp_reserve_io=", pnp_setup_reserve_io);
529
530/* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
531
532static int __init pnp_setup_reserve_mem(char *str)
533{
534 int i;
535
536 for (i = 0; i < 16; i++)
537 if (get_option(&str,&pnp_reserve_mem[i]) != 2)
538 break;
539 return 1;
540}
541
542__setup("pnp_reserve_mem=", pnp_setup_reserve_mem);
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
new file mode 100644
index 000000000000..b952aec49189
--- /dev/null
+++ b/drivers/pnp/support.c
@@ -0,0 +1,40 @@
1/*
2 * support.c - provides standard pnp functions for the use of pnp protocol drivers,
3 *
4 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
5 *
6 */
7
8#include <linux/config.h>
9#include <linux/module.h>
10#include <linux/ctype.h>
11
12#ifdef CONFIG_PNP_DEBUG
13 #define DEBUG
14#else
15 #undef DEBUG
16#endif
17
18#include <linux/pnp.h>
19#include "base.h"
20
21/**
22 * pnp_is_active - Determines if a device is active based on its current resources
23 * @dev: pointer to the desired PnP device
24 *
25 */
26
27int pnp_is_active(struct pnp_dev * dev)
28{
29 if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&
30 !pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&
31 pnp_irq(dev, 0) == -1 &&
32 pnp_dma(dev, 0) == -1)
33 return 0;
34 else
35 return 1;
36}
37
38
39
40EXPORT_SYMBOL(pnp_is_active);
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
16static 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
24static 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
52static 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
88static 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
94static 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
102static 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 */
111fs_initcall(pnp_system_init);