summaryrefslogtreecommitdiffstats
path: root/drivers/pnp
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/pnp
Linux-2.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 @@
+#
+# Plug and Play configuration
+#
+
+menu "Plug and Play support"
+
+config PNP
+ bool "Plug and Play support"
+ depends on ISA || ACPI_BUS
+ ---help---
+ Plug and Play (PnP) is a standard for peripherals which allows those
+ peripherals to be configured by software, e.g. assign IRQ's or other
+ parameters. No jumpers on the cards are needed, instead the values
+ are provided to the cards from the BIOS, from the operating system,
+ or using a user-space utility.
+
+ Say Y here if you would like Linux to configure your Plug and Play
+ devices. You should then also say Y to all of the protocols below.
+ Alternatively, you can say N here and configure your PnP devices
+ using user space utilities such as the isapnptools package.
+
+ If unsure, say Y.
+
+config PNP_DEBUG
+ bool "PnP Debug Messages"
+ depends on PNP
+ help
+ Say Y if you want the Plug and Play Layer to print debug messages.
+ This is useful if you are developing a PnP driver or troubleshooting.
+
+comment "Protocols"
+ depends on PNP
+
+source "drivers/pnp/isapnp/Kconfig"
+
+source "drivers/pnp/pnpbios/Kconfig"
+
+source "drivers/pnp/pnpacpi/Kconfig"
+
+endmenu
+
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 @@
+#
+# Makefile for the Linux Plug-and-Play Support.
+#
+
+obj-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o system.o
+
+obj-$(CONFIG_PNPACPI) += pnpacpi/
+obj-$(CONFIG_PNPBIOS) += pnpbios/
+obj-$(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 @@
+extern struct bus_type pnp_bus_type;
+extern spinlock_t pnp_lock;
+void *pnp_alloc(long size);
+int pnp_interface_attach_device(struct pnp_dev *dev);
+void pnp_fixup_device(struct pnp_dev *dev);
+void pnp_free_option(struct pnp_option *option);
+int __pnp_add_device(struct pnp_dev *dev);
+void __pnp_remove_device(struct pnp_dev *dev);
+
+int pnp_check_port(struct pnp_dev * dev, int idx);
+int pnp_check_mem(struct pnp_dev * dev, int idx);
+int pnp_check_irq(struct pnp_dev * dev, int idx);
+int 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 @@
+/*
+ * card.c - contains functions for managing groups of PnP devices
+ *
+ * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_PNP_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+
+#include <linux/pnp.h>
+#include "base.h"
+
+LIST_HEAD(pnp_cards);
+LIST_HEAD(pnp_card_drivers);
+
+
+static const struct pnp_card_device_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card)
+{
+ const struct pnp_card_device_id * drv_id = drv->id_table;
+ while (*drv_id->id){
+ if (compare_pnp_id(card->id,drv_id->id)) {
+ int i = 0;
+ for (;;) {
+ int found;
+ struct pnp_dev *dev;
+ if (i == PNP_MAX_DEVICES || ! *drv_id->devs[i].id)
+ return drv_id;
+ found = 0;
+ card_for_each_dev(card, dev) {
+ if (compare_pnp_id(dev->id, drv_id->devs[i].id)) {
+ found = 1;
+ break;
+ }
+ }
+ if (! found)
+ break;
+ i++;
+ }
+ }
+ drv_id++;
+ }
+ return NULL;
+}
+
+static void card_remove(struct pnp_dev * dev)
+{
+ dev->card_link = NULL;
+}
+
+static void card_remove_first(struct pnp_dev * dev)
+{
+ struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver);
+ if (!dev->card || !drv)
+ return;
+ if (drv->remove)
+ drv->remove(dev->card_link);
+ drv->link.remove = &card_remove;
+ kfree(dev->card_link);
+ card_remove(dev);
+}
+
+static int card_probe(struct pnp_card * card, struct pnp_card_driver * drv)
+{
+ const struct pnp_card_device_id *id = match_card(drv,card);
+ if (id) {
+ struct pnp_card_link * clink = pnp_alloc(sizeof(struct pnp_card_link));
+ if (!clink)
+ return 0;
+ clink->card = card;
+ clink->driver = drv;
+ if (drv->probe) {
+ if (drv->probe(clink, id)>=0)
+ return 1;
+ else {
+ struct pnp_dev * dev;
+ card_for_each_dev(card, dev) {
+ if (dev->card_link == clink)
+ pnp_release_card_device(dev);
+ }
+ kfree(clink);
+ }
+ } else
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * pnp_add_card_id - adds an EISA id to the specified card
+ * @id: pointer to a pnp_id structure
+ * @card: pointer to the desired card
+ *
+ */
+
+int pnp_add_card_id(struct pnp_id *id, struct pnp_card * card)
+{
+ struct pnp_id * ptr;
+ if (!id)
+ return -EINVAL;
+ if (!card)
+ return -EINVAL;
+ id->next = NULL;
+ ptr = card->id;
+ while (ptr && ptr->next)
+ ptr = ptr->next;
+ if (ptr)
+ ptr->next = id;
+ else
+ card->id = id;
+ return 0;
+}
+
+static void pnp_free_card_ids(struct pnp_card * card)
+{
+ struct pnp_id * id;
+ struct pnp_id *next;
+ if (!card)
+ return;
+ id = card->id;
+ while (id) {
+ next = id->next;
+ kfree(id);
+ id = next;
+ }
+}
+
+static void pnp_release_card(struct device *dmdev)
+{
+ struct pnp_card * card = to_pnp_card(dmdev);
+ pnp_free_card_ids(card);
+ kfree(card);
+}
+
+
+static ssize_t pnp_show_card_name(struct device *dmdev, char *buf)
+{
+ char *str = buf;
+ struct pnp_card *card = to_pnp_card(dmdev);
+ str += sprintf(str,"%s\n", card->name);
+ return (str - buf);
+}
+
+static DEVICE_ATTR(name,S_IRUGO,pnp_show_card_name,NULL);
+
+static ssize_t pnp_show_card_ids(struct device *dmdev, char *buf)
+{
+ char *str = buf;
+ struct pnp_card *card = to_pnp_card(dmdev);
+ struct pnp_id * pos = card->id;
+
+ while (pos) {
+ str += sprintf(str,"%s\n", pos->id);
+ pos = pos->next;
+ }
+ return (str - buf);
+}
+
+static DEVICE_ATTR(card_id,S_IRUGO,pnp_show_card_ids,NULL);
+
+static int pnp_interface_attach_card(struct pnp_card *card)
+{
+ device_create_file(&card->dev,&dev_attr_name);
+ device_create_file(&card->dev,&dev_attr_card_id);
+ return 0;
+}
+
+/**
+ * pnp_add_card - adds a PnP card to the PnP Layer
+ * @card: pointer to the card to add
+ */
+
+int pnp_add_card(struct pnp_card * card)
+{
+ int error;
+ struct list_head * pos, * temp;
+ if (!card || !card->protocol)
+ return -EINVAL;
+
+ sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, card->number);
+ card->dev.parent = &card->protocol->dev;
+ card->dev.bus = NULL;
+ card->dev.release = &pnp_release_card;
+ error = device_register(&card->dev);
+
+ if (error == 0) {
+ pnp_interface_attach_card(card);
+ spin_lock(&pnp_lock);
+ list_add_tail(&card->global_list, &pnp_cards);
+ list_add_tail(&card->protocol_list, &card->protocol->cards);
+ spin_unlock(&pnp_lock);
+
+ /* we wait until now to add devices in order to ensure the drivers
+ * will be able to use all of the related devices on the card
+ * without waiting any unresonable length of time */
+ list_for_each(pos,&card->devices){
+ struct pnp_dev *dev = card_to_pnp_dev(pos);
+ __pnp_add_device(dev);
+ }
+
+ /* match with card drivers */
+ list_for_each_safe(pos,temp,&pnp_card_drivers){
+ struct pnp_card_driver * drv = list_entry(pos, struct pnp_card_driver, global_list);
+ card_probe(card,drv);
+ }
+ } else
+ pnp_err("sysfs failure, card '%s' will be unavailable", card->dev.bus_id);
+ return error;
+}
+
+/**
+ * pnp_remove_card - removes a PnP card from the PnP Layer
+ * @card: pointer to the card to remove
+ */
+
+void pnp_remove_card(struct pnp_card * card)
+{
+ struct list_head *pos, *temp;
+ if (!card)
+ return;
+ device_unregister(&card->dev);
+ spin_lock(&pnp_lock);
+ list_del(&card->global_list);
+ list_del(&card->protocol_list);
+ spin_unlock(&pnp_lock);
+ list_for_each_safe(pos,temp,&card->devices){
+ struct pnp_dev *dev = card_to_pnp_dev(pos);
+ pnp_remove_card_device(dev);
+ }
+}
+
+/**
+ * pnp_add_card_device - adds a device to the specified card
+ * @card: pointer to the card to add to
+ * @dev: pointer to the device to add
+ */
+
+int pnp_add_card_device(struct pnp_card * card, struct pnp_dev * dev)
+{
+ if (!card || !dev || !dev->protocol)
+ return -EINVAL;
+ dev->dev.parent = &card->dev;
+ dev->card_link = NULL;
+ snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%02x:%02x.%02x", dev->protocol->number,
+ card->number,dev->number);
+ spin_lock(&pnp_lock);
+ dev->card = card;
+ list_add_tail(&dev->card_list, &card->devices);
+ spin_unlock(&pnp_lock);
+ return 0;
+}
+
+/**
+ * pnp_remove_card_device- removes a device from the specified card
+ * @card: pointer to the card to remove from
+ * @dev: pointer to the device to remove
+ */
+
+void pnp_remove_card_device(struct pnp_dev * dev)
+{
+ spin_lock(&pnp_lock);
+ dev->card = NULL;
+ list_del(&dev->card_list);
+ spin_unlock(&pnp_lock);
+ __pnp_remove_device(dev);
+}
+
+/**
+ * pnp_request_card_device - Searches for a PnP device under the specified card
+ * @lcard: pointer to the card link, cannot be NULL
+ * @id: pointer to a PnP ID structure that explains the rules for finding the device
+ * @from: Starting place to search from. If NULL it will start from the begining.
+ */
+
+struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char * id, struct pnp_dev * from)
+{
+ struct list_head * pos;
+ struct pnp_dev * dev;
+ struct pnp_card_driver * drv;
+ struct pnp_card * card;
+ if (!clink || !id)
+ goto done;
+ card = clink->card;
+ drv = clink->driver;
+ if (!from) {
+ pos = card->devices.next;
+ } else {
+ if (from->card != card)
+ goto done;
+ pos = from->card_list.next;
+ }
+ while (pos != &card->devices) {
+ dev = card_to_pnp_dev(pos);
+ if ((!dev->card_link) && compare_pnp_id(dev->id,id))
+ goto found;
+ pos = pos->next;
+ }
+
+done:
+ return NULL;
+
+found:
+ down_write(&dev->dev.bus->subsys.rwsem);
+ dev->card_link = clink;
+ dev->dev.driver = &drv->link.driver;
+ if (drv->link.driver.probe) {
+ if (drv->link.driver.probe(&dev->dev)) {
+ dev->dev.driver = NULL;
+ return NULL;
+ }
+ }
+ device_bind_driver(&dev->dev);
+ up_write(&dev->dev.bus->subsys.rwsem);
+
+ return dev;
+}
+
+/**
+ * pnp_release_card_device - call this when the driver no longer needs the device
+ * @dev: pointer to the PnP device stucture
+ */
+
+void pnp_release_card_device(struct pnp_dev * dev)
+{
+ struct pnp_card_driver * drv = dev->card_link->driver;
+ if (!drv)
+ return;
+ down_write(&dev->dev.bus->subsys.rwsem);
+ drv->link.remove = &card_remove;
+ device_release_driver(&dev->dev);
+ drv->link.remove = &card_remove_first;
+ up_write(&dev->dev.bus->subsys.rwsem);
+}
+
+/**
+ * pnp_register_card_driver - registers a PnP card driver with the PnP Layer
+ * @drv: pointer to the driver to register
+ */
+
+int pnp_register_card_driver(struct pnp_card_driver * drv)
+{
+ int count = 0;
+ struct list_head *pos, *temp;
+
+ drv->link.name = drv->name;
+ drv->link.id_table = NULL; /* this will disable auto matching */
+ drv->link.flags = drv->flags;
+ drv->link.probe = NULL;
+ drv->link.remove = &card_remove_first;
+
+ spin_lock(&pnp_lock);
+ list_add_tail(&drv->global_list, &pnp_card_drivers);
+ spin_unlock(&pnp_lock);
+ pnp_register_driver(&drv->link);
+
+ list_for_each_safe(pos,temp,&pnp_cards){
+ struct pnp_card *card = list_entry(pos, struct pnp_card, global_list);
+ count += card_probe(card,drv);
+ }
+ return count;
+}
+
+/**
+ * pnp_unregister_card_driver - unregisters a PnP card driver from the PnP Layer
+ * @drv: pointer to the driver to unregister
+ */
+
+void pnp_unregister_card_driver(struct pnp_card_driver * drv)
+{
+ spin_lock(&pnp_lock);
+ list_del(&drv->global_list);
+ spin_unlock(&pnp_lock);
+ pnp_unregister_driver(&drv->link);
+}
+
+EXPORT_SYMBOL(pnp_add_card);
+EXPORT_SYMBOL(pnp_remove_card);
+EXPORT_SYMBOL(pnp_add_card_device);
+EXPORT_SYMBOL(pnp_remove_card_device);
+EXPORT_SYMBOL(pnp_add_card_id);
+EXPORT_SYMBOL(pnp_request_card_device);
+EXPORT_SYMBOL(pnp_release_card_device);
+EXPORT_SYMBOL(pnp_register_card_driver);
+EXPORT_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 @@
+/*
+ * core.c - contains all core device and protocol registration functions
+ *
+ * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
+ *
+ */
+
+#include <linux/pnp.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+
+#include "base.h"
+
+
+static LIST_HEAD(pnp_protocols);
+LIST_HEAD(pnp_global);
+DEFINE_SPINLOCK(pnp_lock);
+
+void *pnp_alloc(long size)
+{
+ void *result;
+
+ result = kmalloc(size, GFP_KERNEL);
+ if (!result){
+ printk(KERN_ERR "pnp: Out of Memory\n");
+ return NULL;
+ }
+ memset(result, 0, size);
+ return result;
+}
+
+/**
+ * pnp_protocol_register - adds a pnp protocol to the pnp layer
+ * @protocol: pointer to the corresponding pnp_protocol structure
+ *
+ * Ex protocols: ISAPNP, PNPBIOS, etc
+ */
+
+int pnp_register_protocol(struct pnp_protocol *protocol)
+{
+ int nodenum;
+ struct list_head * pos;
+
+ if (!protocol)
+ return -EINVAL;
+
+ INIT_LIST_HEAD(&protocol->devices);
+ INIT_LIST_HEAD(&protocol->cards);
+ nodenum = 0;
+ spin_lock(&pnp_lock);
+
+ /* assign the lowest unused number */
+ list_for_each(pos,&pnp_protocols) {
+ struct pnp_protocol * cur = to_pnp_protocol(pos);
+ if (cur->number == nodenum){
+ pos = &pnp_protocols;
+ nodenum++;
+ }
+ }
+
+ list_add_tail(&protocol->protocol_list, &pnp_protocols);
+ spin_unlock(&pnp_lock);
+
+ protocol->number = nodenum;
+ sprintf(protocol->dev.bus_id, "pnp%d", nodenum);
+ return device_register(&protocol->dev);
+}
+
+/**
+ * pnp_protocol_unregister - removes a pnp protocol from the pnp layer
+ * @protocol: pointer to the corresponding pnp_protocol structure
+ *
+ */
+void pnp_unregister_protocol(struct pnp_protocol *protocol)
+{
+ spin_lock(&pnp_lock);
+ list_del(&protocol->protocol_list);
+ spin_unlock(&pnp_lock);
+ device_unregister(&protocol->dev);
+}
+
+
+static void pnp_free_ids(struct pnp_dev *dev)
+{
+ struct pnp_id * id;
+ struct pnp_id * next;
+ if (!dev)
+ return;
+ id = dev->id;
+ while (id) {
+ next = id->next;
+ kfree(id);
+ id = next;
+ }
+}
+
+static void pnp_release_device(struct device *dmdev)
+{
+ struct pnp_dev * dev = to_pnp_dev(dmdev);
+ pnp_free_option(dev->independent);
+ pnp_free_option(dev->dependent);
+ pnp_free_ids(dev);
+ kfree(dev);
+}
+
+int __pnp_add_device(struct pnp_dev *dev)
+{
+ int ret;
+ pnp_fixup_device(dev);
+ dev->dev.bus = &pnp_bus_type;
+ dev->dev.release = &pnp_release_device;
+ dev->status = PNP_READY;
+ spin_lock(&pnp_lock);
+ list_add_tail(&dev->global_list, &pnp_global);
+ list_add_tail(&dev->protocol_list, &dev->protocol->devices);
+ spin_unlock(&pnp_lock);
+
+ ret = device_register(&dev->dev);
+ if (ret == 0)
+ pnp_interface_attach_device(dev);
+ return ret;
+}
+
+/*
+ * pnp_add_device - adds a pnp device to the pnp layer
+ * @dev: pointer to dev to add
+ *
+ * adds to driver model, name database, fixups, interface, etc.
+ */
+
+int pnp_add_device(struct pnp_dev *dev)
+{
+ if (!dev || !dev->protocol || dev->card)
+ return -EINVAL;
+ dev->dev.parent = &dev->protocol->dev;
+ sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, dev->number);
+ return __pnp_add_device(dev);
+}
+
+void __pnp_remove_device(struct pnp_dev *dev)
+{
+ spin_lock(&pnp_lock);
+ list_del(&dev->global_list);
+ list_del(&dev->protocol_list);
+ spin_unlock(&pnp_lock);
+ device_unregister(&dev->dev);
+}
+
+/**
+ * pnp_remove_device - removes a pnp device from the pnp layer
+ * @dev: pointer to dev to add
+ *
+ * this function will free all mem used by dev
+ */
+
+void pnp_remove_device(struct pnp_dev *dev)
+{
+ if (!dev || dev->card)
+ return;
+ __pnp_remove_device(dev);
+}
+
+static int __init pnp_init(void)
+{
+ printk(KERN_INFO "Linux Plug and Play Support v0.97 (c) Adam Belay\n");
+ return bus_register(&pnp_bus_type);
+}
+
+subsys_initcall(pnp_init);
+
+EXPORT_SYMBOL(pnp_register_protocol);
+EXPORT_SYMBOL(pnp_unregister_protocol);
+EXPORT_SYMBOL(pnp_add_device);
+EXPORT_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 @@
+/*
+ * driver.c - device id matching, driver model, etc.
+ *
+ * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_PNP_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+
+#include <linux/pnp.h>
+#include "base.h"
+
+static int compare_func(const char *ida, const char *idb)
+{
+ int i;
+ /* we only need to compare the last 4 chars */
+ for (i=3; i<7; i++)
+ {
+ if (ida[i] != 'X' &&
+ idb[i] != 'X' &&
+ toupper(ida[i]) != toupper(idb[i]))
+ return 0;
+ }
+ return 1;
+}
+
+int compare_pnp_id(struct pnp_id *pos, const char *id)
+{
+ if (!pos || !id || (strlen(id) != 7))
+ return 0;
+ if (memcmp(id,"ANYDEVS",7)==0)
+ return 1;
+ while (pos){
+ if (memcmp(pos->id,id,3)==0)
+ if (compare_func(pos->id,id)==1)
+ return 1;
+ pos = pos->next;
+ }
+ return 0;
+}
+
+static const struct pnp_device_id * match_device(struct pnp_driver *drv, struct pnp_dev *dev)
+{
+ const struct pnp_device_id *drv_id = drv->id_table;
+ if (!drv_id)
+ return NULL;
+
+ while (*drv_id->id) {
+ if (compare_pnp_id(dev->id, drv_id->id))
+ return drv_id;
+ drv_id++;
+ }
+ return NULL;
+}
+
+int pnp_device_attach(struct pnp_dev *pnp_dev)
+{
+ spin_lock(&pnp_lock);
+ if(pnp_dev->status != PNP_READY){
+ spin_unlock(&pnp_lock);
+ return -EBUSY;
+ }
+ pnp_dev->status = PNP_ATTACHED;
+ spin_unlock(&pnp_lock);
+ return 0;
+}
+
+void pnp_device_detach(struct pnp_dev *pnp_dev)
+{
+ spin_lock(&pnp_lock);
+ if (pnp_dev->status == PNP_ATTACHED)
+ pnp_dev->status = PNP_READY;
+ spin_unlock(&pnp_lock);
+ pnp_disable_dev(pnp_dev);
+}
+
+static int pnp_device_probe(struct device *dev)
+{
+ int error;
+ struct pnp_driver *pnp_drv;
+ struct pnp_dev *pnp_dev;
+ const struct pnp_device_id *dev_id = NULL;
+ pnp_dev = to_pnp_dev(dev);
+ pnp_drv = to_pnp_driver(dev->driver);
+
+ pnp_dbg("match found with the PnP device '%s' and the driver '%s'", dev->bus_id,pnp_drv->name);
+
+ error = pnp_device_attach(pnp_dev);
+ if (error < 0)
+ return error;
+
+ if (pnp_dev->active == 0) {
+ if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
+ error = pnp_activate_dev(pnp_dev);
+ if (error < 0)
+ return error;
+ }
+ } else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE)
+ == PNP_DRIVER_RES_DISABLE) {
+ error = pnp_disable_dev(pnp_dev);
+ if (error < 0)
+ return error;
+ }
+ error = 0;
+ if (pnp_drv->probe) {
+ dev_id = match_device(pnp_drv, pnp_dev);
+ if (dev_id != NULL)
+ error = pnp_drv->probe(pnp_dev, dev_id);
+ }
+ if (error >= 0){
+ pnp_dev->driver = pnp_drv;
+ error = 0;
+ } else
+ goto fail;
+ return error;
+
+fail:
+ pnp_device_detach(pnp_dev);
+ return error;
+}
+
+static int pnp_device_remove(struct device *dev)
+{
+ struct pnp_dev * pnp_dev = to_pnp_dev(dev);
+ struct pnp_driver * drv = pnp_dev->driver;
+
+ if (drv) {
+ if (drv->remove)
+ drv->remove(pnp_dev);
+ pnp_dev->driver = NULL;
+ }
+ pnp_device_detach(pnp_dev);
+ return 0;
+}
+
+static int pnp_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct pnp_dev * pnp_dev = to_pnp_dev(dev);
+ struct pnp_driver * pnp_drv = to_pnp_driver(drv);
+ if (match_device(pnp_drv, pnp_dev) == NULL)
+ return 0;
+ return 1;
+}
+
+
+struct bus_type pnp_bus_type = {
+ .name = "pnp",
+ .match = pnp_bus_match,
+};
+
+
+int pnp_register_driver(struct pnp_driver *drv)
+{
+ int count;
+ struct list_head *pos;
+
+ pnp_dbg("the driver '%s' has been registered", drv->name);
+
+ drv->driver.name = drv->name;
+ drv->driver.bus = &pnp_bus_type;
+ drv->driver.probe = pnp_device_probe;
+ drv->driver.remove = pnp_device_remove;
+
+ count = driver_register(&drv->driver);
+
+ /* get the number of initial matches */
+ if (count >= 0){
+ count = 0;
+ list_for_each(pos,&drv->driver.devices){
+ count++;
+ }
+ }
+ return count;
+}
+
+void pnp_unregister_driver(struct pnp_driver *drv)
+{
+ driver_unregister(&drv->driver);
+ pnp_dbg("the driver '%s' has been unregistered", drv->name);
+}
+
+/**
+ * pnp_add_id - adds an EISA id to the specified device
+ * @id: pointer to a pnp_id structure
+ * @dev: pointer to the desired device
+ *
+ */
+
+int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev)
+{
+ struct pnp_id *ptr;
+ if (!id)
+ return -EINVAL;
+ if (!dev)
+ return -EINVAL;
+ id->next = NULL;
+ ptr = dev->id;
+ while (ptr && ptr->next)
+ ptr = ptr->next;
+ if (ptr)
+ ptr->next = id;
+ else
+ dev->id = id;
+ return 0;
+}
+
+EXPORT_SYMBOL(pnp_register_driver);
+EXPORT_SYMBOL(pnp_unregister_driver);
+EXPORT_SYMBOL(pnp_add_id);
+EXPORT_SYMBOL(pnp_device_attach);
+EXPORT_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 @@
+/*
+ * interface.c - contains everything related to the user interface
+ *
+ * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@suse.cz>
+ * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
+ *
+ */
+
+#include <linux/pnp.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+
+#include "base.h"
+
+struct pnp_info_buffer {
+ char *buffer; /* pointer to begin of buffer */
+ char *curr; /* current position in buffer */
+ unsigned long size; /* current size */
+ unsigned long len; /* total length of buffer */
+ int stop; /* stop flag */
+ int error; /* error code */
+};
+
+typedef struct pnp_info_buffer pnp_info_buffer_t;
+
+static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt,...)
+{
+ va_list args;
+ int res;
+
+ if (buffer->stop || buffer->error)
+ return 0;
+ va_start(args, fmt);
+ res = vsnprintf(buffer->curr, buffer->len - buffer->size, fmt, args);
+ va_end(args);
+ if (buffer->size + res >= buffer->len) {
+ buffer->stop = 1;
+ return 0;
+ }
+ buffer->curr += res;
+ buffer->size += res;
+ return res;
+}
+
+static void pnp_print_port(pnp_info_buffer_t *buffer, char *space, struct pnp_port *port)
+{
+ pnp_printf(buffer, "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
+ space, port->min, port->max, port->align ? (port->align-1) : 0, port->size,
+ port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
+}
+
+static void pnp_print_irq(pnp_info_buffer_t *buffer, char *space, struct pnp_irq *irq)
+{
+ int first = 1, i;
+
+ pnp_printf(buffer, "%sirq ", space);
+ for (i = 0; i < PNP_IRQ_NR; i++)
+ if (test_bit(i, irq->map)) {
+ if (!first) {
+ pnp_printf(buffer, ",");
+ } else {
+ first = 0;
+ }
+ if (i == 2 || i == 9)
+ pnp_printf(buffer, "2/9");
+ else
+ pnp_printf(buffer, "%i", i);
+ }
+ if (bitmap_empty(irq->map, PNP_IRQ_NR))
+ pnp_printf(buffer, "<none>");
+ if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
+ pnp_printf(buffer, " High-Edge");
+ if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
+ pnp_printf(buffer, " Low-Edge");