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!
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
new file mode 100644
index 0000000..7f31991
--- /dev/null
+++ b/drivers/pci/Kconfig
@@ -0,0 +1,59 @@
+#
+# PCI configuration
+#
+config PCI_MSI
+	bool "Message Signaled Interrupts (MSI and MSI-X)"
+	depends on PCI
+	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+	help
+	   This allows device drivers to enable MSI (Message Signaled
+	   Interrupts).  Message Signaled Interrupts enable a device to
+	   generate an interrupt using an inbound Memory Write on its
+	   PCI bus instead of asserting a device IRQ pin.
+
+	   If you don't know what to do here, say N.
+
+config PCI_LEGACY_PROC
+	bool "Legacy /proc/pci interface"
+	depends on PCI
+	---help---
+	  This feature enables a procfs file -- /proc/pci -- that provides a 
+	  summary of PCI devices in the system. 
+
+	  This feature has been deprecated as of v2.5.53, in favor of using the 
+	  tool lspci(8). This feature may be removed at a future date. 
+
+	  lspci can provide the same data, as well as much more. lspci is a part of
+	  the pci-utils package, which should be installed by your distribution. 
+	  See <file:Documentation/Changes> for information on where to get the latest
+	  version. 
+
+	  When in doubt, say N.
+
+config PCI_NAMES
+	bool "PCI device name database"
+	depends on PCI
+	---help---
+	  By default, the kernel contains a database of all known PCI device
+	  names to make the information in /proc/pci, /proc/ioports and
+	  similar files comprehensible to the user. 
+
+	  This database increases size of the kernel image by about 80KB. This 
+	  memory is freed after the system boots up if CONFIG_HOTPLUG is not set.
+
+	  Anyway, if you are building an installation floppy or kernel for an 
+	  embedded system where kernel image size really matters, you can disable 
+	  this feature and you'll get device ID numbers instead of names.
+
+	  When in doubt, say Y.
+
+config PCI_DEBUG
+	bool "PCI Debugging"
+	depends on PCI && DEBUG_KERNEL
+	help
+	  Say Y here if you want the PCI core to produce a bunch of debug
+	  messages to the system log.  Select this if you are having a
+	  problem with PCI support and want to see more of what is going on.
+
+	  When in doubt, say N.
+
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
new file mode 100644
index 0000000..7dea494
--- /dev/null
+++ b/drivers/pci/Makefile
@@ -0,0 +1,65 @@
+#
+# Makefile for the PCI bus specific drivers.
+#
+
+obj-y		+= access.o bus.o probe.o remove.o pci.o quirks.o \
+			names.o pci-driver.o search.o pci-sysfs.o \
+			rom.o
+obj-$(CONFIG_PROC_FS) += proc.o
+
+ifndef CONFIG_SPARC64
+obj-y += setup-res.o
+endif
+
+obj-$(CONFIG_HOTPLUG) += hotplug.o
+
+# Build the PCI Hotplug drivers if we were asked to
+obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
+
+#
+# Some architectures use the generic PCI setup functions
+#
+obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
+obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
+obj-$(CONFIG_PARISC) += setup-bus.o
+obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
+obj-$(CONFIG_PPC32) += setup-irq.o
+obj-$(CONFIG_PPC64) += setup-bus.o
+obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
+obj-$(CONFIG_X86_VISWS) += setup-irq.o
+obj-$(CONFIG_PCI_MSI) += msi.o
+
+#
+# ACPI Related PCI FW Functions
+#
+obj-$(CONFIG_ACPI)    += pci-acpi.o
+
+# Cardbus & CompactPCI use setup-bus
+obj-$(CONFIG_HOTPLUG) += setup-bus.o
+
+ifndef CONFIG_X86
+obj-y += syscall.o
+endif
+
+ifeq ($(CONFIG_PCI_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+hostprogs-y := gen-devlist
+
+# Dependencies on generated files need to be listed explicitly
+$(obj)/names.o: $(obj)/devlist.h $(obj)/classlist.h
+$(obj)/classlist.h: $(obj)/devlist.h
+
+# And that's how to generate them
+quiet_cmd_devlist = DEVLIST $@
+      cmd_devlist = ( cd $(obj); ./gen-devlist ) < $<
+$(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist
+	$(call cmd,devlist)
+
+# Files generated that shall be removed upon make clean
+clean-files := devlist.h classlist.h
+
+# Build PCI Express stuff if needed
+obj-$(CONFIG_PCIEPORTBUS) += pcie/
+
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
new file mode 100644
index 0000000..24a76de
--- /dev/null
+++ b/drivers/pci/access.c
@@ -0,0 +1,62 @@
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+
+static DEFINE_SPINLOCK(pci_lock);
+
+/*
+ *  Wrappers for all PCI configuration access functions.  They just check
+ *  alignment, do locking and call the low-level functions pointed to
+ *  by pci_dev->ops.
+ */
+
+#define PCI_byte_BAD 0
+#define PCI_word_BAD (pos & 1)
+#define PCI_dword_BAD (pos & 3)
+
+#define PCI_OP_READ(size,type,len) \
+int pci_bus_read_config_##size \
+	(struct pci_bus *bus, unsigned int devfn, int pos, type *value)	\
+{									\
+	int res;							\
+	unsigned long flags;						\
+	u32 data = 0;							\
+	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
+	spin_lock_irqsave(&pci_lock, flags);				\
+	res = bus->ops->read(bus, devfn, pos, len, &data);		\
+	*value = (type)data;						\
+	spin_unlock_irqrestore(&pci_lock, flags);			\
+	return res;							\
+}
+
+#define PCI_OP_WRITE(size,type,len) \
+int pci_bus_write_config_##size \
+	(struct pci_bus *bus, unsigned int devfn, int pos, type value)	\
+{									\
+	int res;							\
+	unsigned long flags;						\
+	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
+	spin_lock_irqsave(&pci_lock, flags);				\
+	res = bus->ops->write(bus, devfn, pos, len, value);		\
+	spin_unlock_irqrestore(&pci_lock, flags);			\
+	return res;							\
+}
+
+PCI_OP_READ(byte, u8, 1)
+PCI_OP_READ(word, u16, 2)
+PCI_OP_READ(dword, u32, 4)
+PCI_OP_WRITE(byte, u8, 1)
+PCI_OP_WRITE(word, u16, 2)
+PCI_OP_WRITE(dword, u32, 4)
+
+EXPORT_SYMBOL(pci_bus_read_config_byte);
+EXPORT_SYMBOL(pci_bus_read_config_word);
+EXPORT_SYMBOL(pci_bus_read_config_dword);
+EXPORT_SYMBOL(pci_bus_write_config_byte);
+EXPORT_SYMBOL(pci_bus_write_config_word);
+EXPORT_SYMBOL(pci_bus_write_config_dword);
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
new file mode 100644
index 0000000..dbd3360
--- /dev/null
+++ b/drivers/pci/bus.c
@@ -0,0 +1,151 @@
+/*
+ *	drivers/pci/bus.c
+ *
+ * From setup-res.c, by:
+ *	Dave Rusling (david.rusling@reo.mts.dec.com)
+ *	David Mosberger (davidm@cs.arizona.edu)
+ *	David Miller (davem@redhat.com)
+ *	Ivan Kokshaysky (ink@jurassic.park.msu.ru)
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+#include "pci.h"
+
+/**
+ * pci_bus_alloc_resource - allocate a resource from a parent bus
+ * @bus: PCI bus
+ * @res: resource to allocate
+ * @size: size of resource to allocate
+ * @align: alignment of resource to allocate
+ * @min: minimum /proc/iomem address to allocate
+ * @type_mask: IORESOURCE_* type flags
+ * @alignf: resource alignment function
+ * @alignf_data: data argument for resource alignment function
+ *
+ * Given the PCI bus a device resides on, the size, minimum address,
+ * alignment and type, try to find an acceptable resource allocation
+ * for a specific device resource.
+ */
+int
+pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+	unsigned long size, unsigned long align, unsigned long min,
+	unsigned int type_mask,
+	void (*alignf)(void *, struct resource *,
+			unsigned long, unsigned long),
+	void *alignf_data)
+{
+	int i, ret = -ENOMEM;
+
+	type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
+
+	for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+		struct resource *r = bus->resource[i];
+		if (!r)
+			continue;
+
+		/* type_mask must match */
+		if ((res->flags ^ r->flags) & type_mask)
+			continue;
+
+		/* We cannot allocate a non-prefetching resource
+		   from a pre-fetching area */
+		if ((r->flags & IORESOURCE_PREFETCH) &&
+		    !(res->flags & IORESOURCE_PREFETCH))
+			continue;
+
+		/* Ok, try it out.. */
+		ret = allocate_resource(r, res, size, min, -1, align,
+					alignf, alignf_data);
+		if (ret == 0)
+			break;
+	}
+	return ret;
+}
+
+/**
+ * add a single device
+ * @dev: device to add
+ *
+ * This adds a single pci device to the global
+ * device list and adds sysfs and procfs entries
+ */
+void __devinit pci_bus_add_device(struct pci_dev *dev)
+{
+	device_add(&dev->dev);
+
+	spin_lock(&pci_bus_lock);
+	list_add_tail(&dev->global_list, &pci_devices);
+	spin_unlock(&pci_bus_lock);
+
+	pci_proc_attach_device(dev);
+	pci_create_sysfs_dev_files(dev);
+}
+
+/**
+ * pci_bus_add_devices - insert newly discovered PCI devices
+ * @bus: bus to check for new devices
+ *
+ * Add newly discovered PCI devices (which are on the bus->devices
+ * list) to the global PCI device list, add the sysfs and procfs
+ * entries.  Where a bridge is found, add the discovered bus to
+ * the parents list of child buses, and recurse (breadth-first
+ * to be compatible with 2.4)
+ *
+ * Call hotplug for each new devices.
+ */
+void __devinit pci_bus_add_devices(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		/*
+		 * Skip already-present devices (which are on the
+		 * global device list.)
+		 */
+		if (!list_empty(&dev->global_list))
+			continue;
+		pci_bus_add_device(dev);
+	}
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+
+		BUG_ON(list_empty(&dev->global_list));
+
+		/*
+		 * If there is an unattached subordinate bus, attach
+		 * it and then scan for unattached PCI devices.
+		 */
+		if (dev->subordinate && list_empty(&dev->subordinate->node)) {
+			spin_lock(&pci_bus_lock);
+			list_add_tail(&dev->subordinate->node, &dev->bus->children);
+			spin_unlock(&pci_bus_lock);
+			pci_bus_add_devices(dev->subordinate);
+
+			sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
+		}
+	}
+}
+
+void pci_enable_bridges(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		if (dev->subordinate) {
+			pci_enable_device(dev);
+			pci_set_master(dev);
+			pci_enable_bridges(dev->subordinate);
+		}
+	}
+}
+
+EXPORT_SYMBOL(pci_bus_alloc_resource);
+EXPORT_SYMBOL_GPL(pci_bus_add_device);
+EXPORT_SYMBOL(pci_bus_add_devices);
+EXPORT_SYMBOL(pci_enable_bridges);
diff --git a/drivers/pci/gen-devlist.c b/drivers/pci/gen-devlist.c
new file mode 100644
index 0000000..8abfc49
--- /dev/null
+++ b/drivers/pci/gen-devlist.c
@@ -0,0 +1,132 @@
+/*
+ *	Generate devlist.h and classlist.h from the PCI ID file.
+ *
+ *	(c) 1999--2002 Martin Mares <mj@ucw.cz>
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define MAX_NAME_SIZE 200
+
+static void
+pq(FILE *f, const char *c, int len)
+{
+	int i = 1;
+	while (*c && i != len) {
+		if (*c == '"')
+			fprintf(f, "\\\"");
+		else {
+			fputc(*c, f);
+			if (*c == '?' && c[1] == '?') {
+				/* Avoid trigraphs */
+				fprintf(f, "\" \"");
+			}
+		}
+		c++;
+		i++;
+	}
+}
+
+int
+main(void)
+{
+	char line[1024], *c, *bra, vend[8];
+	int vendors = 0;
+	int mode = 0;
+	int lino = 0;
+	int vendor_len = 0;
+	FILE *devf, *clsf;
+
+	devf = fopen("devlist.h", "w");
+	clsf = fopen("classlist.h", "w");
+	if (!devf || !clsf) {
+		fprintf(stderr, "Cannot create output file!\n");
+		return 1;
+	}
+
+	while (fgets(line, sizeof(line)-1, stdin)) {
+		lino++;
+		if ((c = strchr(line, '\n')))
+			*c = 0;
+		if (!line[0] || line[0] == '#')
+			continue;
+		if (line[1] == ' ') {
+			if (line[0] == 'C' && strlen(line) > 4 && line[4] == ' ') {
+				vend[0] = line[2];
+				vend[1] = line[3];
+				vend[2] = 0;
+				mode = 2;
+			} else goto err;
+		}
+		else if (line[0] == '\t') {
+			if (line[1] == '\t')
+				continue;
+			switch (mode) {
+			case 1:
+				if (strlen(line) > 5 && line[5] == ' ') {
+					c = line + 5;
+					while (*c == ' ')
+						*c++ = 0;
+					if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) {
+						/* Too long, try cutting off long description */
+						bra = strchr(c, '[');
+						if (bra && bra > c && bra[-1] == ' ')
+							bra[-1] = 0;
+						if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) {
+							fprintf(stderr, "Line %d: Device name too long. Name truncated.\n", lino);
+							fprintf(stderr, "%s\n", c);
+							/*return 1;*/
+						}
+					}
+					fprintf(devf, "\tDEVICE(%s,%s,\"", vend, line+1);
+					pq(devf, c, MAX_NAME_SIZE - vendor_len - 1);
+					fputs("\")\n", devf);
+				} else goto err;
+				break;
+			case 2:
+				if (strlen(line) > 3 && line[3] == ' ') {
+					c = line + 3;
+					while (*c == ' ')
+						*c++ = 0;
+					fprintf(clsf, "CLASS(%s%s, \"%s\")\n", vend, line+1, c);
+				} else goto err;
+				break;
+			default:
+				goto err;
+			}
+		} else if (strlen(line) > 4 && line[4] == ' ') {
+			c = line + 4;
+			while (*c == ' ')
+				*c++ = 0;
+			if (vendors)
+				fputs("ENDVENDOR()\n\n", devf);
+			vendors++;
+			strcpy(vend, line);
+			vendor_len = strlen(c);
+			if (vendor_len + 24 > MAX_NAME_SIZE) {
+				fprintf(stderr, "Line %d: Vendor name too long\n", lino);
+				return 1;
+			}
+			fprintf(devf, "VENDOR(%s,\"", vend);
+			pq(devf, c, 0);
+			fputs("\")\n", devf);
+			mode = 1;
+		} else {
+		err:
+			fprintf(stderr, "Line %d: Syntax error in mode %d: %s\n", lino, mode, line);
+			return 1;
+		}
+	}
+	fputs("ENDVENDOR()\n\
+\n\
+#undef VENDOR\n\
+#undef DEVICE\n\
+#undef ENDVENDOR\n", devf);
+	fputs("\n#undef CLASS\n", clsf);
+
+	fclose(devf);
+	fclose(clsf);
+
+	return 0;
+}
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
new file mode 100644
index 0000000..d471b3e
--- /dev/null
+++ b/drivers/pci/hotplug.c
@@ -0,0 +1,163 @@
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include "pci.h"
+
+int pci_hotplug (struct device *dev, char **envp, int num_envp,
+		 char *buffer, int buffer_size)
+{
+	struct pci_dev *pdev;
+	char *scratch;
+	int i = 0;
+	int length = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	pdev = to_pci_dev(dev);
+	if (!pdev)
+		return -ENODEV;
+
+	scratch = buffer;
+
+	/* stuff we want to pass to /sbin/hotplug */
+	envp[i++] = scratch;
+	length += scnprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
+			    pdev->class);
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+
+	envp[i++] = scratch;
+	length += scnprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
+			    pdev->vendor, pdev->device);
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+
+	envp[i++] = scratch;
+	length += scnprintf (scratch, buffer_size - length,
+			    "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
+			    pdev->subsystem_device);
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+	++length;
+	scratch += length;
+
+	envp[i++] = scratch;
+	length += scnprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
+			    pci_name(pdev));
+	if ((buffer_size - length <= 0) || (i >= num_envp))
+		return -ENOMEM;
+
+	envp[i] = NULL;
+
+	return 0;
+}
+
+static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
+{
+	struct list_head *ln;
+	struct pci_dev *dev;
+	struct pci_dev_wrapped wrapped_dev;
+	int result = 0;
+
+	pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(wrapped_bus->bus),
+		wrapped_bus->bus->number);
+
+	if (fn->pre_visit_pci_bus) {
+		result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
+		if (result)
+			return result;
+	}
+
+	ln = wrapped_bus->bus->devices.next; 
+	while (ln != &wrapped_bus->bus->devices) {
+		dev = pci_dev_b(ln);
+		ln = ln->next;
+
+		memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+		wrapped_dev.dev = dev;
+
+		result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
+		if (result)
+			return result;
+	}
+
+	if (fn->post_visit_pci_bus)
+		result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
+
+	return result;
+}
+
+static int pci_visit_bridge (struct pci_visit * fn,
+			     struct pci_dev_wrapped *wrapped_dev,
+			     struct pci_bus_wrapped *wrapped_parent)
+{
+	struct pci_bus *bus;
+	struct pci_bus_wrapped wrapped_bus;
+	int result = 0;
+
+	pr_debug("PCI: Scanning bridge %s\n", pci_name(wrapped_dev->dev));
+
+	if (fn->visit_pci_dev) {
+		result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
+		if (result)
+			return result;
+	}
+
+	bus = wrapped_dev->dev->subordinate;
+	if (bus) {
+		memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+		wrapped_bus.bus = bus;
+
+		result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
+	}
+	return result;
+}
+
+/**
+ * pci_visit_dev - scans the pci buses.
+ * Every bus and every function is presented to a custom
+ * function that can act upon it.
+ */
+int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
+		  struct pci_bus_wrapped *wrapped_parent)
+{
+	struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
+	int result = 0;
+
+	if (!dev)
+		return 0;
+
+	if (fn->pre_visit_pci_dev) {
+		result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
+		if (result)
+			return result;
+	}
+
+	switch (dev->class >> 8) {
+		case PCI_CLASS_BRIDGE_PCI:
+			result = pci_visit_bridge(fn, wrapped_dev,
+						  wrapped_parent);
+			if (result)
+				return result;
+			break;
+		default:
+			pr_debug("PCI: Scanning device %s\n", pci_name(dev));
+			if (fn->visit_pci_dev) {
+				result = fn->visit_pci_dev (wrapped_dev,
+							    wrapped_parent);
+				if (result)
+					return result;
+			}
+	}
+
+	if (fn->post_visit_pci_dev)
+		result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
+
+	return result;
+}
+EXPORT_SYMBOL(pci_visit_dev);
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
new file mode 100644
index 0000000..1a4d4ca
--- /dev/null
+++ b/drivers/pci/hotplug/Kconfig
@@ -0,0 +1,197 @@
+#
+# PCI Hotplug support
+#
+
+menu "PCI Hotplug Support"
+
+config HOTPLUG_PCI
+	tristate "Support for PCI Hotplug (EXPERIMENTAL)"
+	depends on PCI && EXPERIMENTAL
+	select HOTPLUG
+	---help---
+	  Say Y here if you have a motherboard with a PCI Hotplug controller.
+	  This allows you to add and remove PCI cards while the machine is
+	  powered up and running.  The file system pcihpfs must be mounted
+	  in order to interact with any PCI Hotplug controllers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pci_hotplug.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_FAKE
+	tristate "Fake PCI Hotplug driver"
+	depends on HOTPLUG_PCI
+	help
+	  Say Y here if you want to use the fake PCI hotplug driver. It can
+	  be used to simulate PCI hotplug events if even if your system is
+	  not PCI hotplug capable.
+
+	  This driver will "emulate" removing PCI devices from the system.
+	  If the "power" file is written to with "0" then the specified PCI
+	  device will be completely removed from the kernel.
+
+	  WARNING, this does NOT turn off the power to the PCI device.
+	  This is a "logical" removal, not a physical or electrical
+	  removal.
+
+	  Use this module at your own risk.  You have been warned!
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called fakephp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_COMPAQ
+	tristate "Compaq PCI Hotplug driver"
+	depends on HOTPLUG_PCI && X86 && PCI_BIOS
+	help
+	  Say Y here if you have a motherboard with a Compaq PCI Hotplug
+	  controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpqphp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_COMPAQ_NVRAM
+	bool "Save configuration into NVRAM on Compaq servers"
+	depends on HOTPLUG_PCI_COMPAQ
+	help
+	  Say Y here if you have a Compaq server that has a PCI Hotplug
+	  controller.  This will allow the PCI Hotplug driver to store the PCI
+	  system configuration options in NVRAM.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_IBM
+	tristate "IBM PCI Hotplug driver"
+	depends on HOTPLUG_PCI && X86_IO_APIC && X86 && PCI_BIOS
+	help
+	  Say Y here if you have a motherboard with a IBM PCI Hotplug
+	  controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ibmphp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_ACPI
+	tristate "ACPI PCI Hotplug driver"
+	depends on ACPI_BUS && HOTPLUG_PCI
+	help
+	  Say Y here if you have a system that supports PCI Hotplug using
+	  ACPI.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called acpiphp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_ACPI_IBM
+	tristate "ACPI PCI Hotplug driver IBM extensions"
+	depends on HOTPLUG_PCI_ACPI
+	help
+	  Say Y here if you have an IBM system that supports PCI Hotplug using
+	  ACPI.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called acpiphp_ibm.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_CPCI
+	bool "CompactPCI Hotplug driver"
+	depends on HOTPLUG_PCI
+	help
+	  Say Y here if you have a CompactPCI system card with CompactPCI
+	  hotswap support per the PICMG 2.1 specification.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_CPCI_ZT5550
+	tristate "Ziatech ZT5550 CompactPCI Hotplug driver"
+	depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86
+	help
+	  Say Y here if you have an Performance Technologies (formerly Intel,
+          formerly just Ziatech) Ziatech ZT5550 CompactPCI system card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpcihp_zt5550.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_CPCI_GENERIC
+	tristate "Generic port I/O CompactPCI Hotplug driver"
+	depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86
+	help
+	  Say Y here if you have a CompactPCI system card that exposes the #ENUM
+	  hotswap signal as a bit in a system register that can be read through
+	  standard port I/O.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpcihp_generic.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_SHPC
+	tristate "SHPC PCI Hotplug driver"
+	depends on HOTPLUG_PCI
+	help
+	  Say Y here if you have a motherboard with a SHPC PCI Hotplug
+	  controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called shpchp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
+	bool "Use polling mechanism for hot-plug events (for testing purpose)"
+	depends on HOTPLUG_PCI_SHPC
+	help
+	  Say Y here if you want to use the polling mechanism for hot-plug 
+	  events for early platform testing.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_SHPC_PHPRM_LEGACY
+	bool "For AMD SHPC only: Use $HRT for resource/configuration"
+	depends on HOTPLUG_PCI_SHPC && !ACPI_BUS 
+	help
+	  Say Y here for AMD SHPC. You have to select this option if you are 
+	  using this driver on platform with AMD SHPC.
+
+config HOTPLUG_PCI_RPA
+	tristate "RPA PCI Hotplug driver"
+	depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
+	help
+	  Say Y here if you have a a RPA system that supports PCI Hotplug.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rpaphp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_RPA_DLPAR
+	tristate "RPA Dynamic Logical Partitioning for I/O slots"
+	depends on HOTPLUG_PCI_RPA
+	help
+	  Say Y here if your system supports Dynamic Logical Partitioning
+	  for I/O slots.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rpadlpar_io.
+ 
+ 	  When in doubt, say N.
+
+config HOTPLUG_PCI_SGI
+	tristate "SGI PCI Hotplug Support"
+	depends on HOTPLUG_PCI && IA64_SGI_SN2
+	help
+	  Say Y here if you have an SGI IA64 Altix system.
+
+	  When in doubt, say N.
+
+endmenu
+
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
new file mode 100644
index 0000000..93c120d
--- /dev/null
+++ b/drivers/pci/hotplug/Makefile
@@ -0,0 +1,74 @@
+#
+# Makefile for the Linux kernel pci hotplug controller drivers.
+#
+
+obj-$(CONFIG_HOTPLUG_PCI)		+= pci_hotplug.o
+obj-$(CONFIG_HOTPLUG_PCI_FAKE)		+= fakephp.o 
+obj-$(CONFIG_HOTPLUG_PCI_COMPAQ)	+= cpqphp.o
+obj-$(CONFIG_HOTPLUG_PCI_IBM)		+= ibmphp.o
+obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= acpiphp.o
+obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM)	+= acpiphp_ibm.o
+obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550)	+= cpcihp_zt5550.o
+obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC)	+= cpcihp_generic.o
+obj-$(CONFIG_HOTPLUG_PCI_PCIE)		+= pciehp.o
+obj-$(CONFIG_HOTPLUG_PCI_SHPC)		+= shpchp.o
+obj-$(CONFIG_HOTPLUG_PCI_RPA)		+= rpaphp.o
+obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR)	+= rpadlpar_io.o
+
+pci_hotplug-objs	:=	pci_hotplug_core.o
+
+ifdef CONFIG_HOTPLUG_PCI_CPCI
+pci_hotplug-objs	+=	cpci_hotplug_core.o	\
+				cpci_hotplug_pci.o
+endif
+
+cpqphp-objs		:=	cpqphp_core.o	\
+				cpqphp_ctrl.o	\
+				cpqphp_sysfs.o	\
+				cpqphp_pci.o
+cpqphp-$(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM) += cpqphp_nvram.o
+cpqphp-objs += $(cpqphp-y)
+
+ibmphp-objs		:=	ibmphp_core.o	\
+				ibmphp_ebda.o	\
+				ibmphp_pci.o	\
+				ibmphp_res.o	\
+				ibmphp_hpc.o
+
+acpiphp-objs		:=	acpiphp_core.o	\
+				acpiphp_glue.o	\
+				acpiphp_pci.o	\
+				acpiphp_res.o
+
+rpaphp-objs		:=	rpaphp_core.o	\
+				rpaphp_pci.o	\
+				rpaphp_slot.o	\
+				rpaphp_vio.o
+
+rpadlpar_io-objs	:=	rpadlpar_core.o \
+				rpadlpar_sysfs.o
+
+pciehp-objs		:=	pciehp_core.o	\
+				pciehp_ctrl.o	\
+				pciehp_pci.o	\
+				pciehp_hpc.o
+ifdef CONFIG_ACPI_BUS
+	pciehp-objs += pciehprm_acpi.o
+else
+	pciehp-objs += pciehprm_nonacpi.o
+endif
+
+shpchp-objs		:=	shpchp_core.o	\
+				shpchp_ctrl.o	\
+				shpchp_pci.o	\
+				shpchp_sysfs.o	\
+				shpchp_hpc.o
+ifdef CONFIG_ACPI_BUS
+	shpchp-objs += shpchprm_acpi.o
+else
+	ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY
+		shpchp-objs += shpchprm_legacy.o
+	else
+		shpchp-objs += shpchprm_nonacpi.o
+	endif
+endif
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
new file mode 100644
index 0000000..d949987
--- /dev/null
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -0,0 +1,268 @@
+/*
+ * ACPI PCI Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002,2003 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>,
+ *		    <t-kochi@bq.jp.nec.com>
+ *
+ */
+
+#ifndef _ACPIPHP_H
+#define _ACPIPHP_H
+
+#include <linux/acpi.h>
+#include <linux/kobject.h>	/* for KOBJ_NAME_LEN */
+#include "pci_hotplug.h"
+
+#define dbg(format, arg...)					\
+	do {							\
+		if (acpiphp_debug)				\
+			printk(KERN_DEBUG "%s: " format,	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+
+/* name size which is used for entries in pcihpfs */
+#define SLOT_NAME_SIZE	KOBJ_NAME_LEN		/* {_SUN} */
+
+struct acpiphp_bridge;
+struct acpiphp_slot;
+struct pci_resource;
+
+/*
+ * struct slot - slot information for each *physical* slot
+ */
+struct slot {
+	u8 number;
+	struct hotplug_slot	*hotplug_slot;
+	struct list_head	slot_list;
+
+	struct acpiphp_slot	*acpi_slot;
+};
+
+/*
+ * struct pci_resource - describes pci resource (mem, pfmem, io, bus)
+ */
+struct pci_resource {
+	struct pci_resource * next;
+	u64 base;
+	u32 length;
+};
+
+/**
+ * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters
+ * @cache_line_size in DWORD
+ * @latency_timer in PCI clock
+ * @enable_SERR 0 or 1
+ * @enable_PERR 0 or 1
+ */
+struct hpp_param {
+	u8 cache_line_size;
+	u8 latency_timer;
+	u8 enable_SERR;
+	u8 enable_PERR;
+};
+
+
+/**
+ * struct acpiphp_bridge - PCI bridge information
+ *
+ * for each bridge device in ACPI namespace
+ */
+struct acpiphp_bridge {
+	struct list_head list;
+	acpi_handle handle;
+	struct acpiphp_slot *slots;
+	int type;
+	int nr_slots;
+
+	u8 seg;
+	u8 bus;
+	u8 sub;
+
+	u32 flags;
+
+	/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
+	struct pci_bus *pci_bus;
+
+	/* PCI-to-PCI bridge device */
+	struct pci_dev *pci_dev;
+
+	/* ACPI 2.0 _HPP parameters */
+	struct hpp_param hpp;
+
+	spinlock_t res_lock;
+
+	/* available resources on this bus */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+};
+
+
+/**
+ * struct acpiphp_slot - PCI slot information
+ *
+ * PCI slot information for each *physical* PCI slot
+ */
+struct acpiphp_slot {
+	struct acpiphp_slot *next;
+	struct acpiphp_bridge *bridge;	/* parent */
+	struct list_head funcs;		/* one slot may have different
+					   objects (i.e. for each function) */
+	struct semaphore crit_sect;
+
+	u32		id;		/* slot id (serial #) for hotplug core */
+	u8		device;		/* pci device# */
+
+	u32		sun;		/* ACPI _SUN (slot unique number) */
+	u32		slotno;		/* slot number relative to bridge */
+	u32		flags;		/* see below */
+};
+
+
+/**
+ * struct acpiphp_func - PCI function information
+ *
+ * PCI function information for each object in ACPI namespace
+ * typically 8 objects per slot (i.e. for each PCI function)
+ */
+struct acpiphp_func {
+	struct acpiphp_slot *slot;	/* parent */
+
+	struct list_head sibling;
+	struct pci_dev *pci_dev;
+
+	acpi_handle	handle;
+
+	u8		function;	/* pci function# */
+	u32		flags;		/* see below */
+
+	/* resources used for this function */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+};
+
+/**
+ * struct acpiphp_attention_info - device specific attention registration
+ *
+ * ACPI has no generic method of setting/getting attention status
+ * this allows for device specific driver registration
+ */
+struct acpiphp_attention_info
+{
+	int (*set_attn)(struct hotplug_slot *slot, u8 status);
+	int (*get_attn)(struct hotplug_slot *slot, u8 *status);
+	struct module *owner;
+};
+
+/* PCI bus bridge HID */
+#define ACPI_PCI_HOST_HID		"PNP0A03"
+
+/* PCI BRIDGE type */
+#define BRIDGE_TYPE_HOST		0
+#define BRIDGE_TYPE_P2P			1
+
+/* ACPI _STA method value (ignore bit 4; battery present) */
+#define ACPI_STA_PRESENT		(0x00000001)
+#define ACPI_STA_ENABLED		(0x00000002)
+#define ACPI_STA_SHOW_IN_UI		(0x00000004)
+#define ACPI_STA_FUNCTIONING		(0x00000008)
+#define ACPI_STA_ALL			(0x0000000f)
+
+/* bridge flags */
+#define BRIDGE_HAS_STA		(0x00000001)
+#define BRIDGE_HAS_EJ0		(0x00000002)
+#define BRIDGE_HAS_HPP		(0x00000004)
+#define BRIDGE_HAS_PS0		(0x00000010)
+#define BRIDGE_HAS_PS1		(0x00000020)
+#define BRIDGE_HAS_PS2		(0x00000040)
+#define BRIDGE_HAS_PS3		(0x00000080)
+
+/* slot flags */
+
+#define SLOT_POWEREDON		(0x00000001)
+#define SLOT_ENABLED		(0x00000002)
+#define SLOT_MULTIFUNCTION	(0x00000004)
+
+/* function flags */
+
+#define FUNC_HAS_STA		(0x00000001)
+#define FUNC_HAS_EJ0		(0x00000002)
+#define FUNC_HAS_PS0		(0x00000010)
+#define FUNC_HAS_PS1		(0x00000020)
+#define FUNC_HAS_PS2		(0x00000040)
+#define FUNC_HAS_PS3		(0x00000080)
+
+/* function prototypes */
+
+/* acpiphp_core.c */
+extern int acpiphp_register_attention(struct acpiphp_attention_info*info);
+extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
+
+/* acpiphp_glue.c */
+extern int acpiphp_glue_init (void);
+extern void acpiphp_glue_exit (void);
+extern int acpiphp_get_num_slots (void);
+extern struct acpiphp_slot *get_slot_from_id (int id);
+typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
+
+extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
+extern int acpiphp_disable_slot (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
+extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
+extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
+
+/* acpiphp_pci.c */
+extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn);
+extern int acpiphp_configure_slot (struct acpiphp_slot *slot);
+extern int acpiphp_configure_function (struct acpiphp_func *func);
+extern void acpiphp_unconfigure_function (struct acpiphp_func *func);
+extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge);
+extern int acpiphp_init_func_resource (struct acpiphp_func *func);
+
+/* acpiphp_res.c */
+extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size);
+extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size);
+extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size);
+extern int acpiphp_resource_sort_and_combine (struct pci_resource **head);
+extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length);
+extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to);
+extern void acpiphp_free_resource (struct pci_resource **res);
+extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */
+extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */
+
+/* variables */
+extern int acpiphp_debug;
+
+#endif /* _ACPIPHP_H */
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
new file mode 100644
index 0000000..4539e61
--- /dev/null
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -0,0 +1,453 @@
+/*
+ * ACPI PCI Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002,2003 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>,
+ *		    <t-kochi@bq.jp.nec.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+static LIST_HEAD(slot_list);
+
+#define MY_NAME	"acpiphp"
+
+static int debug;
+int acpiphp_debug;
+
+/* local variables */
+static int num_slots;
+static struct acpiphp_attention_info *attention_info;
+
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>"
+#define DRIVER_DESC	"ACPI Hot Plug PCI Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+module_param(debug, bool, 0644);
+
+/* export the attention callback registration methods */
+EXPORT_SYMBOL_GPL(acpiphp_register_attention);
+EXPORT_SYMBOL_GPL(acpiphp_unregister_attention);
+
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status (struct hotplug_slot *slot, u8 *value);
+static int get_address		(struct hotplug_slot *slot, u32 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
+	.owner			= THIS_MODULE,
+	.enable_slot		= enable_slot,
+	.disable_slot		= disable_slot,
+	.set_attention_status	= set_attention_status,
+	.get_power_status	= get_power_status,
+	.get_attention_status	= get_attention_status,
+	.get_latch_status	= get_latch_status,
+	.get_adapter_status	= get_adapter_status,
+	.get_address		= get_address,
+};
+
+
+/**
+ * acpiphp_register_attention - set attention LED callback
+ * @info: must be completely filled with LED callbacks
+ *
+ * Description: this is used to register a hardware specific ACPI
+ * driver that manipulates the attention LED.  All the fields in
+ * info must be set.
+ **/
+int acpiphp_register_attention(struct acpiphp_attention_info *info)
+{
+	int retval = -EINVAL;
+
+	if (info && info->owner && info->set_attn &&
+			info->get_attn && !attention_info) {
+		retval = 0;
+		attention_info = info;
+	}
+	return retval;
+}
+
+
+/**
+ * acpiphp_unregister_attention - unset attention LED callback
+ * @info: must match the pointer used to register
+ *
+ * Description: this is used to un-register a hardware specific acpi
+ * driver that manipulates the attention LED.  The pointer to the 
+ * info struct must be the same as the one used to set it.
+ **/
+int acpiphp_unregister_attention(struct acpiphp_attention_info *info)
+{
+	int retval = -EINVAL;
+
+	if (info && attention_info == info) {
+		attention_info = NULL;
+		retval = 0;
+	}
+	return retval;
+}
+
+
+/**
+ * enable_slot - power on and enable a slot
+ * @hotplug_slot: slot to enable
+ *
+ * Actual tasks are done in acpiphp_enable_slot()
+ *
+ */
+static int enable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/* enable the specified slot */
+	return acpiphp_enable_slot(slot->acpi_slot);
+}
+
+
+/**
+ * disable_slot - disable and power off a slot
+ * @hotplug_slot: slot to disable
+ *
+ * Actual tasks are done in acpiphp_disable_slot()
+ *
+ */
+static int disable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/* disable the specified slot */
+	return acpiphp_disable_slot(slot->acpi_slot);
+}
+
+
+ /**
+  * set_attention_status - set attention LED
+ * @hotplug_slot: slot to set attention LED on
+ * @status: value to set attention LED to (0 or 1)
+ *
+ * attention status LED, so we use a callback that
+ * was registered with us.  This allows hardware specific
+ * ACPI implementations to blink the light for us.
+ **/
+ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
+ {
+	int retval = -ENODEV;
+
+ 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+ 
+	if (attention_info && try_module_get(attention_info->owner)) {
+		retval = attention_info->set_attn(hotplug_slot, status);
+		module_put(attention_info->owner);
+	} else
+		attention_info = NULL;
+	return retval;
+ }
+ 
+
+/**
+ * get_power_status - get power status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ * Some platforms may not implement _STA method properly.
+ * In that case, the value returned may not be reliable.
+ *
+ */
+static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_power_status(slot->acpi_slot);
+
+	return 0;
+}
+
+
+ /**
+ * get_attention_status - get attention LED status
+ * @hotplug_slot: slot to get status from
+ * @value: returns with value of attention LED
+ *
+ * ACPI doesn't have known method to determine the state
+ * of the attention status LED, so we use a callback that
+ * was registered with us.  This allows hardware specific
+ * ACPI implementations to determine its state
+ **/
+static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	int retval = -EINVAL;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	if (attention_info && try_module_get(attention_info->owner)) {
+		retval = attention_info->get_attn(hotplug_slot, value);
+		module_put(attention_info->owner);
+	} else
+		attention_info = NULL;
+	return retval;
+}
+
+
+/**
+ * get_latch_status - get latch status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ * ACPI doesn't provide any formal means to access latch status.
+ * Instead, we fake latch status from _STA
+ *
+ */
+static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_latch_status(slot->acpi_slot);
+
+	return 0;
+}
+
+
+/**
+ * get_adapter_status - get adapter status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ * ACPI doesn't provide any formal means to access adapter status.
+ * Instead, we fake adapter status from _STA
+ *
+ */
+static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_adapter_status(slot->acpi_slot);
+
+	return 0;
+}
+
+
+/**
+ * get_address - get pci address of a slot
+ * @hotplug_slot: slot to get status
+ * @busdev: pointer to struct pci_busdev (seg, bus, dev)
+ *
+ */
+static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_address(slot->acpi_slot);
+
+	return 0;
+}
+
+static int __init init_acpi(void)
+{
+	int retval;
+
+	/* initialize internal data structure etc. */
+	retval = acpiphp_glue_init();
+
+	/* read initial number of slots */
+	if (!retval) {
+		num_slots = acpiphp_get_num_slots();
+		if (num_slots == 0)
+			retval = -ENODEV;
+	}
+
+	return retval;
+}
+
+
+/**
+ * make_slot_name - make a slot name that appears in pcihpfs
+ * @slot: slot to name
+ *
+ */
+static void make_slot_name(struct slot *slot)
+{
+	snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%u",
+		 slot->acpi_slot->sun);
+}
+
+/**
+ * release_slot - free up the memory used by a slot
+ * @hotplug_slot: slot to free
+ */
+static void release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	kfree(slot);
+}
+
+/**
+ * init_slots - initialize 'struct slot' structures for each slot
+ *
+ */
+static int __init init_slots(void)
+{
+	struct slot *slot;
+	int retval = -ENOMEM;
+	int i;
+
+	for (i = 0; i < num_slots; ++i) {
+		slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
+		if (!slot)
+			goto error;
+		memset(slot, 0, sizeof(struct slot));
+
+		slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
+		if (!slot->hotplug_slot)
+			goto error_slot;
+		memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
+
+		slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+		if (!slot->hotplug_slot->info)
+			goto error_hpslot;
+		memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
+
+		slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!slot->hotplug_slot->name)
+			goto error_info;
+
+		slot->number = i;
+
+		slot->hotplug_slot->private = slot;
+		slot->hotplug_slot->release = &release_slot;
+		slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
+
+		slot->acpi_slot = get_slot_from_id(i);
+		slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
+		slot->hotplug_slot->info->attention_status = 0;
+		slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
+		slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
+		slot->hotplug_slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
+		slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
+
+		make_slot_name(slot);
+
+		retval = pci_hp_register(slot->hotplug_slot);
+		if (retval) {
+			err("pci_hp_register failed with error %d\n", retval);
+			goto error_name;
+		}
+
+		/* add slot to our internal list */
+		list_add(&slot->slot_list, &slot_list);
+		info("Slot [%s] registered\n", slot->hotplug_slot->name);
+	}
+
+	return 0;
+error_name:
+	kfree(slot->hotplug_slot->name);
+error_info:
+	kfree(slot->hotplug_slot->info);
+error_hpslot:
+	kfree(slot->hotplug_slot);
+error_slot:
+	kfree(slot);
+error:
+	return retval;
+}
+
+
+static void __exit cleanup_slots (void)
+{
+	struct list_head *tmp, *n;
+	struct slot *slot;
+
+	list_for_each_safe (tmp, n, &slot_list) {
+		/* memory will be freed in release_slot callback */
+		slot = list_entry(tmp, struct slot, slot_list);
+		list_del(&slot->slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
+	}
+}
+
+
+static int __init acpiphp_init(void)
+{
+	int retval;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	acpiphp_debug = debug;
+
+	/* read all the ACPI info from the system */
+	retval = init_acpi();
+	if (retval)
+		return retval;
+
+	return init_slots();
+}
+
+
+static void __exit acpiphp_exit(void)
+{
+	cleanup_slots();
+	/* deallocate internal data structures etc. */
+	acpiphp_glue_exit();
+}
+
+module_init(acpiphp_init);
+module_exit(acpiphp_exit);
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
new file mode 100644
index 0000000..e7f4129
--- /dev/null
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -0,0 +1,1344 @@
+/*
+ * ACPI PCI HotPlug glue functions to ACPI CA subsystem
+ *
+ * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002,2003 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <t-kochi@bq.jp.nec.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <asm/semaphore.h>
+
+#include "../pci.h"
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+static LIST_HEAD(bridge_list);
+
+#define MY_NAME "acpiphp_glue"
+
+static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
+static void handle_hotplug_event_func (acpi_handle, u32, void *);
+
+/*
+ * initialization & terminatation routines
+ */
+
+/**
+ * is_ejectable - determine if a slot is ejectable
+ * @handle: handle to acpi namespace
+ *
+ * Ejectable slot should satisfy at least these conditions:
+ *
+ *  1. has _ADR method
+ *  2. has _EJ0 method
+ *
+ * optionally
+ *
+ *  1. has _STA method
+ *  2. has _PS0 method
+ *  3. has _PS3 method
+ *  4. ..
+ *
+ */
+static int is_ejectable(acpi_handle handle)
+{
+	acpi_status status;
+	acpi_handle tmp;
+
+	status = acpi_get_handle(handle, "_ADR", &tmp);
+	if (ACPI_FAILURE(status)) {
+		return 0;
+	}
+
+	status = acpi_get_handle(handle, "_EJ0", &tmp);
+	if (ACPI_FAILURE(status)) {
+		return 0;
+	}
+
+	return 1;
+}
+
+
+/* callback routine to check the existence of ejectable slots */
+static acpi_status
+is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	int *count = (int *)context;
+
+	if (is_ejectable(handle)) {
+		(*count)++;
+		/* only one ejectable slot is enough */
+		return AE_CTRL_TERMINATE;
+	} else {
+		return AE_OK;
+	}
+}
+
+
+/* callback routine to register each ACPI PCI slot object */
+static acpi_status
+register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
+	struct acpiphp_slot *slot;
+	struct acpiphp_func *newfunc;
+	acpi_handle tmp;
+	acpi_status status = AE_OK;
+	unsigned long adr, sun;
+	int device, function;
+	static int num_slots = 0;	/* XXX if we support I/O node hotplug... */
+
+	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
+
+	if (ACPI_FAILURE(status))
+		return AE_OK;
+
+	status = acpi_get_handle(handle, "_EJ0", &tmp);
+
+	if (ACPI_FAILURE(status))
+		return AE_OK;
+
+	device = (adr >> 16) & 0xffff;
+	function = adr & 0xffff;
+
+	newfunc = kmalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
+	if (!newfunc)
+		return AE_NO_MEMORY;
+	memset(newfunc, 0, sizeof(struct acpiphp_func));
+
+	INIT_LIST_HEAD(&newfunc->sibling);
+	newfunc->handle = handle;
+	newfunc->function = function;
+	newfunc->flags = FUNC_HAS_EJ0;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
+		newfunc->flags |= FUNC_HAS_STA;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp)))
+		newfunc->flags |= FUNC_HAS_PS0;
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
+		newfunc->flags |= FUNC_HAS_PS3;
+
+	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
+	if (ACPI_FAILURE(status))
+		sun = -1;
+
+	/* search for objects that share the same slot */
+	for (slot = bridge->slots; slot; slot = slot->next)
+		if (slot->device == device) {
+			if (slot->sun != sun)
+				warn("sibling found, but _SUN doesn't match!\n");
+			break;
+		}
+
+	if (!slot) {
+		slot = kmalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
+		if (!slot) {
+			kfree(newfunc);
+			return AE_NO_MEMORY;
+		}
+
+		memset(slot, 0, sizeof(struct acpiphp_slot));
+		slot->bridge = bridge;
+		slot->id = num_slots++;
+		slot->device = device;
+		slot->sun = sun;
+		INIT_LIST_HEAD(&slot->funcs);
+		init_MUTEX(&slot->crit_sect);
+
+		slot->next = bridge->slots;
+		bridge->slots = slot;
+
+		bridge->nr_slots++;
+
+		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n",
+		    slot->bridge->bus, slot->device, slot->sun);
+	}
+
+	newfunc->slot = slot;
+	list_add_tail(&newfunc->sibling, &slot->funcs);
+
+	/* associate corresponding pci_dev */
+	newfunc->pci_dev = pci_find_slot(bridge->bus,
+					 PCI_DEVFN(device, function));
+	if (newfunc->pci_dev) {
+		if (acpiphp_init_func_resource(newfunc) < 0) {
+			kfree(newfunc);
+			return AE_ERROR;
+		}
+		slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+	}
+
+	/* install notify handler */
+	status = acpi_install_notify_handler(handle,
+					     ACPI_SYSTEM_NOTIFY,
+					     handle_hotplug_event_func,
+					     newfunc);
+
+	if (ACPI_FAILURE(status)) {
+		err("failed to register interrupt notify handler\n");
+		return status;
+	}
+
+	return AE_OK;
+}
+
+
+/* see if it's worth looking at this bridge */
+static int detect_ejectable_slots(acpi_handle *bridge_handle)
+{
+	acpi_status status;
+	int count;
+
+	count = 0;
+
+	/* only check slots defined directly below bridge object */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
+				     is_ejectable_slot, (void *)&count, NULL);
+
+	return count;
+}
+
+
+/* decode ACPI _CRS data and convert into our internal resource list
+ * TBD: _TRA, etc.
+ */
+static acpi_status
+decode_acpi_resource(struct acpi_resource *resource, void *context)
+{
+	struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context;
+	struct acpi_resource_address64 address;
+	struct pci_resource *res;
+
+	if (resource->id != ACPI_RSTYPE_ADDRESS16 &&
+	    resource->id != ACPI_RSTYPE_ADDRESS32 &&
+	    resource->id != ACPI_RSTYPE_ADDRESS64)
+		return AE_OK;
+
+	acpi_resource_to_address64(resource, &address);
+
+	if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) {
+		dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type,
+		    (unsigned long long)address.min_address_range,
+		    (unsigned long long)address.max_address_range);
+		res = acpiphp_make_resource(address.min_address_range,
+				    address.address_length);
+		if (!res) {
+			err("out of memory\n");
+			return AE_OK;
+		}
+
+		switch (address.resource_type) {
+		case ACPI_MEMORY_RANGE:
+			if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
+				res->next = bridge->p_mem_head;
+				bridge->p_mem_head = res;
+			} else {
+				res->next = bridge->mem_head;
+				bridge->mem_head = res;
+			}
+			break;
+		case ACPI_IO_RANGE:
+			res->next = bridge->io_head;
+			bridge->io_head = res;
+			break;
+		case ACPI_BUS_NUMBER_RANGE:
+			res->next = bridge->bus_head;
+			bridge->bus_head = res;
+			break;
+		default:
+			/* invalid type */
+			kfree(res);
+			break;
+		}
+	}
+
+	return AE_OK;
+}
+
+/* decode ACPI 2.0 _HPP hot plug parameters */
+static void decode_hpp(struct acpiphp_bridge *bridge)
+{
+	acpi_status status;
+	struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER,
+				      .pointer = NULL};
+	union acpi_object *package;
+	int i;
+
+	/* default numbers */
+	bridge->hpp.cache_line_size = 0x10;
+	bridge->hpp.latency_timer = 0x40;
+	bridge->hpp.enable_SERR = 0;
+	bridge->hpp.enable_PERR = 0;
+
+	status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
+
+	if (ACPI_FAILURE(status)) {
+		dbg("_HPP evaluation failed\n");
+		return;
+	}
+
+	package = (union acpi_object *) buffer.pointer;
+
+	if (!package || package->type != ACPI_TYPE_PACKAGE ||
+	    package->package.count != 4 || !package->package.elements) {
+		err("invalid _HPP object; ignoring\n");
+		goto err_exit;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (package->package.elements[i].type != ACPI_TYPE_INTEGER) {
+			err("invalid _HPP parameter type; ignoring\n");
+			goto err_exit;
+		}
+	}
+
+	bridge->hpp.cache_line_size = package->package.elements[0].integer.value;
+	bridge->hpp.latency_timer = package->package.elements[1].integer.value;
+	bridge->hpp.enable_SERR = package->package.elements[2].integer.value;
+	bridge->hpp.enable_PERR = package->package.elements[3].integer.value;
+
+	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n",
+		bridge->hpp.cache_line_size,
+		bridge->hpp.latency_timer,
+		bridge->hpp.enable_SERR,
+		bridge->hpp.enable_PERR);
+
+	bridge->flags |= BRIDGE_HAS_HPP;
+
+ err_exit:
+	kfree(buffer.pointer);
+}
+
+
+/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */
+static void init_bridge_misc(struct acpiphp_bridge *bridge)
+{
+	acpi_status status;
+
+	/* decode ACPI 2.0 _HPP (hot plug parameters) */
+	decode_hpp(bridge);
+
+	/* subtract all resources already allocated */
+	acpiphp_detect_pci_resource(bridge);
+
+	/* register all slot objects under this bridge */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
+				     register_slot, bridge, NULL);
+
+	/* install notify handler */
+	status = acpi_install_notify_handler(bridge->handle,
+					     ACPI_SYSTEM_NOTIFY,
+					     handle_hotplug_event_bridge,
+					     bridge);
+
+	if (ACPI_FAILURE(status)) {
+		err("failed to register interrupt notify handler\n");
+	}
+
+	list_add(&bridge->list, &bridge_list);
+
+	dbg("Bridge resource:\n");
+	acpiphp_dump_resource(bridge);
+}
+
+
+/* allocate and initialize host bridge data structure */
+static void add_host_bridge(acpi_handle *handle, int seg, int bus)
+{
+	acpi_status status;
+	struct acpiphp_bridge *bridge;
+
+	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
+	if (bridge == NULL)
+		return;
+
+	memset(bridge, 0, sizeof(struct acpiphp_bridge));
+
+	bridge->type = BRIDGE_TYPE_HOST;
+	bridge->handle = handle;
+	bridge->seg = seg;
+	bridge->bus = bus;
+
+	bridge->pci_bus = pci_find_bus(seg, bus);
+
+	spin_lock_init(&bridge->res_lock);
+
+	/* to be overridden when we decode _CRS	*/
+	bridge->sub = bridge->bus;
+
+	/* decode resources */
+
+	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+		decode_acpi_resource, bridge);
+
+	if (ACPI_FAILURE(status)) {
+		err("failed to decode bridge resources\n");
+		kfree(bridge);
+		return;
+	}
+
+	acpiphp_resource_sort_and_combine(&bridge->io_head);
+	acpiphp_resource_sort_and_combine(&bridge->mem_head);
+	acpiphp_resource_sort_and_combine(&bridge->p_mem_head);
+	acpiphp_resource_sort_and_combine(&bridge->bus_head);
+
+	dbg("ACPI _CRS resource:\n");
+	acpiphp_dump_resource(bridge);
+
+	if (bridge->bus_head) {
+		bridge->bus = bridge->bus_head->base;
+		bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1;
+	}
+
+	init_bridge_misc(bridge);
+}
+
+
+/* allocate and initialize PCI-to-PCI bridge data structure */
+static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int fn)
+{
+	struct acpiphp_bridge *bridge;
+	u8 tmp8;
+	u16 tmp16;
+	u64 base64, limit64;
+	u32 base, limit, base32u, limit32u;
+
+	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
+	if (bridge == NULL) {
+		err("out of memory\n");
+		return;
+	}
+
+	memset(bridge, 0, sizeof(struct acpiphp_bridge));
+
+	bridge->type = BRIDGE_TYPE_P2P;
+	bridge->handle = handle;
+	bridge->seg = seg;
+
+	bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
+	if (!bridge->pci_dev) {
+		err("Can't get pci_dev\n");
+		kfree(bridge);
+		return;
+	}
+
+	bridge->pci_bus = bridge->pci_dev->subordinate;
+	if (!bridge->pci_bus) {
+		err("This is not a PCI-to-PCI bridge!\n");
+		kfree(bridge);
+		return;
+	}
+
+	spin_lock_init(&bridge->res_lock);
+
+	bridge->bus = bridge->pci_bus->number;
+	bridge->sub = bridge->pci_bus->subordinate;
+
+	/*
+	 * decode resources under this P2P bridge
+	 */
+
+	/* I/O resources */
+	pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8);
+	base = tmp8;
+	pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8);
+	limit = tmp8;
+
+	switch (base & PCI_IO_RANGE_TYPE_MASK) {
+	case PCI_IO_RANGE_TYPE_16:
+		base = (base << 8) & 0xf000;
+		limit = ((limit << 8) & 0xf000) + 0xfff;
+		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
+		if (!bridge->io_head) {
+			err("out of memory\n");
+			kfree(bridge);
+			return;
+		}
+		dbg("16bit I/O range: %04x-%04x\n",
+		    (u32)bridge->io_head->base,
+		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
+		break;
+	case PCI_IO_RANGE_TYPE_32:
+		pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16);
+		base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000);
+		pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16);
+		limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;
+		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
+		if (!bridge->io_head) {
+			err("out of memory\n");
+			kfree(bridge);
+			return;
+		}
+		dbg("32bit I/O range: %08x-%08x\n",
+		    (u32)bridge->io_head->base,
+		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
+		break;
+	case 0x0f:
+		dbg("I/O space unsupported\n");
+		break;
+	default:
+		warn("Unknown I/O range type\n");
+	}
+
+	/* Memory resources (mandatory for P2P bridge) */
+	pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16);
+	base = (tmp16 & 0xfff0) << 16;
+	pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16);
+	limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
+	bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
+	if (!bridge->mem_head) {
+		err("out of memory\n");
+		kfree(bridge);
+		return;
+	}
+	dbg("32bit Memory range: %08x-%08x\n",
+	    (u32)bridge->mem_head->base,
+	    (u32)(bridge->mem_head->base + bridge->mem_head->length-1));
+
+	/* Prefetchable Memory resources (optional) */
+	pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16);
+	base = tmp16;
+	pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16);
+	limit = tmp16;
+
+	switch (base & PCI_MEMORY_RANGE_TYPE_MASK) {
+	case PCI_PREF_RANGE_TYPE_32:
+		base = (base & 0xfff0) << 16;
+		limit = ((limit & 0xfff0) << 16) | 0xfffff;
+		bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
+		if (!bridge->p_mem_head) {
+			err("out of memory\n");
+			kfree(bridge);
+			return;
+		}
+		dbg("32bit Prefetchable memory range: %08x-%08x\n",
+		    (u32)bridge->p_mem_head->base,
+		    (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
+		break;
+	case PCI_PREF_RANGE_TYPE_64:
+		pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u);
+		pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u);
+		base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16);
+		limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff;
+
+		bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
+		if (!bridge->p_mem_head) {
+			err("out of memory\n");
+			kfree(bridge);
+			return;
+		}
+		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",
+		    (u32)(bridge->p_mem_head->base >> 32),
+		    (u32)(bridge->p_mem_head->base & 0xffffffff),
+		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),
+		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff));
+		break;
+	case 0x0f:
+		break;
+	default:
+		warn("Unknown prefetchale memory type\n");
+	}
+
+	init_bridge_misc(bridge);
+}
+
+
+/* callback routine to find P2P bridges */
+static acpi_status
+find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+	acpi_status status;
+	acpi_handle dummy_handle;
+	unsigned long *segbus = context;
+	unsigned long tmp;
+	int seg, bus, device, function;
+	struct pci_dev *dev;
+
+	/* get PCI address */
+	seg = (*segbus >> 8) & 0xff;
+	bus = *segbus & 0xff;
+
+	status = acpi_get_handle(handle, "_ADR", &dummy_handle);
+	if (ACPI_FAILURE(status))
+		return AE_OK;		/* continue */
+
+	status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);
+	if (ACPI_FAILURE(status)) {
+		dbg("%s: _ADR evaluation failure\n", __FUNCTION__);
+		return AE_OK;
+	}
+
+	device = (tmp >> 16) & 0xffff;
+	function = tmp & 0xffff;
+
+	dev = pci_find_slot(bus, PCI_DEVFN(device, function));
+
+	if (!dev)
+		return AE_OK;
+
+	if (!dev->subordinate)
+		return AE_OK;
+
+	/* check if this bridge has ejectable slots */
+	if (detect_ejectable_slots(handle) > 0) {
+		dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
+		add_p2p_bridge(handle, seg, bus, device, function);
+	}
+
+	return AE_OK;
+}
+
+
+/* find hot-pluggable slots, and then find P2P bridge */
+static int add_bridge(acpi_handle handle)
+{
+	acpi_status status;
+	unsigned long tmp;
+	int seg, bus;
+	acpi_handle dummy_handle;
+
+	/* if the bridge doesn't have _STA, we assume it is always there */
+	status = acpi_get_handle(handle, "_STA", &dummy_handle);
+	if (ACPI_SUCCESS(status)) {
+		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
+		if (ACPI_FAILURE(status)) {
+			dbg("%s: _STA evaluation failure\n", __FUNCTION__);
+			return 0;
+		}
+		if ((tmp & ACPI_STA_FUNCTIONING) == 0)
+			/* don't register this object */
+			return 0;
+	}
+
+	/* get PCI segment number */
+	status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
+
+	seg = ACPI_SUCCESS(status) ? tmp : 0;
+
+	/* get PCI bus number */
+	status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
+
+	if (ACPI_SUCCESS(status)) {
+		bus = tmp;
+	} else {
+		warn("can't get bus number, assuming 0\n");
+		bus = 0;
+	}
+
+	/* check if this bridge has ejectable slots */
+	if (detect_ejectable_slots(handle) > 0) {
+		dbg("found PCI host-bus bridge with hot-pluggable slots\n");
+		add_host_bridge(handle, seg, bus);
+		return 0;
+	}
+
+	tmp = seg << 8 | bus;
+
+	/* search P2P bridges under this host bridge */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+				     find_p2p_bridge, &tmp, NULL);
+
+	if (ACPI_FAILURE(status))
+		warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
+
+	return 0;
+}
+
+
+static void remove_bridge(acpi_handle handle)
+{
+	/* No-op for now .. */
+}
+
+
+static int power_on_slot(struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	struct acpiphp_func *func;
+	struct list_head *l;
+	int retval = 0;
+
+	/* if already enabled, just skip */
+	if (slot->flags & SLOT_POWEREDON)
+		goto err_exit;
+
+	list_for_each (l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_PS0) {
+			dbg("%s: executing _PS0\n", __FUNCTION__);
+			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
+			if (ACPI_FAILURE(status)) {
+				warn("%s: _PS0 failed\n", __FUNCTION__);
+				retval = -1;
+				goto err_exit;
+			} else
+				break;
+		}
+	}
+
+	/* TBD: evaluate _STA to check if the slot is enabled */
+
+	slot->flags |= SLOT_POWEREDON;
+
+ err_exit:
+	return retval;
+}
+
+
+static int power_off_slot(struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	struct acpiphp_func *func;
+	struct list_head *l;
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+
+	int retval = 0;
+
+	/* if already disabled, just skip */
+	if ((slot->flags & SLOT_POWEREDON) == 0)
+		goto err_exit;
+
+	list_for_each (l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) {
+			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
+			if (ACPI_FAILURE(status)) {
+				warn("%s: _PS3 failed\n", __FUNCTION__);
+				retval = -1;
+				goto err_exit;
+			} else
+				break;
+		}
+	}
+
+	list_for_each (l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		/* We don't want to call _EJ0 on non-existing functions. */
+		if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) {
+			/* _EJ0 method take one argument */
+			arg_list.count = 1;
+			arg_list.pointer = &arg;
+			arg.type = ACPI_TYPE_INTEGER;
+			arg.integer.value = 1;
+
+			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
+			if (ACPI_FAILURE(status)) {
+				warn("%s: _EJ0 failed\n", __FUNCTION__);
+				retval = -1;
+				goto err_exit;
+			} else
+				break;
+		}
+	}
+
+	/* TBD: evaluate _STA to check if the slot is disabled */
+
+	slot->flags &= (~SLOT_POWEREDON);
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * enable_device - enable, configure a slot
+ * @slot: slot to be enabled
+ *
+ * This function should be called per *physical slot*,
+ * not per each slot object in ACPI namespace.
+ *
+ */
+static int enable_device(struct acpiphp_slot *slot)
+{
+	u8 bus;
+	struct pci_dev *dev;
+	struct pci_bus *child;
+	struct list_head *l;
+	struct acpiphp_func *func;
+	int retval = 0;
+	int num;
+
+	if (slot->flags & SLOT_ENABLED)
+		goto err_exit;
+
+	/* sanity check: dev should be NULL when hot-plugged in */
+	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
+	if (dev) {
+		/* This case shouldn't happen */
+		err("pci_dev structure already exists.\n");
+		retval = -1;
+		goto err_exit;
+	}
+
+	/* allocate resources to device */
+	retval = acpiphp_configure_slot(slot);
+	if (retval)
+		goto err_exit;
+
+	/* returned `dev' is the *first function* only! */
+	num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));
+	if (num)
+		pci_bus_add_devices(slot->bridge->pci_bus);
+	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
+
+	if (!dev) {
+		err("No new device found\n");
+		retval = -1;
+		goto err_exit;
+	}
+
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus);
+		child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus);
+		pci_do_scan_bus(child);
+	}
+
+	/* associate pci_dev to our representation */
+	list_for_each (l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		func->pci_dev = pci_find_slot(slot->bridge->bus,
+					      PCI_DEVFN(slot->device,
+							func->function));
+		if (!func->pci_dev)
+			continue;
+
+		/* configure device */
+		retval = acpiphp_configure_function(func);
+		if (retval)
+			goto err_exit;
+	}
+
+	slot->flags |= SLOT_ENABLED;
+
+	dbg("Available resources:\n");
+	acpiphp_dump_resource(slot->bridge);
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * disable_device - disable a slot
+ */
+static int disable_device(struct acpiphp_slot *slot)
+{
+	int retval = 0;
+	struct acpiphp_func *func;
+	struct list_head *l;
+
+	/* is this slot already disabled? */
+	if (!(slot->flags & SLOT_ENABLED))
+		goto err_exit;
+
+	list_for_each (l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->pci_dev)
+			acpiphp_unconfigure_function(func);
+	}
+
+	slot->flags &= (~SLOT_ENABLED);
+
+ err_exit:
+	return retval;
+}
+
+
+/**
+ * get_slot_status - get ACPI slot status
+ *
+ * if a slot has _STA for each function and if any one of them
+ * returned non-zero status, return it
+ *
+ * if a slot doesn't have _STA and if any one of its functions'
+ * configuration space is configured, return 0x0f as a _STA
+ *
+ * otherwise return 0
+ */
+static unsigned int get_slot_status(struct acpiphp_slot *slot)
+{
+	acpi_status status;
+	unsigned long sta = 0;
+	u32 dvid;
+	struct list_head *l;
+	struct acpiphp_func *func;
+
+	list_for_each (l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+
+		if (func->flags & FUNC_HAS_STA) {
+			status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
+			if (ACPI_SUCCESS(status) && sta)
+				break;
+		} else {
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+						  PCI_DEVFN(slot->device,
+							    func->function),
+						  PCI_VENDOR_ID, &dvid);
+			if (dvid != 0xffffffff) {
+				sta = ACPI_STA_ALL;
+				break;
+			}
+		}
+	}
+
+	return (unsigned int)sta;
+}
+
+/**
+ * acpiphp_check_bridge - re-enumerate devices
+ *
+ * Iterate over all slots under this bridge and make sure that if a
+ * card is present they are enabled, and if not they are disabled.
+ */
+static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
+{
+	struct acpiphp_slot *slot;
+	int retval = 0;
+	int enabled, disabled;
+
+	enabled = disabled = 0;
+
+	for (slot = bridge->slots; slot; slot = slot->next) {
+		unsigned int status = get_slot_status(slot);
+		if (slot->flags & SLOT_ENABLED) {
+			if (status == ACPI_STA_ALL)
+				continue;
+			retval = acpiphp_disable_slot(slot);
+			if (retval) {
+				err("Error occurred in disabling\n");
+				goto err_exit;
+			}
+			disabled++;
+		} else {
+			if (status != ACPI_STA_ALL)
+				continue;
+			retval = acpiphp_enable_slot(slot);
+			if (retval) {
+				err("Error occurred in enabling\n");
+				goto err_exit;
+			}
+			enabled++;
+		}
+	}
+
+	dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled);
+
+ err_exit:
+	return retval;
+}
+
+/*
+ * ACPI event handlers
+ */
+
+/**
+ * handle_hotplug_event_bridge - handle ACPI event on bridges
+ *
+ * @handle: Notify()'ed acpi_handle
+ * @type: Notify code
+ * @context: pointer to acpiphp_bridge structure
+ *
+ * handles ACPI event notification on {host,p2p} bridges
+ *
+ */
+static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context)
+{
+	struct acpiphp_bridge *bridge;
+	char objname[64];
+	struct acpi_buffer buffer = { .length = sizeof(objname),
+				      .pointer = objname };
+
+	bridge = (struct acpiphp_bridge *)context;
+
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		/* bus re-enumerate */
+		dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
+		acpiphp_check_bridge(bridge);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		/* device check */
+		dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
+		acpiphp_check_bridge(bridge);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_WAKE:
+		/* wake event */
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
+		break;
+
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		/* request device eject */
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
+		break;
+
+	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
+		printk(KERN_ERR "Device %s cannot be configured due"
+				" to a frequency mismatch\n", objname);
+		break;
+
+	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+		printk(KERN_ERR "Device %s cannot be configured due"
+				" to a bus mode mismatch\n", objname);
+		break;
+
+	case ACPI_NOTIFY_POWER_FAULT:
+		printk(KERN_ERR "Device %s has suffered a power fault\n",
+				objname);
+		break;
+
+	default:
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
+		break;
+	}
+}
+
+
+/**
+ * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
+ *
+ * @handle: Notify()'ed acpi_handle
+ * @type: Notify code
+ * @context: pointer to acpiphp_func structure
+ *
+ * handles ACPI event notification on slots
+ *
+ */
+static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
+{
+	struct acpiphp_func *func;
+	char objname[64];
+	struct acpi_buffer buffer = { .length = sizeof(objname),
+				      .pointer = objname };
+
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+	func = (struct acpiphp_func *)context;
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		/* bus re-enumerate */
+		dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
+		acpiphp_enable_slot(func->slot);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		/* device check : re-enumerate from parent bus */
+		dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
+		acpiphp_check_bridge(func->slot->bridge);
+		break;
+
+	case ACPI_NOTIFY_DEVICE_WAKE:
+		/* wake event */
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
+		break;
+
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		/* request device eject */
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
+		acpiphp_disable_slot(func->slot);
+		break;
+
+	default:
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
+		break;
+	}
+}
+
+
+static struct acpi_pci_driver acpi_pci_hp_driver = {
+	.add =		add_bridge,
+	.remove =	remove_bridge,
+};
+
+/**
+ * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures
+ *
+ */
+int __init acpiphp_glue_init(void)
+{
+	int num;
+
+	if (list_empty(&pci_root_buses))
+		return -1;
+
+	num = acpi_pci_register_driver(&acpi_pci_hp_driver);
+
+	if (num <= 0)
+		return -1;
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures
+ *
+ * This function frees all data allocated in acpiphp_glue_init()
+ */
+void __exit acpiphp_glue_exit(void)
+{
+	struct list_head *l1, *l2, *n1, *n2;
+	struct acpiphp_bridge *bridge;
+	struct acpiphp_slot *slot, *next;
+	struct acpiphp_func *func;
+	acpi_status status;
+
+	list_for_each_safe (l1, n1, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)l1;
+		slot = bridge->slots;
+		while (slot) {
+			next = slot->next;
+			list_for_each_safe (l2, n2, &slot->funcs) {
+				func = list_entry(l2, struct acpiphp_func, sibling);
+				acpiphp_free_resource(&func->io_head);
+				acpiphp_free_resource(&func->mem_head);
+				acpiphp_free_resource(&func->p_mem_head);
+				acpiphp_free_resource(&func->bus_head);
+				status = acpi_remove_notify_handler(func->handle,
+								    ACPI_SYSTEM_NOTIFY,
+								    handle_hotplug_event_func);
+				if (ACPI_FAILURE(status))
+					err("failed to remove notify handler\n");
+				kfree(func);
+			}
+			kfree(slot);
+			slot = next;
+		}
+		status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
+						    handle_hotplug_event_bridge);
+		if (ACPI_FAILURE(status))
+			err("failed to remove notify handler\n");
+
+		acpiphp_free_resource(&bridge->io_head);
+		acpiphp_free_resource(&bridge->mem_head);
+		acpiphp_free_resource(&bridge->p_mem_head);
+		acpiphp_free_resource(&bridge->bus_head);
+
+		kfree(bridge);
+	}
+
+	acpi_pci_unregister_driver(&acpi_pci_hp_driver);
+}
+
+
+/**
+ * acpiphp_get_num_slots - count number of slots in a system
+ */
+int __init acpiphp_get_num_slots(void)
+{
+	struct list_head *node;
+	struct acpiphp_bridge *bridge;
+	int num_slots;
+
+	num_slots = 0;
+
+	list_for_each (node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots);
+		num_slots += bridge->nr_slots;
+	}
+
+	dbg("Total %dslots\n", num_slots);
+	return num_slots;
+}
+
+
+#if 0
+/**
+ * acpiphp_for_each_slot - call function for each slot
+ * @fn: callback function
+ * @data: context to be passed to callback function
+ *
+ */
+static int acpiphp_for_each_slot(acpiphp_callback fn, void *data)
+{
+	struct list_head *node;
+	struct acpiphp_bridge *bridge;
+	struct acpiphp_slot *slot;
+	int retval = 0;
+
+	list_for_each (node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		for (slot = bridge->slots; slot; slot = slot->next) {
+			retval = fn(slot, data);
+			if (!retval)
+				goto err_exit;
+		}
+	}
+
+ err_exit:
+	return retval;
+}
+#endif
+
+/* search matching slot from id  */
+struct acpiphp_slot *get_slot_from_id(int id)
+{
+	struct list_head *node;
+	struct acpiphp_bridge *bridge;
+	struct acpiphp_slot *slot;
+
+	list_for_each (node, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)node;
+		for (slot = bridge->slots; slot; slot = slot->next)
+			if (slot->id == id)
+				return slot;
+	}
+
+	/* should never happen! */
+	err("%s: no object for id %d\n", __FUNCTION__, id);
+	WARN_ON(1);
+	return NULL;
+}
+
+
+/**
+ * acpiphp_enable_slot - power on slot
+ */
+int acpiphp_enable_slot(struct acpiphp_slot *slot)
+{
+	int retval;
+
+	down(&slot->crit_sect);
+
+	/* wake up all functions */
+	retval = power_on_slot(slot);
+	if (retval)
+		goto err_exit;
+
+	if (get_slot_status(slot) == ACPI_STA_ALL)
+		/* configure all functions */
+		retval = enable_device(slot);
+
+ err_exit:
+	up(&slot->crit_sect);
+	return retval;
+}
+
+
+/**
+ * acpiphp_disable_slot - power off slot
+ */
+int acpiphp_disable_slot(struct acpiphp_slot *slot)
+{
+	int retval = 0;
+
+	down(&slot->crit_sect);
+
+	/* unconfigure all functions */
+	retval = disable_device(slot);
+	if (retval)
+		goto err_exit;
+
+	/* power off all functions */
+	retval = power_off_slot(slot);
+	if (retval)
+		goto err_exit;
+
+	acpiphp_resource_sort_and_combine(&slot->bridge->io_head);
+	acpiphp_resource_sort_and_combine(&slot->bridge->mem_head);
+	acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head);
+	acpiphp_resource_sort_and_combine(&slot->bridge->bus_head);
+	dbg("Available resources:\n");
+	acpiphp_dump_resource(slot->bridge);
+
+ err_exit:
+	up(&slot->crit_sect);
+	return retval;
+}
+
+
+/*
+ * slot enabled:  1
+ * slot disabled: 0
+ */
+u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
+{
+	unsigned int sta;
+
+	sta = get_slot_status(slot);
+
+	return (sta & ACPI_STA_ENABLED) ? 1 : 0;
+}
+
+
+/*
+ * latch closed:  1
+ * latch   open:  0
+ */
+u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
+{
+	unsigned int sta;
+
+	sta = get_slot_status(slot);
+
+	return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0;
+}
+
+
+/*
+ * adapter presence : 1
+ *          absence : 0
+ */
+u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
+{
+	unsigned int sta;
+
+	sta = get_slot_status(slot);
+
+	return (sta == 0) ? 0 : 1;
+}
+
+
+/*
+ * pci address (seg/bus/dev)
+ */
+u32 acpiphp_get_address(struct acpiphp_slot *slot)
+{
+	u32 address;
+
+	address = ((slot->bridge->seg) << 16) |
+		  ((slot->bridge->bus) << 8) |
+		  slot->device;
+
+	return address;
+}
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
new file mode 100644
index 0000000..7e7f913
--- /dev/null
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -0,0 +1,499 @@
+/*
+ * ACPI PCI Hot Plug IBM Extension
+ *
+ * Copyright (C) 2004 Vernon Mauery <vernux@us.ibm.com>
+ * Copyright (C) 2004 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <vernux@us.ibm.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <acpi/acpi_bus.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <asm/uaccess.h>
+#include <linux/moduleparam.h>
+
+#include "acpiphp.h"
+#include "pci_hotplug.h"
+
+#define DRIVER_VERSION	"1.0.1"
+#define DRIVER_AUTHOR	"Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
+#define DRIVER_DESC	"ACPI Hot Plug PCI Controller Driver IBM extension"
+
+static int debug;
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, " Debugging mode enabled or not");
+#define MY_NAME "acpiphp_ibm"
+
+#undef dbg
+#define dbg(format, arg...)				\
+do {							\
+	if (debug)					\
+		printk(KERN_DEBUG "%s: " format,	\
+				MY_NAME , ## arg);	\
+} while (0)
+
+#define FOUND_APCI 0x61504349
+/* these are the names for the IBM ACPI pseudo-device */
+#define IBM_HARDWARE_ID1 "IBM37D0"
+#define IBM_HARDWARE_ID2 "IBM37D4"
+
+#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun)
+
+/* union apci_descriptor - allows access to the
+ * various device descriptors that are embedded in the
+ * aPCI table
+ */
+union apci_descriptor {
+	struct {
+		char sig[4];
+		u8   len;
+	} header;
+	struct {
+		u8  type;
+		u8  len;
+		u16 slot_id;
+		u8  bus_id;
+		u8  dev_num;
+		u8  slot_num;
+		u8  slot_attr[2];
+		u8  attn;
+		u8  status[2];
+		u8  sun;
+		u8  res[3];
+	} slot;
+	struct {
+		u8 type;
+		u8 len;
+	} generic;
+};
+
+/* struct notification - keeps info about the device
+ * that cause the ACPI notification event
+ */
+struct notification {
+	struct acpi_device *device;
+	u8                  event;
+};
+
+static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status);
+static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status);
+static void ibm_handle_events(acpi_handle handle, u32 event, void *context);
+static int ibm_get_table_from_acpi(char **bufp);
+static ssize_t ibm_read_apci_table(struct kobject *kobj,
+		char *buffer, loff_t pos, size_t size);
+static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
+		u32 lvl, void *context, void **rv);
+static int __init ibm_acpiphp_init(void);
+static void __exit ibm_acpiphp_exit(void);
+
+static acpi_handle ibm_acpi_handle;
+static struct notification ibm_note;
+static struct bin_attribute ibm_apci_table_attr = {
+	    .attr = {
+		    .name = "apci_table",
+		    .owner = THIS_MODULE,
+		    .mode = S_IRUGO,
+	    },
+	    .read = ibm_read_apci_table,
+	    .write = NULL,
+};
+static struct acpiphp_attention_info ibm_attention_info = 
+{
+	.set_attn = ibm_set_attention_status,
+	.get_attn = ibm_get_attention_status,
+	.owner = THIS_MODULE,
+};
+
+/**
+ * ibm_slot_from_id - workaround for bad ibm hardware
+ * @id: the slot number that linux refers to the slot by
+ *
+ * Description: this method returns the aCPI slot descriptor
+ * corresponding to the Linux slot number.  This descriptor
+ * has info about the aPCI slot id and attention status.
+ * This descriptor must be freed using kfree when done.
+ **/
+static union apci_descriptor *ibm_slot_from_id(int id)
+{
+	int ind = 0, size;
+	union apci_descriptor *ret = NULL, *des;
+	char *table;
+
+	size = ibm_get_table_from_acpi(&table);
+	des = (union apci_descriptor *)table;
+	if (memcmp(des->header.sig, "aPCI", 4) != 0)
+		goto ibm_slot_done;
+
+	des = (union apci_descriptor *)&table[ind += des->header.len];
+	while (ind < size && (des->generic.type != 0x82 ||
+			des->slot.slot_num != id)) {
+		des = (union apci_descriptor *)&table[ind += des->generic.len];
+	}
+
+	if (ind < size && des->slot.slot_num == id)
+		ret = des;
+
+ibm_slot_done:
+	if (ret) {
+		ret = kmalloc(sizeof(union apci_descriptor), GFP_KERNEL);
+		memcpy(ret, des, sizeof(union apci_descriptor));
+	}
+	kfree(table);
+	return ret;
+}
+
+/**
+ * ibm_set_attention_status - callback method to set the attention LED
+ * @slot: the hotplug_slot to work with
+ * @status: what to set the LED to (0 or 1)
+ *
+ * Description: this method is registered with the acpiphp module as a
+ * callback to do the device specific task of setting the LED status
+ **/
+static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status)
+{
+	union acpi_object args[2]; 
+	struct acpi_object_list params = { .pointer = args, .count = 2 };
+	acpi_status stat; 
+	unsigned long rc;
+	union apci_descriptor *ibm_slot;
+
+	ibm_slot = ibm_slot_from_id(hpslot_to_sun(slot));
+
+	dbg("%s: set slot %d (%d) attention status to %d\n", __FUNCTION__,
+			ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
+			(status ? 1 : 0));
+
+	args[0].type = ACPI_TYPE_INTEGER;
+	args[0].integer.value = ibm_slot->slot.slot_id;
+	args[1].type = ACPI_TYPE_INTEGER;
+	args[1].integer.value = (status) ? 1 : 0;
+
+	kfree(ibm_slot);
+
+	stat = acpi_evaluate_integer(ibm_acpi_handle, "APLS", &params, &rc);
+	if (ACPI_FAILURE(stat)) {
+		err("APLS evaluation failed:  0x%08x\n", stat);
+		return -ENODEV;
+	} else if (!rc) {
+		err("APLS method failed:  0x%08lx\n", rc);
+		return -ERANGE;
+	}
+	return 0;
+}
+
+/**
+ * ibm_get_attention_status - callback method to get attention LED status
+ * @slot: the hotplug_slot to work with
+ * @status: returns what the LED is set to (0 or 1)
+ *
+ * Description: this method is registered with the acpiphp module as a
+ * callback to do the device specific task of getting the LED status
+ * 
+ * Because there is no direct method of getting the LED status directly
+ * from an ACPI call, we read the aPCI table and parse out our
+ * slot descriptor to read the status from that.
+ **/
+static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status)
+{
+	union apci_descriptor *ibm_slot;
+
+	ibm_slot = ibm_slot_from_id(hpslot_to_sun(slot));
+
+	if (ibm_slot->slot.attn & 0xa0 || ibm_slot->slot.status[1] & 0x08)
+		*status = 1;
+	else
+		*status = 0;
+
+	dbg("%s: get slot %d (%d) attention status is %d\n", __FUNCTION__,
+			ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
+			*status);
+
+	kfree(ibm_slot);
+	return 0;
+}
+
+/**
+ * ibm_handle_events - listens for ACPI events for the IBM37D0 device
+ * @handle: an ACPI handle to the device that caused the event
+ * @event: the event info (device specific)
+ * @context: passed context (our notification struct)
+ *
+ * Description: this method is registered as a callback with the ACPI
+ * subsystem it is called when this device has an event to notify the OS of
+ *
+ * The events actually come from the device as two events that get
+ * synthesized into one event with data by this function.  The event
+ * ID comes first and then the slot number that caused it.  We report
+ * this as one event to the OS.
+ *
+ * From section 5.6.2.2 of the ACPI 2.0 spec, I understand that the OSPM will
+ * only re-enable the interrupt that causes this event AFTER this method
+ * has returned, thereby enforcing serial access for the notification struct.
+ **/
+static void ibm_handle_events(acpi_handle handle, u32 event, void *context)
+{
+	u8 detail = event & 0x0f;
+	u8 subevent = event & 0xf0;
+	struct notification *note = context;
+
+	dbg("%s: Received notification %02x\n", __FUNCTION__, event);
+
+	if (subevent == 0x80) {
+		dbg("%s: generationg bus event\n", __FUNCTION__);
+		acpi_bus_generate_event(note->device, note->event, detail);
+	} else
+		note->event = event;
+}
+
+/**
+ * ibm_get_table_from_acpi - reads the APLS buffer from ACPI
+ * @bufp: address to pointer to allocate for the table
+ *
+ * Description: this method reads the APLS buffer in from ACPI and
+ * stores the "stripped" table into a single buffer
+ * it allocates and passes the address back in bufp
+ *
+ * If NULL is passed in as buffer, this method only calculates
+ * the size of the table and returns that without filling
+ * in the buffer
+ *
+ * returns < 0 on error or the size of the table on success
+ **/
+static int ibm_get_table_from_acpi(char **bufp)
+{
+	union acpi_object *package;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	acpi_status status;
+	char *lbuf = NULL;
+	int i, size = -EIO;
+
+	status = acpi_evaluate_object(ibm_acpi_handle, "APCI", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		err("%s:  APCI evaluation failed\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	package = (union acpi_object *) buffer.pointer;
+	if(!(package) ||
+			(package->type != ACPI_TYPE_PACKAGE) ||
+			!(package->package.elements)) {
+		err("%s:  Invalid APCI object\n", __FUNCTION__);
+		goto read_table_done;
+	}
+
+	for(size = 0, i = 0; i < package->package.count; i++) {
+		if (package->package.elements[i].type != ACPI_TYPE_BUFFER) {
+			err("%s:  Invalid APCI element %d\n", __FUNCTION__, i);
+			goto read_table_done;
+		}
+		size += package->package.elements[i].buffer.length;
+	}
+
+	if (bufp == NULL)
+		goto read_table_done;
+
+	lbuf = kmalloc(size, GFP_KERNEL);
+	dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n",
+			__FUNCTION__, package->package.count, size, lbuf);
+
+	if (lbuf) {
+		*bufp = lbuf;
+		memset(lbuf, 0, size);
+	} else {
+		size = -ENOMEM;
+		goto read_table_done;
+	}
+
+	size = 0;
+	for (i=0; i<package->package.count; i++) {
+		memcpy(&lbuf[size],
+				package->package.elements[i].buffer.pointer,
+				package->package.elements[i].buffer.length);
+		size += package->package.elements[i].buffer.length;
+	}
+
+read_table_done:
+	kfree(buffer.pointer);
+	return size;
+}
+
+/**
+ * ibm_read_apci_table - callback for the sysfs apci_table file
+ * @kobj: the kobject this binary attribute is a part of
+ * @buffer: the kernel space buffer to fill
+ * @pos: the offset into the file
+ * @size: the number of bytes requested
+ *
+ * Description: gets registered with sysfs as the reader callback
+ * to be executed when /sys/bus/pci/slots/apci_table gets read
+ *
+ * Since we don't get notified on open and close for this file,
+ * things get really tricky here...
+ * our solution is to only allow reading the table in all at once
+ **/
+static ssize_t ibm_read_apci_table(struct kobject *kobj,
+		char *buffer, loff_t pos, size_t size)
+{
+	int bytes_read = -EINVAL;
+	char *table = NULL;
+	
+	dbg("%s: pos = %d, size = %zd\n", __FUNCTION__, (int)pos, size);
+
+	if (pos == 0) {
+		bytes_read = ibm_get_table_from_acpi(&table);
+		if (bytes_read > 0 && bytes_read <= size)
+			memcpy(buffer, table, bytes_read);
+		kfree(table);
+	}
+	return bytes_read;
+}
+
+/**
+ * ibm_find_acpi_device - callback to find our ACPI device
+ * @handle: the ACPI handle of the device we are inspecting
+ * @lvl: depth into the namespace tree
+ * @context: a pointer to our handle to fill when we find the device
+ * @rv: a return value to fill if desired
+ *
+ * Description: used as a callback when calling acpi_walk_namespace
+ * to find our device.  When this method returns non-zero
+ * acpi_walk_namespace quits its search and returns our value
+ **/
+static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
+		u32 lvl, void *context, void **rv)
+{
+	acpi_handle *phandle = (acpi_handle *)context;
+	acpi_status status; 
+	struct acpi_device_info info; 
+	struct acpi_buffer info_buffer = {
+		.length = sizeof(struct acpi_device_info),
+		.pointer = &info,
+	};
+
+	status = acpi_get_object_info(handle, &info_buffer);
+	if (ACPI_FAILURE(status)) {
+		err("%s:  Failed to get device information", __FUNCTION__);
+		return 0;
+	}
+	info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0';
+
+	if(info.current_status && (info.valid & ACPI_VALID_HID) &&
+			(!strcmp(info.hardware_id.value, IBM_HARDWARE_ID1) ||
+			!strcmp(info.hardware_id.value, IBM_HARDWARE_ID2))) {
+		dbg("found hardware: %s, handle: %p\n", info.hardware_id.value,
+				handle);
+		*phandle = handle;
+		/* returning non-zero causes the search to stop
+		 * and returns this value to the caller of 
+		 * acpi_walk_namespace, but it also causes some warnings
+		 * in the acpi debug code to print...
+		 */
+		return FOUND_APCI;
+	}
+	return 0;
+}
+
+static int __init ibm_acpiphp_init(void)
+{
+	int retval = 0;
+	acpi_status status;
+	struct acpi_device *device;
+	struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj;
+
+	dbg("%s\n", __FUNCTION__);
+
+	if (acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+			ACPI_UINT32_MAX, ibm_find_acpi_device,
+			&ibm_acpi_handle, NULL) != FOUND_APCI) {
+		err("%s: acpi_walk_namespace failed\n", __FUNCTION__);
+		retval = -ENODEV;
+		goto init_return;
+	}
+	dbg("%s: found IBM aPCI device\n", __FUNCTION__);
+	if (acpi_bus_get_device(ibm_acpi_handle, &device)) {
+		err("%s: acpi_bus_get_device failed\n", __FUNCTION__);
+		retval = -ENODEV;
+		goto init_return;
+	}
+	if (acpiphp_register_attention(&ibm_attention_info)) {
+		retval = -ENODEV;
+		goto init_return;
+	}
+
+	ibm_note.device = device;
+	status = acpi_install_notify_handler(
+			ibm_acpi_handle,
+			ACPI_DEVICE_NOTIFY,
+			ibm_handle_events,
+			&ibm_note);
+	if (ACPI_FAILURE(status)) {
+		err("%s:  Failed to register notification handler\n",
+				__FUNCTION__);
+		retval = -EBUSY;
+		goto init_cleanup;
+	}
+
+	ibm_apci_table_attr.size = ibm_get_table_from_acpi(NULL);
+	retval = sysfs_create_bin_file(sysdir, &ibm_apci_table_attr);
+
+	return retval;
+
+init_cleanup:
+	acpiphp_unregister_attention(&ibm_attention_info);
+init_return:
+	return retval;
+}
+
+static void __exit ibm_acpiphp_exit(void)
+{
+	acpi_status status;
+	struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj;
+
+	dbg("%s\n", __FUNCTION__);
+
+	if (acpiphp_unregister_attention(&ibm_attention_info))
+		err("%s: attention info deregistration failed", __FUNCTION__);
+
+	   status = acpi_remove_notify_handler(
+			   ibm_acpi_handle,
+			   ACPI_DEVICE_NOTIFY,
+			   ibm_handle_events);
+	   if (ACPI_FAILURE(status))
+		   err("%s:  Notification handler removal failed\n",
+				   __FUNCTION__);
+	// remove the /sys entries
+	if (sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr))
+		err("%s: removal of sysfs file apci_table failed\n",
+				__FUNCTION__);
+}
+
+module_init(ibm_acpiphp_init);
+module_exit(ibm_acpiphp_exit);
diff --git a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c
new file mode 100644
index 0000000..54d97c9
--- /dev/null
+++ b/drivers/pci/hotplug/acpiphp_pci.c
@@ -0,0 +1,449 @@
+/*
+ * ACPI PCI HotPlug PCI configuration space management
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 IBM Corp.
+ * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <t-kochi@bq.jp.nec.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include "../pci.h"
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+#define MY_NAME "acpiphp_pci"
+
+
+/* allocate mem/pmem/io resource to a new function */
+static int init_config_space (struct acpiphp_func *func)
+{
+	u32 bar, len;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct acpiphp_bridge *bridge;
+	struct pci_resource *res;
+	struct pci_bus *pbus;
+	int bus, device, function;
+	unsigned int devfn;
+	u16 tmp;
+
+	bridge = func->slot->bridge;
+	pbus = bridge->pci_bus;
+	bus = bridge->bus;
+	device = func->slot->device;
+	function = func->function;
+	devfn = PCI_DEVFN(device, function);
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_bus_write_config_dword(pbus, devfn,
+					   address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword(pbus, devfn, address[count], &bar);
+
+		if (!bar)	/* This BAR is not implemented */
+			continue;
+
+		dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar);
+
+		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+
+			len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
+
+			dbg("len in IO %x, BAR %d\n", len, count);
+
+			spin_lock(&bridge->res_lock);
+			res = acpiphp_get_io_resource(&bridge->io_head, len);
+			spin_unlock(&bridge->res_lock);
+
+			if (!res) {
+				err("cannot allocate requested io for %02x:%02x.%d len %x\n",
+				    bus, device, function, len);
+				return -1;
+			}
+			pci_bus_write_config_dword(pbus, devfn,
+						   address[count],
+						   (u32)res->base);
+			res->next = func->io_head;
+			func->io_head = res;
+
+		} else {
+			/* This is Memory */
+			if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+
+				len = bar & 0xFFFFFFF0;
+				len = ~len + 1;
+
+				dbg("len in PFMEM %x, BAR %d\n", len, count);
+
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource(&bridge->p_mem_head, len);
+				spin_unlock(&bridge->res_lock);
+
+				if (!res) {
+					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
+					    bus, device, function, len);
+					return -1;
+				}
+
+				pci_bus_write_config_dword(pbus, devfn,
+							   address[count],
+							   (u32)res->base);
+
+				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					dbg("inside the pfmem 64 case, count %d\n", count);
+					count += 1;
+					pci_bus_write_config_dword(pbus, devfn,
+								   address[count],
+								   (u32)(res->base >> 32));
+				}
+
+				res->next = func->p_mem_head;
+				func->p_mem_head = res;
+
+			} else {
+				/* regular memory */
+
+				len = bar & 0xFFFFFFF0;
+				len = ~len + 1;
+
+				dbg("len in MEM %x, BAR %d\n", len, count);
+
+				spin_lock(&bridge->res_lock);
+				res = acpiphp_get_resource(&bridge->mem_head, len);
+				spin_unlock(&bridge->res_lock);
+
+				if (!res) {
+					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
+					    bus, device, function, len);
+					return -1;
+				}
+
+				pci_bus_write_config_dword(pbus, devfn,
+							   address[count],
+							   (u32)res->base);
+
+				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					dbg("inside mem 64 case, reg. mem, count %d\n", count);
+					count += 1;
+					pci_bus_write_config_dword(pbus, devfn,
+								   address[count],
+								   (u32)(res->base >> 32));
+				}
+
+				res->next = func->mem_head;
+				func->mem_head = res;
+
+			}
+		}
+	}
+
+	/* disable expansion rom */
+	pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000);
+
+	/* set PCI parameters from _HPP */
+	pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE,
+				  bridge->hpp.cache_line_size);
+	pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER,
+				  bridge->hpp.latency_timer);
+
+	pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp);
+	if (bridge->hpp.enable_SERR)
+		tmp |= PCI_COMMAND_SERR;
+	if (bridge->hpp.enable_PERR)
+		tmp |= PCI_COMMAND_PARITY;
+	pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp);
+
+	return 0;
+}
+
+/* detect_used_resource - subtract resource under dev from bridge */
+static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
+{
+	int count;
+
+	dbg("Device %s\n", pci_name(dev));
+
+	for (count = 0; count < DEVICE_COUNT_RESOURCE; count++) {
+		struct pci_resource *res;
+		struct pci_resource **head;
+		unsigned long base = dev->resource[count].start;
+		unsigned long len = dev->resource[count].end - base + 1;
+		unsigned long flags = dev->resource[count].flags;
+
+		if (!flags)
+			continue;
+
+		dbg("BAR[%d] 0x%lx - 0x%lx (0x%lx)\n", count, base,
+				base + len - 1, flags);
+
+		if (flags & IORESOURCE_IO) {
+			head = &bridge->io_head;
+		} else if (flags & IORESOURCE_PREFETCH) {
+			head = &bridge->p_mem_head;
+		} else {
+			head = &bridge->mem_head;
+		}
+
+		spin_lock(&bridge->res_lock);
+		res = acpiphp_get_resource_with_base(head, base, len);
+		spin_unlock(&bridge->res_lock);
+		if (res)
+			kfree(res);
+	}
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_detect_pci_resource - detect resources under bridge
+ * @bridge: detect all resources already used under this bridge
+ *
+ * collect all resources already allocated for all devices under a bridge.
+ */
+int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
+{
+	struct list_head *l;
+	struct pci_dev *dev;
+
+	list_for_each (l, &bridge->pci_bus->devices) {
+		dev = pci_dev_b(l);
+		detect_used_resource(bridge, dev);
+	}
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_init_slot_resource - gather resource usage information of a slot
+ * @slot: ACPI slot object to be checked, should have valid pci_dev member
+ *
+ * TBD: PCI-to-PCI bridge case
+ *      use pci_dev->resource[]
+ */
+int acpiphp_init_func_resource (struct acpiphp_func *func)
+{
+	u64 base;
+	u32 bar, len;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct pci_resource *res;
+	struct pci_dev *dev;
+
+	dev = func->pci_dev;
+	dbg("Hot-pluggable device %s\n", pci_name(dev));
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_read_config_dword(dev, address[count], &bar);
+
+		if (!bar)	/* This BAR is not implemented */
+			continue;
+
+		pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
+		pci_read_config_dword(dev, address[count], &len);
+
+		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			base = bar & 0xFFFFFFFC;
+			len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
+
+			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
+
+			res = acpiphp_make_resource(base, len);
+			if (!res)
+				goto no_memory;
+
+			res->next = func->io_head;
+			func->io_head = res;
+
+		} else {
+			/* This is Memory */
+			base = bar & 0xFFFFFFF0;
+			if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					dbg("prefetch mem 64\n");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
+				res = acpiphp_make_resource(base, len);
+				if (!res)
+					goto no_memory;
+
+				res->next = func->p_mem_head;
+				func->p_mem_head = res;
+
+			} else {
+				/* regular memory */
+
+				len &= 0xFFFFFFF0;
+				len = ~len + 1;
+
+				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					dbg("mem 64\n");
+					count += 1;
+				}
+				dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
+				res = acpiphp_make_resource(base, len);
+				if (!res)
+					goto no_memory;
+
+				res->next = func->mem_head;
+				func->mem_head = res;
+
+			}
+		}
+
+		pci_write_config_dword(dev, address[count], bar);
+	}
+#if 1
+	acpiphp_dump_func_resource(func);
+#endif
+
+	return 0;
+
+ no_memory:
+	err("out of memory\n");
+	acpiphp_free_resource(&func->io_head);
+	acpiphp_free_resource(&func->mem_head);
+	acpiphp_free_resource(&func->p_mem_head);
+
+	return -1;
+}
+
+
+/**
+ * acpiphp_configure_slot - allocate PCI resources
+ * @slot: slot to be configured
+ *
+ * initializes a PCI functions on a device inserted
+ * into the slot
+ *
+ */
+int acpiphp_configure_slot (struct acpiphp_slot *slot)
+{
+	struct acpiphp_func *func;
+	struct list_head *l;
+	u8 hdr;
+	u32 dvid;
+	int retval = 0;
+	int is_multi = 0;
+
+	pci_bus_read_config_byte(slot->bridge->pci_bus,
+				 PCI_DEVFN(slot->device, 0),
+				 PCI_HEADER_TYPE, &hdr);
+
+	if (hdr & 0x80)
+		is_multi = 1;
+
+	list_for_each (l, &slot->funcs) {
+		func = list_entry(l, struct acpiphp_func, sibling);
+		if (is_multi || func->function == 0) {
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+						  PCI_DEVFN(slot->device,
+							    func->function),
+						  PCI_VENDOR_ID, &dvid);
+			if (dvid != 0xffffffff) {
+				retval = init_config_space(func);
+				if (retval)
+					break;
+			}
+		}
+	}
+
+	return retval;
+}
+
+/**
+ * acpiphp_configure_function - configure PCI function
+ * @func: function to be configured
+ *
+ * initializes a PCI functions on a device inserted
+ * into the slot
+ *
+ */
+int acpiphp_configure_function (struct acpiphp_func *func)
+{
+	/* all handled by the pci core now */
+	return 0;
+}
+
+/**
+ * acpiphp_unconfigure_function - unconfigure PCI function
+ * @func: function to be unconfigured
+ *
+ */
+void acpiphp_unconfigure_function (struct acpiphp_func *func)
+{
+	struct acpiphp_bridge *bridge;
+
+	/* if pci_dev is NULL, ignore it */
+	if (!func->pci_dev)
+		return;
+
+	pci_remove_bus_device(func->pci_dev);
+
+	/* free all resources */
+	bridge = func->slot->bridge;
+
+	spin_lock(&bridge->res_lock);
+	acpiphp_move_resource(&func->io_head, &bridge->io_head);
+	acpiphp_move_resource(&func->mem_head, &bridge->mem_head);
+	acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head);
+	acpiphp_move_resource(&func->bus_head, &bridge->bus_head);
+	spin_unlock(&bridge->res_lock);
+}
diff --git a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c
new file mode 100644
index 0000000..f54b1fa
--- /dev/null
+++ b/drivers/pci/hotplug/acpiphp_res.c
@@ -0,0 +1,700 @@
+/*
+ * ACPI PCI HotPlug Utility functions
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
+ * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
+ * Copyright (C) 2002 NEC Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>, <t-kochi@bq.jp.nec.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+
+#include <linux/ioctl.h>
+#include <linux/fcntl.h>
+
+#include <linux/list.h>
+
+#include "pci_hotplug.h"
+#include "acpiphp.h"
+
+#define MY_NAME "acpiphp_res"
+
+
+/*
+ * sort_by_size - sort nodes by their length, smallest first
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length > (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length > current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+
+#if 0
+/*
+ * sort_by_max_size - sort nodes by their length, largest first
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length < (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length < current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+#endif
+
+/**
+ * get_io_resource - get resource for I/O ports
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length that is not in the
+ * ISA aliasing window.  If it finds a node larger than "size"
+ * it will split it up.
+ *
+ * size must be a power of two.
+ *
+ * difference from get_resource is handling of ISA aliasing space.
+ *
+ */
+struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_size(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_qword - node->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
+
+			if (!split_node)
+				return NULL;
+
+			node->base = temp_qword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = acpiphp_make_resource(node->base + size, node->length - size);
+
+			if (!split_node)
+				return NULL;
+
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if ((node->base & 0x300L) && !(node->base & 0xfffff000))
+			continue;
+
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+
+	return node;
+}
+
+
+#if 0
+/**
+ * get_max_resource - get the largest resource
+ *
+ * Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ */
+static struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_max_size(head))
+		return NULL;
+
+	for (max = *head;max; max = max->next) {
+
+		/* If not big enough we could probably just bail,
+		   instead we'll continue to the next. */
+		if (max->length < size)
+			continue;
+
+		if (max->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = (max->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max->length - (temp_qword - max->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(max->base, temp_qword - max->base);
+
+			if (!split_node)
+				return NULL;
+
+			max->base = temp_qword;
+			max->length -= split_node->length;
+
+			/* Put it next in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		if ((max->base + max->length) & (size - 1)) {
+			/* this one isn't end aligned properly at the top
+			   so we'll make a new entry and split it up */
+			temp_qword = ((max->base + max->length) & ~(size - 1));
+
+			split_node = acpiphp_make_resource(temp_qword,
+							   max->length + max->base - temp_qword);
+
+			if (!split_node)
+				return NULL;
+
+			max->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max->length < size)
+			continue;
+
+		/* Now take it out of the list */
+		temp = (struct pci_resource*) *head;
+		if (temp == max) {
+			*head = max->next;
+		} else {
+			while (temp && temp->next != max) {
+				temp = temp->next;
+			}
+
+			temp->next = max->next;
+		}
+
+		max->next = NULL;
+		return max;
+	}
+
+	/* If we get here, we couldn't find one */
+	return NULL;
+}
+#endif
+
+/**
+ * get_resource - get resource (mem, pfmem)
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ *
+ */
+struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_size(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
+		    __FUNCTION__, size, node, (u32)node->base, node->length);
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			dbg("%s: not aligned\n", __FUNCTION__);
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_qword - node->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
+
+			if (!split_node)
+				return NULL;
+
+			node->base = temp_qword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			dbg("%s: too big\n", __FUNCTION__);
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = acpiphp_make_resource(node->base + size, node->length - size);
+
+			if (!split_node)
+				return NULL;
+
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		dbg("%s: got one!!!\n", __FUNCTION__);
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return node;
+}
+
+/**
+ * get_resource_with_base - get resource with specific base address
+ *
+ * this function
+ * returns the first node of "size" length located at specified base address.
+ * If it finds a node larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ *
+ */
+struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u64 temp_qword;
+
+	if (!(*head))
+		return NULL;
+
+	if (acpiphp_resource_sort_and_combine(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
+		    (u32)base, size, node, (u32)node->base, node->length);
+		if (node->base > base)
+			continue;
+
+		if ((node->base + node->length) < (base + size))
+			continue;
+
+		if (node->base < base) {
+			dbg(": split 1\n");
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_qword = base;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_qword - node->base)) < size)
+				continue;
+
+			split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
+
+			if (!split_node)
+				return NULL;
+
+			node->base = temp_qword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}
+
+		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
+		    (u32)base, size, node, (u32)node->base, node->length);
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			dbg(": split 2\n");
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = acpiphp_make_resource(node->base + size, node->length - size);
+
+			if (!split_node)
+				return NULL;
+
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		dbg(": got one!!!\n");
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return node;
+}
+
+
+/**
+ * acpiphp_resource_sort_and_combine
+ *
+ * Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int acpiphp_resource_sort_and_combine (struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	dbg("*head->next = %p\n",(*head)->next);
+
+	if (!(*head)->next)
+		return 0;	/* only one item on the list, already sorted! */
+
+	dbg("*head->base = 0x%x\n",(u32)(*head)->base);
+	dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->base > (*head)->next->base)) {
+			node1 = *head;
+			(*head) = (*head)->next;
+			node1->next = (*head)->next;
+			(*head)->next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1->next && node1->next->next) {
+			if (node1->next->base > node1->next->next->base) {
+				out_of_order++;
+				node2 = node1->next;
+				node1->next = node1->next->next;
+				node1 = node1->next;
+				node2->next = node1->next;
+				node1->next = node2;
+			} else
+				node1 = node1->next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 && node1->next) {
+		if ((node1->base + node1->length) == node1->next->base) {
+			/* Combine */
+			dbg("8..\n");
+			node1->length += node1->next->length;
+			node2 = node1->next;
+			node1->next = node1->next->next;
+			kfree(node2);
+		} else
+			node1 = node1->next;
+	}
+
+	return 0;
+}
+
+
+/**
+ * acpiphp_make_resource - make resource structure
+ * @base: base address of a resource
+ * @length: length of a resource
+ */
+struct pci_resource *acpiphp_make_resource (u64 base, u32 length)
+{
+	struct pci_resource *res;
+
+	res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+	if (res) {
+		memset(res, 0, sizeof(struct pci_resource));
+		res->base = base;
+		res->length = length;
+	}
+
+	return res;
+}
+
+
+/**
+ * acpiphp_move_resource - move linked resources from one to another
+ * @from: head of linked resource list
+ * @to: head of linked resource list
+ */
+void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to)
+{
+	struct pci_resource *tmp;
+
+	while (*from) {
+		tmp = (*from)->next;
+		(*from)->next = *to;
+		*to = *from;
+		*from = tmp;
+	}
+
+	/* *from = NULL is guaranteed */
+}
+
+
+/**
+ * acpiphp_free_resource - free all linked resources
+ * @res: head of linked resource list
+ */
+void acpiphp_free_resource (struct pci_resource **res)
+{
+	struct pci_resource *tmp;
+
+	while (*res) {
+		tmp = (*res)->next;
+		kfree(*res);
+		*res = tmp;
+	}
+
+	/* *res = NULL is guaranteed */
+}
+
+
+/* debug support functions;  will go away sometime :) */
+static void dump_resource(struct pci_resource *head)
+{
+	struct pci_resource *p;
+	int cnt;
+
+	p = head;
+	cnt = 0;
+
+	while (p) {
+		dbg("[%02d] %08x - %08x\n",
+		    cnt++, (u32)p->base, (u32)p->base + p->length - 1);
+		p = p->next;
+	}
+}
+
+void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
+{
+	dbg("I/O resource:\n");
+	dump_resource(bridge->io_head);
+	dbg("MEM resource:\n");
+	dump_resource(bridge->mem_head);
+	dbg("PMEM resource:\n");
+	dump_resource(bridge->p_mem_head);
+	dbg("BUS resource:\n");
+	dump_resource(bridge->bus_head);
+}
+
+void acpiphp_dump_func_resource(struct acpiphp_func *func)
+{
+	dbg("I/O resource:\n");
+	dump_resource(func->io_head);
+	dbg("MEM resource:\n");
+	dump_resource(func->mem_head);
+	dbg("PMEM resource:\n");
+	dump_resource(func->p_mem_head);
+	dbg("BUS resource:\n");
+	dump_resource(func->bus_head);
+}
diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
new file mode 100644
index 0000000..3ddd759
--- /dev/null
+++ b/drivers/pci/hotplug/cpci_hotplug.h
@@ -0,0 +1,96 @@
+/*
+ * CompactPCI Hot Plug Core Functions
+ *
+ * Copyright (C) 2002 SOMA Networks, Inc.
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <scottm@somanetworks.com>
+ */
+
+#ifndef _CPCI_HOTPLUG_H
+#define _CPCI_HOTPLUG_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+
+/* PICMG 2.12 R2.0 HS CSR bits: */
+#define HS_CSR_INS	0x0080
+#define HS_CSR_EXT	0x0040
+#define HS_CSR_PI	0x0030
+#define HS_CSR_LOO	0x0008
+#define HS_CSR_PIE	0x0004
+#define HS_CSR_EIM	0x0002
+#define HS_CSR_DHA	0x0001
+
+struct slot {
+	u8 number;
+	unsigned int devfn;
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	unsigned int extracting;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head slot_list;
+};
+
+struct cpci_hp_controller_ops {
+	int (*query_enum) (void);
+	int (*enable_irq) (void);
+	int (*disable_irq) (void);
+	int (*check_irq) (void *dev_id);
+	int (*hardware_test) (struct slot* slot, u32 value);
+	u8  (*get_power) (struct slot* slot);
+	int (*set_power) (struct slot* slot, int value);
+};
+
+struct cpci_hp_controller {
+	unsigned int irq;
+	unsigned long irq_flags;
+	char *devname;
+	void *dev_id;
+	char *name;
+	struct cpci_hp_controller_ops *ops;
+};
+
+extern int cpci_hp_register_controller(struct cpci_hp_controller *controller);
+extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller);
+extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last);
+extern int cpci_hp_unregister_bus(struct pci_bus *bus);
+extern int cpci_hp_start(void);
+extern int cpci_hp_stop(void);
+
+/*
+ * Internal function prototypes, these functions should not be used by
+ * board/chassis drivers.
+ */
+extern u8 cpci_get_attention_status(struct slot *slot);
+extern u8 cpci_get_latch_status(struct slot *slot);
+extern u8 cpci_get_adapter_status(struct slot *slot);
+extern u16 cpci_get_hs_csr(struct slot * slot);
+extern int cpci_set_attention_status(struct slot *slot, int status);
+extern int cpci_check_and_clear_ins(struct slot * slot);
+extern int cpci_check_ext(struct slot * slot);
+extern int cpci_clear_ext(struct slot * slot);
+extern int cpci_led_on(struct slot * slot);
+extern int cpci_led_off(struct slot * slot);
+extern int cpci_configure_slot(struct slot *slot);
+extern int cpci_unconfigure_slot(struct slot *slot);
+
+#endif	/* _CPCI_HOTPLUG_H */
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
new file mode 100644
index 0000000..ed24360
--- /dev/null
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -0,0 +1,792 @@
+/*
+ * CompactPCI Hot Plug Driver
+ *
+ * Copyright (C) 2002 SOMA Networks, Inc.
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <scottm@somanetworks.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include "pci_hotplug.h"
+#include "cpci_hotplug.h"
+
+#define DRIVER_VERSION	"0.2"
+#define DRIVER_AUTHOR	"Scott Murray <scottm@somanetworks.com>"
+#define DRIVER_DESC	"CompactPCI Hot Plug Core"
+
+#define MY_NAME	"cpci_hotplug"
+
+#define dbg(format, arg...)					\
+	do {							\
+		if(cpci_debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				MY_NAME , ## arg); 		\
+	} while(0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+/* local variables */
+static spinlock_t list_lock;
+static LIST_HEAD(slot_list);
+static int slots;
+int cpci_debug;
+static struct cpci_hp_controller *controller;
+static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
+static struct semaphore thread_exit;		/* guard ensure thread has exited before calling it quits */
+static int thread_finished = 1;
+
+static int enable_slot(struct hotplug_slot *slot);
+static int disable_slot(struct hotplug_slot *slot);
+static int set_attention_status(struct hotplug_slot *slot, u8 value);
+static int get_power_status(struct hotplug_slot *slot, u8 * value);
+static int get_attention_status(struct hotplug_slot *slot, u8 * value);
+
+static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
+	.owner = THIS_MODULE,
+	.enable_slot = enable_slot,
+	.disable_slot = disable_slot,
+	.set_attention_status = set_attention_status,
+	.get_power_status = get_power_status,
+	.get_attention_status = get_attention_status,
+};
+
+static int
+update_latch_status(struct hotplug_slot *hotplug_slot, u8 value)
+{
+	struct hotplug_slot_info info;
+
+	memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
+	info.latch_status = value;
+	return pci_hp_change_slot_info(hotplug_slot, &info);
+}
+
+static int
+update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value)
+{
+	struct hotplug_slot_info info;
+
+	memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
+	info.adapter_status = value;
+	return pci_hp_change_slot_info(hotplug_slot, &info);
+}
+
+static int
+enable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	if(controller->ops->set_power) {
+		retval = controller->ops->set_power(slot, 1);
+	}
+
+	return retval;
+}
+
+static int
+disable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	/* Unconfigure device */
+	dbg("%s - unconfiguring slot %s",
+	    __FUNCTION__, slot->hotplug_slot->name);
+	if((retval = cpci_unconfigure_slot(slot))) {
+		err("%s - could not unconfigure slot %s",
+		    __FUNCTION__, slot->hotplug_slot->name);
+		return retval;
+	}
+	dbg("%s - finished unconfiguring slot %s",
+	    __FUNCTION__, slot->hotplug_slot->name);
+
+	/* Clear EXT (by setting it) */
+	if(cpci_clear_ext(slot)) {
+		err("%s - could not clear EXT for slot %s",
+		    __FUNCTION__, slot->hotplug_slot->name);
+		retval = -ENODEV;
+	}
+	cpci_led_on(slot);
+
+	if(controller->ops->set_power) {
+		retval = controller->ops->set_power(slot, 0);
+	}
+
+	if(update_adapter_status(slot->hotplug_slot, 0)) {
+		warn("failure to update adapter file");
+	}
+
+	slot->extracting = 0;
+
+	return retval;
+}
+
+static u8
+cpci_get_power_status(struct slot *slot)
+{
+	u8 power = 1;
+
+	if(controller->ops->get_power) {
+		power = controller->ops->get_power(slot);
+	}
+	return power;
+}
+
+static int
+get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	*value = cpci_get_power_status(slot);
+	return 0;
+}
+
+static int
+get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	*value = cpci_get_attention_status(slot);
+	return 0;
+}
+
+static int
+set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+	return cpci_set_attention_status(hotplug_slot->private, status);
+}
+
+static void release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	kfree(slot);
+}
+
+#define SLOT_NAME_SIZE	6
+static void
+make_slot_name(struct slot *slot)
+{
+	snprintf(slot->hotplug_slot->name,
+		 SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number);
+}
+
+int
+cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
+{
+	struct slot *slot;
+	struct hotplug_slot *hotplug_slot;
+	struct hotplug_slot_info *info;
+	char *name;
+	int status = -ENOMEM;
+	int i;
+
+	if(!(controller && bus)) {
+		return -ENODEV;
+	}
+
+	/*
+	 * Create a structure for each slot, and register that slot
+	 * with the pci_hotplug subsystem.
+	 */
+	for (i = first; i <= last; ++i) {
+		slot = kmalloc(sizeof (struct slot), GFP_KERNEL);
+		if (!slot)
+			goto error;
+		memset(slot, 0, sizeof (struct slot));
+
+		hotplug_slot =
+		    kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
+		if (!hotplug_slot)
+			goto error_slot;
+		memset(hotplug_slot, 0, sizeof (struct hotplug_slot));
+		slot->hotplug_slot = hotplug_slot;
+
+		info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if (!info)
+			goto error_hpslot;
+		memset(info, 0, sizeof (struct hotplug_slot_info));
+		hotplug_slot->info = info;
+
+		name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!name)
+			goto error_info;
+		hotplug_slot->name = name;
+
+		slot->bus = bus;
+		slot->number = i;
+		slot->devfn = PCI_DEVFN(i, 0);
+
+		hotplug_slot->private = slot;
+		hotplug_slot->release = &release_slot;
+		make_slot_name(slot);
+		hotplug_slot->ops = &cpci_hotplug_slot_ops;
+
+		/*
+		 * Initialize the slot info structure with some known
+		 * good values.
+		 */
+		dbg("initializing slot %s", slot->hotplug_slot->name);
+		info->power_status = cpci_get_power_status(slot);
+		info->attention_status = cpci_get_attention_status(slot);
+
+		dbg("registering slot %s", slot->hotplug_slot->name);
+		status = pci_hp_register(slot->hotplug_slot);
+		if (status) {
+			err("pci_hp_register failed with error %d", status);
+			goto error_name;
+		}
+
+		/* Add slot to our internal list */
+		spin_lock(&list_lock);
+		list_add(&slot->slot_list, &slot_list);
+		slots++;
+		spin_unlock(&list_lock);
+	}
+	return 0;
+error_name:
+	kfree(name);
+error_info:
+	kfree(info);
+error_hpslot:
+	kfree(hotplug_slot);
+error_slot:
+	kfree(slot);
+error:
+	return status;
+}
+
+int
+cpci_hp_unregister_bus(struct pci_bus *bus)
+{
+	struct slot *slot;
+	struct list_head *tmp;
+	struct list_head *next;
+	int status;
+
+	spin_lock(&list_lock);
+	if(!slots) {
+		spin_unlock(&list_lock);
+		return -1;
+	}
+	list_for_each_safe(tmp, next, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		if(slot->bus == bus) {
+			dbg("deregistering slot %s", slot->hotplug_slot->name);
+			status = pci_hp_deregister(slot->hotplug_slot);
+			if(status) {
+				err("pci_hp_deregister failed with error %d",
+				    status);
+				return status;
+			}
+
+			list_del(&slot->slot_list);
+			slots--;
+		}
+	}
+	spin_unlock(&list_lock);
+	return 0;
+}
+
+/* This is the interrupt mode interrupt handler */
+static irqreturn_t
+cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
+{
+	dbg("entered cpci_hp_intr");
+
+	/* Check to see if it was our interrupt */
+	if((controller->irq_flags & SA_SHIRQ) &&
+	    !controller->ops->check_irq(controller->dev_id)) {
+		dbg("exited cpci_hp_intr, not our interrupt");
+		return IRQ_NONE;
+	}
+
+	/* Disable ENUM interrupt */
+	controller->ops->disable_irq();
+
+	/* Trigger processing by the event thread */
+	dbg("Signal event_semaphore");
+	up(&event_semaphore);
+	dbg("exited cpci_hp_intr");
+	return IRQ_HANDLED;
+}
+
+/*
+ * According to PICMG 2.12 R2.0, section 6.3.2, upon
+ * initialization, the system driver shall clear the
+ * INS bits of the cold-inserted devices.
+ */
+static int
+init_slots(void)
+{
+	struct slot *slot;
+	struct list_head *tmp;
+	struct pci_dev* dev;
+
+	dbg("%s - enter", __FUNCTION__);
+	spin_lock(&list_lock);
+	if(!slots) {
+		spin_unlock(&list_lock);
+		return -1;
+	}
+	list_for_each(tmp, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		dbg("%s - looking at slot %s",
+		    __FUNCTION__, slot->hotplug_slot->name);
+		if(cpci_check_and_clear_ins(slot)) {
+			dbg("%s - cleared INS for slot %s",
+			    __FUNCTION__, slot->hotplug_slot->name);
+			dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0));
+			if(dev) {
+				if(update_adapter_status(slot->hotplug_slot, 1)) {
+					warn("failure to update adapter file");
+				}
+				if(update_latch_status(slot->hotplug_slot, 1)) {
+					warn("failure to update latch file");
+				}
+				slot->dev = dev;
+			} else {
+				err("%s - no driver attached to device in slot %s",
+				    __FUNCTION__, slot->hotplug_slot->name);
+			}
+		}
+	}
+	spin_unlock(&list_lock);
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int
+check_slots(void)
+{
+	struct slot *slot;
+	struct list_head *tmp;
+	int extracted;
+	int inserted;
+
+	spin_lock(&list_lock);
+	if(!slots) {
+		spin_unlock(&list_lock);
+		err("no slots registered, shutting down");
+		return -1;
+	}
+	extracted = inserted = 0;
+	list_for_each(tmp, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		dbg("%s - looking at slot %s",
+		    __FUNCTION__, slot->hotplug_slot->name);
+		if(cpci_check_and_clear_ins(slot)) {
+			u16 hs_csr;
+
+			/* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
+			if(slot->dev) {
+				warn("slot %s already inserted", slot->hotplug_slot->name);
+				inserted++;
+				continue;
+			}
+
+			/* Process insertion */
+			dbg("%s - slot %s inserted",
+			    __FUNCTION__, slot->hotplug_slot->name);
+
+			/* GSM, debug */
+			hs_csr = cpci_get_hs_csr(slot);
+			dbg("%s - slot %s HS_CSR (1) = %04x",
+			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
+
+			/* Configure device */
+			dbg("%s - configuring slot %s",
+			    __FUNCTION__, slot->hotplug_slot->name);
+			if(cpci_configure_slot(slot)) {
+				err("%s - could not configure slot %s",
+				    __FUNCTION__, slot->hotplug_slot->name);
+				continue;
+			}
+			dbg("%s - finished configuring slot %s",
+			    __FUNCTION__, slot->hotplug_slot->name);
+
+			/* GSM, debug */
+			hs_csr = cpci_get_hs_csr(slot);
+			dbg("%s - slot %s HS_CSR (2) = %04x",
+			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
+
+			if(update_latch_status(slot->hotplug_slot, 1)) {
+				warn("failure to update latch file");
+			}
+
+			if(update_adapter_status(slot->hotplug_slot, 1)) {
+				warn("failure to update adapter file");
+			}
+
+			cpci_led_off(slot);
+
+			/* GSM, debug */
+			hs_csr = cpci_get_hs_csr(slot);
+			dbg("%s - slot %s HS_CSR (3) = %04x",
+			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
+
+			inserted++;
+		} else if(cpci_check_ext(slot)) {
+			u16 hs_csr;
+
+			/* Process extraction request */
+			dbg("%s - slot %s extracted",
+			    __FUNCTION__, slot->hotplug_slot->name);
+
+			/* GSM, debug */
+			hs_csr = cpci_get_hs_csr(slot);
+			dbg("%s - slot %s HS_CSR = %04x",
+			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
+
+			if(!slot->extracting) {
+				if(update_latch_status(slot->hotplug_slot, 0)) {
+					warn("failure to update latch file");
+				}
+				slot->extracting = 1;
+			}
+			extracted++;
+		}
+	}
+	spin_unlock(&list_lock);
+	if(inserted || extracted) {
+		return extracted;
+	}
+	else {
+		err("cannot find ENUM# source, shutting down");
+		return -1;
+	}
+}
+
+/* This is the interrupt mode worker thread body */
+static int
+event_thread(void *data)
+{
+	int rc;
+	struct slot *slot;
+	struct list_head *tmp;
+
+	lock_kernel();
+	daemonize("cpci_hp_eventd");
+	unlock_kernel();
+
+	dbg("%s - event thread started", __FUNCTION__);
+	while(1) {
+		dbg("event thread sleeping");
+		down_interruptible(&event_semaphore);
+		dbg("event thread woken, thread_finished = %d",
+		    thread_finished);
+		if(thread_finished || signal_pending(current))
+			break;
+		while(controller->ops->query_enum()) {
+			rc = check_slots();
+			if (rc > 0)
+				/* Give userspace a chance to handle extraction */
+				msleep(500);
+			else if (rc < 0) {
+				dbg("%s - error checking slots", __FUNCTION__);
+				thread_finished = 1;
+				break;
+			}
+		}
+		/* Check for someone yanking out a board */
+		list_for_each(tmp, &slot_list) {
+			slot = list_entry(tmp, struct slot, slot_list);
+			if(slot->extracting) {
+				/*
+				 * Hmmm, we're likely hosed at this point, should we
+				 * bother trying to tell the driver or not?
+				 */
+				err("card in slot %s was improperly removed",
+				    slot->hotplug_slot->name);
+				if(update_adapter_status(slot->hotplug_slot, 0)) {
+					warn("failure to update adapter file");
+				}
+				slot->extracting = 0;
+			}
+		}
+
+		/* Re-enable ENUM# interrupt */
+		dbg("%s - re-enabling irq", __FUNCTION__);
+		controller->ops->enable_irq();
+	}
+
+	dbg("%s - event thread signals exit", __FUNCTION__);
+	up(&thread_exit);
+	return 0;
+}
+
+/* This is the polling mode worker thread body */
+static int
+poll_thread(void *data)
+{
+	int rc;
+	struct slot *slot;
+	struct list_head *tmp;
+
+	lock_kernel();
+	daemonize("cpci_hp_polld");
+	unlock_kernel();
+
+	while(1) {
+		if(thread_finished || signal_pending(current))
+			break;
+
+		while(controller->ops->query_enum()) {
+			rc = check_slots();
+			if(rc > 0)
+				/* Give userspace a chance to handle extraction */
+				msleep(500);
+			else if (rc < 0) {
+				dbg("%s - error checking slots", __FUNCTION__);
+				thread_finished = 1;
+				break;
+			}
+		}
+		/* Check for someone yanking out a board */
+		list_for_each(tmp, &slot_list) {
+			slot = list_entry(tmp, struct slot, slot_list);
+			if(slot->extracting) {
+				/*
+				 * Hmmm, we're likely hosed at this point, should we
+				 * bother trying to tell the driver or not?
+				 */
+				err("card in slot %s was improperly removed",
+				    slot->hotplug_slot->name);
+				if(update_adapter_status(slot->hotplug_slot, 0)) {
+					warn("failure to update adapter file");
+				}
+				slot->extracting = 0;
+			}
+		}
+
+		msleep(100);
+	}
+	dbg("poll thread signals exit");
+	up(&thread_exit);
+	return 0;
+}
+
+static int
+cpci_start_thread(void)
+{
+	int pid;
+
+	/* initialize our semaphores */
+	init_MUTEX_LOCKED(&event_semaphore);
+	init_MUTEX_LOCKED(&thread_exit);
+	thread_finished = 0;
+
+	if(controller->irq) {
+		pid = kernel_thread(event_thread, NULL, 0);
+	} else {
+		pid = kernel_thread(poll_thread, NULL, 0);
+	}
+	if(pid < 0) {
+		err("Can't start up our thread");
+		return -1;
+	}
+	dbg("Our thread pid = %d", pid);
+	return 0;
+}
+
+static void
+cpci_stop_thread(void)
+{
+	thread_finished = 1;
+	dbg("thread finish command given");
+	if(controller->irq) {
+		up(&event_semaphore);
+	}
+	dbg("wait for thread to exit");
+	down(&thread_exit);
+}
+
+int
+cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
+{
+	int status = 0;
+
+	if(!controller) {
+		controller = new_controller;
+		if(controller->irq) {
+			if(request_irq(controller->irq,
+					cpci_hp_intr,
+					controller->irq_flags,
+					MY_NAME, controller->dev_id)) {
+				err("Can't get irq %d for the hotplug cPCI controller", controller->irq);
+				status = -ENODEV;
+			}
+			dbg("%s - acquired controller irq %d", __FUNCTION__,
+			    controller->irq);
+		}
+	} else {
+		err("cPCI hotplug controller already registered");
+		status = -1;
+	}
+	return status;
+}
+
+int
+cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
+{
+	int status = 0;
+
+	if(controller) {
+		if(!thread_finished) {
+			cpci_stop_thread();
+		}
+		if(controller->irq) {
+			free_irq(controller->irq, controller->dev_id);
+		}
+		controller = NULL;
+	} else {
+		status = -ENODEV;
+	}
+	return status;
+}
+
+int
+cpci_hp_start(void)
+{
+	static int first = 1;
+	int status;
+
+	dbg("%s - enter", __FUNCTION__);
+	if(!controller) {
+		return -ENODEV;
+	}
+
+	spin_lock(&list_lock);
+	if(!slots) {
+		spin_unlock(&list_lock);
+		return -ENODEV;
+	}
+	spin_unlock(&list_lock);
+
+	if(first) {
+		status = init_slots();
+		if(status) {
+			return status;
+		}
+		first = 0;
+	}
+
+	status = cpci_start_thread();
+	if(status) {
+		return status;
+	}
+	dbg("%s - thread started", __FUNCTION__);
+
+	if(controller->irq) {
+		/* Start enum interrupt processing */
+		dbg("%s - enabling irq", __FUNCTION__);
+		controller->ops->enable_irq();
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+int
+cpci_hp_stop(void)
+{
+	if(!controller) {
+		return -ENODEV;
+	}
+
+	if(controller->irq) {
+		/* Stop enum interrupt processing */
+		dbg("%s - disabling irq", __FUNCTION__);
+		controller->ops->disable_irq();
+	}
+	cpci_stop_thread();
+	return 0;
+}
+
+static void __exit
+cleanup_slots(void)
+{
+	struct list_head *tmp;
+	struct slot *slot;
+
+	/*
+	 * Unregister all of our slots with the pci_hotplug subsystem,
+	 * and free up all memory that we had allocated.
+	 */
+	spin_lock(&list_lock);
+	if(!slots) {
+		goto null_cleanup;
+	}
+	list_for_each(tmp, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		list_del(&slot->slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
+		kfree(slot->hotplug_slot->info);
+		kfree(slot->hotplug_slot->name);
+		kfree(slot->hotplug_slot);
+		kfree(slot);
+	}
+      null_cleanup:
+	spin_unlock(&list_lock);
+	return;
+}
+
+int __init
+cpci_hotplug_init(int debug)
+{
+	spin_lock_init(&list_lock);
+	cpci_debug = debug;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION);
+	return 0;
+}
+
+void __exit
+cpci_hotplug_exit(void)
+{
+	/*
+	 * Clean everything up.
+	 */
+	cleanup_slots();
+}
+
+EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
+EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
+EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
+EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus);
+EXPORT_SYMBOL_GPL(cpci_hp_start);
+EXPORT_SYMBOL_GPL(cpci_hp_stop);
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
new file mode 100644
index 0000000..2e96961
--- /dev/null
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -0,0 +1,661 @@
+/*
+ * CompactPCI Hot Plug Driver PCI functions
+ *
+ * Copyright (C) 2002 by SOMA Networks, Inc.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <scottm@somanetworks.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include "../pci.h"
+#include "pci_hotplug.h"
+#include "cpci_hotplug.h"
+
+#if !defined(MODULE)
+#define MY_NAME	"cpci_hotplug"
+#else
+#define MY_NAME	THIS_MODULE->name
+#endif
+
+extern int cpci_debug;
+
+#define dbg(format, arg...)					\
+	do {							\
+		if(cpci_debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				MY_NAME , ## arg); 		\
+	} while(0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+#define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
+
+
+u8 cpci_get_attention_status(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0;
+	}
+
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0;
+	}
+	return hs_csr & 0x0008 ? 1 : 0;
+}
+
+int cpci_set_attention_status(struct slot* slot, int status)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0;
+	}
+
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0;
+	}
+	if(status) {
+		hs_csr |= HS_CSR_LOO;
+	} else {
+		hs_csr &= ~HS_CSR_LOO;
+	}
+	if(pci_bus_write_config_word(slot->bus,
+				      slot->devfn,
+				      hs_cap + 2,
+				      hs_csr)) {
+		return 0;
+	}
+	return 1;
+}
+
+u16 cpci_get_hs_csr(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0xFFFF;
+	}
+
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0xFFFF;
+	}
+	return hs_csr;
+}
+
+#if 0
+u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr)
+{
+	int hs_cap;
+	u16 new_hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0xFFFF;
+	}
+
+	/* Write out the new value */
+	if(pci_bus_write_config_word(slot->bus,
+				      slot->devfn,
+				      hs_cap + 2,
+				      hs_csr)) {
+		return 0xFFFF;
+	}
+
+	/* Read back what we just wrote out */
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &new_hs_csr)) {
+		return 0xFFFF;
+	}
+	return new_hs_csr;
+}
+#endif
+
+int cpci_check_and_clear_ins(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+	int ins = 0;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0;
+	}
+	if(hs_csr & HS_CSR_INS) {
+		/* Clear INS (by setting it) */
+		if(pci_bus_write_config_word(slot->bus,
+					      slot->devfn,
+					      hs_cap + 2,
+					      hs_csr)) {
+			ins = 0;
+		}
+		ins = 1;
+	}
+	return ins;
+}
+
+int cpci_check_ext(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+	int ext = 0;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0;
+	}
+	if(hs_csr & HS_CSR_EXT) {
+		ext = 1;
+	}
+	return ext;
+}
+
+int cpci_clear_ext(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return -ENODEV;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return -ENODEV;
+	}
+	if(hs_csr & HS_CSR_EXT) {
+		/* Clear EXT (by setting it) */
+		if(pci_bus_write_config_word(slot->bus,
+					      slot->devfn,
+					      hs_cap + 2,
+					      hs_csr)) {
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+int cpci_led_on(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return -ENODEV;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return -ENODEV;
+	}
+	if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
+		/* Set LOO */
+		hs_csr |= HS_CSR_LOO;
+		if(pci_bus_write_config_word(slot->bus,
+					      slot->devfn,
+					      hs_cap + 2,
+					      hs_csr)) {
+			err("Could not set LOO for slot %s",
+			    slot->hotplug_slot->name);
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+int cpci_led_off(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return -ENODEV;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return -ENODEV;
+	}
+	if(hs_csr & HS_CSR_LOO) {
+		/* Clear LOO */
+		hs_csr &= ~HS_CSR_LOO;
+		if(pci_bus_write_config_word(slot->bus,
+					      slot->devfn,
+					      hs_cap + 2,
+					      hs_csr)) {
+			err("Could not clear LOO for slot %s",
+			    slot->hotplug_slot->name);
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+
+/*
+ * Device configuration functions
+ */
+
+static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev)
+{
+	u8 irq_pin;
+	int r;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	/* NOTE: device already setup from prior scan */
+
+	/* FIXME: How would we know if we need to enable the expansion ROM? */
+	pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L);
+
+	/* Assign resources */
+	dbg("assigning resources for %02x:%02x.%x",
+	    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	for (r = 0; r < 6; r++) {
+		struct resource *res = dev->resource + r;
+		if(res->flags)
+			pci_assign_resource(dev, r);
+	}
+	dbg("finished assigning resources for %02x:%02x.%x",
+	    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+
+	/* Does this function have an interrupt at all? */
+	dbg("checking for function interrupt");
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
+	if(irq_pin) {
+		dbg("function uses interrupt pin %d", irq_pin);
+	}
+
+	/*
+	 * Need to explicitly set irq field to 0 so that it'll get assigned
+	 * by the pcibios platform dependent code called by pci_enable_device.
+	 */
+	dev->irq = 0;
+
+	dbg("enabling device");
+	pci_enable_device(dev);	/* XXX check return */
+	dbg("now dev->irq = %d", dev->irq);
+	if(irq_pin && dev->irq) {
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+
+	/* Can't use pci_insert_device at the moment, do it manually for now */
+	pci_proc_attach_device(dev);
+	dbg("notifying drivers");
+	//pci_announce_device_to_drivers(dev);
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev)
+{
+	int rc;
+	struct pci_bus* child;
+	struct resource* r;
+	u8 max, n;
+	u16 command;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	/* Do basic bridge initialization */
+	rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
+	if(rc) {
+		printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__);
+	}
+	rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40);
+	if(rc) {
+		printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__);
+	}
+	rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
+	if(rc) {
+		printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__);
+	}
+
+	/*
+	 * Set parent bridge's subordinate field so that configuration space
+	 * access will work in pci_scan_bridge and friends.
+	 */
+	max = pci_max_busnr();
+	bus->subordinate = max + 1;
+	pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1);
+
+	/* Scan behind bridge */
+	n = pci_scan_bridge(bus, dev, max, 2);
+	child = pci_find_bus(0, max + 1);
+	if (!child)
+		return -ENODEV;
+	pci_proc_attach_bus(child);
+
+	/*
+	 * Update parent bridge's subordinate field if there were more bridges
+	 * behind the bridge that was scanned.
+	 */
+	if(n > max) {
+		bus->subordinate = n;
+		pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n);
+	}
+
+	/*
+	 * Update the bridge resources of the bridge to accommodate devices
+	 * behind it.
+	 */
+	pci_bus_size_bridges(child);
+	pci_bus_assign_resources(child);
+
+	/* Enable resource mapping via command register */
+	command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+	r = child->resource[0];
+	if(r && r->start) {
+		command |= PCI_COMMAND_IO;
+	}
+	r = child->resource[1];
+	if(r && r->start) {
+		command |= PCI_COMMAND_MEMORY;
+	}
+	r = child->resource[2];
+	if(r && r->start) {
+		command |= PCI_COMMAND_MEMORY;
+	}
+	rc = pci_write_config_word(dev, PCI_COMMAND, command);
+	if(rc) {
+		err("Error setting command register");
+		return rc;
+	}
+
+	/* Set bridge control register */
+	command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA;
+	rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command);
+	if(rc) {
+		err("Error setting bridge control register");
+		return rc;
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev,
+				   struct pci_bus_wrapped *wrapped_bus)
+{
+	int rc;
+	struct pci_dev *dev = wrapped_dev->dev;
+	struct pci_bus *bus = wrapped_bus->bus;
+	struct slot* slot;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	/*
+	 * We need to fix up the hotplug representation with the Linux
+	 * representation.
+	 */
+	if(wrapped_dev->data) {
+		slot = (struct slot*) wrapped_dev->data;
+		slot->dev = dev;
+	}
+
+	/* If it's a bridge, scan behind it for devices */
+	if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = cpci_configure_bridge(bus, dev);
+		if(rc)
+			return rc;
+	}
+
+	/* Actually configure device */
+	if(dev) {
+		rc = cpci_configure_dev(bus, dev);
+		if(rc)
+			return rc;
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev,
+					    struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev *dev = wrapped_dev->dev;
+	struct slot* slot;
+
+	dbg("%s - enter", __FUNCTION__);
+	if(!dev)
+		return -ENODEV;
+
+	/* Remove the Linux representation */
+	if(pci_remove_device_safe(dev)) {
+		err("Could not remove device\n");
+		return -1;
+	}
+
+	/*
+	 * Now remove the hotplug representation.
+	 */
+	if(wrapped_dev->data) {
+		slot = (struct slot*) wrapped_dev->data;
+		slot->dev = NULL;
+	} else {
+		dbg("No hotplug representation for %02x:%02x.%x",
+		    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus,
+					    struct pci_dev_wrapped *wrapped_dev)
+{
+	struct pci_bus *bus = wrapped_bus->bus;
+	struct pci_bus *parent = bus->self->bus;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	/* The cleanup code for proc entries regarding buses should be in the kernel... */
+	if(bus->procdir)
+		dbg("detach_pci_bus %s", bus->procdir->name);
+	pci_proc_detach_bus(bus);
+
+	/* The cleanup code should live in the kernel... */
+	bus->self->subordinate = NULL;
+
+	/* unlink from parent bus */
+	list_del(&bus->node);
+
+	/* Now, remove */
+	if(bus)
+		kfree(bus);
+
+	/* Update parent's subordinate field */
+	if(parent) {
+		u8 n = pci_bus_max_busnr(parent);
+		if(n < parent->subordinate) {
+			parent->subordinate = n;
+			pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n);
+		}
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static struct pci_visit configure_functions = {
+	.visit_pci_dev = configure_visit_pci_dev,
+};
+
+static struct pci_visit unconfigure_functions_phase2 = {
+	.post_visit_pci_bus = unconfigure_visit_pci_bus_phase2,
+	.post_visit_pci_dev = unconfigure_visit_pci_dev_phase2
+};
+
+
+int cpci_configure_slot(struct slot* slot)
+{
+	int rc = 0;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	if(slot->dev == NULL) {
+		dbg("pci_dev null, finding %02x:%02x:%x",
+		    slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
+		slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
+	}
+
+	/* Still NULL? Well then scan for it! */
+	if(slot->dev == NULL) {
+		int n;
+		dbg("pci_dev still null");
+
+		/*
+		 * This will generate pci_dev structures for all functions, but
+		 * we will only call this case when lookup fails.
+		 */
+		n = pci_scan_slot(slot->bus, slot->devfn);
+		dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n);
+		if(n > 0)
+			pci_bus_add_devices(slot->bus);
+		slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
+		if(slot->dev == NULL) {
+			err("Could not find PCI device for slot %02x", slot->number);
+			return 0;
+		}
+	}
+	dbg("slot->dev = %p", slot->dev);
+	if(slot->dev) {
+		struct pci_dev *dev;
+		struct pci_dev_wrapped wrapped_dev;
+		struct pci_bus_wrapped wrapped_bus;
+		int i;
+
+		memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
+		memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
+
+		for (i = 0; i < 8; i++) {
+			dev = pci_find_slot(slot->bus->number,
+					    PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i));
+			if(!dev)
+				continue;
+			wrapped_dev.dev = dev;
+			wrapped_bus.bus = slot->dev->bus;
+			if(i)
+				wrapped_dev.data = NULL;
+			else
+				wrapped_dev.data = (void*) slot;
+			rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
+		}
+	}
+
+	dbg("%s - exit, rc = %d", __FUNCTION__, rc);
+	return rc;
+}
+
+int cpci_unconfigure_slot(struct slot* slot)
+{
+	int rc = 0;
+	int i;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	struct pci_dev *dev;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	if(!slot->dev) {
+		err("No device for slot %02x\n", slot->number);
+		return -ENODEV;
+	}
+
+	memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
+
+	for (i = 0; i < 8; i++) {
+		dev = pci_find_slot(slot->bus->number,
+				    PCI_DEVFN(PCI_SLOT(slot->devfn), i));
+		if(dev) {
+			wrapped_dev.dev = dev;
+			wrapped_bus.bus = dev->bus;
+ 			if(i)
+ 				wrapped_dev.data = NULL;
+ 			else
+ 				wrapped_dev.data = (void*) slot;
+			dbg("%s - unconfigure phase 2", __FUNCTION__);
+			rc = pci_visit_dev(&unconfigure_functions_phase2,
+					   &wrapped_dev,
+					   &wrapped_bus);
+			if(rc)
+				break;
+		}
+	}
+	dbg("%s - exit, rc = %d", __FUNCTION__, rc);
+	return rc;
+}
diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c
new file mode 100644
index 0000000..a62a434
--- /dev/null
+++ b/drivers/pci/hotplug/cpcihp_generic.c
@@ -0,0 +1,223 @@
+/*
+ * cpcihp_generic.c
+ *
+ * Generic port I/O CompactPCI driver
+ *
+ * Copyright 2002 SOMA Networks, Inc.
+ * Copyright 2001 Intel San Luis Obispo
+ * Copyright 2000,2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This generic CompactPCI hotplug driver should allow using the PCI hotplug
+ * mechanism on any CompactPCI board that exposes the #ENUM signal as a bit
+ * in a system register that can be read through standard port I/O.
+ *
+ * Send feedback to <scottm@somanetworks.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include "cpci_hotplug.h"
+
+#define DRIVER_VERSION	"0.1"
+#define DRIVER_AUTHOR	"Scott Murray <scottm@somanetworks.com>"
+#define DRIVER_DESC	"Generic port I/O CompactPCI Hot Plug Driver"
+
+#if !defined(MODULE)
+#define MY_NAME	"cpcihp_generic"
+#else
+#define MY_NAME	THIS_MODULE->name
+#endif
+
+#define dbg(format, arg...)					\
+	do {							\
+		if(debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				MY_NAME , ## arg); 		\
+	} while(0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+/* local variables */
+static int debug;
+static char *bridge;
+static u8 bridge_busnr;
+static u8 bridge_slot;
+static struct pci_bus *bus;
+static u8 first_slot;
+static u8 last_slot;
+static u16 port;
+static unsigned int enum_bit;
+static u8 enum_mask;
+
+static struct cpci_hp_controller_ops generic_hpc_ops;
+static struct cpci_hp_controller generic_hpc;
+
+static int __init validate_parameters(void)
+{
+	char* str;
+	char* p;
+	unsigned long tmp;
+
+	if(!bridge) {
+		info("not configured, disabling.");
+		return 1;
+	}
+	str = bridge;
+	if(!*str)
+		return -EINVAL;
+
+	tmp = simple_strtoul(str, &p, 16);
+	if(p == str || tmp > 0xff) {
+		err("Invalid hotplug bus bridge device bus number");
+		return -EINVAL;
+	}
+	bridge_busnr = (u8) tmp;
+	dbg("bridge_busnr = 0x%02x", bridge_busnr);
+	if(*p != ':') {
+		err("Invalid hotplug bus bridge device");
+		return -EINVAL;
+	}
+	str = p + 1;
+	tmp = simple_strtoul(str, &p, 16);
+	if(p == str || tmp > 0x1f) {
+		err("Invalid hotplug bus bridge device slot number");
+		return -EINVAL;
+	}
+	bridge_slot = (u8) tmp;
+	dbg("bridge_slot = 0x%02x", bridge_slot);
+
+	dbg("first_slot = 0x%02x", first_slot);
+	dbg("last_slot = 0x%02x", last_slot);
+	if(!(first_slot && last_slot)) {
+		err("Need to specify first_slot and last_slot");
+		return -EINVAL;
+	}
+	if(last_slot < first_slot) {
+		err("first_slot must be less than last_slot");
+		return -EINVAL;
+	}
+
+	dbg("port = 0x%04x", port);
+	dbg("enum_bit = 0x%02x", enum_bit);
+	if(enum_bit > 7) {
+		err("Invalid #ENUM bit");
+		return -EINVAL;
+	}
+	enum_mask = 1 << enum_bit;
+	return 0;
+}
+
+static int query_enum(void)
+{
+	u8 value;
+
+	value = inb_p(port);
+	return ((value & enum_mask) == enum_mask);
+}
+
+static int __init cpcihp_generic_init(void)
+{
+	int status;
+	struct resource* r;
+	struct pci_dev* dev;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION);
+	status = validate_parameters();
+	if(status != 0)
+		return status;
+
+	r = request_region(port, 1, "#ENUM hotswap signal register");
+	if(!r)
+		return -EBUSY;
+
+	dev = pci_find_slot(bridge_busnr, PCI_DEVFN(bridge_slot, 0));
+	if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+		err("Invalid bridge device %s", bridge);
+		return -EINVAL;
+	}
+	bus = dev->subordinate;
+
+	memset(&generic_hpc, 0, sizeof (struct cpci_hp_controller));
+	generic_hpc_ops.query_enum = query_enum;
+	generic_hpc.ops = &generic_hpc_ops;
+
+	status = cpci_hp_register_controller(&generic_hpc);
+	if(status != 0) {
+		err("Could not register cPCI hotplug controller");
+		return -ENODEV;
+	}
+	dbg("registered controller");
+
+	status = cpci_hp_register_bus(bus, first_slot, last_slot);
+	if(status != 0) {
+		err("Could not register cPCI hotplug bus");
+		goto init_bus_register_error;
+	}
+	dbg("registered bus");
+
+	status = cpci_hp_start();
+	if(status != 0) {
+		err("Could not started cPCI hotplug system");
+		goto init_start_error;
+	}
+	dbg("started cpci hp system");
+	return 0;
+init_start_error:
+	cpci_hp_unregister_bus(bus);
+init_bus_register_error:
+	cpci_hp_unregister_controller(&generic_hpc);
+	err("status = %d", status);
+	return status;
+
+}
+
+static void __exit cpcihp_generic_exit(void)
+{
+	cpci_hp_stop();
+	cpci_hp_unregister_bus(bus);
+	cpci_hp_unregister_controller(&generic_hpc);
+	release_region(port, 1);
+}
+
+module_init(cpcihp_generic_init);
+module_exit(cpcihp_generic_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+module_param(bridge, charp, 0);
+MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, <bus>:<slot> (bus and slot are in hexadecimal)");
+module_param(first_slot, byte, 0);
+MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number");
+module_param(last_slot, byte, 0);
+MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number");
+module_param(port, ushort, 0);
+MODULE_PARM_DESC(port, "#ENUM signal I/O port");
+module_param(enum_bit, uint, 0);
+MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)");
diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c
new file mode 100644
index 0000000..e992802
--- /dev/null
+++ b/drivers/pci/hotplug/cpcihp_zt5550.c
@@ -0,0 +1,305 @@
+/*
+ * cpcihp_zt5550.c
+ *
+ * Intel/Ziatech ZT5550 CompactPCI Host Controller driver
+ *
+ * Copyright 2002 SOMA Networks, Inc.
+ * Copyright 2001 Intel San Luis Obispo
+ * Copyright 2000,2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <scottm@somanetworks.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include "cpci_hotplug.h"
+#include "cpcihp_zt5550.h"
+
+#define DRIVER_VERSION	"0.2"
+#define DRIVER_AUTHOR	"Scott Murray <scottm@somanetworks.com>"
+#define DRIVER_DESC	"ZT5550 CompactPCI Hot Plug Driver"
+
+#define MY_NAME	"cpcihp_zt5550"
+
+#define dbg(format, arg...)					\
+	do {							\
+		if(debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				MY_NAME , ## arg); 		\
+	} while(0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+/* local variables */
+static int debug;
+static int poll;
+static struct cpci_hp_controller_ops zt5550_hpc_ops;
+static struct cpci_hp_controller zt5550_hpc;
+
+/* Primary cPCI bus bridge device */
+static struct pci_dev *bus0_dev;
+static struct pci_bus *bus0;
+
+/* Host controller device */
+static struct pci_dev *hc_dev;
+
+/* Host controller register addresses */
+static void __iomem *hc_registers;
+static void __iomem *csr_hc_index;
+static void __iomem *csr_hc_data;
+static void __iomem *csr_int_status;
+static void __iomem *csr_int_mask;
+
+
+static int zt5550_hc_config(struct pci_dev *pdev)
+{
+	/* Since we know that no boards exist with two HC chips, treat it as an error */
+	if(hc_dev) {
+		err("too many host controller devices?");
+		return -EBUSY;
+	}
+	hc_dev = pdev;
+	dbg("hc_dev = %p", hc_dev);
+	dbg("pci resource start %lx", pci_resource_start(hc_dev, 1));
+	dbg("pci resource len %lx", pci_resource_len(hc_dev, 1));
+
+	if(!request_mem_region(pci_resource_start(hc_dev, 1),
+				pci_resource_len(hc_dev, 1), MY_NAME)) {
+		err("cannot reserve MMIO region");
+		return -ENOMEM;
+	}
+
+	hc_registers =
+	    ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1));
+	if(!hc_registers) {
+		err("cannot remap MMIO region %lx @ %lx",
+		    pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1));
+		release_mem_region(pci_resource_start(hc_dev, 1),
+				   pci_resource_len(hc_dev, 1));
+		return -ENODEV;
+	}
+
+	csr_hc_index = hc_registers + CSR_HCINDEX;
+	csr_hc_data = hc_registers + CSR_HCDATA;
+	csr_int_status = hc_registers + CSR_INTSTAT;
+	csr_int_mask = hc_registers + CSR_INTMASK;
+
+	/*
+	 * Disable host control, fault and serial interrupts
+	 */
+	dbg("disabling host control, fault and serial interrupts");
+	writeb((u8) HC_INT_MASK_REG, csr_hc_index);
+	writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data);
+	dbg("disabled host control, fault and serial interrupts");
+
+	/*
+	 * Disable timer0, timer1 and ENUM interrupts
+	 */
+	dbg("disabling timer0, timer1 and ENUM interrupts");
+	writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask);
+	dbg("disabled timer0, timer1 and ENUM interrupts");
+	return 0;
+}
+
+static int zt5550_hc_cleanup(void)
+{
+	if(!hc_dev)
+		return -ENODEV;
+
+	iounmap(hc_registers);
+	release_mem_region(pci_resource_start(hc_dev, 1),
+			   pci_resource_len(hc_dev, 1));
+	return 0;
+}
+
+static int zt5550_hc_query_enum(void)
+{
+	u8 value;
+
+	value = inb_p(ENUM_PORT);
+	return ((value & ENUM_MASK) == ENUM_MASK);
+}
+
+static int zt5550_hc_check_irq(void *dev_id)
+{
+	int ret;
+	u8 reg;
+
+	ret = 0;
+	if(dev_id == zt5550_hpc.dev_id) {
+		reg = readb(csr_int_status);
+		if(reg)
+			ret = 1;
+	}
+	return ret;
+}
+
+static int zt5550_hc_enable_irq(void)
+{
+	u8 reg;
+
+	if(hc_dev == NULL) {
+		return -ENODEV;
+	}
+	reg = readb(csr_int_mask);
+	reg = reg & ~ENUM_INT_MASK;
+	writeb(reg, csr_int_mask);
+	return 0;
+}
+
+static int zt5550_hc_disable_irq(void)
+{
+	u8 reg;
+
+	if(hc_dev == NULL) {
+		return -ENODEV;
+	}
+
+	reg = readb(csr_int_mask);
+	reg = reg | ENUM_INT_MASK;
+	writeb(reg, csr_int_mask);
+	return 0;
+}
+
+static int zt5550_hc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int status;
+
+	status = zt5550_hc_config(pdev);
+	if(status != 0) {
+		return status;
+	}
+	dbg("returned from zt5550_hc_config");
+
+	memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller));
+	zt5550_hpc_ops.query_enum = zt5550_hc_query_enum;
+	zt5550_hpc.ops = &zt5550_hpc_ops;
+	if(!poll) {
+		zt5550_hpc.irq = hc_dev->irq;
+		zt5550_hpc.irq_flags = SA_SHIRQ;
+		zt5550_hpc.dev_id = hc_dev;
+
+		zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq;
+		zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq;
+		zt5550_hpc_ops.check_irq = zt5550_hc_check_irq;
+	} else {
+		info("using ENUM# polling mode");
+	}
+
+	status = cpci_hp_register_controller(&zt5550_hpc);
+	if(status != 0) {
+		err("could not register cPCI hotplug controller");
+		goto init_hc_error;
+	}
+	dbg("registered controller");
+
+	/* Look for first device matching cPCI bus's bridge vendor and device IDs */
+	if(!(bus0_dev = pci_get_device(PCI_VENDOR_ID_DEC,
+					 PCI_DEVICE_ID_DEC_21154, NULL))) {
+		status = -ENODEV;
+		goto init_register_error;
+	}
+	bus0 = bus0_dev->subordinate;
+	pci_dev_put(bus0_dev);
+
+	status = cpci_hp_register_bus(bus0, 0x0a, 0x0f);
+	if(status != 0) {
+		err("could not register cPCI hotplug bus");
+		goto init_register_error;
+	}
+	dbg("registered bus");
+
+	status = cpci_hp_start();
+	if(status != 0) {
+		err("could not started cPCI hotplug system");
+		cpci_hp_unregister_bus(bus0);
+		goto init_register_error;
+	}
+	dbg("started cpci hp system");
+
+	return 0;
+init_register_error:
+	cpci_hp_unregister_controller(&zt5550_hpc);
+init_hc_error:
+	err("status = %d", status);
+	zt5550_hc_cleanup();
+	return status;
+
+}
+
+static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev)
+{
+	cpci_hp_stop();
+	cpci_hp_unregister_bus(bus0);
+	cpci_hp_unregister_controller(&zt5550_hpc);
+	zt5550_hc_cleanup();
+}
+
+
+static struct pci_device_id zt5550_hc_pci_tbl[] = {
+	{ PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl);
+	
+static struct pci_driver zt5550_hc_driver = {
+	.name		= "zt5550_hc",
+	.id_table	= zt5550_hc_pci_tbl,
+	.probe		= zt5550_hc_init_one,
+	.remove		= __devexit_p(zt5550_hc_remove_one),
+};
+
+static int __init zt5550_init(void)
+{
+	struct resource* r;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION);
+	r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register");
+	if(!r)
+		return -EBUSY;
+
+	return pci_register_driver(&zt5550_hc_driver);
+}
+
+static void __exit
+zt5550_exit(void)
+{
+	pci_unregister_driver(&zt5550_hc_driver);
+	release_region(ENUM_PORT, 1);
+}
+
+module_init(zt5550_init);
+module_exit(zt5550_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+module_param(poll, bool, 0644);
+MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not");
diff --git a/drivers/pci/hotplug/cpcihp_zt5550.h b/drivers/pci/hotplug/cpcihp_zt5550.h
new file mode 100644
index 0000000..bebc606
--- /dev/null
+++ b/drivers/pci/hotplug/cpcihp_zt5550.h
@@ -0,0 +1,79 @@
+/*
+ * cpcihp_zt5550.h
+ *
+ * Intel/Ziatech ZT5550 CompactPCI Host Controller driver definitions
+ *
+ * Copyright 2002 SOMA Networks, Inc.
+ * Copyright 2001 Intel San Luis Obispo
+ * Copyright 2000,2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <scottm@somanetworks.com>
+ */
+
+#ifndef _CPCIHP_ZT5550_H
+#define _CPCIHP_ZT5550_H
+
+/* Direct registers */
+#define CSR_HCINDEX		0x00
+#define CSR_HCDATA		0x04
+#define CSR_INTSTAT		0x08
+#define CSR_INTMASK		0x09
+#define CSR_CNT0CMD		0x0C
+#define CSR_CNT1CMD		0x0E
+#define CSR_CNT0		0x10
+#define CSR_CNT1		0x14
+
+/* Masks for interrupt bits in CSR_INTMASK direct register */
+#define CNT0_INT_MASK		0x01
+#define CNT1_INT_MASK		0x02
+#define ENUM_INT_MASK		0x04
+#define ALL_DIRECT_INTS_MASK	0x07
+
+/* Indexed registers (through CSR_INDEX, CSR_DATA) */
+#define HC_INT_MASK_REG		0x04
+#define HC_STATUS_REG		0x08
+#define HC_CMD_REG		0x0C
+#define ARB_CONFIG_GNT_REG	0x10
+#define ARB_CONFIG_CFG_REG	0x12
+#define ARB_CONFIG_REG	 	0x10
+#define ISOL_CONFIG_REG		0x18
+#define FAULT_STATUS_REG	0x20
+#define FAULT_CONFIG_REG	0x24
+#define WD_CONFIG_REG		0x2C
+#define HC_DIAG_REG		0x30
+#define SERIAL_COMM_REG		0x34
+#define SERIAL_OUT_REG		0x38
+#define SERIAL_IN_REG		0x3C
+
+/* Masks for interrupt bits in HC_INT_MASK_REG indexed register */
+#define SERIAL_INT_MASK		0x01
+#define FAULT_INT_MASK		0x02
+#define HCF_INT_MASK		0x04
+#define ALL_INDEXED_INTS_MASK	0x07
+
+/* Digital I/O port storing ENUM# */
+#define ENUM_PORT	0xE1
+/* Mask to get to the ENUM# bit on the bus */
+#define ENUM_MASK	0x40
+
+#endif				/* _CPCIHP_ZT5550_H */
diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
new file mode 100644
index 0000000..092491e
--- /dev/null
+++ b/drivers/pci/hotplug/cpqphp.h
@@ -0,0 +1,721 @@
+/*
+ * Compaq Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+#ifndef _CPQPHP_H
+#define _CPQPHP_H
+
+#include "pci_hotplug.h"
+#include <linux/interrupt.h>
+#include <asm/io.h>		/* for read? and write? functions */
+#include <linux/delay.h>	/* for delays */
+
+#define MY_NAME	"cpqphp"
+
+#define dbg(fmt, arg...) do { if (cpqhp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
+
+
+
+struct smbios_system_slot {
+	u8 type;
+	u8 length;
+	u16 handle;
+	u8 name_string_num;
+	u8 slot_type;
+	u8 slot_width;
+	u8 slot_current_usage;
+	u8 slot_length;
+	u16 slot_number;
+	u8 properties1;
+	u8 properties2;
+} __attribute__ ((packed));
+
+/* offsets to the smbios generic type based on the above structure layout */
+enum smbios_system_slot_offsets {
+	SMBIOS_SLOT_GENERIC_TYPE =	offsetof(struct smbios_system_slot, type),
+	SMBIOS_SLOT_GENERIC_LENGTH =	offsetof(struct smbios_system_slot, length),
+	SMBIOS_SLOT_GENERIC_HANDLE =	offsetof(struct smbios_system_slot, handle),
+	SMBIOS_SLOT_NAME_STRING_NUM =	offsetof(struct smbios_system_slot, name_string_num),
+	SMBIOS_SLOT_TYPE =		offsetof(struct smbios_system_slot, slot_type),
+	SMBIOS_SLOT_WIDTH =		offsetof(struct smbios_system_slot, slot_width),
+	SMBIOS_SLOT_CURRENT_USAGE =	offsetof(struct smbios_system_slot, slot_current_usage),
+	SMBIOS_SLOT_LENGTH =		offsetof(struct smbios_system_slot, slot_length),
+	SMBIOS_SLOT_NUMBER =		offsetof(struct smbios_system_slot, slot_number),
+	SMBIOS_SLOT_PROPERTIES1 =	offsetof(struct smbios_system_slot, properties1),
+	SMBIOS_SLOT_PROPERTIES2 =	offsetof(struct smbios_system_slot, properties2),
+};
+
+struct smbios_generic {
+	u8 type;
+	u8 length;
+	u16 handle;
+} __attribute__ ((packed));
+
+/* offsets to the smbios generic type based on the above structure layout */
+enum smbios_generic_offsets {
+	SMBIOS_GENERIC_TYPE =	offsetof(struct smbios_generic, type),
+	SMBIOS_GENERIC_LENGTH =	offsetof(struct smbios_generic, length),
+	SMBIOS_GENERIC_HANDLE =	offsetof(struct smbios_generic, handle),
+};
+
+struct smbios_entry_point {
+	char anchor[4];
+	u8 ep_checksum;
+	u8 ep_length;
+	u8 major_version;
+	u8 minor_version;
+	u16 max_size_entry;
+	u8 ep_rev;
+	u8 reserved[5];
+	char int_anchor[5];
+	u8 int_checksum;
+	u16 st_length;
+	u32 st_address;
+	u16 number_of_entrys;
+	u8 bcd_rev;
+} __attribute__ ((packed));
+
+/* offsets to the smbios entry point based on the above structure layout */
+enum smbios_entry_point_offsets {
+	ANCHOR =		offsetof(struct smbios_entry_point, anchor[0]),
+	EP_CHECKSUM =		offsetof(struct smbios_entry_point, ep_checksum),
+	EP_LENGTH =		offsetof(struct smbios_entry_point, ep_length),
+	MAJOR_VERSION =		offsetof(struct smbios_entry_point, major_version),
+	MINOR_VERSION =		offsetof(struct smbios_entry_point, minor_version),
+	MAX_SIZE_ENTRY =	offsetof(struct smbios_entry_point, max_size_entry),
+	EP_REV =		offsetof(struct smbios_entry_point, ep_rev),
+	INT_ANCHOR =		offsetof(struct smbios_entry_point, int_anchor[0]),
+	INT_CHECKSUM =		offsetof(struct smbios_entry_point, int_checksum),
+	ST_LENGTH =		offsetof(struct smbios_entry_point, st_length),
+	ST_ADDRESS =		offsetof(struct smbios_entry_point, st_address),
+	NUMBER_OF_ENTRYS =	offsetof(struct smbios_entry_point, number_of_entrys),
+	BCD_REV =		offsetof(struct smbios_entry_point, bcd_rev),
+};
+
+struct ctrl_reg {			/* offset */
+	u8	slot_RST;		/* 0x00 */
+	u8	slot_enable;		/* 0x01 */
+	u16	misc;			/* 0x02 */
+	u32	led_control;		/* 0x04 */
+	u32	int_input_clear;	/* 0x08 */
+	u32	int_mask;		/* 0x0a */
+	u8	reserved0;		/* 0x10 */
+	u8	reserved1;		/* 0x11 */
+	u8	reserved2;		/* 0x12 */
+	u8	gen_output_AB;		/* 0x13 */
+	u32	non_int_input;		/* 0x14 */
+	u32	reserved3;		/* 0x18 */
+	u32	reserved4;		/* 0x1a */
+	u32	reserved5;		/* 0x20 */
+	u8	reserved6;		/* 0x24 */
+	u8	reserved7;		/* 0x25 */
+	u16	reserved8;		/* 0x26 */
+	u8	slot_mask;		/* 0x28 */
+	u8	reserved9;		/* 0x29 */
+	u8	reserved10;		/* 0x2a */
+	u8	reserved11;		/* 0x2b */
+	u8	slot_SERR;		/* 0x2c */
+	u8	slot_power;		/* 0x2d */
+	u8	reserved12;		/* 0x2e */
+	u8	reserved13;		/* 0x2f */
+	u8	next_curr_freq;		/* 0x30 */
+	u8	reset_freq_mode;	/* 0x31 */
+} __attribute__ ((packed));
+
+/* offsets to the controller registers based on the above structure layout */
+enum ctrl_offsets {
+	SLOT_RST = 		offsetof(struct ctrl_reg, slot_RST),
+	SLOT_ENABLE =		offsetof(struct ctrl_reg, slot_enable),
+	MISC =			offsetof(struct ctrl_reg, misc),
+	LED_CONTROL =		offsetof(struct ctrl_reg, led_control),
+	INT_INPUT_CLEAR =	offsetof(struct ctrl_reg, int_input_clear),
+	INT_MASK = 		offsetof(struct ctrl_reg, int_mask),
+	CTRL_RESERVED0 = 	offsetof(struct ctrl_reg, reserved0),
+	CTRL_RESERVED1 =	offsetof(struct ctrl_reg, reserved1),
+	CTRL_RESERVED2 =	offsetof(struct ctrl_reg, reserved1),
+	GEN_OUTPUT_AB = 	offsetof(struct ctrl_reg, gen_output_AB),
+	NON_INT_INPUT = 	offsetof(struct ctrl_reg, non_int_input),
+	CTRL_RESERVED3 =	offsetof(struct ctrl_reg, reserved3),
+	CTRL_RESERVED4 =	offsetof(struct ctrl_reg, reserved4),
+	CTRL_RESERVED5 =	offsetof(struct ctrl_reg, reserved5),
+	CTRL_RESERVED6 =	offsetof(struct ctrl_reg, reserved6),
+	CTRL_RESERVED7 =	offsetof(struct ctrl_reg, reserved7),
+	CTRL_RESERVED8 =	offsetof(struct ctrl_reg, reserved8),
+	SLOT_MASK = 		offsetof(struct ctrl_reg, slot_mask),
+	CTRL_RESERVED9 = 	offsetof(struct ctrl_reg, reserved9),
+	CTRL_RESERVED10 =	offsetof(struct ctrl_reg, reserved10),
+	CTRL_RESERVED11 =	offsetof(struct ctrl_reg, reserved11),
+	SLOT_SERR =		offsetof(struct ctrl_reg, slot_SERR),
+	SLOT_POWER =		offsetof(struct ctrl_reg, slot_power),
+	NEXT_CURR_FREQ =	offsetof(struct ctrl_reg, next_curr_freq),
+	RESET_FREQ_MODE =	offsetof(struct ctrl_reg, reset_freq_mode),
+};
+
+struct hrt {
+	char sig0;
+	char sig1;
+	char sig2;
+	char sig3;
+	u16 unused_IRQ;
+	u16 PCIIRQ;
+	u8 number_of_entries;
+	u8 revision;
+	u16 reserved1;
+	u32 reserved2;
+} __attribute__ ((packed));
+
+/* offsets to the hotplug resource table registers based on the above structure layout */
+enum hrt_offsets {
+	SIG0 =			offsetof(struct hrt, sig0),
+	SIG1 =			offsetof(struct hrt, sig1),
+	SIG2 =			offsetof(struct hrt, sig2),
+	SIG3 =			offsetof(struct hrt, sig3),
+	UNUSED_IRQ =		offsetof(struct hrt, unused_IRQ),
+	PCIIRQ =		offsetof(struct hrt, PCIIRQ),
+	NUMBER_OF_ENTRIES =	offsetof(struct hrt, number_of_entries),
+	REVISION =		offsetof(struct hrt, revision),
+	HRT_RESERVED1 =		offsetof(struct hrt, reserved1),
+	HRT_RESERVED2 =		offsetof(struct hrt, reserved2),
+};
+
+struct slot_rt {
+	u8 dev_func;
+	u8 primary_bus;
+	u8 secondary_bus;
+	u8 max_bus;
+	u16 io_base;
+	u16 io_length;
+	u16 mem_base;
+	u16 mem_length;
+	u16 pre_mem_base;
+	u16 pre_mem_length;
+} __attribute__ ((packed));
+
+/* offsets to the hotplug slot resource table registers based on the above structure layout */
+enum slot_rt_offsets {
+	DEV_FUNC =		offsetof(struct slot_rt, dev_func),
+	PRIMARY_BUS = 		offsetof(struct slot_rt, primary_bus),
+	SECONDARY_BUS = 	offsetof(struct slot_rt, secondary_bus),
+	MAX_BUS = 		offsetof(struct slot_rt, max_bus),
+	IO_BASE = 		offsetof(struct slot_rt, io_base),
+	IO_LENGTH = 		offsetof(struct slot_rt, io_length),
+	MEM_BASE = 		offsetof(struct slot_rt, mem_base),
+	MEM_LENGTH = 		offsetof(struct slot_rt, mem_length),
+	PRE_MEM_BASE = 		offsetof(struct slot_rt, pre_mem_base),
+	PRE_MEM_LENGTH = 	offsetof(struct slot_rt, pre_mem_length),
+};
+
+struct pci_func {
+	struct pci_func *next;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 is_a_board;
+	u16 status;
+	u8 configured;
+	u8 switch_save;
+	u8 presence_save;
+	u32 base_length[0x06];
+	u8 base_type[0x06];
+	u16 reserved2;
+	u32 config_space[0x20];
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct timer_list *p_task_event;
+	struct pci_dev* pci_dev;
+};
+
+struct slot {
+	struct slot *next;
+	u8 bus;
+	u8 device;
+	u8 number;
+	u8 is_a_board;
+	u8 configured;
+	u8 state;
+	u8 switch_save;
+	u8 presence_save;
+	u32 capabilities;
+	u16 reserved2;
+	struct timer_list task_event;
+	u8 hp_slot;
+	struct controller *ctrl;
+	void __iomem *p_sm_slot;
+	struct hotplug_slot *hotplug_slot;
+};
+
+struct pci_resource {
+	struct pci_resource * next;
+	u32 base;
+	u32 length;
+};
+
+struct event_info {
+	u32 event_type;
+	u8 hp_slot;
+};
+
+struct controller {
+	struct controller *next;
+	u32 ctrl_int_comp;
+	struct semaphore crit_sect;	/* critical section semaphore */
+	void __iomem *hpc_reg;		/* cookie for our pci controller location */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev *pci_dev;
+	struct pci_bus *pci_bus;
+	struct event_info event_queue[10];
+	struct slot *slot;
+	u8 next_event;
+	u8 interrupt;
+	u8 cfgspc_irq;
+	u8 bus;				/* bus number for the pci hotplug controller */
+	u8 rev;
+	u8 slot_device_offset;
+	u8 first_slot;
+	u8 add_support;
+	u8 push_flag;
+	enum pci_bus_speed speed;
+	enum pci_bus_speed speed_capability;
+	u8 push_button;			/* 0 = no pushbutton, 1 = pushbutton present */
+	u8 slot_switch_type;		/* 0 = no switch, 1 = switch present */
+	u8 defeature_PHP;		/* 0 = PHP not supported, 1 = PHP supported */
+	u8 alternate_base_address;	/* 0 = not supported, 1 = supported */
+	u8 pci_config_space;		/* Index/data access to working registers 0 = not supported, 1 = supported */
+	u8 pcix_speed_capability;	/* PCI-X */
+	u8 pcix_support;		/* PCI-X */
+	u16 vendor_id;
+	struct work_struct int_task_event;
+	wait_queue_head_t queue;	/* sleep & wake process */
+};
+
+struct irq_mapping {
+	u8 barber_pole;
+	u8 valid_INT;
+	u8 interrupt[4];
+};
+
+struct resource_lists {
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct irq_mapping *irqs;
+};
+
+#define ROM_PHY_ADDR			0x0F0000
+#define ROM_PHY_LEN			0x00ffff
+
+#define PCI_HPC_ID			0xA0F7
+#define PCI_SUB_HPC_ID			0xA2F7
+#define PCI_SUB_HPC_ID2			0xA2F8
+#define PCI_SUB_HPC_ID3			0xA2F9
+#define PCI_SUB_HPC_ID_INTC		0xA2FA
+#define PCI_SUB_HPC_ID4			0xA2FD
+
+#define INT_BUTTON_IGNORE		0
+#define INT_PRESENCE_ON			1
+#define INT_PRESENCE_OFF		2
+#define INT_SWITCH_CLOSE		3
+#define INT_SWITCH_OPEN			4
+#define INT_POWER_FAULT			5
+#define INT_POWER_FAULT_CLEAR		6
+#define INT_BUTTON_PRESS		7
+#define INT_BUTTON_RELEASE		8
+#define INT_BUTTON_CANCEL		9
+
+#define STATIC_STATE			0
+#define BLINKINGON_STATE		1
+#define BLINKINGOFF_STATE		2
+#define POWERON_STATE			3
+#define POWEROFF_STATE			4
+
+#define PCISLOT_INTERLOCK_CLOSED	0x00000001
+#define PCISLOT_ADAPTER_PRESENT		0x00000002
+#define PCISLOT_POWERED			0x00000004
+#define PCISLOT_66_MHZ_OPERATION	0x00000008
+#define PCISLOT_64_BIT_OPERATION	0x00000010
+#define PCISLOT_REPLACE_SUPPORTED	0x00000020
+#define PCISLOT_ADD_SUPPORTED		0x00000040
+#define PCISLOT_INTERLOCK_SUPPORTED	0x00000080
+#define PCISLOT_66_MHZ_SUPPORTED	0x00000100
+#define PCISLOT_64_BIT_SUPPORTED	0x00000200
+
+#define PCI_TO_PCI_BRIDGE_CLASS		0x00060400
+
+#define INTERLOCK_OPEN			0x00000002
+#define ADD_NOT_SUPPORTED		0x00000003
+#define CARD_FUNCTIONING		0x00000005
+#define ADAPTER_NOT_SAME		0x00000006
+#define NO_ADAPTER_PRESENT		0x00000009
+#define NOT_ENOUGH_RESOURCES		0x0000000B
+#define DEVICE_TYPE_NOT_SUPPORTED	0x0000000C
+#define POWER_FAILURE			0x0000000E
+
+#define REMOVE_NOT_SUPPORTED		0x00000003
+
+
+/*
+ * error Messages
+ */
+#define msg_initialization_err	"Initialization failure, error=%d\n"
+#define msg_HPC_rev_error	"Unsupported revision of the PCI hot plug controller found.\n"
+#define msg_HPC_non_compaq_or_intel	"The PCI hot plug controller is not supported by this driver.\n"
+#define msg_HPC_not_supported	"this system is not supported by this version of cpqphpd. Upgrade to a newer version of cpqphpd\n"
+#define msg_unable_to_save	"unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n"
+#define msg_button_on		"PCI slot #%d - powering on due to button press.\n"
+#define msg_button_off		"PCI slot #%d - powering off due to button press.\n"
+#define msg_button_cancel	"PCI slot #%d - action canceled due to button press.\n"
+#define msg_button_ignore	"PCI slot #%d - button press ignored.  (action in progress...)\n"
+
+
+/* sysfs functions for the hotplug controller info */
+extern void cpqhp_create_ctrl_files		(struct controller *ctrl);
+
+/* controller functions */
+extern void	cpqhp_pushbutton_thread		(unsigned long event_pointer);
+extern irqreturn_t cpqhp_ctrl_intr		(int IRQ, void *data, struct pt_regs *regs);
+extern int	cpqhp_find_available_resources	(struct controller *ctrl, void __iomem *rom_start);
+extern int	cpqhp_event_start_thread	(void);
+extern void	cpqhp_event_stop_thread		(void);
+extern struct pci_func *cpqhp_slot_create	(unsigned char busnumber);
+extern struct pci_func *cpqhp_slot_find		(unsigned char bus, unsigned char device, unsigned char index);
+extern int	cpqhp_process_SI		(struct controller *ctrl, struct pci_func *func);
+extern int	cpqhp_process_SS		(struct controller *ctrl, struct pci_func *func);
+extern int	cpqhp_hardware_test		(struct controller *ctrl, int test_num);
+
+/* resource functions */
+extern int	cpqhp_resource_sort_and_combine	(struct pci_resource **head);
+
+/* pci functions */
+extern int	cpqhp_set_irq			(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
+extern int	cpqhp_get_bus_dev		(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot);
+extern int	cpqhp_save_config		(struct controller *ctrl, int busnumber, int is_hot_plug);
+extern int	cpqhp_save_base_addr_length	(struct controller *ctrl, struct pci_func * func);
+extern int	cpqhp_save_used_resources	(struct controller *ctrl, struct pci_func * func);
+extern int	cpqhp_configure_board		(struct controller *ctrl, struct pci_func * func);
+extern int	cpqhp_save_slot_config		(struct controller *ctrl, struct pci_func * new_slot);
+extern int	cpqhp_valid_replace		(struct controller *ctrl, struct pci_func * func);
+extern void	cpqhp_destroy_board_resources	(struct pci_func * func);
+extern int	cpqhp_return_board_resources	(struct pci_func * func, struct resource_lists * resources);
+extern void	cpqhp_destroy_resource_list	(struct resource_lists * resources);
+extern int	cpqhp_configure_device		(struct controller* ctrl, struct pci_func* func);
+extern int	cpqhp_unconfigure_device	(struct pci_func* func);
+
+/* Global variables */
+extern int cpqhp_debug;
+extern int cpqhp_legacy_mode;
+extern struct controller *cpqhp_ctrl_list;
+extern struct pci_func *cpqhp_slot_list[256];
+
+/* these can be gotten rid of, but for debugging they are purty */
+extern u8 cpqhp_nic_irq;
+extern u8 cpqhp_disk_irq;
+
+
+/* inline functions */
+
+/*
+ * return_resource
+ *
+ * Puts node back in the resource list pointed to by head
+ *
+ */
+static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
+{
+	if (!node || !head)
+		return;
+	node->next = *head;
+	*head = node;
+}
+
+static inline void set_SOGO(struct controller *ctrl)
+{
+	u16 misc;
+	
+	misc = readw(ctrl->hpc_reg + MISC);
+	misc = (misc | 0x0001) & 0xFFFB;
+	writew(misc, ctrl->hpc_reg + MISC);
+}
+
+
+static inline void amber_LED_on(struct controller *ctrl, u8 slot)
+{
+	u32 led_control;
+	
+	led_control = readl(ctrl->hpc_reg + LED_CONTROL);
+	led_control |= (0x01010000L << slot);
+	writel(led_control, ctrl->hpc_reg + LED_CONTROL);
+}
+
+
+static inline void amber_LED_off(struct controller *ctrl, u8 slot)
+{
+	u32 led_control;
+	
+	led_control = readl(ctrl->hpc_reg + LED_CONTROL);
+	led_control &= ~(0x01010000L << slot);
+	writel(led_control, ctrl->hpc_reg + LED_CONTROL);
+}
+
+
+static inline int read_amber_LED(struct controller *ctrl, u8 slot)
+{
+	u32 led_control;
+
+	led_control = readl(ctrl->hpc_reg + LED_CONTROL);
+	led_control &= (0x01010000L << slot);
+	
+	return led_control ? 1 : 0;
+}
+
+
+static inline void green_LED_on(struct controller *ctrl, u8 slot)
+{
+	u32 led_control;
+	
+	led_control = readl(ctrl->hpc_reg + LED_CONTROL);
+	led_control |= 0x0101L << slot;
+	writel(led_control, ctrl->hpc_reg + LED_CONTROL);
+}
+
+static inline void green_LED_off(struct controller *ctrl, u8 slot)
+{
+	u32 led_control;
+	
+	led_control = readl(ctrl->hpc_reg + LED_CONTROL);
+	led_control &= ~(0x0101L << slot);
+	writel(led_control, ctrl->hpc_reg + LED_CONTROL);
+}
+
+
+static inline void green_LED_blink(struct controller *ctrl, u8 slot)
+{
+	u32 led_control;
+	
+	led_control = readl(ctrl->hpc_reg + LED_CONTROL);
+	led_control &= ~(0x0101L << slot);
+	led_control |= (0x0001L << slot);
+	writel(led_control, ctrl->hpc_reg + LED_CONTROL);
+}
+
+
+static inline void slot_disable(struct controller *ctrl, u8 slot)
+{
+	u8 slot_enable;
+
+	slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE);
+	slot_enable &= ~(0x01 << slot);
+	writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE);
+}
+
+
+static inline void slot_enable(struct controller *ctrl, u8 slot)
+{
+	u8 slot_enable;
+
+	slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE);
+	slot_enable |= (0x01 << slot);
+	writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE);
+}
+
+
+static inline u8 is_slot_enabled(struct controller *ctrl, u8 slot)
+{
+	u8 slot_enable;
+
+	slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE);
+	slot_enable &= (0x01 << slot);
+	return slot_enable ? 1 : 0;
+}
+
+
+static inline u8 read_slot_enable(struct controller *ctrl)
+{
+	return readb(ctrl->hpc_reg + SLOT_ENABLE);
+}
+
+
+/*
+ * get_controller_speed - find the current frequency/mode of controller.
+ *
+ * @ctrl: controller to get frequency/mode for.
+ *
+ * Returns controller speed.
+ *
+ */
+static inline u8 get_controller_speed(struct controller *ctrl)
+{
+	u8 curr_freq;
+ 	u16 misc;
+ 	
+	if (ctrl->pcix_support) {
+		curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ);
+		if ((curr_freq & 0xB0) == 0xB0) 
+			return PCI_SPEED_133MHz_PCIX;
+		if ((curr_freq & 0xA0) == 0xA0)
+			return PCI_SPEED_100MHz_PCIX;
+		if ((curr_freq & 0x90) == 0x90)
+			return PCI_SPEED_66MHz_PCIX;
+		if (curr_freq & 0x10)
+			return PCI_SPEED_66MHz;
+
+		return PCI_SPEED_33MHz;
+	}
+
+ 	misc = readw(ctrl->hpc_reg + MISC);
+ 	return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
+}
+ 
+
+/*
+ * get_adapter_speed - find the max supported frequency/mode of adapter.
+ *
+ * @ctrl: hotplug controller.
+ * @hp_slot: hotplug slot where adapter is installed.
+ *
+ * Returns adapter speed.
+ *
+ */
+static inline u8 get_adapter_speed(struct controller *ctrl, u8 hp_slot)
+{
+	u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT);
+	dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword);
+	if (ctrl->pcix_support) {
+		if (temp_dword & (0x10000 << hp_slot))
+			return PCI_SPEED_133MHz_PCIX;
+		if (temp_dword & (0x100 << hp_slot))
+			return PCI_SPEED_66MHz_PCIX;
+	}
+
+	if (temp_dword & (0x01 << hp_slot))
+		return PCI_SPEED_66MHz;
+
+	return PCI_SPEED_33MHz;
+}
+
+static inline void enable_slot_power(struct controller *ctrl, u8 slot)
+{
+	u8 slot_power;
+
+	slot_power = readb(ctrl->hpc_reg + SLOT_POWER);
+	slot_power |= (0x01 << slot);
+	writeb(slot_power, ctrl->hpc_reg + SLOT_POWER);
+}
+
+static inline void disable_slot_power(struct controller *ctrl, u8 slot)
+{
+	u8 slot_power;
+
+	slot_power = readb(ctrl->hpc_reg + SLOT_POWER);
+	slot_power &= ~(0x01 << slot);
+	writeb(slot_power, ctrl->hpc_reg + SLOT_POWER);
+}
+
+
+static inline int cpq_get_attention_status(struct controller *ctrl, struct slot *slot)
+{
+	u8 hp_slot;
+
+	hp_slot = slot->device - ctrl->slot_device_offset;
+
+	return read_amber_LED(ctrl, hp_slot);
+}
+
+
+static inline int get_slot_enabled(struct controller *ctrl, struct slot *slot)
+{
+	u8 hp_slot;
+
+	hp_slot = slot->device - ctrl->slot_device_offset;
+
+	return is_slot_enabled(ctrl, hp_slot);
+}
+
+
+static inline int cpq_get_latch_status(struct controller *ctrl, struct slot *slot)
+{
+	u32 status;
+	u8 hp_slot;
+
+	hp_slot = slot->device - ctrl->slot_device_offset;
+	dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n",
+	    __FUNCTION__, slot->device, ctrl->slot_device_offset);
+
+	status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot));
+
+	return(status == 0) ? 1 : 0;
+}
+
+
+static inline int get_presence_status(struct controller *ctrl, struct slot *slot)
+{
+	int presence_save = 0;
+	u8 hp_slot;
+	u32 tempdword;
+
+	hp_slot = slot->device - ctrl->slot_device_offset;
+
+	tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
+	presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02;
+
+	return presence_save;
+}
+
+#define SLOT_NAME_SIZE 10
+
+static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
+{
+	snprintf(buffer, buffer_size, "%d", slot->number);
+}
+
+
+static inline int wait_for_ctrl_irq(struct controller *ctrl)
+{
+        DECLARE_WAITQUEUE(wait, current);
+	int retval = 0;
+
+	dbg("%s - start\n", __FUNCTION__);
+	add_wait_queue(&ctrl->queue, &wait);
+	/* Sleep for up to 1 second to wait for the LED to change. */
+	msleep_interruptible(1000);
+	remove_wait_queue(&ctrl->queue, &wait);
+	if (signal_pending(current))
+		retval =  -EINTR;
+
+	dbg("%s - end\n", __FUNCTION__);
+	return retval;
+}
+
+#endif
+
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
new file mode 100644
index 0000000..afbccfa
--- /dev/null
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -0,0 +1,1509 @@
+/*
+ * Compaq Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ * Jan 12, 2003 -	Added 66/100/133MHz PCI-X support,
+ * 			Torben Mathiasen <torben.mathiasen@hp.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/uaccess.h>
+
+#include "cpqphp.h"
+#include "cpqphp_nvram.h"
+#include "../../../arch/i386/pci/pci.h"	/* horrible hack showing how processor dependent we are... */
+
+
+/* Global variables */
+int cpqhp_debug;
+int cpqhp_legacy_mode;
+struct controller *cpqhp_ctrl_list;	/* = NULL */
+struct pci_func *cpqhp_slot_list[256];
+
+/* local variables */
+static void __iomem *smbios_table;
+static void __iomem *smbios_start;
+static void __iomem *cpqhp_rom_start;
+static int power_mode;
+static int debug;
+
+#define DRIVER_VERSION	"0.9.8"
+#define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"
+#define DRIVER_DESC	"Compaq Hot Plug PCI Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(power_mode, bool, 0644);
+MODULE_PARM_DESC(power_mode, "Power mode enabled or not");
+
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
+#define CPQHPC_MODULE_MINOR 208
+
+static int one_time_init	(void);
+static int set_attention_status	(struct hotplug_slot *slot, u8 value);
+static int process_SI		(struct hotplug_slot *slot);
+static int process_SS		(struct hotplug_slot *slot);
+static int hardware_test	(struct hotplug_slot *slot, u32 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+
+static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {
+	.owner =		THIS_MODULE,
+	.set_attention_status =	set_attention_status,
+	.enable_slot =		process_SI,
+	.disable_slot =		process_SS,
+	.hardware_test =	hardware_test,
+	.get_power_status =	get_power_status,
+	.get_attention_status =	get_attention_status,
+	.get_latch_status =	get_latch_status,
+	.get_adapter_status =	get_adapter_status,
+  	.get_max_bus_speed =	get_max_bus_speed,
+  	.get_cur_bus_speed =	get_cur_bus_speed,
+};
+
+
+static inline int is_slot64bit(struct slot *slot)
+{
+	return (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) ? 1 : 0;
+}
+
+static inline int is_slot66mhz(struct slot *slot)
+{
+	return (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) ? 1 : 0;
+}
+
+/**
+ * detect_SMBIOS_pointer - find the System Management BIOS Table in mem region.
+ *
+ * @begin: begin pointer for region to be scanned.
+ * @end: end pointer for region to be scanned.
+ *
+ * Returns pointer to the head of the SMBIOS tables (or NULL)
+ *
+ */
+static void __iomem * detect_SMBIOS_pointer(void __iomem *begin, void __iomem *end)
+{
+	void __iomem *fp;
+	void __iomem *endp;
+	u8 temp1, temp2, temp3, temp4;
+	int status = 0;
+
+	endp = (end - sizeof(u32) + 1);
+
+	for (fp = begin; fp <= endp; fp += 16) {
+		temp1 = readb(fp);
+		temp2 = readb(fp+1);
+		temp3 = readb(fp+2);
+		temp4 = readb(fp+3);
+		if (temp1 == '_' &&
+		    temp2 == 'S' &&
+		    temp3 == 'M' &&
+		    temp4 == '_') {
+			status = 1;
+			break;
+		}
+	}
+	
+	if (!status)
+		fp = NULL;
+
+	dbg("Discovered SMBIOS Entry point at %p\n", fp);
+
+	return fp;
+}
+
+/**
+ * init_SERR - Initializes the per slot SERR generation.
+ *
+ * For unexpected switch opens
+ *
+ */
+static int init_SERR(struct controller * ctrl)
+{
+	u32 tempdword;
+	u32 number_of_slots;
+	u8 physical_slot;
+
+	if (!ctrl)
+		return 1;
+
+	tempdword = ctrl->first_slot;
+
+	number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F;
+	// Loop through slots
+	while (number_of_slots) {
+		physical_slot = tempdword;
+		writeb(0, ctrl->hpc_reg + SLOT_SERR);
+		tempdword++;
+		number_of_slots--;
+	}
+
+	return 0;
+}
+
+
+/* nice debugging output */
+static int pci_print_IRQ_route (void)
+{
+	struct irq_routing_table *routing_table;
+	int len;
+	int loop;
+
+	u8 tbus, tdevice, tslot;
+
+	routing_table = pcibios_get_irq_routing_table();
+	if (routing_table == NULL) {
+		err("No BIOS Routing Table??? Not good\n");
+		return -ENOMEM;
+	}
+
+	len = (routing_table->size - sizeof(struct irq_routing_table)) /
+			sizeof(struct irq_info);
+	// Make sure I got at least one entry
+	if (len == 0) {
+		kfree(routing_table);
+		return -1;
+	}
+
+	dbg("bus dev func slot\n");
+
+	for (loop = 0; loop < len; ++loop) {
+		tbus = routing_table->slots[loop].bus;
+		tdevice = routing_table->slots[loop].devfn;
+		tslot = routing_table->slots[loop].slot;
+		dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot);
+
+	}
+	kfree(routing_table);
+	return 0;
+}
+
+
+/**
+ * get_subsequent_smbios_entry: get the next entry from bios table.
+ *
+ * Gets the first entry if previous == NULL
+ * Otherwise, returns the next entry
+ * Uses global SMBIOS Table pointer
+ *
+ * @curr: %NULL or pointer to previously returned structure
+ *
+ * returns a pointer to an SMBIOS structure or NULL if none found
+ */
+static void __iomem *get_subsequent_smbios_entry(void __iomem *smbios_start,
+						void __iomem *smbios_table,
+						void __iomem *curr)
+{
+	u8 bail = 0;
+	u8 previous_byte = 1;
+	void __iomem *p_temp;
+	void __iomem *p_max;
+
+	if (!smbios_table || !curr)
+		return(NULL);
+
+	// set p_max to the end of the table
+	p_max = smbios_start + readw(smbios_table + ST_LENGTH);
+
+	p_temp = curr;
+	p_temp += readb(curr + SMBIOS_GENERIC_LENGTH);
+
+	while ((p_temp < p_max) && !bail) {
+		/* Look for the double NULL terminator
+		 * The first condition is the previous byte
+		 * and the second is the curr */
+		if (!previous_byte && !(readb(p_temp))) {
+			bail = 1;
+		}
+
+		previous_byte = readb(p_temp);
+		p_temp++;
+	}
+
+	if (p_temp < p_max) {
+		return p_temp;
+	} else {
+		return NULL;
+	}
+}
+
+
+/**
+ * get_SMBIOS_entry
+ *
+ * @type:SMBIOS structure type to be returned
+ * @previous: %NULL or pointer to previously returned structure
+ *
+ * Gets the first entry of the specified type if previous == NULL
+ * Otherwise, returns the next entry of the given type.
+ * Uses global SMBIOS Table pointer
+ * Uses get_subsequent_smbios_entry
+ *
+ * returns a pointer to an SMBIOS structure or %NULL if none found
+ */
+static void __iomem *get_SMBIOS_entry(void __iomem *smbios_start,
+					void __iomem *smbios_table,
+					u8 type,
+					void __iomem *previous)
+{
+	if (!smbios_table)
+		return NULL;
+
+	if (!previous) {		  
+		previous = smbios_start;
+	} else {
+		previous = get_subsequent_smbios_entry(smbios_start,
+					smbios_table, previous);
+	}
+
+	while (previous) {
+	       	if (readb(previous + SMBIOS_GENERIC_TYPE) != type) {
+			previous = get_subsequent_smbios_entry(smbios_start,
+						smbios_table, previous);
+		} else {
+			break;
+		}
+	}
+
+	return previous;
+}
+
+static void release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	kfree(slot);
+}
+
+static int ctrl_slot_setup(struct controller *ctrl,
+			void __iomem *smbios_start,
+			void __iomem *smbios_table)
+{
+	struct slot *new_slot;
+	u8 number_of_slots;
+	u8 slot_device;
+	u8 slot_number;
+	u8 ctrl_slot;
+	u32 tempdword;
+	void __iomem *slot_entry= NULL;
+	int result = -ENOMEM;
+
+	dbg("%s\n", __FUNCTION__);
+
+	tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
+
+	number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F;
+	slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4;
+	slot_number = ctrl->first_slot;
+
+	while (number_of_slots) {
+		new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
+		if (!new_slot)
+			goto error;
+
+		memset(new_slot, 0, sizeof(struct slot));
+		new_slot->hotplug_slot = kmalloc(sizeof(*(new_slot->hotplug_slot)),
+						GFP_KERNEL);
+		if (!new_slot->hotplug_slot)
+			goto error_slot;
+		memset(new_slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
+
+		new_slot->hotplug_slot->info =
+				kmalloc(sizeof(*(new_slot->hotplug_slot->info)),
+							GFP_KERNEL);
+		if (!new_slot->hotplug_slot->info)
+			goto error_hpslot;
+		memset(new_slot->hotplug_slot->info, 0,
+				sizeof(struct hotplug_slot_info));
+		new_slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!new_slot->hotplug_slot->name)
+			goto error_info;
+
+		new_slot->ctrl = ctrl;
+		new_slot->bus = ctrl->bus;
+		new_slot->device = slot_device;
+		new_slot->number = slot_number;
+		dbg("slot->number = %d\n",new_slot->number);
+
+		slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9,
+					slot_entry);
+
+		while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) {
+			slot_entry = get_SMBIOS_entry(smbios_start,
+						smbios_table, 9, slot_entry);
+		}
+
+		new_slot->p_sm_slot = slot_entry;
+
+		init_timer(&new_slot->task_event);
+		new_slot->task_event.expires = jiffies + 5 * HZ;
+		new_slot->task_event.function = cpqhp_pushbutton_thread;
+
+		//FIXME: these capabilities aren't used but if they are
+		//       they need to be correctly implemented
+		new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED;
+		new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED;
+
+		if (is_slot64bit(new_slot))
+			new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED;
+		if (is_slot66mhz(new_slot))
+			new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED;
+		if (ctrl->speed == PCI_SPEED_66MHz)
+			new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION;
+
+		ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4);
+
+		// Check presence
+		new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02;
+		// Check the switch state
+		new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01;
+		// Check the slot enable
+		new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04;
+
+		/* register this slot with the hotplug pci core */
+		new_slot->hotplug_slot->release = &release_slot;
+		new_slot->hotplug_slot->private = new_slot;
+		make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
+		new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops;
+		
+		new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot);
+		new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot);
+		new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot);
+		new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot);
+		
+		dbg ("registering bus %d, dev %d, number %d, "
+				"ctrl->slot_device_offset %d, slot %d\n",
+				new_slot->bus, new_slot->device,
+				new_slot->number, ctrl->slot_device_offset,
+				slot_number);
+		result = pci_hp_register (new_slot->hotplug_slot);
+		if (result) {
+			err ("pci_hp_register failed with error %d\n", result);
+			goto error_name;
+		}
+		
+		new_slot->next = ctrl->slot;
+		ctrl->slot = new_slot;
+
+		number_of_slots--;
+		slot_device++;
+		slot_number++;
+	}
+
+	return 0;
+
+error_name:
+	kfree(new_slot->hotplug_slot->name);
+error_info:
+	kfree(new_slot->hotplug_slot->info);
+error_hpslot:
+	kfree(new_slot->hotplug_slot);
+error_slot:
+	kfree(new_slot);
+error:
+	return result;
+}
+
+static int ctrl_slot_cleanup (struct controller * ctrl)
+{
+	struct slot *old_slot, *next_slot;
+
+	old_slot = ctrl->slot;
+	ctrl->slot = NULL;
+
+	while (old_slot) {
+		/* memory will be freed by the release_slot callback */
+		next_slot = old_slot->next;
+		pci_hp_deregister (old_slot->hotplug_slot);
+		old_slot = next_slot;
+	}
+
+	//Free IRQ associated with hot plug device
+	free_irq(ctrl->interrupt, ctrl);
+	//Unmap the memory
+	iounmap(ctrl->hpc_reg);
+	//Finally reclaim PCI mem
+	release_mem_region(pci_resource_start(ctrl->pci_dev, 0),
+			   pci_resource_len(ctrl->pci_dev, 0));
+
+	return(0);
+}
+
+
+//============================================================================
+// function:	get_slot_mapping
+//
+// Description: Attempts to determine a logical slot mapping for a PCI
+//		device.  Won't work for more than one PCI-PCI bridge
+//		in a slot.
+//
+// Input:	u8 bus_num - bus number of PCI device
+//		u8 dev_num - device number of PCI device
+//		u8 *slot - Pointer to u8 where slot number will
+//			be returned
+//
+// Output:	SUCCESS or FAILURE
+//=============================================================================
+static int
+get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot)
+{
+	struct irq_routing_table *PCIIRQRoutingInfoLength;
+	u32 work;
+	long len;
+	long loop;
+
+	u8 tbus, tdevice, tslot, bridgeSlot;
+
+	dbg("%s: %p, %d, %d, %p\n", __FUNCTION__, bus, bus_num, dev_num, slot);
+
+	bridgeSlot = 0xFF;
+
+	PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table();
+	if (!PCIIRQRoutingInfoLength)
+		return -1;
+
+	len = (PCIIRQRoutingInfoLength->size -
+	       sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
+	// Make sure I got at least one entry
+	if (len == 0) {
+		kfree(PCIIRQRoutingInfoLength);
+		return -1;
+	}
+
+	for (loop = 0; loop < len; ++loop) {
+		tbus = PCIIRQRoutingInfoLength->slots[loop].bus;
+		tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3;
+		tslot = PCIIRQRoutingInfoLength->slots[loop].slot;
+
+		if ((tbus == bus_num) && (tdevice == dev_num)) {
+			*slot = tslot;
+			kfree(PCIIRQRoutingInfoLength);
+			return 0;
+		} else {
+			/* Did not get a match on the target PCI device. Check
+			 * if the current IRQ table entry is a PCI-to-PCI bridge
+			 * device.  If so, and it's secondary bus matches the
+			 * bus number for the target device, I need to save the
+			 * bridge's slot number.  If I can not find an entry for
+			 * the target device, I will have to assume it's on the
+			 * other side of the bridge, and assign it the bridge's
+			 * slot. */
+			bus->number = tbus;
+			pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0),
+						PCI_REVISION_ID, &work);
+
+			if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
+				pci_bus_read_config_dword(bus,
+							PCI_DEVFN(tdevice, 0),
+							PCI_PRIMARY_BUS, &work);
+				// See if bridge's secondary bus matches target bus.
+				if (((work >> 8) & 0x000000FF) == (long) bus_num) {
+					bridgeSlot = tslot;
+				}
+			}
+		}
+
+	}
+
+	// If we got here, we didn't find an entry in the IRQ mapping table 
+	// for the target PCI device.  If we did determine that the target 
+	// device is on the other side of a PCI-to-PCI bridge, return the 
+	// slot number for the bridge.
+	if (bridgeSlot != 0xFF) {
+		*slot = bridgeSlot;
+		kfree(PCIIRQRoutingInfoLength);
+		return 0;
+	}
+	kfree(PCIIRQRoutingInfoLength);
+	// Couldn't find an entry in the routing table for this PCI device
+	return -1;
+}
+
+
+/**
+ * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off
+ *
+ */
+static int
+cpqhp_set_attention_status(struct controller *ctrl, struct pci_func *func,
+				u32 status)
+{
+	u8 hp_slot;
+
+	if (func == NULL)
+		return(1);
+
+	hp_slot = func->device - ctrl->slot_device_offset;
+
+	// Wait for exclusive access to hardware
+	down(&ctrl->crit_sect);
+
+	if (status == 1) {
+		amber_LED_on (ctrl, hp_slot);
+	} else if (status == 0) {
+		amber_LED_off (ctrl, hp_slot);
+	} else {
+		// Done with exclusive hardware access
+		up(&ctrl->crit_sect);
+		return(1);
+	}
+
+	set_SOGO(ctrl);
+
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
+
+	// Done with exclusive hardware access
+	up(&ctrl->crit_sect);
+
+	return(0);
+}
+
+
+/**
+ * set_attention_status - Turns the Amber LED for a slot on or off
+ *
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct pci_func *slot_func;
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+	u8 bus;
+	u8 devfn;
+	u8 device;
+	u8 function;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1)
+		return -ENODEV;
+
+	device = devfn >> 3;
+	function = devfn & 0x7;
+	dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function);
+
+	slot_func = cpqhp_slot_find(bus, device, function);
+	if (!slot_func)
+		return -ENODEV;
+
+	return cpqhp_set_attention_status(ctrl, slot_func, status);
+}
+
+
+static int process_SI(struct hotplug_slot *hotplug_slot)
+{
+	struct pci_func *slot_func;
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+	u8 bus;
+	u8 devfn;
+	u8 device;
+	u8 function;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1)
+		return -ENODEV;
+
+	device = devfn >> 3;
+	function = devfn & 0x7;
+	dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function);
+
+	slot_func = cpqhp_slot_find(bus, device, function);
+	if (!slot_func)
+		return -ENODEV;
+
+	slot_func->bus = bus;
+	slot_func->device = device;
+	slot_func->function = function;
+	slot_func->configured = 0;
+	dbg("board_added(%p, %p)\n", slot_func, ctrl);
+	return cpqhp_process_SI(ctrl, slot_func);
+}
+
+
+static int process_SS(struct hotplug_slot *hotplug_slot)
+{
+	struct pci_func *slot_func;
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+	u8 bus;
+	u8 devfn;
+	u8 device;
+	u8 function;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1)
+		return -ENODEV;
+
+	device = devfn >> 3;
+	function = devfn & 0x7;
+	dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function);
+
+	slot_func = cpqhp_slot_find(bus, device, function);
+	if (!slot_func)
+		return -ENODEV;
+
+	dbg("In %s, slot_func = %p, ctrl = %p\n", __FUNCTION__, slot_func, ctrl);
+	return cpqhp_process_SS(ctrl, slot_func);
+}
+
+
+static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value)
+{
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	return cpqhp_hardware_test(ctrl, value);	
+}
+
+
+static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = get_slot_enabled(ctrl, slot);
+	return 0;
+}
+
+static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = cpq_get_attention_status(ctrl, slot);
+	return 0;
+}
+
+static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = cpq_get_latch_status(ctrl, slot);
+
+	return 0;
+}
+
+static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = get_presence_status(ctrl, slot);
+
+	return 0;
+}
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = ctrl->speed_capability;
+
+	return 0;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	struct controller *ctrl = slot->ctrl;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = ctrl->speed;
+
+	return 0;
+}
+
+static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	u8 num_of_slots = 0;
+	u8 hp_slot = 0;
+	u8 device;
+	u8 rev;
+	u8 bus_cap;
+	u16 temp_word;
+	u16 vendor_id;
+	u16 subsystem_vid;
+	u16 subsystem_deviceid;
+	u32 rc;
+	struct controller *ctrl;
+	struct pci_func *func;
+
+	// Need to read VID early b/c it's used to differentiate CPQ and INTC discovery
+	rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id);
+	if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) {
+		err(msg_HPC_non_compaq_or_intel);
+		return -ENODEV;
+	}
+	dbg("Vendor ID: %x\n", vendor_id);
+
+	rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+	dbg("revision: %d\n", rev);
+	if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) {
+		err(msg_HPC_rev_error);
+		return -ENODEV;
+	}
+
+	/* Check for the proper subsytem ID's
+	 * Intel uses a different SSID programming model than Compaq.  
+	 * For Intel, each SSID bit identifies a PHP capability.
+	 * Also Intel HPC's may have RID=0.
+	 */
+	if ((rev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) {
+		// TODO: This code can be made to support non-Compaq or Intel subsystem IDs
+		rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid);
+		if (rc) {
+			err("%s : pci_read_config_word failed\n", __FUNCTION__);
+			return rc;
+		}
+		dbg("Subsystem Vendor ID: %x\n", subsystem_vid);
+		if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) {
+			err(msg_HPC_non_compaq_or_intel);
+			return -ENODEV;
+		}
+
+		ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
+		if (!ctrl) {
+			err("%s : out of memory\n", __FUNCTION__);
+			return -ENOMEM;
+		}
+		memset(ctrl, 0, sizeof(struct controller));
+
+		rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid);
+		if (rc) {
+			err("%s : pci_read_config_word failed\n", __FUNCTION__);
+			goto err_free_ctrl;
+		}
+
+		info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid);
+
+		/* Set Vendor ID, so it can be accessed later from other functions */
+		ctrl->vendor_id = vendor_id;
+
+		switch (subsystem_vid) {
+			case PCI_VENDOR_ID_COMPAQ:
+				if (rev >= 0x13) { /* CIOBX */
+					ctrl->push_flag = 1;
+					ctrl->slot_switch_type = 1;
+					ctrl->push_button = 1;
+					ctrl->pci_config_space = 1;
+					ctrl->defeature_PHP = 1;
+					ctrl->pcix_support = 1;
+					ctrl->pcix_speed_capability = 1;
+					pci_read_config_byte(pdev, 0x41, &bus_cap);
+					if (bus_cap & 0x80) {
+						dbg("bus max supports 133MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_133MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 0x40) {
+						dbg("bus max supports 100MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 20) {
+						dbg("bus max supports 66MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_66MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 10) {
+						dbg("bus max supports 66MHz PCI\n");
+						ctrl->speed_capability = PCI_SPEED_66MHz;
+						break;
+					}
+
+					break;
+				}
+
+				switch (subsystem_deviceid) {
+					case PCI_SUB_HPC_ID:
+						/* Original 6500/7000 implementation */
+						ctrl->slot_switch_type = 1;
+						ctrl->speed_capability = PCI_SPEED_33MHz;
+						ctrl->push_button = 0;
+						ctrl->pci_config_space = 1;
+						ctrl->defeature_PHP = 1;
+						ctrl->pcix_support = 0;
+						ctrl->pcix_speed_capability = 0;
+						break;
+					case PCI_SUB_HPC_ID2:
+						/* First Pushbutton implementation */
+						ctrl->push_flag = 1;
+						ctrl->slot_switch_type = 1;
+						ctrl->speed_capability = PCI_SPEED_33MHz;
+						ctrl->push_button = 1;
+						ctrl->pci_config_space = 1;
+						ctrl->defeature_PHP = 1;
+						ctrl->pcix_support = 0;
+						ctrl->pcix_speed_capability = 0;
+						break;
+					case PCI_SUB_HPC_ID_INTC:
+						/* Third party (6500/7000) */
+						ctrl->slot_switch_type = 1;
+						ctrl->speed_capability = PCI_SPEED_33MHz;
+						ctrl->push_button = 0;
+						ctrl->pci_config_space = 1;
+						ctrl->defeature_PHP = 1;
+						ctrl->pcix_support = 0;
+						ctrl->pcix_speed_capability = 0;
+						break;
+					case PCI_SUB_HPC_ID3:
+						/* First 66 Mhz implementation */
+						ctrl->push_flag = 1;
+						ctrl->slot_switch_type = 1;
+						ctrl->speed_capability = PCI_SPEED_66MHz;
+						ctrl->push_button = 1;
+						ctrl->pci_config_space = 1;
+						ctrl->defeature_PHP = 1;
+						ctrl->pcix_support = 0;
+						ctrl->pcix_speed_capability = 0;
+						break;
+					case PCI_SUB_HPC_ID4:
+						/* First PCI-X implementation, 100MHz */
+						ctrl->push_flag = 1;
+						ctrl->slot_switch_type = 1;
+						ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+						ctrl->push_button = 1;
+						ctrl->pci_config_space = 1;
+						ctrl->defeature_PHP = 1;
+						ctrl->pcix_support = 1;
+						ctrl->pcix_speed_capability = 0;	
+						break;
+					default:
+						err(msg_HPC_not_supported);
+						rc = -ENODEV;
+						goto err_free_ctrl;
+				}
+				break;
+
+			case PCI_VENDOR_ID_INTEL:
+				/* Check for speed capability (0=33, 1=66) */
+				if (subsystem_deviceid & 0x0001) {
+					ctrl->speed_capability = PCI_SPEED_66MHz;
+				} else {
+					ctrl->speed_capability = PCI_SPEED_33MHz;
+				}
+
+				/* Check for push button */
+				if (subsystem_deviceid & 0x0002) {
+					/* no push button */
+					ctrl->push_button = 0;
+				} else {
+					/* push button supported */
+					ctrl->push_button = 1;
+				}
+
+				/* Check for slot switch type (0=mechanical, 1=not mechanical) */
+				if (subsystem_deviceid & 0x0004) {
+					/* no switch */
+					ctrl->slot_switch_type = 0;
+				} else {
+					/* switch */
+					ctrl->slot_switch_type = 1;
+				}
+
+				/* PHP Status (0=De-feature PHP, 1=Normal operation) */
+				if (subsystem_deviceid & 0x0008) {
+					ctrl->defeature_PHP = 1;	// PHP supported
+				} else {
+					ctrl->defeature_PHP = 0;	// PHP not supported
+				}
+
+				/* Alternate Base Address Register Interface (0=not supported, 1=supported) */
+				if (subsystem_deviceid & 0x0010) {
+					ctrl->alternate_base_address = 1;	// supported
+				} else {
+					ctrl->alternate_base_address = 0;	// not supported
+				}
+
+				/* PCI Config Space Index (0=not supported, 1=supported) */
+				if (subsystem_deviceid & 0x0020) {
+					ctrl->pci_config_space = 1;		// supported
+				} else {
+					ctrl->pci_config_space = 0;		// not supported
+				}
+
+				/* PCI-X support */
+				if (subsystem_deviceid & 0x0080) {
+					/* PCI-X capable */
+					ctrl->pcix_support = 1;
+					/* Frequency of operation in PCI-X mode */
+					if (subsystem_deviceid & 0x0040) {
+						/* 133MHz PCI-X if bit 7 is 1 */
+						ctrl->pcix_speed_capability = 1;
+					} else {
+						/* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */
+						/* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */
+						ctrl->pcix_speed_capability = 0;
+					}
+				} else {
+					/* Conventional PCI */
+					ctrl->pcix_support = 0;
+					ctrl->pcix_speed_capability = 0;
+				}
+				break;
+
+			default:
+				err(msg_HPC_not_supported);
+				rc = -ENODEV;
+				goto err_free_ctrl;
+		}
+
+	} else {
+		err(msg_HPC_not_supported);
+		return -ENODEV;
+	}
+
+	// Tell the user that we found one.
+	info("Initializing the PCI hot plug controller residing on PCI bus %d\n",
+					pdev->bus->number);
+
+	dbg("Hotplug controller capabilities:\n");
+	dbg("    speed_capability       %d\n", ctrl->speed_capability);
+	dbg("    slot_switch_type       %s\n", ctrl->slot_switch_type ?
+					"switch present" : "no switch");
+	dbg("    defeature_PHP          %s\n", ctrl->defeature_PHP ?
+					"PHP supported" : "PHP not supported");
+	dbg("    alternate_base_address %s\n", ctrl->alternate_base_address ?
+					"supported" : "not supported");
+	dbg("    pci_config_space       %s\n", ctrl->pci_config_space ?
+					"supported" : "not supported");
+	dbg("    pcix_speed_capability  %s\n", ctrl->pcix_speed_capability ?
+					"supported" : "not supported");
+	dbg("    pcix_support           %s\n", ctrl->pcix_support ?
+					"supported" : "not supported");
+
+	ctrl->pci_dev = pdev;
+	pci_set_drvdata(pdev, ctrl);
+
+	/* make our own copy of the pci bus structure,
+	 * as we like tweaking it a lot */
+	ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
+	if (!ctrl->pci_bus) {
+		err("out of memory\n");
+		rc = -ENOMEM;
+		goto err_free_ctrl;
+	}
+	memcpy(ctrl->pci_bus, pdev->bus, sizeof(*ctrl->pci_bus));
+
+	ctrl->bus = pdev->bus->number;
+	ctrl->rev = rev;
+	dbg("bus device function rev: %d %d %d %d\n", ctrl->bus,
+		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), ctrl->rev);
+
+	init_MUTEX(&ctrl->crit_sect);
+	init_waitqueue_head(&ctrl->queue);
+
+	/* initialize our threads if they haven't already been started up */
+	rc = one_time_init();
+	if (rc) {
+		goto err_free_bus;
+	}
+	
+	dbg("pdev = %p\n", pdev);
+	dbg("pci resource start %lx\n", pci_resource_start(pdev, 0));
+	dbg("pci resource len %lx\n", pci_resource_len(pdev, 0));
+
+	if (!request_mem_region(pci_resource_start(pdev, 0),
+				pci_resource_len(pdev, 0), MY_NAME)) {
+		err("cannot reserve MMIO region\n");
+		rc = -ENOMEM;
+		goto err_free_bus;
+	}
+
+	ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0),
+					pci_resource_len(pdev, 0));
+	if (!ctrl->hpc_reg) {
+		err("cannot remap MMIO region %lx @ %lx\n",
+				pci_resource_len(pdev, 0),
+				pci_resource_start(pdev, 0));
+		rc = -ENODEV;
+		goto err_free_mem_region;
+	}
+
+	// Check for 66Mhz operation
+	ctrl->speed = get_controller_speed(ctrl);
+
+
+	/********************************************************
+	 *
+	 *              Save configuration headers for this and
+	 *              subordinate PCI buses
+	 *
+	 ********************************************************/
+
+	// find the physical slot number of the first hot plug slot
+
+	/* Get slot won't work for devices behind bridges, but
+	 * in this case it will always be called for the "base"
+	 * bus/dev/func of a slot.
+	 * CS: this is leveraging the PCIIRQ routing code from the kernel
+	 * (pci-pc.c: get_irq_routing_table) */
+	rc = get_slot_mapping(ctrl->pci_bus, pdev->bus->number,
+				(readb(ctrl->hpc_reg + SLOT_MASK) >> 4),
+				&(ctrl->first_slot));
+	dbg("get_slot_mapping: first_slot = %d, returned = %d\n",
+				ctrl->first_slot, rc);
+	if (rc) {
+		err(msg_initialization_err, rc);
+		goto err_iounmap;
+	}
+
+	// Store PCI Config Space for all devices on this bus
+	rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK));
+	if (rc) {
+		err("%s: unable to save PCI configuration data, error %d\n",
+				__FUNCTION__, rc);
+		goto err_iounmap;
+	}
+
+	/*
+	 * Get IO, memory, and IRQ resources for new devices
+	 */
+	// The next line is required for cpqhp_find_available_resources
+	ctrl->interrupt = pdev->irq;
+	if (ctrl->interrupt < 0x10) {
+		cpqhp_legacy_mode = 1;
+		dbg("System seems to be configured for Full Table Mapped MPS mode\n");
+	}
+
+	ctrl->cfgspc_irq = 0;
+	pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &ctrl->cfgspc_irq);
+
+	rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start);
+	ctrl->add_support = !rc;
+	if (rc) {
+		dbg("cpqhp_find_available_resources = 0x%x\n", rc);
+		err("unable to locate PCI configuration resources for hot plug add.\n");
+		goto err_iounmap;
+	}
+
+	/*
+	 * Finish setting up the hot plug ctrl device
+	 */
+	ctrl->slot_device_offset = readb(ctrl->hpc_reg + SLOT_MASK) >> 4;
+	dbg("NumSlots %d \n", ctrl->slot_device_offset);
+
+	ctrl->next_event = 0;
+
+	/* Setup the slot information structures */
+	rc = ctrl_slot_setup(ctrl, smbios_start, smbios_table);
+	if (rc) {
+		err(msg_initialization_err, 6);
+		err("%s: unable to save PCI configuration data, error %d\n",
+			__FUNCTION__, rc);
+		goto err_iounmap;
+	}
+	
+	/* Mask all general input interrupts */
+	writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK);
+
+	/* set up the interrupt */
+	dbg("HPC interrupt = %d \n", ctrl->interrupt);
+	if (request_irq(ctrl->interrupt, cpqhp_ctrl_intr,
+			SA_SHIRQ, MY_NAME, ctrl)) {
+		err("Can't get irq %d for the hotplug pci controller\n",
+			ctrl->interrupt);
+		rc = -ENODEV;
+		goto err_iounmap;
+	}
+
+	/* Enable Shift Out interrupt and clear it, also enable SERR on power fault */
+	temp_word = readw(ctrl->hpc_reg + MISC);
+	temp_word |= 0x4006;
+	writew(temp_word, ctrl->hpc_reg + MISC);
+
+	// Changed 05/05/97 to clear all interrupts at start
+	writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR);
+
+	ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
+
+	writel(0x0L, ctrl->hpc_reg + INT_MASK);
+
+	if (!cpqhp_ctrl_list) {
+		cpqhp_ctrl_list = ctrl;
+		ctrl->next = NULL;
+	} else {
+		ctrl->next = cpqhp_ctrl_list;
+		cpqhp_ctrl_list = ctrl;
+	}
+
+	// turn off empty slots here unless command line option "ON" set
+	// Wait for exclusive access to hardware
+	down(&ctrl->crit_sect);
+
+	num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F;
+
+	// find first device number for the ctrl
+	device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4;
+
+	while (num_of_slots) {
+		dbg("num_of_slots: %d\n", num_of_slots);
+		func = cpqhp_slot_find(ctrl->bus, device, 0);
+		if (!func)
+			break;
+
+		hp_slot = func->device - ctrl->slot_device_offset;
+		dbg("hp_slot: %d\n", hp_slot);
+
+		// We have to save the presence info for these slots
+		temp_word = ctrl->ctrl_int_comp >> 16;
+		func->presence_save = (temp_word >> hp_slot) & 0x01;
+		func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
+
+		if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) {
+			func->switch_save = 0;
+		} else {
+			func->switch_save = 0x10;
+		}
+
+		if (!power_mode) {
+			if (!func->is_a_board) {
+				green_LED_off(ctrl, hp_slot);
+				slot_disable(ctrl, hp_slot);
+			}
+		}
+
+		device++;
+		num_of_slots--;
+	}
+
+	if (!power_mode) {
+		set_SOGO(ctrl);
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq(ctrl);
+	}
+
+	rc = init_SERR(ctrl);
+	if (rc) {
+		err("init_SERR failed\n");
+		up(&ctrl->crit_sect);
+		goto err_free_irq;
+	}
+
+	// Done with exclusive hardware access
+	up(&ctrl->crit_sect);
+
+	cpqhp_create_ctrl_files(ctrl);
+
+	return 0;
+
+err_free_irq:
+	free_irq(ctrl->interrupt, ctrl);
+err_iounmap:
+	iounmap(ctrl->hpc_reg);
+err_free_mem_region:
+	release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+err_free_bus:
+	kfree(ctrl->pci_bus);
+err_free_ctrl:
+	kfree(ctrl);
+	return rc;
+}
+
+
+static int one_time_init(void)
+{
+	int loop;
+	int retval = 0;
+	static int initialized = 0;
+
+	if (initialized)
+		return 0;
+
+	power_mode = 0;
+
+	retval = pci_print_IRQ_route();
+	if (retval)
+		goto error;
+
+	dbg("Initialize + Start the notification mechanism \n");
+
+	retval = cpqhp_event_start_thread();
+	if (retval)
+		goto error;
+
+	dbg("Initialize slot lists\n");
+	for (loop = 0; loop < 256; loop++) {
+		cpqhp_slot_list[loop] = NULL;
+	}
+
+	// FIXME: We also need to hook the NMI handler eventually.
+	// this also needs to be worked with Christoph
+	// register_NMI_handler();
+
+	// Map rom address
+	cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN);
+	if (!cpqhp_rom_start) {
+		err ("Could not ioremap memory region for ROM\n");
+		retval = -EIO;
+		goto error;
+	}
+	
+	/* Now, map the int15 entry point if we are on compaq specific hardware */
+	compaq_nvram_init(cpqhp_rom_start);
+	
+	/* Map smbios table entry point structure */
+	smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start,
+					cpqhp_rom_start + ROM_PHY_LEN);
+	if (!smbios_table) {
+		err ("Could not find the SMBIOS pointer in memory\n");
+		retval = -EIO;
+		goto error_rom_start;
+	}
+
+	smbios_start = ioremap(readl(smbios_table + ST_ADDRESS),
+					readw(smbios_table + ST_LENGTH));
+	if (!smbios_start) {
+		err ("Could not ioremap memory region taken from SMBIOS values\n");
+		retval = -EIO;
+		goto error_smbios_start;
+	}
+
+	initialized = 1;
+
+	return retval;
+
+error_smbios_start:
+	iounmap(smbios_start);
+error_rom_start:
+	iounmap(cpqhp_rom_start);
+error:
+	return retval;
+}
+
+
+static void __exit unload_cpqphpd(void)
+{
+	struct pci_func *next;
+	struct pci_func *TempSlot;
+	int loop;
+	u32 rc;
+	struct controller *ctrl;
+	struct controller *tctrl;
+	struct pci_resource *res;
+	struct pci_resource *tres;
+
+	rc = compaq_nvram_store(cpqhp_rom_start);
+
+	ctrl = cpqhp_ctrl_list;
+
+	while (ctrl) {
+		if (ctrl->hpc_reg) {
+			u16 misc;
+			rc = read_slot_enable (ctrl);
+			
+			writeb(0, ctrl->hpc_reg + SLOT_SERR);
+			writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK);
+			
+			misc = readw(ctrl->hpc_reg + MISC);
+			misc &= 0xFFFD;
+			writew(misc, ctrl->hpc_reg + MISC);
+		}
+
+		ctrl_slot_cleanup(ctrl);
+
+		res = ctrl->io_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		res = ctrl->mem_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		res = ctrl->p_mem_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		res = ctrl->bus_head;
+		while (res) {
+			tres = res;
+			res = res->next;
+			kfree(tres);
+		}
+
+		kfree (ctrl->pci_bus);
+
+		tctrl = ctrl;
+		ctrl = ctrl->next;
+		kfree(tctrl);
+	}
+
+	for (loop = 0; loop < 256; loop++) {
+		next = cpqhp_slot_list[loop];
+		while (next != NULL) {
+			res = next->io_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			res = next->mem_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			res = next->p_mem_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			res = next->bus_head;
+			while (res) {
+				tres = res;
+				res = res->next;
+				kfree(tres);
+			}
+
+			TempSlot = next;
+			next = next->next;
+			kfree(TempSlot);
+		}
+	}
+
+	// Stop the notification mechanism
+	cpqhp_event_stop_thread();
+
+	//unmap the rom address
+	if (cpqhp_rom_start)
+		iounmap(cpqhp_rom_start);
+	if (smbios_start)
+		iounmap(smbios_start);
+}
+
+
+
+static struct pci_device_id hpcd_pci_tbl[] = {
+	{
+	/* handle any PCI Hotplug controller */
+	.class =        ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00),
+	.class_mask =   ~0,
+	
+	/* no matter who makes it */
+	.vendor =       PCI_ANY_ID,
+	.device =       PCI_ANY_ID,
+	.subvendor =    PCI_ANY_ID,
+	.subdevice =    PCI_ANY_ID,
+	
+	}, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl);
+
+
+
+static struct pci_driver cpqhpc_driver = {
+	.name =		"compaq_pci_hotplug",
+	.id_table =	hpcd_pci_tbl,
+	.probe =	cpqhpc_probe,
+	/* remove:	cpqhpc_remove_one, */
+};
+
+
+
+static int __init cpqhpc_init(void)
+{
+	int result;
+
+	cpqhp_debug = debug;
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+	result = pci_register_driver(&cpqhpc_driver);
+	dbg("pci_register_driver = %d\n", result);
+	return result;
+}
+
+
+static void __exit cpqhpc_cleanup(void)
+{
+	dbg("unload_cpqphpd()\n");
+	unload_cpqphpd();
+
+	dbg("pci_unregister_driver\n");
+	pci_unregister_driver(&cpqhpc_driver);
+}
+
+
+module_init(cpqhpc_init);
+module_exit(cpqhpc_cleanup);
+
+
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
new file mode 100644
index 0000000..10a5a76
--- /dev/null
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -0,0 +1,3096 @@
+/*
+ * Compaq Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include "cpqphp.h"
+
+static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,
+			u8 behind_bridge, struct resource_lists *resources);
+static int configure_new_function(struct controller* ctrl, struct pci_func *func,
+			u8 behind_bridge, struct resource_lists *resources);
+static void interrupt_event_handler(struct controller *ctrl);
+
+static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
+static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
+static int event_finished;
+static unsigned long pushbutton_pending;	/* = 0 */
+
+/* things needed for the long_delay function */
+static struct semaphore		delay_sem;
+static wait_queue_head_t	delay_wait;
+
+/* delay is in jiffies to wait for */
+static void long_delay(int delay)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	
+	/* only allow 1 customer into the delay queue at once
+	 * yes this makes some people wait even longer, but who really cares?
+	 * this is for _huge_ delays to make the hardware happy as the 
+	 * signals bounce around
+	 */
+	down (&delay_sem);
+
+	init_waitqueue_head(&delay_wait);
+
+	add_wait_queue(&delay_wait, &wait);
+	msleep_interruptible(jiffies_to_msecs(delay));
+	remove_wait_queue(&delay_wait, &wait);
+	
+	up(&delay_sem);
+}
+
+
+/* FIXME: The following line needs to be somewhere else... */
+#define WRONG_BUS_FREQUENCY 0x07
+static u8 handle_switch_change(u8 change, struct controller * ctrl)
+{
+	int hp_slot;
+	u8 rc = 0;
+	u16 temp_word;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	if (!change)
+		return 0;
+
+	/* Switch Change */
+	dbg("cpqsbd:  Switch interrupt received.\n");
+
+	for (hp_slot = 0; hp_slot < 6; hp_slot++) {
+		if (change & (0x1L << hp_slot)) {
+			/**********************************
+			 * this one changed.
+			 **********************************/
+			func = cpqhp_slot_find(ctrl->bus,
+				(hp_slot + ctrl->slot_device_offset), 0);
+
+			/* this is the structure that tells the worker thread
+			 *what to do */
+			taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+			ctrl->next_event = (ctrl->next_event + 1) % 10;
+			taskInfo->hp_slot = hp_slot;
+
+			rc++;
+
+			temp_word = ctrl->ctrl_int_comp >> 16;
+			func->presence_save = (temp_word >> hp_slot) & 0x01;
+			func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
+
+			if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) {
+				/**********************************
+				 * Switch opened
+				 **********************************/
+
+				func->switch_save = 0;
+
+				taskInfo->event_type = INT_SWITCH_OPEN;
+			} else {
+				/**********************************
+				 * Switch closed
+				 **********************************/
+
+				func->switch_save = 0x10;
+
+				taskInfo->event_type = INT_SWITCH_CLOSE;
+			}
+		}
+	}
+
+	return rc;
+}
+
+/**
+ * cpqhp_find_slot: find the struct slot of given device
+ * @ctrl: scan lots of this controller
+ * @device: the device id to find
+ */
+static struct slot *cpqhp_find_slot(struct controller *ctrl, u8 device)
+{
+	struct slot *slot = ctrl->slot;
+
+	while (slot && (slot->device != device)) {
+		slot = slot->next;
+	}
+
+	return slot;
+}
+
+
+static u8 handle_presence_change(u16 change, struct controller * ctrl)
+{
+	int hp_slot;
+	u8 rc = 0;
+	u8 temp_byte;
+	u16 temp_word;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+	struct slot *p_slot;
+
+	if (!change)
+		return 0;
+
+	/**********************************
+	 * Presence Change
+	 **********************************/
+	dbg("cpqsbd:  Presence/Notify input change.\n");
+	dbg("         Changed bits are 0x%4.4x\n", change );
+
+	for (hp_slot = 0; hp_slot < 6; hp_slot++) {
+		if (change & (0x0101 << hp_slot)) {
+			/**********************************
+			 * this one changed.
+			 **********************************/
+			func = cpqhp_slot_find(ctrl->bus,
+				(hp_slot + ctrl->slot_device_offset), 0);
+
+			taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+			ctrl->next_event = (ctrl->next_event + 1) % 10;
+			taskInfo->hp_slot = hp_slot;
+
+			rc++;
+
+			p_slot = cpqhp_find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4));
+			if (!p_slot)
+				return 0;
+
+			/* If the switch closed, must be a button
+			 * If not in button mode, nevermind */
+			if (func->switch_save && (ctrl->push_button == 1)) {
+				temp_word = ctrl->ctrl_int_comp >> 16;
+				temp_byte = (temp_word >> hp_slot) & 0x01;
+				temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02;
+
+				if (temp_byte != func->presence_save) {
+					/**************************************
+					 * button Pressed (doesn't do anything)
+					 **************************************/
+					dbg("hp_slot %d button pressed\n", hp_slot);
+					taskInfo->event_type = INT_BUTTON_PRESS;
+				} else {
+					/**********************************
+					 * button Released - TAKE ACTION!!!!
+					 **********************************/
+					dbg("hp_slot %d button released\n", hp_slot);
+					taskInfo->event_type = INT_BUTTON_RELEASE;
+
+					/* Cancel if we are still blinking */
+					if ((p_slot->state == BLINKINGON_STATE)
+					    || (p_slot->state == BLINKINGOFF_STATE)) {
+						taskInfo->event_type = INT_BUTTON_CANCEL;
+						dbg("hp_slot %d button cancel\n", hp_slot);
+					} else if ((p_slot->state == POWERON_STATE)
+						   || (p_slot->state == POWEROFF_STATE)) {
+						/* info(msg_button_ignore, p_slot->number); */
+						taskInfo->event_type = INT_BUTTON_IGNORE;
+						dbg("hp_slot %d button ignore\n", hp_slot);
+					}
+				}
+			} else {
+				/* Switch is open, assume a presence change
+				 * Save the presence state */
+				temp_word = ctrl->ctrl_int_comp >> 16;
+				func->presence_save = (temp_word >> hp_slot) & 0x01;
+				func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
+
+				if ((!(ctrl->ctrl_int_comp & (0x010000 << hp_slot))) ||
+				    (!(ctrl->ctrl_int_comp & (0x01000000 << hp_slot)))) {
+					/* Present */
+					taskInfo->event_type = INT_PRESENCE_ON;
+				} else {
+					/* Not Present */
+					taskInfo->event_type = INT_PRESENCE_OFF;
+				}
+			}
+		}
+	}
+
+	return rc;
+}
+
+
+static u8 handle_power_fault(u8 change, struct controller * ctrl)
+{
+	int hp_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	if (!change)
+		return 0;
+
+	/**********************************
+	 * power fault
+	 **********************************/
+
+	info("power fault interrupt\n");
+
+	for (hp_slot = 0; hp_slot < 6; hp_slot++) {
+		if (change & (0x01 << hp_slot)) {
+			/**********************************
+			 * this one changed.
+			 **********************************/
+			func = cpqhp_slot_find(ctrl->bus,
+				(hp_slot + ctrl->slot_device_offset), 0);
+
+			taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+			ctrl->next_event = (ctrl->next_event + 1) % 10;
+			taskInfo->hp_slot = hp_slot;
+
+			rc++;
+
+			if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) {
+				/**********************************
+				 * power fault Cleared
+				 **********************************/
+				func->status = 0x00;
+
+				taskInfo->event_type = INT_POWER_FAULT_CLEAR;
+			} else {
+				/**********************************
+				 * power fault
+				 **********************************/
+				taskInfo->event_type = INT_POWER_FAULT;
+
+				if (ctrl->rev < 4) {
+					amber_LED_on (ctrl, hp_slot);
+					green_LED_off (ctrl, hp_slot);
+					set_SOGO (ctrl);
+
+					/* this is a fatal condition, we want
+					 * to crash the machine to protect from
+					 * data corruption. simulated_NMI
+					 * shouldn't ever return */
+					/* FIXME
+					simulated_NMI(hp_slot, ctrl); */
+
+					/* The following code causes a software
+					 * crash just in case simulated_NMI did
+					 * return */
+					/*FIXME
+					panic(msg_power_fault); */
+				} else {
+					/* set power fault status for this board */
+					func->status = 0xFF;
+					info("power fault bit %x set\n", hp_slot);
+				}
+			}
+		}
+	}
+
+	return rc;
+}
+
+
+/**
+ * sort_by_size: sort nodes on the list by their length, smallest first.
+ * @head: list to sort
+ *
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length > (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length > current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+
+
+/**
+ * sort_by_max_size: sort nodes on the list by their length, largest first.
+ * @head: list to sort
+ *
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length < (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length < current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+
+
+/**
+ * do_pre_bridge_resource_split: find node of resources that are unused
+ *
+ */
+static struct pci_resource *do_pre_bridge_resource_split(struct pci_resource **head,
+				struct pci_resource **orig_head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 rc;
+	u32 temp_dword;
+	dbg("do_pre_bridge_resource_split\n");
+
+	if (!(*head) || !(*orig_head))
+		return NULL;
+
+	rc = cpqhp_resource_sort_and_combine(head);
+
+	if (rc)
+		return NULL;
+
+	if ((*head)->base != (*orig_head)->base)
+		return NULL;
+
+	if ((*head)->length == (*orig_head)->length)
+		return NULL;
+
+
+	/* If we got here, there the bridge requires some of the resource, but
+	 * we may be able to split some off of the front */
+
+	node = *head;
+
+	if (node->length & (alignment -1)) {
+		/* this one isn't an aligned length, so we'll make a new entry
+		 * and split it up. */
+		split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+		if (!split_node)
+			return NULL;
+
+		temp_dword = (node->length | (alignment-1)) + 1 - alignment;
+
+		split_node->base = node->base;
+		split_node->length = temp_dword;
+
+		node->length -= temp_dword;
+		node->base += split_node->length;
+
+		/* Put it in the list */
+		*head = split_node;
+		split_node->next = node;
+	}
+
+	if (node->length < alignment)
+		return NULL;
+
+	/* Now unlink it */
+	if (*head == node) {
+		*head = node->next;
+	} else {
+		prevnode = *head;
+		while (prevnode->next != node)
+			prevnode = prevnode->next;
+
+		prevnode->next = node->next;
+	}
+	node->next = NULL;
+
+	return node;
+}
+
+
+/**
+ * do_bridge_resource_split: find one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_bridge_resource_split(struct pci_resource **head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	u32 rc;
+	u32 temp_dword;
+
+	rc = cpqhp_resource_sort_and_combine(head);
+
+	if (rc)
+		return NULL;
+
+	node = *head;
+
+	while (node->next) {
+		prevnode = node;
+		node = node->next;
+		kfree(prevnode);
+	}
+
+	if (node->length < alignment)
+		goto error;
+
+	if (node->base & (alignment - 1)) {
+		/* Short circuit if adjusted size is too small */
+		temp_dword = (node->base | (alignment-1)) + 1;
+		if ((node->length - (temp_dword - node->base)) < alignment)
+			goto error;
+
+		node->length -= (temp_dword - node->base);
+		node->base = temp_dword;
+	}
+
+	if (node->length & (alignment - 1))
+		/* There's stuff in use after this node */
+		goto error;
+
+	return node;
+error:
+	kfree(node);
+	return NULL;
+}
+
+
+/**
+ * get_io_resource: find first node of given size not in ISA aliasing window.
+ * @head: list to search
+ * @size: size of node to find, must be a power of two.
+ *
+ * Description: this function sorts the resource list by size and then returns
+ * returns the first node of "size" length that is not in the ISA aliasing
+ * window.  If it finds a node larger than "size" it will split it up.
+ *
+ */
+static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+
+	if (!(*head))
+		return NULL;
+
+	if ( cpqhp_resource_sort_and_combine(head) )
+		return NULL;
+
+	if ( sort_by_size(head) )
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			 * so we'll make a new entry and split it up */
+			temp_dword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			/* this one is longer than we need
+			 * so we'll make a new entry and split it up */
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if (node->base & 0x300L)
+			continue;
+
+		/* If we got here, then it is the right size
+		 * Now take it out of the list and break */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		break;
+	}
+
+	return node;
+}
+
+
+/**
+ * get_max_resource: get largest node which has at least the given size.
+ * @head: the list to search the node in
+ * @size: the minimum size of the node to find
+ *
+ * Description: Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ */
+static struct pci_resource *get_max_resource(struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+
+	if (cpqhp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_max_size(head))
+		return NULL;
+
+	for (max = *head; max; max = max->next) {
+		/* If not big enough we could probably just bail, 
+		 * instead we'll continue to the next. */
+		if (max->length < size)
+			continue;
+
+		if (max->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			 * so we'll make a new entry and split it up */
+			temp_dword = (max->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max->length - (temp_dword - max->base)) < size)
+				continue;
+
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = max->base;
+			split_node->length = temp_dword - max->base;
+			max->base = temp_dword;
+			max->length -= split_node->length;
+
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		if ((max->base + max->length) & (size - 1)) {
+			/* this one isn't end aligned properly at the top
+			 * so we'll make a new entry and split it up */
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+			temp_dword = ((max->base + max->length) & ~(size - 1));
+			split_node->base = temp_dword;
+			split_node->length = max->length + max->base
+					     - split_node->base;
+			max->length -= split_node->length;
+
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max->length < size)
+			continue;
+
+		/* Now take it out of the list */
+		temp = *head;
+		if (temp == max) {
+			*head = max->next;
+		} else {
+			while (temp && temp->next != max) {
+				temp = temp->next;
+			}
+
+			temp->next = max->next;
+		}
+
+		max->next = NULL;
+		break;
+	}
+
+	return max;
+}
+
+
+/**
+ * get_resource: find resource of given size and split up larger ones.
+ * @head: the list to search for resources
+ * @size: the size limit to use
+ *
+ * Description: This function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_resource(struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+
+	if (cpqhp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_size(head))
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
+		    __FUNCTION__, size, node, node->base, node->length);
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			dbg("%s: not aligned\n", __FUNCTION__);
+			/* this one isn't base aligned properly
+			 * so we'll make a new entry and split it up */
+			temp_dword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			dbg("%s: too big\n", __FUNCTION__);
+			/* this one is longer than we need
+			 * so we'll make a new entry and split it up */
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		dbg("%s: got one!!!\n", __FUNCTION__);
+		/* If we got here, then it is the right size
+		 * Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		break;
+	}
+	return node;
+}
+
+
+/**
+ * cpqhp_resource_sort_and_combine: sort nodes by base addresses and clean up.
+ * @head: the list to sort and clean up
+ *
+ * Description: Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int cpqhp_resource_sort_and_combine(struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
+
+	if (!(*head))
+		return 1;
+
+	dbg("*head->next = %p\n",(*head)->next);
+
+	if (!(*head)->next)
+		return 0;	/* only one item on the list, already sorted! */
+
+	dbg("*head->base = 0x%x\n",(*head)->base);
+	dbg("*head->next->base = 0x%x\n",(*head)->next->base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->base > (*head)->next->base)) {
+			node1 = *head;
+			(*head) = (*head)->next;
+			node1->next = (*head)->next;
+			(*head)->next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1->next && node1->next->next) {
+			if (node1->next->base > node1->next->next->base) {
+				out_of_order++;
+				node2 = node1->next;
+				node1->next = node1->next->next;
+				node1 = node1->next;
+				node2->next = node1->next;
+				node1->next = node2;
+			} else
+				node1 = node1->next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 && node1->next) {
+		if ((node1->base + node1->length) == node1->next->base) {
+			/* Combine */
+			dbg("8..\n");
+			node1->length += node1->next->length;
+			node2 = node1->next;
+			node1->next = node1->next->next;
+			kfree(node2);
+		} else
+			node1 = node1->next;
+	}
+
+	return 0;
+}
+
+
+irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs)
+{
+	struct controller *ctrl = data;
+	u8 schedule_flag = 0;
+	u8 reset;
+	u16 misc;
+	u32 Diff;
+	u32 temp_dword;
+
+	
+	misc = readw(ctrl->hpc_reg + MISC);
+	/***************************************
+	 * Check to see if it was our interrupt
+	 ***************************************/
+	if (!(misc & 0x000C)) {
+		return IRQ_NONE;
+	}
+
+	if (misc & 0x0004) {
+		/**********************************
+		 * Serial Output interrupt Pending
+		 **********************************/
+
+		/* Clear the interrupt */
+		misc |= 0x0004;
+		writew(misc, ctrl->hpc_reg + MISC);
+
+		/* Read to clear posted writes */
+		misc = readw(ctrl->hpc_reg + MISC);
+
+		dbg ("%s - waking up\n", __FUNCTION__);
+		wake_up_interruptible(&ctrl->queue);
+	}
+
+	if (misc & 0x0008) {
+		/* General-interrupt-input interrupt Pending */
+		Diff = readl(ctrl->hpc_reg + INT_INPUT_CLEAR) ^ ctrl->ctrl_int_comp;
+
+		ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
+
+		/* Clear the interrupt */
+		writel(Diff, ctrl->hpc_reg + INT_INPUT_CLEAR);
+
+		/* Read it back to clear any posted writes */
+		temp_dword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
+
+		if (!Diff)
+			/* Clear all interrupts */
+			writel(0xFFFFFFFF, ctrl->hpc_reg + INT_INPUT_CLEAR);
+
+		schedule_flag += handle_switch_change((u8)(Diff & 0xFFL), ctrl);
+		schedule_flag += handle_presence_change((u16)((Diff & 0xFFFF0000L) >> 16), ctrl);
+		schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl);
+	}
+
+	reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE);
+	if (reset & 0x40) {
+		/* Bus reset has completed */
+		reset &= 0xCF;
+		writeb(reset, ctrl->hpc_reg + RESET_FREQ_MODE);
+		reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE);
+		wake_up_interruptible(&ctrl->queue);
+	}
+
+	if (schedule_flag) {
+		up(&event_semaphore);
+		dbg("Signal event_semaphore\n");
+	}
+	return IRQ_HANDLED;
+}
+
+
+/**
+ * cpqhp_slot_create - Creates a node and adds it to the proper bus.
+ * @busnumber - bus where new node is to be located
+ *
+ * Returns pointer to the new node or NULL if unsuccessful
+ */
+struct pci_func *cpqhp_slot_create(u8 busnumber)
+{
+	struct pci_func *new_slot;
+	struct pci_func *next;
+
+	new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
+
+	if (new_slot == NULL) {
+		/* I'm not dead yet!
+		 * You will be. */
+		return new_slot;
+	}
+
+	memset(new_slot, 0, sizeof(struct pci_func));
+
+	new_slot->next = NULL;
+	new_slot->configured = 1;
+
+	if (cpqhp_slot_list[busnumber] == NULL) {
+		cpqhp_slot_list[busnumber] = new_slot;
+	} else {
+		next = cpqhp_slot_list[busnumber];
+		while (next->next != NULL)
+			next = next->next;
+		next->next = new_slot;
+	}
+	return new_slot;
+}
+
+
+/**
+ * slot_remove - Removes a node from the linked list of slots.
+ * @old_slot: slot to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int slot_remove(struct pci_func * old_slot)
+{
+	struct pci_func *next;
+
+	if (old_slot == NULL)
+		return 1;
+
+	next = cpqhp_slot_list[old_slot->bus];
+
+	if (next == NULL) {
+		return 1;
+	}
+
+	if (next == old_slot) {
+		cpqhp_slot_list[old_slot->bus] = old_slot->next;
+		cpqhp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return 0;
+	}
+
+	while ((next->next != old_slot) && (next->next != NULL)) {
+		next = next->next;
+	}
+
+	if (next->next == old_slot) {
+		next->next = old_slot->next;
+		cpqhp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return 0;
+	} else
+		return 2;
+}
+
+
+/**
+ * bridge_slot_remove - Removes a node from the linked list of slots.
+ * @bridge: bridge to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int bridge_slot_remove(struct pci_func *bridge)
+{
+	u8 subordinateBus, secondaryBus;
+	u8 tempBus;
+	struct pci_func *next;
+
+	secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
+	subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
+
+	for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
+		next = cpqhp_slot_list[tempBus];
+
+		while (!slot_remove(next)) {
+			next = cpqhp_slot_list[tempBus];
+		}
+	}
+
+	next = cpqhp_slot_list[bridge->bus];
+
+	if (next == NULL)
+		return 1;
+
+	if (next == bridge) {
+		cpqhp_slot_list[bridge->bus] = bridge->next;
+		goto out;
+	}
+
+	while ((next->next != bridge) && (next->next != NULL))
+		next = next->next;
+
+	if (next->next != bridge)
+		return 2;
+	next->next = bridge->next;
+out:
+	kfree(bridge);
+	return 0;
+}
+
+
+/**
+ * cpqhp_slot_find - Looks for a node by bus, and device, multiple functions accessed
+ * @bus: bus to find
+ * @device: device to find
+ * @index: is 0 for first function found, 1 for the second...
+ *
+ * Returns pointer to the node if successful, %NULL otherwise.
+ */
+struct pci_func *cpqhp_slot_find(u8 bus, u8 device, u8 index)
+{
+	int found = -1;
+	struct pci_func *func;
+
+	func = cpqhp_slot_list[bus];
+
+	if ((func == NULL) || ((func->device == device) && (index == 0)))
+		return func;
+
+	if (func->device == device)
+		found++;
+
+	while (func->next != NULL) {
+		func = func->next;
+
+		if (func->device == device)
+			found++;
+
+		if (found == index)
+			return func;
+	}
+
+	return NULL;
+}
+
+
+/* DJZ: I don't think is_bridge will work as is.
+ * FIXME */
+static int is_bridge(struct pci_func * func)
+{
+	/* Check the header type */
+	if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01)
+		return 1;
+	else
+		return 0;
+}
+
+
+/**
+ * set_controller_speed - set the frequency and/or mode of a specific
+ * controller segment.
+ *
+ * @ctrl: controller to change frequency/mode for.
+ * @adapter_speed: the speed of the adapter we want to match.
+ * @hp_slot: the slot number where the adapter is installed.
+ *
+ * Returns 0 if we successfully change frequency and/or mode to match the
+ * adapter speed.
+ * 
+ */
+static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot)
+{
+	struct slot *slot;
+	u8 reg;
+	u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER);
+	u16 reg16;
+	u32 leds = readl(ctrl->hpc_reg + LED_CONTROL);
+	
+	if (ctrl->speed == adapter_speed)
+		return 0;
+	
+	/* We don't allow freq/mode changes if we find another adapter running
+	 * in another slot on this controller */
+	for(slot = ctrl->slot; slot; slot = slot->next) {
+		if (slot->device == (hp_slot + ctrl->slot_device_offset)) 
+			continue;
+		if (!slot->hotplug_slot && !slot->hotplug_slot->info) 
+			continue;
+		if (slot->hotplug_slot->info->adapter_status == 0) 
+			continue;
+		/* If another adapter is running on the same segment but at a
+		 * lower speed/mode, we allow the new adapter to function at
+		 * this rate if supported */
+		if (ctrl->speed < adapter_speed) 
+			return 0;
+
+		return 1;
+	}
+	
+	/* If the controller doesn't support freq/mode changes and the
+	 * controller is running at a higher mode, we bail */
+	if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability))
+		return 1;
+	
+	/* But we allow the adapter to run at a lower rate if possible */
+	if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability))
+		return 0;
+
+	/* We try to set the max speed supported by both the adapter and
+	 * controller */
+	if (ctrl->speed_capability < adapter_speed) {
+		if (ctrl->speed == ctrl->speed_capability)
+			return 0;
+		adapter_speed = ctrl->speed_capability;
+	}
+
+	writel(0x0L, ctrl->hpc_reg + LED_CONTROL);
+	writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE);
+	
+	set_SOGO(ctrl); 
+	wait_for_ctrl_irq(ctrl);
+	
+	if (adapter_speed != PCI_SPEED_133MHz_PCIX)
+		reg = 0xF5;
+	else
+		reg = 0xF4;	
+	pci_write_config_byte(ctrl->pci_dev, 0x41, reg);
+	
+	reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ);
+	reg16 &= ~0x000F;
+	switch(adapter_speed) {
+		case(PCI_SPEED_133MHz_PCIX): 
+			reg = 0x75;
+			reg16 |= 0xB; 
+			break;
+		case(PCI_SPEED_100MHz_PCIX):
+			reg = 0x74;
+			reg16 |= 0xA;
+			break;
+		case(PCI_SPEED_66MHz_PCIX):
+			reg = 0x73;
+			reg16 |= 0x9;
+			break;
+		case(PCI_SPEED_66MHz):
+			reg = 0x73;
+			reg16 |= 0x1;
+			break;
+		default: /* 33MHz PCI 2.2 */
+			reg = 0x71;
+			break;
+			
+	}
+	reg16 |= 0xB << 12;
+	writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ);
+	
+	mdelay(5); 
+	
+	/* Reenable interrupts */
+	writel(0, ctrl->hpc_reg + INT_MASK);
+
+	pci_write_config_byte(ctrl->pci_dev, 0x41, reg); 
+	
+	/* Restart state machine */
+	reg = ~0xF;
+	pci_read_config_byte(ctrl->pci_dev, 0x43, &reg);
+	pci_write_config_byte(ctrl->pci_dev, 0x43, reg);
+	
+	/* Only if mode change...*/
+	if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) ||
+		((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) 
+			set_SOGO(ctrl);
+	
+	wait_for_ctrl_irq(ctrl);
+	mdelay(1100);
+	
+	/* Restore LED/Slot state */
+	writel(leds, ctrl->hpc_reg + LED_CONTROL);
+	writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE);
+	
+	set_SOGO(ctrl);
+	wait_for_ctrl_irq(ctrl);
+
+	ctrl->speed = adapter_speed;
+	slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	info("Successfully changed frequency/mode for adapter in slot %d\n", 
+			slot->number);
+	return 0;
+}
+
+/* the following routines constitute the bulk of the 
+   hotplug controller logic
+ */
+
+
+/**
+ * board_replaced - Called after a board has been replaced in the system.
+ *
+ * This is only used if we don't have resources for hot add
+ * Turns power on for the board
+ * Checks to see if board is the same
+ * If board is same, reconfigures it
+ * If board isn't same, turns it back off.
+ *
+ */
+static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
+{
+	u8 hp_slot;
+	u8 temp_byte;
+	u8 adapter_speed;
+	u32 index;
+	u32 rc = 0;
+	u32 src = 8;
+
+	hp_slot = func->device - ctrl->slot_device_offset;
+
+	if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) {
+		/**********************************
+		 * The switch is open.
+		 **********************************/
+		rc = INTERLOCK_OPEN;
+	} else if (is_slot_enabled (ctrl, hp_slot)) {
+		/**********************************
+		 * The board is already on
+		 **********************************/
+		rc = CARD_FUNCTIONING;
+	} else {
+		down(&ctrl->crit_sect);
+
+		/* turn on board without attaching to the bus */
+		enable_slot_power (ctrl, hp_slot);
+
+		set_SOGO(ctrl);
+
+		/* Wait for SOBS to be unset */
+		wait_for_ctrl_irq (ctrl);
+
+		/* Change bits in slot power register to force another shift out
+		 * NOTE: this is to work around the timer bug */
+		temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
+		writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
+		writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
+
+		set_SOGO(ctrl);
+
+		/* Wait for SOBS to be unset */
+		wait_for_ctrl_irq (ctrl);
+		
+		adapter_speed = get_adapter_speed(ctrl, hp_slot);
+		if (ctrl->speed != adapter_speed)
+			if (set_controller_speed(ctrl, adapter_speed, hp_slot))
+				rc = WRONG_BUS_FREQUENCY;
+
+		/* turn off board without attaching to the bus */
+		disable_slot_power (ctrl, hp_slot);
+
+		set_SOGO(ctrl);
+
+		/* Wait for SOBS to be unset */
+		wait_for_ctrl_irq (ctrl);
+
+		up(&ctrl->crit_sect);
+
+		if (rc)
+			return rc;
+
+		down(&ctrl->crit_sect);
+
+		slot_enable (ctrl, hp_slot);
+		green_LED_blink (ctrl, hp_slot);
+
+		amber_LED_off (ctrl, hp_slot);
+
+		set_SOGO(ctrl);
+
+		/* Wait for SOBS to be unset */
+		wait_for_ctrl_irq (ctrl);
+
+		up(&ctrl->crit_sect);
+
+		/* Wait for ~1 second because of hot plug spec */
+		long_delay(1*HZ);
+
+		/* Check for a power fault */
+		if (func->status == 0xFF) {
+			/* power fault occurred, but it was benign */
+			rc = POWER_FAILURE;
+			func->status = 0;
+		} else
+			rc = cpqhp_valid_replace(ctrl, func);
+
+		if (!rc) {
+			/* It must be the same board */
+
+			rc = cpqhp_configure_board(ctrl, func);
+
+			if (rc || src) {
+				/* If configuration fails, turn it off
+				 * Get slot won't work for devices behind
+				 * bridges, but in this case it will always be
+				 * called for the "base" bus/dev/func of an
+				 * adapter. */
+
+				down(&ctrl->crit_sect);
+
+				amber_LED_on (ctrl, hp_slot);
+				green_LED_off (ctrl, hp_slot);
+				slot_disable (ctrl, hp_slot);
+
+				set_SOGO(ctrl);
+
+				/* Wait for SOBS to be unset */
+				wait_for_ctrl_irq (ctrl);
+
+				up(&ctrl->crit_sect);
+
+				if (rc)
+					return rc;
+				else
+					return 1;
+			}
+
+			func->status = 0;
+			func->switch_save = 0x10;
+
+			index = 1;
+			while (((func = cpqhp_slot_find(func->bus, func->device, index)) != NULL) && !rc) {
+				rc |= cpqhp_configure_board(ctrl, func);
+				index++;
+			}
+
+			if (rc) {
+				/* If configuration fails, turn it off
+				 * Get slot won't work for devices behind
+				 * bridges, but in this case it will always be
+				 * called for the "base" bus/dev/func of an
+				 * adapter. */
+
+				down(&ctrl->crit_sect);
+
+				amber_LED_on (ctrl, hp_slot);
+				green_LED_off (ctrl, hp_slot);
+				slot_disable (ctrl, hp_slot);
+
+				set_SOGO(ctrl);
+
+				/* Wait for SOBS to be unset */
+				wait_for_ctrl_irq (ctrl);
+
+				up(&ctrl->crit_sect);
+
+				return rc;
+			}
+			/* Done configuring so turn LED on full time */
+
+			down(&ctrl->crit_sect);
+
+			green_LED_on (ctrl, hp_slot);
+
+			set_SOGO(ctrl);
+
+			/* Wait for SOBS to be unset */
+			wait_for_ctrl_irq (ctrl);
+
+			up(&ctrl->crit_sect);
+			rc = 0;
+		} else {
+			/* Something is wrong
+
+			 * Get slot won't work for devices behind bridges, but
+			 * in this case it will always be called for the "base"
+			 * bus/dev/func of an adapter. */
+
+			down(&ctrl->crit_sect);
+
+			amber_LED_on (ctrl, hp_slot);
+			green_LED_off (ctrl, hp_slot);
+			slot_disable (ctrl, hp_slot);
+
+			set_SOGO(ctrl);
+
+			/* Wait for SOBS to be unset */
+			wait_for_ctrl_irq (ctrl);
+
+			up(&ctrl->crit_sect);
+		}
+
+	}
+	return rc;
+
+}
+
+
+/**
+ * board_added - Called after a board has been added to the system.
+ *
+ * Turns power on for the board
+ * Configures board
+ *
+ */
+static u32 board_added(struct pci_func *func, struct controller *ctrl)
+{
+	u8 hp_slot;
+	u8 temp_byte;
+	u8 adapter_speed;
+	int index;
+	u32 temp_register = 0xFFFFFFFF;
+	u32 rc = 0;
+	struct pci_func *new_slot = NULL;
+	struct slot *p_slot;
+	struct resource_lists res_lists;
+
+	hp_slot = func->device - ctrl->slot_device_offset;
+	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n",
+	    __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
+
+	down(&ctrl->crit_sect);
+
+	/* turn on board without attaching to the bus */
+	enable_slot_power(ctrl, hp_slot);
+
+	set_SOGO(ctrl);
+
+	/* Wait for SOBS to be unset */
+	wait_for_ctrl_irq (ctrl);
+
+	/* Change bits in slot power register to force another shift out
+	 * NOTE: this is to work around the timer bug */
+	temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
+	writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
+	writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
+
+	set_SOGO(ctrl);
+
+	/* Wait for SOBS to be unset */
+	wait_for_ctrl_irq (ctrl);
+	
+	adapter_speed = get_adapter_speed(ctrl, hp_slot);
+	if (ctrl->speed != adapter_speed)
+		if (set_controller_speed(ctrl, adapter_speed, hp_slot))
+			rc = WRONG_BUS_FREQUENCY;
+	
+	/* turn off board without attaching to the bus */
+	disable_slot_power (ctrl, hp_slot);
+
+	set_SOGO(ctrl);
+
+	/* Wait for SOBS to be unset */
+	wait_for_ctrl_irq(ctrl);
+
+	up(&ctrl->crit_sect);
+
+	if (rc)
+		return rc;
+	
+	p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	/* turn on board and blink green LED */
+
+	dbg("%s: before down\n", __FUNCTION__);
+	down(&ctrl->crit_sect);
+	dbg("%s: after down\n", __FUNCTION__);
+
+	dbg("%s: before slot_enable\n", __FUNCTION__);
+	slot_enable (ctrl, hp_slot);
+
+	dbg("%s: before green_LED_blink\n", __FUNCTION__);
+	green_LED_blink (ctrl, hp_slot);
+
+	dbg("%s: before amber_LED_blink\n", __FUNCTION__);
+	amber_LED_off (ctrl, hp_slot);
+
+	dbg("%s: before set_SOGO\n", __FUNCTION__);
+	set_SOGO(ctrl);
+
+	/* Wait for SOBS to be unset */
+	dbg("%s: before wait_for_ctrl_irq\n", __FUNCTION__);
+	wait_for_ctrl_irq (ctrl);
+	dbg("%s: after wait_for_ctrl_irq\n", __FUNCTION__);
+
+	dbg("%s: before up\n", __FUNCTION__);
+	up(&ctrl->crit_sect);
+	dbg("%s: after up\n", __FUNCTION__);
+
+	/* Wait for ~1 second because of hot plug spec */
+	dbg("%s: before long_delay\n", __FUNCTION__);
+	long_delay(1*HZ);
+	dbg("%s: after long_delay\n", __FUNCTION__);
+
+	dbg("%s: func status = %x\n", __FUNCTION__, func->status);
+	/* Check for a power fault */
+	if (func->status == 0xFF) {
+		/* power fault occurred, but it was benign */
+		temp_register = 0xFFFFFFFF;
+		dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
+		rc = POWER_FAILURE;
+		func->status = 0;
+	} else {
+		/* Get vendor/device ID u32 */
+		ctrl->pci_bus->number = func->bus;
+		rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register);
+		dbg("%s: pci_read_config_dword returns %d\n", __FUNCTION__, rc);
+		dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register);
+
+		if (rc != 0) {
+			/* Something's wrong here */
+			temp_register = 0xFFFFFFFF;
+			dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register);
+		}
+		/* Preset return code.  It will be changed later if things go okay. */
+		rc = NO_ADAPTER_PRESENT;
+	}
+
+	/* All F's is an empty slot or an invalid board */
+	if (temp_register != 0xFFFFFFFF) {	  /* Check for a board in the slot */
+		res_lists.io_head = ctrl->io_head;
+		res_lists.mem_head = ctrl->mem_head;
+		res_lists.p_mem_head = ctrl->p_mem_head;
+		res_lists.bus_head = ctrl->bus_head;
+		res_lists.irqs = NULL;
+
+		rc = configure_new_device(ctrl, func, 0, &res_lists);
+
+		dbg("%s: back from configure_new_device\n", __FUNCTION__);
+		ctrl->io_head = res_lists.io_head;
+		ctrl->mem_head = res_lists.mem_head;
+		ctrl->p_mem_head = res_lists.p_mem_head;
+		ctrl->bus_head = res_lists.bus_head;
+
+		cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
+		cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
+		cpqhp_resource_sort_and_combine(&(ctrl->io_head));
+		cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
+
+		if (rc) {
+			down(&ctrl->crit_sect);
+
+			amber_LED_on (ctrl, hp_slot);
+			green_LED_off (ctrl, hp_slot);
+			slot_disable (ctrl, hp_slot);
+
+			set_SOGO(ctrl);
+
+			/* Wait for SOBS to be unset */
+			wait_for_ctrl_irq (ctrl);
+
+			up(&ctrl->crit_sect);
+			return rc;
+		} else {
+			cpqhp_save_slot_config(ctrl, func);
+		}
+
+
+		func->status = 0;
+		func->switch_save = 0x10;
+		func->is_a_board = 0x01;
+
+		/* next, we will instantiate the linux pci_dev structures (with
+		 * appropriate driver notification, if already present) */
+		dbg("%s: configure linux pci_dev structure\n", __FUNCTION__);
+		index = 0;
+		do {
+			new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++);
+			if (new_slot && !new_slot->pci_dev) {
+				cpqhp_configure_device(ctrl, new_slot);
+			}
+		} while (new_slot);
+
+		down(&ctrl->crit_sect);
+
+		green_LED_on (ctrl, hp_slot);
+
+		set_SOGO(ctrl);
+
+		/* Wait for SOBS to be unset */
+		wait_for_ctrl_irq (ctrl);
+
+		up(&ctrl->crit_sect);
+	} else {
+		down(&ctrl->crit_sect);
+
+		amber_LED_on (ctrl, hp_slot);
+		green_LED_off (ctrl, hp_slot);
+		slot_disable (ctrl, hp_slot);
+
+		set_SOGO(ctrl);
+
+		/* Wait for SOBS to be unset */
+		wait_for_ctrl_irq (ctrl);
+
+		up(&ctrl->crit_sect);
+
+		return rc;
+	}
+	return 0;
+}
+
+
+/**
+ * remove_board - Turns off slot and LED's
+ *
+ */
+static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl)
+{
+	int index;
+	u8 skip = 0;
+	u8 device;
+	u8 hp_slot;
+	u8 temp_byte;
+	u32 rc;
+	struct resource_lists res_lists;
+	struct pci_func *temp_func;
+
+	if (cpqhp_unconfigure_device(func))
+		return 1;
+
+	device = func->device;
+
+	hp_slot = func->device - ctrl->slot_device_offset;
+	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+
+	/* When we get here, it is safe to change base address registers.
+	 * We will attempt to save the base address register lengths */
+	if (replace_flag || !ctrl->add_support)
+		rc = cpqhp_save_base_addr_length(ctrl, func);
+	else if (!func->bus_head && !func->mem_head &&
+		 !func->p_mem_head && !func->io_head) {
+		/* Here we check to see if we've saved any of the board's
+		 * resources already.  If so, we'll skip the attempt to
+		 * determine what's being used. */
+		index = 0;
+		temp_func = cpqhp_slot_find(func->bus, func->device, index++);
+		while (temp_func) {
+			if (temp_func->bus_head || temp_func->mem_head
+			    || temp_func->p_mem_head || temp_func->io_head) {
+				skip = 1;
+				break;
+			}
+			temp_func = cpqhp_slot_find(temp_func->bus, temp_func->device, index++);
+		}
+
+		if (!skip)
+			rc = cpqhp_save_used_resources(ctrl, func);
+	}
+	/* Change status to shutdown */
+	if (func->is_a_board)
+		func->status = 0x01;
+	func->configured = 0;
+
+	down(&ctrl->crit_sect);
+
+	green_LED_off (ctrl, hp_slot);
+	slot_disable (ctrl, hp_slot);
+
+	set_SOGO(ctrl);
+
+	/* turn off SERR for slot */
+	temp_byte = readb(ctrl->hpc_reg + SLOT_SERR);
+	temp_byte &= ~(0x01 << hp_slot);
+	writeb(temp_byte, ctrl->hpc_reg + SLOT_SERR);
+
+	/* Wait for SOBS to be unset */
+	wait_for_ctrl_irq (ctrl);
+
+	up(&ctrl->crit_sect);
+
+	if (!replace_flag && ctrl->add_support) {
+		while (func) {
+			res_lists.io_head = ctrl->io_head;
+			res_lists.mem_head = ctrl->mem_head;
+			res_lists.p_mem_head = ctrl->p_mem_head;
+			res_lists.bus_head = ctrl->bus_head;
+
+			cpqhp_return_board_resources(func, &res_lists);
+
+			ctrl->io_head = res_lists.io_head;
+			ctrl->mem_head = res_lists.mem_head;
+			ctrl->p_mem_head = res_lists.p_mem_head;
+			ctrl->bus_head = res_lists.bus_head;
+
+			cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
+			cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
+			cpqhp_resource_sort_and_combine(&(ctrl->io_head));
+			cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
+
+			if (is_bridge(func)) {
+				bridge_slot_remove(func);
+			} else
+				slot_remove(func);
+
+			func = cpqhp_slot_find(ctrl->bus, device, 0);
+		}
+
+		/* Setup slot structure with entry for empty slot */
+		func = cpqhp_slot_create(ctrl->bus);
+
+		if (func == NULL)
+			return 1;
+
+		func->bus = ctrl->bus;
+		func->device = device;
+		func->function = 0;
+		func->configured = 0;
+		func->switch_save = 0x10;
+		func->is_a_board = 0;
+		func->p_task_event = NULL;
+	}
+
+	return 0;
+}
+
+static void pushbutton_helper_thread(unsigned long data)
+{
+	pushbutton_pending = data;
+	up(&event_semaphore);
+}
+
+
+/* this is the main worker thread */
+static int event_thread(void* data)
+{
+	struct controller *ctrl;
+	lock_kernel();
+	daemonize("phpd_event");
+	
+	unlock_kernel();
+
+	while (1) {
+		dbg("!!!!event_thread sleeping\n");
+		down_interruptible (&event_semaphore);
+		dbg("event_thread woken finished = %d\n", event_finished);
+		if (event_finished) break;
+		/* Do stuff here */
+		if (pushbutton_pending)
+			cpqhp_pushbutton_thread(pushbutton_pending);
+		else
+			for (ctrl = cpqhp_ctrl_list; ctrl; ctrl=ctrl->next)
+				interrupt_event_handler(ctrl);
+	}
+	dbg("event_thread signals exit\n");
+	up(&event_exit);
+	return 0;
+}
+
+
+int cpqhp_event_start_thread(void)
+{
+	int pid;
+
+	/* initialize our semaphores */
+	init_MUTEX(&delay_sem);
+	init_MUTEX_LOCKED(&event_semaphore);
+	init_MUTEX_LOCKED(&event_exit);
+	event_finished=0;
+
+	pid = kernel_thread(event_thread, NULL, 0);
+	if (pid < 0) {
+		err ("Can't start up our event thread\n");
+		return -1;
+	}
+	dbg("Our event thread pid = %d\n", pid);
+	return 0;
+}
+
+
+void cpqhp_event_stop_thread(void)
+{
+	event_finished = 1;
+	dbg("event_thread finish command given\n");
+	up(&event_semaphore);
+	dbg("wait for event_thread to exit\n");
+	down(&event_exit);
+}
+
+
+static int update_slot_info(struct controller *ctrl, struct slot *slot)
+{
+	struct hotplug_slot_info *info;
+	int result;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->power_status = get_slot_enabled(ctrl, slot);
+	info->attention_status = cpq_get_attention_status(ctrl, slot);
+	info->latch_status = cpq_get_latch_status(ctrl, slot);
+	info->adapter_status = get_presence_status(ctrl, slot);
+	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
+	kfree (info);
+	return result;
+}
+
+static void interrupt_event_handler(struct controller *ctrl)
+{
+	int loop = 0;
+	int change = 1;
+	struct pci_func *func;
+	u8 hp_slot;
+	struct slot *p_slot;
+
+	while (change) {
+		change = 0;
+
+		for (loop = 0; loop < 10; loop++) {
+			/* dbg("loop %d\n", loop); */
+			if (ctrl->event_queue[loop].event_type != 0) {
+				hp_slot = ctrl->event_queue[loop].hp_slot;
+
+				func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0);
+				if (!func)
+					return;
+
+				p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+				if (!p_slot)
+					return;
+
+				dbg("hp_slot %d, func %p, p_slot %p\n",
+				    hp_slot, func, p_slot);
+
+				if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
+					dbg("button pressed\n");
+				} else if (ctrl->event_queue[loop].event_type == 
+					   INT_BUTTON_CANCEL) {
+					dbg("button cancel\n");
+					del_timer(&p_slot->task_event);
+
+					down(&ctrl->crit_sect);
+
+					if (p_slot->state == BLINKINGOFF_STATE) {
+						/* slot is on */
+						dbg("turn on green LED\n");
+						green_LED_on (ctrl, hp_slot);
+					} else if (p_slot->state == BLINKINGON_STATE) {
+						/* slot is off */
+						dbg("turn off green LED\n");
+						green_LED_off (ctrl, hp_slot);
+					}
+
+					info(msg_button_cancel, p_slot->number);
+
+					p_slot->state = STATIC_STATE;
+
+					amber_LED_off (ctrl, hp_slot);
+
+					set_SOGO(ctrl);
+
+					/* Wait for SOBS to be unset */
+					wait_for_ctrl_irq (ctrl);
+
+					up(&ctrl->crit_sect);
+				}
+				/*** button Released (No action on press...) */
+				else if (ctrl->event_queue[loop].event_type == INT_BUTTON_RELEASE) {
+					dbg("button release\n");
+
+					if (is_slot_enabled (ctrl, hp_slot)) {
+						dbg("slot is on\n");
+						p_slot->state = BLINKINGOFF_STATE;
+						info(msg_button_off, p_slot->number);
+					} else {
+						dbg("slot is off\n");
+						p_slot->state = BLINKINGON_STATE;
+						info(msg_button_on, p_slot->number);
+					}
+					down(&ctrl->crit_sect);
+					
+					dbg("blink green LED and turn off amber\n");
+					
+					amber_LED_off (ctrl, hp_slot);
+					green_LED_blink (ctrl, hp_slot);
+					
+					set_SOGO(ctrl);
+
+					/* Wait for SOBS to be unset */
+					wait_for_ctrl_irq (ctrl);
+
+					up(&ctrl->crit_sect);
+					init_timer(&p_slot->task_event);
+					p_slot->hp_slot = hp_slot;
+					p_slot->ctrl = ctrl;
+/*					p_slot->physical_slot = physical_slot; */
+					p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
+					p_slot->task_event.function = pushbutton_helper_thread;
+					p_slot->task_event.data = (u32) p_slot;
+
+					dbg("add_timer p_slot = %p\n", p_slot);
+					add_timer(&p_slot->task_event);
+				}
+				/***********POWER FAULT */
+				else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
+					dbg("power fault\n");
+				} else {
+					/* refresh notification */
+					if (p_slot)
+						update_slot_info(ctrl, p_slot);
+				}
+
+				ctrl->event_queue[loop].event_type = 0;
+
+				change = 1;
+			}
+		}		/* End of FOR loop */
+	}
+
+	return;
+}
+
+
+/**
+ * cpqhp_pushbutton_thread
+ *
+ * Scheduled procedure to handle blocking stuff for the pushbuttons
+ * Handles all pending events and exits.
+ *
+ */
+void cpqhp_pushbutton_thread(unsigned long slot)
+{
+	u8 hp_slot;
+	u8 device;
+	struct pci_func *func;
+	struct slot *p_slot = (struct slot *) slot;
+	struct controller *ctrl = (struct controller *) p_slot->ctrl;
+
+	pushbutton_pending = 0;
+	hp_slot = p_slot->hp_slot;
+
+	device = p_slot->device;
+
+	if (is_slot_enabled(ctrl, hp_slot)) {
+		p_slot->state = POWEROFF_STATE;
+		/* power Down board */
+		func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0);
+		dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl);
+		if (!func) {
+			dbg("Error! func NULL in %s\n", __FUNCTION__);
+			return ;
+		}
+
+		if (func != NULL && ctrl != NULL) {
+			if (cpqhp_process_SS(ctrl, func) != 0) {
+				amber_LED_on (ctrl, hp_slot);
+				green_LED_on (ctrl, hp_slot);
+				
+				set_SOGO(ctrl);
+
+				/* Wait for SOBS to be unset */
+				wait_for_ctrl_irq (ctrl);
+			}
+		}
+
+		p_slot->state = STATIC_STATE;
+	} else {
+		p_slot->state = POWERON_STATE;
+		/* slot is off */
+
+		func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0);
+		dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl);
+		if (!func) {
+			dbg("Error! func NULL in %s\n", __FUNCTION__);
+			return ;
+		}
+
+		if (func != NULL && ctrl != NULL) {
+			if (cpqhp_process_SI(ctrl, func) != 0) {
+				amber_LED_on(ctrl, hp_slot);
+				green_LED_off(ctrl, hp_slot);
+				
+				set_SOGO(ctrl);
+
+				/* Wait for SOBS to be unset */
+				wait_for_ctrl_irq (ctrl);
+			}
+		}
+
+		p_slot->state = STATIC_STATE;
+	}
+
+	return;
+}
+
+
+int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func)
+{
+	u8 device, hp_slot;
+	u16 temp_word;
+	u32 tempdword;
+	int rc;
+	struct slot* p_slot;
+	int physical_slot = 0;
+
+	tempdword = 0;
+
+	device = func->device;
+	hp_slot = device - ctrl->slot_device_offset;
+	p_slot = cpqhp_find_slot(ctrl, device);
+	if (p_slot)
+		physical_slot = p_slot->number;
+
+	/* Check to see if the interlock is closed */
+	tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
+
+	if (tempdword & (0x01 << hp_slot)) {
+		return 1;
+	}
+
+	if (func->is_a_board) {
+		rc = board_replaced(func, ctrl);
+	} else {
+		/* add board */
+		slot_remove(func);
+
+		func = cpqhp_slot_create(ctrl->bus);
+		if (func == NULL)
+			return 1;
+
+		func->bus = ctrl->bus;
+		func->device = device;
+		func->function = 0;
+		func->configured = 0;
+		func->is_a_board = 1;
+
+		/* We have to save the presence info for these slots */
+		temp_word = ctrl->ctrl_int_comp >> 16;
+		func->presence_save = (temp_word >> hp_slot) & 0x01;
+		func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02;
+
+		if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) {
+			func->switch_save = 0;
+		} else {
+			func->switch_save = 0x10;
+		}
+
+		rc = board_added(func, ctrl);
+		if (rc) {
+			if (is_bridge(func)) {
+				bridge_slot_remove(func);
+			} else
+				slot_remove(func);
+
+			/* Setup slot structure with entry for empty slot */
+			func = cpqhp_slot_create(ctrl->bus);
+
+			if (func == NULL)
+				return 1;
+
+			func->bus = ctrl->bus;
+			func->device = device;
+			func->function = 0;
+			func->configured = 0;
+			func->is_a_board = 0;
+
+			/* We have to save the presence info for these slots */
+			temp_word = ctrl->ctrl_int_comp >> 16;
+			func->presence_save = (temp_word >> hp_slot) & 0x01;
+			func->presence_save |=
+			(temp_word >> (hp_slot + 7)) & 0x02;
+
+			if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) {
+				func->switch_save = 0;
+			} else {
+				func->switch_save = 0x10;
+			}
+		}
+	}
+
+	if (rc) {
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
+	}
+
+	if (p_slot)
+		update_slot_info(ctrl, p_slot);
+
+	return rc;
+}
+
+
+int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func)
+{
+	u8 device, class_code, header_type, BCR;
+	u8 index = 0;
+	u8 replace_flag;
+	u32 rc = 0;
+	unsigned int devfn;
+	struct slot* p_slot;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
+	int physical_slot=0;
+
+	device = func->device; 
+	func = cpqhp_slot_find(ctrl->bus, device, index++);
+	p_slot = cpqhp_find_slot(ctrl, device);
+	if (p_slot) {
+		physical_slot = p_slot->number;
+	}
+
+	/* Make sure there are no video controllers here */
+	while (func && !rc) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		/* Check the Class Code */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+		if (rc)
+			return rc;
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY) {
+			/* Display/Video adapter (not supported) */
+			rc = REMOVE_NOT_SUPPORTED;
+		} else {
+			/* See if it's a bridge */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+			if (rc)
+				return rc;
+
+			/* If it's a bridge, check the VGA Enable bit */
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
+				if (rc)
+					return rc;
+
+				/* If the VGA Enable bit is set, remove isn't
+				 * supported */
+				if (BCR & PCI_BRIDGE_CTL_VGA) {
+					rc = REMOVE_NOT_SUPPORTED;
+				}
+			}
+		}
+
+		func = cpqhp_slot_find(ctrl->bus, device, index++);
+	}
+
+	func = cpqhp_slot_find(ctrl->bus, device, 0);
+	if ((func != NULL) && !rc) {
+		/* FIXME: Replace flag should be passed into process_SS */
+		replace_flag = !(ctrl->add_support);
+		rc = remove_board(func, replace_flag, ctrl);
+	} else if (!rc) {
+		rc = 1;
+	}
+
+	if (p_slot)
+		update_slot_info(ctrl, p_slot);
+
+	return rc;
+}
+
+/**
+ * switch_leds: switch the leds, go from one site to the other.
+ * @ctrl: controller to use
+ * @num_of_slots: number of slots to use
+ * @direction: 1 to start from the left side, 0 to start right.
+ */
+static void switch_leds(struct controller *ctrl, const int num_of_slots,
+			u32 *work_LED, const int direction)
+{
+	int loop;
+
+	for (loop = 0; loop < num_of_slots; loop++) {
+		if (direction)
+			*work_LED = *work_LED >> 1;
+		else
+			*work_LED = *work_LED << 1;
+		writel(*work_LED, ctrl->hpc_reg + LED_CONTROL);
+
+		set_SOGO(ctrl);
+
+		/* Wait for SOGO interrupt */
+		wait_for_ctrl_irq(ctrl);
+
+		/* Get ready for next iteration */
+		long_delay((2*HZ)/10);
+	}
+}
+
+/**
+ * hardware_test - runs hardware tests
+ *
+ * For hot plug ctrl folks to play with.
+ * test_num is the number written to the "test" file in sysfs
+ *
+ */
+int cpqhp_hardware_test(struct controller *ctrl, int test_num)
+{
+	u32 save_LED;
+	u32 work_LED;
+	int loop;
+	int num_of_slots;
+
+	num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f;
+
+	switch (test_num) {
+		case 1:
+			/* Do stuff here! */
+
+			/* Do that funky LED thing */
+			/* so we can restore them later */
+			save_LED = readl(ctrl->hpc_reg + LED_CONTROL);
+			work_LED = 0x01010101;
+			switch_leds(ctrl, num_of_slots, &work_LED, 0);
+			switch_leds(ctrl, num_of_slots, &work_LED, 1);
+			switch_leds(ctrl, num_of_slots, &work_LED, 0);
+			switch_leds(ctrl, num_of_slots, &work_LED, 1);
+
+			work_LED = 0x01010000;
+			writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
+			switch_leds(ctrl, num_of_slots, &work_LED, 0);
+			switch_leds(ctrl, num_of_slots, &work_LED, 1);
+			work_LED = 0x00000101;
+			writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
+			switch_leds(ctrl, num_of_slots, &work_LED, 0);
+			switch_leds(ctrl, num_of_slots, &work_LED, 1);
+
+			work_LED = 0x01010000;
+			writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
+			for (loop = 0; loop < num_of_slots; loop++) {
+				set_SOGO(ctrl);
+
+				/* Wait for SOGO interrupt */
+				wait_for_ctrl_irq (ctrl);
+
+				/* Get ready for next iteration */
+				long_delay((3*HZ)/10);
+				work_LED = work_LED >> 16;
+				writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
+				
+				set_SOGO(ctrl);
+
+				/* Wait for SOGO interrupt */
+				wait_for_ctrl_irq (ctrl);
+
+				/* Get ready for next iteration */
+				long_delay((3*HZ)/10);
+				work_LED = work_LED << 16;
+				writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
+				work_LED = work_LED << 1;
+				writel(work_LED, ctrl->hpc_reg + LED_CONTROL);
+			}
+
+			/* put it back the way it was */
+			writel(save_LED, ctrl->hpc_reg + LED_CONTROL);
+
+			set_SOGO(ctrl);
+
+			/* Wait for SOBS to be unset */
+			wait_for_ctrl_irq (ctrl);
+			break;
+		case 2:
+			/* Do other stuff here! */
+			break;
+		case 3:
+			/* and more... */
+			break;
+	}
+	return 0;
+}
+
+
+/**
+ * configure_new_device - Configures the PCI header information of one board.
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Returns 0 if success
+ *
+ */
+static u32 configure_new_device(struct controller * ctrl, struct pci_func * func,
+				 u8 behind_bridge, struct resource_lists * resources)
+{
+	u8 temp_byte, function, max_functions, stop_it;
+	int rc;
+	u32 ID;
+	struct pci_func *new_slot;
+	int index;
+
+	new_slot = func;
+
+	dbg("%s\n", __FUNCTION__);
+	/* Check for Multi-function device */
+	ctrl->pci_bus->number = func->bus;
+	rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte);
+	if (rc) {
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if (temp_byte & 0x80)	/* Multi-function device */
+		max_functions = 8;
+	else
+		max_functions = 1;
+
+	function = 0;
+
+	do {
+		rc = configure_new_function(ctrl, new_slot, behind_bridge, resources);
+
+		if (rc) {
+			dbg("configure_new_function failed %d\n",rc);
+			index = 0;
+
+			while (new_slot) {
+				new_slot = cpqhp_slot_find(new_slot->bus, new_slot->device, index++);
+
+				if (new_slot)
+					cpqhp_return_board_resources(new_slot, resources);
+			}
+
+			return rc;
+		}
+
+		function++;
+
+		stop_it = 0;
+
+		/* The following loop skips to the next present function
+		 * and creates a board structure */
+
+		while ((function < max_functions) && (!stop_it)) {
+			pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
+
+			if (ID == 0xFFFFFFFF) {	  /* There's nothing there. */
+				function++;
+			} else {  /* There's something there */
+				/* Setup slot structure. */
+				new_slot = cpqhp_slot_create(func->bus);
+
+				if (new_slot == NULL)
+					return 1;
+
+				new_slot->bus = func->bus;
+				new_slot->device = func->device;
+				new_slot->function = function;
+				new_slot->is_a_board = 1;
+				new_slot->status = 0;
+
+				stop_it++;
+			}
+		}
+
+	} while (function < max_functions);
+	dbg("returning from configure_new_device\n");
+
+	return 0;
+}
+
+
+/*
+  Configuration logic that involves the hotplug data structures and 
+  their bookkeeping
+ */
+
+
+/**
+ * configure_new_function - Configures the PCI header information of one device
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Calls itself recursively for bridged devices.
+ * Returns 0 if success
+ *
+ */
+static int configure_new_function(struct controller *ctrl, struct pci_func *func,
+				   u8 behind_bridge,
+				   struct resource_lists *resources)
+{
+	int cloop;
+	u8 IRQ = 0;
+	u8 temp_byte;
+	u8 device;
+	u8 class_code;
+	u16 command;
+	u16 temp_word;
+	u32 temp_dword;
+	u32 rc;
+	u32 temp_register;
+	u32 base;
+	u32 ID;
+	unsigned int devfn;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_resource *hold_mem_node;
+	struct pci_resource *hold_p_mem_node;
+	struct pci_resource *hold_IO_node;
+	struct pci_resource *hold_bus_node;
+	struct irq_mapping irqs;
+	struct pci_func *new_slot;
+	struct pci_bus *pci_bus;
+	struct resource_lists temp_resources;
+
+	pci_bus = ctrl->pci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	/* Check for Bridge */
+	rc = pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte);
+	if (rc)
+		return rc;
+
+	if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+		/* set Primary bus */
+		dbg("set Primary bus = %d\n", func->bus);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
+		if (rc)
+			return rc;
+
+		/* find range of busses to use */
+		dbg("find ranges of buses to use\n");
+		bus_node = get_max_resource(&(resources->bus_head), 1);
+
+		/* If we don't have any busses to allocate, we can't continue */
+		if (!bus_node)
+			return -ENOMEM;
+
+		/* set Secondary bus */
+		temp_byte = bus_node->base;
+		dbg("set Secondary bus = %d\n", bus_node->base);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* set subordinate bus */
+		temp_byte = bus_node->base + bus_node->length - 1;
+		dbg("set subordinate bus = %d\n", bus_node->base + bus_node->length - 1);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* set subordinate Latency Timer and base Latency Timer */
+		temp_byte = 0x40;
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+		if (rc)
+			return rc;
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+		if (rc)
+			return rc;
+
+		/* set Cache Line size */
+		temp_byte = 0x08;
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+		if (rc)
+			return rc;
+
+		/* Setup the IO, memory, and prefetchable windows */
+		io_node = get_max_resource(&(resources->io_head), 0x1000);
+		if (!io_node)
+			return -ENOMEM;
+		mem_node = get_max_resource(&(resources->mem_head), 0x100000);
+		if (!mem_node)
+			return -ENOMEM;
+		p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000);
+		if (!p_mem_node)
+			return -ENOMEM;
+		dbg("Setup the IO, memory, and prefetchable windows\n");
+		dbg("io_node\n");
+		dbg("(base, len, next) (%x, %x, %p)\n", io_node->base,
+					io_node->length, io_node->next);
+		dbg("mem_node\n");
+		dbg("(base, len, next) (%x, %x, %p)\n", mem_node->base,
+					mem_node->length, mem_node->next);
+		dbg("p_mem_node\n");
+		dbg("(base, len, next) (%x, %x, %p)\n", p_mem_node->base,
+					p_mem_node->length, p_mem_node->next);
+
+		/* set up the IRQ info */
+		if (!resources->irqs) {
+			irqs.barber_pole = 0;
+			irqs.interrupt[0] = 0;
+			irqs.interrupt[1] = 0;
+			irqs.interrupt[2] = 0;
+			irqs.interrupt[3] = 0;
+			irqs.valid_INT = 0;
+		} else {
+			irqs.barber_pole = resources->irqs->barber_pole;
+			irqs.interrupt[0] = resources->irqs->interrupt[0];
+			irqs.interrupt[1] = resources->irqs->interrupt[1];
+			irqs.interrupt[2] = resources->irqs->interrupt[2];
+			irqs.interrupt[3] = resources->irqs->interrupt[3];
+			irqs.valid_INT = resources->irqs->valid_INT;
+		}
+
+		/* set up resource lists that are now aligned on top and bottom
+		 * for anything behind the bridge. */
+		temp_resources.bus_head = bus_node;
+		temp_resources.io_head = io_node;
+		temp_resources.mem_head = mem_node;
+		temp_resources.p_mem_head = p_mem_node;
+		temp_resources.irqs = &irqs;
+
+		/* Make copies of the nodes we are going to pass down so that
+		 * if there is a problem,we can just use these to free resources */
+		hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL);
+		hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL);
+		hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL);
+		hold_p_mem_node = kmalloc(sizeof(*hold_p_mem_node), GFP_KERNEL);
+
+		if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
+			kfree(hold_bus_node);
+			kfree(hold_IO_node);
+			kfree(hold_mem_node);
+			kfree(hold_p_mem_node);
+
+			return 1;
+		}
+
+		memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
+
+		bus_node->base += 1;
+		bus_node->length -= 1;
+		bus_node->next = NULL;
+
+		/* If we have IO resources copy them and fill in the bridge's
+		 * IO range registers */
+		if (io_node) {
+			memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
+			io_node->next = NULL;
+
+			/* set IO base and Limit registers */
+			temp_byte = io_node->base >> 8;
+			rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+			temp_byte = (io_node->base + io_node->length - 1) >> 8;
+			rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+		} else {
+			kfree(hold_IO_node);
+			hold_IO_node = NULL;
+		}
+
+		/* If we have memory resources copy them and fill in the
+		 * bridge's memory range registers.  Otherwise, fill in the
+		 * range registers with values that disable them. */
+		if (mem_node) {
+			memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
+			mem_node->next = NULL;
+
+			/* set Mem base and Limit registers */
+			temp_word = mem_node->base >> 16;
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			temp_word = (mem_node->base + mem_node->length - 1) >> 16;
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_mem_node);
+			hold_mem_node = NULL;
+		}
+
+		/* If we have prefetchable memory resources copy them and 
+		 * fill in the bridge's memory range registers.  Otherwise,
+		 * fill in the range registers with values that disable them. */
+		if (p_mem_node) {
+			memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
+			p_mem_node->next = NULL;
+
+			/* set Pre Mem base and Limit registers */
+			temp_word = p_mem_node->base >> 16;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_p_mem_node);
+			hold_p_mem_node = NULL;
+		}
+
+		/* Adjust this to compensate for extra adjustment in first loop */
+		irqs.barber_pole--;
+
+		rc = 0;
+
+		/* Here we actually find the devices and configure them */
+		for (device = 0; (device <= 0x1F) && !rc; device++) {
+			irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
+
+			ID = 0xFFFFFFFF;
+			pci_bus->number = hold_bus_node->base;
+			pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), 0x00, &ID);
+			pci_bus->number = func->bus;
+
+			if (ID != 0xFFFFFFFF) {	  /*  device present */
+				/* Setup slot structure. */
+				new_slot = cpqhp_slot_create(hold_bus_node->base);
+
+				if (new_slot == NULL) {
+					rc = -ENOMEM;
+					continue;
+				}
+
+				new_slot->bus = hold_bus_node->base;
+				new_slot->device = device;
+				new_slot->function = 0;
+				new_slot->is_a_board = 1;
+				new_slot->status = 0;
+
+				rc = configure_new_device(ctrl, new_slot, 1, &temp_resources);
+				dbg("configure_new_device rc=0x%x\n",rc);
+			}	/* End of IF (device in slot?) */
+		}		/* End of FOR loop */
+
+		if (rc)
+			goto free_and_out;
+		/* save the interrupt routing information */
+		if (resources->irqs) {
+			resources->irqs->interrupt[0] = irqs.interrupt[0];
+			resources->irqs->interrupt[1] = irqs.interrupt[1];
+			resources->irqs->interrupt[2] = irqs.interrupt[2];
+			resources->irqs->interrupt[3] = irqs.interrupt[3];
+			resources->irqs->valid_INT = irqs.valid_INT;
+		} else if (!behind_bridge) {
+			/* We need to hook up the interrupts here */
+			for (cloop = 0; cloop < 4; cloop++) {
+				if (irqs.valid_INT & (0x01 << cloop)) {
+					rc = cpqhp_set_irq(func->bus, func->device,
+							   0x0A + cloop, irqs.interrupt[cloop]);
+					if (rc)
+						goto free_and_out;
+				}
+			}	/* end of for loop */
+		}
+		/* Return unused bus resources
+		 * First use the temporary node to store information for
+		 * the board */
+		if (hold_bus_node && bus_node && temp_resources.bus_head) {
+			hold_bus_node->length = bus_node->base - hold_bus_node->base;
+
+			hold_bus_node->next = func->bus_head;
+			func->bus_head = hold_bus_node;
+
+			temp_byte = temp_resources.bus_head->base - 1;
+
+			/* set subordinate bus */
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+
+			if (temp_resources.bus_head->length == 0) {
+				kfree(temp_resources.bus_head);
+				temp_resources.bus_head = NULL;
+			} else {
+				return_resource(&(resources->bus_head), temp_resources.bus_head);
+			}
+		}
+
+		/* If we have IO space available and there is some left,
+		 * return the unused portion */
+		if (hold_IO_node && temp_resources.io_head) {
+			io_node = do_pre_bridge_resource_split(&(temp_resources.io_head),
+							       &hold_IO_node, 0x1000);
+
+			/* Check if we were able to split something off */
+			if (io_node) {
+				hold_IO_node->base = io_node->base + io_node->length;
+
+				temp_byte = (hold_IO_node->base) >> 8;
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+				return_resource(&(resources->io_head), io_node);
+			}
+
+			io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000);
+
+			/* Check if we were able to split something off */
+			if (io_node) {
+				/* First use the temporary node to store
+				 * information for the board */
+				hold_IO_node->length = io_node->base - hold_IO_node->base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_IO_node->length) {
+					hold_IO_node->next = func->io_head;
+					func->io_head = hold_IO_node;
+
+					temp_byte = (io_node->base - 1) >> 8;
+					rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&(resources->io_head), io_node);
+				} else {
+					/* it doesn't need any IO */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_LIMIT, temp_word);
+
+					return_resource(&(resources->io_head), io_node);
+					kfree(hold_IO_node);
+				}
+			} else {
+				/* it used most of the range */
+				hold_IO_node->next = func->io_head;
+				func->io_head = hold_IO_node;
+			}
+		} else if (hold_IO_node) {
+			/* it used the whole range */
+			hold_IO_node->next = func->io_head;
+			func->io_head = hold_IO_node;
+		}
+		/* If we have memory space available and there is some left,
+		 * return the unused portion */
+		if (hold_mem_node && temp_resources.mem_head) {
+			mem_node = do_pre_bridge_resource_split(&(temp_resources.  mem_head),
+								&hold_mem_node, 0x100000);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				hold_mem_node->base = mem_node->base + mem_node->length;
+
+				temp_word = (hold_mem_node->base) >> 16;
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+				return_resource(&(resources->mem_head), mem_node);
+			}
+
+			mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				/* First use the temporary node to store
+				 * information for the board */
+				hold_mem_node->length = mem_node->base - hold_mem_node->base;
+
+				if (hold_mem_node->length) {
+					hold_mem_node->next = func->mem_head;
+					func->mem_head = hold_mem_node;
+
+					/* configure end address */
+					temp_word = (mem_node->base - 1) >> 16;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					/* Return unused resources to the pool */
+					return_resource(&(resources->mem_head), mem_node);
+				} else {
+					/* it doesn't need any Mem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->mem_head), mem_node);
+					kfree(hold_mem_node);
+				}
+			} else {
+				/* it used most of the range */
+				hold_mem_node->next = func->mem_head;
+				func->mem_head = hold_mem_node;
+			}
+		} else if (hold_mem_node) {
+			/* it used the whole range */
+			hold_mem_node->next = func->mem_head;
+			func->mem_head = hold_mem_node;
+		}
+		/* If we have prefetchable memory space available and there
+		 * is some left at the end, return the unused portion */
+		if (hold_p_mem_node && temp_resources.p_mem_head) {
+			p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
+								  &hold_p_mem_node, 0x100000);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				hold_p_mem_node->base = p_mem_node->base + p_mem_node->length;
+
+				temp_word = (hold_p_mem_node->base) >> 16;
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+				return_resource(&(resources->p_mem_head), p_mem_node);
+			}
+
+			p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				/* First use the temporary node to store
+				 * information for the board */
+				hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_p_mem_node->length) {
+					hold_p_mem_node->next = func->p_mem_head;
+					func->p_mem_head = hold_p_mem_node;
+
+					temp_word = (p_mem_node->base - 1) >> 16;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->p_mem_head), p_mem_node);
+				} else {
+					/* it doesn't need any PMem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->p_mem_head), p_mem_node);
+					kfree(hold_p_mem_node);
+				}
+			} else {
+				/* it used the most of the range */
+				hold_p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = hold_p_mem_node;
+			}
+		} else if (hold_p_mem_node) {
+			/* it used the whole range */
+			hold_p_mem_node->next = func->p_mem_head;
+			func->p_mem_head = hold_p_mem_node;
+		}
+		/* We should be configuring an IRQ and the bridge's base address
+		 * registers if it needs them.  Although we have never seen such
+		 * a device */
+
+		/* enable card */
+		command = 0x0157;	/* = PCI_COMMAND_IO |
+					 *   PCI_COMMAND_MEMORY |
+					 *   PCI_COMMAND_MASTER |
+					 *   PCI_COMMAND_INVALIDATE |
+					 *   PCI_COMMAND_PARITY |
+					 *   PCI_COMMAND_SERR */
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command);
+
+		/* set Bridge Control Register */
+		command = 0x07;		/* = PCI_BRIDGE_CTL_PARITY |
+					 *   PCI_BRIDGE_CTL_SERR |
+					 *   PCI_BRIDGE_CTL_NO_ISA */
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+	} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+		/* Standard device */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY) {
+			/* Display (video) adapter (not supported) */
+			return DEVICE_TYPE_NOT_SUPPORTED;
+		}
+		/* Figure out IO and memory needs */
+		for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
+			temp_register = 0xFFFFFFFF;
+
+			dbg("CND: bus=%d, devfn=%d, offset=%d\n", pci_bus->number, devfn, cloop);
+			rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+
+			rc = pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register);
+			dbg("CND: base = 0x%x\n", temp_register);
+
+			if (temp_register) {	  /* If this register is implemented */
+				if ((temp_register & 0x03L) == 0x01) {
+					/* Map IO */
+
+					/* set base = amount of IO space */
+					base = temp_register & 0xFFFFFFFC;
+					base = ~base + 1;
+
+					dbg("CND:      length = 0x%x\n", base);
+					io_node = get_io_resource(&(resources->io_head), base);
+					dbg("Got io_node start = %8.8x, length = %8.8x next (%p)\n",
+					    io_node->base, io_node->length, io_node->next);
+					dbg("func (%p) io_head (%p)\n", func, func->io_head);
+
+					/* allocate the resource to the board */
+					if (io_node) {
+						base = io_node->base;
+
+						io_node->next = func->io_head;
+						func->io_head = io_node;
+					} else
+						return -ENOMEM;
+				} else if ((temp_register & 0x0BL) == 0x08) {
+					/* Map prefetchable memory */
+					base = temp_register & 0xFFFFFFF0;
+					base = ~base + 1;
+
+					dbg("CND:      length = 0x%x\n", base);
+					p_mem_node = get_resource(&(resources->p_mem_head), base);
+
+					/* allocate the resource to the board */
+					if (p_mem_node) {
+						base = p_mem_node->base;
+
+						p_mem_node->next = func->p_mem_head;
+						func->p_mem_head = p_mem_node;
+					} else
+						return -ENOMEM;
+				} else if ((temp_register & 0x0BL) == 0x00) {
+					/* Map memory */
+					base = temp_register & 0xFFFFFFF0;
+					base = ~base + 1;
+
+					dbg("CND:      length = 0x%x\n", base);
+					mem_node = get_resource(&(resources->mem_head), base);
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base = mem_node->base;
+
+						mem_node->next = func->mem_head;
+						func->mem_head = mem_node;
+					} else
+						return -ENOMEM;
+				} else if ((temp_register & 0x0BL) == 0x04) {
+					/* Map memory */
+					base = temp_register & 0xFFFFFFF0;
+					base = ~base + 1;
+
+					dbg("CND:      length = 0x%x\n", base);
+					mem_node = get_resource(&(resources->mem_head), base);
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base = mem_node->base;
+
+						mem_node->next = func->mem_head;
+						func->mem_head = mem_node;
+					} else
+						return -ENOMEM;
+				} else if ((temp_register & 0x0BL) == 0x06) {
+					/* Those bits are reserved, we can't handle this */
+					return 1;
+				} else {
+					/* Requesting space below 1M */
+					return NOT_ENOUGH_RESOURCES;
+				}
+
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base);
+
+				/* Check for 64-bit base */
+				if ((temp_register & 0x07L) == 0x04) {
+					cloop += 4;
+
+					/* Upper 32 bits of address always zero
+					 * on today's systems */
+					/* FIXME this is probably not true on
+					 * Alpha and ia64??? */
+					base = 0;
+					rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base);
+				}
+			}
+		}		/* End of base register loop */
+		if (cpqhp_legacy_mode) {
+			/* Figure out which interrupt pin this function uses */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, 
+				PCI_INTERRUPT_PIN, &temp_byte);
+
+			/* If this function needs an interrupt and we are behind
+			 * a bridge and the pin is tied to something that's
+			 * alread mapped, set this one the same */
+			if (temp_byte && resources->irqs && 
+			    (resources->irqs->valid_INT & 
+			     (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) {
+				/* We have to share with something already set up */
+				IRQ = resources->irqs->interrupt[(temp_byte + 
+					resources->irqs->barber_pole - 1) & 0x03];
+			} else {
+				/* Program IRQ based on card type */
+				rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+
+				if (class_code == PCI_BASE_CLASS_STORAGE) {
+					IRQ = cpqhp_disk_irq;
+				} else {
+					IRQ = cpqhp_nic_irq;
+				}
+			}
+
+			/* IRQ Line */
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ);
+		}
+
+		if (!behind_bridge) {
+			rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ);
+			if (rc)
+				return 1;
+		} else {
+			/* TBD - this code may also belong in the other clause
+			 * of this If statement */
+			resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ;
+			resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03;
+		}
+
+		/* Latency Timer */
+		temp_byte = 0x40;
+		rc = pci_bus_write_config_byte(pci_bus, devfn,
+					PCI_LATENCY_TIMER, temp_byte);
+
+		/* Cache Line size */
+		temp_byte = 0x08;
+		rc = pci_bus_write_config_byte(pci_bus, devfn,
+					PCI_CACHE_LINE_SIZE, temp_byte);
+
+		/* disable ROM base Address */
+		temp_dword = 0x00L;
+		rc = pci_bus_write_config_word(pci_bus, devfn,
+					PCI_ROM_ADDRESS, temp_dword);
+
+		/* enable card */
+		temp_word = 0x0157;	/* = PCI_COMMAND_IO |
+					 *   PCI_COMMAND_MEMORY |
+					 *   PCI_COMMAND_MASTER |
+					 *   PCI_COMMAND_INVALIDATE |
+					 *   PCI_COMMAND_PARITY |
+					 *   PCI_COMMAND_SERR */
+		rc = pci_bus_write_config_word (pci_bus, devfn,
+					PCI_COMMAND, temp_word);
+	} else {		/* End of Not-A-Bridge else */
+		/* It's some strange type of PCI adapter (Cardbus?) */
+		return DEVICE_TYPE_NOT_SUPPORTED;
+	}
+
+	func->configured = 1;
+
+	return 0;
+free_and_out:
+	cpqhp_destroy_resource_list (&temp_resources);
+
+	return_resource(&(resources-> bus_head), hold_bus_node);
+	return_resource(&(resources-> io_head), hold_IO_node);
+	return_resource(&(resources-> mem_head), hold_mem_node);
+	return_resource(&(resources-> p_mem_head), hold_p_mem_node);
+	return rc;
+}
diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c
new file mode 100644
index 0000000..ac98a11
--- /dev/null
+++ b/drivers/pci/hotplug/cpqphp_nvram.c
@@ -0,0 +1,666 @@
+/*
+ * Compaq Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include "cpqphp.h"
+#include "cpqphp_nvram.h"
+
+
+#define ROM_INT15_PHY_ADDR		0x0FF859
+#define READ_EV				0xD8A4
+#define WRITE_EV			0xD8A5
+
+struct register_foo {
+	union {
+		unsigned long lword;		/* eax */
+		unsigned short word;		/* ax */
+
+		struct {
+			unsigned char low;	/* al */
+			unsigned char high;	/* ah */
+		} byte;
+	} data;
+
+	unsigned char opcode;	/* see below */
+	unsigned long length;	/* if the reg. is a pointer, how much data */
+} __attribute__ ((packed));
+
+struct all_reg {
+	struct register_foo eax_reg;
+	struct register_foo ebx_reg;
+	struct register_foo ecx_reg;
+	struct register_foo edx_reg;
+	struct register_foo edi_reg;
+	struct register_foo esi_reg;
+	struct register_foo eflags_reg;
+} __attribute__ ((packed));
+
+
+struct ev_hrt_header {
+	u8 Version;
+	u8 num_of_ctrl;
+	u8 next;
+};
+
+struct ev_hrt_ctrl {
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 mem_avail;
+	u8 p_mem_avail;
+	u8 io_avail;
+	u8 bus_avail;
+	u8 next;
+};
+
+
+static u8 evbuffer_init;
+static u8 evbuffer_length;
+static u8 evbuffer[1024];
+
+static void __iomem *compaq_int15_entry_point;
+
+static spinlock_t int15_lock;		/* lock for ordering int15_bios_call() */
+
+
+/* This is a series of function that deals with
+   setting & getting the hotplug resource table in some environment variable.
+*/
+
+/*
+ * We really shouldn't be doing this unless there is a _very_ good reason to!!!
+ * greg k-h
+ */
+
+
+static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail)
+{
+	u8 **tByte;
+
+	if ((*used + 1) > *avail)
+		return(1);
+	
+	*((u8*)*p_buffer) = value;
+	tByte = (u8**)p_buffer;
+	(*tByte)++;
+	*used+=1;
+	return(0);
+}
+
+
+static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail)
+{
+	if ((*used + 4) > *avail)
+		return(1);
+
+	**p_buffer = value;
+	(*p_buffer)++;
+	*used+=4;
+	return(0);
+}
+
+
+/*
+ * check_for_compaq_ROM
+ *
+ * this routine verifies that the ROM OEM string is 'COMPAQ'
+ *
+ * returns 0 for non-Compaq ROM, 1 for Compaq ROM
+ */
+static int check_for_compaq_ROM (void __iomem *rom_start)
+{
+	u8 temp1, temp2, temp3, temp4, temp5, temp6;
+	int result = 0;
+
+	temp1 = readb(rom_start + 0xffea + 0);
+	temp2 = readb(rom_start + 0xffea + 1);
+	temp3 = readb(rom_start + 0xffea + 2);
+	temp4 = readb(rom_start + 0xffea + 3);
+	temp5 = readb(rom_start + 0xffea + 4);
+	temp6 = readb(rom_start + 0xffea + 5);
+	if ((temp1 == 'C') &&
+	    (temp2 == 'O') &&
+	    (temp3 == 'M') &&
+	    (temp4 == 'P') &&
+	    (temp5 == 'A') &&
+	    (temp6 == 'Q')) {
+		result = 1;
+	}
+	dbg ("%s - returned %d\n", __FUNCTION__, result);
+	return result;
+}
+
+
+static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
+{
+	unsigned long flags;
+	int op = operation;
+	int ret_val;
+	
+	if (!compaq_int15_entry_point)
+		return -ENODEV;
+	
+	spin_lock_irqsave(&int15_lock, flags);
+	__asm__ (
+		"xorl   %%ebx,%%ebx\n" \
+		"xorl    %%edx,%%edx\n" \
+		"pushf\n" \
+		"push %%cs\n" \
+		"cli\n" \
+		"call *%6\n"
+		: "=c" (*buf_size), "=a" (ret_val)
+		: "a" (op), "c" (*buf_size), "S" (ev_name),
+		"D" (buffer), "m" (compaq_int15_entry_point)
+		: "%ebx", "%edx");
+	spin_unlock_irqrestore(&int15_lock, flags);
+	
+	return((ret_val & 0xFF00) >> 8);
+}
+
+
+/*
+ * load_HRT
+ *
+ * Read the hot plug Resource Table from NVRAM
+ */
+static int load_HRT (void __iomem *rom_start)
+{
+	u32 available;
+	u32 temp_dword;
+	u8 temp_byte = 0xFF;
+	u32 rc;
+
+	if (!check_for_compaq_ROM(rom_start)) {
+		return -ENODEV;
+	}
+
+	available = 1024;
+
+	// Now load the EV
+	temp_dword = available;
+
+	rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);
+
+	evbuffer_length = temp_dword;
+
+	// We're maintaining the resource lists so write FF to invalidate old info
+	temp_dword = 1;
+
+	rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
+
+	return rc;
+}
+
+
+/*
+ * store_HRT
+ *
+ * Save the hot plug Resource Table in NVRAM
+ */
+static u32 store_HRT (void __iomem *rom_start)
+{
+	u32 *buffer;
+	u32 *pFill;
+	u32 usedbytes;
+	u32 available;
+	u32 temp_dword;
+	u32 rc;
+	u8 loop;
+	u8 numCtrl = 0;
+	struct controller *ctrl;
+	struct pci_resource *resNode;
+	struct ev_hrt_header *p_EV_header;
+	struct ev_hrt_ctrl *p_ev_ctrl;
+
+	available = 1024;
+
+	if (!check_for_compaq_ROM(rom_start)) {
+		return(1);
+	}
+
+	buffer = (u32*) evbuffer;
+
+	if (!buffer)
+		return(1);
+
+	pFill = buffer;
+	usedbytes = 0;
+
+	p_EV_header = (struct ev_hrt_header *) pFill;
+
+	ctrl = cpqhp_ctrl_list;
+	
+	// The revision of this structure
+	rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available);
+	if (rc)
+		return(rc);
+
+	// The number of controllers
+	rc = add_byte( &pFill, 1, &usedbytes, &available);
+	if (rc)
+		return(rc);
+
+	while (ctrl) {
+		p_ev_ctrl = (struct ev_hrt_ctrl *) pFill;
+
+		numCtrl++;
+
+		// The bus number
+		rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available);
+		if (rc)
+			return(rc);
+
+		// The device Number
+		rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
+		if (rc)
+			return(rc);
+
+		// The function Number
+		rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
+		if (rc)
+			return(rc);
+
+		// Skip the number of available entries
+		rc = add_dword( &pFill, 0, &usedbytes, &available);
+		if (rc)
+			return(rc);
+
+		// Figure out memory Available
+
+		resNode = ctrl->mem_head;
+
+		loop = 0;
+
+		while (resNode) {
+			loop ++;
+
+			// base
+			rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
+			if (rc)
+				return(rc);
+
+			// length
+			rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
+			if (rc)
+				return(rc);
+
+			resNode = resNode->next;
+		}
+
+		// Fill in the number of entries
+		p_ev_ctrl->mem_avail = loop;
+
+		// Figure out prefetchable memory Available
+
+		resNode = ctrl->p_mem_head;
+
+		loop = 0;
+
+		while (resNode) {
+			loop ++;
+
+			// base
+			rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
+			if (rc)
+				return(rc);
+
+			// length
+			rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
+			if (rc)
+				return(rc);
+
+			resNode = resNode->next;
+		}
+
+		// Fill in the number of entries
+		p_ev_ctrl->p_mem_avail = loop;
+
+		// Figure out IO Available
+
+		resNode = ctrl->io_head;
+
+		loop = 0;
+
+		while (resNode) {
+			loop ++;
+
+			// base
+			rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
+			if (rc)
+				return(rc);
+
+			// length
+			rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
+			if (rc)
+				return(rc);
+
+			resNode = resNode->next;
+		}
+
+		// Fill in the number of entries
+		p_ev_ctrl->io_avail = loop;
+
+		// Figure out bus Available
+
+		resNode = ctrl->bus_head;
+
+		loop = 0;
+
+		while (resNode) {
+			loop ++;
+
+			// base
+			rc = add_dword( &pFill, resNode->base, &usedbytes, &available);
+			if (rc)
+				return(rc);
+
+			// length
+			rc = add_dword( &pFill, resNode->length, &usedbytes, &available);
+			if (rc)
+				return(rc);
+
+			resNode = resNode->next;
+		}
+
+		// Fill in the number of entries
+		p_ev_ctrl->bus_avail = loop;
+
+		ctrl = ctrl->next;
+	}
+	
+	p_EV_header->num_of_ctrl = numCtrl;
+
+	// Now store the EV
+
+	temp_dword = usedbytes;
+
+	rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword);
+
+	dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword);
+
+	evbuffer_length = temp_dword;
+
+	if (rc) {
+		err(msg_unable_to_save);
+		return(1);
+	}
+
+	return(0);
+}
+
+
+void compaq_nvram_init (void __iomem *rom_start)
+{
+	if (rom_start) {
+		compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);
+	}
+	dbg("int15 entry  = %p\n", compaq_int15_entry_point);
+
+	/* initialize our int15 lock */
+	spin_lock_init(&int15_lock);
+}
+
+
+int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
+{
+	u8 bus, device, function;
+	u8 nummem, numpmem, numio, numbus;
+	u32 rc;
+	u8 *p_byte;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct ev_hrt_ctrl *p_ev_ctrl;
+	struct ev_hrt_header *p_EV_header;
+
+	if (!evbuffer_init) {
+		// Read the resource list information in from NVRAM
+		if (load_HRT(rom_start))
+			memset (evbuffer, 0, 1024);
+
+		evbuffer_init = 1;
+	}
+
+	// If we saved information in NVRAM, use it now
+	p_EV_header = (struct ev_hrt_header *) evbuffer;
+
+	// The following code is for systems where version 1.0 of this
+	// driver has been loaded, but doesn't support the hardware.
+	// In that case, the driver would incorrectly store something
+	// in NVRAM.
+	if ((p_EV_header->Version == 2) ||
+	    ((p_EV_header->Version == 1) && !ctrl->push_flag)) {
+		p_byte = &(p_EV_header->next);
+
+		p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);
+
+		p_byte += 3;
+
+		if (p_byte > ((u8*)p_EV_header + evbuffer_length))
+			return 2;
+
+		bus = p_ev_ctrl->bus;
+		device = p_ev_ctrl->device;
+		function = p_ev_ctrl->function;
+
+		while ((bus != ctrl->bus) ||
+		       (device != PCI_SLOT(ctrl->pci_dev->devfn)) || 
+		       (function != PCI_FUNC(ctrl->pci_dev->devfn))) {
+			nummem = p_ev_ctrl->mem_avail;
+			numpmem = p_ev_ctrl->p_mem_avail;
+			numio = p_ev_ctrl->io_avail;
+			numbus = p_ev_ctrl->bus_avail;
+
+			p_byte += 4;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length))
+				return 2;
+
+			// Skip forward to the next entry
+			p_byte += (nummem + numpmem + numio + numbus) * 8;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length))
+				return 2;
+
+			p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;
+
+			p_byte += 3;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length))
+				return 2;
+
+			bus = p_ev_ctrl->bus;
+			device = p_ev_ctrl->device;
+			function = p_ev_ctrl->function;
+		}
+
+		nummem = p_ev_ctrl->mem_avail;
+		numpmem = p_ev_ctrl->p_mem_avail;
+		numio = p_ev_ctrl->io_avail;
+		numbus = p_ev_ctrl->bus_avail;
+
+		p_byte += 4;
+
+		if (p_byte > ((u8*)p_EV_header + evbuffer_length))
+			return 2;
+
+		while (nummem--) {
+			mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!mem_node)
+				break;
+
+			mem_node->base = *(u32*)p_byte;
+			dbg("mem base = %8.8x\n",mem_node->base);
+			p_byte += 4;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
+				kfree(mem_node);
+				return 2;
+			}
+
+			mem_node->length = *(u32*)p_byte;
+			dbg("mem length = %8.8x\n",mem_node->length);
+			p_byte += 4;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
+				kfree(mem_node);
+				return 2;
+			}
+
+			mem_node->next = ctrl->mem_head;
+			ctrl->mem_head = mem_node;
+		}
+
+		while (numpmem--) {
+			p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!p_mem_node)
+				break;
+
+			p_mem_node->base = *(u32*)p_byte;
+			dbg("pre-mem base = %8.8x\n",p_mem_node->base);
+			p_byte += 4;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
+				kfree(p_mem_node);
+				return 2;
+			}
+
+			p_mem_node->length = *(u32*)p_byte;
+			dbg("pre-mem length = %8.8x\n",p_mem_node->length);
+			p_byte += 4;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
+				kfree(p_mem_node);
+				return 2;
+			}
+
+			p_mem_node->next = ctrl->p_mem_head;
+			ctrl->p_mem_head = p_mem_node;
+		}
+
+		while (numio--) {
+			io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!io_node)
+				break;
+
+			io_node->base = *(u32*)p_byte;
+			dbg("io base = %8.8x\n",io_node->base);
+			p_byte += 4;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
+				kfree(io_node);
+				return 2;
+			}
+
+			io_node->length = *(u32*)p_byte;
+			dbg("io length = %8.8x\n",io_node->length);
+			p_byte += 4;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
+				kfree(io_node);
+				return 2;
+			}
+
+			io_node->next = ctrl->io_head;
+			ctrl->io_head = io_node;
+		}
+
+		while (numbus--) {
+			bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!bus_node)
+				break;
+
+			bus_node->base = *(u32*)p_byte;
+			p_byte += 4;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
+				kfree(bus_node);
+				return 2;
+			}
+
+			bus_node->length = *(u32*)p_byte;
+			p_byte += 4;
+
+			if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
+				kfree(bus_node);
+				return 2;
+			}
+
+			bus_node->next = ctrl->bus_head;
+			ctrl->bus_head = bus_node;
+		}
+
+		// If all of the following fail, we don't have any resources for
+		// hot plug add
+		rc = 1;
+		rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
+		rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
+		rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
+		rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
+
+		if (rc)
+			return(rc);
+	} else {
+		if ((evbuffer[0] != 0) && (!ctrl->push_flag)) 
+			return 1;
+	}
+
+	return 0;
+}
+
+	
+int compaq_nvram_store (void __iomem *rom_start)
+{
+	int rc = 1;
+
+	if (rom_start == NULL)
+		return -ENODEV;
+
+	if (evbuffer_init) {
+		rc = store_HRT(rom_start);
+		if (rc) {
+			err(msg_unable_to_save);
+		}
+	}
+	return rc;
+}
+
diff --git a/drivers/pci/hotplug/cpqphp_nvram.h b/drivers/pci/hotplug/cpqphp_nvram.h
new file mode 100644
index 0000000..e89c070
--- /dev/null
+++ b/drivers/pci/hotplug/cpqphp_nvram.h
@@ -0,0 +1,57 @@
+/*
+ * Compaq Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+
+#ifndef _CPQPHP_NVRAM_H
+#define _CPQPHP_NVRAM_H
+
+#ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM
+
+static inline void compaq_nvram_init (void __iomem *rom_start)
+{
+	return;
+}
+
+static inline int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
+{
+	return 0;
+}
+
+static inline int compaq_nvram_store (void __iomem *rom_start)
+{
+	return 0;
+}
+
+#else
+
+extern void compaq_nvram_init	(void __iomem *rom_start);
+extern int compaq_nvram_load	(void __iomem *rom_start, struct controller *ctrl);
+extern int compaq_nvram_store	(void __iomem *rom_start);
+
+#endif
+
+#endif
+
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
new file mode 100644
index 0000000..93e39c4
--- /dev/null
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -0,0 +1,1569 @@
+/*
+ * Compaq Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include "../pci.h"
+#include "cpqphp.h"
+#include "cpqphp_nvram.h"
+#include "../../../arch/i386/pci/pci.h"	/* horrible hack showing how processor dependent we are... */
+
+
+u8 cpqhp_nic_irq;
+u8 cpqhp_disk_irq;
+
+static u16 unused_IRQ;
+
+/*
+ * detect_HRT_floating_pointer
+ *
+ * find the Hot Plug Resource Table in the specified region of memory.
+ *
+ */
+static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end)
+{
+	void __iomem *fp;
+	void __iomem *endp;
+	u8 temp1, temp2, temp3, temp4;
+	int status = 0;
+
+	endp = (end - sizeof(struct hrt) + 1);
+
+	for (fp = begin; fp <= endp; fp += 16) {
+		temp1 = readb(fp + SIG0);
+		temp2 = readb(fp + SIG1);
+		temp3 = readb(fp + SIG2);
+		temp4 = readb(fp + SIG3);
+		if (temp1 == '$' &&
+		    temp2 == 'H' &&
+		    temp3 == 'R' &&
+		    temp4 == 'T') {
+			status = 1;
+			break;
+		}
+	}
+
+	if (!status)
+		fp = NULL;
+
+	dbg("Discovered Hotplug Resource Table at %p\n", fp);
+	return fp;
+}
+
+
+int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)  
+{
+	unsigned char bus;
+	struct pci_bus *child;
+	int num;
+
+	if (func->pci_dev == NULL)
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
+
+	/* No pci device, we need to create it then */
+	if (func->pci_dev == NULL) {
+		dbg("INFO: pci_dev still null\n");
+
+		num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function));
+		if (num)
+			pci_bus_add_devices(ctrl->pci_dev->bus);
+
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
+		if (func->pci_dev == NULL) {
+			dbg("ERROR: pci_dev still null\n");
+			return 0;
+		}
+	}
+
+	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
+		child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
+		pci_do_scan_bus(child);
+	}
+
+	return 0;
+}
+
+
+int cpqhp_unconfigure_device(struct pci_func* func) 
+{
+	int j;
+	
+	dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function);
+
+	for (j=0; j<8 ; j++) {
+		struct pci_dev* temp = pci_find_slot(func->bus, PCI_DEVFN(func->device, j));
+		if (temp)
+			pci_remove_bus_device(temp);
+	}
+	return 0;
+}
+
+static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value)
+{
+	u32 vendID = 0;
+
+	if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1)
+		return -1;
+	if (vendID == 0xffffffff)
+		return -1;
+	return pci_bus_read_config_dword (bus, devfn, offset, value);
+}
+
+
+/*
+ * cpqhp_set_irq
+ *
+ * @bus_num: bus number of PCI device
+ * @dev_num: device number of PCI device
+ * @slot: pointer to u8 where slot number will be returned
+ */
+int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
+{
+	int rc = 0;
+
+	if (cpqhp_legacy_mode) {
+		struct pci_dev *fakedev;
+		struct pci_bus *fakebus;
+		u16 temp_word;
+
+		fakedev = kmalloc(sizeof(*fakedev), GFP_KERNEL);
+		fakebus = kmalloc(sizeof(*fakebus), GFP_KERNEL);
+		if (!fakedev || !fakebus) {
+			kfree(fakedev);
+			kfree(fakebus);
+			return -ENOMEM;
+		}
+
+		fakedev->devfn = dev_num << 3;
+		fakedev->bus = fakebus;
+		fakebus->number = bus_num;
+		dbg("%s: dev %d, bus %d, pin %d, num %d\n",
+		    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
+		rc = pcibios_set_irq_routing(fakedev, int_pin - 0x0a, irq_num);
+		kfree(fakedev);
+		kfree(fakebus);
+		dbg("%s: rc %d\n", __FUNCTION__, rc);
+		if (!rc)
+			return !rc;
+
+		// set the Edge Level Control Register (ELCR)
+		temp_word = inb(0x4d0);
+		temp_word |= inb(0x4d1) << 8;
+
+		temp_word |= 0x01 << irq_num;
+
+		// This should only be for x86 as it sets the Edge Level Control Register
+		outb((u8) (temp_word & 0xFF), 0x4d0);
+		outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
+		rc = 0;
+	}
+
+	return rc;
+}
+
+
+/*
+ * WTF??? This function isn't in the code, yet a function calls it, but the 
+ * compiler optimizes it away?  strange.  Here as a placeholder to keep the 
+ * compiler happy.
+ */
+static int PCI_ScanBusNonBridge (u8 bus, u8 device)
+{
+	return 0;
+}
+
+static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num)
+{
+	u16 tdevice;
+	u32 work;
+	u8 tbus;
+
+	ctrl->pci_bus->number = bus_num;
+
+	for (tdevice = 0; tdevice < 0xFF; tdevice++) {
+		//Scan for access first
+		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
+			continue;
+		dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice);
+		//Yep we got one. Not a bridge ?
+		if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) {
+			*dev_num = tdevice;
+			dbg("found it !\n");
+			return 0;
+		}
+	}
+	for (tdevice = 0; tdevice < 0xFF; tdevice++) {
+		//Scan for access first
+		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
+			continue;
+		dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice);
+		//Yep we got one. bridge ?
+		if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
+			pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus);
+			dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice);
+			if (PCI_ScanBusNonBridge(tbus, tdevice) == 0)
+				return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge)
+{
+	struct irq_routing_table *PCIIRQRoutingInfoLength;
+	long len;
+	long loop;
+	u32 work;
+
+	u8 tbus, tdevice, tslot;
+
+	PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table();
+	if (!PCIIRQRoutingInfoLength)
+		return -1;
+
+	len = (PCIIRQRoutingInfoLength->size -
+	       sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
+	// Make sure I got at least one entry
+	if (len == 0) {
+		if (PCIIRQRoutingInfoLength != NULL)
+			kfree(PCIIRQRoutingInfoLength );
+		return -1;
+	}
+
+	for (loop = 0; loop < len; ++loop) {
+		tbus = PCIIRQRoutingInfoLength->slots[loop].bus;
+		tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn;
+		tslot = PCIIRQRoutingInfoLength->slots[loop].slot;
+
+		if (tslot == slot) {
+			*bus_num = tbus;
+			*dev_num = tdevice;
+			ctrl->pci_bus->number = tbus;
+			pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work);
+			if (!nobridge || (work == 0xffffffff)) {
+				if (PCIIRQRoutingInfoLength != NULL)
+					kfree(PCIIRQRoutingInfoLength );
+				return 0;
+			}
+
+			dbg("bus_num %d devfn %d\n", *bus_num, *dev_num);
+			pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work);
+			dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS);
+
+			if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
+				pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus);
+				dbg("Scan bus for Non Bridge: bus %d\n", tbus);
+				if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) {
+					*bus_num = tbus;
+					if (PCIIRQRoutingInfoLength != NULL)
+						kfree(PCIIRQRoutingInfoLength );
+					return 0;
+				}
+			} else {
+				if (PCIIRQRoutingInfoLength != NULL)
+					kfree(PCIIRQRoutingInfoLength );
+				return 0;
+			}
+
+		}
+	}
+	if (PCIIRQRoutingInfoLength != NULL)
+		kfree(PCIIRQRoutingInfoLength );
+	return -1;
+}
+
+
+int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot)
+{
+	return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0);	//plain (bridges allowed)
+}
+
+
+/* More PCI configuration routines; this time centered around hotplug controller */
+
+
+/*
+ * cpqhp_save_config
+ *
+ * Reads configuration for all slots in a PCI bus and saves info.
+ *
+ * Note:  For non-hot plug busses, the slot # saved is the device #
+ *
+ * returns 0 if success
+ */
+int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
+{
+	long rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	struct pci_func *new_slot;
+	int sub_bus;
+	int FirstSupported;
+	int LastSupported;
+	int max_functions;
+	int function;
+	u8 DevError;
+	int device = 0;
+	int cloop = 0;
+	int stop_it;
+	int index;
+
+	//              Decide which slots are supported
+
+	if (is_hot_plug) {
+		//*********************************
+		// is_hot_plug is the slot mask
+		//*********************************
+		FirstSupported = is_hot_plug >> 4;
+		LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1;
+	} else {
+		FirstSupported = 0;
+		LastSupported = 0x1F;
+	}
+
+	//     Save PCI configuration space for all devices in supported slots
+	ctrl->pci_bus->number = busnumber;
+	for (device = FirstSupported; device <= LastSupported; device++) {
+		ID = 0xFFFFFFFF;
+		rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
+
+		if (ID != 0xFFFFFFFF) {	  //  device in slot
+			rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
+			if (rc)
+				return rc;
+
+			rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
+			if (rc)
+				return rc;
+
+			// If multi-function device, set max_functions to 8
+			if (header_type & 0x80)
+				max_functions = 8;
+			else
+				max_functions = 1;
+
+			function = 0;
+
+			do {
+				DevError = 0;
+
+				if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   // P-P Bridge
+					//  Recurse the subordinate bus
+					//  get the subordinate bus number
+					rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
+					if (rc) {
+						return rc;
+					} else {
+						sub_bus = (int) secondary_bus;
+
+						// Save secondary bus cfg spc
+						// with this recursive call.
+						rc = cpqhp_save_config(ctrl, sub_bus, 0);
+						if (rc)
+							return rc;
+						ctrl->pci_bus->number = busnumber;
+					}
+				}
+
+				index = 0;
+				new_slot = cpqhp_slot_find(busnumber, device, index++);
+				while (new_slot && 
+				       (new_slot->function != (u8) function))
+					new_slot = cpqhp_slot_find(busnumber, device, index++);
+
+				if (!new_slot) {
+					// Setup slot structure.
+					new_slot = cpqhp_slot_create(busnumber);
+
+					if (new_slot == NULL)
+						return(1);
+				}
+
+				new_slot->bus = (u8) busnumber;
+				new_slot->device = (u8) device;
+				new_slot->function = (u8) function;
+				new_slot->is_a_board = 1;
+				new_slot->switch_save = 0x10;
+				// In case of unsupported board
+				new_slot->status = DevError;
+				new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function);
+
+				for (cloop = 0; cloop < 0x20; cloop++) {
+					rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
+					if (rc)
+						return rc;
+				}
+
+				function++;
+
+				stop_it = 0;
+
+				//  this loop skips to the next present function
+				//  reading in Class Code and Header type.
+
+				while ((function < max_functions)&&(!stop_it)) {
+					rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
+					if (ID == 0xFFFFFFFF) {	 // nothing there.
+						function++;
+					} else {  // Something there
+						rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
+						if (rc)
+							return rc;
+
+						rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
+						if (rc)
+							return rc;
+
+						stop_it++;
+					}
+				}
+
+			} while (function < max_functions);
+		}		// End of IF (device in slot?)
+		else if (is_hot_plug) {
+			// Setup slot structure with entry for empty slot
+			new_slot = cpqhp_slot_create(busnumber);
+
+			if (new_slot == NULL) {
+				return(1);
+			}
+
+			new_slot->bus = (u8) busnumber;
+			new_slot->device = (u8) device;
+			new_slot->function = 0;
+			new_slot->is_a_board = 0;
+			new_slot->presence_save = 0;
+			new_slot->switch_save = 0;
+		}
+	}			// End of FOR loop
+
+	return(0);
+}
+
+
+/*
+ * cpqhp_save_slot_config
+ *
+ * Saves configuration info for all PCI devices in a given slot
+ * including subordinate busses.
+ *
+ * returns 0 if success
+ */
+int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot)
+{
+	long rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	int sub_bus;
+	int max_functions;
+	int function;
+	int cloop = 0;
+	int stop_it;
+
+	ID = 0xFFFFFFFF;
+
+	ctrl->pci_bus->number = new_slot->bus;
+	pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
+
+	if (ID != 0xFFFFFFFF) {	  //  device in slot
+		pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
+		pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
+
+		if (header_type & 0x80)	// Multi-function device
+			max_functions = 8;
+		else
+			max_functions = 1;
+
+		function = 0;
+
+		do {
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
+				//  Recurse the subordinate bus
+				pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
+
+				sub_bus = (int) secondary_bus;
+
+				// Save the config headers for the secondary bus.
+				rc = cpqhp_save_config(ctrl, sub_bus, 0);
+				if (rc)
+					return(rc);
+				ctrl->pci_bus->number = new_slot->bus;
+
+			}	// End of IF
+
+			new_slot->status = 0;
+
+			for (cloop = 0; cloop < 0x20; cloop++) {
+				pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
+			}
+
+			function++;
+
+			stop_it = 0;
+
+			//  this loop skips to the next present function
+			//  reading in the Class Code and the Header type.
+
+			while ((function < max_functions) && (!stop_it)) {
+				pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
+
+				if (ID == 0xFFFFFFFF) {	 // nothing there.
+					function++;
+				} else {  // Something there
+					pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
+
+					pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
+
+					stop_it++;
+				}
+			}
+
+		} while (function < max_functions);
+	}			// End of IF (device in slot?)
+	else {
+		return 2;
+	}
+
+	return 0;
+}
+
+
+/*
+ * cpqhp_save_base_addr_length
+ *
+ * Saves the length of all base address registers for the
+ * specified slot.  this is for hot plug REPLACE
+ *
+ * returns 0 if success
+ */
+int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func)
+{
+	u8 cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	u8 type;
+	int sub_bus;
+	u32 temp_register;
+	u32 base;
+	u32 rc;
+	struct pci_func *next;
+	int index = 0;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
+	unsigned int devfn;
+
+	func = cpqhp_slot_find(func->bus, func->device, index++);
+
+	while (func != NULL) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		// Check for Bridge
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+
+		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+			// PCI-PCI Bridge
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
+
+			sub_bus = (int) secondary_bus;
+
+			next = cpqhp_slot_list[sub_bus];
+
+			while (next != NULL) {
+				rc = cpqhp_save_base_addr_length(ctrl, next);
+				if (rc)
+					return rc;
+
+				next = next->next;
+			}
+			pci_bus->number = func->bus;
+
+			//FIXME: this loop is duplicated in the non-bridge case.  The two could be rolled together
+			// Figure out IO and memory base lengths
+			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
+
+				if (base) {  // If this register is implemented
+					if (base & 0x01L) {
+						// IO base
+						// set base = amount of IO space requested
+						base = base & 0xFFFFFFFE;
+						base = (~base) + 1;
+
+						type = 1;
+					} else {
+						// memory base
+						base = base & 0xFFFFFFF0;
+						base = (~base) + 1;
+
+						type = 0;
+					}
+				} else {
+					base = 0x0L;
+					type = 0;
+				}
+
+				// Save information in slot structure
+				func->base_length[(cloop - 0x10) >> 2] =
+				base;
+				func->base_type[(cloop - 0x10) >> 2] = type;
+
+			}	// End of base register loop
+
+
+		} else if ((header_type & 0x7F) == 0x00) {	  // PCI-PCI Bridge
+			// Figure out IO and memory base lengths
+			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
+
+				if (base) {  // If this register is implemented
+					if (base & 0x01L) {
+						// IO base
+						// base = amount of IO space requested
+						base = base & 0xFFFFFFFE;
+						base = (~base) + 1;
+
+						type = 1;
+					} else {
+						// memory base
+						// base = amount of memory space requested
+						base = base & 0xFFFFFFF0;
+						base = (~base) + 1;
+
+						type = 0;
+					}
+				} else {
+					base = 0x0L;
+					type = 0;
+				}
+
+				// Save information in slot structure
+				func->base_length[(cloop - 0x10) >> 2] = base;
+				func->base_type[(cloop - 0x10) >> 2] = type;
+
+			}	// End of base register loop
+
+		} else {	  // Some other unknown header type
+		}
+
+		// find the next device in this slot
+		func = cpqhp_slot_find(func->bus, func->device, index++);
+	}
+
+	return(0);
+}
+
+
+/*
+ * cpqhp_save_used_resources
+ *
+ * Stores used resource information for existing boards.  this is
+ * for boards that were in the system when this driver was loaded.
+ * this function is for hot plug ADD
+ *
+ * returns 0 if success
+ */
+int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func)
+{
+	u8 cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	u8 temp_byte;
+	u8 b_base;
+	u8 b_length;
+	u16 command;
+	u16 save_command;
+	u16 w_base;
+	u16 w_length;
+	u32 temp_register;
+	u32 save_base;
+	u32 base;
+	int index = 0;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
+	unsigned int devfn;
+
+	func = cpqhp_slot_find(func->bus, func->device, index++);
+
+	while ((func != NULL) && func->is_a_board) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		// Save the command register
+		pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command);
+
+		// disable card
+		command = 0x00;
+		pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+		// Check for Bridge
+		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+
+		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
+			// Clear Bridge Control Register
+			command = 0x00;
+			pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
+
+			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node->base = secondary_bus;
+			bus_node->length = temp_byte - secondary_bus + 1;
+
+			bus_node->next = func->bus_head;
+			func->bus_head = bus_node;
+
+			// Save IO base and Limit registers
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base);
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length);
+
+			if ((b_base <= b_length) && (save_command & 0x01)) {
+				io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
+				if (!io_node)
+					return -ENOMEM;
+
+				io_node->base = (b_base & 0xF0) << 8;
+				io_node->length = (b_length - b_base + 0x10) << 8;
+
+				io_node->next = func->io_head;
+				func->io_head = io_node;
+			}
+
+			// Save memory base and Limit registers
+			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (save_command & 0x02)) {
+				mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
+				if (!mem_node)
+					return -ENOMEM;
+
+				mem_node->base = w_base << 16;
+				mem_node->length = (w_length - w_base + 0x10) << 16;
+
+				mem_node->next = func->mem_head;
+				func->mem_head = mem_node;
+			}
+
+			// Save prefetchable memory base and Limit registers
+			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (save_command & 0x02)) {
+				p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
+				if (!p_mem_node)
+					return -ENOMEM;
+
+				p_mem_node->base = w_base << 16;
+				p_mem_node->length = (w_length - w_base + 0x10) << 16;
+
+				p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = p_mem_node;
+			}
+			// Figure out IO and memory base lengths
+			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);
+
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
+
+				temp_register = base;
+
+				if (base) {  // If this register is implemented
+					if (((base & 0x03L) == 0x01)
+					    && (save_command & 0x01)) {
+						// IO base
+						// set temp_register = amount of IO space requested
+						temp_register = base & 0xFFFFFFFE;
+						temp_register = (~temp_register) + 1;
+
+						io_node = kmalloc(sizeof(*io_node),
+								GFP_KERNEL);
+						if (!io_node)
+							return -ENOMEM;
+
+						io_node->base =
+						save_base & (~0x03L);
+						io_node->length = temp_register;
+
+						io_node->next = func->io_head;
+						func->io_head = io_node;
+					} else
+						if (((base & 0x0BL) == 0x08)
+						    && (save_command & 0x02)) {
+						// prefetchable memory base
+						temp_register = base & 0xFFFFFFF0;
+						temp_register = (~temp_register) + 1;
+
+						p_mem_node = kmalloc(sizeof(*p_mem_node),
+								GFP_KERNEL);
+						if (!p_mem_node)
+							return -ENOMEM;
+
+						p_mem_node->base = save_base & (~0x0FL);
+						p_mem_node->length = temp_register;
+
+						p_mem_node->next = func->p_mem_head;
+						func->p_mem_head = p_mem_node;
+					} else
+						if (((base & 0x0BL) == 0x00)
+						    && (save_command & 0x02)) {
+						// prefetchable memory base
+						temp_register = base & 0xFFFFFFF0;
+						temp_register = (~temp_register) + 1;
+
+						mem_node = kmalloc(sizeof(*mem_node),
+								GFP_KERNEL);
+						if (!mem_node)
+							return -ENOMEM;
+
+						mem_node->base = save_base & (~0x0FL);
+						mem_node->length = temp_register;
+
+						mem_node->next = func->mem_head;
+						func->mem_head = mem_node;
+					} else
+						return(1);
+				}
+			}	// End of base register loop
+		} else if ((header_type & 0x7F) == 0x00) {	  // Standard header
+			// Figure out IO and memory base lengths
+			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
+				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
+
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword(pci_bus, devfn, cloop, &base);
+
+				temp_register = base;
+
+				if (base) {	  // If this register is implemented
+					if (((base & 0x03L) == 0x01)
+					    && (save_command & 0x01)) {
+						// IO base
+						// set temp_register = amount of IO space requested
+						temp_register = base & 0xFFFFFFFE;
+						temp_register = (~temp_register) + 1;
+
+						io_node = kmalloc(sizeof(*io_node),
+								GFP_KERNEL);
+						if (!io_node)
+							return -ENOMEM;
+
+						io_node->base = save_base & (~0x01L);
+						io_node->length = temp_register;
+
+						io_node->next = func->io_head;
+						func->io_head = io_node;
+					} else
+						if (((base & 0x0BL) == 0x08)
+						    && (save_command & 0x02)) {
+						// prefetchable memory base
+						temp_register = base & 0xFFFFFFF0;
+						temp_register = (~temp_register) + 1;
+
+						p_mem_node = kmalloc(sizeof(*p_mem_node),
+								GFP_KERNEL);
+						if (!p_mem_node)
+							return -ENOMEM;
+
+						p_mem_node->base = save_base & (~0x0FL);
+						p_mem_node->length = temp_register;
+
+						p_mem_node->next = func->p_mem_head;
+						func->p_mem_head = p_mem_node;
+					} else
+						if (((base & 0x0BL) == 0x00)
+						    && (save_command & 0x02)) {
+						// prefetchable memory base
+						temp_register = base & 0xFFFFFFF0;
+						temp_register = (~temp_register) + 1;
+
+						mem_node = kmalloc(sizeof(*mem_node),
+								GFP_KERNEL);
+						if (!mem_node)
+							return -ENOMEM;
+
+						mem_node->base = save_base & (~0x0FL);
+						mem_node->length = temp_register;
+
+						mem_node->next = func->mem_head;
+						func->mem_head = mem_node;
+					} else
+						return(1);
+				}
+			}	// End of base register loop
+		} else {	  // Some other unknown header type
+		}
+
+		// find the next device in this slot
+		func = cpqhp_slot_find(func->bus, func->device, index++);
+	}
+
+	return(0);
+}
+
+
+/*
+ * cpqhp_configure_board
+ *
+ * Copies saved configuration information to one slot.
+ * this is called recursively for bridge devices.
+ * this is for hot plug REPLACE!
+ *
+ * returns 0 if success
+ */
+int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func)
+{
+	int cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	int sub_bus;
+	struct pci_func *next;
+	u32 temp;
+	u32 rc;
+	int index = 0;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
+	unsigned int devfn;
+
+	func = cpqhp_slot_find(func->bus, func->device, index++);
+
+	while (func != NULL) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		// Start at the top of config space so that the control
+		// registers are programmed last
+		for (cloop = 0x3C; cloop > 0; cloop -= 4) {
+			pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]);
+		}
+
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+
+		// If this is a bridge device, restore subordinate devices
+		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
+
+			sub_bus = (int) secondary_bus;
+
+			next = cpqhp_slot_list[sub_bus];
+
+			while (next != NULL) {
+				rc = cpqhp_configure_board(ctrl, next);
+				if (rc)
+					return rc;
+
+				next = next->next;
+			}
+		} else {
+
+			// Check all the base Address Registers to make sure
+			// they are the same.  If not, the board is different.
+
+			for (cloop = 16; cloop < 40; cloop += 4) {
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp);
+
+				if (temp != func->config_space[cloop >> 2]) {
+					dbg("Config space compare failure!!! offset = %x\n", cloop);
+					dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function);
+					dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]);
+					return 1;
+				}
+			}
+		}
+
+		func->configured = 1;
+
+		func = cpqhp_slot_find(func->bus, func->device, index++);
+	}
+
+	return 0;
+}
+
+
+/*
+ * cpqhp_valid_replace
+ *
+ * this function checks to see if a board is the same as the
+ * one it is replacing.  this check will detect if the device's
+ * vendor or device id's are the same
+ *
+ * returns 0 if the board is the same nonzero otherwise
+ */
+int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func)
+{
+	u8 cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	u8 type;
+	u32 temp_register = 0;
+	u32 base;
+	u32 rc;
+	struct pci_func *next;
+	int index = 0;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
+	unsigned int devfn;
+
+	if (!func->is_a_board)
+		return(ADD_NOT_SUPPORTED);
+
+	func = cpqhp_slot_find(func->bus, func->device, index++);
+
+	while (func != NULL) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register);
+
+		// No adapter present
+		if (temp_register == 0xFFFFFFFF)
+			return(NO_ADAPTER_PRESENT);
+
+		if (temp_register != func->config_space[0])
+			return(ADAPTER_NOT_SAME);
+
+		// Check for same revision number and class code
+		pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register);
+
+		// Adapter not the same
+		if (temp_register != func->config_space[0x08 >> 2])
+			return(ADAPTER_NOT_SAME);
+
+		// Check for Bridge
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+
+		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
+			// In order to continue checking, we must program the
+			// bus registers in the bridge to respond to accesses
+			// for it's subordinate bus(es)
+
+			temp_register = func->config_space[0x18 >> 2];
+			pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register);
+
+			secondary_bus = (temp_register >> 8) & 0xFF;
+
+			next = cpqhp_slot_list[secondary_bus];
+
+			while (next != NULL) {
+				rc = cpqhp_valid_replace(ctrl, next);
+				if (rc)
+					return rc;
+
+				next = next->next;
+			}
+
+		}
+		// Check to see if it is a standard config header
+		else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+			// Check subsystem vendor and ID
+			pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
+
+			if (temp_register != func->config_space[0x2C >> 2]) {
+				// If it's a SMART-2 and the register isn't filled
+				// in, ignore the difference because
+				// they just have an old rev of the firmware
+
+				if (!((func->config_space[0] == 0xAE100E11)
+				      && (temp_register == 0x00L)))
+					return(ADAPTER_NOT_SAME);
+			}
+			// Figure out IO and memory base lengths
+			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
+				if (base) {	  // If this register is implemented
+					if (base & 0x01L) {
+						// IO base
+						// set base = amount of IO space requested
+						base = base & 0xFFFFFFFE;
+						base = (~base) + 1;
+
+						type = 1;
+					} else {
+						// memory base
+						base = base & 0xFFFFFFF0;
+						base = (~base) + 1;
+
+						type = 0;
+					}
+				} else {
+					base = 0x0L;
+					type = 0;
+				}
+
+				// Check information in slot structure
+				if (func->base_length[(cloop - 0x10) >> 2] != base)
+					return(ADAPTER_NOT_SAME);
+
+				if (func->base_type[(cloop - 0x10) >> 2] != type)
+					return(ADAPTER_NOT_SAME);
+
+			}	// End of base register loop
+
+		}		// End of (type 0 config space) else
+		else {
+			// this is not a type 0 or 1 config space header so
+			// we don't know how to do it
+			return(DEVICE_TYPE_NOT_SUPPORTED);
+		}
+
+		// Get the next function
+		func = cpqhp_slot_find(func->bus, func->device, index++);
+	}
+
+
+	return 0;
+}
+
+
+/*
+ * cpqhp_find_available_resources
+ *
+ * Finds available memory, IO, and IRQ resources for programming
+ * devices which may be added to the system
+ * this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */  
+int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start)
+{
+	u8 temp;
+	u8 populated_slot;
+	u8 bridged_slot;
+	void __iomem *one_slot;
+	void __iomem *rom_resource_table;
+	struct pci_func *func = NULL;
+	int i = 10, index;
+	u32 temp_dword, rc;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+
+	rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff);
+	dbg("rom_resource_table = %p\n", rom_resource_table);
+
+	if (rom_resource_table == NULL) {
+		return -ENODEV;
+	}
+	// Sum all resources and setup resource maps
+	unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
+	dbg("unused_IRQ = %x\n", unused_IRQ);
+
+	temp = 0;
+	while (unused_IRQ) {
+		if (unused_IRQ & 1) {
+			cpqhp_disk_irq = temp;
+			break;
+		}
+		unused_IRQ = unused_IRQ >> 1;
+		temp++;
+	}
+
+	dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq);
+	unused_IRQ = unused_IRQ >> 1;
+	temp++;
+
+	while (unused_IRQ) {
+		if (unused_IRQ & 1) {
+			cpqhp_nic_irq = temp;
+			break;
+		}
+		unused_IRQ = unused_IRQ >> 1;
+		temp++;
+	}
+
+	dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq);
+	unused_IRQ = readl(rom_resource_table + PCIIRQ);
+
+	temp = 0;
+
+	if (!cpqhp_nic_irq) {
+		cpqhp_nic_irq = ctrl->cfgspc_irq;
+	}
+
+	if (!cpqhp_disk_irq) {
+		cpqhp_disk_irq = ctrl->cfgspc_irq;
+	}
+
+	dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq);
+
+	rc = compaq_nvram_load(rom_start, ctrl);
+	if (rc)
+		return rc;
+
+	one_slot = rom_resource_table + sizeof (struct hrt);
+
+	i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
+	dbg("number_of_entries = %d\n", i);
+
+	if (!readb(one_slot + SECONDARY_BUS))
+		return 1;
+
+	dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n");
+
+	while (i && readb(one_slot + SECONDARY_BUS)) {
+		u8 dev_func = readb(one_slot + DEV_FUNC);
+		u8 primary_bus = readb(one_slot + PRIMARY_BUS);
+		u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
+		u8 max_bus = readb(one_slot + MAX_BUS);
+		u16 io_base = readw(one_slot + IO_BASE);
+		u16 io_length = readw(one_slot + IO_LENGTH);
+		u16 mem_base = readw(one_slot + MEM_BASE);
+		u16 mem_length = readw(one_slot + MEM_LENGTH);
+		u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
+		u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
+
+		dbg("%2.2x | %4.4x  | %4.4x | %4.4x   | %4.4x | %4.4x   | %4.4x |%2.2x %2.2x %2.2x\n",
+		    dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
+		    primary_bus, secondary_bus, max_bus);
+
+		// If this entry isn't for our controller's bus, ignore it
+		if (primary_bus != ctrl->bus) {
+			i--;
+			one_slot += sizeof (struct slot_rt);
+			continue;
+		}
+		// find out if this entry is for an occupied slot
+		ctrl->pci_bus->number = primary_bus;
+		pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
+		dbg("temp_D_word = %x\n", temp_dword);
+
+		if (temp_dword != 0xFFFFFFFF) {
+			index = 0;
+			func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0);
+
+			while (func && (func->function != (dev_func & 0x07))) {
+				dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index);
+				func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++);
+			}
+
+			// If we can't find a match, skip this table entry
+			if (!func) {
+				i--;
+				one_slot += sizeof (struct slot_rt);
+				continue;
+			}
+			// this may not work and shouldn't be used
+			if (secondary_bus != primary_bus)
+				bridged_slot = 1;
+			else
+				bridged_slot = 0;
+
+			populated_slot = 1;
+		} else {
+			populated_slot = 0;
+			bridged_slot = 0;
+		}
+
+
+		// If we've got a valid IO base, use it
+
+		temp_dword = io_base + io_length;
+
+		if ((io_base) && (temp_dword < 0x10000)) {
+			io_node = kmalloc(sizeof(*io_node), GFP_KERNEL);
+			if (!io_node)
+				return -ENOMEM;
+
+			io_node->base = io_base;
+			io_node->length = io_length;
+
+			dbg("found io_node(base, length) = %x, %x\n",
+					io_node->base, io_node->length);
+			dbg("populated slot =%d \n", populated_slot);
+			if (!populated_slot) {
+				io_node->next = ctrl->io_head;
+				ctrl->io_head = io_node;
+			} else {
+				io_node->next = func->io_head;
+				func->io_head = io_node;
+			}
+		}
+
+		// If we've got a valid memory base, use it
+		temp_dword = mem_base + mem_length;
+		if ((mem_base) && (temp_dword < 0x10000)) {
+			mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL);
+			if (!mem_node)
+				return -ENOMEM;
+
+			mem_node->base = mem_base << 16;
+
+			mem_node->length = mem_length << 16;
+
+			dbg("found mem_node(base, length) = %x, %x\n",
+					mem_node->base, mem_node->length);
+			dbg("populated slot =%d \n", populated_slot);
+			if (!populated_slot) {
+				mem_node->next = ctrl->mem_head;
+				ctrl->mem_head = mem_node;
+			} else {
+				mem_node->next = func->mem_head;
+				func->mem_head = mem_node;
+			}
+		}
+
+		// If we've got a valid prefetchable memory base, and
+		// the base + length isn't greater than 0xFFFF
+		temp_dword = pre_mem_base + pre_mem_length;
+		if ((pre_mem_base) && (temp_dword < 0x10000)) {
+			p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL);
+			if (!p_mem_node)
+				return -ENOMEM;
+
+			p_mem_node->base = pre_mem_base << 16;
+
+			p_mem_node->length = pre_mem_length << 16;
+			dbg("found p_mem_node(base, length) = %x, %x\n",
+					p_mem_node->base, p_mem_node->length);
+			dbg("populated slot =%d \n", populated_slot);
+
+			if (!populated_slot) {
+				p_mem_node->next = ctrl->p_mem_head;
+				ctrl->p_mem_head = p_mem_node;
+			} else {
+				p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = p_mem_node;
+			}
+		}
+
+		// If we've got a valid bus number, use it
+		// The second condition is to ignore bus numbers on
+		// populated slots that don't have PCI-PCI bridges
+		if (secondary_bus && (secondary_bus != primary_bus)) {
+			bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node->base = secondary_bus;
+			bus_node->length = max_bus - secondary_bus + 1;
+			dbg("found bus_node(base, length) = %x, %x\n",
+					bus_node->base, bus_node->length);
+			dbg("populated slot =%d \n", populated_slot);
+			if (!populated_slot) {
+				bus_node->next = ctrl->bus_head;
+				ctrl->bus_head = bus_node;
+			} else {
+				bus_node->next = func->bus_head;
+				func->bus_head = bus_node;
+			}
+		}
+
+		i--;
+		one_slot += sizeof (struct slot_rt);
+	}
+
+	// If all of the following fail, we don't have any resources for
+	// hot plug add
+	rc = 1;
+	rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
+	rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
+	rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
+	rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
+
+	return rc;
+}
+
+
+/*
+ * cpqhp_return_board_resources
+ *
+ * this routine returns all resources allocated to a board to
+ * the available pool.
+ *
+ * returns 0 if success
+ */
+int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources)
+{
+	int rc = 0;
+	struct pci_resource *node;
+	struct pci_resource *t_node;
+	dbg("%s\n", __FUNCTION__);
+
+	if (!func)
+		return 1;
+
+	node = func->io_head;
+	func->io_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->io_head), node);
+		node = t_node;
+	}
+
+	node = func->mem_head;
+	func->mem_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->mem_head), node);
+		node = t_node;
+	}
+
+	node = func->p_mem_head;
+	func->p_mem_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->p_mem_head), node);
+		node = t_node;
+	}
+
+	node = func->bus_head;
+	func->bus_head = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(&(resources->bus_head), node);
+		node = t_node;
+	}
+
+	rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head));
+	rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head));
+	rc |= cpqhp_resource_sort_and_combine(&(resources->io_head));
+	rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head));
+
+	return rc;
+}
+
+
+/*
+ * cpqhp_destroy_resource_list
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void cpqhp_destroy_resource_list (struct resource_lists * resources)
+{
+	struct pci_resource *res, *tres;
+
+	res = resources->io_head;
+	resources->io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = resources->mem_head;
+	resources->mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = resources->p_mem_head;
+	resources->p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = resources->bus_head;
+	resources->bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
+
+/*
+ * cpqhp_destroy_board_resources
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void cpqhp_destroy_board_resources (struct pci_func * func)
+{
+	struct pci_resource *res, *tres;
+
+	res = func->io_head;
+	func->io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = func->mem_head;
+	func->mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = func->p_mem_head;
+	func->p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+
+	res = func->bus_head;
+	func->bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c
new file mode 100644
index 0000000..41c7971
--- /dev/null
+++ b/drivers/pci/hotplug/cpqphp_sysfs.c
@@ -0,0 +1,143 @@
+/*
+ * Compaq Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include "cpqphp.h"
+
+
+/* A few routines that create sysfs entries for the hot plug controller */
+
+static ssize_t show_ctrl (struct device *dev, char *buf)
+{
+	struct pci_dev *pci_dev;
+	struct controller *ctrl;
+	char * out = buf;
+	int index;
+	struct pci_resource *res;
+
+	pci_dev = container_of (dev, struct pci_dev, dev);
+	ctrl = pci_get_drvdata(pci_dev);
+
+	out += sprintf(buf, "Free resources: memory\n");
+	index = 11;
+	res = ctrl->mem_head;
+	while (res && index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+		res = res->next;
+	}
+	out += sprintf(out, "Free resources: prefetchable memory\n");
+	index = 11;
+	res = ctrl->p_mem_head;
+	while (res && index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+		res = res->next;
+	}
+	out += sprintf(out, "Free resources: IO\n");
+	index = 11;
+	res = ctrl->io_head;
+	while (res && index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+		res = res->next;
+	}
+	out += sprintf(out, "Free resources: bus numbers\n");
+	index = 11;
+	res = ctrl->bus_head;
+	while (res && index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+		res = res->next;
+	}
+
+	return out - buf;
+}
+static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
+
+static ssize_t show_dev (struct device *dev, char *buf)
+{
+	struct pci_dev *pci_dev;
+	struct controller *ctrl;
+	char * out = buf;
+	int index;
+	struct pci_resource *res;
+	struct pci_func *new_slot;
+	struct slot *slot;
+
+	pci_dev = container_of (dev, struct pci_dev, dev);
+	ctrl = pci_get_drvdata(pci_dev);
+
+	slot=ctrl->slot;
+
+	while (slot) {
+		new_slot = cpqhp_slot_find(slot->bus, slot->device, 0);
+		if (!new_slot)
+			break;
+		out += sprintf(out, "assigned resources: memory\n");
+		index = 11;
+		res = new_slot->mem_head;
+		while (res && index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+			res = res->next;
+		}
+		out += sprintf(out, "assigned resources: prefetchable memory\n");
+		index = 11;
+		res = new_slot->p_mem_head;
+		while (res && index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+			res = res->next;
+		}
+		out += sprintf(out, "assigned resources: IO\n");
+		index = 11;
+		res = new_slot->io_head;
+		while (res && index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+			res = res->next;
+		}
+		out += sprintf(out, "assigned resources: bus numbers\n");
+		index = 11;
+		res = new_slot->bus_head;
+		while (res && index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+			res = res->next;
+		}
+		slot=slot->next;
+	}
+
+	return out - buf;
+}
+static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL);
+
+void cpqhp_create_ctrl_files (struct controller *ctrl)
+{
+	device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
+	device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev);
+}
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
new file mode 100644
index 0000000..8e47fa66
--- /dev/null
+++ b/drivers/pci/hotplug/fakephp.c
@@ -0,0 +1,358 @@
+/*
+ * Fake PCI Hot Plug Controller Driver
+ *
+ * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2003 IBM Corp.
+ * Copyright (C) 2003 Rolf Eike Beer <eike-kernel@sf-tec.de>
+ *
+ * Based on ideas and code from:
+ * 	Vladimir Kondratiev <vladimir.kondratiev@intel.com>
+ *	Rolf Eike Beer <eike-kernel@sf-tec.de>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * Send feedback to <greg@kroah.com>
+ */
+
+/*
+ *
+ * This driver will "emulate" removing PCI devices from the system.  If
+ * the "power" file is written to with "0" then the specified PCI device
+ * will be completely removed from the kernel.
+ *
+ * WARNING, this does NOT turn off the power to the PCI device.  This is
+ * a "logical" removal, not a physical or electrical removal.
+ *
+ * Use this module at your own risk, you have been warned!
+ *
+ * Enabling PCI devices is left as an exercise for the reader...
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+#include "../pci.h"
+
+#if !defined(MODULE)
+	#define MY_NAME	"fakephp"
+#else
+	#define MY_NAME	THIS_MODULE->name
+#endif
+
+#define dbg(format, arg...)					\
+	do {							\
+		if (debug)					\
+			printk(KERN_DEBUG "%s: " format,	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <greg@kroah.com>"
+#define DRIVER_DESC	"Fake PCI Hot Plug Controller Driver"
+
+struct dummy_slot {
+	struct list_head node;
+	struct hotplug_slot *slot;
+	struct pci_dev *dev;
+};
+
+static int debug;
+static LIST_HEAD(slot_list);
+
+static int enable_slot (struct hotplug_slot *slot);
+static int disable_slot (struct hotplug_slot *slot);
+
+static struct hotplug_slot_ops dummy_hotplug_slot_ops = {
+	.owner			= THIS_MODULE,
+	.enable_slot		= enable_slot,
+	.disable_slot		= disable_slot,
+};
+
+static void dummy_release(struct hotplug_slot *slot)
+{
+	struct dummy_slot *dslot = slot->private;
+
+	list_del(&dslot->node);
+	kfree(dslot->slot->info);
+	kfree(dslot->slot);
+	pci_dev_put(dslot->dev);
+	kfree(dslot);
+}
+
+static int add_slot(struct pci_dev *dev)
+{
+	struct dummy_slot *dslot;
+	struct hotplug_slot *slot;
+	int retval = -ENOMEM;
+
+	slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
+	if (!slot)
+		goto error;
+	memset(slot, 0, sizeof(*slot));
+
+	slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+	if (!slot->info)
+		goto error_slot;
+	memset(slot->info, 0, sizeof(struct hotplug_slot_info));
+
+	slot->info->power_status = 1;
+	slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
+	slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
+
+	slot->name = &dev->dev.bus_id[0];
+	dbg("slot->name = %s\n", slot->name);
+
+	dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
+	if (!dslot)
+		goto error_info;
+
+	slot->ops = &dummy_hotplug_slot_ops;
+	slot->release = &dummy_release;
+	slot->private = dslot;
+
+	retval = pci_hp_register(slot);
+	if (retval) {
+		err("pci_hp_register failed with error %d\n", retval);
+		goto error_dslot;
+	}
+
+	dslot->slot = slot;
+	dslot->dev = pci_dev_get(dev);
+	list_add (&dslot->node, &slot_list);
+	return retval;
+
+error_dslot:
+	kfree(dslot);
+error_info:
+	kfree(slot->info);
+error_slot:
+	kfree(slot);
+error:
+	return retval;
+}
+
+static int __init pci_scan_buses(void)
+{
+	struct pci_dev *dev = NULL;
+	int retval = 0;
+
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		retval = add_slot(dev);
+		if (retval) {
+			pci_dev_put(dev);
+			break;
+		}
+	}
+
+	return retval;
+}
+
+static void remove_slot(struct dummy_slot *dslot)
+{
+	int retval;
+
+	dbg("removing slot %s\n", dslot->slot->name);
+	retval = pci_hp_deregister(dslot->slot);
+	if (retval)
+		err("Problem unregistering a slot %s\n", dslot->slot->name);
+}
+
+/**
+ * Rescan slot.
+ * Tries hard not to re-enable already existing devices
+ * also handles scanning of subfunctions
+ *
+ * @param temp   Device template. Should be set: bus and devfn.
+ */
+static void pci_rescan_slot(struct pci_dev *temp)
+{
+	struct pci_bus *bus = temp->bus;
+	struct pci_dev *dev;
+	int func;
+	u8 hdr_type;
+	if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
+		temp->hdr_type = hdr_type & 0x7f;
+		if (!pci_find_slot(bus->number, temp->devfn)) {
+			dev = pci_scan_single_device(bus, temp->devfn);
+			if (dev) {
+				dbg("New device on %s function %x:%x\n",
+					bus->name, temp->devfn >> 3,
+					temp->devfn & 7);
+				pci_bus_add_device(dev);
+				add_slot(dev);
+			}
+		}
+		/* multifunction device? */
+		if (!(hdr_type & 0x80))
+			return;
+
+		/* continue scanning for other functions */
+		for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) {
+			if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
+				continue;
+			temp->hdr_type = hdr_type & 0x7f;
+
+			if (!pci_find_slot(bus->number, temp->devfn)) {
+				dev = pci_scan_single_device(bus, temp->devfn);
+				if (dev) {
+					dbg("New device on %s function %x:%x\n",
+						bus->name, temp->devfn >> 3,
+						temp->devfn & 7);
+					pci_bus_add_device(dev);
+					add_slot(dev);
+				}
+			}
+		}
+	}
+}
+
+
+/**
+ * Rescan PCI bus.
+ * call pci_rescan_slot for each possible function of the bus
+ *
+ * @param bus
+ */
+static void pci_rescan_bus(const struct pci_bus *bus)
+{
+	unsigned int devfn;
+	struct pci_dev *dev;
+	dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	if (!dev)
+		return;
+
+	memset(dev, 0, sizeof(dev));
+	dev->bus = (struct pci_bus*)bus;
+	dev->sysdata = bus->sysdata;
+	for (devfn = 0; devfn < 0x100; devfn += 8) {
+		dev->devfn = devfn;
+		pci_rescan_slot(dev);
+	}
+	kfree(dev);
+}
+
+/* recursively scan all buses */
+static void pci_rescan_buses(const struct list_head *list)
+{
+	const struct list_head *l;
+	list_for_each(l,list) {
+		const struct pci_bus *b = pci_bus_b(l);
+		pci_rescan_bus(b);
+		pci_rescan_buses(&b->children);
+	}
+}
+
+/* initiate rescan of all pci buses */
+static inline void pci_rescan(void) {
+	pci_rescan_buses(&pci_root_buses);
+}
+
+
+static int enable_slot(struct hotplug_slot *hotplug_slot)
+{
+	/* mis-use enable_slot for rescanning of the pci bus */
+	pci_rescan();
+	return -ENODEV;
+}
+
+/* find the hotplug_slot for the pci_dev */
+static struct hotplug_slot *get_slot_from_dev(struct pci_dev *dev)
+{
+	struct dummy_slot *dslot;
+
+	list_for_each_entry(dslot, &slot_list, node) {
+		if (dslot->dev == dev)
+			return dslot->slot;
+	}
+	return NULL;
+}
+
+
+static int disable_slot(struct hotplug_slot *slot)
+{
+	struct dummy_slot *dslot;
+	struct hotplug_slot *hslot;
+	struct pci_dev *dev;
+	int func;
+
+	if (!slot)
+		return -ENODEV;
+	dslot = slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, slot->name);
+
+	/* don't disable bridged devices just yet, we can't handle them easily... */
+	if (dslot->dev->subordinate) {
+		err("Can't remove PCI devices with other PCI devices behind it yet.\n");
+		return -ENODEV;
+	}
+	/* search for subfunctions and disable them first */
+	if (!(dslot->dev->devfn & 7)) {
+		for (func = 1; func < 8; func++) {
+			dev = pci_find_slot(dslot->dev->bus->number,
+					dslot->dev->devfn + func);
+			if (dev) {
+				hslot = get_slot_from_dev(dev);
+				if (hslot)
+					disable_slot(hslot);
+				else {
+					err("Hotplug slot not found for subfunction of PCI device\n");
+					return -ENODEV;
+				}
+			} else
+				dbg("No device in slot found\n");
+		}
+	}
+
+	/* remove the device from the pci core */
+	pci_remove_bus_device(dslot->dev);
+
+	/* blow away this sysfs entry and other parts. */
+	remove_slot(dslot);
+
+	return 0;
+}
+
+static void cleanup_slots (void)
+{
+	struct list_head *tmp;
+	struct list_head *next;
+	struct dummy_slot *dslot;
+
+	list_for_each_safe (tmp, next, &slot_list) {
+		dslot = list_entry (tmp, struct dummy_slot, node);
+		remove_slot(dslot);
+	}
+	
+}
+
+static int __init dummyphp_init(void)
+{
+	info(DRIVER_DESC "\n");
+
+	return pci_scan_buses();
+}
+
+
+static void __exit dummyphp_exit(void)
+{
+	cleanup_slots();
+}
+
+module_init(dummyphp_init);
+module_exit(dummyphp_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h
new file mode 100644
index 0000000..5bc039d
--- /dev/null
+++ b/drivers/pci/hotplug/ibmphp.h
@@ -0,0 +1,763 @@
+#ifndef __IBMPHP_H
+#define __IBMPHP_H
+
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation
+ *
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2003 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include "pci_hotplug.h"
+
+extern int ibmphp_debug;
+
+#if !defined(MODULE)
+	#define MY_NAME "ibmphpd"
+#else
+	#define MY_NAME THIS_MODULE->name
+#endif
+#define debug(fmt, arg...) do { if (ibmphp_debug == 1) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
+#define debug_pci(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
+
+
+/* EBDA stuff */
+
+/***********************************************************
+* SLOT CAPABILITY                                          *
+***********************************************************/
+
+#define EBDA_SLOT_133_MAX		0x20
+#define EBDA_SLOT_100_MAX		0x10
+#define EBDA_SLOT_66_MAX		0x02
+#define EBDA_SLOT_PCIX_CAP		0x08
+
+
+/************************************************************
+*  RESOURE TYPE                                             *
+************************************************************/
+
+#define EBDA_RSRC_TYPE_MASK		0x03
+#define EBDA_IO_RSRC_TYPE		0x00
+#define EBDA_MEM_RSRC_TYPE		0x01
+#define EBDA_PFM_RSRC_TYPE		0x03
+#define EBDA_RES_RSRC_TYPE		0x02
+
+
+/*************************************************************
+*  IO RESTRICTION TYPE                                       *
+*************************************************************/
+
+#define EBDA_IO_RESTRI_MASK		0x0c
+#define EBDA_NO_RESTRI			0x00
+#define EBDA_AVO_VGA_ADDR		0x04
+#define EBDA_AVO_VGA_ADDR_AND_ALIA	0x08
+#define EBDA_AVO_ISA_ADDR		0x0c
+
+
+/**************************************************************
+*  DEVICE TYPE DEF                                            *
+**************************************************************/
+
+#define EBDA_DEV_TYPE_MASK		0x10
+#define EBDA_PCI_DEV			0x10
+#define EBDA_NON_PCI_DEV		0x00
+
+
+/***************************************************************
+*  PRIMARY DEF DEFINITION                                      *
+***************************************************************/
+
+#define EBDA_PRI_DEF_MASK		0x20
+#define EBDA_PRI_PCI_BUS_INFO		0x20
+#define EBDA_NORM_DEV_RSRC_INFO		0x00
+
+
+//--------------------------------------------------------------
+// RIO TABLE DATA STRUCTURE
+//--------------------------------------------------------------
+
+struct rio_table_hdr {
+	u8 ver_num; 
+	u8 scal_count;
+	u8 riodev_count;
+	u16 offset;
+};
+
+//-------------------------------------------------------------
+// SCALABILITY DETAIL
+//-------------------------------------------------------------
+
+struct scal_detail {
+	u8 node_id;
+	u32 cbar;
+	u8 port0_node_connect;
+	u8 port0_port_connect;
+	u8 port1_node_connect;
+	u8 port1_port_connect;
+	u8 port2_node_connect;
+	u8 port2_port_connect;
+	u8 chassis_num;
+//	struct list_head scal_detail_list;
+};
+
+//--------------------------------------------------------------
+// RIO DETAIL 
+//--------------------------------------------------------------
+
+struct rio_detail {
+	u8 rio_node_id;
+	u32 bbar;
+	u8 rio_type;
+	u8 owner_id;
+	u8 port0_node_connect;
+	u8 port0_port_connect;
+	u8 port1_node_connect;
+	u8 port1_port_connect;
+	u8 first_slot_num;
+	u8 status;
+	u8 wpindex;
+	u8 chassis_num;
+	struct list_head rio_detail_list;
+};
+
+struct opt_rio {
+	u8 rio_type;
+	u8 chassis_num;
+	u8 first_slot_num;
+	u8 middle_num;
+	struct list_head opt_rio_list;
+};	
+
+struct opt_rio_lo {
+	u8 rio_type;
+	u8 chassis_num;
+	u8 first_slot_num;
+	u8 middle_num;
+	u8 pack_count;
+	struct list_head opt_rio_lo_list;
+};	
+
+/****************************************************************
+*  HPC DESCRIPTOR NODE                                          *
+****************************************************************/
+
+struct ebda_hpc_list {
+	u8 format;
+	u16 num_ctlrs;
+	short phys_addr;
+//      struct list_head ebda_hpc_list;
+};
+/*****************************************************************
+*   IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS           *
+*   STRUCTURE                                                    *
+*****************************************************************/
+
+struct ebda_hpc_slot {
+	u8 slot_num;
+	u32 slot_bus_num;
+	u8 ctl_index;
+	u8 slot_cap;
+};
+
+struct ebda_hpc_bus {
+	u32 bus_num;
+	u8 slots_at_33_conv;
+	u8 slots_at_66_conv;
+	u8 slots_at_66_pcix;
+	u8 slots_at_100_pcix;
+	u8 slots_at_133_pcix;
+};
+
+
+/********************************************************************
+*   THREE TYPE OF HOT PLUG CONTROLER                                *
+********************************************************************/
+
+struct isa_ctlr_access {
+	u16 io_start;
+	u16 io_end;
+};
+
+struct pci_ctlr_access {
+	u8 bus;
+	u8 dev_fun;
+};
+
+struct wpeg_i2c_ctlr_access {
+	ulong wpegbbar;
+	u8 i2c_addr;
+};
+
+#define HPC_DEVICE_ID		0x0246
+#define HPC_SUBSYSTEM_ID	0x0247
+#define HPC_PCI_OFFSET		0x40
+/*************************************************************************
+*   RSTC DESCRIPTOR NODE                                                 *
+*************************************************************************/
+
+struct ebda_rsrc_list {
+	u8 format;
+	u16 num_entries;
+	u16 phys_addr;
+	struct ebda_rsrc_list *next;
+};
+
+
+/***************************************************************************
+*   PCI RSRC NODE                                                          *
+***************************************************************************/
+
+struct ebda_pci_rsrc {
+	u8 rsrc_type;
+	u8 bus_num;
+	u8 dev_fun;
+	u32 start_addr;
+	u32 end_addr;
+	u8 marked;	/* for NVRAM */
+	struct list_head ebda_pci_rsrc_list;
+};
+
+
+/***********************************************************
+* BUS_INFO DATE STRUCTURE                                  *
+***********************************************************/
+
+struct bus_info {
+	u8 slot_min;
+	u8 slot_max;
+	u8 slot_count;
+	u8 busno;
+	u8 controller_id;
+	u8 current_speed;
+	u8 current_bus_mode;
+	u8 index;
+	u8 slots_at_33_conv;
+	u8 slots_at_66_conv;
+	u8 slots_at_66_pcix;
+	u8 slots_at_100_pcix;
+	u8 slots_at_133_pcix;
+	struct list_head bus_info_list;
+};
+
+
+/***********************************************************
+* GLOBAL VARIABLES                                         *
+***********************************************************/
+extern struct list_head ibmphp_ebda_pci_rsrc_head;
+extern struct list_head ibmphp_slot_head;
+/***********************************************************
+* FUNCTION PROTOTYPES                                      *
+***********************************************************/
+
+extern void ibmphp_free_ebda_hpc_queue (void);
+extern int ibmphp_access_ebda (void);
+extern struct slot *ibmphp_get_slot_from_physical_num (u8);
+extern int ibmphp_get_total_hp_slots (void);
+extern void ibmphp_free_ibm_slot (struct slot *);
+extern void ibmphp_free_bus_info_queue (void);
+extern void ibmphp_free_ebda_pci_rsrc_queue (void);
+extern struct bus_info *ibmphp_find_same_bus_num (u32);
+extern int ibmphp_get_bus_index (u8);
+extern u16 ibmphp_get_total_controllers (void);
+extern int ibmphp_register_pci (void);
+
+/* passed parameters */
+#define MEM		0
+#define IO		1
+#define PFMEM		2
+
+/* bit masks */
+#define RESTYPE		0x03
+#define IOMASK		0x00	/* will need to take its complement */
+#define MMASK		0x01
+#define PFMASK		0x03
+#define PCIDEVMASK	0x10	/* we should always have PCI devices */
+#define PRIMARYBUSMASK	0x20
+
+/* pci specific defines */
+#define PCI_VENDOR_ID_NOTVALID		0xFFFF
+#define PCI_HEADER_TYPE_MULTIDEVICE	0x80
+#define PCI_HEADER_TYPE_MULTIBRIDGE	0x81
+
+#define LATENCY		0x64
+#define CACHE		64
+#define DEVICEENABLE	0x015F		/* CPQ has 0x0157 */
+
+#define IOBRIDGE	0x1000		/* 4k */
+#define MEMBRIDGE	0x100000	/* 1M */
+
+/* irqs */
+#define SCSI_IRQ	0x09
+#define LAN_IRQ		0x0A
+#define OTHER_IRQ	0x0B
+
+/* Data Structures */
+
+/* type is of the form x x xx xx
+ *                     | |  |  |_ 00 - I/O, 01 - Memory, 11 - PFMemory
+ *                     | |  - 00 - No Restrictions, 01 - Avoid VGA, 10 - Avoid
+ *                     | |    VGA and their aliases, 11 - Avoid ISA
+ *                     | - 1 - PCI device, 0 - non pci device
+ *                     - 1 - Primary PCI Bus Information (0 if Normal device)
+ * the IO restrictions [2:3] are only for primary buses
+ */
+
+
+/* we need this struct because there could be several resource blocks
+ * allocated per primary bus in the EBDA
+ */
+struct range_node {
+	int rangeno;
+	u32 start;
+	u32 end;
+	struct range_node *next;
+};
+
+struct bus_node {
+	u8 busno;
+	int noIORanges;
+	struct range_node *rangeIO;
+	int noMemRanges;
+	struct range_node *rangeMem;
+	int noPFMemRanges;
+	struct range_node *rangePFMem;
+	int needIOUpdate;
+	int needMemUpdate;
+	int needPFMemUpdate;
+	struct resource_node *firstIO;	/* first IO resource on the Bus */
+	struct resource_node *firstMem;	/* first memory resource on the Bus */
+	struct resource_node *firstPFMem;	/* first prefetchable memory resource on the Bus */
+	struct resource_node *firstPFMemFromMem;	/* when run out of pfmem available, taking from Mem */
+	struct list_head bus_list;
+};
+
+struct resource_node {
+	int rangeno;
+	u8 busno;
+	u8 devfunc;
+	u32 start;
+	u32 end;
+	u32 len;
+	int type;		/* MEM, IO, PFMEM */
+	u8 fromMem;		/* this is to indicate that the range is from
+				 * from the Memory bucket rather than from PFMem */
+	struct resource_node *next;
+	struct resource_node *nextRange;	/* for the other mem range on bus */
+};
+
+struct res_needed {
+	u32 mem;
+	u32 pfmem;
+	u32 io;
+	u8 not_correct;		/* needed for return */
+	int devices[32];	/* for device numbers behind this bridge */
+};
+
+/* functions */
+
+extern int ibmphp_rsrc_init (void);
+extern int ibmphp_add_resource (struct resource_node *);
+extern int ibmphp_remove_resource (struct resource_node *);
+extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int);
+extern int ibmphp_check_resource (struct resource_node *, u8);
+extern int ibmphp_remove_bus (struct bus_node *, u8);
+extern void ibmphp_free_resources (void);
+extern int ibmphp_add_pfmem_from_mem (struct resource_node *);
+extern struct bus_node *ibmphp_find_res_bus (u8);
+extern void ibmphp_print_test (void);	/* for debugging purposes */
+
+extern void ibmphp_hpc_initvars (void);
+extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *);
+extern int ibmphp_hpc_writeslot (struct slot *, u8);
+extern void ibmphp_lock_operations (void);
+extern void ibmphp_unlock_operations (void);
+extern int ibmphp_hpc_start_poll_thread (void);
+extern void ibmphp_hpc_stop_poll_thread (void);
+
+//----------------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------
+// HPC return codes
+//----------------------------------------------------------------------------
+#define FALSE				0x00
+#define TRUE				0x01
+#define HPC_ERROR			0xFF
+
+//-----------------------------------------------------------------------------
+// BUS INFO
+//-----------------------------------------------------------------------------
+#define BUS_SPEED			0x30
+#define BUS_MODE			0x40
+#define BUS_MODE_PCIX			0x01
+#define BUS_MODE_PCI			0x00
+#define BUS_SPEED_2			0x20
+#define BUS_SPEED_1			0x10
+#define BUS_SPEED_33			0x00
+#define BUS_SPEED_66			0x01
+#define BUS_SPEED_100			0x02
+#define BUS_SPEED_133			0x03
+#define BUS_SPEED_66PCIX		0x04
+#define BUS_SPEED_66UNKNOWN		0x05
+#define BUS_STATUS_AVAILABLE		0x01
+#define BUS_CONTROL_AVAILABLE		0x02
+#define SLOT_LATCH_REGS_SUPPORTED	0x10
+
+#define PRGM_MODEL_REV_LEVEL		0xF0
+#define MAX_ADAPTER_NONE		0x09
+
+//----------------------------------------------------------------------------
+// HPC 'write' operations/commands
+//----------------------------------------------------------------------------
+//	Command			Code	State	Write to reg
+//					Machine	at index
+//-------------------------	----	-------	------------
+#define HPC_CTLR_ENABLEIRQ	0x00	// N	15
+#define HPC_CTLR_DISABLEIRQ	0x01	// N	15
+#define HPC_SLOT_OFF		0x02	// Y	0-14
+#define HPC_SLOT_ON		0x03	// Y	0-14
+#define HPC_SLOT_ATTNOFF	0x04	// N	0-14
+#define HPC_SLOT_ATTNON		0x05	// N	0-14
+#define HPC_CTLR_CLEARIRQ	0x06	// N	15
+#define HPC_CTLR_RESET		0x07	// Y	15
+#define HPC_CTLR_IRQSTEER	0x08	// N	15
+#define HPC_BUS_33CONVMODE	0x09	// Y	31-34
+#define HPC_BUS_66CONVMODE	0x0A	// Y	31-34
+#define HPC_BUS_66PCIXMODE	0x0B	// Y	31-34
+#define HPC_BUS_100PCIXMODE	0x0C	// Y	31-34
+#define HPC_BUS_133PCIXMODE	0x0D	// Y	31-34
+#define HPC_ALLSLOT_OFF		0x11	// Y	15
+#define HPC_ALLSLOT_ON		0x12	// Y	15
+#define HPC_SLOT_BLINKLED	0x13	// N	0-14
+
+//----------------------------------------------------------------------------
+// read commands
+//----------------------------------------------------------------------------
+#define READ_SLOTSTATUS		0x01
+#define READ_EXTSLOTSTATUS	0x02
+#define READ_BUSSTATUS		0x03
+#define READ_CTLRSTATUS		0x04
+#define READ_ALLSTAT		0x05
+#define READ_ALLSLOT		0x06
+#define READ_SLOTLATCHLOWREG	0x07
+#define READ_REVLEVEL		0x08
+#define READ_HPCOPTIONS		0x09
+//----------------------------------------------------------------------------
+// slot status
+//----------------------------------------------------------------------------
+#define HPC_SLOT_POWER		0x01
+#define HPC_SLOT_CONNECT	0x02
+#define HPC_SLOT_ATTN		0x04
+#define HPC_SLOT_PRSNT2		0x08
+#define HPC_SLOT_PRSNT1		0x10
+#define HPC_SLOT_PWRGD		0x20
+#define HPC_SLOT_BUS_SPEED	0x40
+#define HPC_SLOT_LATCH		0x80
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_POWER status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_POWER_OFF	0x00
+#define HPC_SLOT_POWER_ON	0x01
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_CONNECT status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_CONNECTED	0x00
+#define HPC_SLOT_DISCONNECTED	0x01
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_ATTN status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_ATTN_OFF	0x00
+#define HPC_SLOT_ATTN_ON	0x01
+#define HPC_SLOT_ATTN_BLINK	0x02
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_PRSNT status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_EMPTY		0x00
+#define HPC_SLOT_PRSNT_7	0x01
+#define HPC_SLOT_PRSNT_15	0x02
+#define HPC_SLOT_PRSNT_25	0x03
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_PWRGD status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_PWRGD_FAULT_NONE	0x00
+#define HPC_SLOT_PWRGD_GOOD		0x01
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_BUS_SPEED status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_BUS_SPEED_OK	0x00
+#define HPC_SLOT_BUS_SPEED_MISM	0x01
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_LATCH status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_LATCH_OPEN	0x01	// NOTE : in PCI spec bit off = open
+#define HPC_SLOT_LATCH_CLOSED	0x00	// NOTE : in PCI spec bit on  = closed
+
+
+//----------------------------------------------------------------------------
+// extended slot status
+//----------------------------------------------------------------------------
+#define HPC_SLOT_PCIX		0x01
+#define HPC_SLOT_SPEED1		0x02
+#define HPC_SLOT_SPEED2		0x04
+#define HPC_SLOT_BLINK_ATTN	0x08
+#define HPC_SLOT_RSRVD1		0x10
+#define HPC_SLOT_RSRVD2		0x20
+#define HPC_SLOT_BUS_MODE	0x40
+#define HPC_SLOT_RSRVD3		0x80
+
+//----------------------------------------------------------------------------
+// HPC_XSLOT_PCIX_CAP status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_PCIX_NO	0x00
+#define HPC_SLOT_PCIX_YES	0x01
+
+//----------------------------------------------------------------------------
+// HPC_XSLOT_SPEED status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_SPEED_33	0x00
+#define HPC_SLOT_SPEED_66	0x01
+#define HPC_SLOT_SPEED_133	0x02
+
+//----------------------------------------------------------------------------
+// HPC_XSLOT_ATTN_BLINK status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_ATTN_BLINK_OFF	0x00
+#define HPC_SLOT_ATTN_BLINK_ON	0x01
+
+//----------------------------------------------------------------------------
+// HPC_XSLOT_BUS_MODE status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_BUS_MODE_OK	0x00
+#define HPC_SLOT_BUS_MODE_MISM	0x01
+
+//----------------------------------------------------------------------------
+// Controller status
+//----------------------------------------------------------------------------
+#define HPC_CTLR_WORKING	0x01
+#define HPC_CTLR_FINISHED	0x02
+#define HPC_CTLR_RESULT0	0x04
+#define HPC_CTLR_RESULT1	0x08
+#define HPC_CTLR_RESULE2	0x10
+#define HPC_CTLR_RESULT3	0x20
+#define HPC_CTLR_IRQ_ROUTG	0x40
+#define HPC_CTLR_IRQ_PENDG	0x80
+
+//----------------------------------------------------------------------------
+// HPC_CTLR_WROKING status return codes
+//----------------------------------------------------------------------------
+#define HPC_CTLR_WORKING_NO	0x00
+#define HPC_CTLR_WORKING_YES	0x01
+
+//----------------------------------------------------------------------------
+// HPC_CTLR_FINISHED status return codes
+//----------------------------------------------------------------------------
+#define HPC_CTLR_FINISHED_NO	0x00
+#define HPC_CTLR_FINISHED_YES	0x01
+
+//----------------------------------------------------------------------------
+// HPC_CTLR_RESULT status return codes
+//----------------------------------------------------------------------------
+#define HPC_CTLR_RESULT_SUCCESS	0x00
+#define HPC_CTLR_RESULT_FAILED	0x01
+#define HPC_CTLR_RESULT_RSVD	0x02
+#define HPC_CTLR_RESULT_NORESP	0x03
+
+
+//----------------------------------------------------------------------------
+// macro for slot info
+//----------------------------------------------------------------------------
+#define SLOT_POWER(s)	((u8) ((s & HPC_SLOT_POWER) \
+	? HPC_SLOT_POWER_ON : HPC_SLOT_POWER_OFF))
+
+#define SLOT_CONNECT(s)	((u8) ((s & HPC_SLOT_CONNECT) \
+	? HPC_SLOT_DISCONNECTED : HPC_SLOT_CONNECTED))
+
+#define SLOT_ATTN(s,es)	((u8) ((es & HPC_SLOT_BLINK_ATTN) \
+	? HPC_SLOT_ATTN_BLINK \
+	: ((s & HPC_SLOT_ATTN) ? HPC_SLOT_ATTN_ON : HPC_SLOT_ATTN_OFF)))
+
+#define SLOT_PRESENT(s)	((u8) ((s & HPC_SLOT_PRSNT1) \
+	? ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_EMPTY : HPC_SLOT_PRSNT_15) \
+	: ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_PRSNT_25 : HPC_SLOT_PRSNT_7)))
+
+#define SLOT_PWRGD(s)	((u8) ((s & HPC_SLOT_PWRGD) \
+	? HPC_SLOT_PWRGD_GOOD : HPC_SLOT_PWRGD_FAULT_NONE))
+
+#define SLOT_BUS_SPEED(s)	((u8) ((s & HPC_SLOT_BUS_SPEED) \
+	? HPC_SLOT_BUS_SPEED_MISM : HPC_SLOT_BUS_SPEED_OK))
+
+#define SLOT_LATCH(s)	((u8) ((s & HPC_SLOT_LATCH) \
+	? HPC_SLOT_LATCH_CLOSED : HPC_SLOT_LATCH_OPEN))
+
+#define SLOT_PCIX(es)	((u8) ((es & HPC_SLOT_PCIX) \
+	? HPC_SLOT_PCIX_YES : HPC_SLOT_PCIX_NO))
+
+#define SLOT_SPEED(es)	((u8) ((es & HPC_SLOT_SPEED2) \
+	? ((es & HPC_SLOT_SPEED1) ? HPC_SLOT_SPEED_133   \
+				: HPC_SLOT_SPEED_66)   \
+	: HPC_SLOT_SPEED_33))
+
+#define SLOT_BUS_MODE(es)	((u8) ((es & HPC_SLOT_BUS_MODE) \
+	? HPC_SLOT_BUS_MODE_MISM : HPC_SLOT_BUS_MODE_OK))
+
+//--------------------------------------------------------------------------
+// macro for bus info
+//---------------------------------------------------------------------------
+#define CURRENT_BUS_SPEED(s)	((u8) (s & BUS_SPEED_2) \
+	? ((s & BUS_SPEED_1) ? BUS_SPEED_133 : BUS_SPEED_100) \
+	: ((s & BUS_SPEED_1) ? BUS_SPEED_66 : BUS_SPEED_33))
+
+#define CURRENT_BUS_MODE(s)	((u8) (s & BUS_MODE) ? BUS_MODE_PCIX : BUS_MODE_PCI)
+
+#define READ_BUS_STATUS(s)	((u8) (s->options & BUS_STATUS_AVAILABLE))
+
+#define READ_BUS_MODE(s)	((s->revision & PRGM_MODEL_REV_LEVEL) >= 0x20)
+
+#define SET_BUS_STATUS(s)	((u8) (s->options & BUS_CONTROL_AVAILABLE))
+
+#define READ_SLOT_LATCH(s)	((u8) (s->options & SLOT_LATCH_REGS_SUPPORTED))
+
+//----------------------------------------------------------------------------
+// macro for controller info
+//----------------------------------------------------------------------------
+#define CTLR_WORKING(c) ((u8) ((c & HPC_CTLR_WORKING) \
+	? HPC_CTLR_WORKING_YES : HPC_CTLR_WORKING_NO))
+#define CTLR_FINISHED(c) ((u8) ((c & HPC_CTLR_FINISHED) \
+	? HPC_CTLR_FINISHED_YES : HPC_CTLR_FINISHED_NO))
+#define CTLR_RESULT(c) ((u8) ((c & HPC_CTLR_RESULT1)  \
+	? ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_NORESP \
+				: HPC_CTLR_RESULT_RSVD)  \
+	: ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_FAILED \
+				: HPC_CTLR_RESULT_SUCCESS)))
+
+// command that affect the state machine of HPC
+#define NEEDTOCHECK_CMDSTATUS(c) ((c == HPC_SLOT_OFF)        || \
+				  (c == HPC_SLOT_ON)         || \
+				  (c == HPC_CTLR_RESET)      || \
+				  (c == HPC_BUS_33CONVMODE)  || \
+				  (c == HPC_BUS_66CONVMODE)  || \
+				  (c == HPC_BUS_66PCIXMODE)  || \
+				  (c == HPC_BUS_100PCIXMODE) || \
+				  (c == HPC_BUS_133PCIXMODE) || \
+				  (c == HPC_ALLSLOT_OFF)     || \
+				  (c == HPC_ALLSLOT_ON))
+
+
+/* Core part of the driver */
+
+#define ENABLE		1
+#define DISABLE		0
+
+#define CARD_INFO	0x07
+#define PCIX133		0x07
+#define PCIX66		0x05
+#define PCI66		0x04
+
+extern struct pci_bus *ibmphp_pci_bus;
+
+/* Variables */
+
+struct pci_func {
+	struct pci_dev *dev;	/* from the OS */
+	u8 busno;
+	u8 device;
+	u8 function;
+	struct resource_node *io[6];
+	struct resource_node *mem[6];
+	struct resource_node *pfmem[6];
+	struct pci_func *next;
+	int devices[32];	/* for bridge config */
+	u8 irq[4];		/* for interrupt config */
+	u8 bus;			/* flag for unconfiguring, to say if PPB */
+};
+
+struct slot {
+	u8 bus;
+	u8 device;
+	u8 number;
+	u8 real_physical_slot_num;
+	char name[100];
+	u32 capabilities;
+	u8 supported_speed;
+	u8 supported_bus_mode;
+	struct hotplug_slot *hotplug_slot;
+	struct controller *ctrl;
+	struct pci_func *func;
+	u8 irq[4];
+	u8 flag;		/* this is for disable slot and polling */
+	int bit_mode;		/* 0 = 32, 1 = 64 */
+	u8 ctlr_index;
+	struct bus_info *bus_on;
+	struct list_head ibm_slot_list;
+	u8 status;
+	u8 ext_status;
+	u8 busstatus;
+};
+
+struct controller {
+	struct ebda_hpc_slot *slots;
+	struct ebda_hpc_bus *buses;
+	struct pci_dev *ctrl_dev; /* in case where controller is PCI */
+	u8 starting_slot_num;	/* starting and ending slot #'s this ctrl controls*/
+	u8 ending_slot_num;
+	u8 revision;
+	u8 options;		/* which options HPC supports */
+	u8 status;
+	u8 ctlr_id;
+	u8 slot_count;
+	u8 bus_count;
+	u8 ctlr_relative_id;
+	u32 irq;
+	union {
+		struct isa_ctlr_access isa_ctlr;
+		struct pci_ctlr_access pci_ctlr;
+		struct wpeg_i2c_ctlr_access wpeg_ctlr;
+	} u;
+	u8 ctlr_type;
+	struct list_head ebda_hpc_list;
+};
+
+/* Functions */
+
+extern int ibmphp_init_devno (struct slot **);	/* This function is called from EBDA, so we need it not be static */
+extern int ibmphp_do_disable_slot (struct slot *slot_cur);
+extern int ibmphp_update_slot_info (struct slot *);	/* This function is called from HPC, so we need it to not be be static */
+extern int ibmphp_configure_card (struct pci_func *, u8);
+extern int ibmphp_unconfigure_card (struct slot **, int);
+extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops;
+
+#endif				//__IBMPHP_H
+
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
new file mode 100644
index 0000000..0392e00
--- /dev/null
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -0,0 +1,1422 @@
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation
+ *
+ * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2003 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include "../pci.h"
+#include "../../../arch/i386/pci/pci.h"	/* for struct irq_routing_table */
+#include "ibmphp.h"
+
+#define attn_on(sl)  ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON)
+#define attn_off(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNOFF)
+#define attn_LED_blink(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_BLINKLED)
+#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
+#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
+
+#define DRIVER_VERSION	"0.6"
+#define DRIVER_DESC	"IBM Hot Plug PCI Controller Driver"
+
+int ibmphp_debug;
+
+static int debug;
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC (debug, "Debugging mode enabled or not");
+MODULE_LICENSE ("GPL");
+MODULE_DESCRIPTION (DRIVER_DESC);
+
+struct pci_bus *ibmphp_pci_bus;
+static int max_slots;
+
+static int irqs[16];    /* PIC mode IRQ's we're using so far (in case MPS
+			 * tables don't provide default info for empty slots */
+
+static int init_flag;
+
+/*
+static int get_max_adapter_speed_1 (struct hotplug_slot *, u8 *, u8);
+
+static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value)
+{
+	return get_max_adapter_speed_1 (hs, value, 1);
+}
+*/
+static inline int get_cur_bus_info(struct slot **sl) 
+{
+	int rc = 1;
+	struct slot * slot_cur = *sl;
+
+	debug("options = %x\n", slot_cur->ctrl->options);
+	debug("revision = %x\n", slot_cur->ctrl->revision);	
+
+	if (READ_BUS_STATUS(slot_cur->ctrl)) 
+		rc = ibmphp_hpc_readslot(slot_cur, READ_BUSSTATUS, NULL);
+	
+	if (rc) 
+		return rc;
+	  
+	slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED(slot_cur->busstatus);
+	if (READ_BUS_MODE(slot_cur->ctrl))
+		slot_cur->bus_on->current_bus_mode =
+				CURRENT_BUS_MODE(slot_cur->busstatus);
+	else
+		slot_cur->bus_on->current_bus_mode = 0xFF;
+
+	debug("busstatus = %x, bus_speed = %x, bus_mode = %x\n",
+			slot_cur->busstatus,
+			slot_cur->bus_on->current_speed,
+			slot_cur->bus_on->current_bus_mode);
+	
+	*sl = slot_cur;
+	return 0;
+}
+
+static inline int slot_update(struct slot **sl)
+{
+	int rc;
+ 	rc = ibmphp_hpc_readslot(*sl, READ_ALLSTAT, NULL);
+	if (rc) 
+		return rc;
+	if (!init_flag)
+		rc = get_cur_bus_info(sl);
+	return rc;
+}
+
+static int __init get_max_slots (void)
+{
+	struct slot * slot_cur;
+	struct list_head * tmp;
+	u8 slot_count = 0;
+
+	list_for_each(tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry(tmp, struct slot, ibm_slot_list);
+		/* sometimes the hot-pluggable slots start with 4 (not always from 1) */
+		slot_count = max(slot_count, slot_cur->number);
+	}
+	return slot_count;
+}
+
+/* This routine will put the correct slot->device information per slot.  It's
+ * called from initialization of the slot structures. It will also assign
+ * interrupt numbers per each slot.
+ * Parameters: struct slot
+ * Returns 0 or errors
+ */
+int ibmphp_init_devno(struct slot **cur_slot)
+{
+	struct irq_routing_table *rtable;
+	int len;
+	int loop;
+	int i;
+
+	rtable = pcibios_get_irq_routing_table();
+	if (!rtable) {
+		err("no BIOS routing table...\n");
+		return -ENOMEM;
+	}
+
+	len = (rtable->size - sizeof(struct irq_routing_table)) /
+			sizeof(struct irq_info);
+
+	if (!len)
+		return -1;
+	for (loop = 0; loop < len; loop++) {
+		if ((*cur_slot)->number == rtable->slots[loop].slot) {
+		if ((*cur_slot)->bus == rtable->slots[loop].bus) {
+			(*cur_slot)->device = PCI_SLOT(rtable->slots[loop].devfn);
+			for (i = 0; i < 4; i++)
+				(*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector((int) (*cur_slot)->bus,
+						(int) (*cur_slot)->device, i);
+
+				debug("(*cur_slot)->irq[0] = %x\n",
+						(*cur_slot)->irq[0]);
+				debug("(*cur_slot)->irq[1] = %x\n",
+						(*cur_slot)->irq[1]);
+				debug("(*cur_slot)->irq[2] = %x\n",
+						(*cur_slot)->irq[2]);
+				debug("(*cur_slot)->irq[3] = %x\n",
+						(*cur_slot)->irq[3]);
+
+				debug("rtable->exlusive_irqs = %x\n",
+					rtable->exclusive_irqs);
+				debug("rtable->slots[loop].irq[0].bitmap = %x\n",
+					rtable->slots[loop].irq[0].bitmap);
+				debug("rtable->slots[loop].irq[1].bitmap = %x\n",
+					rtable->slots[loop].irq[1].bitmap);
+				debug("rtable->slots[loop].irq[2].bitmap = %x\n",
+					rtable->slots[loop].irq[2].bitmap);
+				debug("rtable->slots[loop].irq[3].bitmap = %x\n",
+					rtable->slots[loop].irq[3].bitmap);
+
+				debug("rtable->slots[loop].irq[0].link = %x\n",
+					rtable->slots[loop].irq[0].link);
+				debug("rtable->slots[loop].irq[1].link = %x\n",
+					rtable->slots[loop].irq[1].link);
+				debug("rtable->slots[loop].irq[2].link = %x\n",
+					rtable->slots[loop].irq[2].link);
+				debug("rtable->slots[loop].irq[3].link = %x\n",
+					rtable->slots[loop].irq[3].link);
+				debug("end of init_devno\n");
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
+
+static inline int power_on(struct slot *slot_cur)
+{
+	u8 cmd = HPC_SLOT_ON;
+	int retval;
+
+	retval = ibmphp_hpc_writeslot(slot_cur, cmd);
+	if (retval) {
+		err("power on failed\n");
+		return retval;
+	}
+	if (CTLR_RESULT(slot_cur->ctrl->status)) {
+		err("command not completed successfully in power_on\n");
+		return -EIO;
+	}
+	msleep(3000);	/* For ServeRAID cards, and some 66 PCI */
+	return 0;
+}
+
+static inline int power_off(struct slot *slot_cur)
+{
+	u8 cmd = HPC_SLOT_OFF;
+	int retval;
+
+	retval = ibmphp_hpc_writeslot(slot_cur, cmd);
+	if (retval) {
+		err("power off failed\n");
+		return retval;
+	}
+	if (CTLR_RESULT(slot_cur->ctrl->status)) {
+		err("command not completed successfully in power_off\n");
+		retval = -EIO;
+	}
+	return retval;
+}
+
+static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
+{
+	int rc = 0;
+	struct slot *pslot;
+	u8 cmd;
+
+	debug("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n",
+			(ulong) hotplug_slot, value);
+	ibmphp_lock_operations();
+	cmd = 0x00;     // avoid compiler warning
+
+	if (hotplug_slot) {
+		switch (value) {
+		case HPC_SLOT_ATTN_OFF:
+			cmd = HPC_SLOT_ATTNOFF;
+			break;
+		case HPC_SLOT_ATTN_ON:
+			cmd = HPC_SLOT_ATTNON;
+			break;
+		case HPC_SLOT_ATTN_BLINK:
+			cmd = HPC_SLOT_BLINKLED;
+			break;
+		default:
+			rc = -ENODEV;
+			err("set_attention_status - Error : invalid input [%x]\n",
+					value);
+			break;
+		}
+		if (rc == 0) {
+			pslot = hotplug_slot->private;
+			if (pslot)
+				rc = ibmphp_hpc_writeslot(pslot, cmd);
+			else
+				rc = -ENODEV;
+		}
+	} else	
+		rc = -ENODEV;
+
+	ibmphp_unlock_operations();
+
+	debug("set_attention_status - Exit rc[%d]\n", rc);
+	return rc;
+}
+
+static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	struct slot myslot;
+
+	debug("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
+					(ulong) hotplug_slot, (ulong) value);
+        
+	ibmphp_lock_operations();
+	if (hotplug_slot && value) {
+		pslot = hotplug_slot->private;
+		if (pslot) {
+			memcpy(&myslot, pslot, sizeof(struct slot));
+			rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
+						&(myslot.status));
+			if (!rc)
+				rc = ibmphp_hpc_readslot(pslot,
+						READ_EXTSLOTSTATUS,
+						&(myslot.ext_status));
+			if (!rc)
+				*value = SLOT_ATTN(myslot.status,
+						myslot.ext_status);
+		}
+	}
+
+	ibmphp_unlock_operations();
+	debug("get_attention_status - Exit rc[%d] value[%x]\n", rc, *value);
+	return rc;
+}
+
+static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	struct slot myslot;
+
+	debug("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
+					(ulong) hotplug_slot, (ulong) value);
+	ibmphp_lock_operations();
+	if (hotplug_slot && value) {
+		pslot = hotplug_slot->private;
+		if (pslot) {
+			memcpy(&myslot, pslot, sizeof(struct slot));
+			rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
+						&(myslot.status));
+			if (!rc)
+				*value = SLOT_LATCH(myslot.status);
+		}
+	}
+
+	ibmphp_unlock_operations();
+	debug("get_latch_status - Exit rc[%d] rc[%x] value[%x]\n",
+			rc, rc, *value);
+	return rc;
+}
+
+
+static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	struct slot myslot;
+
+	debug("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
+					(ulong) hotplug_slot, (ulong) value);
+	ibmphp_lock_operations();
+	if (hotplug_slot && value) {
+		pslot = hotplug_slot->private;
+		if (pslot) {
+			memcpy(&myslot, pslot, sizeof(struct slot));
+			rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
+						&(myslot.status));
+			if (!rc)
+				*value = SLOT_PWRGD(myslot.status);
+		}
+	}
+
+	ibmphp_unlock_operations();
+	debug("get_power_status - Exit rc[%d] rc[%x] value[%x]\n",
+			rc, rc, *value);
+	return rc;
+}
+
+static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	u8 present;
+	struct slot myslot;
+
+	debug("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
+					(ulong) hotplug_slot, (ulong) value);
+	ibmphp_lock_operations();
+	if (hotplug_slot && value) {
+		pslot = hotplug_slot->private;
+		if (pslot) {
+			memcpy(&myslot, pslot, sizeof(struct slot));
+			rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
+						&(myslot.status));
+			if (!rc) {
+				present = SLOT_PRESENT(myslot.status);
+				if (present == HPC_SLOT_EMPTY)
+					*value = 0;
+				else
+					*value = 1;
+			}
+		}
+	}
+
+	ibmphp_unlock_operations();
+	debug("get_adapter_present - Exit rc[%d] value[%x]\n", rc, *value);
+	return rc;
+}
+
+static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	u8 mode = 0;
+
+	debug("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
+
+	ibmphp_lock_operations();
+
+	if (hotplug_slot && value) {
+		pslot = hotplug_slot->private;
+		if (pslot) {
+			rc = 0;
+			mode = pslot->supported_bus_mode;
+			*value = pslot->supported_speed; 
+			switch (*value) {
+			case BUS_SPEED_33:
+				break;
+			case BUS_SPEED_66:
+				if (mode == BUS_MODE_PCIX) 
+					*value += 0x01;
+				break;
+			case BUS_SPEED_100:
+			case BUS_SPEED_133:
+				*value = pslot->supported_speed + 0x01;
+				break;
+			default:
+				/* Note (will need to change): there would be soon 256, 512 also */
+				rc = -ENODEV;
+			}
+		}
+	}
+
+	ibmphp_unlock_operations();
+	debug("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
+	return rc;
+}
+
+static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	u8 mode = 0;
+
+	debug("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
+
+	ibmphp_lock_operations();
+
+	if (hotplug_slot && value) {
+		pslot = hotplug_slot->private;
+		if (pslot) {
+			rc = get_cur_bus_info(&pslot);
+			if (!rc) {
+				mode = pslot->bus_on->current_bus_mode;
+				*value = pslot->bus_on->current_speed;
+				switch (*value) {
+				case BUS_SPEED_33:
+					break;
+				case BUS_SPEED_66:
+					if (mode == BUS_MODE_PCIX) 
+						*value += 0x01;
+					else if (mode == BUS_MODE_PCI)
+						;
+					else
+						*value = PCI_SPEED_UNKNOWN;
+					break;
+				case BUS_SPEED_100:
+				case BUS_SPEED_133:
+					*value += 0x01;
+					break;
+				default:
+					/* Note of change: there would also be 256, 512 soon */
+					rc = -ENODEV;
+				}
+			}
+		}
+	}
+
+	ibmphp_unlock_operations();
+	debug("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
+	return rc;
+}
+
+/*
+static int get_max_adapter_speed_1(struct hotplug_slot *hotplug_slot, u8 * value, u8 flag)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	struct slot myslot;
+
+	debug("get_max_adapter_speed_1 - Entry hotplug_slot[%lx] pvalue[%lx]\n",
+						(ulong)hotplug_slot, (ulong) value);
+
+	if (flag)
+		ibmphp_lock_operations();
+
+	if (hotplug_slot && value) {
+		pslot = hotplug_slot->private;
+		if (pslot) {
+			memcpy(&myslot, pslot, sizeof(struct slot));
+			rc = ibmphp_hpc_readslot(pslot, READ_SLOTSTATUS,
+						&(myslot.status));
+
+			if (!(SLOT_LATCH (myslot.status)) &&
+					(SLOT_PRESENT (myslot.status))) {
+				rc = ibmphp_hpc_readslot(pslot,
+						READ_EXTSLOTSTATUS,
+						&(myslot.ext_status));
+				if (!rc)
+					*value = SLOT_SPEED(myslot.ext_status);
+			} else
+				*value = MAX_ADAPTER_NONE;
+                }
+	}
+
+	if (flag)
+		ibmphp_unlock_operations();
+
+	debug("get_max_adapter_speed_1 - Exit rc[%d] value[%x]\n", rc, *value);
+	return rc;
+}
+
+static int get_bus_name(struct hotplug_slot *hotplug_slot, char * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot = NULL;
+
+	debug("get_bus_name - Entry hotplug_slot[%lx]\n", (ulong)hotplug_slot);
+
+	ibmphp_lock_operations();
+
+	if (hotplug_slot) {
+		pslot = hotplug_slot->private;
+		if (pslot) {
+			rc = 0;
+			snprintf(value, 100, "Bus %x", pslot->bus);
+		}
+	} else
+		rc = -ENODEV;
+
+	ibmphp_unlock_operations();
+	debug("get_bus_name - Exit rc[%d] value[%x]\n", rc, *value);
+	return rc;
+}
+*/
+
+/****************************************************************************
+ * This routine will initialize the ops data structure used in the validate
+ * function. It will also power off empty slots that are powered on since BIOS
+ * leaves those on, albeit disconnected
+ ****************************************************************************/
+static int __init init_ops(void)
+{
+	struct slot *slot_cur;
+	struct list_head *tmp;
+	int retval;
+	int rc;
+
+	list_for_each(tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry(tmp, struct slot, ibm_slot_list);
+
+		if (!slot_cur)
+			return -ENODEV;
+
+		debug("BEFORE GETTING SLOT STATUS, slot # %x\n",
+							slot_cur->number);
+		if (slot_cur->ctrl->revision == 0xFF) 
+			if (get_ctrl_revision(slot_cur,
+						&slot_cur->ctrl->revision))
+				return -1;
+
+		if (slot_cur->bus_on->current_speed == 0xFF) 
+			if (get_cur_bus_info(&slot_cur)) 
+				return -1;
+
+		if (slot_cur->ctrl->options == 0xFF)
+			if (get_hpc_options(slot_cur, &slot_cur->ctrl->options))
+				return -1;
+
+		retval = slot_update(&slot_cur);
+		if (retval)
+			return retval;
+
+		debug("status = %x\n", slot_cur->status);
+		debug("ext_status = %x\n", slot_cur->ext_status);
+		debug("SLOT_POWER = %x\n", SLOT_POWER(slot_cur->status));
+		debug("SLOT_PRESENT = %x\n", SLOT_PRESENT(slot_cur->status));
+		debug("SLOT_LATCH = %x\n", SLOT_LATCH(slot_cur->status));
+
+		if ((SLOT_PWRGD(slot_cur->status)) && 
+		    !(SLOT_PRESENT(slot_cur->status)) && 
+		    !(SLOT_LATCH(slot_cur->status))) {
+			debug("BEFORE POWER OFF COMMAND\n");
+				rc = power_off(slot_cur);
+				if (rc)
+					return rc;
+
+	/*		retval = slot_update(&slot_cur);
+	 *		if (retval)
+	 *			return retval;
+	 *		ibmphp_update_slot_info(slot_cur);
+	 */
+		}
+	}
+	init_flag = 0;
+	return 0;
+}
+
+/* This operation will check whether the slot is within the bounds and
+ * the operation is valid to perform on that slot
+ * Parameters: slot, operation
+ * Returns: 0 or error codes
+ */
+static int validate(struct slot *slot_cur, int opn)
+{
+	int number;
+	int retval;
+
+	if (!slot_cur)
+		return -ENODEV;
+	number = slot_cur->number;
+	if ((number > max_slots) || (number < 0))
+		return -EBADSLT;
+	debug("slot_number in validate is %d\n", slot_cur->number);
+
+	retval = slot_update(&slot_cur);
+	if (retval)
+		return retval;
+
+	switch (opn) {
+		case ENABLE:
+			if (!(SLOT_PWRGD(slot_cur->status)) && 
+			     (SLOT_PRESENT(slot_cur->status)) && 
+			     !(SLOT_LATCH(slot_cur->status)))
+				return 0;
+			break;
+		case DISABLE:
+			if ((SLOT_PWRGD(slot_cur->status)) && 
+			    (SLOT_PRESENT(slot_cur->status)) &&
+			    !(SLOT_LATCH(slot_cur->status)))
+				return 0;
+			break;
+		default:
+			break;
+	}
+	err("validate failed....\n");
+	return -EINVAL;
+}
+
+/****************************************************************************
+ * This routine is for updating the data structures in the hotplug core
+ * Parameters: struct slot
+ * Returns: 0 or error
+ ****************************************************************************/
+int ibmphp_update_slot_info(struct slot *slot_cur)
+{
+	struct hotplug_slot_info *info;
+	int rc;
+	u8 bus_speed;
+	u8 mode;
+
+	info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+	if (!info) {
+		err("out of system memory\n");
+		return -ENOMEM;
+	}
+        
+	info->power_status = SLOT_PWRGD(slot_cur->status);
+	info->attention_status = SLOT_ATTN(slot_cur->status,
+						slot_cur->ext_status);
+	info->latch_status = SLOT_LATCH(slot_cur->status);
+        if (!SLOT_PRESENT(slot_cur->status)) {
+                info->adapter_status = 0;
+/*		info->max_adapter_speed_status = MAX_ADAPTER_NONE; */
+	} else {
+                info->adapter_status = 1;
+/*		get_max_adapter_speed_1(slot_cur->hotplug_slot,
+					&info->max_adapter_speed_status, 0); */
+	}
+
+	bus_speed = slot_cur->bus_on->current_speed;
+	mode = slot_cur->bus_on->current_bus_mode;
+
+	switch (bus_speed) {
+		case BUS_SPEED_33:
+			break;
+		case BUS_SPEED_66:
+			if (mode == BUS_MODE_PCIX) 
+				bus_speed += 0x01;
+			else if (mode == BUS_MODE_PCI)
+				;
+			else
+				bus_speed = PCI_SPEED_UNKNOWN;
+			break;
+		case BUS_SPEED_100:
+		case BUS_SPEED_133:
+			bus_speed += 0x01;
+			break;
+		default:
+			bus_speed = PCI_SPEED_UNKNOWN;
+	}
+
+	info->cur_bus_speed = bus_speed;
+	info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed;
+	// To do: bus_names 
+	
+	rc = pci_hp_change_slot_info(slot_cur->hotplug_slot, info);
+	kfree(info);
+	return rc;
+}
+
+
+/******************************************************************************
+ * This function will return the pci_func, given bus and devfunc, or NULL.  It
+ * is called from visit routines
+ ******************************************************************************/
+
+static struct pci_func *ibm_slot_find(u8 busno, u8 device, u8 function)
+{
+	struct pci_func *func_cur;
+	struct slot *slot_cur;
+	struct list_head * tmp;
+	list_for_each(tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry(tmp, struct slot, ibm_slot_list);
+		if (slot_cur->func) {
+			func_cur = slot_cur->func;
+			while (func_cur) {
+				if ((func_cur->busno == busno) &&
+						(func_cur->device == device) &&
+						(func_cur->function == function))
+					return func_cur;
+				func_cur = func_cur->next;
+			}
+		}
+	}
+	return NULL;
+}
+
+/*************************************************************
+ * This routine frees up memory used by struct slot, including
+ * the pointers to pci_func, bus, hotplug_slot, controller,
+ * and deregistering from the hotplug core
+ *************************************************************/
+static void free_slots(void)
+{
+	struct slot *slot_cur;
+	struct list_head * tmp;
+	struct list_head * next;
+
+	debug("%s -- enter\n", __FUNCTION__);
+
+	list_for_each_safe(tmp, next, &ibmphp_slot_head) {
+		slot_cur = list_entry(tmp, struct slot, ibm_slot_list);
+		pci_hp_deregister(slot_cur->hotplug_slot);
+	}
+	debug("%s -- exit\n", __FUNCTION__);
+}
+
+static void ibm_unconfigure_device(struct pci_func *func)
+{
+	struct pci_dev *temp;
+	u8 j;
+
+	debug("inside %s\n", __FUNCTION__);
+	debug("func->device = %x, func->function = %x\n",
+					func->device, func->function);
+	debug("func->device << 3 | 0x0  = %x\n", func->device << 3 | 0x0);
+
+	for (j = 0; j < 0x08; j++) {
+		temp = pci_find_slot(func->busno, (func->device << 3) | j);
+		if (temp)
+			pci_remove_bus_device(temp);
+	}
+}
+
+/*
+ * The following function is to fix kernel bug regarding 
+ * getting bus entries, here we manually add those primary 
+ * bus entries to kernel bus structure whenever apply
+ */
+static u8 bus_structure_fixup(u8 busno)
+{
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	u16 l;
+
+	if (pci_find_bus(0, busno) || !(ibmphp_find_same_bus_num(busno)))
+		return 1;
+
+	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus) {
+		err("%s - out of memory\n", __FUNCTION__);
+		return 1;
+	}
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		kfree(bus);
+		err("%s - out of memory\n", __FUNCTION__);
+		return 1;
+	}
+
+	bus->number = busno;
+	bus->ops = ibmphp_pci_bus->ops;
+	dev->bus = bus;
+	for (dev->devfn = 0; dev->devfn < 256; dev->devfn += 8) {
+		if (!pci_read_config_word(dev, PCI_VENDOR_ID, &l) &&
+					(l != 0x0000) && (l != 0xffff)) {
+			debug("%s - Inside bus_struture_fixup()\n",
+							__FUNCTION__);
+			pci_scan_bus(busno, ibmphp_pci_bus->ops, NULL);
+			break;
+		}
+	}
+
+	kfree(dev);
+	kfree(bus);
+
+	return 0;
+}
+
+static int ibm_configure_device(struct pci_func *func)
+{
+	unsigned char bus;
+	struct pci_bus *child;
+	int num;
+	int flag = 0;	/* this is to make sure we don't double scan the bus,
+					for bridged devices primarily */
+
+	if (!(bus_structure_fixup(func->busno)))
+		flag = 1;
+	if (func->dev == NULL)
+		func->dev = pci_find_slot(func->busno,
+				PCI_DEVFN(func->device, func->function));
+
+	if (func->dev == NULL) {
+		struct pci_bus *bus = pci_find_bus(0, func->busno);
+		if (!bus)
+			return 0;
+
+		num = pci_scan_slot(bus,
+				PCI_DEVFN(func->device, func->function));
+		if (num)
+			pci_bus_add_devices(bus);
+
+		func->dev = pci_find_slot(func->busno,
+				PCI_DEVFN(func->device, func->function));
+		if (func->dev == NULL) {
+			err("ERROR... : pci_dev still NULL\n");
+			return 0;
+		}
+	}
+	if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
+		pci_read_config_byte(func->dev, PCI_SECONDARY_BUS, &bus);
+		child = pci_add_new_bus(func->dev->bus, func->dev, bus);
+		pci_do_scan_bus(child);
+	}
+
+	return 0;
+}
+
+/*******************************************************
+ * Returns whether the bus is empty or not 
+ *******************************************************/
+static int is_bus_empty(struct slot * slot_cur)
+{
+	int rc;
+	struct slot * tmp_slot;
+	u8 i = slot_cur->bus_on->slot_min;
+
+	while (i <= slot_cur->bus_on->slot_max) {
+		if (i == slot_cur->number) {
+			i++;
+			continue;
+		}
+		tmp_slot = ibmphp_get_slot_from_physical_num(i);
+		if (!tmp_slot)
+			return 0;
+		rc = slot_update(&tmp_slot);
+		if (rc)
+			return 0;
+		if (SLOT_PRESENT(tmp_slot->status) &&
+					SLOT_PWRGD(tmp_slot->status))
+			return 0;
+		i++;
+	}
+	return 1;
+}
+
+/***********************************************************
+ * If the HPC permits and the bus currently empty, tries to set the 
+ * bus speed and mode at the maximum card and bus capability
+ * Parameters: slot
+ * Returns: bus is set (0) or error code
+ ***********************************************************/
+static int set_bus(struct slot * slot_cur)
+{
+	int rc;
+	u8 speed;
+	u8 cmd = 0x0;
+	int retval;
+	static struct pci_device_id ciobx[] = {
+		{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, 0x0101) },
+	        { },
+	};	
+
+	debug("%s - entry slot # %d\n", __FUNCTION__, slot_cur->number);
+	if (SET_BUS_STATUS(slot_cur->ctrl) && is_bus_empty(slot_cur)) {
+		rc = slot_update(&slot_cur);
+		if (rc)
+			return rc;
+		speed = SLOT_SPEED(slot_cur->ext_status);
+		debug("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed);
+		switch (speed) {
+		case HPC_SLOT_SPEED_33:
+			cmd = HPC_BUS_33CONVMODE;
+			break;
+		case HPC_SLOT_SPEED_66:
+			if (SLOT_PCIX(slot_cur->ext_status)) {
+				if ((slot_cur->supported_speed >= BUS_SPEED_66) &&
+						(slot_cur->supported_bus_mode == BUS_MODE_PCIX))
+					cmd = HPC_BUS_66PCIXMODE;
+				else if (!SLOT_BUS_MODE(slot_cur->ext_status))
+					/* if max slot/bus capability is 66 pci
+					and there's no bus mode mismatch, then
+					the adapter supports 66 pci */ 
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			} else {
+				if (slot_cur->supported_speed >= BUS_SPEED_66)
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			}
+			break;
+		case HPC_SLOT_SPEED_133:
+			switch (slot_cur->supported_speed) {
+			case BUS_SPEED_33:
+				cmd = HPC_BUS_33CONVMODE;
+				break;
+			case BUS_SPEED_66:
+				if (slot_cur->supported_bus_mode == BUS_MODE_PCIX)
+					cmd = HPC_BUS_66PCIXMODE;
+				else
+					cmd = HPC_BUS_66CONVMODE;
+				break;
+			case BUS_SPEED_100:
+				cmd = HPC_BUS_100PCIXMODE;
+				break;
+			case BUS_SPEED_133:
+				/* This is to take care of the bug in CIOBX chip */
+				if (pci_dev_present(ciobx))
+					ibmphp_hpc_writeslot(slot_cur,
+							HPC_BUS_100PCIXMODE);
+				cmd = HPC_BUS_133PCIXMODE;
+				break;
+			default:
+				err("Wrong bus speed\n");
+				return -ENODEV;
+			}
+			break;
+		default:
+			err("wrong slot speed\n");
+			return -ENODEV;
+		}
+		debug("setting bus speed for slot %d, cmd %x\n",
+						slot_cur->number, cmd);
+		retval = ibmphp_hpc_writeslot(slot_cur, cmd);
+		if (retval) {
+			err("setting bus speed failed\n");
+			return retval;
+		}
+		if (CTLR_RESULT(slot_cur->ctrl->status)) {
+			err("command not completed successfully in set_bus\n");
+			return -EIO;
+		}
+	}
+	/* This is for x440, once Brandon fixes the firmware, 
+	will not need this delay */
+	msleep(1000);
+	debug("%s -Exit\n", __FUNCTION__);
+	return 0;
+}
+
+/* This routine checks the bus limitations that the slot is on from the BIOS.
+ * This is used in deciding whether or not to power up the slot.  
+ * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on
+ * same bus) 
+ * Parameters: slot
+ * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus
+ */
+static int check_limitations(struct slot *slot_cur)
+{
+	u8 i;
+	struct slot * tmp_slot;
+	u8 count = 0;
+	u8 limitation = 0;
+
+	for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) {
+		tmp_slot = ibmphp_get_slot_from_physical_num(i);
+		if (!tmp_slot)
+			return -ENODEV;
+		if ((SLOT_PWRGD(tmp_slot->status)) &&
+					!(SLOT_CONNECT(tmp_slot->status)))
+			count++;
+	}
+	get_cur_bus_info(&slot_cur);
+	switch (slot_cur->bus_on->current_speed) {
+	case BUS_SPEED_33:
+		limitation = slot_cur->bus_on->slots_at_33_conv;
+		break;
+	case BUS_SPEED_66:
+		if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
+			limitation = slot_cur->bus_on->slots_at_66_pcix;
+		else
+			limitation = slot_cur->bus_on->slots_at_66_conv;
+		break;
+	case BUS_SPEED_100:
+		limitation = slot_cur->bus_on->slots_at_100_pcix;
+		break;
+	case BUS_SPEED_133:
+		limitation = slot_cur->bus_on->slots_at_133_pcix;
+		break;
+	}
+
+	if ((count + 1) > limitation)
+		return -EINVAL;
+	return 0;
+}
+
+static inline void print_card_capability(struct slot *slot_cur)
+{
+	info("capability of the card is ");
+	if ((slot_cur->ext_status & CARD_INFO) == PCIX133) 
+		info("   133 MHz PCI-X\n");
+	else if ((slot_cur->ext_status & CARD_INFO) == PCIX66)
+		info("    66 MHz PCI-X\n");
+	else if ((slot_cur->ext_status & CARD_INFO) == PCI66)
+		info("    66 MHz PCI\n");
+	else
+		info("    33 MHz PCI\n");
+
+}
+
+/* This routine will power on the slot, configure the device(s) and find the
+ * drivers for them.
+ * Parameters: hotplug_slot
+ * Returns: 0 or failure codes
+ */
+static int enable_slot(struct hotplug_slot *hs)
+{
+	int rc, i, rcpr;
+	struct slot *slot_cur;
+	u8 function;
+	struct pci_func *tmp_func;
+
+	ibmphp_lock_operations();
+
+	debug("ENABLING SLOT........\n");
+	slot_cur = hs->private;
+
+	if ((rc = validate(slot_cur, ENABLE))) {
+		err("validate function failed\n");
+		goto error_nopower;
+	}
+
+	attn_LED_blink(slot_cur);
+	
+	rc = set_bus(slot_cur);
+	if (rc) {
+		err("was not able to set the bus\n");
+		goto error_nopower;
+	}
+
+	/*-----------------debugging------------------------------*/
+	get_cur_bus_info(&slot_cur);
+	debug("the current bus speed right after set_bus = %x\n",
+					slot_cur->bus_on->current_speed);
+	/*----------------------------------------------------------*/
+
+	rc = check_limitations(slot_cur);
+	if (rc) {
+		err("Adding this card exceeds the limitations of this bus.\n");
+		err("(i.e., >1 133MHz cards running on same bus, or "
+		     ">2 66 PCI cards running on same bus\n.");
+		err("Try hot-adding into another bus\n");
+		rc = -EINVAL;
+		goto error_nopower;
+	}
+
+	rc = power_on(slot_cur);
+
+	if (rc) {
+		err("something wrong when powering up... please see below for details\n");
+		/* need to turn off before on, otherwise, blinking overwrites */
+		attn_off(slot_cur);
+		attn_on(slot_cur);
+		if (slot_update(&slot_cur)) {
+			attn_off(slot_cur);
+			attn_on(slot_cur);
+			rc = -ENODEV;
+			goto exit;
+		}
+		/* Check to see the error of why it failed */
+		if ((SLOT_POWER(slot_cur->status)) &&
+					!(SLOT_PWRGD(slot_cur->status)))
+			err("power fault occurred trying to power up\n");
+		else if (SLOT_BUS_SPEED(slot_cur->status)) {
+			err("bus speed mismatch occurred.  please check "
+				"current bus speed and card capability\n");
+			print_card_capability(slot_cur);
+		} else if (SLOT_BUS_MODE(slot_cur->ext_status)) {
+			err("bus mode mismatch occurred.  please check "
+				"current bus mode and card capability\n");
+			print_card_capability(slot_cur);
+		}
+		ibmphp_update_slot_info(slot_cur);
+		goto exit;
+	}
+	debug("after power_on\n");
+	/*-----------------------debugging---------------------------*/
+	get_cur_bus_info(&slot_cur);
+	debug("the current bus speed right after power_on = %x\n",
+					slot_cur->bus_on->current_speed);
+	/*----------------------------------------------------------*/
+
+	rc = slot_update(&slot_cur);
+	if (rc)
+		goto error_power;
+	
+	rc = -EINVAL;
+	if (SLOT_POWER(slot_cur->status) && !(SLOT_PWRGD(slot_cur->status))) {
+		err("power fault occurred trying to power up...\n");
+		goto error_power;
+	}
+	if (SLOT_POWER(slot_cur->status) && (SLOT_BUS_SPEED(slot_cur->status))) {
+		err("bus speed mismatch occurred.  please check current bus "
+					"speed and card capability\n");
+		print_card_capability(slot_cur);
+		goto error_power;
+	} 
+	/* Don't think this case will happen after above checks...
+	 * but just in case, for paranoia sake */
+	if (!(SLOT_POWER(slot_cur->status))) {
+		err("power on failed...\n");
+		goto error_power;
+	}
+
+	slot_cur->func = kmalloc(sizeof(struct pci_func), GFP_KERNEL);
+	if (!slot_cur->func) {
+		/* We cannot do update_slot_info here, since no memory for
+		 * kmalloc n.e.ways, and update_slot_info allocates some */
+		err("out of system memory\n");
+		rc = -ENOMEM;
+		goto error_power;
+	}
+	memset(slot_cur->func, 0, sizeof(struct pci_func));
+	slot_cur->func->busno = slot_cur->bus;
+	slot_cur->func->device = slot_cur->device;
+	for (i = 0; i < 4; i++)
+		slot_cur->func->irq[i] = slot_cur->irq[i];
+
+	debug("b4 configure_card, slot_cur->bus = %x, slot_cur->device = %x\n",
+					slot_cur->bus, slot_cur->device);
+
+	if (ibmphp_configure_card(slot_cur->func, slot_cur->number)) {
+		err("configure_card was unsuccessful...\n");
+		/* true because don't need to actually deallocate resources,
+		 * just remove references */
+		ibmphp_unconfigure_card(&slot_cur, 1);
+		debug("after unconfigure_card\n");
+		slot_cur->func = NULL;
+		rc = -ENOMEM;
+		goto error_power;
+	}
+
+	function = 0x00;
+	do {
+		tmp_func = ibm_slot_find(slot_cur->bus, slot_cur->func->device,
+							function++);
+		if (tmp_func && !(tmp_func->dev))
+			ibm_configure_device(tmp_func);
+	} while (tmp_func);
+
+	attn_off(slot_cur);
+	if (slot_update(&slot_cur)) {
+		rc = -EFAULT;
+		goto exit;
+	}
+	ibmphp_print_test();
+	rc = ibmphp_update_slot_info(slot_cur);
+exit:
+	ibmphp_unlock_operations(); 
+	return rc;
+
+error_nopower:
+	attn_off(slot_cur);	/* need to turn off if was blinking b4 */
+	attn_on(slot_cur);
+error_cont:
+	rcpr = slot_update(&slot_cur);
+	if (rcpr) {
+		rc = rcpr;
+		goto exit;
+	}
+	ibmphp_update_slot_info(slot_cur);
+	goto exit;
+
+error_power:
+	attn_off(slot_cur);	/* need to turn off if was blinking b4 */
+	attn_on(slot_cur);
+	rcpr = power_off(slot_cur);
+	if (rcpr) {
+		rc = rcpr;
+		goto exit;
+	}
+	goto error_cont;
+}
+
+/**************************************************************
+* HOT REMOVING ADAPTER CARD                                   *
+* INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE                *
+* OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE         *
+          DISABLE POWER ,                                    *
+**************************************************************/
+static int ibmphp_disable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+	int rc;
+	
+	ibmphp_lock_operations();
+	rc = ibmphp_do_disable_slot(slot);
+	ibmphp_unlock_operations();
+	return rc;
+}
+
+int ibmphp_do_disable_slot(struct slot *slot_cur)
+{
+	int rc;
+	u8 flag;
+
+	debug("DISABLING SLOT...\n"); 
+		
+	if ((slot_cur == NULL) || (slot_cur->ctrl == NULL)) {
+		return -ENODEV;
+	}
+	
+	flag = slot_cur->flag;
+	slot_cur->flag = TRUE;
+
+	if (flag == TRUE) {
+		rc = validate(slot_cur, DISABLE);
+			/* checking if powered off already & valid slot # */
+		if (rc)
+			goto error;
+	}
+	attn_LED_blink(slot_cur);
+
+	if (slot_cur->func == NULL) {
+		/* We need this for fncs's that were there on bootup */
+		slot_cur->func = kmalloc(sizeof(struct pci_func), GFP_KERNEL);
+		if (!slot_cur->func) {
+			err("out of system memory\n");
+			rc = -ENOMEM;
+			goto error;
+		}
+		memset(slot_cur->func, 0, sizeof(struct pci_func));
+		slot_cur->func->busno = slot_cur->bus;
+		slot_cur->func->device = slot_cur->device;
+	}
+
+	ibm_unconfigure_device(slot_cur->func);
+        
+	/* If we got here from latch suddenly opening on operating card or 
+	a power fault, there's no power to the card, so cannot
+	read from it to determine what resources it occupied.  This operation
+	is forbidden anyhow.  The best we can do is remove it from kernel
+	lists at least */
+
+	if (!flag) {
+		attn_off(slot_cur);
+		return 0;
+	}
+
+	rc = ibmphp_unconfigure_card(&slot_cur, 0);
+	slot_cur->func = NULL;
+	debug("in disable_slot. after unconfigure_card\n");
+	if (rc) {
+		err("could not unconfigure card.\n");
+		goto error;
+	}
+
+	rc = ibmphp_hpc_writeslot(slot_cur, HPC_SLOT_OFF);
+	if (rc)
+		goto error;
+
+	attn_off(slot_cur);
+	rc = slot_update(&slot_cur);
+	if (rc)
+		goto exit;
+
+	rc = ibmphp_update_slot_info(slot_cur);
+	ibmphp_print_test();
+exit:
+	return rc;
+
+error:
+	/*  Need to turn off if was blinking b4 */
+	attn_off(slot_cur);
+	attn_on(slot_cur);
+	if (slot_update(&slot_cur)) {
+		rc = -EFAULT;
+		goto exit;
+	}
+	if (flag)		
+		ibmphp_update_slot_info(slot_cur);
+	goto exit;
+}
+
+struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
+	.owner =			THIS_MODULE,
+	.set_attention_status =		set_attention_status,
+	.enable_slot =			enable_slot,
+	.disable_slot =			ibmphp_disable_slot,
+	.hardware_test =		NULL,
+	.get_power_status =		get_power_status,
+	.get_attention_status =		get_attention_status,
+	.get_latch_status =		get_latch_status,
+	.get_adapter_status =		get_adapter_present,
+	.get_max_bus_speed =		get_max_bus_speed,
+	.get_cur_bus_speed =		get_cur_bus_speed,
+/*	.get_max_adapter_speed =	get_max_adapter_speed,
+	.get_bus_name_status =		get_bus_name,
+*/
+};
+
+static void ibmphp_unload(void)
+{
+	free_slots();
+	debug("after slots\n");
+	ibmphp_free_resources();
+	debug("after resources\n");
+	ibmphp_free_bus_info_queue();
+	debug("after bus info\n");
+	ibmphp_free_ebda_hpc_queue();
+	debug("after ebda hpc\n");
+	ibmphp_free_ebda_pci_rsrc_queue();
+	debug("after ebda pci rsrc\n");
+	kfree(ibmphp_pci_bus);
+}
+
+static int __init ibmphp_init(void)
+{
+	struct pci_bus *bus;
+	int i = 0;
+	int rc = 0;
+
+	init_flag = 1;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	ibmphp_pci_bus = kmalloc(sizeof(*ibmphp_pci_bus), GFP_KERNEL);
+	if (!ibmphp_pci_bus) {
+		err("out of memory\n");
+		rc = -ENOMEM;
+		goto exit;
+	}
+
+	bus = pci_find_bus(0, 0);
+	if (!bus) {
+		err("Can't find the root pci bus, can not continue\n");
+		rc = -ENODEV;
+		goto error;
+	}
+	memcpy(ibmphp_pci_bus, bus, sizeof(*ibmphp_pci_bus));
+
+	ibmphp_debug = debug;
+
+	ibmphp_hpc_initvars();
+
+	for (i = 0; i < 16; i++)
+		irqs[i] = 0;
+
+	if ((rc = ibmphp_access_ebda()))
+		goto error;
+	debug("after ibmphp_access_ebda()\n");
+
+	if ((rc = ibmphp_rsrc_init()))
+		goto error;
+	debug("AFTER Resource & EBDA INITIALIZATIONS\n");
+
+	max_slots = get_max_slots();
+	
+	if ((rc = ibmphp_register_pci()))
+		goto error;
+
+	if (init_ops()) {
+		rc = -ENODEV;
+		goto error;
+	}
+
+	ibmphp_print_test();
+	if ((rc = ibmphp_hpc_start_poll_thread())) {
+		goto error;
+	}
+
+	/* lock ourselves into memory with a module 
+	 * count of -1 so that no one can unload us. */
+	module_put(THIS_MODULE);
+
+exit:
+	return rc;
+
+error:
+	ibmphp_unload();
+	goto exit;
+}
+
+static void __exit ibmphp_exit(void)
+{
+	ibmphp_hpc_stop_poll_thread();
+	debug("after polling\n");
+	ibmphp_unload();
+	debug("done\n");
+}
+
+module_init(ibmphp_init);
+module_exit(ibmphp_exit);
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
new file mode 100644
index 0000000..aea1187
--- /dev/null
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
@@ -0,0 +1,1275 @@
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Tong Yu, IBM Corporation
+ *
+ * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2003 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include "ibmphp.h"
+
+/*
+ * POST builds data blocks(in this data block definition, a char-1
+ * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended
+ * BIOS Data Area which describe the configuration of the hot-plug
+ * controllers and resources used by the PCI Hot-Plug devices.
+ *
+ * This file walks EBDA, maps data block from physical addr,
+ * reconstruct linked lists about all system resource(MEM, PFM, IO)
+ * already assigned by POST, as well as linked lists about hot plug
+ * controllers (ctlr#, slot#, bus&slot features...)
+ */
+
+/* Global lists */
+LIST_HEAD (ibmphp_ebda_pci_rsrc_head);
+LIST_HEAD (ibmphp_slot_head);
+
+/* Local variables */
+static struct ebda_hpc_list *hpc_list_ptr;
+static struct ebda_rsrc_list *rsrc_list_ptr;
+static struct rio_table_hdr *rio_table_ptr = NULL;
+static LIST_HEAD (ebda_hpc_head);
+static LIST_HEAD (bus_info_head);
+static LIST_HEAD (rio_vg_head);
+static LIST_HEAD (rio_lo_head);
+static LIST_HEAD (opt_vg_head);
+static LIST_HEAD (opt_lo_head);
+static void __iomem *io_mem;
+
+/* Local functions */
+static int ebda_rsrc_controller (void);
+static int ebda_rsrc_rsrc (void);
+static int ebda_rio_table (void);
+
+static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void)
+{
+	struct ebda_hpc_list *list;
+
+	list = kmalloc (sizeof (struct ebda_hpc_list), GFP_KERNEL);
+	if (!list)
+		return NULL;
+	memset (list, 0, sizeof (*list));
+	return list;
+}
+
+static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count)
+{
+	struct controller *controller;
+	struct ebda_hpc_slot *slots;
+	struct ebda_hpc_bus *buses;
+
+	controller = kmalloc (sizeof (struct controller), GFP_KERNEL);
+	if (!controller)
+		goto error;
+	memset (controller, 0, sizeof (*controller));
+
+	slots = kmalloc (sizeof (struct ebda_hpc_slot) * slot_count, GFP_KERNEL);
+	if (!slots)
+		goto error_contr;
+	memset (slots, 0, sizeof (*slots) * slot_count);
+	controller->slots = slots;
+
+	buses = kmalloc (sizeof (struct ebda_hpc_bus) * bus_count, GFP_KERNEL);
+	if (!buses)
+		goto error_slots;
+	memset (buses, 0, sizeof (*buses) * bus_count);
+	controller->buses = buses;
+
+	return controller;
+error_slots:
+	kfree(controller->slots);
+error_contr:
+	kfree(controller);
+error:
+	return NULL;
+}
+
+static void free_ebda_hpc (struct controller *controller)
+{
+	kfree (controller->slots);
+	kfree (controller->buses);
+	kfree (controller);
+}
+
+static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void)
+{
+	struct ebda_rsrc_list *list;
+
+	list = kmalloc (sizeof (struct ebda_rsrc_list), GFP_KERNEL);
+	if (!list)
+		return NULL;
+	memset (list, 0, sizeof (*list));
+	return list;
+}
+
+static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void)
+{
+	struct ebda_pci_rsrc *resource;
+
+	resource = kmalloc (sizeof (struct ebda_pci_rsrc), GFP_KERNEL);
+	if (!resource)
+		return NULL;
+	memset (resource, 0, sizeof (*resource));
+	return resource;
+}
+
+static void __init print_bus_info (void)
+{
+	struct bus_info *ptr;
+	struct list_head *ptr1;
+	
+	list_for_each (ptr1, &bus_info_head) {
+		ptr = list_entry (ptr1, struct bus_info, bus_info_list);
+		debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min);
+		debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max);
+		debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count);
+		debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno);
+		debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed);
+		debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id);
+		
+		debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv);
+		debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv);
+		debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix);
+		debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix);
+		debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix);
+
+	}
+}
+
+static void print_lo_info (void)
+{
+	struct rio_detail *ptr;
+	struct list_head *ptr1;
+	debug ("print_lo_info ----\n");	
+	list_for_each (ptr1, &rio_lo_head) {
+		ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
+		debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id);
+		debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type);
+		debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id);
+		debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num);
+		debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex);
+		debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num);
+
+	}
+}
+
+static void print_vg_info (void)
+{
+	struct rio_detail *ptr;
+	struct list_head *ptr1;
+	debug ("%s ---\n", __FUNCTION__);
+	list_for_each (ptr1, &rio_vg_head) {
+		ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
+		debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id);
+		debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type);
+		debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id);
+		debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num);
+		debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex);
+		debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num);
+
+	}
+}
+
+static void __init print_ebda_pci_rsrc (void)
+{
+	struct ebda_pci_rsrc *ptr;
+	struct list_head *ptr1;
+
+	list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) {
+		ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
+		debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", 
+			__FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr);
+	}
+}
+
+static void __init print_ibm_slot (void)
+{
+	struct slot *ptr;
+	struct list_head *ptr1;
+
+	list_for_each (ptr1, &ibmphp_slot_head) {
+		ptr = list_entry (ptr1, struct slot, ibm_slot_list);
+		debug ("%s - slot_number: %x\n", __FUNCTION__, ptr->number); 
+	}
+}
+
+static void __init print_opt_vg (void)
+{
+	struct opt_rio *ptr;
+	struct list_head *ptr1;
+	debug ("%s ---\n", __FUNCTION__);
+	list_for_each (ptr1, &opt_vg_head) {
+		ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
+		debug ("%s - rio_type %x\n", __FUNCTION__, ptr->rio_type); 
+		debug ("%s - chassis_num: %x\n", __FUNCTION__, ptr->chassis_num); 
+		debug ("%s - first_slot_num: %x\n", __FUNCTION__, ptr->first_slot_num); 
+		debug ("%s - middle_num: %x\n", __FUNCTION__, ptr->middle_num); 
+	}
+}
+
+static void __init print_ebda_hpc (void)
+{
+	struct controller *hpc_ptr;
+	struct list_head *ptr1;
+	u16 index;
+
+	list_for_each (ptr1, &ebda_hpc_head) {
+
+		hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list); 
+
+		for (index = 0; index < hpc_ptr->slot_count; index++) {
+			debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num);
+			debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num);
+			debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index);
+			debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap);
+		}
+
+		for (index = 0; index < hpc_ptr->bus_count; index++) {
+			debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num);
+		}
+
+		debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type);
+		switch (hpc_ptr->ctlr_type) {
+		case 1:
+			debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus);
+			debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun);
+			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
+			break;
+
+		case 0:
+			debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start);
+			debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end);
+			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
+			break;
+
+		case 2:
+		case 4:
+			debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar);
+			debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr);
+			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
+			break;
+		}
+	}
+}
+
+int __init ibmphp_access_ebda (void)
+{
+	u8 format, num_ctlrs, rio_complete, hs_complete;
+	u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, re, rc_id, re_id, base;
+	int rc = 0;
+
+
+	rio_complete = 0;
+	hs_complete = 0;
+
+	io_mem = ioremap ((0x40 << 4) + 0x0e, 2);
+	if (!io_mem )
+		return -ENOMEM;
+	ebda_seg = readw (io_mem);
+	iounmap (io_mem);
+	debug ("returned ebda segment: %x\n", ebda_seg);
+	
+	io_mem = ioremap (ebda_seg<<4, 65000);
+	if (!io_mem )
+		return -ENOMEM;
+	next_offset = 0x180;
+
+	for (;;) {
+		offset = next_offset;
+		next_offset = readw (io_mem + offset);	/* offset of next blk */
+
+		offset += 2;
+		if (next_offset == 0)	/* 0 indicate it's last blk */
+			break;
+		blk_id = readw (io_mem + offset);	/* this blk id */
+
+		offset += 2;
+		/* check if it is hot swap block or rio block */
+		if (blk_id != 0x4853 && blk_id != 0x4752)
+			continue;
+		/* found hs table */
+		if (blk_id == 0x4853) {
+			debug ("now enter hot swap block---\n");
+			debug ("hot blk id: %x\n", blk_id);
+			format = readb (io_mem + offset);
+
+			offset += 1;
+			if (format != 4)
+				goto error_nodev;
+			debug ("hot blk format: %x\n", format);
+			/* hot swap sub blk */
+			base = offset;
+
+			sub_addr = base;
+			re = readw (io_mem + sub_addr);	/* next sub blk */
+
+			sub_addr += 2;
+			rc_id = readw (io_mem + sub_addr); 	/* sub blk id */
+
+			sub_addr += 2;
+			if (rc_id != 0x5243)
+				goto error_nodev;
+			/* rc sub blk signature  */
+			num_ctlrs = readb (io_mem + sub_addr);
+
+			sub_addr += 1;
+			hpc_list_ptr = alloc_ebda_hpc_list ();
+			if (!hpc_list_ptr) {
+				rc = -ENOMEM;
+				goto out;
+			}
+			hpc_list_ptr->format = format;
+			hpc_list_ptr->num_ctlrs = num_ctlrs;
+			hpc_list_ptr->phys_addr = sub_addr;	/*  offset of RSRC_CONTROLLER blk */
+			debug ("info about hpc descriptor---\n");
+			debug ("hot blk format: %x\n", format);
+			debug ("num of controller: %x\n", num_ctlrs);
+			debug ("offset of hpc data structure enteries: %x\n ", sub_addr);
+
+			sub_addr = base + re;	/* re sub blk */
+			/* FIXME: rc is never used/checked */
+			rc = readw (io_mem + sub_addr);	/* next sub blk */
+
+			sub_addr += 2;
+			re_id = readw (io_mem + sub_addr);	/* sub blk id */
+
+			sub_addr += 2;
+			if (re_id != 0x5245)
+				goto error_nodev;
+
+			/* signature of re */
+			num_entries = readw (io_mem + sub_addr);
+
+			sub_addr += 2;	/* offset of RSRC_ENTRIES blk */
+			rsrc_list_ptr = alloc_ebda_rsrc_list ();
+			if (!rsrc_list_ptr ) {
+				rc = -ENOMEM;
+				goto out;
+			}
+			rsrc_list_ptr->format = format;
+			rsrc_list_ptr->num_entries = num_entries;
+			rsrc_list_ptr->phys_addr = sub_addr;
+
+			debug ("info about rsrc descriptor---\n");
+			debug ("format: %x\n", format);
+			debug ("num of rsrc: %x\n", num_entries);
+			debug ("offset of rsrc data structure enteries: %x\n ", sub_addr);
+
+			hs_complete = 1;
+		} else {
+		/* found rio table, blk_id == 0x4752 */
+			debug ("now enter io table ---\n");
+			debug ("rio blk id: %x\n", blk_id);
+
+			rio_table_ptr = kmalloc (sizeof (struct rio_table_hdr), GFP_KERNEL);
+			if (!rio_table_ptr)
+				return -ENOMEM; 
+			memset (rio_table_ptr, 0, sizeof (struct rio_table_hdr) );
+			rio_table_ptr->ver_num = readb (io_mem + offset);
+			rio_table_ptr->scal_count = readb (io_mem + offset + 1);
+			rio_table_ptr->riodev_count = readb (io_mem + offset + 2);
+			rio_table_ptr->offset = offset +3 ;
+			
+			debug("info about rio table hdr ---\n");
+			debug("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ",
+				rio_table_ptr->ver_num, rio_table_ptr->scal_count,
+				rio_table_ptr->riodev_count, rio_table_ptr->offset);
+
+			rio_complete = 1;
+		}
+	}
+
+	if (!hs_complete && !rio_complete)
+		goto error_nodev;
+
+	if (rio_table_ptr) {
+		if (rio_complete && rio_table_ptr->ver_num == 3) {
+			rc = ebda_rio_table ();
+			if (rc)
+				goto out;
+		}
+	}
+	rc = ebda_rsrc_controller ();
+	if (rc)
+		goto out;
+
+	rc = ebda_rsrc_rsrc ();
+	goto out;
+error_nodev:
+	rc = -ENODEV;
+out:
+	iounmap (io_mem);
+	return rc;
+}
+
+/*
+ * map info of scalability details and rio details from physical address
+ */
+static int __init ebda_rio_table (void)
+{
+	u16 offset;
+	u8 i;
+	struct rio_detail *rio_detail_ptr;
+
+	offset = rio_table_ptr->offset;
+	offset += 12 * rio_table_ptr->scal_count;
+
+	// we do concern about rio details
+	for (i = 0; i < rio_table_ptr->riodev_count; i++) {
+		rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL);
+		if (!rio_detail_ptr)
+			return -ENOMEM;
+		memset (rio_detail_ptr, 0, sizeof (struct rio_detail));
+		rio_detail_ptr->rio_node_id = readb (io_mem + offset);
+		rio_detail_ptr->bbar = readl (io_mem + offset + 1);
+		rio_detail_ptr->rio_type = readb (io_mem + offset + 5);
+		rio_detail_ptr->owner_id = readb (io_mem + offset + 6);
+		rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7);
+		rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8);
+		rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9);
+		rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10);
+		rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11);
+		rio_detail_ptr->status = readb (io_mem + offset + 12);
+		rio_detail_ptr->wpindex = readb (io_mem + offset + 13);
+		rio_detail_ptr->chassis_num = readb (io_mem + offset + 14);
+//		debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status);
+		//create linked list of chassis
+		if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5) 
+			list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head);
+		//create linked list of expansion box				
+		else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7) 
+			list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head);
+		else 
+			// not in my concern
+			kfree (rio_detail_ptr);
+		offset += 15;
+	}
+	print_lo_info ();
+	print_vg_info ();
+	return 0;
+}
+
+/*
+ * reorganizing linked list of chassis	 
+ */
+static struct opt_rio *search_opt_vg (u8 chassis_num)
+{
+	struct opt_rio *ptr;
+	struct list_head *ptr1;
+	list_for_each (ptr1, &opt_vg_head) {
+		ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
+		if (ptr->chassis_num == chassis_num)
+			return ptr;
+	}		
+	return NULL;
+}
+
+static int __init combine_wpg_for_chassis (void)
+{
+	struct opt_rio *opt_rio_ptr = NULL;
+	struct rio_detail *rio_detail_ptr = NULL;
+	struct list_head *list_head_ptr = NULL;
+	
+	list_for_each (list_head_ptr, &rio_vg_head) {
+		rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
+		opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num);
+		if (!opt_rio_ptr) {
+			opt_rio_ptr = (struct opt_rio *) kmalloc (sizeof (struct opt_rio), GFP_KERNEL);
+			if (!opt_rio_ptr)
+				return -ENOMEM;
+			memset (opt_rio_ptr, 0, sizeof (struct opt_rio));
+			opt_rio_ptr->rio_type = rio_detail_ptr->rio_type;
+			opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num;
+			opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
+			opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num;
+			list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head);
+		} else {	
+			opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
+			opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num);
+		}	
+	}
+	print_opt_vg ();
+	return 0;	
+}	
+
+/*
+ * reorgnizing linked list of expansion box	 
+ */
+static struct opt_rio_lo *search_opt_lo (u8 chassis_num)
+{
+	struct opt_rio_lo *ptr;
+	struct list_head *ptr1;
+	list_for_each (ptr1, &opt_lo_head) {
+		ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list);
+		if (ptr->chassis_num == chassis_num)
+			return ptr;
+	}		
+	return NULL;
+}
+
+static int combine_wpg_for_expansion (void)
+{
+	struct opt_rio_lo *opt_rio_lo_ptr = NULL;
+	struct rio_detail *rio_detail_ptr = NULL;
+	struct list_head *list_head_ptr = NULL;
+	
+	list_for_each (list_head_ptr, &rio_lo_head) {
+		rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
+		opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num);
+		if (!opt_rio_lo_ptr) {
+			opt_rio_lo_ptr = (struct opt_rio_lo *) kmalloc (sizeof (struct opt_rio_lo), GFP_KERNEL);
+			if (!opt_rio_lo_ptr)
+				return -ENOMEM;
+			memset (opt_rio_lo_ptr, 0, sizeof (struct opt_rio_lo));
+			opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type;
+			opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num;
+			opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
+			opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num;
+			opt_rio_lo_ptr->pack_count = 1;
+			
+			list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head);
+		} else {	
+			opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
+			opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num);
+			opt_rio_lo_ptr->pack_count = 2;
+		}	
+	}
+	return 0;	
+}
+	
+
+/* Since we don't know the max slot number per each chassis, hence go
+ * through the list of all chassis to find out the range
+ * Arguments: slot_num, 1st slot number of the chassis we think we are on, 
+ * var (0 = chassis, 1 = expansion box) 
+ */
+static int first_slot_num (u8 slot_num, u8 first_slot, u8 var)
+{
+	struct opt_rio *opt_vg_ptr = NULL;
+	struct opt_rio_lo *opt_lo_ptr = NULL;
+	struct list_head *ptr = NULL;
+	int rc = 0;
+
+	if (!var) {
+		list_for_each (ptr, &opt_vg_head) {
+			opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
+			if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) { 
+				rc = -ENODEV;
+				break;
+			}
+		}
+	} else {
+		list_for_each (ptr, &opt_lo_head) {
+			opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
+			if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) {
+				rc = -ENODEV;
+				break;
+			}
+		}
+	}
+	return rc;
+}
+
+static struct opt_rio_lo * find_rxe_num (u8 slot_num)
+{
+	struct opt_rio_lo *opt_lo_ptr;
+	struct list_head *ptr;
+
+	list_for_each (ptr, &opt_lo_head) {
+		opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
+		//check to see if this slot_num belongs to expansion box
+		if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1))) 
+			return opt_lo_ptr;
+	}
+	return NULL;
+}
+
+static struct opt_rio * find_chassis_num (u8 slot_num)
+{
+	struct opt_rio *opt_vg_ptr;
+	struct list_head *ptr;
+
+	list_for_each (ptr, &opt_vg_head) {
+		opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
+		//check to see if this slot_num belongs to chassis 
+		if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0))) 
+			return opt_vg_ptr;
+	}
+	return NULL;
+}
+
+/* This routine will find out how many slots are in the chassis, so that
+ * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc
+ */
+static u8 calculate_first_slot (u8 slot_num)
+{
+	u8 first_slot = 1;
+	struct list_head * list;
+	struct slot * slot_cur;
+	
+	list_for_each (list, &ibmphp_slot_head) {
+		slot_cur = list_entry (list, struct slot, ibm_slot_list);
+		if (slot_cur->ctrl) {
+			if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num)) 
+				first_slot = slot_cur->ctrl->ending_slot_num;
+		}
+	}			
+	return first_slot + 1;
+
+}
+static char *create_file_name (struct slot * slot_cur)
+{
+	struct opt_rio *opt_vg_ptr = NULL;
+	struct opt_rio_lo *opt_lo_ptr = NULL;
+	static char str[30];
+	int which = 0; /* rxe = 1, chassis = 0 */
+	u8 number = 1; /* either chassis or rxe # */
+	u8 first_slot = 1;
+	u8 slot_num;
+	u8 flag = 0;
+
+	if (!slot_cur) {
+		err ("Structure passed is empty\n");
+		return NULL;
+	}
+	
+	slot_num = slot_cur->number;
+
+	memset (str, 0, sizeof(str));
+	
+	if (rio_table_ptr) {
+		if (rio_table_ptr->ver_num == 3) {
+			opt_vg_ptr = find_chassis_num (slot_num);
+			opt_lo_ptr = find_rxe_num (slot_num);
+		}
+	}
+	if (opt_vg_ptr) {
+		if (opt_lo_ptr) {
+			if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) {
+				number = opt_lo_ptr->chassis_num;
+				first_slot = opt_lo_ptr->first_slot_num;
+				which = 1; /* it is RXE */
+			} else {
+				first_slot = opt_vg_ptr->first_slot_num;
+				number = opt_vg_ptr->chassis_num;
+				which = 0;
+			}
+		} else {
+			first_slot = opt_vg_ptr->first_slot_num;
+			number = opt_vg_ptr->chassis_num;
+			which = 0;
+		}
+		++flag;
+	} else if (opt_lo_ptr) {
+		number = opt_lo_ptr->chassis_num;
+		first_slot = opt_lo_ptr->first_slot_num;
+		which = 1;
+		++flag;
+	} else if (rio_table_ptr) {
+		if (rio_table_ptr->ver_num == 3) {
+			/* if both NULL and we DO have correct RIO table in BIOS */
+			return NULL;
+		}
+	} 
+	if (!flag) {
+		if (slot_cur->ctrl->ctlr_type == 4) {
+			first_slot = calculate_first_slot (slot_num);
+			which = 1;
+		} else {
+			which = 0;
+		}
+	}
+
+	sprintf(str, "%s%dslot%d",
+		which == 0 ? "chassis" : "rxe",
+		number, slot_num - first_slot + 1);
+	return str;
+}
+
+static int fillslotinfo(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot;
+	int rc = 0;
+
+	if (!hotplug_slot || !hotplug_slot->private)
+		return -EINVAL;
+
+	slot = hotplug_slot->private;
+	rc = ibmphp_hpc_readslot(slot, READ_ALLSTAT, NULL);
+	if (rc)
+		return rc;
+
+	// power - enabled:1  not:0
+	hotplug_slot->info->power_status = SLOT_POWER(slot->status);
+
+	// attention - off:0, on:1, blinking:2
+	hotplug_slot->info->attention_status = SLOT_ATTN(slot->status, slot->ext_status);
+
+	// latch - open:1 closed:0
+	hotplug_slot->info->latch_status = SLOT_LATCH(slot->status);
+
+	// pci board - present:1 not:0
+	if (SLOT_PRESENT (slot->status))
+		hotplug_slot->info->adapter_status = 1;
+	else
+		hotplug_slot->info->adapter_status = 0;
+/*
+	if (slot->bus_on->supported_bus_mode
+		&& (slot->bus_on->supported_speed == BUS_SPEED_66))
+		hotplug_slot->info->max_bus_speed_status = BUS_SPEED_66PCIX;
+	else
+		hotplug_slot->info->max_bus_speed_status = slot->bus_on->supported_speed;
+*/
+
+	return rc;
+}
+
+static void release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot;
+
+	if (!hotplug_slot || !hotplug_slot->private)
+		return;
+
+	slot = hotplug_slot->private;
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	slot->ctrl = NULL;
+	slot->bus_on = NULL;
+
+	/* we don't want to actually remove the resources, since free_resources will do just that */
+	ibmphp_unconfigure_card(&slot, -1);
+
+	kfree (slot);
+}
+
+static struct pci_driver ibmphp_driver;
+
+/*
+ * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of
+ * each hpc from physical address to a list of hot plug controllers based on
+ * hpc descriptors.
+ */
+static int __init ebda_rsrc_controller (void)
+{
+	u16 addr, addr_slot, addr_bus;
+	u8 ctlr_id, temp, bus_index;
+	u16 ctlr, slot, bus;
+	u16 slot_num, bus_num, index;
+	struct hotplug_slot *hp_slot_ptr;
+	struct controller *hpc_ptr;
+	struct ebda_hpc_bus *bus_ptr;
+	struct ebda_hpc_slot *slot_ptr;
+	struct bus_info *bus_info_ptr1, *bus_info_ptr2;
+	int rc;
+	struct slot *tmp_slot;
+	struct list_head *list;
+
+	addr = hpc_list_ptr->phys_addr;
+	for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
+		bus_index = 1;
+		ctlr_id = readb (io_mem + addr);
+		addr += 1;
+		slot_num = readb (io_mem + addr);
+
+		addr += 1;
+		addr_slot = addr;	/* offset of slot structure */
+		addr += (slot_num * 4);
+
+		bus_num = readb (io_mem + addr);
+
+		addr += 1;
+		addr_bus = addr;	/* offset of bus */
+		addr += (bus_num * 9);	/* offset of ctlr_type */
+		temp = readb (io_mem + addr);
+
+		addr += 1;
+		/* init hpc structure */
+		hpc_ptr = alloc_ebda_hpc (slot_num, bus_num);
+		if (!hpc_ptr ) {
+			rc = -ENOMEM;
+			goto error_no_hpc;
+		}
+		hpc_ptr->ctlr_id = ctlr_id;
+		hpc_ptr->ctlr_relative_id = ctlr;
+		hpc_ptr->slot_count = slot_num;
+		hpc_ptr->bus_count = bus_num;
+		debug ("now enter ctlr data struture ---\n");
+		debug ("ctlr id: %x\n", ctlr_id);
+		debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id);
+		debug ("count of slots controlled by this ctlr: %x\n", slot_num);
+		debug ("count of buses controlled by this ctlr: %x\n", bus_num);
+
+		/* init slot structure, fetch slot, bus, cap... */
+		slot_ptr = hpc_ptr->slots;
+		for (slot = 0; slot < slot_num; slot++) {
+			slot_ptr->slot_num = readb (io_mem + addr_slot);
+			slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num);
+			slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num);
+			slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num);
+
+			// create bus_info lined list --- if only one slot per bus: slot_min = slot_max 
+
+			bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num);
+			if (!bus_info_ptr2) {
+				bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL);
+				if (!bus_info_ptr1) {
+					rc = -ENOMEM;
+					goto error_no_hp_slot;
+				}
+				memset (bus_info_ptr1, 0, sizeof (struct bus_info));
+				bus_info_ptr1->slot_min = slot_ptr->slot_num;
+				bus_info_ptr1->slot_max = slot_ptr->slot_num;
+				bus_info_ptr1->slot_count += 1;
+				bus_info_ptr1->busno = slot_ptr->slot_bus_num;
+				bus_info_ptr1->index = bus_index++;
+				bus_info_ptr1->current_speed = 0xff;
+				bus_info_ptr1->current_bus_mode = 0xff;
+				
+				bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
+				
+				list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head);
+
+			} else {
+				bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num);
+				bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num);
+				bus_info_ptr2->slot_count += 1;
+
+			}
+
+			// end of creating the bus_info linked list
+
+			slot_ptr++;
+			addr_slot += 1;
+		}
+
+		/* init bus structure */
+		bus_ptr = hpc_ptr->buses;
+		for (bus = 0; bus < bus_num; bus++) {
+			bus_ptr->bus_num = readb (io_mem + addr_bus + bus);
+			bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus);
+			bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1);
+
+			bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2);
+
+			bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3);
+
+			bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4);
+
+			bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num);
+			if (bus_info_ptr2) {
+				bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv;
+				bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv;
+				bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix;
+				bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix;
+				bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; 
+			}
+			bus_ptr++;
+		}
+
+		hpc_ptr->ctlr_type = temp;
+
+		switch (hpc_ptr->ctlr_type) {
+			case 1:
+				hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr);
+				hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1);
+				hpc_ptr->irq = readb (io_mem + addr + 2);
+				addr += 3;
+				debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", 
+					hpc_ptr->u.pci_ctlr.bus,
+					hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
+				break;
+
+			case 0:
+				hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr);
+				hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2);
+				if (!request_region (hpc_ptr->u.isa_ctlr.io_start,
+						     (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1),
+						     "ibmphp")) {
+					rc = -ENODEV;
+					goto error_no_hp_slot;
+				}
+				hpc_ptr->irq = readb (io_mem + addr + 4);
+				addr += 5;
+				break;
+
+			case 2:
+			case 4:
+				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
+				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
+				hpc_ptr->irq = readb (io_mem + addr + 5);
+				addr += 6;
+				break;
+			default:
+				rc = -ENODEV;
+				goto error_no_hp_slot;
+		}
+
+		//reorganize chassis' linked list
+		combine_wpg_for_chassis ();
+		combine_wpg_for_expansion ();
+		hpc_ptr->revision = 0xff;
+		hpc_ptr->options = 0xff;
+		hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
+		hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num;
+
+		// register slots with hpc core as well as create linked list of ibm slot
+		for (index = 0; index < hpc_ptr->slot_count; index++) {
+
+			hp_slot_ptr = kmalloc(sizeof(*hp_slot_ptr), GFP_KERNEL);
+			if (!hp_slot_ptr) {
+				rc = -ENOMEM;
+				goto error_no_hp_slot;
+			}
+			memset(hp_slot_ptr, 0, sizeof(*hp_slot_ptr));
+
+			hp_slot_ptr->info = kmalloc (sizeof(struct hotplug_slot_info), GFP_KERNEL);
+			if (!hp_slot_ptr->info) {
+				rc = -ENOMEM;
+				goto error_no_hp_info;
+			}
+			memset(hp_slot_ptr->info, 0, sizeof(struct hotplug_slot_info));
+
+			hp_slot_ptr->name = kmalloc(30, GFP_KERNEL);
+			if (!hp_slot_ptr->name) {
+				rc = -ENOMEM;
+				goto error_no_hp_name;
+			}
+
+			tmp_slot = kmalloc(sizeof(*tmp_slot), GFP_KERNEL);
+			if (!tmp_slot) {
+				rc = -ENOMEM;
+				goto error_no_slot;
+			}
+			memset(tmp_slot, 0, sizeof(*tmp_slot));
+
+			tmp_slot->flag = TRUE;
+
+			tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap;
+			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
+				tmp_slot->supported_speed =  3;
+			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
+				tmp_slot->supported_speed =  2;
+			else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
+				tmp_slot->supported_speed =  1;
+				
+			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
+				tmp_slot->supported_bus_mode = 1;
+			else
+				tmp_slot->supported_bus_mode = 0;
+
+
+			tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num;
+
+			bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num);
+			if (!bus_info_ptr1) {
+				rc = -ENODEV;
+				goto error;
+			}
+			tmp_slot->bus_on = bus_info_ptr1;
+			bus_info_ptr1 = NULL;
+			tmp_slot->ctrl = hpc_ptr;
+
+			tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index;
+			tmp_slot->number = hpc_ptr->slots[index].slot_num;
+			tmp_slot->hotplug_slot = hp_slot_ptr;
+
+			hp_slot_ptr->private = tmp_slot;
+			hp_slot_ptr->release = release_slot;
+
+			rc = fillslotinfo(hp_slot_ptr);
+			if (rc)
+				goto error;
+
+			rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private);
+			if (rc)
+				goto error;
+			hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops;
+
+			// end of registering ibm slot with hotplug core
+
+			list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head);
+		}
+
+		print_bus_info ();
+		list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head );
+
+	}			/* each hpc  */
+
+	list_for_each (list, &ibmphp_slot_head) {
+		tmp_slot = list_entry (list, struct slot, ibm_slot_list);
+
+		snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
+		pci_hp_register (tmp_slot->hotplug_slot);
+	}
+
+	print_ebda_hpc ();
+	print_ibm_slot ();
+	return 0;
+
+error:
+	kfree (hp_slot_ptr->private);
+error_no_slot:
+	kfree (hp_slot_ptr->name);
+error_no_hp_name:
+	kfree (hp_slot_ptr->info);
+error_no_hp_info:
+	kfree (hp_slot_ptr);
+error_no_hp_slot:
+	free_ebda_hpc (hpc_ptr);
+error_no_hpc:
+	iounmap (io_mem);
+	return rc;
+}
+
+/* 
+ * map info (bus, devfun, start addr, end addr..) of i/o, memory,
+ * pfm from the physical addr to a list of resource.
+ */
+static int __init ebda_rsrc_rsrc (void)
+{
+	u16 addr;
+	short rsrc;
+	u8 type, rsrc_type;
+	struct ebda_pci_rsrc *rsrc_ptr;
+
+	addr = rsrc_list_ptr->phys_addr;
+	debug ("now entering rsrc land\n");
+	debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr);
+
+	for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) {
+		type = readb (io_mem + addr);
+
+		addr += 1;
+		rsrc_type = type & EBDA_RSRC_TYPE_MASK;
+
+		if (rsrc_type == EBDA_IO_RSRC_TYPE) {
+			rsrc_ptr = alloc_ebda_pci_rsrc ();
+			if (!rsrc_ptr) {
+				iounmap (io_mem);
+				return -ENOMEM;
+			}
+			rsrc_ptr->rsrc_type = type;
+
+			rsrc_ptr->bus_num = readb (io_mem + addr);
+			rsrc_ptr->dev_fun = readb (io_mem + addr + 1);
+			rsrc_ptr->start_addr = readw (io_mem + addr + 2);
+			rsrc_ptr->end_addr = readw (io_mem + addr + 4);
+			addr += 6;
+
+			debug ("rsrc from io type ----\n");
+			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
+				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
+
+			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
+		}
+
+		if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) {
+			rsrc_ptr = alloc_ebda_pci_rsrc ();
+			if (!rsrc_ptr ) {
+				iounmap (io_mem);
+				return -ENOMEM;
+			}
+			rsrc_ptr->rsrc_type = type;
+
+			rsrc_ptr->bus_num = readb (io_mem + addr);
+			rsrc_ptr->dev_fun = readb (io_mem + addr + 1);
+			rsrc_ptr->start_addr = readl (io_mem + addr + 2);
+			rsrc_ptr->end_addr = readl (io_mem + addr + 6);
+			addr += 10;
+
+			debug ("rsrc from mem or pfm ---\n");
+			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", 
+				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
+
+			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
+		}
+	}
+	kfree (rsrc_list_ptr);
+	rsrc_list_ptr = NULL;
+	print_ebda_pci_rsrc ();
+	return 0;
+}
+
+u16 ibmphp_get_total_controllers (void)
+{
+	return hpc_list_ptr->num_ctlrs;
+}
+
+struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num)
+{
+	struct slot *slot;
+	struct list_head *list;
+
+	list_for_each (list, &ibmphp_slot_head) {
+		slot = list_entry (list, struct slot, ibm_slot_list);
+		if (slot->number == physical_num)
+			return slot;
+	}
+	return NULL;
+}
+
+/* To find:
+ *	- the smallest slot number
+ *	- the largest slot number
+ *	- the total number of the slots based on each bus
+ *	  (if only one slot per bus slot_min = slot_max )
+ */
+struct bus_info *ibmphp_find_same_bus_num (u32 num)
+{
+	struct bus_info *ptr;
+	struct list_head  *ptr1;
+
+	list_for_each (ptr1, &bus_info_head) {
+		ptr = list_entry (ptr1, struct bus_info, bus_info_list); 
+		if (ptr->busno == num) 
+			 return ptr;
+	}
+	return NULL;
+}
+
+/*  Finding relative bus number, in order to map corresponding
+ *  bus register
+ */
+int ibmphp_get_bus_index (u8 num)
+{
+	struct bus_info *ptr;
+	struct list_head  *ptr1;
+
+	list_for_each (ptr1, &bus_info_head) {
+		ptr = list_entry (ptr1, struct bus_info, bus_info_list);
+		if (ptr->busno == num)  
+			return ptr->index;
+	}
+	return -ENODEV;
+}
+
+void ibmphp_free_bus_info_queue (void)
+{
+	struct bus_info *bus_info;
+	struct list_head *list;
+	struct list_head *next;
+
+	list_for_each_safe (list, next, &bus_info_head ) {
+		bus_info = list_entry (list, struct bus_info, bus_info_list);
+		kfree (bus_info);
+	}
+}
+
+void ibmphp_free_ebda_hpc_queue (void)
+{
+	struct controller *controller = NULL;
+	struct list_head *list;
+	struct list_head *next;
+	int pci_flag = 0;
+
+	list_for_each_safe (list, next, &ebda_hpc_head) {
+		controller = list_entry (list, struct controller, ebda_hpc_list);
+		if (controller->ctlr_type == 0)
+			release_region (controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1));
+		else if ((controller->ctlr_type == 1) && (!pci_flag)) {
+			++pci_flag;
+			pci_unregister_driver (&ibmphp_driver);
+		}
+		free_ebda_hpc (controller);
+	}
+}
+
+void ibmphp_free_ebda_pci_rsrc_queue (void)
+{
+	struct ebda_pci_rsrc *resource;
+	struct list_head *list;
+	struct list_head *next;
+
+	list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) {
+		resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
+		kfree (resource);
+		resource = NULL;
+	}
+}
+
+static struct pci_device_id id_table[] = {
+	{
+		.vendor		= PCI_VENDOR_ID_IBM,
+		.device		= HPC_DEVICE_ID,
+		.subvendor	= PCI_VENDOR_ID_IBM,
+		.subdevice	= HPC_SUBSYSTEM_ID,
+		.class		= ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00),
+	}, {}
+};		
+
+MODULE_DEVICE_TABLE(pci, id_table);
+
+static int ibmphp_probe (struct pci_dev *, const struct pci_device_id *);
+static struct pci_driver ibmphp_driver = {
+	.name		= "ibmphp",
+	.id_table	= id_table,
+	.probe		= ibmphp_probe,
+};
+
+int ibmphp_register_pci (void)
+{
+	struct controller *ctrl;
+	struct list_head *tmp;
+	int rc = 0;
+
+	list_for_each (tmp, &ebda_hpc_head) {
+		ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
+		if (ctrl->ctlr_type == 1) {
+			rc = pci_register_driver(&ibmphp_driver);
+			break;
+		}
+	}
+	return rc;
+}
+static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids)
+{
+	struct controller *ctrl;
+	struct list_head *tmp;
+
+	debug ("inside ibmphp_probe\n");
+	
+	list_for_each (tmp, &ebda_hpc_head) {
+		ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
+		if (ctrl->ctlr_type == 1) {
+			if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) {
+				ctrl->ctrl_dev = dev;
+				debug ("found device!!!\n");
+				debug ("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device);
+				return 0;
+			}
+		}
+	}
+	return -ENODEV;
+}
+
diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c
new file mode 100644
index 0000000..6894b54
--- /dev/null
+++ b/drivers/pci/hotplug/ibmphp_hpc.c
@@ -0,0 +1,1161 @@
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Jyoti Shah, IBM Corporation
+ *
+ * Copyright (C) 2001-2003 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *                  <jshah@us.ibm.com>
+ *
+ */
+
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include "ibmphp.h"
+
+static int to_debug = FALSE;
+#define debug_polling(fmt, arg...)	do { if (to_debug) debug (fmt, arg); } while (0)
+
+//----------------------------------------------------------------------------
+// timeout values
+//----------------------------------------------------------------------------
+#define CMD_COMPLETE_TOUT_SEC	60	// give HPC 60 sec to finish cmd
+#define HPC_CTLR_WORKING_TOUT	60	// give HPC 60 sec to finish cmd
+#define HPC_GETACCESS_TIMEOUT	60	// seconds
+#define POLL_INTERVAL_SEC	2	// poll HPC every 2 seconds
+#define POLL_LATCH_CNT		5	// poll latch 5 times, then poll slots
+
+//----------------------------------------------------------------------------
+// Winnipeg Architected Register Offsets
+//----------------------------------------------------------------------------
+#define WPG_I2CMBUFL_OFFSET	0x08	// I2C Message Buffer Low
+#define WPG_I2CMOSUP_OFFSET	0x10	// I2C Master Operation Setup Reg
+#define WPG_I2CMCNTL_OFFSET	0x20	// I2C Master Control Register
+#define WPG_I2CPARM_OFFSET	0x40	// I2C Parameter Register
+#define WPG_I2CSTAT_OFFSET	0x70	// I2C Status Register
+
+//----------------------------------------------------------------------------
+// Winnipeg Store Type commands (Add this commands to the register offset)
+//----------------------------------------------------------------------------
+#define WPG_I2C_AND		0x1000	// I2C AND operation
+#define WPG_I2C_OR		0x2000	// I2C OR operation
+
+//----------------------------------------------------------------------------
+// Command set for I2C Master Operation Setup Regisetr
+//----------------------------------------------------------------------------
+#define WPG_READATADDR_MASK	0x00010000	// read,bytes,I2C shifted,index
+#define WPG_WRITEATADDR_MASK	0x40010000	// write,bytes,I2C shifted,index
+#define WPG_READDIRECT_MASK	0x10010000
+#define WPG_WRITEDIRECT_MASK	0x60010000
+
+
+//----------------------------------------------------------------------------
+// bit masks for I2C Master Control Register
+//----------------------------------------------------------------------------
+#define WPG_I2CMCNTL_STARTOP_MASK	0x00000002	// Start the Operation
+
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+#define WPG_I2C_IOREMAP_SIZE	0x2044	// size of linear address interval
+
+//----------------------------------------------------------------------------
+// command index
+//----------------------------------------------------------------------------
+#define WPG_1ST_SLOT_INDEX	0x01	// index - 1st slot for ctlr
+#define WPG_CTLR_INDEX		0x0F	// index - ctlr
+#define WPG_1ST_EXTSLOT_INDEX	0x10	// index - 1st ext slot for ctlr
+#define WPG_1ST_BUS_INDEX	0x1F	// index - 1st bus for ctlr
+
+//----------------------------------------------------------------------------
+// macro utilities
+//----------------------------------------------------------------------------
+// if bits 20,22,25,26,27,29,30 are OFF return TRUE
+#define HPC_I2CSTATUS_CHECK(s)	((u8)((s & 0x00000A76) ? FALSE : TRUE))
+
+//----------------------------------------------------------------------------
+// global variables
+//----------------------------------------------------------------------------
+static int ibmphp_shutdown;
+static int tid_poll;
+static struct semaphore sem_hpcaccess;	// lock access to HPC
+static struct semaphore semOperations;	// lock all operations and
+					// access to data structures
+static struct semaphore sem_exit;	// make sure polling thread goes away
+//----------------------------------------------------------------------------
+// local function prototypes
+//----------------------------------------------------------------------------
+static u8 i2c_ctrl_read (struct controller *, void __iomem *, u8);
+static u8 i2c_ctrl_write (struct controller *, void __iomem *, u8, u8);
+static u8 hpc_writecmdtoindex (u8, u8);
+static u8 hpc_readcmdtoindex (u8, u8);
+static void get_hpc_access (void);
+static void free_hpc_access (void);
+static void poll_hpc (void);
+static int process_changeinstatus (struct slot *, struct slot *);
+static int process_changeinlatch (u8, u8, struct controller *);
+static int hpc_poll_thread (void *);
+static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *);
+//----------------------------------------------------------------------------
+
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_hpc_initvars
+*
+* Action:  initialize semaphores and variables
+*---------------------------------------------------------------------*/
+void __init ibmphp_hpc_initvars (void)
+{
+	debug ("%s - Entry\n", __FUNCTION__);
+
+	init_MUTEX (&sem_hpcaccess);
+	init_MUTEX (&semOperations);
+	init_MUTEX_LOCKED (&sem_exit);
+	to_debug = FALSE;
+	ibmphp_shutdown = FALSE;
+	tid_poll = 0;
+
+	debug ("%s - Exit\n", __FUNCTION__);
+}
+
+/*----------------------------------------------------------------------
+* Name:    i2c_ctrl_read
+*
+* Action:  read from HPC over I2C
+*
+*---------------------------------------------------------------------*/
+static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 index)
+{
+	u8 status;
+	int i;
+	void __iomem *wpg_addr;	// base addr + offset
+	unsigned long wpg_data;	// data to/from WPG LOHI format
+	unsigned long ultemp;
+	unsigned long data;	// actual data HILO format
+
+	debug_polling ("%s - Entry WPGBbar[%p] index[%x] \n", __FUNCTION__, WPGBbar, index);
+
+	//--------------------------------------------------------------------
+	// READ - step 1
+	// read at address, byte length, I2C address (shifted), index
+	// or read direct, byte length, index
+	if (ctlr_ptr->ctlr_type == 0x02) {
+		data = WPG_READATADDR_MASK;
+		// fill in I2C address
+		ultemp = (unsigned long)ctlr_ptr->u.wpeg_ctlr.i2c_addr;
+		ultemp = ultemp >> 1;
+		data |= (ultemp << 8);
+
+		// fill in index
+		data |= (unsigned long)index;
+	} else if (ctlr_ptr->ctlr_type == 0x04) {
+		data = WPG_READDIRECT_MASK;
+
+		// fill in index
+		ultemp = (unsigned long)index;
+		ultemp = ultemp << 8;
+		data |= ultemp;
+	} else {
+		err ("this controller type is not supported \n");
+		return HPC_ERROR;
+	}
+
+	wpg_data = swab32 (data);	// swap data before writing
+	wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// READ - step 2 : clear the message buffer
+	data = 0x00000000;
+	wpg_data = swab32 (data);
+	wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// READ - step 3 : issue start operation, I2C master control bit 30:ON
+	//                 2020 : [20] OR operation at [20] offset 0x20
+	data = WPG_I2CMCNTL_STARTOP_MASK;
+	wpg_data = swab32 (data);
+	wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// READ - step 4 : wait until start operation bit clears
+	i = CMD_COMPLETE_TOUT_SEC;
+	while (i) {
+		msleep(10);
+		wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET;
+		wpg_data = readl (wpg_addr);
+		data = swab32 (wpg_data);
+		if (!(data & WPG_I2CMCNTL_STARTOP_MASK))
+			break;
+		i--;
+	}
+	if (i == 0) {
+		debug ("%s - Error : WPG timeout\n", __FUNCTION__);
+		return HPC_ERROR;
+	}
+	//--------------------------------------------------------------------
+	// READ - step 5 : read I2C status register
+	i = CMD_COMPLETE_TOUT_SEC;
+	while (i) {
+		msleep(10);
+		wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET;
+		wpg_data = readl (wpg_addr);
+		data = swab32 (wpg_data);
+		if (HPC_I2CSTATUS_CHECK (data))
+			break;
+		i--;
+	}
+	if (i == 0) {
+		debug ("ctrl_read - Exit Error:I2C timeout\n");
+		return HPC_ERROR;
+	}
+
+	//--------------------------------------------------------------------
+	// READ - step 6 : get DATA
+	wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET;
+	wpg_data = readl (wpg_addr);
+	data = swab32 (wpg_data);
+
+	status = (u8) data;
+
+	debug_polling ("%s - Exit index[%x] status[%x]\n", __FUNCTION__, index, status);
+
+	return (status);
+}
+
+/*----------------------------------------------------------------------
+* Name:    i2c_ctrl_write
+*
+* Action:  write to HPC over I2C
+*
+* Return   0 or error codes
+*---------------------------------------------------------------------*/
+static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void __iomem *WPGBbar, u8 index, u8 cmd)
+{
+	u8 rc;
+	void __iomem *wpg_addr;	// base addr + offset
+	unsigned long wpg_data;	// data to/from WPG LOHI format 
+	unsigned long ultemp;
+	unsigned long data;	// actual data HILO format
+	int i;
+
+	debug_polling ("%s - Entry WPGBbar[%p] index[%x] cmd[%x]\n", __FUNCTION__, WPGBbar, index, cmd);
+
+	rc = 0;
+	//--------------------------------------------------------------------
+	// WRITE - step 1
+	// write at address, byte length, I2C address (shifted), index
+	// or write direct, byte length, index
+	data = 0x00000000;
+
+	if (ctlr_ptr->ctlr_type == 0x02) {
+		data = WPG_WRITEATADDR_MASK;
+		// fill in I2C address
+		ultemp = (unsigned long)ctlr_ptr->u.wpeg_ctlr.i2c_addr;
+		ultemp = ultemp >> 1;
+		data |= (ultemp << 8);
+
+		// fill in index
+		data |= (unsigned long)index;
+	} else if (ctlr_ptr->ctlr_type == 0x04) {
+		data = WPG_WRITEDIRECT_MASK;
+
+		// fill in index
+		ultemp = (unsigned long)index;
+		ultemp = ultemp << 8;
+		data |= ultemp;
+	} else {
+		err ("this controller type is not supported \n");
+		return HPC_ERROR;
+	}
+
+	wpg_data = swab32 (data);	// swap data before writing
+	wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// WRITE - step 2 : clear the message buffer
+	data = 0x00000000 | (unsigned long)cmd;
+	wpg_data = swab32 (data);
+	wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// WRITE - step 3 : issue start operation,I2C master control bit 30:ON
+	//                 2020 : [20] OR operation at [20] offset 0x20
+	data = WPG_I2CMCNTL_STARTOP_MASK;
+	wpg_data = swab32 (data);
+	wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// WRITE - step 4 : wait until start operation bit clears
+	i = CMD_COMPLETE_TOUT_SEC;
+	while (i) {
+		msleep(10);
+		wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET;
+		wpg_data = readl (wpg_addr);
+		data = swab32 (wpg_data);
+		if (!(data & WPG_I2CMCNTL_STARTOP_MASK))
+			break;
+		i--;
+	}
+	if (i == 0) {
+		debug ("%s - Exit Error:WPG timeout\n", __FUNCTION__);
+		rc = HPC_ERROR;
+	}
+
+	//--------------------------------------------------------------------
+	// WRITE - step 5 : read I2C status register
+	i = CMD_COMPLETE_TOUT_SEC;
+	while (i) {
+		msleep(10);
+		wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET;
+		wpg_data = readl (wpg_addr);
+		data = swab32 (wpg_data);
+		if (HPC_I2CSTATUS_CHECK (data))
+			break;
+		i--;
+	}
+	if (i == 0) {
+		debug ("ctrl_read - Error : I2C timeout\n");
+		rc = HPC_ERROR;
+	}
+
+	debug_polling ("%s Exit rc[%x]\n", __FUNCTION__, rc);
+	return (rc);
+}
+
+//------------------------------------------------------------
+//  Read from ISA type HPC 
+//------------------------------------------------------------
+static u8 isa_ctrl_read (struct controller *ctlr_ptr, u8 offset)
+{
+	u16 start_address;
+	u16 end_address;
+	u8 data;
+
+	start_address = ctlr_ptr->u.isa_ctlr.io_start;
+	end_address = ctlr_ptr->u.isa_ctlr.io_end;
+	data = inb (start_address + offset);
+	return data;
+}
+
+//--------------------------------------------------------------
+// Write to ISA type HPC
+//--------------------------------------------------------------
+static void isa_ctrl_write (struct controller *ctlr_ptr, u8 offset, u8 data)
+{
+	u16 start_address;
+	u16 port_address;
+	
+	start_address = ctlr_ptr->u.isa_ctlr.io_start;
+	port_address = start_address + (u16) offset;
+	outb (data, port_address);
+}
+
+static u8 pci_ctrl_read (struct controller *ctrl, u8 offset)
+{
+	u8 data = 0x00;
+	debug ("inside pci_ctrl_read\n");
+	if (ctrl->ctrl_dev)
+		pci_read_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, &data);
+	return data;
+}
+
+static u8 pci_ctrl_write (struct controller *ctrl, u8 offset, u8 data)
+{
+	u8 rc = -ENODEV;
+	debug ("inside pci_ctrl_write\n");
+	if (ctrl->ctrl_dev) {
+		pci_write_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, data);
+		rc = 0;
+	}
+	return rc;
+}
+
+static u8 ctrl_read (struct controller *ctlr, void __iomem *base, u8 offset)
+{
+	u8 rc;
+	switch (ctlr->ctlr_type) {
+	case 0:
+		rc = isa_ctrl_read (ctlr, offset);
+		break;
+	case 1:
+		rc = pci_ctrl_read (ctlr, offset);
+		break;
+	case 2:
+	case 4:
+		rc = i2c_ctrl_read (ctlr, base, offset);
+		break;
+	default:
+		return -ENODEV;
+	}
+	return rc;
+}
+
+static u8 ctrl_write (struct controller *ctlr, void __iomem *base, u8 offset, u8 data)
+{
+	u8 rc = 0;
+	switch (ctlr->ctlr_type) {
+	case 0:
+		isa_ctrl_write(ctlr, offset, data);
+		break;
+	case 1:
+		rc = pci_ctrl_write (ctlr, offset, data);
+		break;
+	case 2:
+	case 4:
+		rc = i2c_ctrl_write(ctlr, base, offset, data);
+		break;
+	default:
+		return -ENODEV;
+	}
+	return rc;
+}
+/*----------------------------------------------------------------------
+* Name:    hpc_writecmdtoindex()
+*
+* Action:  convert a write command to proper index within a controller
+*
+* Return   index, HPC_ERROR
+*---------------------------------------------------------------------*/
+static u8 hpc_writecmdtoindex (u8 cmd, u8 index)
+{
+	u8 rc;
+
+	switch (cmd) {
+	case HPC_CTLR_ENABLEIRQ:	// 0x00.N.15
+	case HPC_CTLR_CLEARIRQ:	// 0x06.N.15
+	case HPC_CTLR_RESET:	// 0x07.N.15
+	case HPC_CTLR_IRQSTEER:	// 0x08.N.15
+	case HPC_CTLR_DISABLEIRQ:	// 0x01.N.15
+	case HPC_ALLSLOT_ON:	// 0x11.N.15
+	case HPC_ALLSLOT_OFF:	// 0x12.N.15
+		rc = 0x0F;
+		break;
+
+	case HPC_SLOT_OFF:	// 0x02.Y.0-14
+	case HPC_SLOT_ON:	// 0x03.Y.0-14
+	case HPC_SLOT_ATTNOFF:	// 0x04.N.0-14
+	case HPC_SLOT_ATTNON:	// 0x05.N.0-14
+	case HPC_SLOT_BLINKLED:	// 0x13.N.0-14
+		rc = index;
+		break;
+
+	case HPC_BUS_33CONVMODE:
+	case HPC_BUS_66CONVMODE:
+	case HPC_BUS_66PCIXMODE:
+	case HPC_BUS_100PCIXMODE:
+	case HPC_BUS_133PCIXMODE:
+		rc = index + WPG_1ST_BUS_INDEX - 1;
+		break;
+
+	default:
+		err ("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd);
+		rc = HPC_ERROR;
+	}
+
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    hpc_readcmdtoindex()
+*
+* Action:  convert a read command to proper index within a controller
+*
+* Return   index, HPC_ERROR
+*---------------------------------------------------------------------*/
+static u8 hpc_readcmdtoindex (u8 cmd, u8 index)
+{
+	u8 rc;
+
+	switch (cmd) {
+	case READ_CTLRSTATUS:
+		rc = 0x0F;
+		break;
+	case READ_SLOTSTATUS:
+	case READ_ALLSTAT:
+		rc = index;
+		break;
+	case READ_EXTSLOTSTATUS:
+		rc = index + WPG_1ST_EXTSLOT_INDEX;
+		break;
+	case READ_BUSSTATUS:
+		rc = index + WPG_1ST_BUS_INDEX - 1;
+		break;
+	case READ_SLOTLATCHLOWREG:
+		rc = 0x28;
+		break;
+	case READ_REVLEVEL:
+		rc = 0x25;
+		break;
+	case READ_HPCOPTIONS:
+		rc = 0x27;
+		break;
+	default:
+		rc = HPC_ERROR;
+	}
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    HPCreadslot()
+*
+* Action:  issue a READ command to HPC
+*
+* Input:   pslot   - can not be NULL for READ_ALLSTAT
+*          pstatus - can be NULL for READ_ALLSTAT
+*
+* Return   0 or error codes
+*---------------------------------------------------------------------*/
+int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus)
+{
+	void __iomem *wpg_bbar = NULL;
+	struct controller *ctlr_ptr;
+	struct list_head *pslotlist;
+	u8 index, status;
+	int rc = 0;
+	int busindex;
+
+	debug_polling ("%s - Entry pslot[%p] cmd[%x] pstatus[%p]\n", __FUNCTION__, pslot, cmd, pstatus);
+
+	if ((pslot == NULL)
+	    || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) {
+		rc = -EINVAL;
+		err ("%s - Error invalid pointer, rc[%d]\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if (cmd == READ_BUSSTATUS) {
+		busindex = ibmphp_get_bus_index (pslot->bus);
+		if (busindex < 0) {
+			rc = -EINVAL;
+			err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc);
+			return rc;
+		} else
+			index = (u8) busindex;
+	} else
+		index = pslot->ctlr_index;
+
+	index = hpc_readcmdtoindex (cmd, index);
+
+	if (index == HPC_ERROR) {
+		rc = -EINVAL;
+		err ("%s - Exit Error:invalid index, rc[%d]\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	ctlr_ptr = pslot->ctrl;
+
+	get_hpc_access ();
+
+	//--------------------------------------------------------------------
+	// map physical address to logical address
+	//--------------------------------------------------------------------
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
+		wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
+
+	//--------------------------------------------------------------------
+	// check controller status before reading
+	//--------------------------------------------------------------------
+	rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status);
+	if (!rc) {
+		switch (cmd) {
+		case READ_ALLSTAT:
+			// update the slot structure
+			pslot->ctrl->status = status;
+			pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar,
+						       &status);
+			if (!rc)
+				pslot->ext_status = ctrl_read (ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX);
+
+			break;
+
+		case READ_SLOTSTATUS:
+			// DO NOT update the slot structure
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+
+		case READ_EXTSLOTSTATUS:
+			// DO NOT update the slot structure
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+
+		case READ_CTLRSTATUS:
+			// DO NOT update the slot structure
+			*pstatus = status;
+			break;
+
+		case READ_BUSSTATUS:
+			pslot->busstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+		case READ_REVLEVEL:
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+		case READ_HPCOPTIONS:
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+		case READ_SLOTLATCHLOWREG:
+			// DO NOT update the slot structure
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+
+			// Not used
+		case READ_ALLSLOT:
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				index = pslot->ctlr_index;
+				rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr,
+								wpg_bbar, &status);
+				if (!rc) {
+					pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index);
+					rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT,
+									ctlr_ptr, wpg_bbar, &status);
+					if (!rc)
+						pslot->ext_status =
+						    ctrl_read (ctlr_ptr, wpg_bbar,
+								index + WPG_1ST_EXTSLOT_INDEX);
+				} else {
+					err ("%s - Error ctrl_read failed\n", __FUNCTION__);
+					rc = -EINVAL;
+					break;
+				}
+			}
+			break;
+		default:
+			rc = -EINVAL;
+			break;
+		}
+	}
+	//--------------------------------------------------------------------
+	// cleanup
+	//--------------------------------------------------------------------
+	
+	// remove physical to logical address mapping
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
+		iounmap (wpg_bbar);
+	
+	free_hpc_access ();
+
+	debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_hpc_writeslot()
+*
+* Action: issue a WRITE command to HPC
+*---------------------------------------------------------------------*/
+int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd)
+{
+	void __iomem *wpg_bbar = NULL;
+	struct controller *ctlr_ptr;
+	u8 index, status;
+	int busindex;
+	u8 done;
+	int rc = 0;
+	int timeout;
+
+	debug_polling ("%s - Entry pslot[%p] cmd[%x]\n", __FUNCTION__, pslot, cmd);
+	if (pslot == NULL) {
+		rc = -EINVAL;
+		err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if ((cmd == HPC_BUS_33CONVMODE) || (cmd == HPC_BUS_66CONVMODE) ||
+		(cmd == HPC_BUS_66PCIXMODE) || (cmd == HPC_BUS_100PCIXMODE) ||
+		(cmd == HPC_BUS_133PCIXMODE)) {
+		busindex = ibmphp_get_bus_index (pslot->bus);
+		if (busindex < 0) {
+			rc = -EINVAL;
+			err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc);
+			return rc;
+		} else
+			index = (u8) busindex;
+	} else
+		index = pslot->ctlr_index;
+
+	index = hpc_writecmdtoindex (cmd, index);
+
+	if (index == HPC_ERROR) {
+		rc = -EINVAL;
+		err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	ctlr_ptr = pslot->ctrl;
+
+	get_hpc_access ();
+
+	//--------------------------------------------------------------------
+	// map physical address to logical address
+	//--------------------------------------------------------------------
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) {
+		wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
+
+		debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__,
+		ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar,
+		ctlr_ptr->u.wpeg_ctlr.i2c_addr);
+	}
+	//--------------------------------------------------------------------
+	// check controller status before writing
+	//--------------------------------------------------------------------
+	rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status);
+	if (!rc) {
+
+		ctrl_write (ctlr_ptr, wpg_bbar, index, cmd);
+
+		//--------------------------------------------------------------------
+		// check controller is still not working on the command
+		//--------------------------------------------------------------------
+		timeout = CMD_COMPLETE_TOUT_SEC;
+		done = FALSE;
+		while (!done) {
+			rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar,
+							&status);
+			if (!rc) {
+				if (NEEDTOCHECK_CMDSTATUS (cmd)) {
+					if (CTLR_FINISHED (status) == HPC_CTLR_FINISHED_YES)
+						done = TRUE;
+				} else
+					done = TRUE;
+			}
+			if (!done) {
+				msleep(1000);
+				if (timeout < 1) {
+					done = TRUE;
+					err ("%s - Error command complete timeout\n", __FUNCTION__);
+					rc = -EFAULT;
+				} else
+					timeout--;
+			}
+		}
+		ctlr_ptr->status = status;
+	}
+	// cleanup
+
+	// remove physical to logical address mapping
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
+		iounmap (wpg_bbar);
+	free_hpc_access ();
+
+	debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    get_hpc_access()
+*
+* Action: make sure only one process can access HPC at one time
+*---------------------------------------------------------------------*/
+static void get_hpc_access (void)
+{
+	down (&sem_hpcaccess);
+}
+
+/*----------------------------------------------------------------------
+* Name:    free_hpc_access()
+*---------------------------------------------------------------------*/
+void free_hpc_access (void)
+{
+	up (&sem_hpcaccess);
+}
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_lock_operations()
+*
+* Action: make sure only one process can change the data structure
+*---------------------------------------------------------------------*/
+void ibmphp_lock_operations (void)
+{
+	down (&semOperations);
+	to_debug = TRUE;
+}
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_unlock_operations()
+*---------------------------------------------------------------------*/
+void ibmphp_unlock_operations (void)
+{
+	debug ("%s - Entry\n", __FUNCTION__);
+	up (&semOperations);
+	to_debug = FALSE;
+	debug ("%s - Exit\n", __FUNCTION__);
+}
+
+/*----------------------------------------------------------------------
+* Name:    poll_hpc()
+*---------------------------------------------------------------------*/
+#define POLL_LATCH_REGISTER	0
+#define POLL_SLOTS		1
+#define POLL_SLEEP		2
+static void poll_hpc (void)
+{
+	struct slot myslot;
+	struct slot *pslot = NULL;
+	struct list_head *pslotlist;
+	int rc;
+	int poll_state = POLL_LATCH_REGISTER;
+	u8 oldlatchlow = 0x00;
+	u8 curlatchlow = 0x00;
+	int poll_count = 0;
+	u8 ctrl_count = 0x00;
+
+	debug ("%s - Entry\n", __FUNCTION__);
+
+	while (!ibmphp_shutdown) {
+		if (ibmphp_shutdown) 
+			break;
+		
+		/* try to get the lock to do some kind of harware access */
+		down (&semOperations);
+
+		switch (poll_state) {
+		case POLL_LATCH_REGISTER: 
+			oldlatchlow = curlatchlow;
+			ctrl_count = 0x00;
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				if (ctrl_count >= ibmphp_get_total_controllers())
+					break;
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+					ctrl_count++;
+					if (READ_SLOT_LATCH (pslot->ctrl)) {
+						rc = ibmphp_hpc_readslot (pslot,
+									  READ_SLOTLATCHLOWREG,
+									  &curlatchlow);
+						if (oldlatchlow != curlatchlow)
+							process_changeinlatch (oldlatchlow,
+									       curlatchlow,
+									       pslot->ctrl);
+					}
+				}
+			}
+			++poll_count;
+			poll_state = POLL_SLEEP;
+			break;
+		case POLL_SLOTS:
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				// make a copy of the old status
+				memcpy ((void *) &myslot, (void *) pslot,
+					sizeof (struct slot));
+				rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL);
+				if ((myslot.status != pslot->status)
+				    || (myslot.ext_status != pslot->ext_status))
+					process_changeinstatus (pslot, &myslot);
+			}
+			ctrl_count = 0x00;
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				if (ctrl_count >= ibmphp_get_total_controllers())
+					break;
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+					ctrl_count++;
+					if (READ_SLOT_LATCH (pslot->ctrl))
+						rc = ibmphp_hpc_readslot (pslot,
+									  READ_SLOTLATCHLOWREG,
+									  &curlatchlow);
+				}
+			}
+			++poll_count;
+			poll_state = POLL_SLEEP;
+			break;
+		case POLL_SLEEP:
+			/* don't sleep with a lock on the hardware */
+			up (&semOperations);
+			msleep(POLL_INTERVAL_SEC * 1000);
+
+			if (ibmphp_shutdown) 
+				break;
+			
+			down (&semOperations);
+			
+			if (poll_count >= POLL_LATCH_CNT) {
+				poll_count = 0;
+				poll_state = POLL_SLOTS;
+			} else
+				poll_state = POLL_LATCH_REGISTER;
+			break;
+		}	
+		/* give up the harware semaphore */
+		up (&semOperations);
+		/* sleep for a short time just for good measure */
+		msleep(100);
+	}
+	up (&sem_exit);
+	debug ("%s - Exit\n", __FUNCTION__);
+}
+
+
+/*----------------------------------------------------------------------
+* Name:    process_changeinstatus
+*
+* Action:  compare old and new slot status, process the change in status
+*
+* Input:   pointer to slot struct, old slot struct
+*
+* Return   0 or error codes
+* Value:
+*
+* Side
+* Effects: None.
+*
+* Notes:
+*---------------------------------------------------------------------*/
+static int process_changeinstatus (struct slot *pslot, struct slot *poldslot)
+{
+	u8 status;
+	int rc = 0;
+	u8 disable = FALSE;
+	u8 update = FALSE;
+
+	debug ("process_changeinstatus - Entry pslot[%p], poldslot[%p]\n", pslot, poldslot);
+
+	// bit 0 - HPC_SLOT_POWER
+	if ((pslot->status & 0x01) != (poldslot->status & 0x01))
+		update = TRUE;
+
+	// bit 1 - HPC_SLOT_CONNECT
+	// ignore
+
+	// bit 2 - HPC_SLOT_ATTN
+	if ((pslot->status & 0x04) != (poldslot->status & 0x04))
+		update = TRUE;
+
+	// bit 3 - HPC_SLOT_PRSNT2
+	// bit 4 - HPC_SLOT_PRSNT1
+	if (((pslot->status & 0x08) != (poldslot->status & 0x08))
+		|| ((pslot->status & 0x10) != (poldslot->status & 0x10)))
+		update = TRUE;
+
+	// bit 5 - HPC_SLOT_PWRGD
+	if ((pslot->status & 0x20) != (poldslot->status & 0x20))
+		// OFF -> ON: ignore, ON -> OFF: disable slot
+		if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) 
+			disable = TRUE;
+
+	// bit 6 - HPC_SLOT_BUS_SPEED
+	// ignore
+
+	// bit 7 - HPC_SLOT_LATCH
+	if ((pslot->status & 0x80) != (poldslot->status & 0x80)) {
+		update = TRUE;
+		// OPEN -> CLOSE
+		if (pslot->status & 0x80) {
+			if (SLOT_PWRGD (pslot->status)) {
+				// power goes on and off after closing latch
+				// check again to make sure power is still ON
+				msleep(1000);
+				rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status);
+				if (SLOT_PWRGD (status))
+					update = TRUE;
+				else	// overwrite power in pslot to OFF
+					pslot->status &= ~HPC_SLOT_POWER;
+			}
+		}
+		// CLOSE -> OPEN 
+		else if ((SLOT_PWRGD (poldslot->status) == HPC_SLOT_PWRGD_GOOD)
+			&& (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) {
+			disable = TRUE;
+		}
+		// else - ignore
+	}
+	// bit 4 - HPC_SLOT_BLINK_ATTN
+	if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08))
+		update = TRUE;
+
+	if (disable) {
+		debug ("process_changeinstatus - disable slot\n");
+		pslot->flag = FALSE;
+		rc = ibmphp_do_disable_slot (pslot);
+	}
+
+	if (update || disable) {
+		ibmphp_update_slot_info (pslot);
+	}
+
+	debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __FUNCTION__, rc, disable, update);
+
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    process_changeinlatch
+*
+* Action:  compare old and new latch reg status, process the change
+*
+* Input:   old and current latch register status
+*
+* Return   0 or error codes
+* Value:
+*---------------------------------------------------------------------*/
+static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl)
+{
+	struct slot myslot, *pslot;
+	u8 i;
+	u8 mask;
+	int rc = 0;
+
+	debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new);
+	// bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots
+
+	for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) {
+		mask = 0x01 << i;
+		if ((mask & old) != (mask & new)) {
+			pslot = ibmphp_get_slot_from_physical_num (i);
+			if (pslot) {
+				memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+				rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL);
+				debug ("%s - call process_changeinstatus for slot[%d]\n", __FUNCTION__, i);
+				process_changeinstatus (pslot, &myslot);
+			} else {
+				rc = -EINVAL;
+				err ("%s - Error bad pointer for slot[%d]\n", __FUNCTION__, i);
+			}
+		}
+	}
+	debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    hpc_poll_thread
+*
+* Action:  polling
+*
+* Return   0
+* Value:
+*---------------------------------------------------------------------*/
+static int hpc_poll_thread (void *data)
+{
+	debug ("%s - Entry\n", __FUNCTION__);
+
+	daemonize("hpc_poll");
+	allow_signal(SIGKILL);
+
+	poll_hpc ();
+
+	tid_poll = 0;
+	debug ("%s - Exit\n", __FUNCTION__);
+	return 0;
+}
+
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_hpc_start_poll_thread
+*
+* Action:  start polling thread
+*---------------------------------------------------------------------*/
+int __init ibmphp_hpc_start_poll_thread (void)
+{
+	int rc = 0;
+
+	debug ("%s - Entry\n", __FUNCTION__);
+
+	tid_poll = kernel_thread (hpc_poll_thread, NULL, 0);
+	if (tid_poll < 0) {
+		err ("%s - Error, thread not started\n", __FUNCTION__);
+		rc = -1;
+	}
+
+	debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_hpc_stop_poll_thread
+*
+* Action:  stop polling thread and cleanup
+*---------------------------------------------------------------------*/
+void __exit ibmphp_hpc_stop_poll_thread (void)
+{
+	debug ("%s - Entry\n", __FUNCTION__);
+
+	ibmphp_shutdown = TRUE;
+	debug ("before locking operations \n");
+	ibmphp_lock_operations ();
+	debug ("after locking operations \n");
+	
+	// wait for poll thread to exit
+	debug ("before sem_exit down \n");
+	down (&sem_exit);
+	debug ("after sem_exit down \n");
+
+	// cleanup
+	debug ("before free_hpc_access \n");
+	free_hpc_access ();
+	debug ("after free_hpc_access \n");
+	ibmphp_unlock_operations ();
+	debug ("after unlock operations \n");
+	up (&sem_exit);
+	debug ("after sem exit up\n");
+
+	debug ("%s - Exit\n", __FUNCTION__);
+}
+
+/*----------------------------------------------------------------------
+* Name:    hpc_wait_ctlr_notworking
+*
+* Action:  wait until the controller is in a not working state
+*
+* Return   0, HPC_ERROR
+* Value:
+*---------------------------------------------------------------------*/
+static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void __iomem *wpg_bbar,
+				    u8 * pstatus)
+{
+	int rc = 0;
+	u8 done = FALSE;
+
+	debug_polling ("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout);
+
+	while (!done) {
+		*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX);
+		if (*pstatus == HPC_ERROR) {
+			rc = HPC_ERROR;
+			done = TRUE;
+		}
+		if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO)
+			done = TRUE;
+		if (!done) {
+			msleep(1000);
+			if (timeout < 1) {
+				done = TRUE;
+				err ("HPCreadslot - Error ctlr timeout\n");
+				rc = HPC_ERROR;
+			} else
+				timeout--;
+		}
+	}
+	debug_polling ("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus);
+	return rc;
+}
diff --git a/drivers/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c
new file mode 100644
index 0000000..2335fac
--- /dev/null
+++ b/drivers/pci/hotplug/ibmphp_pci.c
@@ -0,0 +1,1747 @@
+/*
+ * IBM Hot Plug Controller Driver
+ * 
+ * Written By: Irene Zubarev, IBM Corporation
+ * 
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include "ibmphp.h"
+
+
+static int configure_device(struct pci_func *);
+static int configure_bridge(struct pci_func **, u8);
+static struct res_needed *scan_behind_bridge(struct pci_func *, u8);
+static int add_new_bus (struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8);
+static u8 find_sec_number (u8 primary_busno, u8 slotno);
+
+/*
+ * NOTE..... If BIOS doesn't provide default routing, we assign:
+ * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. 
+ * If adapter is bridged, then we assign 11 to it and devices behind it.
+ * We also assign the same irq numbers for multi function devices.
+ * These are PIC mode, so shouldn't matter n.e.ways (hopefully)
+ */
+static void assign_alt_irq (struct pci_func * cur_func, u8 class_code)
+{
+	int j;
+	for (j = 0; j < 4; j++) {
+		if (cur_func->irq[j] == 0xff) {
+			switch (class_code) {
+				case PCI_BASE_CLASS_STORAGE:
+					cur_func->irq[j] = SCSI_IRQ;
+					break;
+				case PCI_BASE_CLASS_NETWORK:
+					cur_func->irq[j] = LAN_IRQ;
+					break;
+				default:
+					cur_func->irq[j] = OTHER_IRQ;
+					break;
+			}
+		}
+	}
+}
+
+/*
+ * Configures the device to be added (will allocate needed resources if it
+ * can), the device can be a bridge or a regular pci device, can also be
+ * multi-functional
+ * 
+ * Input: function to be added
+ * 
+ * TO DO:  The error case with Multifunction device or multi function bridge,
+ * if there is an error, will need to go through all previous functions and 
+ * unconfigure....or can add some code into unconfigure_card....
+ */
+int ibmphp_configure_card (struct pci_func *func, u8 slotno)
+{
+	u16 vendor_id;
+	u32 class;
+	u8 class_code;
+	u8 hdr_type, device, sec_number;
+	u8 function;
+	struct pci_func *newfunc;	/* for multi devices */
+	struct pci_func *cur_func, *prev_func;
+	int rc, i, j;
+	int cleanup_count;
+	u8 flag;
+	u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */
+
+	debug ("inside configure_card, func->busno = %x\n", func->busno);
+
+	device = func->device;
+	cur_func = func;
+
+	/* We only get bus and device from IRQ routing table.  So at this point,
+	 * func->busno is correct, and func->device contains only device (at the 5 
+	 * highest bits)
+	 */
+
+	/* For every function on the card */
+	for (function = 0x00; function < 0x08; function++) {
+		unsigned int devfn = PCI_DEVFN(device, function);
+		ibmphp_pci_bus->number = cur_func->busno;
+
+		cur_func->function = function;
+
+		debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n",
+			cur_func->busno, cur_func->device, cur_func->function);
+
+		pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
+
+		debug ("vendor_id is %x\n", vendor_id);
+		if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
+			/* found correct device!!! */
+			debug ("found valid device, vendor_id = %x\n", vendor_id);
+
+			++valid_device;
+
+			/* header: x x x x x x x x
+			 *         | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge
+			 *         |_=> 0 = single function device, 1 = multi-function device
+			 */
+
+			pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
+			pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
+
+			class_code = class >> 24;
+			debug ("hrd_type = %x, class = %x, class_code %x\n", hdr_type, class, class_code);
+			class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
+			if (class == PCI_CLASS_NOT_DEFINED_VGA) {
+				err ("The device %x is VGA compatible and as is not supported for hot plugging. "
+				     "Please choose another device.\n", cur_func->device);
+				return -ENODEV;
+			} else if (class == PCI_CLASS_DISPLAY_VGA) {
+				err ("The device %x is not supported for hot plugging. "
+				     "Please choose another device.\n", cur_func->device);
+				return -ENODEV;
+			}
+			switch (hdr_type) {
+				case PCI_HEADER_TYPE_NORMAL:
+					debug ("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class);
+					assign_alt_irq (cur_func, class_code);
+					if ((rc = configure_device (cur_func)) < 0) {
+						/* We need to do this in case some other BARs were properly inserted */
+						err ("was not able to configure devfunc %x on bus %x.\n",
+						     cur_func->device, cur_func->busno);
+						cleanup_count = 6;
+						goto error;
+					}	
+					cur_func->next = NULL;
+					function = 0x8;
+					break;
+				case PCI_HEADER_TYPE_MULTIDEVICE:
+					assign_alt_irq (cur_func, class_code);
+					if ((rc = configure_device (cur_func)) < 0) {
+						/* We need to do this in case some other BARs were properly inserted */
+						err ("was not able to configure devfunc %x on bus %x...bailing out\n",
+						     cur_func->device, cur_func->busno);
+						cleanup_count = 6;
+						goto error;
+					}
+					newfunc = kmalloc(sizeof(*newfunc), GFP_KERNEL);
+					if (!newfunc) {
+						err ("out of system memory\n");
+						return -ENOMEM;
+					}
+					memset (newfunc, 0, sizeof (struct pci_func));
+					newfunc->busno = cur_func->busno;
+					newfunc->device = device;
+					cur_func->next = newfunc;
+					cur_func = newfunc;
+					for (j = 0; j < 4; j++)
+						newfunc->irq[j] = cur_func->irq[j];
+					break;
+				case PCI_HEADER_TYPE_MULTIBRIDGE:
+					class >>= 8;
+					if (class != PCI_CLASS_BRIDGE_PCI) {
+						err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. "
+						     "Please insert another card.\n", cur_func->device);
+						return -ENODEV;
+					}
+					assign_alt_irq (cur_func, class_code);
+					rc = configure_bridge (&cur_func, slotno);
+					if (rc == -ENODEV) {
+						err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n");
+						err ("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device);
+						return rc;
+					}
+					if (rc) {
+						/* We need to do this in case some other BARs were properly inserted */
+						err ("was not able to hot-add PPB properly.\n");
+						func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
+						cleanup_count = 2;
+						goto error;
+					}
+
+					pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
+					flag = FALSE;
+					for (i = 0; i < 32; i++) {
+						if (func->devices[i]) {
+							newfunc = kmalloc(sizeof(*newfunc), GFP_KERNEL);
+							if (!newfunc) {
+								err ("out of system memory\n");
+								return -ENOMEM;
+							}
+							memset (newfunc, 0, sizeof (struct pci_func));
+							newfunc->busno = sec_number;
+							newfunc->device = (u8) i;
+							for (j = 0; j < 4; j++)
+								newfunc->irq[j] = cur_func->irq[j];
+
+							if (flag) {
+								for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;
+								prev_func->next = newfunc;
+							} else
+								cur_func->next = newfunc;
+
+							rc = ibmphp_configure_card (newfunc, slotno);
+							/* This could only happen if kmalloc failed */
+							if (rc) {
+								/* We need to do this in case bridge itself got configured properly, but devices behind it failed */
+								func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
+								cleanup_count = 2;
+								goto error;
+							}
+							flag = TRUE;
+						}
+					}
+
+					newfunc = kmalloc(sizeof(*newfunc), GFP_KERNEL);
+					if (!newfunc) {
+						err ("out of system memory\n");
+						return -ENOMEM;
+					}
+					memset (newfunc, 0, sizeof (struct pci_func));
+					newfunc->busno = cur_func->busno;
+					newfunc->device = device;
+					for (j = 0; j < 4; j++)
+						newfunc->irq[j] = cur_func->irq[j];
+					for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;
+					prev_func->next = newfunc;
+					cur_func = newfunc;
+					break;
+				case PCI_HEADER_TYPE_BRIDGE:
+					class >>= 8;
+					debug ("class now is %x\n", class);
+					if (class != PCI_CLASS_BRIDGE_PCI) {
+						err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. "
+						     "Please insert another card.\n", cur_func->device);
+						return -ENODEV;
+					}
+
+					assign_alt_irq (cur_func, class_code);
+
+					debug ("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno);
+					rc = configure_bridge (&cur_func, slotno);
+					if (rc == -ENODEV) {
+						err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n");
+						err ("Bus %x, devfunc %x\n", cur_func->busno, cur_func->device);
+						return rc;
+					}
+					if (rc) {
+						/* We need to do this in case some other BARs were properly inserted */
+						func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
+						err ("was not able to hot-add PPB properly.\n");
+						cleanup_count = 2;
+						goto error;
+					}
+					debug ("cur_func->busno = %x, device = %x, function = %x\n",
+						cur_func->busno, device, function);
+					pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
+					debug ("after configuring bridge..., sec_number = %x\n", sec_number);
+					flag = FALSE;
+					for (i = 0; i < 32; i++) {
+						if (func->devices[i]) {
+							debug ("inside for loop, device is %x\n", i);
+							newfunc = kmalloc(sizeof(*newfunc), GFP_KERNEL);
+							if (!newfunc) {
+								err (" out of system memory\n");
+								return -ENOMEM;
+							}
+							memset (newfunc, 0, sizeof (struct pci_func));
+							newfunc->busno = sec_number;
+							newfunc->device = (u8) i;
+							for (j = 0; j < 4; j++)
+								newfunc->irq[j] = cur_func->irq[j];
+
+							if (flag) {
+								for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;
+								prev_func->next = newfunc;
+							} else
+								cur_func->next = newfunc;
+
+							rc = ibmphp_configure_card (newfunc, slotno);
+
+							/* Again, this case should not happen... For complete paranoia, will need to call remove_bus */
+							if (rc) {
+								/* We need to do this in case some other BARs were properly inserted */
+								func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
+								cleanup_count = 2;
+								goto error;
+							}
+							flag = TRUE;
+						}
+					}
+
+					function = 0x8;
+					break;
+				default:
+					err ("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type);
+					return -ENXIO;
+					break;
+			}	/* end of switch */
+		}	/* end of valid device */
+	}	/* end of for */
+
+	if (!valid_device) {
+		err ("Cannot find any valid devices on the card.  Or unable to read from card.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+
+error:
+	for (i = 0; i < cleanup_count; i++) {
+		if (cur_func->io[i]) {
+			ibmphp_remove_resource (cur_func->io[i]);
+			cur_func->io[i] = NULL;
+		} else if (cur_func->pfmem[i]) {
+			ibmphp_remove_resource (cur_func->pfmem[i]);
+			cur_func->pfmem[i] = NULL;
+		} else if (cur_func->mem[i]) {
+			ibmphp_remove_resource (cur_func->mem[i]);
+			cur_func->mem[i] = NULL;
+		}
+	}
+	return rc;
+}
+
+/*
+ * This function configures the pci BARs of a single device.  
+ * Input: pointer to the pci_func
+ * Output: configured PCI, 0, or error
+ */
+static int configure_device (struct pci_func *func)
+{
+	u32 bar[6];
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	u8 irq;
+	int count;
+	int len[6];
+	struct resource_node *io[6];
+	struct resource_node *mem[6];
+	struct resource_node *mem_tmp;
+	struct resource_node *pfmem[6];
+	unsigned int devfn;
+
+	debug ("%s - inside\n", __FUNCTION__);
+
+	devfn = PCI_DEVFN(func->device, func->function);
+	ibmphp_pci_bus->number = func->busno;
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+
+		/* not sure if i need this.  per scott, said maybe need smth like this
+		   if devices don't adhere 100% to the spec, so don't want to write
+		   to the reserved bits
+
+		pcibios_read_config_byte(cur_func->busno, cur_func->device, 
+		PCI_BASE_ADDRESS_0 + 4 * count, &tmp);
+		if (tmp & 0x01) // IO
+			pcibios_write_config_dword(cur_func->busno, cur_func->device, 
+			PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD);
+		else  // Memory
+			pcibios_write_config_dword(cur_func->busno, cur_func->device, 
+			PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF);
+		 */
+		pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
+
+		if (!bar[count])	/* This BAR is not implemented */
+			continue;
+
+		debug ("Device %x BAR %d wants %x\n", func->device, count, bar[count]);
+
+		if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			debug ("inside IO SPACE\n");
+
+			len[count] = bar[count] & 0xFFFFFFFC;
+			len[count] = ~len[count] + 1;
+
+			debug ("len[count] in IO %x, count %d\n", len[count], count);
+
+			io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+
+			if (!io[count]) {
+				err ("out of system memory\n");
+				return -ENOMEM;
+			}
+			memset (io[count], 0, sizeof (struct resource_node));
+			io[count]->type = IO;
+			io[count]->busno = func->busno;
+			io[count]->devfunc = PCI_DEVFN(func->device, func->function);
+			io[count]->len = len[count];
+			if (ibmphp_check_resource(io[count], 0) == 0) {
+				ibmphp_add_resource (io[count]);
+				func->io[count] = io[count];
+			} else {
+				err ("cannot allocate requested io for bus %x device %x function %x len %x\n",
+				     func->busno, func->device, func->function, len[count]);
+				kfree (io[count]);
+				return -EIO;
+			}
+			pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start);
+	
+			/* _______________This is for debugging purposes only_____________________ */ 
+			debug ("b4 writing, the IO address is %x\n", func->io[count]->start);
+			pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
+			debug ("after writing.... the start address is %x\n", bar[count]);
+			/* _________________________________________________________________________*/
+
+		} else {
+			/* This is Memory */
+			if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+				debug ("PFMEM SPACE\n");
+
+				len[count] = bar[count] & 0xFFFFFFF0;
+				len[count] = ~len[count] + 1;
+
+				debug ("len[count] in PFMEM %x, count %d\n", len[count], count);
+
+				pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+				if (!pfmem[count]) {
+					err ("out of system memory\n");
+					return -ENOMEM;
+				}
+				memset (pfmem[count], 0, sizeof (struct resource_node));
+				pfmem[count]->type = PFMEM;
+				pfmem[count]->busno = func->busno;
+				pfmem[count]->devfunc = PCI_DEVFN(func->device,
+							func->function);
+				pfmem[count]->len = len[count];
+				pfmem[count]->fromMem = FALSE;
+				if (ibmphp_check_resource (pfmem[count], 0) == 0) {
+					ibmphp_add_resource (pfmem[count]);
+					func->pfmem[count] = pfmem[count];
+				} else {
+					mem_tmp = kmalloc(sizeof(*mem_tmp), GFP_KERNEL);
+					if (!mem_tmp) {
+						err ("out of system memory\n");
+						kfree (pfmem[count]);
+						return -ENOMEM;
+					}
+					memset (mem_tmp, 0, sizeof (struct resource_node));
+					mem_tmp->type = MEM;
+					mem_tmp->busno = pfmem[count]->busno;
+					mem_tmp->devfunc = pfmem[count]->devfunc;
+					mem_tmp->len = pfmem[count]->len;
+					debug ("there's no pfmem... going into mem.\n");
+					if (ibmphp_check_resource (mem_tmp, 0) == 0) {
+						ibmphp_add_resource (mem_tmp);
+						pfmem[count]->fromMem = TRUE;
+						pfmem[count]->rangeno = mem_tmp->rangeno;
+						pfmem[count]->start = mem_tmp->start;
+						pfmem[count]->end = mem_tmp->end;
+						ibmphp_add_pfmem_from_mem (pfmem[count]);
+						func->pfmem[count] = pfmem[count];
+					} else {
+						err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n",
+						     func->busno, func->device, len[count]);
+						kfree (mem_tmp);
+						kfree (pfmem[count]);
+						return -EIO;
+					}
+				}
+
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start);
+
+				/*_______________This is for debugging purposes only______________________________*/				
+				debug ("b4 writing, start address is %x\n", func->pfmem[count]->start);
+				pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
+				debug ("after writing, start address is %x\n", bar[count]);
+				/*_________________________________________________________________________________*/
+
+				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					debug ("inside the mem 64 case, count %d\n", count);
+					count += 1;
+					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000);
+				}
+			} else {
+				/* regular memory */
+				debug ("REGULAR MEM SPACE\n");
+
+				len[count] = bar[count] & 0xFFFFFFF0;
+				len[count] = ~len[count] + 1;
+
+				debug ("len[count] in Mem %x, count %d\n", len[count], count);
+
+				mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+				if (!mem[count]) {
+					err ("out of system memory\n");
+					return -ENOMEM;
+				}
+				memset (mem[count], 0, sizeof (struct resource_node));
+				mem[count]->type = MEM;
+				mem[count]->busno = func->busno;
+				mem[count]->devfunc = PCI_DEVFN(func->device,
+							func->function);
+				mem[count]->len = len[count];
+				if (ibmphp_check_resource (mem[count], 0) == 0) {
+					ibmphp_add_resource (mem[count]);
+					func->mem[count] = mem[count];
+				} else {
+					err ("cannot allocate requested mem for bus %x, device %x, len %x\n",
+					     func->busno, func->device, len[count]);
+					kfree (mem[count]);
+					return -EIO;
+				}
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start);
+				/* _______________________This is for debugging purposes only _______________________*/
+				debug ("b4 writing, start address is %x\n", func->mem[count]->start);
+				pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
+				debug ("after writing, the address is %x\n", bar[count]);
+				/* __________________________________________________________________________________*/
+
+				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					debug ("inside mem 64 case, reg. mem, count %d\n", count);
+					count += 1;
+					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000);
+				}
+			}
+		}		/* end of mem */
+	}			/* end of for */
+
+	func->bus = 0;		/* To indicate that this is not a PPB */
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq);
+	if ((irq > 0x00) && (irq < 0x05))
+		pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
+
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY);
+
+	pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L);
+	pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE);
+
+	return 0;
+}
+
+/******************************************************************************
+ * This routine configures a PCI-2-PCI bridge and the functions behind it
+ * Parameters: pci_func
+ * Returns: 
+ ******************************************************************************/
+static int configure_bridge (struct pci_func **func_passed, u8 slotno)
+{
+	int count;
+	int i;
+	int rc;
+	u8 sec_number;
+	u8 io_base;
+	u16 pfmem_base;
+	u32 bar[2];
+	u32 len[2];
+	u8 flag_io = FALSE;
+	u8 flag_mem = FALSE;
+	u8 flag_pfmem = FALSE;
+	u8 need_io_upper = FALSE;
+	u8 need_pfmem_upper = FALSE;
+	struct res_needed *amount_needed = NULL;
+	struct resource_node *io = NULL;
+	struct resource_node *bus_io[2] = {NULL, NULL};
+	struct resource_node *mem = NULL;
+	struct resource_node *bus_mem[2] = {NULL, NULL};
+	struct resource_node *mem_tmp = NULL;
+	struct resource_node *pfmem = NULL;
+	struct resource_node *bus_pfmem[2] = {NULL, NULL};
+	struct bus_node *bus;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		0
+	};
+	struct pci_func *func = *func_passed;
+	unsigned int devfn;
+	u8 irq;
+	int retval;
+
+	debug ("%s - enter\n", __FUNCTION__);
+
+	devfn = PCI_DEVFN(func->function, func->device);
+	ibmphp_pci_bus->number = func->busno;
+
+	/* Configuring necessary info for the bridge so that we could see the devices
+	 * behind it
+	 */
+
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, func->busno);
+
+	/* _____________________For debugging purposes only __________________________
+	pci_bus_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number);
+	debug ("primary # written into the bridge is %x\n", pri_number);
+	 ___________________________________________________________________________*/
+
+	/* in EBDA, only get allocated 1 additional bus # per slot */
+	sec_number = find_sec_number (func->busno, slotno);
+	if (sec_number == 0xff) {
+		err ("cannot allocate secondary bus number for the bridged device\n");
+		return -EINVAL;
+	}
+
+	debug ("after find_sec_number, the number we got is %x\n", sec_number);
+	debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno);
+
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, sec_number);
+	
+	/* __________________For debugging purposes only __________________________________
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
+	debug ("sec_number after write/read is %x\n", sec_number);
+	 ________________________________________________________________________________*/
+
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, sec_number);
+
+	/* __________________For debugging purposes only ____________________________________
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sec_number);
+	debug ("subordinate number after write/read is %x\n", sec_number);
+	 __________________________________________________________________________________*/
+
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SEC_LATENCY_TIMER, LATENCY);
+
+	debug ("func->busno is %x\n", func->busno);
+	debug ("sec_number after writing is %x\n", sec_number);
+
+
+	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+	   !!!!!!!!!!!!!!!NEED TO ADD!!!  FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! 
+	   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
+
+
+	/* First we need to allocate mem/io for the bridge itself in case it needs it */
+	for (count = 0; address[count]; count++) {	/* for 2 BARs */
+		pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
+
+		if (!bar[count]) {
+			/* This BAR is not implemented */
+			debug ("so we come here then, eh?, count = %d\n", count);
+			continue;
+		}
+		//  tmp_bar = bar[count];
+
+		debug ("Bar %d wants %x\n", count, bar[count]);
+
+		if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			len[count] = bar[count] & 0xFFFFFFFC;
+			len[count] = ~len[count] + 1;
+
+			debug ("len[count] in IO = %x\n", len[count]);
+
+			bus_io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+		
+			if (!bus_io[count]) {
+				err ("out of system memory\n");
+				retval = -ENOMEM;
+				goto error;
+			}
+			memset (bus_io[count], 0, sizeof (struct resource_node));
+			bus_io[count]->type = IO;
+			bus_io[count]->busno = func->busno;
+			bus_io[count]->devfunc = PCI_DEVFN(func->device,
+							func->function);
+			bus_io[count]->len = len[count];
+			if (ibmphp_check_resource (bus_io[count], 0) == 0) {
+				ibmphp_add_resource (bus_io[count]);
+				func->io[count] = bus_io[count];
+			} else {
+				err ("cannot allocate requested io for bus %x, device %x, len %x\n",
+				     func->busno, func->device, len[count]);
+				kfree (bus_io[count]);
+				return -EIO;
+			}
+
+			pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start);
+
+		} else {
+			/* This is Memory */
+			if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+				len[count] = bar[count] & 0xFFFFFFF0;
+				len[count] = ~len[count] + 1;
+
+				debug ("len[count] in PFMEM = %x\n", len[count]);
+
+				bus_pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+				if (!bus_pfmem[count]) {
+					err ("out of system memory\n");
+					retval = -ENOMEM;
+					goto error;
+				}
+				memset (bus_pfmem[count], 0, sizeof (struct resource_node));
+				bus_pfmem[count]->type = PFMEM;
+				bus_pfmem[count]->busno = func->busno;
+				bus_pfmem[count]->devfunc = PCI_DEVFN(func->device,
+							func->function);
+				bus_pfmem[count]->len = len[count];
+				bus_pfmem[count]->fromMem = FALSE;
+				if (ibmphp_check_resource (bus_pfmem[count], 0) == 0) {
+					ibmphp_add_resource (bus_pfmem[count]);
+					func->pfmem[count] = bus_pfmem[count];
+				} else {
+					mem_tmp = kmalloc(sizeof(*mem_tmp), GFP_KERNEL);
+					if (!mem_tmp) {
+						err ("out of system memory\n");
+						retval = -ENOMEM;
+						goto error;
+					}
+					memset (mem_tmp, 0, sizeof (struct resource_node));
+					mem_tmp->type = MEM;
+					mem_tmp->busno = bus_pfmem[count]->busno;
+					mem_tmp->devfunc = bus_pfmem[count]->devfunc;
+					mem_tmp->len = bus_pfmem[count]->len;
+					if (ibmphp_check_resource (mem_tmp, 0) == 0) {
+						ibmphp_add_resource (mem_tmp);
+						bus_pfmem[count]->fromMem = TRUE;
+						bus_pfmem[count]->rangeno = mem_tmp->rangeno;
+						ibmphp_add_pfmem_from_mem (bus_pfmem[count]);
+						func->pfmem[count] = bus_pfmem[count];
+					} else {
+						err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", 
+						     func->busno, func->device, len[count]);
+						kfree (mem_tmp);
+						kfree (bus_pfmem[count]);
+						return -EIO;
+					}
+				}
+
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start);
+
+				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					count += 1;
+					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000);
+
+				}
+			} else {
+				/* regular memory */
+				len[count] = bar[count] & 0xFFFFFFF0;
+				len[count] = ~len[count] + 1;
+
+				debug ("len[count] in Memory is %x\n", len[count]);
+
+				bus_mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+				if (!bus_mem[count]) {
+					err ("out of system memory\n");
+					retval = -ENOMEM;
+					goto error;
+				}
+				memset (bus_mem[count], 0, sizeof (struct resource_node));
+				bus_mem[count]->type = MEM;
+				bus_mem[count]->busno = func->busno;
+				bus_mem[count]->devfunc = PCI_DEVFN(func->device,
+							func->function);
+				bus_mem[count]->len = len[count];
+				if (ibmphp_check_resource (bus_mem[count], 0) == 0) {
+					ibmphp_add_resource (bus_mem[count]);
+					func->mem[count] = bus_mem[count];
+				} else {
+					err ("cannot allocate requested mem for bus %x, device %x, len %x\n",
+					     func->busno, func->device, len[count]);
+					kfree (bus_mem[count]);
+					return -EIO;
+				}
+
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start);
+
+				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					count += 1;
+					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000);
+
+				}
+			}
+		}		/* end of mem */
+	}			/* end of for  */
+
+	/* Now need to see how much space the devices behind the bridge needed */
+	amount_needed = scan_behind_bridge (func, sec_number);
+	if (amount_needed == NULL)
+		return -ENOMEM;
+
+	ibmphp_pci_bus->number = func->busno;
+	debug ("after coming back from scan_behind_bridge\n");
+	debug ("amount_needed->not_correct = %x\n", amount_needed->not_correct);
+	debug ("amount_needed->io = %x\n", amount_needed->io);
+	debug ("amount_needed->mem = %x\n", amount_needed->mem);
+	debug ("amount_needed->pfmem =  %x\n", amount_needed->pfmem);
+
+	if (amount_needed->not_correct) {		
+		debug ("amount_needed is not correct\n");
+		for (count = 0; address[count]; count++) {
+			/* for 2 BARs */
+			if (bus_io[count]) {
+				ibmphp_remove_resource (bus_io[count]);
+				func->io[count] = NULL;
+			} else if (bus_pfmem[count]) {
+				ibmphp_remove_resource (bus_pfmem[count]);
+				func->pfmem[count] = NULL;
+			} else if (bus_mem[count]) {
+				ibmphp_remove_resource (bus_mem[count]);
+				func->mem[count] = NULL;
+			}
+		}
+		kfree (amount_needed);
+		return -ENODEV;
+	}
+
+	if (!amount_needed->io) {
+		debug ("it doesn't want IO?\n");
+		flag_io = TRUE;
+	} else {
+		debug ("it wants %x IO behind the bridge\n", amount_needed->io);
+		io = kmalloc(sizeof(*io), GFP_KERNEL);
+		
+		if (!io) {
+			err ("out of system memory\n");
+			retval = -ENOMEM;
+			goto error;
+		}
+		memset (io, 0, sizeof (struct resource_node));
+		io->type = IO;
+		io->busno = func->busno;
+		io->devfunc = PCI_DEVFN(func->device, func->function);
+		io->len = amount_needed->io;
+		if (ibmphp_check_resource (io, 1) == 0) {
+			debug ("were we able to add io\n");
+			ibmphp_add_resource (io);
+			flag_io = TRUE;
+		}
+	}
+
+	if (!amount_needed->mem) {
+		debug ("it doesn't want n.e.memory?\n");
+		flag_mem = TRUE;
+	} else {
+		debug ("it wants %x memory behind the bridge\n", amount_needed->mem);
+		mem = kmalloc(sizeof(*mem), GFP_KERNEL);
+		if (!mem) {
+			err ("out of system memory\n");
+			retval = -ENOMEM;
+			goto error;
+		}
+		memset (mem, 0, sizeof (struct resource_node));
+		mem->type = MEM;
+		mem->busno = func->busno;
+		mem->devfunc = PCI_DEVFN(func->device, func->function);
+		mem->len = amount_needed->mem;
+		if (ibmphp_check_resource (mem, 1) == 0) {
+			ibmphp_add_resource (mem);
+			flag_mem = TRUE;
+			debug ("were we able to add mem\n");
+		}
+	}
+
+	if (!amount_needed->pfmem) {
+		debug ("it doesn't want n.e.pfmem mem?\n");
+		flag_pfmem = TRUE;
+	} else {
+		debug ("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem);
+		pfmem = kmalloc(sizeof(*pfmem), GFP_KERNEL);
+		if (!pfmem) {
+			err ("out of system memory\n");
+			retval = -ENOMEM;
+			goto error;
+		}
+		memset (pfmem, 0, sizeof (struct resource_node));
+		pfmem->type = PFMEM;
+		pfmem->busno = func->busno;
+		pfmem->devfunc = PCI_DEVFN(func->device, func->function);
+		pfmem->len = amount_needed->pfmem;
+		pfmem->fromMem = FALSE;
+		if (ibmphp_check_resource (pfmem, 1) == 0) {
+			ibmphp_add_resource (pfmem);
+			flag_pfmem = TRUE;
+		} else {
+			mem_tmp = kmalloc(sizeof(*mem_tmp), GFP_KERNEL);
+			if (!mem_tmp) {
+				err ("out of system memory\n");
+				retval = -ENOMEM;
+				goto error;
+			}
+			memset (mem_tmp, 0, sizeof (struct resource_node));
+			mem_tmp->type = MEM;
+			mem_tmp->busno = pfmem->busno;
+			mem_tmp->devfunc = pfmem->devfunc;
+			mem_tmp->len = pfmem->len;
+			if (ibmphp_check_resource (mem_tmp, 1) == 0) {
+				ibmphp_add_resource (mem_tmp);
+				pfmem->fromMem = TRUE;
+				pfmem->rangeno = mem_tmp->rangeno;
+				ibmphp_add_pfmem_from_mem (pfmem);
+				flag_pfmem = TRUE;
+			}
+		}
+	}
+
+	debug ("b4 if (flag_io && flag_mem && flag_pfmem)\n");
+	debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem);
+
+	if (flag_io && flag_mem && flag_pfmem) {
+		/* If on bootup, there was a bridged card in this slot,
+		 * then card was removed and ibmphp got unloaded and loaded
+		 * back again, there's no way for us to remove the bus
+		 * struct, so no need to kmalloc, can use existing node
+		 */
+		bus = ibmphp_find_res_bus (sec_number);
+		if (!bus) {
+			bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+			if (!bus) {
+				err ("out of system memory\n");
+				retval = -ENOMEM;
+				goto error;
+			}
+			memset (bus, 0, sizeof (struct bus_node));
+			bus->busno = sec_number;
+			debug ("b4 adding new bus\n");
+			rc = add_new_bus (bus, io, mem, pfmem, func->busno);
+		} else if (!(bus->rangeIO) && !(bus->rangeMem) && !(bus->rangePFMem))
+			rc = add_new_bus (bus, io, mem, pfmem, 0xFF);
+		else {
+			err ("expected bus structure not empty?\n");
+			retval = -EIO;
+			goto error;
+		}
+		if (rc) {
+			if (rc == -ENOMEM) {
+				ibmphp_remove_bus (bus, func->busno);
+				kfree (amount_needed);
+				return rc;
+			}
+			retval = rc;
+			goto error;
+		}
+		pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &io_base);
+		pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &pfmem_base);
+
+		if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
+			debug ("io 32\n");
+			need_io_upper = TRUE;
+		}
+		if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
+			debug ("pfmem 64\n");
+			need_pfmem_upper = TRUE;
+		}
+
+		if (bus->noIORanges) {
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8);
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8);	
+
+			/* _______________This is for debugging purposes only ____________________
+			pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &temp);
+			debug ("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8);
+			pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &temp);
+			debug ("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8);
+			 ________________________________________________________________________*/
+
+			if (need_io_upper) {	/* since can't support n.e.ways */
+				pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, 0x0000);
+				pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, 0x0000);
+			}
+		} else {
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00);
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00);
+		}
+
+		if (bus->noMemRanges) {
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16);
+			
+			/* ____________________This is for debugging purposes only ________________________
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &temp);
+			debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &temp);
+			debug ("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
+			 __________________________________________________________________________________*/
+
+		} else {
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0xffff);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000);
+		}
+		if (bus->noPFMemRanges) {
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16);
+
+			/* __________________________This is for debugging purposes only _______________________
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &temp);
+			debug ("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &temp);
+			debug ("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
+			 ______________________________________________________________________________________*/
+
+			if (need_pfmem_upper) {	/* since can't support n.e.ways */
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, 0x00000000);
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, 0x00000000);
+			}
+		} else {
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0xffff);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000);
+		}
+
+		debug ("b4 writing control information\n");
+
+		pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq);
+		if ((irq > 0x00) && (irq < 0x05))
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
+		/*    
+		pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, ctrl);
+		pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY);
+		pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
+		 */
+
+		pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE);
+		pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, 0x07);
+		for (i = 0; i < 32; i++) {
+			if (amount_needed->devices[i]) {
+				debug ("device where devices[i] is 1 = %x\n", i);
+				func->devices[i] = 1;
+			}
+		}
+		func->bus = 1;	/* For unconfiguring, to indicate it's PPB */
+		func_passed = &func;
+		debug ("func->busno b4 returning is %x\n", func->busno);
+		debug ("func->busno b4 returning in the other structure is %x\n", (*func_passed)->busno);
+		kfree (amount_needed);
+		return 0;
+	} else {
+		err ("Configuring bridge was unsuccessful...\n");
+		mem_tmp = NULL;
+		retval = -EIO;
+		goto error;
+	}
+
+error:
+	kfree(amount_needed);
+	if (pfmem)
+		ibmphp_remove_resource (pfmem);
+	if (io)
+		ibmphp_remove_resource (io);
+	if (mem)
+		ibmphp_remove_resource (mem);
+	for (i = 0; i < 2; i++) {	/* for 2 BARs */
+		if (bus_io[i]) {
+			ibmphp_remove_resource (bus_io[i]);
+			func->io[i] = NULL;
+		} else if (bus_pfmem[i]) {
+			ibmphp_remove_resource (bus_pfmem[i]);
+			func->pfmem[i] = NULL;
+		} else if (bus_mem[i]) {
+			ibmphp_remove_resource (bus_mem[i]);
+			func->mem[i] = NULL;
+		}
+	}
+	return retval;
+}
+
+/*****************************************************************************
+ * This function adds up the amount of resources needed behind the PPB bridge
+ * and passes it to the configure_bridge function
+ * Input: bridge function
+ * Ouput: amount of resources needed
+ *****************************************************************************/
+static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno)
+{
+	int count, len[6];
+	u16 vendor_id;
+	u8 hdr_type;
+	u8 device, function;
+	unsigned int devfn;
+	int howmany = 0;	/*this is to see if there are any devices behind the bridge */
+
+	u32 bar[6], class;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	struct res_needed *amount;
+
+	amount = kmalloc(sizeof(*amount), GFP_KERNEL);
+	if (amount == NULL)
+		return NULL;
+	memset (amount, 0, sizeof (struct res_needed));
+
+	ibmphp_pci_bus->number = busno;
+
+	debug ("the bus_no behind the bridge is %x\n", busno);
+	debug ("scanning devices behind the bridge...\n");
+	for (device = 0; device < 32; device++) {
+		amount->devices[device] = 0;
+		for (function = 0; function < 8; function++) {
+			devfn = PCI_DEVFN(device, function);
+
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
+
+			if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
+				/* found correct device!!! */
+				howmany++;
+
+				pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
+				pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
+
+				debug ("hdr_type behind the bridge is %x\n", hdr_type);
+				if (hdr_type & PCI_HEADER_TYPE_BRIDGE) {
+					err ("embedded bridges not supported for hot-plugging.\n");
+					amount->not_correct = TRUE;
+					return amount;
+				}
+
+				class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
+				if (class == PCI_CLASS_NOT_DEFINED_VGA) {
+					err ("The device %x is VGA compatible and as is not supported for hot plugging. "
+					     "Please choose another device.\n", device);
+					amount->not_correct = TRUE;
+					return amount;
+				} else if (class == PCI_CLASS_DISPLAY_VGA) {
+					err ("The device %x is not supported for hot plugging. "
+					     "Please choose another device.\n", device);
+					amount->not_correct = TRUE;
+					return amount;
+				}
+
+				amount->devices[device] = 1;
+
+				for (count = 0; address[count]; count++) {
+					/* for 6 BARs */
+					/*
+					pci_bus_read_config_byte (ibmphp_pci_bus, devfn, address[count], &tmp);
+					if (tmp & 0x01) // IO
+						pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFD);
+					else // MEMORY
+						pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
+					*/
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
+					pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
+
+					debug ("what is bar[count]? %x, count = %d\n", bar[count], count);
+
+					if (!bar[count])	/* This BAR is not implemented */
+						continue;
+
+					//tmp_bar = bar[count];
+
+					debug ("count %d device %x function %x wants %x resources\n", count, device, function, bar[count]);
+
+					if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {
+						/* This is IO */
+						len[count] = bar[count] & 0xFFFFFFFC;
+						len[count] = ~len[count] + 1;
+						amount->io += len[count];
+					} else {
+						/* This is Memory */
+						if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+							/* pfmem */
+							len[count] = bar[count] & 0xFFFFFFF0;
+							len[count] = ~len[count] + 1;
+							amount->pfmem += len[count];
+							if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64)
+								/* takes up another dword */
+								count += 1;
+
+						} else {
+							/* regular memory */
+							len[count] = bar[count] & 0xFFFFFFF0;
+							len[count] = ~len[count] + 1;
+							amount->mem += len[count];
+							if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+								/* takes up another dword */
+								count += 1;
+							}
+						}
+					}
+				}	/* end for */
+			}	/* end if (valid) */
+		}	/* end for */
+	}	/* end for */
+
+	if (!howmany)
+		amount->not_correct = TRUE;
+	else
+		amount->not_correct = FALSE;
+	if ((amount->io) && (amount->io < IOBRIDGE))
+		amount->io = IOBRIDGE;
+	if ((amount->mem) && (amount->mem < MEMBRIDGE))
+		amount->mem = MEMBRIDGE;
+	if ((amount->pfmem) && (amount->pfmem < MEMBRIDGE))
+		amount->pfmem = MEMBRIDGE;
+	return amount;
+}
+
+/* The following 3 unconfigure_boot_ routines deal with the case when we had the card 
+ * upon bootup in the system, since we don't allocate func to such case, we need to read 
+ * the start addresses from pci config space and then find the corresponding entries in 
+ * our resource lists.  The functions return either 0, -ENODEV, or -1 (general failure)
+ * Change: we also call these functions even if we configured the card ourselves (i.e., not
+ * the bootup case), since it should work same way
+ */
+static int unconfigure_boot_device (u8 busno, u8 device, u8 function)
+{
+	u32 start_address;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct resource_node *io;
+	struct resource_node *mem;
+	struct resource_node *pfmem;
+	struct bus_node *bus;
+	u32 end_address;
+	u32 temp_end;
+	u32 size;
+	u32 tmp_address;
+	unsigned int devfn;
+
+	debug ("%s - enter\n", __FUNCTION__);
+
+	bus = ibmphp_find_res_bus (busno);
+	if (!bus) {
+		debug ("cannot find corresponding bus.\n");
+		return -EINVAL;
+	}
+
+	devfn = PCI_DEVFN(device, function);
+	ibmphp_pci_bus->number = busno;
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address);
+
+		/* We can do this here, b/c by that time the device driver of the card has been stopped */
+
+		pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &size);
+		pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], start_address);
+
+		debug ("start_address is %x\n", start_address);
+		debug ("busno, device, function %x %x %x\n", busno, device, function);
+		if (!size) {
+			/* This BAR is not implemented */
+			debug ("is this bar no implemented?, count = %d\n", count);
+			continue;
+		}
+		tmp_address = start_address;
+		if (start_address & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			start_address &= PCI_BASE_ADDRESS_IO_MASK;
+			size = size & 0xFFFFFFFC;
+			size = ~size + 1;
+			end_address = start_address + size - 1;
+			if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) {
+				err ("cannot find corresponding IO resource to remove\n");
+				return -EIO;
+			}
+			debug ("io->start = %x\n", io->start);
+			temp_end = io->end;
+			start_address = io->end + 1;
+			ibmphp_remove_resource (io);
+			/* This is needed b/c of the old I/O restrictions in the BIOS */
+			while (temp_end < end_address) {
+				if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) {
+					err ("cannot find corresponding IO resource to remove\n");
+					return -EIO;
+				}
+				debug ("io->start = %x\n", io->start);
+				temp_end = io->end;
+				start_address = io->end + 1;
+				ibmphp_remove_resource (io);
+			}
+
+			/* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */
+		} else {
+			/* This is Memory */
+			start_address &= PCI_BASE_ADDRESS_MEM_MASK;
+			if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+				debug ("start address of pfmem is %x\n", start_address);
+
+				if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) {
+					err ("cannot find corresponding PFMEM resource to remove\n");
+					return -EIO;
+				}
+				if (pfmem) {
+					debug ("pfmem->start = %x\n", pfmem->start);
+
+					ibmphp_remove_resource(pfmem);
+				}
+			} else {
+				/* regular memory */
+				debug ("start address of mem is %x\n", start_address);
+				if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) {
+					err ("cannot find corresponding MEM resource to remove\n");
+					return -EIO;
+				}
+				if (mem) {
+					debug ("mem->start = %x\n", mem->start);
+
+					ibmphp_remove_resource(mem);
+				}
+			}
+			if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+				/* takes up another dword */
+				count += 1;
+			}
+		}	/* end of mem */
+	}	/* end of for */
+
+	return 0;
+}
+
+static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function)
+{
+	int count;
+	int bus_no, pri_no, sub_no, sec_no = 0;
+	u32 start_address, tmp_address;
+	u8 sec_number, sub_number, pri_number;
+	struct resource_node *io = NULL;
+	struct resource_node *mem = NULL;
+	struct resource_node *pfmem = NULL;
+	struct bus_node *bus;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		0
+	};
+	unsigned int devfn;
+
+	devfn = PCI_DEVFN(device, function);
+	ibmphp_pci_bus->number = busno;
+	bus_no = (int) busno;
+	debug ("busno is %x\n", busno);
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number);
+	debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number);
+
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
+	debug ("sec_number is %x\n", sec_number);
+	sec_no = (int) sec_number;
+	pri_no = (int) pri_number;
+	if (pri_no != bus_no) {
+		err ("primary numbers in our structures and pci config space don't match.\n");
+		return -EINVAL;
+	}
+
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sub_number);
+	sub_no = (int) sub_number;
+	debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no);
+	if (sec_no != sub_number) {
+		err ("there're more buses behind this bridge.  Hot removal is not supported.  Please choose another card\n");
+		return -ENODEV;
+	}
+
+	bus = ibmphp_find_res_bus (sec_number);
+	debug ("bus->busno is %x\n", bus->busno);
+	debug ("sec_number is %x\n", sec_number);
+	if (!bus) {
+		err ("cannot find Bus structure for the bridged device\n");
+		return -EINVAL;
+	}
+
+	ibmphp_remove_bus (bus, busno);
+
+	for (count = 0; address[count]; count++) {
+		/* for 2 BARs */
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address);
+
+		if (!start_address) {
+			/* This BAR is not implemented */
+			continue;
+		}
+
+		tmp_address = start_address;
+
+		if (start_address & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			start_address &= PCI_BASE_ADDRESS_IO_MASK;
+			if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) {
+				err ("cannot find corresponding IO resource to remove\n");
+				return -EIO;
+			}
+			if (io)
+				debug ("io->start = %x\n", io->start);
+
+			ibmphp_remove_resource (io);
+
+			/* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */
+		} else {
+			/* This is Memory */
+			start_address &= PCI_BASE_ADDRESS_MEM_MASK;
+			if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+				if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) {
+					err ("cannot find corresponding PFMEM resource to remove\n");
+					return -EINVAL;
+				}
+				if (pfmem) {
+					debug ("pfmem->start = %x\n", pfmem->start);
+
+					ibmphp_remove_resource(pfmem);
+				}
+			} else {
+				/* regular memory */
+				if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) {
+					err ("cannot find corresponding MEM resource to remove\n");
+					return -EINVAL;
+				}
+				if (mem) {
+					debug ("mem->start = %x\n", mem->start);
+
+					ibmphp_remove_resource(mem);
+				}
+			}
+			if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+				/* takes up another dword */
+				count += 1;
+			}
+		}	/* end of mem */
+	}	/* end of for */
+	debug ("%s - exiting, returning success\n", __FUNCTION__);
+	return 0;
+}
+
+static int unconfigure_boot_card (struct slot *slot_cur)
+{
+	u16 vendor_id;
+	u32 class;
+	u8 hdr_type;
+	u8 device;
+	u8 busno;
+	u8 function;
+	int rc;
+	unsigned int devfn;
+	u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */
+
+	debug ("%s - enter\n", __FUNCTION__);
+
+	device = slot_cur->device;
+	busno = slot_cur->bus;
+
+	debug ("b4 for loop, device is %x\n", device);
+	/* For every function on the card */
+	for (function = 0x0; function < 0x08; function++) {
+		devfn = PCI_DEVFN(device, function);
+		ibmphp_pci_bus->number = busno;
+
+		pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
+
+		if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
+			/* found correct device!!! */
+			++valid_device;
+
+			debug ("%s - found correct device\n", __FUNCTION__);
+
+			/* header: x x x x x x x x
+			 *         | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge
+			 *         |_=> 0 = single function device, 1 = multi-function device
+			 */
+
+			pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
+			pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
+
+			debug ("hdr_type %x, class %x\n", hdr_type, class);
+			class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
+			if (class == PCI_CLASS_NOT_DEFINED_VGA) {
+				err ("The device %x function %x is VGA compatible and is not supported for hot removing. "
+				     "Please choose another device.\n", device, function);
+				return -ENODEV;
+			} else if (class == PCI_CLASS_DISPLAY_VGA) {
+				err ("The device %x function %x is not supported for hot removing. "
+				     "Please choose another device.\n", device, function);
+				return -ENODEV;
+			}
+
+			switch (hdr_type) {
+				case PCI_HEADER_TYPE_NORMAL:
+					rc = unconfigure_boot_device (busno, device, function);
+					if (rc) {
+						err ("was not able to unconfigure device %x func %x on bus %x. bailing out...\n",
+						     device, function, busno);
+						return rc;
+					}
+					function = 0x8;
+					break;
+				case PCI_HEADER_TYPE_MULTIDEVICE:
+					rc = unconfigure_boot_device (busno, device, function);
+					if (rc) {
+						err ("was not able to unconfigure device %x func %x on bus %x. bailing out...\n",
+						     device, function, busno);
+						return rc;
+					}
+					break;
+				case PCI_HEADER_TYPE_BRIDGE:
+					class >>= 8;
+					if (class != PCI_CLASS_BRIDGE_PCI) {
+						err ("This device %x function %x is not PCI-to-PCI bridge, "
+						     "and is not supported for hot-removing. "
+						     "Please try another card.\n", device, function);
+						return -ENODEV;
+					}
+					rc = unconfigure_boot_bridge (busno, device, function);
+					if (rc != 0) {
+						err ("was not able to hot-remove PPB properly.\n");
+						return rc;
+					}
+
+					function = 0x8;
+					break;
+				case PCI_HEADER_TYPE_MULTIBRIDGE:
+					class >>= 8;
+					if (class != PCI_CLASS_BRIDGE_PCI) {
+						err ("This device %x function %x is not PCI-to-PCI bridge, "
+						     "and is not supported for hot-removing. "
+						     "Please try another card.\n", device, function);
+						return -ENODEV;
+					}
+					rc = unconfigure_boot_bridge (busno, device, function);
+					if (rc != 0) {
+						err ("was not able to hot-remove PPB properly.\n");
+						return rc;
+					}
+					break;
+				default:
+					err ("MAJOR PROBLEM!!!! Cannot read device's header\n");
+					return -1;
+					break;
+			}	/* end of switch */
+		}	/* end of valid device */
+	}	/* end of for */
+
+	if (!valid_device) {
+		err ("Could not find device to unconfigure.  Or could not read the card.\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * free the resources of the card (multi, single, or bridged)
+ * Parameters: slot, flag to say if this is for removing entire module or just
+ * unconfiguring the device
+ * TO DO:  will probably need to add some code in case there was some resource,
+ * to remove it... this is from when we have errors in the configure_card...
+ * 			!!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!!
+ * Returns: 0, -1, -ENODEV 
+ */
+int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end)
+{
+	int i;
+	int count;
+	int rc;
+	struct slot *sl = *slot_cur;
+	struct pci_func *cur_func = NULL;
+	struct pci_func *temp_func;
+
+	debug ("%s - enter\n", __FUNCTION__);
+
+	if (!the_end) {
+		/* Need to unconfigure the card */
+		rc = unconfigure_boot_card (sl);
+		if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) {
+			/* In all other cases, will still need to get rid of func structure if it exists */
+			return rc;
+		}
+	}
+
+	if (sl->func) {
+		cur_func = sl->func;
+		while (cur_func) {
+			/* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */
+			if (cur_func->bus) {
+				/* in other words, it's a PPB */
+				count = 2;
+			} else {
+				count = 6;
+			}
+
+			for (i = 0; i < count; i++) {
+				if (cur_func->io[i]) {
+					debug ("io[%d] exists\n", i);
+					if (the_end > 0)
+						ibmphp_remove_resource (cur_func->io[i]);
+					cur_func->io[i] = NULL;
+				}
+				if (cur_func->mem[i]) {
+					debug ("mem[%d] exists\n", i);
+					if (the_end > 0)
+						ibmphp_remove_resource (cur_func->mem[i]);
+					cur_func->mem[i] = NULL;
+				}
+				if (cur_func->pfmem[i]) {
+					debug ("pfmem[%d] exists\n", i);
+					if (the_end > 0)
+						ibmphp_remove_resource (cur_func->pfmem[i]);
+					cur_func->pfmem[i] = NULL;
+				}
+			}
+
+			temp_func = cur_func->next;
+			kfree (cur_func);
+			cur_func = temp_func;
+		}
+	}
+
+	sl->func = NULL;
+	*slot_cur = sl;
+	debug ("%s - exit\n", __FUNCTION__);
+	return 0;
+}
+
+/*
+ * add a new bus resulting from hot-plugging a PPB bridge with devices
+ *
+ * Input: bus and the amount of resources needed (we know we can assign those,
+ *        since they've been checked already
+ * Output: bus added to the correct spot
+ *         0, -1, error 
+ */
+static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno)
+{
+	struct range_node *io_range = NULL;
+	struct range_node *mem_range = NULL;
+	struct range_node *pfmem_range = NULL;
+	struct bus_node *cur_bus = NULL;
+
+	/* Trying to find the parent bus number */
+	if (parent_busno != 0xFF) {
+		cur_bus	= ibmphp_find_res_bus (parent_busno);
+		if (!cur_bus) {
+			err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n");
+			return -ENODEV;
+		}
+	
+		list_add (&bus->bus_list, &cur_bus->bus_list);
+	}
+	if (io) {
+		io_range = kmalloc(sizeof(*io_range), GFP_KERNEL);
+		if (!io_range) {
+			err ("out of system memory\n");
+			return -ENOMEM;
+		}
+		memset (io_range, 0, sizeof (struct range_node));
+		io_range->start = io->start;
+		io_range->end = io->end;
+		io_range->rangeno = 1;
+		bus->noIORanges = 1;
+		bus->rangeIO = io_range;
+	}
+	if (mem) {
+		mem_range = kmalloc(sizeof(*mem_range), GFP_KERNEL);
+		if (!mem_range) {
+			err ("out of system memory\n");
+			return -ENOMEM;
+		}
+		memset (mem_range, 0, sizeof (struct range_node));
+		mem_range->start = mem->start;
+		mem_range->end = mem->end;
+		mem_range->rangeno = 1;
+		bus->noMemRanges = 1;
+		bus->rangeMem = mem_range;
+	}
+	if (pfmem) {
+		pfmem_range = kmalloc(sizeof(*pfmem_range), GFP_KERNEL);
+		if (!pfmem_range) {	
+			err ("out of system memory\n");
+			return -ENOMEM;
+		}
+		memset (pfmem_range, 0, sizeof (struct range_node));
+		pfmem_range->start = pfmem->start;
+		pfmem_range->end = pfmem->end;
+		pfmem_range->rangeno = 1;
+		bus->noPFMemRanges = 1;
+		bus->rangePFMem = pfmem_range;
+	}
+	return 0;
+}
+
+/*
+ * find the 1st available bus number for PPB to set as its secondary bus
+ * Parameters: bus_number of the primary bus
+ * Returns: bus_number of the secondary bus or 0xff in case of failure
+ */
+static u8 find_sec_number (u8 primary_busno, u8 slotno)
+{
+	int min, max;
+	u8 busno;
+	struct bus_info *bus;
+	struct bus_node *bus_cur;
+
+	bus = ibmphp_find_same_bus_num (primary_busno);
+	if (!bus) {
+		err ("cannot get slot range of the bus from the BIOS\n");
+		return 0xff;
+	}
+	max = bus->slot_max;
+	min = bus->slot_min;
+	if ((slotno > max) || (slotno < min)) {
+		err ("got the wrong range\n");
+		return 0xff;
+	}
+	busno = (u8) (slotno - (u8) min);
+	busno += primary_busno + 0x01;
+	bus_cur = ibmphp_find_res_bus (busno);
+	/* either there is no such bus number, or there are no ranges, which
+	 * can only happen if we removed the bridged device in previous load
+	 * of the driver, and now only have the skeleton bus struct
+	 */
+	if ((!bus_cur) || (!(bus_cur->rangeIO) && !(bus_cur->rangeMem) && !(bus_cur->rangePFMem)))
+		return busno;
+	return 0xff;
+}
+
diff --git a/drivers/pci/hotplug/ibmphp_res.c b/drivers/pci/hotplug/ibmphp_res.c
new file mode 100644
index 0000000..9c224c9
--- /dev/null
+++ b/drivers/pci/hotplug/ibmphp_res.c
@@ -0,0 +1,2156 @@
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Irene Zubarev, IBM Corporation
+ *
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2002 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include "ibmphp.h"
+
+static int flags = 0;		/* for testing */
+
+static void update_resources (struct bus_node *bus_cur, int type, int rangeno);
+static int once_over (void);
+static int remove_ranges (struct bus_node *, struct bus_node *);
+static int update_bridge_ranges (struct bus_node **);
+static int add_range (int type, struct range_node *, struct bus_node *);
+static void fix_resources (struct bus_node *);
+static struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);
+
+static LIST_HEAD(gbuses);
+
+static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag)
+{
+	struct bus_node * newbus;
+
+	if (!(curr) && !(flag)) {
+		err ("NULL pointer passed\n");
+		return NULL;
+	}
+
+	newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
+	if (!newbus) {
+		err ("out of system memory\n");
+		return NULL;
+	}
+
+	memset (newbus, 0, sizeof (struct bus_node));
+	if (flag)
+		newbus->busno = busno;
+	else
+		newbus->busno = curr->bus_num;
+	list_add_tail (&newbus->bus_list, &gbuses);
+	return newbus;
+}
+
+static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr)
+{
+	struct resource_node *rs;
+	
+	if (!curr) {
+		err ("NULL passed to allocate\n");
+		return NULL;
+	}
+
+	rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+	if (!rs) {
+		err ("out of system memory\n");
+		return NULL;
+	}
+	memset (rs, 0, sizeof (struct resource_node));
+	rs->busno = curr->bus_num;
+	rs->devfunc = curr->dev_fun;
+	rs->start = curr->start_addr;
+	rs->end = curr->end_addr;
+	rs->len = curr->end_addr - curr->start_addr + 1;
+	return rs;
+}
+
+static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
+{
+	struct bus_node * newbus;
+	struct range_node *newrange;
+	u8 num_ranges = 0;
+
+	if (first_bus) {
+		newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
+		if (!newbus) {
+			err ("out of system memory.\n");
+			return -ENOMEM;
+		}
+		memset (newbus, 0, sizeof (struct bus_node));
+		newbus->busno = curr->bus_num;
+	} else {
+		newbus = *new_bus;
+		switch (flag) {
+			case MEM:
+				num_ranges = newbus->noMemRanges;
+				break;
+			case PFMEM:
+				num_ranges = newbus->noPFMemRanges;
+				break;
+			case IO:
+				num_ranges = newbus->noIORanges;
+				break;
+		}
+	}
+
+	newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+	if (!newrange) {
+		if (first_bus)
+			kfree (newbus);
+		err ("out of system memory\n");
+		return -ENOMEM;
+	}
+	memset (newrange, 0, sizeof (struct range_node));
+	newrange->start = curr->start_addr;
+	newrange->end = curr->end_addr;
+		
+	if (first_bus || (!num_ranges))
+		newrange->rangeno = 1;
+	else {
+		/* need to insert our range */
+		add_range (flag, newrange, newbus);
+		debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end);
+	}
+
+	switch (flag) {
+		case MEM:
+			newbus->rangeMem = newrange;
+			if (first_bus)
+				newbus->noMemRanges = 1;
+			else {
+				debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				++newbus->noMemRanges;
+				fix_resources (newbus);
+			}
+			break;
+		case IO:
+			newbus->rangeIO = newrange;
+			if (first_bus)
+				newbus->noIORanges = 1;
+			else {
+				debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				++newbus->noIORanges;
+				fix_resources (newbus);
+			}
+			break;
+		case PFMEM:
+			newbus->rangePFMem = newrange;
+			if (first_bus)
+				newbus->noPFMemRanges = 1;
+			else {	
+				debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				++newbus->noPFMemRanges;
+				fix_resources (newbus);
+			}
+
+			break;
+	}
+
+	*new_bus = newbus;
+	*new_range = newrange;
+	return 0;
+}
+
+
+/* Notes:
+ * 1. The ranges are ordered.  The buses are not ordered.  (First come)
+ *
+ * 2. If cannot allocate out of PFMem range, allocate from Mem ranges.  PFmemFromMem
+ * are not sorted. (no need since use mem node). To not change the entire code, we
+ * also add mem node whenever this case happens so as not to change
+ * ibmphp_check_mem_resource etc (and since it really is taking Mem resource)
+ */
+
+/*****************************************************************************
+ * This is the Resource Management initialization function.  It will go through
+ * the Resource list taken from EBDA and fill in this module's data structures
+ *
+ * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, 
+ * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW
+ *
+ * Input: ptr to the head of the resource list from EBDA
+ * Output: 0, -1 or error codes
+ ***************************************************************************/
+int __init ibmphp_rsrc_init (void)
+{
+	struct ebda_pci_rsrc *curr;
+	struct range_node *newrange = NULL;
+	struct bus_node *newbus = NULL;
+	struct bus_node *bus_cur;
+	struct bus_node *bus_prev;
+	struct list_head *tmp;
+	struct resource_node *new_io = NULL;
+	struct resource_node *new_mem = NULL;
+	struct resource_node *new_pfmem = NULL;
+	int rc;
+	struct list_head *tmp_ebda;
+
+	list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) {
+		curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
+		if (!(curr->rsrc_type & PCIDEVMASK)) {
+			/* EBDA still lists non PCI devices, so ignore... */
+			debug ("this is not a PCI DEVICE in rsrc_init, please take care\n");
+			// continue;
+		}
+
+		/* this is a primary bus resource */
+		if (curr->rsrc_type & PRIMARYBUSMASK) {
+			/* memory */
+			if ((curr->rsrc_type & RESTYPE) == MMASK) {
+				/* no bus structure exists in place yet */
+				if (list_empty (&gbuses)) {
+					if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1)))
+						return rc;
+					list_add_tail (&newbus->bus_list, &gbuses);
+					debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				} else {
+					bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);
+					/* found our bus */
+					if (bus_cur) {
+						rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0);
+						if (rc)
+							return rc;
+					} else {
+						/* went through all the buses and didn't find ours, need to create a new bus node */
+						if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1)))
+							return rc;
+
+						list_add_tail (&newbus->bus_list, &gbuses);
+						debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+					}
+				}
+			} else if ((curr->rsrc_type & RESTYPE) == PFMASK) {
+				/* prefetchable memory */
+				if (list_empty (&gbuses)) {
+					/* no bus structure exists in place yet */
+					if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1)))
+						return rc;
+					list_add_tail (&newbus->bus_list, &gbuses);
+					debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				} else {
+					bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);
+					if (bus_cur) {
+						/* found our bus */
+						rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0);
+						if (rc)
+							return rc;
+					} else {
+						/* went through all the buses and didn't find ours, need to create a new bus node */
+						if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1)))
+							return rc;
+						list_add_tail (&newbus->bus_list, &gbuses);
+						debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+					}
+				}
+			} else if ((curr->rsrc_type & RESTYPE) == IOMASK) {
+				/* IO */
+				if (list_empty (&gbuses)) {
+					/* no bus structure exists in place yet */
+					if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1)))
+						return rc;
+					list_add_tail (&newbus->bus_list, &gbuses);
+					debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				} else {
+					bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);
+					if (bus_cur) {
+						rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0);
+						if (rc)
+							return rc;
+					} else {
+						/* went through all the buses and didn't find ours, need to create a new bus node */
+						if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1)))
+							return rc;
+						list_add_tail (&newbus->bus_list, &gbuses);
+						debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+					}
+				}
+
+			} else {
+				;	/* type is reserved  WHAT TO DO IN THIS CASE???
+					   NOTHING TO DO??? */
+			}
+		} else {
+			/* regular pci device resource */
+			if ((curr->rsrc_type & RESTYPE) == MMASK) {
+				/* Memory resource */
+				new_mem = alloc_resources (curr);
+				if (!new_mem)
+					return -ENOMEM;
+				new_mem->type = MEM;
+				/*
+				 * if it didn't find the bus, means PCI dev
+				 * came b4 the Primary Bus info, so need to
+				 * create a bus rangeno becomes a problem...
+				 * assign a -1 and then update once the range
+				 * actually appears...
+				 */
+				if (ibmphp_add_resource (new_mem) < 0) {
+					newbus = alloc_error_bus (curr, 0, 0);
+					if (!newbus)
+						return -ENOMEM;
+					newbus->firstMem = new_mem;
+					++newbus->needMemUpdate;
+					new_mem->rangeno = -1;
+				}
+				debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end);
+
+			} else if ((curr->rsrc_type & RESTYPE) == PFMASK) {
+				/* PFMemory resource */
+				new_pfmem = alloc_resources (curr);
+				if (!new_pfmem)
+					return -ENOMEM;
+				new_pfmem->type = PFMEM;
+				new_pfmem->fromMem = FALSE;
+				if (ibmphp_add_resource (new_pfmem) < 0) {
+					newbus = alloc_error_bus (curr, 0, 0);
+					if (!newbus)
+						return -ENOMEM;
+					newbus->firstPFMem = new_pfmem;
+					++newbus->needPFMemUpdate;
+					new_pfmem->rangeno = -1;
+				}
+
+				debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end);
+			} else if ((curr->rsrc_type & RESTYPE) == IOMASK) {
+				/* IO resource */
+				new_io = alloc_resources (curr);
+				if (!new_io)
+					return -ENOMEM;
+				new_io->type = IO;
+
+				/*
+				 * if it didn't find the bus, means PCI dev
+				 * came b4 the Primary Bus info, so need to
+				 * create a bus rangeno becomes a problem...
+				 * Can assign a -1 and then update once the
+				 * range actually appears...
+				 */
+				if (ibmphp_add_resource (new_io) < 0) {
+					newbus = alloc_error_bus (curr, 0, 0);
+					if (!newbus)
+						return -ENOMEM;
+					newbus->firstIO = new_io;
+					++newbus->needIOUpdate;
+					new_io->rangeno = -1;
+				}
+				debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end);
+			}
+		}
+	}
+
+	list_for_each (tmp, &gbuses) {
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		/* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */
+		rc = update_bridge_ranges (&bus_cur);
+		if (rc)
+			return rc;
+	}
+	rc = once_over ();  /* This is to align ranges (so no -1) */
+	if (rc)
+		return rc;
+	return 0;
+}
+
+/********************************************************************************
+ * This function adds a range into a sorted list of ranges per bus for a particular
+ * range type, it then calls another routine to update the range numbers on the
+ * pci devices' resources for the appropriate resource
+ *
+ * Input: type of the resource, range to add, current bus
+ * Output: 0 or -1, bus and range ptrs 
+ ********************************************************************************/
+static int add_range (int type, struct range_node *range, struct bus_node *bus_cur)
+{
+	struct range_node *range_cur = NULL;
+	struct range_node *range_prev;
+	int count = 0, i_init;
+	int noRanges = 0;
+
+	switch (type) {
+		case MEM:
+			range_cur = bus_cur->rangeMem;
+			noRanges = bus_cur->noMemRanges;
+			break;
+		case PFMEM:
+			range_cur = bus_cur->rangePFMem;
+			noRanges = bus_cur->noPFMemRanges;
+			break;
+		case IO:
+			range_cur = bus_cur->rangeIO;
+			noRanges = bus_cur->noIORanges;
+			break;
+	}
+
+	range_prev = NULL;
+	while (range_cur) {
+		if (range->start < range_cur->start)
+			break;
+		range_prev = range_cur;
+		range_cur = range_cur->next;
+		count = count + 1;
+	}
+	if (!count) {
+		/* our range will go at the beginning of the list */
+		switch (type) {
+			case MEM:
+				bus_cur->rangeMem = range;
+				break;
+			case PFMEM:
+				bus_cur->rangePFMem = range;
+				break;
+			case IO:
+				bus_cur->rangeIO = range;
+				break;
+		}
+		range->next = range_cur;
+		range->rangeno = 1;
+		i_init = 0;
+	} else if (!range_cur) {
+		/* our range will go at the end of the list */
+		range->next = NULL;
+		range_prev->next = range;
+		range->rangeno = range_prev->rangeno + 1;
+		return 0;
+	} else {
+		/* the range is in the middle */
+		range_prev->next = range;
+		range->next = range_cur;
+		range->rangeno = range_cur->rangeno;
+		i_init = range_prev->rangeno;
+	}
+
+	for (count = i_init; count < noRanges; ++count) {
+		++range_cur->rangeno;
+		range_cur = range_cur->next;
+	}
+
+	update_resources (bus_cur, type, i_init + 1);
+	return 0;
+}
+
+/*******************************************************************************
+ * This routine goes through the list of resources of type 'type' and updates
+ * the range numbers that they correspond to.  It was called from add_range fnc
+ *
+ * Input: bus, type of the resource, the rangeno starting from which to update
+ ******************************************************************************/
+static void update_resources (struct bus_node *bus_cur, int type, int rangeno)
+{
+	struct resource_node *res = NULL;
+	u8 eol = FALSE;	/* end of list indicator */
+
+	switch (type) {
+		case MEM:
+			if (bus_cur->firstMem) 
+				res = bus_cur->firstMem;
+			break;
+		case PFMEM:
+			if (bus_cur->firstPFMem)
+				res = bus_cur->firstPFMem;
+			break;
+		case IO:
+			if (bus_cur->firstIO)
+				res = bus_cur->firstIO;
+			break;
+	}
+
+	if (res) {
+		while (res) {
+			if (res->rangeno == rangeno)
+				break;
+			if (res->next)
+				res = res->next;
+			else if (res->nextRange)
+				res = res->nextRange;
+			else {
+				eol = TRUE;
+				break;
+			}
+		}
+
+		if (!eol) {
+			/* found the range */
+			while (res) {
+				++res->rangeno;
+				res = res->next;
+			}
+		}
+	}
+}
+
+static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range)
+{
+	char * str = "";
+	switch (res->type) {
+		case IO:
+			str = "io";
+			break;
+		case MEM:
+			str = "mem";
+			break;
+		case PFMEM:
+			str = "pfmem";
+			break;
+	}
+
+	while (res) {
+		if (res->rangeno == -1) {
+			while (range) {
+				if ((res->start >= range->start) && (res->end <= range->end)) {
+					res->rangeno = range->rangeno;
+					debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno);
+					switch (res->type) {
+						case IO:
+							--bus_cur->needIOUpdate;
+							break;
+						case MEM:
+							--bus_cur->needMemUpdate;
+							break;
+						case PFMEM:
+							--bus_cur->needPFMemUpdate;
+							break;
+					}
+					break;
+				}
+				range = range->next;
+			}
+		}
+		if (res->next)
+			res = res->next;
+		else
+			res = res->nextRange;
+	}
+
+}
+
+/*****************************************************************************
+ * This routine reassigns the range numbers to the resources that had a -1
+ * This case can happen only if upon initialization, resources taken by pci dev
+ * appear in EBDA before the resources allocated for that bus, since we don't
+ * know the range, we assign -1, and this routine is called after a new range
+ * is assigned to see the resources with unknown range belong to the added range
+ *
+ * Input: current bus
+ * Output: none, list of resources for that bus are fixed if can be
+ *******************************************************************************/
+static void fix_resources (struct bus_node *bus_cur)
+{
+	struct range_node *range;
+	struct resource_node *res;
+
+	debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno);
+
+	if (bus_cur->needIOUpdate) {
+		res = bus_cur->firstIO;
+		range = bus_cur->rangeIO;
+		fix_me (res, bus_cur, range);
+	}
+	if (bus_cur->needMemUpdate) {
+		res = bus_cur->firstMem;
+		range = bus_cur->rangeMem;
+		fix_me (res, bus_cur, range);
+	}
+	if (bus_cur->needPFMemUpdate) {
+		res = bus_cur->firstPFMem;
+		range = bus_cur->rangePFMem;
+		fix_me (res, bus_cur, range);
+	}
+}
+
+/*******************************************************************************
+ * This routine adds a resource to the list of resources to the appropriate bus 
+ * based on their resource type and sorted by their starting addresses.  It assigns
+ * the ptrs to next and nextRange if needed.
+ *
+ * Input: resource ptr
+ * Output: ptrs assigned (to the node)
+ * 0 or -1
+ *******************************************************************************/
+int ibmphp_add_resource (struct resource_node *res)
+{
+	struct resource_node *res_cur;
+	struct resource_node *res_prev;
+	struct bus_node *bus_cur;
+	struct range_node *range_cur = NULL;
+	struct resource_node *res_start = NULL;
+
+	debug ("%s - enter\n", __FUNCTION__);
+
+	if (!res) {
+		err ("NULL passed to add\n");
+		return -ENODEV;
+	}
+	
+	bus_cur = find_bus_wprev (res->busno, NULL, 0);
+	
+	if (!bus_cur) {
+		/* didn't find a bus, smth's wrong!!! */
+		debug ("no bus in the system, either pci_dev's wrong or allocation failed\n");
+		return -ENODEV;
+	}
+
+	/* Normal case */
+	switch (res->type) {
+		case IO:
+			range_cur = bus_cur->rangeIO;
+			res_start = bus_cur->firstIO;
+			break;
+		case MEM:
+			range_cur = bus_cur->rangeMem;
+			res_start = bus_cur->firstMem;
+			break;
+		case PFMEM:
+			range_cur = bus_cur->rangePFMem;
+			res_start = bus_cur->firstPFMem;
+			break;
+		default:
+			err ("cannot read the type of the resource to add... problem\n");
+			return -EINVAL;
+	}
+	while (range_cur) {
+		if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) {
+			res->rangeno = range_cur->rangeno;
+			break;
+		}
+		range_cur = range_cur->next;
+	}
+
+	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+	 * this is again the case of rangeno = -1
+	 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+	 */
+
+	if (!range_cur) {
+		switch (res->type) {
+			case IO:
+				++bus_cur->needIOUpdate;					
+				break;
+			case MEM:
+				++bus_cur->needMemUpdate;
+				break;
+			case PFMEM:
+				++bus_cur->needPFMemUpdate;
+				break;
+		}
+		res->rangeno = -1;
+	}
+	
+	debug ("The range is %d\n", res->rangeno);
+	if (!res_start) {
+		/* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */
+		switch (res->type) {
+			case IO:
+				bus_cur->firstIO = res;					
+				break;
+			case MEM:
+				bus_cur->firstMem = res;
+				break;
+			case PFMEM:
+				bus_cur->firstPFMem = res;
+				break;
+		}	
+		res->next = NULL;
+		res->nextRange = NULL;
+	} else {
+		res_cur = res_start;
+		res_prev = NULL;
+
+		debug ("res_cur->rangeno is %d\n", res_cur->rangeno);
+
+		while (res_cur) {
+			if (res_cur->rangeno >= res->rangeno)
+				break;
+			res_prev = res_cur;
+			if (res_cur->next)
+				res_cur = res_cur->next;
+			else
+				res_cur = res_cur->nextRange;
+		}
+
+		if (!res_cur) {
+			/* at the end of the resource list */
+			debug ("i should be here, [%x - %x]\n", res->start, res->end);
+			res_prev->nextRange = res;
+			res->next = NULL;
+			res->nextRange = NULL;
+		} else if (res_cur->rangeno == res->rangeno) {
+			/* in the same range */
+			while (res_cur) {
+				if (res->start < res_cur->start)
+					break;
+				res_prev = res_cur;
+				res_cur = res_cur->next;
+			}
+			if (!res_cur) {
+				/* the last resource in this range */
+				res_prev->next = res;
+				res->next = NULL;
+				res->nextRange = res_prev->nextRange;
+				res_prev->nextRange = NULL;
+			} else if (res->start < res_cur->start) {
+				/* at the beginning or middle of the range */
+				if (!res_prev)	{
+					switch (res->type) {
+						case IO:
+							bus_cur->firstIO = res;
+							break;
+						case MEM:
+							bus_cur->firstMem = res;
+							break;
+						case PFMEM:
+							bus_cur->firstPFMem = res;
+							break;
+					}
+				} else if (res_prev->rangeno == res_cur->rangeno)
+					res_prev->next = res;
+				else
+					res_prev->nextRange = res;
+
+				res->next = res_cur;
+				res->nextRange = NULL;
+			}
+		} else {
+			/* this is the case where it is 1st occurrence of the range */
+			if (!res_prev) {
+				/* at the beginning of the resource list */
+				res->next = NULL;
+				switch (res->type) {
+					case IO:
+						res->nextRange = bus_cur->firstIO;
+						bus_cur->firstIO = res;
+						break;
+					case MEM:
+						res->nextRange = bus_cur->firstMem;
+						bus_cur->firstMem = res;
+						break;
+					case PFMEM:
+						res->nextRange = bus_cur->firstPFMem;
+						bus_cur->firstPFMem = res;
+						break;
+				}
+			} else if (res_cur->rangeno > res->rangeno) {
+				/* in the middle of the resource list */
+				res_prev->nextRange = res;
+				res->next = NULL;
+				res->nextRange = res_cur;
+			}
+		}
+	}
+
+	debug ("%s - exit\n", __FUNCTION__);
+	return 0;
+}
+
+/****************************************************************************
+ * This routine will remove the resource from the list of resources
+ *
+ * Input: io, mem, and/or pfmem resource to be deleted
+ * Ouput: modified resource list
+ *        0 or error code
+ ****************************************************************************/
+int ibmphp_remove_resource (struct resource_node *res)
+{
+	struct bus_node *bus_cur;
+	struct resource_node *res_cur = NULL;
+	struct resource_node *res_prev;
+	struct resource_node *mem_cur;
+	char * type = "";
+
+	if (!res)  {
+		err ("resource to remove is NULL\n");
+		return -ENODEV;
+	}
+
+	bus_cur = find_bus_wprev (res->busno, NULL, 0);
+
+	if (!bus_cur) {
+		err ("cannot find corresponding bus of the io resource to remove  "
+			"bailing out...\n");
+		return -ENODEV;
+	}
+
+	switch (res->type) {
+		case IO:
+			res_cur = bus_cur->firstIO;
+			type = "io";
+			break;
+		case MEM:
+			res_cur = bus_cur->firstMem;
+			type = "mem";
+			break;
+		case PFMEM:
+			res_cur = bus_cur->firstPFMem;
+			type = "pfmem";
+			break;
+		default:
+			err ("unknown type for resource to remove\n");
+			return -EINVAL;
+	}
+	res_prev = NULL;
+
+	while (res_cur) {
+		if ((res_cur->start == res->start) && (res_cur->end == res->end))
+			break;
+		res_prev = res_cur;
+		if (res_cur->next)
+			res_cur = res_cur->next;
+		else
+			res_cur = res_cur->nextRange;
+	}
+
+	if (!res_cur) {
+		if (res->type == PFMEM) {
+			/* 
+			 * case where pfmem might be in the PFMemFromMem list
+			 * so will also need to remove the corresponding mem
+			 * entry
+			 */
+			res_cur = bus_cur->firstPFMemFromMem;
+			res_prev = NULL;
+
+			while (res_cur) {
+				if ((res_cur->start == res->start) && (res_cur->end == res->end)) {
+					mem_cur = bus_cur->firstMem;
+					while (mem_cur) {
+						if ((mem_cur->start == res_cur->start)
+						    && (mem_cur->end == res_cur->end))
+							break;
+						if (mem_cur->next)
+							mem_cur = mem_cur->next;
+						else
+							mem_cur = mem_cur->nextRange;
+					}
+					if (!mem_cur) {
+						err ("cannot find corresponding mem node for pfmem...\n");
+						return -EINVAL;
+					}
+
+					ibmphp_remove_resource (mem_cur);
+					if (!res_prev)
+						bus_cur->firstPFMemFromMem = res_cur->next;
+					else
+						res_prev->next = res_cur->next;
+					kfree (res_cur);
+					return 0;
+				}
+				res_prev = res_cur;
+				if (res_cur->next)
+					res_cur = res_cur->next;
+				else
+					res_cur = res_cur->nextRange;
+			}
+			if (!res_cur) {
+				err ("cannot find pfmem to delete...\n");
+				return -EINVAL;
+			}
+		} else {
+			err ("the %s resource is not in the list to be deleted...\n", type);
+			return -EINVAL;
+		}
+	}
+	if (!res_prev) {
+		/* first device to be deleted */
+		if (res_cur->next) {
+			switch (res->type) {
+				case IO:
+					bus_cur->firstIO = res_cur->next;
+					break;
+				case MEM:
+					bus_cur->firstMem = res_cur->next;
+					break;
+				case PFMEM:
+					bus_cur->firstPFMem = res_cur->next;
+					break;
+			}
+		} else if (res_cur->nextRange) {
+			switch (res->type) {
+				case IO:
+					bus_cur->firstIO = res_cur->nextRange;
+					break;
+				case MEM:
+					bus_cur->firstMem = res_cur->nextRange;
+					break;
+				case PFMEM:
+					bus_cur->firstPFMem = res_cur->nextRange;
+					break;
+			}
+		} else {
+			switch (res->type) {
+				case IO:
+					bus_cur->firstIO = NULL;
+					break;
+				case MEM:
+					bus_cur->firstMem = NULL;
+					break;
+				case PFMEM:
+					bus_cur->firstPFMem = NULL;
+					break;
+			}
+		}
+		kfree (res_cur);
+		return 0;
+	} else {
+		if (res_cur->next) {
+			if (res_prev->rangeno == res_cur->rangeno)
+				res_prev->next = res_cur->next;
+			else
+				res_prev->nextRange = res_cur->next;
+		} else if (res_cur->nextRange) {
+			res_prev->next = NULL;
+			res_prev->nextRange = res_cur->nextRange;
+		} else {
+			res_prev->next = NULL;
+			res_prev->nextRange = NULL;
+		}
+		kfree (res_cur);
+		return 0;
+	}
+
+	return 0;
+}
+
+static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res)
+{
+	struct range_node * range = NULL;
+
+	switch (res->type) {
+		case IO:
+			range = bus_cur->rangeIO;
+			break;
+		case MEM:
+			range = bus_cur->rangeMem;
+			break;
+		case PFMEM:
+			range = bus_cur->rangePFMem;
+			break;
+		default:
+			err ("cannot read resource type in find_range\n");
+	}
+
+	while (range) {
+		if (res->rangeno == range->rangeno)
+			break;
+		range = range->next;
+	}
+	return range;
+}
+
+/*****************************************************************************
+ * This routine will check to make sure the io/mem/pfmem->len that the device asked for 
+ * can fit w/i our list of available IO/MEM/PFMEM resources.  If cannot, returns -EINVAL,
+ * otherwise, returns 0
+ *
+ * Input: resource
+ * Ouput: the correct start and end address are inputted into the resource node,
+ *        0 or -EINVAL
+ *****************************************************************************/
+int ibmphp_check_resource (struct resource_node *res, u8 bridge)
+{
+	struct bus_node *bus_cur;
+	struct range_node *range = NULL;
+	struct resource_node *res_prev;
+	struct resource_node *res_cur = NULL;
+	u32 len_cur = 0, start_cur = 0, len_tmp = 0;
+	int noranges = 0;
+	u32 tmp_start;		/* this is to make sure start address is divisible by the length needed */
+	u32 tmp_divide;
+	u8 flag = FALSE;
+
+	if (!res)
+		return -EINVAL;
+
+	if (bridge) {
+		/* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/
+		if (res->type == IO)
+			tmp_divide = IOBRIDGE;
+		else
+			tmp_divide = MEMBRIDGE;
+	} else
+		tmp_divide = res->len;
+
+	bus_cur = find_bus_wprev (res->busno, NULL, 0);
+
+	if (!bus_cur) {
+		/* didn't find a bus, smth's wrong!!! */
+		debug ("no bus in the system, either pci_dev's wrong or allocation failed\n");
+		return -EINVAL;
+	}
+
+	debug ("%s - enter\n", __FUNCTION__);
+	debug ("bus_cur->busno is %d\n", bus_cur->busno);
+
+	/* This is a quick fix to not mess up with the code very much.  i.e.,
+	 * 2000-2fff, len = 1000, but when we compare, we need it to be fff */
+	res->len -= 1;
+
+	switch (res->type) {
+		case IO:
+			res_cur = bus_cur->firstIO;
+			noranges = bus_cur->noIORanges;
+			break;
+		case MEM:
+			res_cur = bus_cur->firstMem;
+			noranges = bus_cur->noMemRanges;
+			break;
+		case PFMEM:
+			res_cur = bus_cur->firstPFMem;
+			noranges = bus_cur->noPFMemRanges;
+			break;
+		default:
+			err ("wrong type of resource to check\n");
+			return -EINVAL;
+	}
+	res_prev = NULL;
+
+	while (res_cur) {
+		range = find_range (bus_cur, res_cur);
+		debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno);
+
+		if (!range) {
+			err ("no range for the device exists... bailing out...\n");
+			return -EINVAL;
+		}
+
+		/* found our range */
+		if (!res_prev) {
+			/* first time in the loop */
+			if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) {
+				debug ("len_tmp = %x\n", len_tmp);
+
+				if ((len_tmp < len_cur) || (len_cur == 0)) {
+
+					if ((range->start % tmp_divide) == 0) {
+						/* just perfect, starting address is divisible by length */
+						flag = TRUE;
+						len_cur = len_tmp;
+						start_cur = range->start;
+					} else {
+						/* Needs adjusting */
+						tmp_start = range->start;
+						flag = FALSE;
+
+						while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
+							if ((tmp_start % tmp_divide) == 0) {
+								flag = TRUE;
+								len_cur = len_tmp;
+								start_cur = tmp_start;
+								break;
+							}
+							tmp_start += tmp_divide - tmp_start % tmp_divide;
+							if (tmp_start >= res_cur->start - 1)
+								break;
+						}
+					}
+			
+					if (flag && len_cur == res->len) {
+						debug ("but we are not here, right?\n");
+						res->start = start_cur;
+						res->len += 1; /* To restore the balance */
+						res->end = res->start + res->len - 1;
+						return 0;
+					}
+				}
+			}
+		}
+		if (!res_cur->next) {
+			/* last device on the range */
+			if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) {
+				debug ("len_tmp = %x\n", len_tmp);
+				if ((len_tmp < len_cur) || (len_cur == 0)) {
+
+					if (((res_cur->end + 1) % tmp_divide) == 0) {
+						/* just perfect, starting address is divisible by length */
+						flag = TRUE;
+						len_cur = len_tmp;
+						start_cur = res_cur->end + 1;
+					} else {
+						/* Needs adjusting */
+						tmp_start = res_cur->end + 1;
+						flag = FALSE;
+
+						while ((len_tmp = range->end - tmp_start) >= res->len) {
+							if ((tmp_start % tmp_divide) == 0) {
+								flag = TRUE;
+								len_cur = len_tmp;
+								start_cur = tmp_start;
+								break;
+							}
+							tmp_start += tmp_divide - tmp_start % tmp_divide;
+							if (tmp_start >= range->end)
+								break;
+						}
+					}
+					if (flag && len_cur == res->len) {
+						res->start = start_cur;
+						res->len += 1; /* To restore the balance */
+						res->end = res->start + res->len - 1;
+						return 0;
+					}
+				}
+			}
+		}
+
+		if (res_prev) {
+			if (res_prev->rangeno != res_cur->rangeno) {
+				/* 1st device on this range */
+				if ((res_cur->start != range->start) && 
+					((len_tmp = res_cur->start - 1 - range->start) >= res->len)) {
+					if ((len_tmp < len_cur) || (len_cur == 0)) {
+						if ((range->start % tmp_divide) == 0) {	
+							/* just perfect, starting address is divisible by length */
+							flag = TRUE;
+							len_cur = len_tmp;
+							start_cur = range->start;
+						} else {
+							/* Needs adjusting */
+							tmp_start = range->start;
+							flag = FALSE;
+
+							while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
+								if ((tmp_start % tmp_divide) == 0) {
+									flag = TRUE;
+									len_cur = len_tmp;
+									start_cur = tmp_start;
+									break;
+								}
+								tmp_start += tmp_divide - tmp_start % tmp_divide;
+								if (tmp_start >= res_cur->start - 1)
+									break;
+							}
+						}
+
+						if (flag && len_cur == res->len) {
+							res->start = start_cur;
+							res->len += 1; /* To restore the balance */
+							res->end = res->start + res->len - 1;
+							return 0;
+						}
+					}
+				}
+			} else {
+				/* in the same range */
+				if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) {
+					if ((len_tmp < len_cur) || (len_cur == 0)) {
+						if (((res_prev->end + 1) % tmp_divide) == 0) {
+							/* just perfect, starting address's divisible by length */
+							flag = TRUE;
+							len_cur = len_tmp;
+							start_cur = res_prev->end + 1;
+						} else {
+							/* Needs adjusting */
+							tmp_start = res_prev->end + 1;
+							flag = FALSE;
+
+							while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
+								if ((tmp_start % tmp_divide) == 0) {
+									flag = TRUE;
+									len_cur = len_tmp;
+									start_cur = tmp_start;
+									break;
+								}
+								tmp_start += tmp_divide - tmp_start % tmp_divide;
+								if (tmp_start >= res_cur->start - 1)
+									break;
+							}
+						}
+
+						if (flag && len_cur == res->len) {
+							res->start = start_cur;
+							res->len += 1; /* To restore the balance */
+							res->end = res->start + res->len - 1;
+							return 0;
+						}
+					}
+				}
+			}
+		}
+		/* end if (res_prev) */
+		res_prev = res_cur;
+		if (res_cur->next)
+			res_cur = res_cur->next;
+		else
+			res_cur = res_cur->nextRange;
+	}	/* end of while */
+
+
+	if (!res_prev) {
+		/* 1st device ever */
+		/* need to find appropriate range */
+		switch (res->type) {
+			case IO:
+				range = bus_cur->rangeIO;
+				break;
+			case MEM:
+				range = bus_cur->rangeMem;
+				break;
+			case PFMEM:
+				range = bus_cur->rangePFMem;
+				break;
+		}
+		while (range) {
+			if ((len_tmp = range->end - range->start) >= res->len) {
+				if ((len_tmp < len_cur) || (len_cur == 0)) {
+					if ((range->start % tmp_divide) == 0) {
+						/* just perfect, starting address's divisible by length */
+						flag = TRUE;
+						len_cur = len_tmp;
+						start_cur = range->start;
+					} else {
+						/* Needs adjusting */
+						tmp_start = range->start;
+						flag = FALSE;
+
+						while ((len_tmp = range->end - tmp_start) >= res->len) {
+							if ((tmp_start % tmp_divide) == 0) {
+								flag = TRUE;
+								len_cur = len_tmp;
+								start_cur = tmp_start;
+								break;
+							}
+							tmp_start += tmp_divide - tmp_start % tmp_divide;
+							if (tmp_start >= range->end)
+								break;
+						}
+					}
+
+					if (flag && len_cur == res->len) {
+						res->start = start_cur;
+						res->len += 1; /* To restore the balance */
+						res->end = res->start + res->len - 1;
+						return 0;
+					}
+				}
+			}
+			range = range->next;
+		}		/* end of while */
+
+		if ((!range) && (len_cur == 0)) {
+			/* have gone through the list of devices and ranges and haven't found n.e.thing */
+			err ("no appropriate range.. bailing out...\n");
+			return -EINVAL;
+		} else if (len_cur) {
+			res->start = start_cur;
+			res->len += 1; /* To restore the balance */
+			res->end = res->start + res->len - 1;
+			return 0;
+		}
+	}
+
+	if (!res_cur) {
+		debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges);
+		if (res_prev->rangeno < noranges) {
+			/* if there're more ranges out there to check */
+			switch (res->type) {
+				case IO:
+					range = bus_cur->rangeIO;
+					break;
+				case MEM:
+					range = bus_cur->rangeMem;
+					break;
+				case PFMEM:
+					range = bus_cur->rangePFMem;
+					break;
+			}
+			while (range) {
+				if ((len_tmp = range->end - range->start) >= res->len) {
+					if ((len_tmp < len_cur) || (len_cur == 0)) {
+						if ((range->start % tmp_divide) == 0) {
+							/* just perfect, starting address's divisible by length */
+							flag = TRUE;
+							len_cur = len_tmp;
+							start_cur = range->start;
+						} else {
+							/* Needs adjusting */
+							tmp_start = range->start;
+							flag = FALSE;
+
+							while ((len_tmp = range->end - tmp_start) >= res->len) {
+								if ((tmp_start % tmp_divide) == 0) {
+									flag = TRUE;
+									len_cur = len_tmp;
+									start_cur = tmp_start;
+									break;
+								}
+								tmp_start += tmp_divide - tmp_start % tmp_divide;
+								if (tmp_start >= range->end)
+									break;
+							}
+						}
+
+						if (flag && len_cur == res->len) {
+							res->start = start_cur;
+							res->len += 1; /* To restore the balance */
+							res->end = res->start + res->len - 1;
+							return 0;
+						}
+					}
+				}
+				range = range->next;
+			}	/* end of while */
+
+			if ((!range) && (len_cur == 0)) {
+				/* have gone through the list of devices and ranges and haven't found n.e.thing */
+				err ("no appropriate range.. bailing out...\n");
+				return -EINVAL;
+			} else if (len_cur) {
+				res->start = start_cur;
+				res->len += 1; /* To restore the balance */
+				res->end = res->start + res->len - 1;
+				return 0;
+			}
+		} else {
+			/* no more ranges to check on */
+			if (len_cur) {
+				res->start = start_cur;
+				res->len += 1; /* To restore the balance */
+				res->end = res->start + res->len - 1;
+				return 0;
+			} else {
+				/* have gone through the list of devices and haven't found n.e.thing */
+				err ("no appropriate range.. bailing out...\n");
+				return -EINVAL;
+			}
+		}
+	}	/* end if(!res_cur) */
+	return -EINVAL;
+}
+
+/********************************************************************************
+ * This routine is called from remove_card if the card contained PPB.
+ * It will remove all the resources on the bus as well as the bus itself
+ * Input: Bus
+ * Ouput: 0, -ENODEV
+ ********************************************************************************/
+int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno)
+{
+	struct resource_node *res_cur;
+	struct resource_node *res_tmp;
+	struct bus_node *prev_bus;
+	int rc;
+
+	prev_bus = find_bus_wprev (parent_busno, NULL, 0);	
+
+	if (!prev_bus) {
+		debug ("something terribly wrong. Cannot find parent bus to the one to remove\n");
+		return -ENODEV;
+	}
+
+	debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno);
+
+	rc = remove_ranges (bus, prev_bus);
+	if (rc)
+		return rc;
+
+	if (bus->firstIO) {
+		res_cur = bus->firstIO;
+		while (res_cur) {
+			res_tmp = res_cur;
+			if (res_cur->next)
+				res_cur = res_cur->next;
+			else
+				res_cur = res_cur->nextRange;
+			kfree (res_tmp);
+			res_tmp = NULL;
+		}
+		bus->firstIO = NULL;
+	}
+	if (bus->firstMem) {
+		res_cur = bus->firstMem;
+		while (res_cur) {
+			res_tmp = res_cur;
+			if (res_cur->next)
+				res_cur = res_cur->next;
+			else
+				res_cur = res_cur->nextRange;
+			kfree (res_tmp);
+			res_tmp = NULL;
+		}
+		bus->firstMem = NULL;
+	}
+	if (bus->firstPFMem) {
+		res_cur = bus->firstPFMem;
+		while (res_cur) {
+			res_tmp = res_cur;
+			if (res_cur->next)
+				res_cur = res_cur->next;
+			else
+				res_cur = res_cur->nextRange;
+			kfree (res_tmp);
+			res_tmp = NULL;
+		}
+		bus->firstPFMem = NULL;
+	}
+
+	if (bus->firstPFMemFromMem) {
+		res_cur = bus->firstPFMemFromMem;
+		while (res_cur) {
+			res_tmp = res_cur;
+			res_cur = res_cur->next;
+
+			kfree (res_tmp);
+			res_tmp = NULL;
+		}
+		bus->firstPFMemFromMem = NULL;
+	}
+
+	list_del (&bus->bus_list);
+	kfree (bus);
+	return 0;
+}
+
+/******************************************************************************
+ * This routine deletes the ranges from a given bus, and the entries from the 
+ * parent's bus in the resources
+ * Input: current bus, previous bus
+ * Output: 0, -EINVAL
+ ******************************************************************************/
+static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev)
+{
+	struct range_node *range_cur;
+	struct range_node *range_tmp;
+	int i;
+	struct resource_node *res = NULL;
+
+	if (bus_cur->noIORanges) {
+		range_cur = bus_cur->rangeIO;
+		for (i = 0; i < bus_cur->noIORanges; i++) {
+			if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0)
+				return -EINVAL;
+			ibmphp_remove_resource (res);
+
+			range_tmp = range_cur;
+			range_cur = range_cur->next;
+			kfree (range_tmp);
+			range_tmp = NULL;
+		}
+		bus_cur->rangeIO = NULL;
+	}
+	if (bus_cur->noMemRanges) {
+		range_cur = bus_cur->rangeMem;
+		for (i = 0; i < bus_cur->noMemRanges; i++) {
+			if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) 
+				return -EINVAL;
+
+			ibmphp_remove_resource (res);
+			range_tmp = range_cur;
+			range_cur = range_cur->next;
+			kfree (range_tmp);
+			range_tmp = NULL;
+		}
+		bus_cur->rangeMem = NULL;
+	}
+	if (bus_cur->noPFMemRanges) {
+		range_cur = bus_cur->rangePFMem;
+		for (i = 0; i < bus_cur->noPFMemRanges; i++) {
+			if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) 
+				return -EINVAL;
+
+			ibmphp_remove_resource (res);
+			range_tmp = range_cur;
+			range_cur = range_cur->next;
+			kfree (range_tmp);
+			range_tmp = NULL;
+		}
+		bus_cur->rangePFMem = NULL;
+	}
+	return 0;
+}
+
+/*
+ * find the resource node in the bus 
+ * Input: Resource needed, start address of the resource, type of resource
+ */
+int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag)
+{
+	struct resource_node *res_cur = NULL;
+	char * type = "";
+
+	if (!bus) {
+		err ("The bus passed in NULL to find resource\n");
+		return -ENODEV;
+	}
+
+	switch (flag) {
+		case IO:
+			res_cur = bus->firstIO;
+			type = "io";
+			break;
+		case MEM:
+			res_cur = bus->firstMem;
+			type = "mem";
+			break;
+		case PFMEM:
+			res_cur = bus->firstPFMem;
+			type = "pfmem";
+			break;
+		default:
+			err ("wrong type of flag\n");
+			return -EINVAL;
+	}
+	
+	while (res_cur) {
+		if (res_cur->start == start_address) {
+			*res = res_cur;
+			break;
+		}
+		if (res_cur->next)
+			res_cur = res_cur->next;
+		else
+			res_cur = res_cur->nextRange;
+	}
+
+	if (!res_cur) {
+		if (flag == PFMEM) {
+			res_cur = bus->firstPFMemFromMem;
+			while (res_cur) {
+				if (res_cur->start == start_address) {
+					*res = res_cur;
+					break;
+				}
+				res_cur = res_cur->next;
+			}
+			if (!res_cur) {
+				debug ("SOS...cannot find %s resource in the bus.\n", type);
+				return -EINVAL;
+			}
+		} else {
+			debug ("SOS... cannot find %s resource in the bus.\n", type);
+			return -EINVAL;
+		}
+	}
+
+	if (*res)
+		debug ("*res->start = %x\n", (*res)->start);
+
+	return 0;
+}
+
+/***********************************************************************
+ * This routine will free the resource structures used by the
+ * system.  It is called from cleanup routine for the module
+ * Parameters: none
+ * Returns: none
+ ***********************************************************************/
+void ibmphp_free_resources (void)
+{
+	struct bus_node *bus_cur = NULL;
+	struct bus_node *bus_tmp;
+	struct range_node *range_cur;
+	struct range_node *range_tmp;
+	struct resource_node *res_cur;
+	struct resource_node *res_tmp;
+	struct list_head *tmp;
+	struct list_head *next;
+	int i = 0;
+	flags = 1;
+
+	list_for_each_safe (tmp, next, &gbuses) {
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		if (bus_cur->noIORanges) {
+			range_cur = bus_cur->rangeIO;
+			for (i = 0; i < bus_cur->noIORanges; i++) {
+				if (!range_cur)
+					break;
+				range_tmp = range_cur;
+				range_cur = range_cur->next;
+				kfree (range_tmp);
+				range_tmp = NULL;
+			}
+		}
+		if (bus_cur->noMemRanges) {
+			range_cur = bus_cur->rangeMem;
+			for (i = 0; i < bus_cur->noMemRanges; i++) {
+				if (!range_cur)
+					break;
+				range_tmp = range_cur;
+				range_cur = range_cur->next;
+				kfree (range_tmp);
+				range_tmp = NULL;
+			}
+		}
+		if (bus_cur->noPFMemRanges) {
+			range_cur = bus_cur->rangePFMem;
+			for (i = 0; i < bus_cur->noPFMemRanges; i++) {
+				if (!range_cur)
+					break;
+				range_tmp = range_cur;
+				range_cur = range_cur->next;
+				kfree (range_tmp);
+				range_tmp = NULL;
+			}
+		}
+
+		if (bus_cur->firstIO) {
+			res_cur = bus_cur->firstIO;
+			while (res_cur) {
+				res_tmp = res_cur;
+				if (res_cur->next)
+					res_cur = res_cur->next;
+				else
+					res_cur = res_cur->nextRange;
+				kfree (res_tmp);
+				res_tmp = NULL;
+			}
+			bus_cur->firstIO = NULL;
+		}
+		if (bus_cur->firstMem) {
+			res_cur = bus_cur->firstMem;
+			while (res_cur) {
+				res_tmp = res_cur;
+				if (res_cur->next)
+					res_cur = res_cur->next;
+				else
+					res_cur = res_cur->nextRange;
+				kfree (res_tmp);
+				res_tmp = NULL;
+			}
+			bus_cur->firstMem = NULL;
+		}
+		if (bus_cur->firstPFMem) {
+			res_cur = bus_cur->firstPFMem;
+			while (res_cur) {
+				res_tmp = res_cur;
+				if (res_cur->next)
+					res_cur = res_cur->next;
+				else
+					res_cur = res_cur->nextRange;
+				kfree (res_tmp);
+				res_tmp = NULL;
+			}
+			bus_cur->firstPFMem = NULL;
+		}
+
+		if (bus_cur->firstPFMemFromMem) {
+			res_cur = bus_cur->firstPFMemFromMem;
+			while (res_cur) {
+				res_tmp = res_cur;
+				res_cur = res_cur->next;
+
+				kfree (res_tmp);
+				res_tmp = NULL;
+			}
+			bus_cur->firstPFMemFromMem = NULL;
+		}
+
+		bus_tmp = bus_cur;
+		list_del (&bus_cur->bus_list);
+		kfree (bus_tmp);
+		bus_tmp = NULL;
+	}
+}
+
+/*********************************************************************************
+ * This function will go over the PFmem resources to check if the EBDA allocated
+ * pfmem out of memory buckets of the bus.  If so, it will change the range numbers
+ * and a flag to indicate that this resource is out of memory. It will also move the
+ * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create
+ * a new Mem node
+ * This routine is called right after initialization
+ *******************************************************************************/
+static int __init once_over (void)
+{
+	struct resource_node *pfmem_cur;
+	struct resource_node *pfmem_prev;
+	struct resource_node *mem;
+	struct bus_node *bus_cur;
+	struct list_head *tmp;
+
+	list_for_each (tmp, &gbuses) {
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) {
+			for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) {
+				pfmem_cur->fromMem = TRUE;
+				if (pfmem_prev)
+					pfmem_prev->next = pfmem_cur->next;
+				else
+					bus_cur->firstPFMem = pfmem_cur->next;
+
+				if (!bus_cur->firstPFMemFromMem)
+					pfmem_cur->next = NULL;
+				else
+					/* we don't need to sort PFMemFromMem since we're using mem node for
+					   all the real work anyways, so just insert at the beginning of the
+					   list
+					 */
+					pfmem_cur->next = bus_cur->firstPFMemFromMem;
+
+				bus_cur->firstPFMemFromMem = pfmem_cur;
+
+				mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);		
+				if (!mem) {
+					err ("out of system memory\n");
+					return -ENOMEM;
+				}
+				memset (mem, 0, sizeof (struct resource_node));
+				mem->type = MEM;
+				mem->busno = pfmem_cur->busno;
+				mem->devfunc = pfmem_cur->devfunc;
+				mem->start = pfmem_cur->start;
+				mem->end = pfmem_cur->end;
+				mem->len = pfmem_cur->len;
+				if (ibmphp_add_resource (mem) < 0)
+					err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n");
+				pfmem_cur->rangeno = mem->rangeno;
+			}	/* end for pfmem */
+		}	/* end if */
+	}	/* end list_for_each bus */
+	return 0; 
+}
+
+int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem)
+{
+	struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0);
+
+	if (!bus_cur) {
+		err ("cannot find bus of pfmem to add...\n");
+		return -ENODEV;
+	}
+
+	if (bus_cur->firstPFMemFromMem)
+		pfmem->next = bus_cur->firstPFMemFromMem;
+	else
+		pfmem->next = NULL;
+
+	bus_cur->firstPFMemFromMem = pfmem;
+
+	return 0;
+}
+
+/* This routine just goes through the buses to see if the bus already exists.
+ * It is called from ibmphp_find_sec_number, to find out a secondary bus number for
+ * bridged cards
+ * Parameters: bus_number
+ * Returns: Bus pointer or NULL
+ */
+struct bus_node *ibmphp_find_res_bus (u8 bus_number)
+{
+	return find_bus_wprev (bus_number, NULL, 0);
+}
+
+static struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag)
+{
+	struct bus_node *bus_cur;
+	struct list_head *tmp;
+	struct list_head *tmp_prev;
+
+	list_for_each (tmp, &gbuses) {
+		tmp_prev = tmp->prev;
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		if (flag) 
+			*prev = list_entry (tmp_prev, struct bus_node, bus_list);
+		if (bus_cur->busno == bus_number) 
+			return bus_cur;
+	}
+
+	return NULL;
+}
+
+void ibmphp_print_test (void)
+{
+	int i = 0;
+	struct bus_node *bus_cur = NULL;
+	struct range_node *range;
+	struct resource_node *res;
+	struct list_head *tmp;
+	
+	debug_pci ("*****************START**********************\n");
+
+	if ((!list_empty(&gbuses)) && flags) {
+		err ("The GBUSES is not NULL?!?!?!?!?\n");
+		return;
+	}
+
+	list_for_each (tmp, &gbuses) {
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		debug_pci ("This is bus # %d.  There are\n", bus_cur->busno);
+		debug_pci ("IORanges = %d\t", bus_cur->noIORanges);
+		debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges);
+		debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges);
+		debug_pci ("The IO Ranges are as follows:\n");
+		if (bus_cur->rangeIO) {
+			range = bus_cur->rangeIO;
+			for (i = 0; i < bus_cur->noIORanges; i++) {
+				debug_pci ("rangeno is %d\n", range->rangeno);
+				debug_pci ("[%x - %x]\n", range->start, range->end);
+				range = range->next;
+			}
+		}
+
+		debug_pci ("The Mem Ranges are as follows:\n");
+		if (bus_cur->rangeMem) {
+			range = bus_cur->rangeMem;
+			for (i = 0; i < bus_cur->noMemRanges; i++) {
+				debug_pci ("rangeno is %d\n", range->rangeno);
+				debug_pci ("[%x - %x]\n", range->start, range->end);
+				range = range->next;
+			}
+		}
+
+		debug_pci ("The PFMem Ranges are as follows:\n");
+
+		if (bus_cur->rangePFMem) {
+			range = bus_cur->rangePFMem;
+			for (i = 0; i < bus_cur->noPFMemRanges; i++) {
+				debug_pci ("rangeno is %d\n", range->rangeno);
+				debug_pci ("[%x - %x]\n", range->start, range->end);
+				range = range->next;
+			}
+		}
+
+		debug_pci ("The resources on this bus are as follows\n");
+
+		debug_pci ("IO...\n");
+		if (bus_cur->firstIO) {
+			res = bus_cur->firstIO;
+			while (res) {
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				if (res->next)
+					res = res->next;
+				else if (res->nextRange)
+					res = res->nextRange;
+				else
+					break;
+			}
+		}
+		debug_pci ("Mem...\n");
+		if (bus_cur->firstMem) {
+			res = bus_cur->firstMem;
+			while (res) {
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				if (res->next)
+					res = res->next;
+				else if (res->nextRange)
+					res = res->nextRange;
+				else
+					break;
+			}
+		}
+		debug_pci ("PFMem...\n");
+		if (bus_cur->firstPFMem) {
+			res = bus_cur->firstPFMem;
+			while (res) {
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				if (res->next)
+					res = res->next;
+				else if (res->nextRange)
+					res = res->nextRange;
+				else
+					break;
+			}
+		}
+
+		debug_pci ("PFMemFromMem...\n");
+		if (bus_cur->firstPFMemFromMem) {
+			res = bus_cur->firstPFMemFromMem;
+			while (res) {
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				res = res->next;
+			}
+		}
+	}
+	debug_pci ("***********************END***********************\n");
+}
+
+static int range_exists_already (struct range_node * range, struct bus_node * bus_cur, u8 type)
+{
+	struct range_node * range_cur = NULL;
+	switch (type) {
+		case IO:
+			range_cur = bus_cur->rangeIO;
+			break;
+		case MEM:
+			range_cur = bus_cur->rangeMem;
+			break;
+		case PFMEM:
+			range_cur = bus_cur->rangePFMem;
+			break;
+		default:
+			err ("wrong type passed to find out if range already exists\n");
+			return -ENODEV;
+	}
+
+	while (range_cur) {
+		if ((range_cur->start == range->start) && (range_cur->end == range->end))
+			return 1;
+		range_cur = range_cur->next;
+	}
+	
+	return 0;
+}
+
+/* This routine will read the windows for any PPB we have and update the
+ * range info for the secondary bus, and will also input this info into
+ * primary bus, since BIOS doesn't. This is for PPB that are in the system
+ * on bootup.  For bridged cards that were added during previous load of the
+ * driver, only the ranges and the bus structure are added, the devices are
+ * added from NVRAM
+ * Input: primary busno
+ * Returns: none
+ * Note: this function doesn't take into account IO restrictions etc,
+ *	 so will only work for bridges with no video/ISA devices behind them It
+ *	 also will not work for onboard PPB's that can have more than 1 *bus
+ *	 behind them All these are TO DO.
+ *	 Also need to add more error checkings... (from fnc returns etc)
+ */
+static int __init update_bridge_ranges (struct bus_node **bus)
+{
+	u8 sec_busno, device, function, hdr_type, start_io_address, end_io_address;
+	u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address;
+	u32 start_address, end_address, upper_start, upper_end;
+	struct bus_node *bus_sec;
+	struct bus_node *bus_cur;
+	struct resource_node *io;
+	struct resource_node *mem;
+	struct resource_node *pfmem;
+	struct range_node *range;
+	unsigned int devfn;
+
+	bus_cur = *bus;
+	if (!bus_cur)
+		return -ENODEV;
+	ibmphp_pci_bus->number = bus_cur->busno;
+
+	debug ("inside %s\n", __FUNCTION__);
+	debug ("bus_cur->busno = %x\n", bus_cur->busno);
+
+	for (device = 0; device < 32; device++) {
+		for (function = 0x00; function < 0x08; function++) {
+			devfn = PCI_DEVFN(device, function);
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
+
+			if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
+				/* found correct device!!! */
+				pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
+
+				switch (hdr_type) {
+					case PCI_HEADER_TYPE_NORMAL:
+						function = 0x8;
+						break;
+					case PCI_HEADER_TYPE_MULTIDEVICE:
+						break;
+					case PCI_HEADER_TYPE_BRIDGE:
+						function = 0x8;
+					case PCI_HEADER_TYPE_MULTIBRIDGE:
+						/* We assume here that only 1 bus behind the bridge 
+						   TO DO: add functionality for several:
+						   temp = secondary;
+						   while (temp < subordinate) {
+						   ...
+						   temp++;
+						   }
+						 */
+						pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno);
+						bus_sec = find_bus_wprev (sec_busno, NULL, 0); 
+						/* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */
+						if (!bus_sec) {
+							bus_sec = alloc_error_bus (NULL, sec_busno, 1);
+							/* the rest will be populated during NVRAM call */
+							return 0;
+						}
+						pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &start_io_address);
+						pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &end_io_address);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, &upper_io_start);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, &upper_io_end);
+						start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8;
+						start_address |= (upper_io_start << 16);
+						end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8;
+						end_address |= (upper_io_end << 16);
+
+						if ((start_address) && (start_address <= end_address)) {
+							range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+							if (!range) {
+								err ("out of system memory\n");
+								return -ENOMEM;
+							}
+							memset (range, 0, sizeof (struct range_node));
+							range->start = start_address;
+							range->end = end_address + 0xfff;
+
+							if (bus_sec->noIORanges > 0) {
+								if (!range_exists_already (range, bus_sec, IO)) {
+									add_range (IO, range, bus_sec);
+									++bus_sec->noIORanges;
+								} else {
+									kfree (range);
+									range = NULL;
+								}
+							} else {
+								/* 1st IO Range on the bus */
+								range->rangeno = 1;
+								bus_sec->rangeIO = range;
+								++bus_sec->noIORanges;
+							}
+							fix_resources (bus_sec);
+
+							if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) {
+								io = kmalloc (sizeof (struct resource_node), GFP_KERNEL);							
+								if (!io) {
+									kfree (range);
+									err ("out of system memory\n");
+									return -ENOMEM;
+								}
+								memset (io, 0, sizeof (struct resource_node));
+								io->type = IO;
+								io->busno = bus_cur->busno;
+								io->devfunc = ((device << 3) | (function & 0x7));
+								io->start = start_address;
+								io->end = end_address + 0xfff;
+								io->len = io->end - io->start + 1;
+								ibmphp_add_resource (io);
+							}
+						}	
+
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address);
+
+						start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
+						end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
+
+						if ((start_address) && (start_address <= end_address)) {
+
+							range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+							if (!range) {
+								err ("out of system memory\n");
+								return -ENOMEM;
+							}
+							memset (range, 0, sizeof (struct range_node));
+							range->start = start_address;
+							range->end = end_address + 0xfffff;
+
+							if (bus_sec->noMemRanges > 0) {
+								if (!range_exists_already (range, bus_sec, MEM)) {
+									add_range (MEM, range, bus_sec);
+									++bus_sec->noMemRanges;
+								} else {
+									kfree (range);
+									range = NULL;
+								}
+							} else {
+								/* 1st Mem Range on the bus */
+								range->rangeno = 1;
+								bus_sec->rangeMem = range;
+								++bus_sec->noMemRanges;
+							}
+
+							fix_resources (bus_sec);
+
+							if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) {
+								mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+								if (!mem) {
+									kfree (range);
+									err ("out of system memory\n");
+									return -ENOMEM;
+								}
+								memset (mem, 0, sizeof (struct resource_node));
+								mem->type = MEM;
+								mem->busno = bus_cur->busno;
+								mem->devfunc = ((device << 3) | (function & 0x7));
+								mem->start = start_address;
+								mem->end = end_address + 0xfffff;
+								mem->len = mem->end - mem->start + 1;
+								ibmphp_add_resource (mem);
+							}
+						}
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &start_mem_address);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &end_mem_address);
+						pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, &upper_start);
+						pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, &upper_end);
+						start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
+						end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
+#if BITS_PER_LONG == 64
+						start_address |= ((long) upper_start) << 32;
+						end_address |= ((long) upper_end) << 32;
+#endif
+
+						if ((start_address) && (start_address <= end_address)) {
+
+							range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+							if (!range) {
+								err ("out of system memory\n");
+								return -ENOMEM;
+							}
+							memset (range, 0, sizeof (struct range_node));
+							range->start = start_address;
+							range->end = end_address + 0xfffff;
+
+							if (bus_sec->noPFMemRanges > 0) {
+								if (!range_exists_already (range, bus_sec, PFMEM)) {
+									add_range (PFMEM, range, bus_sec);
+									++bus_sec->noPFMemRanges;
+								} else {
+									kfree (range);
+									range = NULL;
+								}
+							} else {
+								/* 1st PFMem Range on the bus */
+								range->rangeno = 1;
+								bus_sec->rangePFMem = range;
+								++bus_sec->noPFMemRanges;
+							}
+
+							fix_resources (bus_sec);
+							if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) {
+								pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+								if (!pfmem) {
+									kfree (range);
+									err ("out of system memory\n");
+									return -ENOMEM;
+								}
+								memset (pfmem, 0, sizeof (struct resource_node));
+								pfmem->type = PFMEM;
+								pfmem->busno = bus_cur->busno;
+								pfmem->devfunc = ((device << 3) | (function & 0x7));
+								pfmem->start = start_address;
+								pfmem->end = end_address + 0xfffff;
+								pfmem->len = pfmem->end - pfmem->start + 1;
+								pfmem->fromMem = FALSE;
+
+								ibmphp_add_resource (pfmem);
+							}
+						}
+						break;
+				}	/* end of switch */
+			}	/* end if vendor */
+		}	/* end for function */
+	}	/* end for device */
+
+	bus = &bus_cur;
+	return 0;
+}
diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h
new file mode 100644
index 0000000..57ace32
--- /dev/null
+++ b/drivers/pci/hotplug/pci_hotplug.h
@@ -0,0 +1,180 @@
+/*
+ * PCI HotPlug Core Functions
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+#ifndef _PCI_HOTPLUG_H
+#define _PCI_HOTPLUG_H
+
+
+/* These values come from the PCI Hotplug Spec */
+enum pci_bus_speed {
+	PCI_SPEED_33MHz			= 0x00,
+	PCI_SPEED_66MHz			= 0x01,
+	PCI_SPEED_66MHz_PCIX		= 0x02,
+	PCI_SPEED_100MHz_PCIX		= 0x03,
+	PCI_SPEED_133MHz_PCIX		= 0x04,
+	PCI_SPEED_66MHz_PCIX_ECC	= 0x05,
+	PCI_SPEED_100MHz_PCIX_ECC	= 0x06,
+	PCI_SPEED_133MHz_PCIX_ECC	= 0x07,
+	PCI_SPEED_66MHz_PCIX_266	= 0x09,
+	PCI_SPEED_100MHz_PCIX_266	= 0x0a,
+	PCI_SPEED_133MHz_PCIX_266	= 0x0b,
+	PCI_SPEED_66MHz_PCIX_533	= 0x11,
+	PCI_SPEED_100MHz_PCIX_533	= 0x12,
+	PCI_SPEED_133MHz_PCIX_533	= 0x13,
+	PCI_SPEED_UNKNOWN		= 0xff,
+};
+
+/* These values come from the PCI Express Spec */
+enum pcie_link_width {
+	PCIE_LNK_WIDTH_RESRV	= 0x00,
+	PCIE_LNK_X1		= 0x01,
+	PCIE_LNK_X2		= 0x02,
+	PCIE_LNK_X4		= 0x04,
+	PCIE_LNK_X8		= 0x08,
+	PCIE_LNK_X12		= 0x0C,
+	PCIE_LNK_X16		= 0x10,
+	PCIE_LNK_X32		= 0x20,
+	PCIE_LNK_WIDTH_UNKNOWN  = 0xFF,
+};
+
+enum pcie_link_speed {
+	PCIE_2PT5GB		= 0x14,
+	PCIE_LNK_SPEED_UNKNOWN	= 0xFF,
+};
+
+struct hotplug_slot;
+struct hotplug_slot_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct hotplug_slot *, char *);
+	ssize_t (*store)(struct hotplug_slot *, const char *, size_t);
+};
+#define to_hotplug_attr(n) container_of(n, struct hotplug_slot_attribute, attr);
+
+/**
+ * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
+ * @owner: The module owner of this structure
+ * @enable_slot: Called when the user wants to enable a specific pci slot
+ * @disable_slot: Called when the user wants to disable a specific pci slot
+ * @set_attention_status: Called to set the specific slot's attention LED to
+ * the specified value
+ * @hardware_test: Called to run a specified hardware test on the specified
+ * slot.
+ * @get_power_status: Called to get the current power status of a slot.
+ * 	If this field is NULL, the value passed in the struct hotplug_slot_info
+ * 	will be used when this value is requested by a user.
+ * @get_attention_status: Called to get the current attention status of a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_latch_status: Called to get the current latch status of a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_address: Called to get pci address of a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_max_bus_speed: Called to get the max bus speed for a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_cur_bus_speed: Called to get the current bus speed for a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ *
+ * The table of function pointers that is passed to the hotplug pci core by a
+ * hotplug pci driver.  These functions are called by the hotplug pci core when
+ * the user wants to do something to a specific slot (query it for information,
+ * set an LED, enable / disable power, etc.)
+ */
+struct hotplug_slot_ops {
+	struct module *owner;
+	int (*enable_slot)		(struct hotplug_slot *slot);
+	int (*disable_slot)		(struct hotplug_slot *slot);
+	int (*set_attention_status)	(struct hotplug_slot *slot, u8 value);
+	int (*hardware_test)		(struct hotplug_slot *slot, u32 value);
+	int (*get_power_status)		(struct hotplug_slot *slot, u8 *value);
+	int (*get_attention_status)	(struct hotplug_slot *slot, u8 *value);
+	int (*get_latch_status)		(struct hotplug_slot *slot, u8 *value);
+	int (*get_adapter_status)	(struct hotplug_slot *slot, u8 *value);
+	int (*get_address)		(struct hotplug_slot *slot, u32 *value);
+	int (*get_max_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+	int (*get_cur_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+};
+
+/**
+ * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot
+ * @power: if power is enabled or not (1/0)
+ * @attention_status: if the attention light is enabled or not (1/0)
+ * @latch_status: if the latch (if any) is open or closed (1/0)
+ * @adapter_present: if there is a pci board present in the slot or not (1/0)
+ * @address: (domain << 16 | bus << 8 | dev)
+ *
+ * Used to notify the hotplug pci core of the status of a specific slot.
+ */
+struct hotplug_slot_info {
+	u8	power_status;
+	u8	attention_status;
+	u8	latch_status;
+	u8	adapter_status;
+	u32	address;
+	enum pci_bus_speed	max_bus_speed;
+	enum pci_bus_speed	cur_bus_speed;
+};
+
+/**
+ * struct hotplug_slot - used to register a physical slot with the hotplug pci core
+ * @name: the name of the slot being registered.  This string must
+ * be unique amoung slots registered on this system.
+ * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot
+ * @info: pointer to the &struct hotplug_slot_info for the inital values for
+ * this slot.
+ * @release: called during pci_hp_deregister to free memory allocated in a
+ * hotplug_slot structure.
+ * @private: used by the hotplug pci controller driver to store whatever it
+ * needs.
+ */
+struct hotplug_slot {
+	char				*name;
+	struct hotplug_slot_ops		*ops;
+	struct hotplug_slot_info	*info;
+	void (*release) (struct hotplug_slot *slot);
+	void				*private;
+
+	/* Variables below this are for use only by the hotplug pci core. */
+	struct list_head		slot_list;
+	struct kobject			kobj;
+};
+#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)
+
+extern int pci_hp_register		(struct hotplug_slot *slot);
+extern int pci_hp_deregister		(struct hotplug_slot *slot);
+extern int pci_hp_change_slot_info	(struct hotplug_slot *slot,
+					 struct hotplug_slot_info *info);
+extern struct subsystem pci_hotplug_slots_subsys;
+
+#endif
+
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
new file mode 100644
index 0000000..c802f62
--- /dev/null
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -0,0 +1,715 @@
+/*
+ * PCI HotPlug Controller Core
+ *
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2002 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include "pci_hotplug.h"
+
+
+#define MY_NAME	"pci_hotplug"
+
+#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
+
+
+/* local variables */
+static int debug;
+
+#define DRIVER_VERSION	"0.5"
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>"
+#define DRIVER_DESC	"PCI Hot Plug PCI Core"
+
+
+//////////////////////////////////////////////////////////////////
+
+static LIST_HEAD(pci_hotplug_slot_list);
+
+struct subsystem pci_hotplug_slots_subsys;
+
+static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
+		struct attribute *attr, char *buf)
+{
+	struct hotplug_slot *slot = to_hotplug_slot(kobj);
+	struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
+	return attribute->show ? attribute->show(slot, buf) : 0;
+}
+
+static ssize_t hotplug_slot_attr_store(struct kobject *kobj,
+		struct attribute *attr, const char *buf, size_t len)
+{
+	struct hotplug_slot *slot = to_hotplug_slot(kobj);
+	struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
+	return attribute->store ? attribute->store(slot, buf, len) : 0;
+}
+
+static struct sysfs_ops hotplug_slot_sysfs_ops = {
+	.show = hotplug_slot_attr_show,
+	.store = hotplug_slot_attr_store,
+};
+
+static void hotplug_slot_release(struct kobject *kobj)
+{
+	struct hotplug_slot *slot = to_hotplug_slot(kobj);
+	if (slot->release)
+		slot->release(slot);
+}
+
+static struct kobj_type hotplug_slot_ktype = {
+	.sysfs_ops = &hotplug_slot_sysfs_ops,
+	.release = &hotplug_slot_release,
+};
+
+decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
+
+/* these strings match up with the values in pci_bus_speed */
+static char *pci_bus_speed_strings[] = {
+	"33 MHz PCI",		/* 0x00 */
+	"66 MHz PCI",		/* 0x01 */
+	"66 MHz PCIX", 		/* 0x02 */
+	"100 MHz PCIX",		/* 0x03 */
+	"133 MHz PCIX",		/* 0x04 */
+	NULL,			/* 0x05 */
+	NULL,			/* 0x06 */
+	NULL,			/* 0x07 */
+	NULL,			/* 0x08 */
+	"66 MHz PCIX 266",	/* 0x09 */
+	"100 MHz PCIX 266",	/* 0x0a */
+	"133 MHz PCIX 266",	/* 0x0b */
+	NULL,			/* 0x0c */
+	NULL,			/* 0x0d */
+	NULL,			/* 0x0e */
+	NULL,			/* 0x0f */
+	NULL,			/* 0x10 */
+	"66 MHz PCIX 533",	/* 0x11 */
+	"100 MHz PCIX 533",	/* 0x12 */
+	"133 MHz PCIX 533",	/* 0x13 */
+	"25 GBps PCI-E",	/* 0x14 */
+};
+
+#ifdef CONFIG_HOTPLUG_PCI_CPCI
+extern int cpci_hotplug_init(int debug);
+extern void cpci_hotplug_exit(void);
+#else
+static inline int cpci_hotplug_init(int debug) { return 0; }
+static inline void cpci_hotplug_exit(void) { }
+#endif
+
+/* Weee, fun with macros... */
+#define GET_STATUS(name,type)	\
+static int get_##name (struct hotplug_slot *slot, type *value)		\
+{									\
+	struct hotplug_slot_ops *ops = slot->ops;			\
+	int retval = 0;							\
+	if (try_module_get(ops->owner)) {				\
+		if (ops->get_##name)					\
+			retval = ops->get_##name (slot, value);		\
+		else							\
+			*value = slot->info->name;			\
+		module_put(ops->owner);					\
+	}								\
+	return retval;							\
+}
+
+GET_STATUS(power_status, u8)
+GET_STATUS(attention_status, u8)
+GET_STATUS(latch_status, u8)
+GET_STATUS(adapter_status, u8)
+GET_STATUS(address, u32)
+GET_STATUS(max_bus_speed, enum pci_bus_speed)
+GET_STATUS(cur_bus_speed, enum pci_bus_speed)
+
+static ssize_t power_read_file (struct hotplug_slot *slot, char *buf)
+{
+	int retval;
+	u8 value;
+
+	retval = get_power_status (slot, &value);
+	if (retval)
+		goto exit;
+	retval = sprintf (buf, "%d\n", value);
+exit:
+	return retval;
+}
+
+static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf,
+		size_t count)
+{
+	unsigned long lpower;
+	u8 power;
+	int retval = 0;
+
+	lpower = simple_strtoul (buf, NULL, 10);
+	power = (u8)(lpower & 0xff);
+	dbg ("power = %d\n", power);
+
+	if (!try_module_get(slot->ops->owner)) {
+		retval = -ENODEV;
+		goto exit;
+	}
+	switch (power) {
+		case 0:
+			if (slot->ops->disable_slot)
+				retval = slot->ops->disable_slot(slot);
+			break;
+
+		case 1:
+			if (slot->ops->enable_slot)
+				retval = slot->ops->enable_slot(slot);
+			break;
+
+		default:
+			err ("Illegal value specified for power\n");
+			retval = -EINVAL;
+	}
+	module_put(slot->ops->owner);
+
+exit:	
+	if (retval)
+		return retval;
+	return count;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_power = {
+	.attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+	.show = power_read_file,
+	.store = power_write_file
+};
+
+static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf)
+{
+	int retval;
+	u8 value;
+
+	retval = get_attention_status (slot, &value);
+	if (retval)
+		goto exit;
+	retval = sprintf (buf, "%d\n", value);
+
+exit:
+	return retval;
+}
+
+static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
+		size_t count)
+{
+	unsigned long lattention;
+	u8 attention;
+	int retval = 0;
+
+	lattention = simple_strtoul (buf, NULL, 10);
+	attention = (u8)(lattention & 0xff);
+	dbg (" - attention = %d\n", attention);
+
+	if (!try_module_get(slot->ops->owner)) {
+		retval = -ENODEV;
+		goto exit;
+	}
+	if (slot->ops->set_attention_status)
+		retval = slot->ops->set_attention_status(slot, attention);
+	module_put(slot->ops->owner);
+
+exit:	
+	if (retval)
+		return retval;
+	return count;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_attention = {
+	.attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+	.show = attention_read_file,
+	.store = attention_write_file
+};
+
+static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf)
+{
+	int retval;
+	u8 value;
+
+	retval = get_latch_status (slot, &value);
+	if (retval)
+		goto exit;
+	retval = sprintf (buf, "%d\n", value);
+
+exit:
+	return retval;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_latch = {
+	.attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
+	.show = latch_read_file,
+};
+
+static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf)
+{
+	int retval;
+	u8 value;
+
+	retval = get_adapter_status (slot, &value);
+	if (retval)
+		goto exit;
+	retval = sprintf (buf, "%d\n", value);
+
+exit:
+	return retval;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_presence = {
+	.attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
+	.show = presence_read_file,
+};
+
+static ssize_t address_read_file (struct hotplug_slot *slot, char *buf)
+{
+	int retval;
+	u32 address;
+
+	retval = get_address (slot, &address);
+	if (retval)
+		goto exit;
+	retval = sprintf (buf, "%04x:%02x:%02x\n",
+			  (address >> 16) & 0xffff,
+			  (address >> 8) & 0xff,
+			  address & 0xff);
+
+exit:
+	return retval;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_address = {
+	.attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
+	.show = address_read_file,
+};
+
+static char *unknown_speed = "Unknown bus speed";
+
+static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
+{
+	char *speed_string;
+	int retval;
+	enum pci_bus_speed value;
+	
+	retval = get_max_bus_speed (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	retval = sprintf (buf, "%s\n", speed_string);
+
+exit:
+	return retval;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = {
+	.attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO},
+	.show = max_bus_speed_read_file,
+};
+
+static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
+{
+	char *speed_string;
+	int retval;
+	enum pci_bus_speed value;
+
+	retval = get_cur_bus_speed (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	retval = sprintf (buf, "%s\n", speed_string);
+
+exit:
+	return retval;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = {
+	.attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO},
+	.show = cur_bus_speed_read_file,
+};
+
+static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf,
+		size_t count)
+{
+	unsigned long ltest;
+	u32 test;
+	int retval = 0;
+
+	ltest = simple_strtoul (buf, NULL, 10);
+	test = (u32)(ltest & 0xffffffff);
+	dbg ("test = %d\n", test);
+
+	if (!try_module_get(slot->ops->owner)) {
+		retval = -ENODEV;
+		goto exit;
+	}
+	if (slot->ops->hardware_test)
+		retval = slot->ops->hardware_test(slot, test);
+	module_put(slot->ops->owner);
+
+exit:	
+	if (retval)
+		return retval;
+	return count;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_test = {
+	.attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+	.store = test_write_file
+};
+
+static int has_power_file (struct hotplug_slot *slot)
+{
+	if ((!slot) || (!slot->ops))
+		return -ENODEV;
+	if ((slot->ops->enable_slot) ||
+	    (slot->ops->disable_slot) ||
+	    (slot->ops->get_power_status))
+		return 0;
+	return -ENOENT;
+}
+
+static int has_attention_file (struct hotplug_slot *slot)
+{
+	if ((!slot) || (!slot->ops))
+		return -ENODEV;
+	if ((slot->ops->set_attention_status) ||
+	    (slot->ops->get_attention_status))
+		return 0;
+	return -ENOENT;
+}
+
+static int has_latch_file (struct hotplug_slot *slot)
+{
+	if ((!slot) || (!slot->ops))
+		return -ENODEV;
+	if (slot->ops->get_latch_status)
+		return 0;
+	return -ENOENT;
+}
+
+static int has_adapter_file (struct hotplug_slot *slot)
+{
+	if ((!slot) || (!slot->ops))
+		return -ENODEV;
+	if (slot->ops->get_adapter_status)
+		return 0;
+	return -ENOENT;
+}
+
+static int has_address_file (struct hotplug_slot *slot)
+{
+	if ((!slot) || (!slot->ops))
+		return -ENODEV;
+	if (slot->ops->get_address)
+		return 0;
+	return -ENOENT;
+}
+
+static int has_max_bus_speed_file (struct hotplug_slot *slot)
+{
+	if ((!slot) || (!slot->ops))
+		return -ENODEV;
+	if (slot->ops->get_max_bus_speed)
+		return 0;
+	return -ENOENT;
+}
+
+static int has_cur_bus_speed_file (struct hotplug_slot *slot)
+{
+	if ((!slot) || (!slot->ops))
+		return -ENODEV;
+	if (slot->ops->get_cur_bus_speed)
+		return 0;
+	return -ENOENT;
+}
+
+static int has_test_file (struct hotplug_slot *slot)
+{
+	if ((!slot) || (!slot->ops))
+		return -ENODEV;
+	if (slot->ops->hardware_test)
+		return 0;
+	return -ENOENT;
+}
+
+static int fs_add_slot (struct hotplug_slot *slot)
+{
+	if (has_power_file(slot) == 0)
+		sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+
+	if (has_attention_file(slot) == 0)
+		sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+
+	if (has_latch_file(slot) == 0)
+		sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+
+	if (has_adapter_file(slot) == 0)
+		sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+
+	if (has_address_file(slot) == 0)
+		sysfs_create_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+
+	if (has_max_bus_speed_file(slot) == 0)
+		sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+
+	if (has_cur_bus_speed_file(slot) == 0)
+		sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+
+	if (has_test_file(slot) == 0)
+		sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr);
+
+	return 0;
+}
+
+static void fs_remove_slot (struct hotplug_slot *slot)
+{
+	if (has_power_file(slot) == 0)
+		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+
+	if (has_attention_file(slot) == 0)
+		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+
+	if (has_latch_file(slot) == 0)
+		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+
+	if (has_adapter_file(slot) == 0)
+		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+
+	if (has_address_file(slot) == 0)
+		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+
+	if (has_max_bus_speed_file(slot) == 0)
+		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+
+	if (has_cur_bus_speed_file(slot) == 0)
+		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+
+	if (has_test_file(slot) == 0)
+		sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr);
+}
+
+static struct hotplug_slot *get_slot_from_name (const char *name)
+{
+	struct hotplug_slot *slot;
+	struct list_head *tmp;
+
+	list_for_each (tmp, &pci_hotplug_slot_list) {
+		slot = list_entry (tmp, struct hotplug_slot, slot_list);
+		if (strcmp(slot->name, name) == 0)
+			return slot;
+	}
+	return NULL;
+}
+
+/**
+ * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
+ * @slot: pointer to the &struct hotplug_slot to register
+ *
+ * Registers a hotplug slot with the pci hotplug subsystem, which will allow
+ * userspace interaction to the slot.
+ *
+ * Returns 0 if successful, anything else for an error.
+ */
+int pci_hp_register (struct hotplug_slot *slot)
+{
+	int result;
+
+	if (slot == NULL)
+		return -ENODEV;
+	if ((slot->info == NULL) || (slot->ops == NULL))
+		return -EINVAL;
+	if (slot->release == NULL) {
+		dbg("Why are you trying to register a hotplug slot"
+		    "without a proper release function?\n");
+		return -EINVAL;
+	}
+
+	kobject_set_name(&slot->kobj, "%s", slot->name);
+	kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
+
+	/* this can fail if we have already registered a slot with the same name */
+	if (kobject_register(&slot->kobj)) {
+		err("Unable to register kobject");
+		return -EINVAL;
+	}
+		
+	list_add (&slot->slot_list, &pci_hotplug_slot_list);
+
+	result = fs_add_slot (slot);
+	dbg ("Added slot %s to the list\n", slot->name);
+	return result;
+}
+
+/**
+ * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem
+ * @slot: pointer to the &struct hotplug_slot to deregister
+ *
+ * The @slot must have been registered with the pci hotplug subsystem
+ * previously with a call to pci_hp_register().
+ *
+ * Returns 0 if successful, anything else for an error.
+ */
+int pci_hp_deregister (struct hotplug_slot *slot)
+{
+	struct hotplug_slot *temp;
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	temp = get_slot_from_name (slot->name);
+	if (temp != slot) {
+		return -ENODEV;
+	}
+	list_del (&slot->slot_list);
+
+	fs_remove_slot (slot);
+	dbg ("Removed slot %s from the list\n", slot->name);
+	kobject_unregister(&slot->kobj);
+	return 0;
+}
+
+/**
+ * pci_hp_change_slot_info - changes the slot's information structure in the core
+ * @slot: pointer to the slot whose info has changed
+ * @info: pointer to the info copy into the slot's info structure
+ *
+ * @slot must have been registered with the pci 
+ * hotplug subsystem previously with a call to pci_hp_register().
+ *
+ * Returns 0 if successful, anything else for an error.
+ */
+int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info)
+{
+	if ((slot == NULL) || (info == NULL))
+		return -ENODEV;
+
+	/*
+	* check all fields in the info structure, and update timestamps
+	* for the files referring to the fields that have now changed.
+	*/
+	if ((has_power_file(slot) == 0) &&
+	    (slot->info->power_status != info->power_status))
+		sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+
+	if ((has_attention_file(slot) == 0) &&
+	    (slot->info->attention_status != info->attention_status))
+		sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+
+	if ((has_latch_file(slot) == 0) &&
+	    (slot->info->latch_status != info->latch_status))
+		sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+
+	if ((has_adapter_file(slot) == 0) &&
+	    (slot->info->adapter_status != info->adapter_status))
+		sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+
+	if ((has_address_file(slot) == 0) &&
+	    (slot->info->address != info->address))
+		sysfs_update_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+
+	if ((has_max_bus_speed_file(slot) == 0) &&
+	    (slot->info->max_bus_speed != info->max_bus_speed))
+		sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+
+	if ((has_cur_bus_speed_file(slot) == 0) &&
+	    (slot->info->cur_bus_speed != info->cur_bus_speed))
+		sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+
+	memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
+
+	return 0;
+}
+
+static int __init pci_hotplug_init (void)
+{
+	int result;
+
+	kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
+	result = subsystem_register(&pci_hotplug_slots_subsys);
+	if (result) {
+		err("Register subsys with error %d\n", result);
+		goto exit;
+	}
+	result = cpci_hotplug_init(debug);
+	if (result) {
+		err ("cpci_hotplug_init with error %d\n", result);
+		goto err_subsys;
+	}
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+	goto exit;
+	
+err_subsys:
+	subsystem_unregister(&pci_hotplug_slots_subsys);
+exit:
+	return result;
+}
+
+static void __exit pci_hotplug_exit (void)
+{
+	cpci_hotplug_exit();
+	subsystem_unregister(&pci_hotplug_slots_subsys);
+}
+
+module_init(pci_hotplug_init);
+module_exit(pci_hotplug_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
+EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
+EXPORT_SYMBOL_GPL(pci_hp_register);
+EXPORT_SYMBOL_GPL(pci_hp_deregister);
+EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
new file mode 100644
index 0000000..f313121
--- /dev/null
+++ b/drivers/pci/hotplug/pciehp.h
@@ -0,0 +1,352 @@
+/*
+ * PCI Express Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+#ifndef _PCIEHP_H
+#define _PCIEHP_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>		
+#include <linux/pcieport_if.h>
+#include "pci_hotplug.h"
+
+#define MY_NAME	"pciehp"
+
+extern int pciehp_poll_mode;
+extern int pciehp_poll_time;
+extern int pciehp_debug;
+
+/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
+#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+
+struct pci_func {
+	struct pci_func *next;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 is_a_board;
+	u16 status;
+	u8 configured;
+	u8 switch_save;
+	u8 presence_save;
+	u32 base_length[0x06];
+	u8 base_type[0x06];
+	u16 reserved2;
+	u32 config_space[0x20];
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev* pci_dev;
+};
+
+struct slot {
+	struct slot *next;
+	u8 bus;
+	u8 device;
+	u32 number;
+	u8 is_a_board;
+	u8 configured;
+	u8 state;
+	u8 switch_save;
+	u8 presence_save;
+	u32 capabilities;
+	u16 reserved2;
+	struct timer_list task_event;
+	u8 hp_slot;
+	struct controller *ctrl;
+	struct hpc_ops *hpc_ops;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head	slot_list;
+};
+
+struct pci_resource {
+	struct pci_resource * next;
+	u32 base;
+	u32 length;
+};
+
+struct event_info {
+	u32 event_type;
+	u8 hp_slot;
+};
+
+struct controller {
+	struct controller *next;
+	struct semaphore crit_sect;	/* critical section semaphore */
+	void *hpc_ctlr_handle;		/* HPC controller handle */
+	int num_slots;			/* Number of slots on ctlr */
+	int slot_num_inc;		/* 1 or -1 */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev *pci_dev;
+	struct pci_bus *pci_bus;
+	struct event_info event_queue[10];
+	struct slot *slot;
+	struct hpc_ops *hpc_ops;
+	wait_queue_head_t queue;	/* sleep & wake process */
+	u8 next_event;
+	u8 seg;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 rev;
+	u8 slot_device_offset;
+	u8 add_support;
+	enum pci_bus_speed speed;
+	u32 first_slot;		/* First physical slot number */  /* PCIE only has 1 slot */
+	u8 slot_bus;		/* Bus where the slots handled by this controller sit */
+	u8 ctrlcap;
+	u16 vendor_id;
+};
+
+struct irq_mapping {
+	u8 barber_pole;
+	u8 valid_INT;
+	u8 interrupt[4];
+};
+
+struct resource_lists {
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct irq_mapping *irqs;
+};
+
+#define INT_BUTTON_IGNORE		0
+#define INT_PRESENCE_ON			1
+#define INT_PRESENCE_OFF		2
+#define INT_SWITCH_CLOSE		3
+#define INT_SWITCH_OPEN			4
+#define INT_POWER_FAULT			5
+#define INT_POWER_FAULT_CLEAR		6
+#define INT_BUTTON_PRESS		7
+#define INT_BUTTON_RELEASE		8
+#define INT_BUTTON_CANCEL		9
+
+#define STATIC_STATE			0
+#define BLINKINGON_STATE		1
+#define BLINKINGOFF_STATE		2
+#define POWERON_STATE			3
+#define POWEROFF_STATE			4
+
+#define PCI_TO_PCI_BRIDGE_CLASS		0x00060400
+
+/* Error messages */
+#define INTERLOCK_OPEN			0x00000002
+#define ADD_NOT_SUPPORTED		0x00000003
+#define CARD_FUNCTIONING		0x00000005
+#define ADAPTER_NOT_SAME		0x00000006
+#define NO_ADAPTER_PRESENT		0x00000009
+#define NOT_ENOUGH_RESOURCES		0x0000000B
+#define DEVICE_TYPE_NOT_SUPPORTED	0x0000000C
+#define WRONG_BUS_FREQUENCY		0x0000000D
+#define POWER_FAILURE			0x0000000E
+
+#define REMOVE_NOT_SUPPORTED		0x00000003
+
+#define DISABLE_CARD			1
+
+/* Field definitions in Slot Capabilities Register */
+#define ATTN_BUTTN_PRSN	0x00000001
+#define	PWR_CTRL_PRSN	0x00000002
+#define MRL_SENS_PRSN	0x00000004
+#define ATTN_LED_PRSN	0x00000008
+#define PWR_LED_PRSN	0x00000010
+#define HP_SUPR_RM_SUP	0x00000020
+
+#define ATTN_BUTTN(cap)		(cap & ATTN_BUTTN_PRSN)
+#define POWER_CTRL(cap)		(cap & PWR_CTRL_PRSN)
+#define MRL_SENS(cap)		(cap & MRL_SENS_PRSN)
+#define ATTN_LED(cap)		(cap & ATTN_LED_PRSN)
+#define PWR_LED(cap)		(cap & PWR_LED_PRSN) 
+#define HP_SUPR_RM(cap)		(cap & HP_SUPR_RM_SUP)
+
+/*
+ * error Messages
+ */
+#define msg_initialization_err	"Initialization failure, error=%d\n"
+#define msg_HPC_rev_error	"Unsupported revision of the PCI hot plug controller found.\n"
+#define msg_HPC_non_pcie	"The PCI hot plug controller is not supported by this driver.\n"
+#define msg_HPC_not_supported	"This system is not supported by this version of pciephd module. Upgrade to a newer version of pciehpd\n"
+#define msg_unable_to_save	"Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n"
+#define msg_button_on		"PCI slot #%d - powering on due to button press.\n"
+#define msg_button_off		"PCI slot #%d - powering off due to button press.\n"
+#define msg_button_cancel	"PCI slot #%d - action canceled due to button press.\n"
+#define msg_button_ignore	"PCI slot #%d - button press ignored.  (action in progress...)\n"
+
+/* controller functions */
+extern int	pciehprm_find_available_resources	(struct controller *ctrl);
+extern int	pciehp_event_start_thread	(void);
+extern void	pciehp_event_stop_thread	(void);
+extern struct 	pci_func *pciehp_slot_create	(unsigned char busnumber);
+extern struct 	pci_func *pciehp_slot_find	(unsigned char bus, unsigned char device, unsigned char index);
+extern int	pciehp_enable_slot		(struct slot *slot);
+extern int	pciehp_disable_slot		(struct slot *slot);
+
+extern u8	pciehp_handle_attention_button	(u8 hp_slot, void *inst_id);
+extern u8	pciehp_handle_switch_change	(u8 hp_slot, void *inst_id);
+extern u8	pciehp_handle_presence_change	(u8 hp_slot, void *inst_id);
+extern u8	pciehp_handle_power_fault	(u8 hp_slot, void *inst_id);
+/* extern void	long_delay (int delay); */
+
+/* resource functions */
+extern int	pciehp_resource_sort_and_combine	(struct pci_resource **head);
+
+/* pci functions */
+extern int	pciehp_set_irq			(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
+/*extern int	pciehp_get_bus_dev		(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/
+extern int	pciehp_save_config	 	(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
+extern int	pciehp_save_used_resources	(struct controller *ctrl, struct pci_func * func, int flag);
+extern int	pciehp_save_slot_config		(struct controller *ctrl, struct pci_func * new_slot);
+extern void	pciehp_destroy_board_resources	(struct pci_func * func);
+extern int	pciehp_return_board_resources	(struct pci_func * func, struct resource_lists * resources);
+extern void	pciehp_destroy_resource_list	(struct resource_lists * resources);
+extern int	pciehp_configure_device		(struct controller* ctrl, struct pci_func* func);
+extern int	pciehp_unconfigure_device	(struct pci_func* func);
+
+
+/* Global variables */
+extern struct controller *pciehp_ctrl_list;
+extern struct pci_func *pciehp_slot_list[256];
+
+/* Inline functions */
+
+static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
+{
+	struct slot *p_slot, *tmp_slot = NULL;
+
+	p_slot = ctrl->slot;
+
+	dbg("p_slot = %p\n", p_slot);
+
+	while (p_slot && (p_slot->device != device)) {
+		tmp_slot = p_slot;
+		p_slot = p_slot->next;
+		dbg("In while loop, p_slot = %p\n", p_slot);
+	}
+	if (p_slot == NULL) {
+		err("ERROR: pciehp_find_slot device=0x%x\n", device);
+		p_slot = tmp_slot;
+	}
+
+	return p_slot;
+}
+
+static inline int wait_for_ctrl_irq(struct controller *ctrl)
+{
+	int retval = 0;
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	dbg("%s : start\n", __FUNCTION__);
+	add_wait_queue(&ctrl->queue, &wait);
+	if (!pciehp_poll_mode)
+		/* Sleep for up to 1 second */
+		msleep_interruptible(1000);
+	else
+		msleep_interruptible(2500);
+	
+	remove_wait_queue(&ctrl->queue, &wait);
+	if (signal_pending(current))
+		retval =  -EINTR;
+
+	dbg("%s : end\n", __FUNCTION__);
+	return retval;
+}
+
+/* Puts node back in the resource list pointed to by head */
+static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
+{
+	if (!node || !head)
+		return;
+	node->next = *head;
+	*head = node;
+}
+
+#define SLOT_NAME_SIZE 10
+
+static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
+{
+	snprintf(buffer, buffer_size, "%d", slot->number);
+}
+
+enum php_ctlr_type {
+	PCI,
+	ISA,
+	ACPI
+};
+
+typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id);
+
+int pcie_init(struct controller *ctrl, struct pcie_device *dev,
+		php_intr_callback_t attention_button_callback,
+		php_intr_callback_t switch_change_callback,
+		php_intr_callback_t presence_change_callback,
+		php_intr_callback_t power_fault_callback);
+
+
+/* This has no meaning for PCI Express, as there is only 1 slot per port */
+int pcie_get_ctlr_slot_config(struct controller *ctrl,
+		int *num_ctlr_slots,
+		int *first_device_num,
+		int *physical_slot_num,
+		u8 *ctrlcap);
+
+struct hpc_ops {
+	int	(*power_on_slot)	(struct slot *slot);
+	int	(*power_off_slot)	(struct slot *slot);
+	int	(*get_power_status)	(struct slot *slot, u8 *status);
+	int	(*get_attention_status)	(struct slot *slot, u8 *status);
+	int	(*set_attention_status)	(struct slot *slot, u8 status);
+	int	(*get_latch_status)	(struct slot *slot, u8 *status);
+	int	(*get_adapter_status)	(struct slot *slot, u8 *status);
+
+	int	(*get_max_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_cur_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+
+	int	(*get_max_lnk_width)	(struct slot *slot, enum pcie_link_width *value);
+	int	(*get_cur_lnk_width)	(struct slot *slot, enum pcie_link_width *value);
+	
+	int	(*query_power_fault)	(struct slot *slot);
+	void	(*green_led_on)		(struct slot *slot);
+	void	(*green_led_off)	(struct slot *slot);
+	void	(*green_led_blink)	(struct slot *slot);
+	void	(*release_ctlr)		(struct controller *ctrl);
+	int	(*check_lnk_status)	(struct controller *ctrl);
+};
+
+#endif				/* _PCIEHP_H */
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
new file mode 100644
index 0000000..8a5b2b5
--- /dev/null
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -0,0 +1,662 @@
+/*
+ * PCI Express Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include "pciehp.h"
+#include "pciehprm.h"
+#include <linux/interrupt.h>
+
+/* Global variables */
+int pciehp_debug;
+int pciehp_poll_mode;
+int pciehp_poll_time;
+struct controller *pciehp_ctrl_list;
+struct pci_func *pciehp_slot_list[256];
+
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
+#define DRIVER_DESC	"PCI Express Hot Plug Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(pciehp_debug, bool, 0644);
+module_param(pciehp_poll_mode, bool, 0644);
+module_param(pciehp_poll_time, int, 0644);
+MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
+MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
+MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
+
+#define PCIE_MODULE_NAME "pciehp"
+
+static int pcie_start_thread (void);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+
+static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
+	.owner =		THIS_MODULE,
+	.set_attention_status =	set_attention_status,
+	.enable_slot =		enable_slot,
+	.disable_slot =		disable_slot,
+	.get_power_status =	get_power_status,
+	.get_attention_status =	get_attention_status,
+	.get_latch_status =	get_latch_status,
+	.get_adapter_status =	get_adapter_status,
+  	.get_max_bus_speed =	get_max_bus_speed,
+  	.get_cur_bus_speed =	get_cur_bus_speed,
+};
+
+static int init_slots(struct controller *ctrl)
+{
+	struct slot *new_slot;
+	u8 number_of_slots;
+	u8 slot_device;
+	u32 slot_number;
+	int result = -ENOMEM;
+
+	dbg("%s\n",__FUNCTION__);
+
+	number_of_slots = ctrl->num_slots;
+	slot_device = ctrl->slot_device_offset;
+	slot_number = ctrl->first_slot;
+
+	while (number_of_slots) {
+		new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
+		if (!new_slot)
+			goto error;
+
+		memset(new_slot, 0, sizeof(struct slot));
+		new_slot->hotplug_slot =
+				kmalloc(sizeof(*(new_slot->hotplug_slot)),
+						GFP_KERNEL);
+		if (!new_slot->hotplug_slot)
+			goto error_slot;
+		memset(new_slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
+
+		new_slot->hotplug_slot->info =
+			kmalloc(sizeof(*(new_slot->hotplug_slot->info)),
+						GFP_KERNEL);
+		if (!new_slot->hotplug_slot->info)
+			goto error_hpslot;
+		memset(new_slot->hotplug_slot->info, 0,
+					sizeof(struct hotplug_slot_info));
+		new_slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE,
+						GFP_KERNEL);
+		if (!new_slot->hotplug_slot->name)
+			goto error_info;
+
+		new_slot->ctrl = ctrl;
+		new_slot->bus = ctrl->slot_bus;
+		new_slot->device = slot_device;
+		new_slot->hpc_ops = ctrl->hpc_ops;
+
+		new_slot->number = ctrl->first_slot;
+		new_slot->hp_slot = slot_device - ctrl->slot_device_offset;
+
+		/* register this slot with the hotplug pci core */
+		new_slot->hotplug_slot->private = new_slot;
+		make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
+		new_slot->hotplug_slot->ops = &pciehp_hotplug_slot_ops;
+
+		new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status));
+		new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status));
+		new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status));
+		new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status));
+
+		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", 
+			new_slot->bus, new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset);
+		result = pci_hp_register (new_slot->hotplug_slot);
+		if (result) {
+			err ("pci_hp_register failed with error %d\n", result);
+			goto error_name;
+		}
+
+		new_slot->next = ctrl->slot;
+		ctrl->slot = new_slot;
+
+		number_of_slots--;
+		slot_device++;
+		slot_number += ctrl->slot_num_inc;
+	}
+
+	return 0;
+
+error_name:
+	kfree(new_slot->hotplug_slot->name);
+error_info:
+	kfree(new_slot->hotplug_slot->info);
+error_hpslot:
+	kfree(new_slot->hotplug_slot);
+error_slot:
+	kfree(new_slot);
+error:
+	return result;
+}
+
+
+static int cleanup_slots (struct controller * ctrl)
+{
+	struct slot *old_slot, *next_slot;
+
+	old_slot = ctrl->slot;
+	ctrl->slot = NULL;
+
+	while (old_slot) {
+		next_slot = old_slot->next;
+		pci_hp_deregister (old_slot->hotplug_slot);
+		kfree(old_slot->hotplug_slot->info);
+		kfree(old_slot->hotplug_slot->name);
+		kfree(old_slot->hotplug_slot);
+		kfree(old_slot);
+		old_slot = next_slot;
+	}
+
+
+	return(0);
+}
+
+static int get_ctlr_slot_config(struct controller *ctrl)
+{
+	int num_ctlr_slots;		/* Not needed; PCI Express has 1 slot per port*/
+	int first_device_num;		/* Not needed */
+	int physical_slot_num;
+	u8 ctrlcap;			
+	int rc;
+
+	rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap);
+	if (rc) {
+		err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
+		return (-1);
+	}
+
+	ctrl->num_slots = num_ctlr_slots;	/* PCI Express has 1 slot per port */
+	ctrl->slot_device_offset = first_device_num;
+	ctrl->first_slot = physical_slot_num;
+	ctrl->ctrlcap = ctrlcap; 	
+
+	dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n",
+		__FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap, 
+		ctrl->bus, ctrl->device);
+
+	return (0);
+}
+
+
+/*
+ * set_attention_status - Turns the Amber LED for a slot on, off or blink
+ */
+static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	hotplug_slot->info->attention_status = status;
+	
+	if (ATTN_LED(slot->ctrl->ctrlcap)) 
+		slot->hpc_ops->set_attention_status(slot, status);
+
+	return 0;
+}
+
+
+static int enable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	return pciehp_enable_slot(slot);
+}
+
+
+static int disable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	return pciehp_disable_slot(slot);
+}
+
+static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_power_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->power_status;
+
+	return 0;
+}
+
+static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_attention_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->attention_status;
+
+	return 0;
+}
+
+static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_latch_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->latch_status;
+
+	return 0;
+}
+
+static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_adapter_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->adapter_status;
+
+	return 0;
+}
+
+static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+	
+	retval = slot->hpc_ops->get_max_bus_speed(slot, value);
+	if (retval < 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+	
+	retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
+	if (retval < 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_id *id)
+{
+	int rc;
+	struct controller *ctrl;
+	struct slot *t_slot;
+	int first_device_num = 0 ;	/* first PCI device number supported by this PCIE */  
+	int num_ctlr_slots;		/* number of slots supported by this HPC */
+	u8 value;
+	struct pci_dev *pdev;
+	
+	dbg("%s: Called by hp_drv\n", __FUNCTION__);
+	ctrl = kmalloc(sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl) {
+		err("%s : out of memory\n", __FUNCTION__);
+		goto err_out_none;
+	}
+	memset(ctrl, 0, sizeof(struct controller));
+
+	dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid);
+	
+	pdev = dev->port;
+
+	rc = pcie_init(ctrl, dev,
+		(php_intr_callback_t) pciehp_handle_attention_button,
+		(php_intr_callback_t) pciehp_handle_switch_change,
+		(php_intr_callback_t) pciehp_handle_presence_change,
+		(php_intr_callback_t) pciehp_handle_power_fault);
+	if (rc) {
+		dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME);
+		goto err_out_free_ctrl;
+	}
+
+	ctrl->pci_dev = pdev;
+
+	pci_set_drvdata(pdev, ctrl);
+
+	ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
+	if (!ctrl->pci_bus) {
+		err("%s: out of memory\n", __FUNCTION__);
+		rc = -ENOMEM;
+		goto err_out_unmap_mmio_region;
+	}
+	dbg("%s: ctrl->pci_bus %p\n", __FUNCTION__, ctrl->pci_bus);
+	memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
+	ctrl->bus = pdev->bus->number;  /* ctrl bus */
+	ctrl->slot_bus = pdev->subordinate->number;  /* bus controlled by this HPC */
+
+	ctrl->device = PCI_SLOT(pdev->devfn);
+	ctrl->function = PCI_FUNC(pdev->devfn);
+	dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
+		ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
+
+	/*
+	 *	Save configuration headers for this and subordinate PCI buses
+	 */
+
+	rc = get_ctlr_slot_config(ctrl);
+	if (rc) {
+		err(msg_initialization_err, rc);
+		goto err_out_free_ctrl_bus;
+	}
+	first_device_num = ctrl->slot_device_offset;
+	num_ctlr_slots = ctrl->num_slots; 
+
+	/* Store PCI Config Space for all devices on this bus */
+	dbg("%s: Before calling pciehp_save_config, ctrl->bus %x,ctrl->slot_bus %x\n", 
+		__FUNCTION__,ctrl->bus, ctrl->slot_bus);
+	rc = pciehp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num);
+	if (rc) {
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Get IO, memory, and IRQ resources for new devices */
+	rc = pciehprm_find_available_resources(ctrl);
+	ctrl->add_support = !rc;
+	
+	if (rc) {
+		dbg("pciehprm_find_available_resources = %#x\n", rc);
+		err("unable to locate PCI configuration resources for hot plug add.\n");
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Setup the slot information structures */
+	rc = init_slots(ctrl);
+	if (rc) {
+		err(msg_initialization_err, 6);
+		goto err_out_free_ctrl_slot;
+	}
+
+	t_slot = pciehp_find_slot(ctrl, first_device_num);
+	dbg("%s: t_slot %p\n", __FUNCTION__, t_slot);
+
+	/*	Finish setting up the hot plug ctrl device */
+	ctrl->next_event = 0;
+
+	if (!pciehp_ctrl_list) {
+		pciehp_ctrl_list = ctrl;
+		ctrl->next = NULL;
+	} else {
+		ctrl->next = pciehp_ctrl_list;
+		pciehp_ctrl_list = ctrl;
+	}
+
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
+	dbg("%s: adpater value %x\n", __FUNCTION__, value);
+	
+	if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
+		rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
+		if (rc) {
+			/* Done with exclusive hardware access */
+			up(&ctrl->crit_sect);
+			goto err_out_free_ctrl_slot;
+		} else
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (ctrl);
+	}
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	return 0;
+
+err_out_free_ctrl_slot:
+	cleanup_slots(ctrl);
+err_out_free_ctrl_bus:
+	kfree(ctrl->pci_bus);
+err_out_unmap_mmio_region:
+	ctrl->hpc_ops->release_ctlr(ctrl);
+err_out_free_ctrl:
+	kfree(ctrl);
+err_out_none:
+	return -ENODEV;
+}
+
+
+static int pcie_start_thread(void)
+{
+	int loop;
+	int retval = 0;
+	
+	dbg("Initialize + Start the notification/polling mechanism \n");
+
+	retval = pciehp_event_start_thread();
+	if (retval) {
+		dbg("pciehp_event_start_thread() failed\n");
+		return retval;
+	}
+
+	dbg("Initialize slot lists\n");
+	/* One slot list for each bus in the system */
+	for (loop = 0; loop < 256; loop++) {
+		pciehp_slot_list[loop] = NULL;
+	}
+
+	return retval;
+}
+
+static inline void __exit
+free_pciehp_res(struct pci_resource *res)
+{
+	struct pci_resource *tres;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
+static void __exit unload_pciehpd(void)
+{
+	struct pci_func *next;
+	struct pci_func *TempSlot;
+	int loop;
+	struct controller *ctrl;
+	struct controller *tctrl;
+
+	ctrl = pciehp_ctrl_list;
+
+	while (ctrl) {
+		cleanup_slots(ctrl);
+
+		free_pciehp_res(ctrl->io_head);
+		free_pciehp_res(ctrl->mem_head);
+		free_pciehp_res(ctrl->p_mem_head);
+		free_pciehp_res(ctrl->bus_head);
+
+		kfree (ctrl->pci_bus);
+
+		ctrl->hpc_ops->release_ctlr(ctrl);
+
+		tctrl = ctrl;
+		ctrl = ctrl->next;
+
+		kfree(tctrl);
+	}
+
+	for (loop = 0; loop < 256; loop++) {
+		next = pciehp_slot_list[loop];
+		while (next != NULL) {
+			free_pciehp_res(next->io_head);
+			free_pciehp_res(next->mem_head);
+			free_pciehp_res(next->p_mem_head);
+			free_pciehp_res(next->bus_head);
+
+			TempSlot = next;
+			next = next->next;
+			kfree(TempSlot);
+		}
+	}
+
+	/* Stop the notification mechanism */
+	pciehp_event_stop_thread();
+
+}
+
+int hpdriver_context = 0;
+
+static void pciehp_remove (struct pcie_device *device)
+{
+	printk("%s ENTRY\n", __FUNCTION__);	
+	printk("%s -> Call free_irq for irq = %d\n",  
+		__FUNCTION__, device->irq);
+	free_irq(device->irq, &hpdriver_context);
+}
+
+#ifdef CONFIG_PM
+static int pciehp_suspend (struct pcie_device *dev, u32 state)
+{
+	printk("%s ENTRY\n", __FUNCTION__);	
+	return 0;
+}
+
+static int pciehp_resume (struct pcie_device *dev)
+{
+	printk("%s ENTRY\n", __FUNCTION__);	
+	return 0;
+}
+#endif
+
+static struct pcie_port_service_id port_pci_ids[] = { { 
+	.vendor = PCI_ANY_ID, 
+	.device = PCI_ANY_ID,
+	.port_type = PCIE_RC_PORT, 
+	.service_type = PCIE_PORT_SERVICE_HP,
+	.driver_data =	0, 
+	}, { /* end: all zeroes */ }
+};
+static const char device_name[] = "hpdriver";
+
+static struct pcie_port_service_driver hpdriver_portdrv = {
+	.name		= (char *)device_name,
+	.id_table	= &port_pci_ids[0],
+
+	.probe		= pciehp_probe,
+	.remove		= pciehp_remove,
+
+#ifdef	CONFIG_PM
+	.suspend	= pciehp_suspend,
+	.resume		= pciehp_resume,
+#endif	/* PM */
+};
+
+static int __init pcied_init(void)
+{
+	int retval = 0;
+
+#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
+	pciehp_poll_mode = 1;
+#endif
+
+	retval = pcie_start_thread();
+	if (retval)
+		goto error_hpc_init;
+
+	retval = pciehprm_init(PCI);
+	if (!retval) {
+ 		retval = pcie_port_service_register(&hpdriver_portdrv);
+ 		dbg("pcie_port_service_register = %d\n", retval);
+  		info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+ 		if (retval)
+ 		   dbg("%s: Failure to register service\n", __FUNCTION__);
+	}
+
+error_hpc_init:
+	if (retval) {
+		pciehprm_cleanup();
+		pciehp_event_stop_thread();
+	} else
+		pciehprm_print_pirt();
+
+	return retval;
+}
+
+static void __exit pcied_cleanup(void)
+{
+	dbg("unload_pciehpd()\n");
+	unload_pciehpd();
+
+	pciehprm_cleanup();
+
+	dbg("pcie_port_service_unregister\n");
+	pcie_port_service_unregister(&hpdriver_portdrv);
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
+}
+
+module_init(pcied_init);
+module_exit(pcied_cleanup);
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
new file mode 100644
index 0000000..0dbcf04
--- /dev/null
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -0,0 +1,2706 @@
+/*
+ * PCI Express Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include "../pci.h"
+#include "pciehp.h"
+#include "pciehprm.h"
+
+static u32 configure_new_device(struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static int configure_new_function( struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static void interrupt_event_handler(struct controller *ctrl);
+
+static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
+static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
+static int event_finished;
+static unsigned long pushbutton_pending;	/* = 0 */
+static unsigned long surprise_rm_pending;	/* = 0 */
+
+u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Attention Button Change */
+	dbg("pciehp:  Attention button interrupt received.\n");
+	
+	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread what to do */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+
+	/*
+	 *  Button pressed - See if need to TAKE ACTION!!!
+	 */
+	info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	taskInfo->event_type = INT_BUTTON_PRESS;
+
+	if ((p_slot->state == BLINKINGON_STATE)
+	    || (p_slot->state == BLINKINGOFF_STATE)) {
+		/* Cancel if we are still blinking; this means that we press the
+		 * attention again before the 5 sec. limit expires to cancel hot-add
+		 * or hot-remove
+		 */
+		taskInfo->event_type = INT_BUTTON_CANCEL;
+		info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	} else if ((p_slot->state == POWERON_STATE)
+		   || (p_slot->state == POWEROFF_STATE)) {
+		/* Ignore if the slot is on power-on or power-off state; this 
+		 * means that the previous attention button action to hot-add or
+		 * hot-remove is undergoing
+		 */
+		taskInfo->event_type = INT_BUTTON_IGNORE;
+		info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	}
+
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return 0;
+
+}
+
+u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Switch Change */
+	dbg("pciehp:  Switch interrupt received.\n");
+
+	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+
+	if (getstatus) {
+		/*
+		 * Switch opened
+		 */
+		info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->switch_save = 0;
+		taskInfo->event_type = INT_SWITCH_OPEN;
+	} else {
+		/*
+		 *  Switch closed
+		 */
+		info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->switch_save = 0x10;
+		taskInfo->event_type = INT_SWITCH_CLOSE;
+	}
+
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Presence Change */
+	dbg("pciehp:  Presence/Notify input change.\n");
+
+	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	/* Switch is open, assume a presence change
+	 * Save the presence state
+	 */
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	if (func->presence_save) {
+		/*
+		 * Card Present
+		 */
+		info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_PRESENCE_ON;
+	} else {
+		/*
+		 * Not Present
+		 */
+		info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_PRESENCE_OFF;
+	}
+
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* power fault */
+	dbg("pciehp:  Power fault interrupt received.\n");
+
+	func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* this is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
+		/*
+		 * power fault Cleared
+		 */
+		info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->status = 0x00;
+		taskInfo->event_type = INT_POWER_FAULT_CLEAR;
+	} else {
+		/*
+		 *   power fault
+		 */
+		info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_POWER_FAULT;
+		/* set power fault status for this board */
+		func->status = 0xFF;
+		info("power fault bit %x set\n", hp_slot);
+	}
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+
+/**
+ * sort_by_size: sort nodes by their length, smallest first.
+ *
+ * @head: list to sort
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length > (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length > current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+
+
+/*
+ * sort_by_max_size
+ *
+ * Sorts nodes on the list by their length.
+ * Largest first.
+ *
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return 1;
+
+	if (!((*head)->next))
+		return 0;
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length < (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length < current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return 0;
+}
+
+
+/**
+ * do_pre_bridge_resource_split: return one unused resource node
+ * @head: list to scan
+ *
+ */
+static struct pci_resource *
+do_pre_bridge_resource_split(struct pci_resource **head,
+				struct pci_resource **orig_head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 rc;
+	u32 temp_dword;
+	dbg("do_pre_bridge_resource_split\n");
+
+	if (!(*head) || !(*orig_head))
+		return NULL;
+
+	rc = pciehp_resource_sort_and_combine(head);
+
+	if (rc)
+		return NULL;
+
+	if ((*head)->base != (*orig_head)->base)
+		return NULL;
+
+	if ((*head)->length == (*orig_head)->length)
+		return NULL;
+
+
+	/* If we got here, there the bridge requires some of the resource, but
+	 *  we may be able to split some off of the front
+	 */	
+	node = *head;
+
+	if (node->length & (alignment -1)) {
+		/* this one isn't an aligned length, so we'll make a new entry
+		 * and split it up.
+		 */
+		split_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+		if (!split_node)
+			return NULL;
+
+		temp_dword = (node->length | (alignment-1)) + 1 - alignment;
+
+		split_node->base = node->base;
+		split_node->length = temp_dword;
+
+		node->length -= temp_dword;
+		node->base += split_node->length;
+
+		/* Put it in the list */
+		*head = split_node;
+		split_node->next = node;
+	}
+
+	if (node->length < alignment)
+		return NULL;
+
+	/* Now unlink it */
+	if (*head == node) {
+		*head = node->next;
+	} else {
+		prevnode = *head;
+		while (prevnode->next != node)
+			prevnode = prevnode->next;
+
+		prevnode->next = node->next;
+	}
+	node->next = NULL;
+
+	return node;
+}
+
+
+/**
+ * do_bridge_resource_split: return one unused resource node
+ * @head: list to scan
+ *
+ */
+static struct pci_resource *
+do_bridge_resource_split(struct pci_resource **head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	u32 rc;
+	u32 temp_dword;
+
+	if (!(*head))
+		return NULL;
+
+	rc = pciehp_resource_sort_and_combine(head);
+
+	if (rc)
+		return NULL;
+
+	node = *head;
+
+	while (node->next) {
+		prevnode = node;
+		node = node->next;
+		kfree(prevnode);
+	}
+
+	if (node->length < alignment) {
+		kfree(node);
+		return NULL;
+	}
+
+	if (node->base & (alignment - 1)) {
+		/* Short circuit if adjusted size is too small */
+		temp_dword = (node->base | (alignment-1)) + 1;
+		if ((node->length - (temp_dword - node->base)) < alignment) {
+			kfree(node);
+			return NULL;
+		}
+
+		node->length -= (temp_dword - node->base);
+		node->base = temp_dword;
+	}
+
+	if (node->length & (alignment - 1)) {
+		/* There's stuff in use after this node */
+		kfree(node);
+		return NULL;
+	}
+
+	return node;
+}
+
+
+/*
+ * get_io_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length that is not in the
+ * ISA aliasing window.  If it finds a node larger than "size"
+ * it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node = NULL;
+	u32 temp_dword;
+
+	if (!(*head))
+		return NULL;
+
+	if ( pciehp_resource_sort_and_combine(head) )
+		return NULL;
+
+	if ( sort_by_size(head) )
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (node->base | (size-1)) + 1;
+
+			/*/ Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if (node->base & 0x300L)
+			continue;
+
+		/* If we got here, then it is the right size 
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+
+	return node;
+}
+
+
+/*
+ * get_max_resource
+ *
+ * Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M
+ *  This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot.
+ */
+static struct pci_resource *get_max_resource(struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+	u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 };
+	int i;
+
+	if (!(*head))
+		return NULL;
+
+	if (pciehp_resource_sort_and_combine(head))
+		return NULL;
+
+	if (sort_by_max_size(head))
+		return NULL;
+
+	for (max = *head;max; max = max->next) {
+
+		/* If not big enough we could probably just bail, 
+		   instead we'll continue to the next. */
+		if (max->length < size)
+			continue;
+
+		if (max->base & (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (max->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max->length - (temp_dword - max->base)) < size)
+				continue;
+
+			split_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = max->base;
+			split_node->length = temp_dword - max->base;
+			max->base = temp_dword;
+			max->length -= split_node->length;
+
+			/* Put it next in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		if ((max->base + max->length) & (size - 1)) {
+			/* this one isn't end aligned properly at the top
+			   so we'll make a new entry and split it up */
+			split_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+			temp_dword = ((max->base + max->length) & ~(size - 1));
+			split_node->base = temp_dword;
+			split_node->length = max->length + max->base
+					     - split_node->base;
+			max->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max->length < size)
+			continue;
+
+		for ( i = 0; max_size[i] > size; i++) {
+			if (max->length > max_size[i]) {
+				split_node = kmalloc(sizeof(struct pci_resource),
+							GFP_KERNEL);
+				if (!split_node)
+					break;	/* return NULL; */
+				split_node->base = max->base + max_size[i];
+				split_node->length = max->length - max_size[i];
+				max->length = max_size[i];
+				/* Put it next in the list */
+				split_node->next = max->next;
+				max->next = split_node;
+				break;
+			}
+		}
+
+		/* Now take it out of the list */
+		temp = (struct pci_resource*) *head;
+		if (temp == max) {
+			*head = max->next;
+		} else {
+			while (temp && temp->next != max) {
+				temp = temp->next;
+			}
+
+			temp->next = max->next;
+		}
+
+		max->next = NULL;
+		return max;
+	}
+
+	/* If we get here, we couldn't find one */
+	return NULL;
+}
+
+
+/*
+ * get_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_resource(struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+
+	if (!(*head))
+		return NULL;
+
+	if ( pciehp_resource_sort_and_combine(head) )
+		return NULL;
+
+	if ( sort_by_size(head) )
+		return NULL;
+
+	for (node = *head; node; node = node->next) {
+		dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n",
+		    __FUNCTION__, size, node, node->base, node->length);
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			dbg("%s: not aligned\n", __FUNCTION__);
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			dbg("%s: too big\n", __FUNCTION__);
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+
+			if (!split_node)
+				return NULL;
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		dbg("%s: got one!!!\n", __FUNCTION__);
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return node;
+}
+
+
+/*
+ * pciehp_resource_sort_and_combine
+ *
+ * Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int pciehp_resource_sort_and_combine(struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
+
+	if (!(*head))
+		return 1;
+
+	dbg("*head->next = %p\n",(*head)->next);
+
+	if (!(*head)->next)
+		return 0;	/* only one item on the list, already sorted! */
+
+	dbg("*head->base = 0x%x\n",(*head)->base);
+	dbg("*head->next->base = 0x%x\n",(*head)->next->base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->base > (*head)->next->base)) {
+			node1 = *head;
+			(*head) = (*head)->next;
+			node1->next = (*head)->next;
+			(*head)->next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1->next && node1->next->next) {
+			if (node1->next->base > node1->next->next->base) {
+				out_of_order++;
+				node2 = node1->next;
+				node1->next = node1->next->next;
+				node1 = node1->next;
+				node2->next = node1->next;
+				node1->next = node2;
+			} else
+				node1 = node1->next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 && node1->next) {
+		if ((node1->base + node1->length) == node1->next->base) {
+			/* Combine */
+			dbg("8..\n");
+			node1->length += node1->next->length;
+			node2 = node1->next;
+			node1->next = node1->next->next;
+			kfree(node2);
+		} else
+			node1 = node1->next;
+	}
+
+	return 0;
+}
+
+
+/**
+ * pciehp_slot_create - Creates a node and adds it to the proper bus.
+ * @busnumber - bus where new node is to be located
+ *
+ * Returns pointer to the new node or NULL if unsuccessful
+ */
+struct pci_func *pciehp_slot_create(u8 busnumber)
+{
+	struct pci_func *new_slot;
+	struct pci_func *next;
+	dbg("%s: busnumber %x\n", __FUNCTION__, busnumber);
+	new_slot = kmalloc(sizeof(struct pci_func), GFP_KERNEL);
+
+	if (new_slot == NULL)
+		return new_slot;
+
+	memset(new_slot, 0, sizeof(struct pci_func));
+
+	new_slot->next = NULL;
+	new_slot->configured = 1;
+
+	if (pciehp_slot_list[busnumber] == NULL) {
+		pciehp_slot_list[busnumber] = new_slot;
+	} else {
+		next = pciehp_slot_list[busnumber];
+		while (next->next != NULL)
+			next = next->next;
+		next->next = new_slot;
+	}
+	return new_slot;
+}
+
+
+/**
+ * slot_remove - Removes a node from the linked list of slots.
+ * @old_slot: slot to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int slot_remove(struct pci_func * old_slot)
+{
+	struct pci_func *next;
+
+	if (old_slot == NULL)
+		return 1;
+
+	next = pciehp_slot_list[old_slot->bus];
+
+	if (next == NULL)
+		return 1;
+
+	if (next == old_slot) {
+		pciehp_slot_list[old_slot->bus] = old_slot->next;
+		pciehp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return 0;
+	}
+
+	while ((next->next != old_slot) && (next->next != NULL)) {
+		next = next->next;
+	}
+
+	if (next->next == old_slot) {
+		next->next = old_slot->next;
+		pciehp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return 0;
+	} else
+		return 2;
+}
+
+
+/**
+ * bridge_slot_remove - Removes a node from the linked list of slots.
+ * @bridge: bridge to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int bridge_slot_remove(struct pci_func *bridge)
+{
+	u8 subordinateBus, secondaryBus;
+	u8 tempBus;
+	struct pci_func *next;
+
+	if (bridge == NULL)
+		return 1;
+
+	secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
+	subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
+
+	for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
+		next = pciehp_slot_list[tempBus];
+
+		while (!slot_remove(next)) {
+			next = pciehp_slot_list[tempBus];
+		}
+	}
+
+	next = pciehp_slot_list[bridge->bus];
+
+	if (next == NULL) {
+		return 1;
+	}
+
+	if (next == bridge) {
+		pciehp_slot_list[bridge->bus] = bridge->next;
+		kfree(bridge);
+		return 0;
+	}
+
+	while ((next->next != bridge) && (next->next != NULL)) {
+		next = next->next;
+	}
+
+	if (next->next == bridge) {
+		next->next = bridge->next;
+		kfree(bridge);
+		return 0;
+	} else
+		return 2;
+}
+
+
+/**
+ * pciehp_slot_find - Looks for a node by bus, and device, multiple functions accessed
+ * @bus: bus to find
+ * @device: device to find
+ * @index: is 0 for first function found, 1 for the second...
+ *
+ * Returns pointer to the node if successful, %NULL otherwise.
+ */
+struct pci_func *pciehp_slot_find(u8 bus, u8 device, u8 index)
+{
+	int found = -1;
+	struct pci_func *func;
+
+	func = pciehp_slot_list[bus];
+	dbg("%s: bus %x device %x index %x\n",
+		__FUNCTION__, bus, device, index);
+	if (func != NULL) {
+		dbg("%s: func-> bus %x device %x function %x pci_dev %p\n",
+			__FUNCTION__, func->bus, func->device, func->function,
+			func->pci_dev);
+	} else
+		dbg("%s: func == NULL\n", __FUNCTION__);
+
+	if ((func == NULL) || ((func->device == device) && (index == 0)))
+		return func;
+
+	if (func->device == device)
+		found++;
+
+	while (func->next != NULL) {
+		func = func->next;
+
+		dbg("%s: In while loop, func-> bus %x device %x function %x pci_dev %p\n",
+			__FUNCTION__, func->bus, func->device, func->function,
+			func->pci_dev);
+		if (func->device == device)
+			found++;
+		dbg("%s: while loop, found %d, index %d\n", __FUNCTION__,
+			found, index);
+
+		if ((found == index) || (func->function == index)) {
+			dbg("%s: Found bus %x dev %x func %x\n", __FUNCTION__,
+					func->bus, func->device, func->function);
+			return func;
+		}
+	}
+
+	return NULL;
+}
+
+static int is_bridge(struct pci_func * func)
+{
+	/* Check the header type */
+	if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* The following routines constitute the bulk of the 
+   hotplug controller logic
+ */
+
+static void set_slot_off(struct controller *ctrl, struct slot * pslot)
+{
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
+	if (POWER_CTRL(ctrl->ctrlcap)) {
+		if (pslot->hpc_ops->power_off_slot(pslot)) {   
+			err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
+			up(&ctrl->crit_sect);
+			return;
+		}
+		wait_for_ctrl_irq (ctrl);
+	}
+
+	if (PWR_LED(ctrl->ctrlcap)) {
+		pslot->hpc_ops->green_led_off(pslot);   
+		wait_for_ctrl_irq (ctrl);
+	}
+
+	if (ATTN_LED(ctrl->ctrlcap)) { 
+		if (pslot->hpc_ops->set_attention_status(pslot, 1)) {   
+			err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
+			up(&ctrl->crit_sect);
+			return;
+		}
+		wait_for_ctrl_irq (ctrl);
+	}
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+}
+
+/**
+ * board_added - Called after a board has been added to the system.
+ *
+ * Turns power on for the board
+ * Configures board
+ *
+ */
+static u32 board_added(struct pci_func * func, struct controller * ctrl)
+{
+	u8 hp_slot;
+	int index;
+	u32 temp_register = 0xFFFFFFFF;
+	u32 rc = 0;
+	struct pci_func *new_func = NULL;
+	struct slot *p_slot;
+	struct resource_lists res_lists;
+
+	p_slot = pciehp_find_slot(ctrl, func->device);
+	hp_slot = func->device - ctrl->slot_device_offset;
+
+	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
+
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	if (POWER_CTRL(ctrl->ctrlcap)) {
+		/* Power on slot */
+		rc = p_slot->hpc_ops->power_on_slot(p_slot);
+		if (rc) {
+			up(&ctrl->crit_sect);
+			return -1;
+		}
+
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+	}
+	
+	if (PWR_LED(ctrl->ctrlcap)) {
+		p_slot->hpc_ops->green_led_blink(p_slot);
+			
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+	}
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	/* Wait for ~1 second */
+	dbg("%s: before long_delay\n", __FUNCTION__);
+	wait_for_ctrl_irq (ctrl);
+	dbg("%s: afterlong_delay\n", __FUNCTION__);
+
+	/*  Check link training status */
+	rc = p_slot->hpc_ops->check_lnk_status(ctrl);  
+	if (rc) {
+		err("%s: Failed to check link status\n", __FUNCTION__);
+		set_slot_off(ctrl, p_slot);
+		return rc;
+	}
+
+	dbg("%s: func status = %x\n", __FUNCTION__, func->status);
+
+	/* Check for a power fault */
+	if (func->status == 0xFF) {
+		/* power fault occurred, but it was benign */
+		temp_register = 0xFFFFFFFF;
+		dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
+		rc = POWER_FAILURE;
+		func->status = 0;
+	} else {
+		/* Get vendor/device ID u32 */
+		rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), 
+			PCI_VENDOR_ID, &temp_register);
+		dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc);
+		dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register);
+
+		if (rc != 0) {
+			/* Something's wrong here */
+			temp_register = 0xFFFFFFFF;
+			dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register);
+		}
+		/* Preset return code.  It will be changed later if things go okay. */
+		rc = NO_ADAPTER_PRESENT;
+	}
+
+	/* All F's is an empty slot or an invalid board */
+	if (temp_register != 0xFFFFFFFF) {	  /* Check for a board in the slot */
+		res_lists.io_head = ctrl->io_head;
+		res_lists.mem_head = ctrl->mem_head;
+		res_lists.p_mem_head = ctrl->p_mem_head;
+		res_lists.bus_head = ctrl->bus_head;
+		res_lists.irqs = NULL;
+
+		rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0);
+		dbg("%s: back from configure_new_device\n", __FUNCTION__);
+
+		ctrl->io_head = res_lists.io_head;
+		ctrl->mem_head = res_lists.mem_head;
+		ctrl->p_mem_head = res_lists.p_mem_head;
+		ctrl->bus_head = res_lists.bus_head;
+
+		pciehp_resource_sort_and_combine(&(ctrl->mem_head));
+		pciehp_resource_sort_and_combine(&(ctrl->p_mem_head));
+		pciehp_resource_sort_and_combine(&(ctrl->io_head));
+		pciehp_resource_sort_and_combine(&(ctrl->bus_head));
+
+		if (rc) {
+			set_slot_off(ctrl, p_slot);
+			return rc;
+		}
+		pciehp_save_slot_config(ctrl, func);
+
+		func->status = 0;
+		func->switch_save = 0x10;
+		func->is_a_board = 0x01;
+
+		/* next, we will instantiate the linux pci_dev structures 
+		 * (with appropriate driver notification, if already present) 
+		 */
+		index = 0;
+		do {
+			new_func = pciehp_slot_find(ctrl->slot_bus, func->device, index++);
+			if (new_func && !new_func->pci_dev) {
+				dbg("%s:call pci_hp_configure_dev, func %x\n", 
+					__FUNCTION__, index);
+				pciehp_configure_device(ctrl, new_func);
+			}
+		} while (new_func);
+
+ 		/* 
+ 		 * Some PCI Express root ports require fixup after hot-plug operation.
+ 		 */
+ 		if (pcie_mch_quirk)
+ 			pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
+ 
+  		if (PWR_LED(ctrl->ctrlcap)) {
+  			/* Wait for exclusive access to hardware */
+  			down(&ctrl->crit_sect);
+   
+  			p_slot->hpc_ops->green_led_on(p_slot);
+  
+  			/* Wait for the command to complete */
+  			wait_for_ctrl_irq (ctrl);
+  	
+  			/* Done with exclusive hardware access */
+  			up(&ctrl->crit_sect);
+  		}
+	} else {
+		set_slot_off(ctrl, p_slot);
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * remove_board - Turns off slot and LED's
+ *
+ */
+static u32 remove_board(struct pci_func *func, struct controller *ctrl)
+{
+	int index;
+	u8 skip = 0;
+	u8 device;
+	u8 hp_slot;
+	u32 rc;
+	struct resource_lists res_lists;
+	struct pci_func *temp_func;
+	struct slot *p_slot;
+
+	if (func == NULL)
+		return 1;
+
+	if (pciehp_unconfigure_device(func))
+		return 1;
+
+	device = func->device;
+
+	hp_slot = func->device - ctrl->slot_device_offset;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+
+	if ((ctrl->add_support) &&
+		!(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) {
+		/* Here we check to see if we've saved any of the board's
+		 * resources already.  If so, we'll skip the attempt to
+		 * determine what's being used.
+		 */
+		index = 0;
+
+		temp_func = func;
+
+		while ((temp_func = pciehp_slot_find(temp_func->bus, temp_func->device, index++))) {
+			if (temp_func->bus_head || temp_func->mem_head
+			    || temp_func->p_mem_head || temp_func->io_head) {
+				skip = 1;
+				break;
+			}
+		}
+
+		if (!skip)
+			rc = pciehp_save_used_resources(ctrl, func, DISABLE_CARD);
+	}
+	/* Change status to shutdown */
+	if (func->is_a_board)
+		func->status = 0x01;
+	func->configured = 0;
+
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	if (POWER_CTRL(ctrl->ctrlcap)) {
+		/* power off slot */
+		rc = p_slot->hpc_ops->power_off_slot(p_slot);
+		if (rc) {
+			err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+			up(&ctrl->crit_sect);
+			return rc;
+		}
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+	}
+
+	if (PWR_LED(ctrl->ctrlcap)) {
+		/* turn off Green LED */
+		p_slot->hpc_ops->green_led_off(p_slot);
+	
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+	}
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	if (ctrl->add_support) {
+		while (func) {
+			res_lists.io_head = ctrl->io_head;
+			res_lists.mem_head = ctrl->mem_head;
+			res_lists.p_mem_head = ctrl->p_mem_head;
+			res_lists.bus_head = ctrl->bus_head;
+
+			dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", 
+				func->bus, func->device, func->function);
+
+			pciehp_return_board_resources(func, &res_lists);
+
+			ctrl->io_head = res_lists.io_head;
+			ctrl->mem_head = res_lists.mem_head;
+			ctrl->p_mem_head = res_lists.p_mem_head;
+			ctrl->bus_head = res_lists.bus_head;
+
+			pciehp_resource_sort_and_combine(&(ctrl->mem_head));
+			pciehp_resource_sort_and_combine(&(ctrl->p_mem_head));
+			pciehp_resource_sort_and_combine(&(ctrl->io_head));
+			pciehp_resource_sort_and_combine(&(ctrl->bus_head));
+
+			if (is_bridge(func)) {
+				dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
+					ctrl->seg, func->bus, func->device, func->function);
+				bridge_slot_remove(func);
+			} else {
+				dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
+					ctrl->seg, func->bus, func->device, func->function);
+				slot_remove(func);
+			}
+
+			func = pciehp_slot_find(ctrl->slot_bus, device, 0);
+		}
+
+		/* Setup slot structure with entry for empty slot */
+		func = pciehp_slot_create(ctrl->slot_bus);
+
+		if (func == NULL) {
+			return 1;
+		}
+
+		func->bus = ctrl->slot_bus;
+		func->device = device;
+		func->function = 0;
+		func->configured = 0;
+		func->switch_save = 0x10;
+		func->is_a_board = 0;
+	}
+
+	return 0;
+}
+
+
+static void pushbutton_helper_thread(unsigned long data)
+{
+	pushbutton_pending = data;
+
+	up(&event_semaphore);
+}
+
+/**
+ * pciehp_pushbutton_thread
+ *
+ * Scheduled procedure to handle blocking stuff for the pushbuttons
+ * Handles all pending events and exits.
+ *
+ */
+static void pciehp_pushbutton_thread(unsigned long slot)
+{
+	struct slot *p_slot = (struct slot *) slot;
+	u8 getstatus;
+	
+	pushbutton_pending = 0;
+
+	if (!p_slot) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return;
+	}
+
+	p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (getstatus) {
+		p_slot->state = POWEROFF_STATE;
+		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		pciehp_disable_slot(p_slot);
+		p_slot->state = STATIC_STATE;
+	} else {
+		p_slot->state = POWERON_STATE;
+		dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
+			/* Wait for exclusive access to hardware */
+			down(&p_slot->ctrl->crit_sect);
+
+			p_slot->hpc_ops->green_led_off(p_slot);
+
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot->ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&p_slot->ctrl->crit_sect);
+		}
+		p_slot->state = STATIC_STATE;
+	}
+
+	return;
+}
+
+/**
+ * pciehp_surprise_rm_thread
+ *
+ * Scheduled procedure to handle blocking stuff for the surprise removal
+ * Handles all pending events and exits.
+ *
+ */
+static void pciehp_surprise_rm_thread(unsigned long slot)
+{
+	struct slot *p_slot = (struct slot *) slot;
+	u8 getstatus;
+	
+	surprise_rm_pending = 0;
+
+	if (!p_slot) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return;
+	}
+
+	p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (!getstatus) {
+		p_slot->state = POWEROFF_STATE;
+		dbg("In removing board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		pciehp_disable_slot(p_slot);
+		p_slot->state = STATIC_STATE;
+	} else {
+		p_slot->state = POWERON_STATE;
+		dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
+			/* Wait for exclusive access to hardware */
+			down(&p_slot->ctrl->crit_sect);
+
+			p_slot->hpc_ops->green_led_off(p_slot);
+
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot->ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&p_slot->ctrl->crit_sect);
+		}
+		p_slot->state = STATIC_STATE;
+	}
+
+	return;
+}
+
+
+
+/* this is the main worker thread */
+static int event_thread(void* data)
+{
+	struct controller *ctrl;
+	lock_kernel();
+	daemonize("pciehpd_event");
+
+	unlock_kernel();
+
+	while (1) {
+		dbg("!!!!event_thread sleeping\n");
+		down_interruptible (&event_semaphore);
+		dbg("event_thread woken finished = %d\n", event_finished);
+		if (event_finished || signal_pending(current))
+			break;
+		/* Do stuff here */
+		if (pushbutton_pending)
+			pciehp_pushbutton_thread(pushbutton_pending);
+		else if (surprise_rm_pending)
+			pciehp_surprise_rm_thread(surprise_rm_pending);
+		else
+			for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
+				interrupt_event_handler(ctrl);
+	}
+	dbg("event_thread signals exit\n");
+	up(&event_exit);
+	return 0;
+}
+
+int pciehp_event_start_thread(void)
+{
+	int pid;
+
+	/* initialize our semaphores */
+	init_MUTEX_LOCKED(&event_exit);
+	event_finished=0;
+
+	init_MUTEX_LOCKED(&event_semaphore);
+	pid = kernel_thread(event_thread, NULL, 0);
+
+	if (pid < 0) {
+		err ("Can't start up our event thread\n");
+		return -1;
+	}
+	dbg("Our event thread pid = %d\n", pid);
+	return 0;
+}
+
+
+void pciehp_event_stop_thread(void)
+{
+	event_finished = 1;
+	dbg("event_thread finish command given\n");
+	up(&event_semaphore);
+	dbg("wait for event_thread to exit\n");
+	down(&event_exit);
+}
+
+
+static int update_slot_info(struct slot *slot)
+{
+	struct hotplug_slot_info *info;
+	/* char buffer[SLOT_NAME_SIZE]; */
+	int result;
+
+	info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	/* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */
+
+	slot->hpc_ops->get_power_status(slot, &(info->power_status));
+	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
+	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
+	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
+
+	/* result = pci_hp_change_slot_info(buffer, info); */
+	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
+	kfree (info);
+	return result;
+}
+
+static void interrupt_event_handler(struct controller *ctrl)
+{
+	int loop = 0;
+	int change = 1;
+	struct pci_func *func;
+	u8 hp_slot;
+	u8 getstatus;
+	struct slot *p_slot;
+
+	while (change) {
+		change = 0;
+
+		for (loop = 0; loop < 10; loop++) {
+			if (ctrl->event_queue[loop].event_type != 0) {
+				hp_slot = ctrl->event_queue[loop].hp_slot;
+
+				func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+				p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+				dbg("hp_slot %d, func %p, p_slot %p\n", hp_slot, func, p_slot);
+
+				if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
+					dbg("button cancel\n");
+					del_timer(&p_slot->task_event);
+
+					switch (p_slot->state) {
+					case BLINKINGOFF_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+						
+						if (PWR_LED(ctrl->ctrlcap)) {
+							p_slot->hpc_ops->green_led_on(p_slot);
+							/* Wait for the command to complete */
+							wait_for_ctrl_irq (ctrl);
+						}
+						if (ATTN_LED(ctrl->ctrlcap)) {
+							p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+							/* Wait for the command to complete */
+							wait_for_ctrl_irq (ctrl);
+						}
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+						break;
+					case BLINKINGON_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+
+						if (PWR_LED(ctrl->ctrlcap)) {
+							p_slot->hpc_ops->green_led_off(p_slot);
+							/* Wait for the command to complete */
+							wait_for_ctrl_irq (ctrl);
+						}
+						if (ATTN_LED(ctrl->ctrlcap)){
+							p_slot->hpc_ops->set_attention_status(p_slot, 0);
+							/* Wait for the command to complete */
+							wait_for_ctrl_irq (ctrl);
+						}
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+
+						break;
+					default:
+						warn("Not a valid state\n");
+						return;
+					}
+					info(msg_button_cancel, p_slot->number);
+					p_slot->state = STATIC_STATE;
+				}
+				/* ***********Button Pressed (No action on 1st press...) */
+				else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
+					
+					if (ATTN_BUTTN(ctrl->ctrlcap)) {
+						dbg("Button pressed\n");
+						p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+						if (getstatus) {
+							/* slot is on */
+							dbg("slot is on\n");
+							p_slot->state = BLINKINGOFF_STATE;
+							info(msg_button_off, p_slot->number);
+						} else {
+							/* slot is off */
+							dbg("slot is off\n");
+							p_slot->state = BLINKINGON_STATE;
+							info(msg_button_on, p_slot->number);
+						}
+
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+
+						/* blink green LED and turn off amber */
+						if (PWR_LED(ctrl->ctrlcap)) {
+							p_slot->hpc_ops->green_led_blink(p_slot);
+							/* Wait for the command to complete */
+							wait_for_ctrl_irq (ctrl);
+						}
+
+						if (ATTN_LED(ctrl->ctrlcap)) {
+							p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+							/* Wait for the command to complete */
+							wait_for_ctrl_irq (ctrl);
+						}
+
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+
+						init_timer(&p_slot->task_event);
+						p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
+						p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
+						p_slot->task_event.data = (unsigned long) p_slot;
+
+						dbg("add_timer p_slot = %p\n", (void *) p_slot);
+						add_timer(&p_slot->task_event);
+					}
+				}
+				/***********POWER FAULT********************/
+				else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
+					if (POWER_CTRL(ctrl->ctrlcap)) {
+						dbg("power fault\n");
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+
+						if (ATTN_LED(ctrl->ctrlcap)) {
+							p_slot->hpc_ops->set_attention_status(p_slot, 1);
+							wait_for_ctrl_irq (ctrl);
+						}
+
+						if (PWR_LED(ctrl->ctrlcap)) {
+							p_slot->hpc_ops->green_led_off(p_slot);
+							wait_for_ctrl_irq (ctrl);
+						}
+
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+					}
+				}
+				/***********SURPRISE REMOVAL********************/
+				else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || 
+					(ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
+					if (HP_SUPR_RM(ctrl->ctrlcap)) {
+						dbg("Surprise Removal\n");
+						if (p_slot) {
+							surprise_rm_pending = (unsigned long) p_slot;
+							up(&event_semaphore);
+							update_slot_info(p_slot);
+						}
+					}
+				} else {
+					/* refresh notification */
+					if (p_slot)
+						update_slot_info(p_slot);
+				}
+
+				ctrl->event_queue[loop].event_type = 0;
+
+				change = 1;
+			}
+		}		/* End of FOR loop */
+	}
+}
+
+
+int pciehp_enable_slot(struct slot *p_slot)
+{
+	u8 getstatus = 0;
+	int rc;
+	struct pci_func *func;
+
+	func = pciehp_slot_find(p_slot->bus, p_slot->device, 0);
+	if (!func) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return 1;
+	}
+
+	/* Check to see if (latch closed, card present, power off) */
+	down(&p_slot->ctrl->crit_sect);
+
+	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (rc || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return 1;
+	}
+	if (MRL_SENS(p_slot->ctrl->ctrlcap)) {	
+		rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+		if (rc || getstatus) {
+			info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+			up(&p_slot->ctrl->crit_sect);
+			return 1;
+		}
+	}
+	
+	if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {	
+		rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+		if (rc || getstatus) {
+			info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
+			up(&p_slot->ctrl->crit_sect);
+			return 1;
+		}
+	}
+	up(&p_slot->ctrl->crit_sect);
+
+	slot_remove(func);
+
+	func = pciehp_slot_create(p_slot->bus);
+	if (func == NULL)
+		return 1;
+
+	func->bus = p_slot->bus;
+	func->device = p_slot->device;
+	func->function = 0;
+	func->configured = 0;
+	func->is_a_board = 1;
+
+	/* We have to save the presence info for these slots */
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	func->switch_save = !getstatus? 0x10:0;
+
+	rc = board_added(func, p_slot->ctrl);
+	if (rc) {
+		if (is_bridge(func))
+			bridge_slot_remove(func);
+		else
+			slot_remove(func);
+
+		/* Setup slot structure with entry for empty slot */
+		func = pciehp_slot_create(p_slot->bus);
+		if (func == NULL)
+			return 1;	/* Out of memory */
+
+		func->bus = p_slot->bus;
+		func->device = p_slot->device;
+		func->function = 0;
+		func->configured = 0;
+		func->is_a_board = 1;
+
+		/* We have to save the presence info for these slots */
+		p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+		func->switch_save = !getstatus? 0x10:0;
+	}
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return rc;
+}
+
+
+int pciehp_disable_slot(struct slot *p_slot)
+{
+	u8 class_code, header_type, BCR;
+	u8 index = 0;
+	u8 getstatus = 0;
+	u32 rc = 0;
+	int ret = 0;
+	unsigned int devfn;
+	struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate;
+	struct pci_func *func;
+
+	if (!p_slot->ctrl)
+		return 1;
+
+	/* Check to see if (latch closed, card present, power on) */
+	down(&p_slot->ctrl->crit_sect);
+
+	if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {	
+		ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+		if (ret || !getstatus) {
+			info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+			up(&p_slot->ctrl->crit_sect);
+			return 1;
+		}
+	}
+
+	if (MRL_SENS(p_slot->ctrl->ctrlcap)) {	
+		ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+		if (ret || getstatus) {
+			info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+			up(&p_slot->ctrl->crit_sect);
+			return 1;
+		}
+	}
+
+	if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {	
+		ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+		if (ret || !getstatus) {
+			info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
+			up(&p_slot->ctrl->crit_sect);
+			return 1;
+		}
+	}
+
+	up(&p_slot->ctrl->crit_sect);
+
+	func = pciehp_slot_find(p_slot->bus, p_slot->device, index++);
+
+	/* Make sure there are no video controllers here
+	 * for all func of p_slot
+	 */
+	while (func && !rc) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		/* Check the Class Code */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+		if (rc)
+			return rc;
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY) {
+			/* Display/Video adapter (not supported) */
+			rc = REMOVE_NOT_SUPPORTED;
+		} else {
+			/* See if it's a bridge */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+			if (rc)
+				return rc;
+
+			/* If it's a bridge, check the VGA Enable bit */
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
+				if (rc)
+					return rc;
+
+				/* If the VGA Enable bit is set, remove isn't supported */
+				if (BCR & PCI_BRIDGE_CTL_VGA) {
+					rc = REMOVE_NOT_SUPPORTED;
+				}
+			}
+		}
+
+		func = pciehp_slot_find(p_slot->bus, p_slot->device, index++);
+	}
+
+	func = pciehp_slot_find(p_slot->bus, p_slot->device, 0);
+	if ((func != NULL) && !rc) {
+		rc = remove_board(func, p_slot->ctrl);
+	} else if (!rc)
+		rc = 1;
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return rc;
+}
+
+
+/**
+ * configure_new_device - Configures the PCI header information of one board.
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Returns 0 if success
+ *
+ */
+static u32 configure_new_device(struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev)
+{
+	u8 temp_byte, function, max_functions, stop_it;
+	int rc;
+	u32 ID;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	int index;
+
+	new_slot = func;
+
+	dbg("%s\n", __FUNCTION__);
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+
+	/* Check for Multi-function device */
+	rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte);
+	if (rc) {
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if (temp_byte & 0x80)	/* Multi-function device */
+		max_functions = 8;
+	else
+		max_functions = 1;
+
+	function = 0;
+
+	do {
+		rc = configure_new_function(ctrl, new_slot, behind_bridge,
+					resources, bridge_bus, bridge_dev);
+
+		if (rc) {
+			dbg("configure_new_function failed: %d\n", rc);
+			index = 0;
+
+			while (new_slot) {
+				new_slot = pciehp_slot_find(new_slot->bus,
+						new_slot->device, index++);
+
+				if (new_slot)
+					pciehp_return_board_resources(new_slot,
+						resources);
+			}
+
+			return rc;
+		}
+
+		function++;
+
+		stop_it = 0;
+
+		/*  The following loop skips to the next present function
+		 *  and creates a board structure
+		 */
+
+		while ((function < max_functions) && (!stop_it)) {
+			pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
+
+			if (ID == 0xFFFFFFFF) {	  /* There's nothing there. */
+				function++;
+			} else {  /* There's something there */
+				/* Setup slot structure. */
+				new_slot = pciehp_slot_create(func->bus);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					return 1;
+				}
+
+				new_slot->bus = func->bus;
+				new_slot->device = func->device;
+				new_slot->function = function;
+				new_slot->is_a_board = 1;
+				new_slot->status = 0;
+
+				stop_it++;
+			}
+		}
+
+	} while (function < max_functions);
+	dbg("returning from %s\n", __FUNCTION__);
+
+	return 0;
+}
+
+/*
+ * Configuration logic that involves the hotplug data structures and 
+ * their bookkeeping
+ */
+
+/**
+ * configure_bridge: fill bridge's registers, either configure or disable it.
+ */
+static int
+configure_bridge(struct pci_bus *pci_bus, unsigned int devfn,
+			struct pci_resource *mem_node,
+			struct pci_resource **hold_mem_node,
+			int base_addr, int limit_addr)
+{
+	u16 temp_word;
+	u32 rc;
+
+	if (mem_node) {
+		memcpy(*hold_mem_node, mem_node, sizeof(struct pci_resource));
+		mem_node->next = NULL;
+
+		/* set Mem base and Limit registers */
+		RES_CHECK(mem_node->base, 16);
+		temp_word = (u16)(mem_node->base >> 16);
+		rc = pci_bus_write_config_word(pci_bus, devfn, base_addr, temp_word);
+
+		RES_CHECK(mem_node->base + mem_node->length - 1, 16);
+		temp_word = (u16)((mem_node->base + mem_node->length - 1) >> 16);
+		rc = pci_bus_write_config_word(pci_bus, devfn, limit_addr, temp_word);
+	} else {
+		temp_word = 0xFFFF;
+		rc = pci_bus_write_config_word(pci_bus, devfn, base_addr, temp_word);
+
+		temp_word = 0x0000;
+		rc = pci_bus_write_config_word(pci_bus, devfn, limit_addr, temp_word);
+
+		kfree(*hold_mem_node);
+		*hold_mem_node = NULL;
+	}
+	return rc;
+}
+
+static int
+configure_new_bridge(struct controller *ctrl, struct pci_func *func,
+		u8 behind_bridge, struct resource_lists *resources,
+		struct pci_bus *pci_bus)
+{
+	int cloop;
+	u8 temp_byte;
+	u8 device;
+	u16 temp_word;
+	u32 rc;
+	u32 ID;
+	unsigned int devfn;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_resource *hold_mem_node;
+	struct pci_resource *hold_p_mem_node;
+	struct pci_resource *hold_IO_node;
+	struct pci_resource *hold_bus_node;
+	struct irq_mapping irqs;
+	struct pci_func *new_slot;
+	struct resource_lists temp_resources;
+
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	/* set Primary bus */
+	dbg("set Primary bus = 0x%x\n", func->bus);
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
+	if (rc)
+		return rc;
+
+	/* find range of busses to use */
+	bus_node = get_max_resource(&resources->bus_head, 1L);
+
+	/* If we don't have any busses to allocate, we can't continue */
+	if (!bus_node) {
+		err("Got NO bus resource to use\n");
+		return -ENOMEM;
+	}
+	dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length);
+
+	/* set Secondary bus */
+	temp_byte = (u8)bus_node->base;
+	dbg("set Secondary bus = 0x%x\n", temp_byte);
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
+	if (rc)
+		return rc;
+
+	/* set subordinate bus */
+	temp_byte = (u8)(bus_node->base + bus_node->length - 1);
+	dbg("set subordinate bus = 0x%x\n", temp_byte);
+	rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+	if (rc)
+		return rc;
+
+	/* Set HP parameters (Cache Line Size, Latency Timer) */
+	rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+	if (rc)
+		return rc;
+
+	/* Setup the IO, memory, and prefetchable windows */
+
+	io_node = get_max_resource(&(resources->io_head), 0x1000L);
+	if (io_node) {
+		dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base,
+				io_node->length, io_node->next);
+	}
+
+	mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+	if (mem_node) {
+		dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base,
+				mem_node->length, mem_node->next);
+	}
+
+	if (resources->p_mem_head)
+		p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L);
+	else {
+		/*
+		 * In some platform implementation, MEM and PMEM are not
+		 *  distinguished, and hence ACPI _CRS has only MEM entries
+		 *  for both MEM and PMEM.
+		 */
+		dbg("using MEM for PMEM\n");
+		p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+	}
+	if (p_mem_node) {
+		dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base,
+				p_mem_node->length, p_mem_node->next);
+	}
+
+	/* set up the IRQ info */
+	if (!resources->irqs) {
+		irqs.barber_pole = 0;
+		irqs.interrupt[0] = 0;
+		irqs.interrupt[1] = 0;
+		irqs.interrupt[2] = 0;
+		irqs.interrupt[3] = 0;
+		irqs.valid_INT = 0;
+	} else {
+		irqs.barber_pole = resources->irqs->barber_pole;
+		irqs.interrupt[0] = resources->irqs->interrupt[0];
+		irqs.interrupt[1] = resources->irqs->interrupt[1];
+		irqs.interrupt[2] = resources->irqs->interrupt[2];
+		irqs.interrupt[3] = resources->irqs->interrupt[3];
+		irqs.valid_INT = resources->irqs->valid_INT;
+	}
+
+	/* set up resource lists that are now aligned on top and bottom
+	 * for anything behind the bridge.
+	 */
+	temp_resources.bus_head = bus_node;
+	temp_resources.io_head = io_node;
+	temp_resources.mem_head = mem_node;
+	temp_resources.p_mem_head = p_mem_node;
+	temp_resources.irqs = &irqs;
+
+	/* Make copies of the nodes we are going to pass down so that
+	 * if there is a problem,we can just use these to free resources
+	 */
+	hold_bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+	hold_IO_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+	hold_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+	hold_p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+	if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
+		kfree(hold_bus_node);
+		kfree(hold_IO_node);
+		kfree(hold_mem_node);
+		kfree(hold_p_mem_node);
+
+		return 1;
+	}
+
+	memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
+
+	bus_node->base += 1;
+	bus_node->length -= 1;
+	bus_node->next = NULL;
+
+	/* If we have IO resources copy them and fill in the bridge's
+	 * IO range registers
+	 */
+	if (io_node) {
+		memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
+		io_node->next = NULL;
+
+		/* set IO base and Limit registers */
+		RES_CHECK(io_node->base, 8);
+		temp_byte = (u8)(io_node->base >> 8);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+		RES_CHECK(io_node->base + io_node->length - 1, 8);
+		temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+	} else {
+		kfree(hold_IO_node);
+		hold_IO_node = NULL;
+	}
+
+	/* If we have memory resources copy them and fill in the bridge's
+	 * memory range registers.  Otherwise, fill in the range
+	 * registers with values that disable them.
+	 */
+	rc = configure_bridge(pci_bus, devfn, mem_node, &hold_mem_node,
+				PCI_MEMORY_BASE, PCI_MEMORY_LIMIT);
+
+	/* If we have prefetchable memory resources copy them and 
+	 * fill in the bridge's memory range registers.  Otherwise,
+	 * fill in the range registers with values that disable them.
+	 */
+	rc = configure_bridge(pci_bus, devfn, p_mem_node, &hold_p_mem_node,
+				PCI_PREF_MEMORY_BASE, PCI_PREF_MEMORY_LIMIT);
+
+	/* Adjust this to compensate for extra adjustment in first loop */
+	irqs.barber_pole--;
+
+	rc = 0;
+
+	/* Here we actually find the devices and configure them */
+	for (device = 0; (device <= 0x1F) && !rc; device++) {
+		irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
+
+		ID = 0xFFFFFFFF;
+		pci_bus->number = hold_bus_node->base;
+		pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
+		pci_bus->number = func->bus;
+
+		if (ID != 0xFFFFFFFF) {	  /*  device Present */
+			/* Setup slot structure. */
+			new_slot = pciehp_slot_create(hold_bus_node->base);
+
+			if (new_slot == NULL) {
+				/* Out of memory */
+				rc = -ENOMEM;
+				continue;
+			}
+
+			new_slot->bus = hold_bus_node->base;
+			new_slot->device = device;
+			new_slot->function = 0;
+			new_slot->is_a_board = 1;
+			new_slot->status = 0;
+
+			rc = configure_new_device(ctrl, new_slot, 1,
+					&temp_resources, func->bus,
+					func->device);
+			dbg("configure_new_device rc=0x%x\n",rc);
+		}	/* End of IF (device in slot?) */
+	}		/* End of FOR loop */
+
+	if (rc) {
+		pciehp_destroy_resource_list(&temp_resources);
+
+		return_resource(&(resources->bus_head), hold_bus_node);
+		return_resource(&(resources->io_head), hold_IO_node);
+		return_resource(&(resources->mem_head), hold_mem_node);
+		return_resource(&(resources->p_mem_head), hold_p_mem_node);
+		return(rc);
+	}
+
+	/* save the interrupt routing information */
+	if (resources->irqs) {
+		resources->irqs->interrupt[0] = irqs.interrupt[0];
+		resources->irqs->interrupt[1] = irqs.interrupt[1];
+		resources->irqs->interrupt[2] = irqs.interrupt[2];
+		resources->irqs->interrupt[3] = irqs.interrupt[3];
+		resources->irqs->valid_INT = irqs.valid_INT;
+	} else if (!behind_bridge) {
+		/* We need to hook up the interrupts here */
+		for (cloop = 0; cloop < 4; cloop++) {
+			if (irqs.valid_INT & (0x01 << cloop)) {
+				rc = pciehp_set_irq(func->bus, func->device,
+							0x0A + cloop, irqs.interrupt[cloop]);
+				if (rc) {
+					pciehp_destroy_resource_list (&temp_resources);
+					return_resource(&(resources->bus_head), hold_bus_node);
+					return_resource(&(resources->io_head), hold_IO_node);
+					return_resource(&(resources->mem_head), hold_mem_node);
+					return_resource(&(resources->p_mem_head), hold_p_mem_node);
+					return rc;
+				}
+			}
+		}	/* end of for loop */
+	}
+
+	/* Return unused bus resources
+	 * First use the temporary node to store information for the board
+	 */
+	if (hold_bus_node && bus_node && temp_resources.bus_head) {
+		hold_bus_node->length = bus_node->base - hold_bus_node->base;
+
+		hold_bus_node->next = func->bus_head;
+		func->bus_head = hold_bus_node;
+
+		temp_byte = (u8)(temp_resources.bus_head->base - 1);
+
+		/* set subordinate bus */
+		dbg("re-set subordinate bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+
+		if (temp_resources.bus_head->length == 0) {
+			kfree(temp_resources.bus_head);
+			temp_resources.bus_head = NULL;
+		} else {
+			dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
+				func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length);
+			return_resource(&(resources->bus_head), temp_resources.bus_head);
+		}
+	}
+
+	/* If we have IO space available and there is some left,
+	 * return the unused portion
+	 */
+	if (hold_IO_node && temp_resources.io_head) {
+		io_node = do_pre_bridge_resource_split(&(temp_resources.io_head),
+							&hold_IO_node, 0x1000);
+
+		/* Check if we were able to split something off */
+		if (io_node) {
+			hold_IO_node->base = io_node->base + io_node->length;
+
+			RES_CHECK(hold_IO_node->base, 8);
+			temp_byte = (u8)((hold_IO_node->base) >> 8);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+			return_resource(&(resources->io_head), io_node);
+		}
+
+		io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000);
+
+		/*  Check if we were able to split something off */
+		if (io_node) {
+			/* First use the temporary node to store information for the board */
+			hold_IO_node->length = io_node->base - hold_IO_node->base;
+
+			/* If we used any, add it to the board's list */
+			if (hold_IO_node->length) {
+				hold_IO_node->next = func->io_head;
+				func->io_head = hold_IO_node;
+
+				RES_CHECK(io_node->base - 1, 8);
+				temp_byte = (u8)((io_node->base - 1) >> 8);
+				rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+				return_resource(&(resources->io_head), io_node);
+			} else {
+				/* it doesn't need any IO */
+				temp_byte = 0x00;
+				rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+				return_resource(&(resources->io_head), io_node);
+				kfree(hold_IO_node);
+			}
+		} else {
+			/* it used most of the range */
+			hold_IO_node->next = func->io_head;
+			func->io_head = hold_IO_node;
+		}
+	} else if (hold_IO_node) {
+		/* it used the whole range */
+		hold_IO_node->next = func->io_head;
+		func->io_head = hold_IO_node;
+	}
+
+	/* If we have memory space available and there is some left,
+	 * return the unused portion
+	 */
+	if (hold_mem_node && temp_resources.mem_head) {
+		mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L);
+
+		/* Check if we were able to split something off */
+		if (mem_node) {
+			hold_mem_node->base = mem_node->base + mem_node->length;
+
+			RES_CHECK(hold_mem_node->base, 16);
+			temp_word = (u16)((hold_mem_node->base) >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			return_resource(&(resources->mem_head), mem_node);
+		}
+
+		mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L);
+
+		/* Check if we were able to split something off */
+		if (mem_node) {
+			/* First use the temporary node to store information for the board */
+			hold_mem_node->length = mem_node->base - hold_mem_node->base;
+
+			if (hold_mem_node->length) {
+				hold_mem_node->next = func->mem_head;
+				func->mem_head = hold_mem_node;
+
+				/* configure end address */
+				RES_CHECK(mem_node->base - 1, 16);
+				temp_word = (u16)((mem_node->base - 1) >> 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+				/* Return unused resources to the pool */
+				return_resource(&(resources->mem_head), mem_node);
+			} else {
+				/* it doesn't need any Mem */
+				temp_word = 0x0000;
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+				return_resource(&(resources->mem_head), mem_node);
+				kfree(hold_mem_node);
+			}
+		} else {
+			/* it used most of the range */
+			hold_mem_node->next = func->mem_head;
+			func->mem_head = hold_mem_node;
+		}
+	} else if (hold_mem_node) {
+		/* it used the whole range */
+		hold_mem_node->next = func->mem_head;
+		func->mem_head = hold_mem_node;
+	}
+
+	/* If we have prefetchable memory space available and there is some 
+	 * left at the end, return the unused portion
+	 */
+	if (hold_p_mem_node && temp_resources.p_mem_head) {
+		p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
+								&hold_p_mem_node, 0x100000L);
+
+		/* Check if we were able to split something off */
+		if (p_mem_node) {
+			hold_p_mem_node->base = p_mem_node->base + p_mem_node->length;
+
+			RES_CHECK(hold_p_mem_node->base, 16);
+			temp_word = (u16)((hold_p_mem_node->base) >> 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			return_resource(&(resources->p_mem_head), p_mem_node);
+		}
+
+		p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L);
+
+		/* Check if we were able to split something off */
+		if (p_mem_node) {
+			/* First use the temporary node to store information for the board */
+			hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base;
+
+			/* If we used any, add it to the board's list */
+			if (hold_p_mem_node->length) {
+				hold_p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = hold_p_mem_node;
+
+				RES_CHECK(p_mem_node->base - 1, 16);
+				temp_word = (u16)((p_mem_node->base - 1) >> 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+				return_resource(&(resources->p_mem_head), p_mem_node);
+			} else {
+				/* it doesn't need any PMem */
+				temp_word = 0x0000;
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+				return_resource(&(resources->p_mem_head), p_mem_node);
+				kfree(hold_p_mem_node);
+			}
+		} else {
+			/* it used the most of the range */
+			hold_p_mem_node->next = func->p_mem_head;
+			func->p_mem_head = hold_p_mem_node;
+		}
+	} else if (hold_p_mem_node) {
+		/* it used the whole range */
+		hold_p_mem_node->next = func->p_mem_head;
+		func->p_mem_head = hold_p_mem_node;
+	}
+
+	/* We should be configuring an IRQ and the bridge's base address
+	 * registers if it needs them.  Although we have never seen such
+	 * a device
+	 */
+
+	pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+
+	dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function);
+
+	return rc;
+}
+
+/**
+ * configure_new_function - Configures the PCI header information of one device
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Calls itself recursively for bridged devices.
+ * Returns 0 if success
+ *
+ */
+static int
+configure_new_function(struct controller *ctrl, struct pci_func *func,
+		u8 behind_bridge, struct resource_lists *resources,
+		u8 bridge_bus, u8 bridge_dev)
+{
+	int cloop;
+	u8 temp_byte;
+	u8 class_code;
+	u16 temp_word;
+	u32 rc;
+	u32 temp_register;
+	u32 base;
+	unsigned int devfn;
+	struct pci_resource *mem_node;
+	struct pci_resource *io_node;
+	struct pci_bus lpci_bus, *pci_bus;
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	/* Check for Bridge */
+	rc = pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte);
+	if (rc)
+		return rc;
+	dbg("%s: bus %x dev %x func %x temp_byte = %x\n", __FUNCTION__,
+		func->bus, func->device, func->function, temp_byte);
+
+	if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+		rc = configure_new_bridge(ctrl, func, behind_bridge, resources,
+						pci_bus);
+
+		if (rc)
+			return rc;
+	} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+		/* Standard device */
+		u64	base64;
+		rc = pci_bus_read_config_byte(pci_bus, devfn, 0x0B, &class_code);
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY)
+			return DEVICE_TYPE_NOT_SUPPORTED;
+
+		/* Figure out IO and memory needs */
+		for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
+			temp_register = 0xFFFFFFFF;
+
+			rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+			rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register);
+			dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, 
+				func->bus, func->device, func->function);
+
+			if (!temp_register)
+				continue;
+
+			base64 = 0L;
+			if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) {
+				/* Map IO */
+
+				/* set base = amount of IO space */
+				base = temp_register & 0xFFFFFFFC;
+				base = ~base + 1;
+
+				dbg("NEED IO length(0x%x)\n", base);
+				io_node = get_io_resource(&(resources->io_head),(ulong)base);
+
+				/* allocate the resource to the board */
+				if (io_node) {
+					dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length);
+					base = (u32)io_node->base;
+					io_node->next = func->io_head;
+					func->io_head = io_node;
+				} else {
+					err("Got NO IO resource(length=0x%x)\n", base);
+					return -ENOMEM;
+				}
+			} else {	/* map MEM */
+				int prefetchable = 1;
+				struct pci_resource **res_node = &func->p_mem_head;
+				char *res_type_str = "PMEM";
+				u32	temp_register2;
+
+				if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) {
+					prefetchable = 0;
+					res_node = &func->mem_head;
+					res_type_str++;
+				}
+
+				base = temp_register & 0xFFFFFFF0;
+				base = ~base + 1;
+
+				switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+				case PCI_BASE_ADDRESS_MEM_TYPE_32:
+					dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base);
+
+					if (prefetchable && resources->p_mem_head)
+						mem_node=get_resource(&(resources->p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node = get_resource(&(resources->mem_head), (ulong)base);
+					}
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base = (u32)mem_node->base; 
+						mem_node->next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, 
+							mem_node->length);
+					} else {
+						err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				case PCI_BASE_ADDRESS_MEM_TYPE_64:
+					rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+					dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, 
+						temp_register, base);
+
+					if (prefetchable && resources->p_mem_head)
+						mem_node = get_resource(&(resources->p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node = get_resource(&(resources->mem_head), (ulong)base);
+					}
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base64 = mem_node->base; 
+						mem_node->next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), 
+							(u32)base64, mem_node->length);
+					} else {
+						err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				default:
+					dbg("reserved BAR type=0x%x\n", temp_register);
+					break;
+				}
+
+			}
+
+			if (base64) {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+				cloop += 4;
+				base64 >>= 32;
+
+				if (base64) {
+					dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64);
+					base64 = 0x0L;
+				}
+
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+			} else {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base);
+			}
+		}		/* End of base register loop */
+
+		/* disable ROM base Address */
+		temp_word = 0x00L;
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word);
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+		if (rc)
+			return rc;
+
+		pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+
+		dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, 
+			func->function);
+	}  /* End of Not-A-Bridge else */
+	else {
+		/* It's some strange type of PCI adapter (Cardbus?) */
+		return DEVICE_TYPE_NOT_SUPPORTED;
+	}
+
+	func->configured = 1;
+
+	return 0;
+}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
new file mode 100644
index 0000000..9e70c46
--- /dev/null
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -0,0 +1,1501 @@
+/*
+ * PCI Express PCI Hot Plug Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>,<dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include "../pci.h"
+#include "pciehp.h"
+
+#ifdef DEBUG
+#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
+#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
+#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
+#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
+#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
+#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
+/* Redefine this flagword to set debug level */
+#define DEBUG_LEVEL            DBG_K_STANDARD
+
+#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
+
+#define DBG_PRINT( dbg_flags, args... )              \
+	do {                                             \
+	  if ( DEBUG_LEVEL & ( dbg_flags ) )             \
+	  {                                              \
+	    int len;                                     \
+	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
+		  __FILE__, __LINE__, __FUNCTION__ );    \
+	    sprintf( __dbg_str_buf + len, args );        \
+	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
+	  }                                              \
+	} while (0)
+
+#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
+#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
+#else
+#define DEFINE_DBG_BUFFER
+#define DBG_ENTER_ROUTINE
+#define DBG_LEAVE_ROUTINE
+#endif				/* DEBUG */
+
+struct ctrl_reg {
+	u8 cap_id;
+	u8 nxt_ptr;
+	u16 cap_reg;
+	u32 dev_cap;
+	u16 dev_ctrl;
+	u16 dev_status;
+	u32 lnk_cap;
+	u16 lnk_ctrl;
+	u16 lnk_status;
+	u32 slot_cap;
+	u16 slot_ctrl;
+	u16 slot_status;
+	u16 root_ctrl;
+	u16 rsvp;
+	u32 root_status;
+} __attribute__ ((packed));
+
+/* offsets to the controller registers based on the above structure layout */
+enum ctrl_offsets {
+	PCIECAPID	=	offsetof(struct ctrl_reg, cap_id),
+	NXTCAPPTR	=	offsetof(struct ctrl_reg, nxt_ptr),
+	CAPREG		=	offsetof(struct ctrl_reg, cap_reg),
+	DEVCAP		=	offsetof(struct ctrl_reg, dev_cap),
+	DEVCTRL		=	offsetof(struct ctrl_reg, dev_ctrl),
+	DEVSTATUS	=	offsetof(struct ctrl_reg, dev_status),
+	LNKCAP		=	offsetof(struct ctrl_reg, lnk_cap),
+	LNKCTRL		=	offsetof(struct ctrl_reg, lnk_ctrl),
+	LNKSTATUS	=	offsetof(struct ctrl_reg, lnk_status),
+	SLOTCAP		=	offsetof(struct ctrl_reg, slot_cap),
+	SLOTCTRL	=	offsetof(struct ctrl_reg, slot_ctrl),
+	SLOTSTATUS	=	offsetof(struct ctrl_reg, slot_status),
+	ROOTCTRL	=	offsetof(struct ctrl_reg, root_ctrl),
+	ROOTSTATUS	=	offsetof(struct ctrl_reg, root_status),
+};
+static int pcie_cap_base = 0;		/* Base of the PCI Express capability item structure */ 
+
+#define PCIE_CAP_ID	( pcie_cap_base + PCIECAPID )
+#define NXT_CAP_PTR	( pcie_cap_base + NXTCAPPTR )
+#define CAP_REG		( pcie_cap_base + CAPREG )
+#define DEV_CAP		( pcie_cap_base + DEVCAP )
+#define DEV_CTRL	( pcie_cap_base + DEVCTRL )
+#define DEV_STATUS	( pcie_cap_base + DEVSTATUS )
+#define LNK_CAP		( pcie_cap_base + LNKCAP )
+#define LNK_CTRL	( pcie_cap_base + LNKCTRL )
+#define LNK_STATUS	( pcie_cap_base + LNKSTATUS )
+#define SLOT_CAP	( pcie_cap_base + SLOTCAP )
+#define SLOT_CTRL	( pcie_cap_base + SLOTCTRL )
+#define SLOT_STATUS	( pcie_cap_base + SLOTSTATUS )
+#define ROOT_CTRL	( pcie_cap_base + ROOTCTRL )
+#define ROOT_STATUS	( pcie_cap_base + ROOTSTATUS )
+
+#define hp_register_read_word(pdev, reg , value)		\
+	pci_read_config_word(pdev, reg, &value)
+
+#define hp_register_read_dword(pdev, reg , value)		\
+	pci_read_config_dword(pdev, reg, &value)
+ 
+#define hp_register_write_word(pdev, reg , value)		\
+	pci_write_config_word(pdev, reg, value)
+
+#define hp_register_dwrite_word(pdev, reg , value)		\
+	pci_write_config_dword(pdev, reg, value)
+
+/* Field definitions in PCI Express Capabilities Register */
+#define CAP_VER			0x000F
+#define DEV_PORT_TYPE		0x00F0
+#define SLOT_IMPL		0x0100
+#define MSG_NUM			0x3E00
+
+/* Device or Port Type */
+#define NAT_ENDPT		0x00
+#define LEG_ENDPT		0x01
+#define ROOT_PORT		0x04
+#define UP_STREAM		0x05
+#define	DN_STREAM		0x06
+#define PCIE_PCI_BRDG		0x07
+#define PCI_PCIE_BRDG		0x10
+
+/* Field definitions in Device Capabilities Register */
+#define DATTN_BUTTN_PRSN	0x1000
+#define DATTN_LED_PRSN		0x2000
+#define DPWR_LED_PRSN		0x4000
+
+/* Field definitions in Link Capabilities Register */
+#define MAX_LNK_SPEED		0x000F
+#define MAX_LNK_WIDTH		0x03F0
+
+/* Link Width Encoding */
+#define LNK_X1		0x01
+#define LNK_X2		0x02
+#define LNK_X4		0x04	
+#define LNK_X8		0x08
+#define LNK_X12		0x0C
+#define LNK_X16		0x10	
+#define LNK_X32		0x20
+
+/*Field definitions of Link Status Register */
+#define LNK_SPEED	0x000F
+#define NEG_LINK_WD	0x03F0
+#define LNK_TRN_ERR	0x0400
+#define	LNK_TRN		0x0800
+#define SLOT_CLK_CONF	0x1000
+
+/* Field definitions in Slot Capabilities Register */
+#define ATTN_BUTTN_PRSN	0x00000001
+#define	PWR_CTRL_PRSN	0x00000002
+#define MRL_SENS_PRSN	0x00000004
+#define ATTN_LED_PRSN	0x00000008
+#define PWR_LED_PRSN	0x00000010
+#define HP_SUPR_RM_SUP	0x00000020
+#define HP_CAP		0x00000040
+#define SLOT_PWR_VALUE	0x000003F8
+#define SLOT_PWR_LIMIT	0x00000C00
+#define PSN		0xFFF80000	/* PSN: Physical Slot Number */
+
+/* Field definitions in Slot Control Register */
+#define ATTN_BUTTN_ENABLE		0x0001
+#define PWR_FAULT_DETECT_ENABLE		0x0002
+#define MRL_DETECT_ENABLE		0x0004
+#define PRSN_DETECT_ENABLE		0x0008
+#define CMD_CMPL_INTR_ENABLE		0x0010
+#define HP_INTR_ENABLE			0x0020
+#define ATTN_LED_CTRL			0x00C0
+#define PWR_LED_CTRL			0x0300
+#define PWR_CTRL			0x0400
+
+/* Attention indicator and Power indicator states */
+#define LED_ON		0x01
+#define LED_BLINK	0x10
+#define LED_OFF		0x11
+
+/* Power Control Command */
+#define POWER_ON	0
+#define POWER_OFF	0x0400
+
+/* Field definitions in Slot Status Register */
+#define ATTN_BUTTN_PRESSED	0x0001
+#define PWR_FAULT_DETECTED	0x0002
+#define MRL_SENS_CHANGED	0x0004
+#define PRSN_DETECT_CHANGED	0x0008
+#define CMD_COMPLETED		0x0010
+#define MRL_STATE		0x0020
+#define PRSN_STATE		0x0040
+
+struct php_ctlr_state_s {
+	struct php_ctlr_state_s *pnext;
+	struct pci_dev *pci_dev;
+	unsigned int irq;
+	unsigned long flags;				/* spinlock's */
+	u32 slot_device_offset;
+	u32 num_slots;
+    	struct timer_list	int_poll_timer;		/* Added for poll event */
+	php_intr_callback_t 	attention_button_callback;
+	php_intr_callback_t 	switch_change_callback;
+	php_intr_callback_t 	presence_change_callback;
+	php_intr_callback_t 	power_fault_callback;
+	void 			*callback_instance_id;
+	struct ctrl_reg 	*creg;				/* Ptr to controller register space */
+};
+
+
+static spinlock_t hpc_event_lock;
+
+DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
+static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
+static int ctlr_seq_num = 0;	/* Controller sequence # */
+static spinlock_t list_lock;
+
+static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs);
+
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+
+/* This is the interrupt polling timeout function. */
+static void int_poll_timeout(unsigned long lphp_ctlr)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+
+	DBG_ENTER_ROUTINE
+
+	if ( !php_ctlr ) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+	}
+
+	/* Poll for interrupt events.  regs == NULL => polling */
+	pcie_isr( 0, (void *)php_ctlr, NULL );
+
+	init_timer(&php_ctlr->int_poll_timer);
+
+	if (!pciehp_poll_time)
+		pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+
+	start_int_poll_timer(php_ctlr, pciehp_poll_time);  
+	
+	return;
+}
+
+/* This function starts the interrupt polling timer. */
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+{
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+	}
+
+	if ( ( seconds <= 0 ) || ( seconds > 60 ) )
+        	seconds = 2;            /* Clamp to sane value */
+
+	php_ctlr->int_poll_timer.function = &int_poll_timeout;
+	php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
+	php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
+	add_timer(&php_ctlr->int_poll_timer);
+
+	return;
+}
+
+static int pcie_write_cmd(struct slot *slot, u16 cmd)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	int retval = 0;
+	u16 slot_status;
+
+	DBG_ENTER_ROUTINE 
+	
+	dbg("%s : Enter\n", __FUNCTION__);
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (retval) {
+			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+			return retval;
+		}
+	dbg("%s : hp_register_read_word SLOT_STATUS %x\n", __FUNCTION__, slot_status);
+	
+	if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { 
+		/* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue 
+		   the next command according to spec.  Just print out the error message */
+		dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
+	}
+
+	dbg("%s: Before hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd);
+	retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, cmd | CMD_CMPL_INTR_ENABLE);
+	if (retval) {
+		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s : hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd | CMD_CMPL_INTR_ENABLE);
+	dbg("%s : Exit\n", __FUNCTION__);
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_check_lnk_status(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
+	u16 lnk_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+	
+	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
+	if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || 
+		!(lnk_status & NEG_LINK_WD)) {
+		err("%s : Link Training Error occurs \n", __FUNCTION__);
+		retval = -1;
+		return retval;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_attention_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_ctrl;
+	u8 atten_led_state;
+	int retval = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL, slot_ctrl);
+
+	atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
+
+	switch (atten_led_state) {
+	case 0:
+		*status = 0xFF;	/* Reserved */
+		break;
+	case 1:
+		*status = 1;	/* On */
+		break;
+	case 2:
+		*status = 2;	/* Blink */
+		break;
+	case 3:
+		*status = 0;	/* Off */
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_power_status(struct slot * slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_ctrl;
+	u8 pwr_state;
+	int	retval = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+
+	pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
+
+	switch (pwr_state) {
+	case 0:
+		*status = 1;
+		break;
+	case 1:
+		*status = 0;	
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_latch_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	*status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;  
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_adapter_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_status;
+	u8 card_state;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+	card_state = (u8)((slot_status & PRSN_STATE) >> 6);
+	*status = (card_state == 1) ? 1 : 0;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_query_power_fault(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_status;
+	u8 pwr_fault;
+	int retval = 0;
+	u8 status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+	pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
+	status = (pwr_fault != 1) ? 1 : 0;
+	
+	DBG_LEAVE_ROUTINE
+	/* Note: Logic 0 => fault */
+	return status;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd = 0;
+	u16 slot_ctrl;
+	int rc = 0;
+
+	dbg("%s: \n", __FUNCTION__);
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return rc;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+
+	switch (value) {
+		case 0 :	/* turn off */
+			slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00C0;
+			break;
+		case 1:		/* turn on */
+			slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040;
+			break;
+		case 2:		/* turn blink */
+			slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080;
+			break;
+		default:
+			return -1;
+	}
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	pcie_write_cmd(slot, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd);
+	
+	return rc;
+}
+
+
+static void hpc_set_green_led_on(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+	int rc = 0;
+       	
+	dbg("%s: \n", __FUNCTION__);	
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	pcie_write_cmd(slot, slot_cmd);
+
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+	return;
+}
+
+static void hpc_set_green_led_off(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+	int rc = 0;
+
+	dbg("%s: \n", __FUNCTION__);	
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+
+	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+	pcie_write_cmd(slot, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd);
+
+	return;
+}
+
+static void hpc_set_green_led_blink(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+	int rc = 0; 
+	
+	dbg("%s: \n", __FUNCTION__);	
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+
+	slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+	pcie_write_cmd(slot, slot_cmd);
+
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+	return;
+}
+
+int pcie_get_ctlr_slot_config(struct controller *ctrl,
+	int *num_ctlr_slots,	/* number of slots in this HPC; only 1 in PCIE  */	
+	int *first_device_num,	/* PCI dev num of the first slot in this PCIE	*/
+	int *physical_slot_num,	/* phy slot num of the first slot in this PCIE	*/
+	u8 *ctrlcap)
+{
+	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
+	u32 slot_cap;
+	int rc = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	*first_device_num = 0;
+	*num_ctlr_slots = 1; 
+
+	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap);
+
+	if (rc) {
+		err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
+		return -1;
+	}
+	
+	*physical_slot_num = slot_cap >> 19;
+	dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num);
+	
+	*ctrlcap = slot_cap & 0x0000007f;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static void hpc_release_ctlr(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
+	struct php_ctlr_state_s *p, *p_prev;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (pciehp_poll_mode) {
+	    del_timer(&php_ctlr->int_poll_timer);
+	} else {	
+		if (php_ctlr->irq) {
+			free_irq(php_ctlr->irq, ctrl);
+			php_ctlr->irq = 0;
+			if (!pcie_mch_quirk) 
+				pci_disable_msi(php_ctlr->pci_dev);
+		}
+	}
+	if (php_ctlr->pci_dev) 
+		php_ctlr->pci_dev = NULL;
+
+	spin_lock(&list_lock);
+	p = php_ctlr_list_head;
+	p_prev = NULL;
+	while (p) {
+		if (p == php_ctlr) {
+			if (p_prev)
+				p_prev->pnext = p->pnext;
+			else
+				php_ctlr_list_head = p->pnext;
+			break;
+		} else {
+			p_prev = p;
+			p = p->pnext;
+		}
+	}
+	spin_unlock(&list_lock);
+
+	kfree(php_ctlr);
+
+	DBG_LEAVE_ROUTINE
+			  
+}
+
+static int hpc_power_on_slot(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	dbg("%s: \n", __FUNCTION__);	
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL, 
+		slot_ctrl);
+
+	slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	retval = pcie_write_cmd(slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
+		return -1;
+	}
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static int hpc_power_off_slot(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	dbg("%s: \n", __FUNCTION__);	
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
+	slot->hp_slot = 0;
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL, 
+		slot_ctrl);
+
+	slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	retval = pcie_write_cmd(slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
+{
+	struct controller *ctrl = NULL;
+	struct php_ctlr_state_s *php_ctlr;
+	u8 schedule_flag = 0;
+	u16 slot_status, intr_detect, intr_loc;
+	u16 temp_word;
+	int hp_slot = 0;	/* only 1 slot per PCI Express port */
+	int rc = 0;
+
+	if (!dev_id)
+		return IRQ_NONE;
+
+	if (!pciehp_poll_mode) { 
+		ctrl = dev_id;
+		php_ctlr = ctrl->hpc_ctlr_handle;
+	} else {
+		php_ctlr = dev_id;
+		ctrl = (struct controller *)php_ctlr->callback_instance_id;
+	}
+
+	if (!ctrl) {
+		dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id);
+		return IRQ_NONE;
+	}
+	
+	if (!php_ctlr) {
+		dbg("%s: php_ctlr == NULL\n", __FUNCTION__);
+		return IRQ_NONE;
+	}
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return IRQ_NONE;
+	}
+
+	intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED |
+					PRSN_DETECT_CHANGED | CMD_COMPLETED );
+
+	intr_loc = slot_status & intr_detect;
+
+	/* Check to see if it was our interrupt */
+	if ( !intr_loc )
+		return IRQ_NONE;
+
+	dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
+	/* Mask Hot-plug Interrupt Enable */
+	if (!pciehp_poll_mode) {
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+
+		dbg("%s: Set Mask Hot-plug Interrupt Enable\n", __FUNCTION__);
+		dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+		temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+		dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+		
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+		dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); 
+		
+		/* Clear command complete interrupt caused by this write */
+		temp_word = 0x1f;
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+		dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word);
+	}
+	
+	if (intr_loc & CMD_COMPLETED) {
+		/* 
+		 * Command Complete Interrupt Pending 
+		 */
+		dbg("%s: In Command Complete Interrupt Pending\n", __FUNCTION__);
+		wake_up_interruptible(&ctrl->queue);
+	}
+
+	if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED))
+		schedule_flag += php_ctlr->switch_change_callback(
+			hp_slot, php_ctlr->callback_instance_id);
+	if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED))
+		schedule_flag += php_ctlr->attention_button_callback(
+			hp_slot, php_ctlr->callback_instance_id);
+	if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED))
+		schedule_flag += php_ctlr->presence_change_callback(
+			hp_slot , php_ctlr->callback_instance_id);
+	if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED))
+		schedule_flag += php_ctlr->power_fault_callback(
+			hp_slot, php_ctlr->callback_instance_id);
+
+	/* Clear all events after serving them */
+	temp_word = 0x1F;
+	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		return IRQ_NONE;
+	}
+	/* Unmask Hot-plug Interrupt Enable */
+	if (!pciehp_poll_mode) {
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+
+		dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
+		dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
+
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+		dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); 	
+	
+		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+		dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); 
+		
+		/* Clear command complete interrupt caused by this write */
+		temp_word = 0x1F;
+		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+		dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); 
+	}
+	
+	return IRQ_HANDLED;
+}
+
+static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	enum pcie_link_speed lnk_speed;
+	u32	lnk_cap;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap);
+
+	if (retval) {
+		err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	switch (lnk_cap & 0x000F) {
+	case 1:
+		lnk_speed = PCIE_2PT5GB;
+		break;
+	default:
+		lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_speed;
+	dbg("Max link speed = %d\n", lnk_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	enum pcie_link_width lnk_wdth;
+	u32	lnk_cap;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap);
+
+	if (retval) {
+		err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	switch ((lnk_cap & 0x03F0) >> 4){
+	case 0:
+		lnk_wdth = PCIE_LNK_WIDTH_RESRV;
+		break;
+	case 1:
+		lnk_wdth = PCIE_LNK_X1;
+		break;
+	case 2:
+		lnk_wdth = PCIE_LNK_X2;
+		break;
+	case 4:
+		lnk_wdth = PCIE_LNK_X4;
+		break;
+	case 8:
+		lnk_wdth = PCIE_LNK_X8;
+		break;
+	case 12:
+		lnk_wdth = PCIE_LNK_X12;
+		break;
+	case 16:
+		lnk_wdth = PCIE_LNK_X16;
+		break;
+	case 32:
+		lnk_wdth = PCIE_LNK_X32;
+		break;
+	default:
+		lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_wdth;
+	dbg("Max link width = %d\n", lnk_wdth);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
+	int retval = 0;
+	u16 lnk_status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	switch (lnk_status & 0x0F) {
+	case 1:
+		lnk_speed = PCIE_2PT5GB;
+		break;
+	default:
+		lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_speed;
+	dbg("Current link speed = %d\n", lnk_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
+{
+	struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+	enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
+	int retval = 0;
+	u16 lnk_status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+	
+	switch ((lnk_status & 0x03F0) >> 4){
+	case 0:
+		lnk_wdth = PCIE_LNK_WIDTH_RESRV;
+		break;
+	case 1:
+		lnk_wdth = PCIE_LNK_X1;
+		break;
+	case 2:
+		lnk_wdth = PCIE_LNK_X2;
+		break;
+	case 4:
+		lnk_wdth = PCIE_LNK_X4;
+		break;
+	case 8:
+		lnk_wdth = PCIE_LNK_X8;
+		break;
+	case 12:
+		lnk_wdth = PCIE_LNK_X12;
+		break;
+	case 16:
+		lnk_wdth = PCIE_LNK_X16;
+		break;
+	case 32:
+		lnk_wdth = PCIE_LNK_X32;
+		break;
+	default:
+		lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_wdth;
+	dbg("Current link width = %d\n", lnk_wdth);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static struct hpc_ops pciehp_hpc_ops = {
+	.power_on_slot			= hpc_power_on_slot,
+	.power_off_slot			= hpc_power_off_slot,
+	.set_attention_status		= hpc_set_attention_status,
+	.get_power_status		= hpc_get_power_status,
+	.get_attention_status		= hpc_get_attention_status,
+	.get_latch_status		= hpc_get_latch_status,
+	.get_adapter_status		= hpc_get_adapter_status,
+
+	.get_max_bus_speed		= hpc_get_max_lnk_speed,
+	.get_cur_bus_speed		= hpc_get_cur_lnk_speed,
+	.get_max_lnk_width		= hpc_get_max_lnk_width,
+	.get_cur_lnk_width		= hpc_get_cur_lnk_width,
+	
+	.query_power_fault		= hpc_query_power_fault,
+	.green_led_on			= hpc_set_green_led_on,
+	.green_led_off			= hpc_set_green_led_off,
+	.green_led_blink		= hpc_set_green_led_blink,
+	
+	.release_ctlr			= hpc_release_ctlr,
+	.check_lnk_status		= hpc_check_lnk_status,
+};
+
+int pcie_init(struct controller * ctrl,
+	struct pcie_device *dev,
+	php_intr_callback_t attention_button_callback,
+	php_intr_callback_t switch_change_callback,
+	php_intr_callback_t presence_change_callback,
+	php_intr_callback_t power_fault_callback)
+{
+	struct php_ctlr_state_s *php_ctlr, *p;
+	void *instance_id = ctrl;
+	int rc;
+	static int first = 1;
+	u16 temp_word;
+	u16 cap_reg;
+	u16 intr_enable = 0;
+	u32 slot_cap;
+	int cap_base, saved_cap_base;
+	u16 slot_status, slot_ctrl;
+	struct pci_dev *pdev;
+
+	DBG_ENTER_ROUTINE
+	
+	spin_lock_init(&list_lock);	
+	php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
+
+	if (!php_ctlr) {	/* allocate controller state data */
+		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
+		goto abort;
+	}
+
+	memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
+	
+	pdev = dev->port;
+	php_ctlr->pci_dev = pdev;	/* save pci_dev in context */
+
+	dbg("%s: pdev->vendor %x pdev->device %x\n", __FUNCTION__,
+		pdev->vendor, pdev->device);
+
+	saved_cap_base = pcie_cap_base;
+
+	if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
+		dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	pcie_cap_base = cap_base;
+
+	dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
+
+	rc = hp_register_read_word(pdev, CAP_REG, cap_reg);
+	if (rc) {
+		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG, cap_reg);
+
+	if (((cap_reg & SLOT_IMPL) == 0) || ((cap_reg & DEV_PORT_TYPE) != 0x0040)){
+		dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap);
+	if (rc) {
+		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP, slot_cap);
+
+	if (!(slot_cap & HP_CAP)) {
+		dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	/* For debugging purpose */
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status);
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+
+	if (first) {
+		spin_lock_init(&hpc_event_lock);
+		first = 0;
+	}
+
+	dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, 
+		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
+	for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+		if (pci_resource_len(pdev, rc) > 0)
+			dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc,
+				pci_resource_start(pdev, rc), pci_resource_len(pdev, rc));
+
+	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, 
+		pdev->subsystem_vendor, pdev->subsystem_device);
+
+	if (pci_enable_device(pdev))
+		goto abort_free_ctlr;
+	
+	init_MUTEX(&ctrl->crit_sect);
+	/* setup wait queue */
+	init_waitqueue_head(&ctrl->queue);
+
+	/* find the IRQ */
+	php_ctlr->irq = dev->irq;
+	dbg("HPC interrupt = %d\n", php_ctlr->irq);
+
+	/* Save interrupt callback info */
+	php_ctlr->attention_button_callback = attention_button_callback;
+	php_ctlr->switch_change_callback = switch_change_callback;
+	php_ctlr->presence_change_callback = presence_change_callback;
+	php_ctlr->power_fault_callback = power_fault_callback;
+	php_ctlr->callback_instance_id = instance_id;
+
+	/* return PCI Controller Info */
+	php_ctlr->slot_device_offset = 0;
+	php_ctlr->num_slots = 1;
+
+	/* Mask Hot-plug Interrupt Enable */
+	rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
+	temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+
+	rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word);
+
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status);
+
+	temp_word = 0x1F; /* Clear all events */
+	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word);
+
+	if (pciehp_poll_mode)  {/* Install interrupt polling code */
+		/* Install and start the interrupt polling timer */
+		init_timer(&php_ctlr->int_poll_timer);
+		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
+	} else {
+		/* Installs the interrupt handler */
+		rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+		if (rc) {
+			err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+			goto abort_free_ctlr;
+		}
+	}
+
+	rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
+	dbg("%s: slot_cap %x\n", __FUNCTION__, slot_cap);
+
+	intr_enable = intr_enable | PRSN_DETECT_ENABLE;
+
+	if (ATTN_BUTTN(slot_cap))
+		intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
+	
+	if (POWER_CTRL(slot_cap))
+		intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
+	
+	if (MRL_SENS(slot_cap))
+		intr_enable = intr_enable | MRL_DETECT_ENABLE;
+
+	temp_word = (temp_word & ~intr_enable) | intr_enable; 
+
+	if (pciehp_poll_mode) {
+		temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
+	} else {
+		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
+	}
+	dbg("%s: temp_word %x\n", __FUNCTION__, temp_word);
+
+	/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
+	rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word);
+	rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, 
+		SLOT_STATUS, slot_status);
+	
+	temp_word =  0x1F; /* Clear all events */
+	rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word);
+	
+	/*  Add this HPC instance into the HPC list */
+	spin_lock(&list_lock);
+	if (php_ctlr_list_head == 0) {
+		php_ctlr_list_head = php_ctlr;
+		p = php_ctlr_list_head;
+		p->pnext = NULL;
+	} else {
+		p = php_ctlr_list_head;
+
+		while (p->pnext)
+			p = p->pnext;
+
+		p->pnext = php_ctlr;
+	}
+	spin_unlock(&list_lock);
+
+	ctlr_seq_num++;
+	ctrl->hpc_ctlr_handle = php_ctlr;
+	ctrl->hpc_ops = &pciehp_hpc_ops;
+
+	DBG_LEAVE_ROUTINE
+	return 0;
+
+	/* We end up here for the many possible ways to fail this API.  */
+abort_free_ctlr:
+	pcie_cap_base = saved_cap_base;
+	kfree(php_ctlr);
+abort:
+	DBG_LEAVE_ROUTINE
+	return -1;
+}
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
new file mode 100644
index 0000000..723b12c
--- /dev/null
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -0,0 +1,827 @@
+/*
+ * PCI Express Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include "../pci.h"
+#include "pciehp.h"
+#ifndef CONFIG_IA64
+#include "../../../arch/i386/pci/pci.h"    /* horrible hack showing how processor dependant we are... */
+#endif
+
+
+int pciehp_configure_device (struct controller* ctrl, struct pci_func* func)  
+{
+	unsigned char bus;
+	struct pci_bus *child;
+	int num;
+
+	if (func->pci_dev == NULL)
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
+
+	/* Still NULL ? Well then scan for it ! */
+	if (func->pci_dev == NULL) {
+		dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__);
+
+		num = pci_scan_slot(ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function));
+
+		if (num)
+			pci_bus_add_devices(ctrl->pci_dev->subordinate);
+		
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
+		if (func->pci_dev == NULL) {
+			dbg("ERROR: pci_dev still null\n");
+			return 0;
+		}
+	}
+
+	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
+		child = pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
+		pci_do_scan_bus(child);
+
+	}
+
+	return 0;
+}
+
+
+int pciehp_unconfigure_device(struct pci_func* func) 
+{
+	int rc = 0;
+	int j;
+	struct pci_bus *pbus;
+
+	dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus,
+				func->device, func->function);
+	pbus = func->pci_dev->bus;
+
+	for (j=0; j<8 ; j++) {
+		struct pci_dev* temp = pci_find_slot(func->bus,
+				(func->device << 3) | j);
+		if (temp) {
+			pci_remove_bus_device(temp);
+		}
+	}
+	/* 
+	 * Some PCI Express root ports require fixup after hot-plug operation.
+	 */
+	if (pcie_mch_quirk) 
+		pci_fixup_device(pci_fixup_final, pbus->self);
+	
+	return rc;
+}
+
+/*
+ * pciehp_set_irq
+ *
+ * @bus_num: bus number of PCI device
+ * @dev_num: device number of PCI device
+ * @slot: pointer to u8 where slot number will be returned
+ */
+int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
+{
+#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
+	int rc;
+	u16 temp_word;
+	struct pci_dev fakedev;
+	struct pci_bus fakebus;
+
+	fakedev.devfn = dev_num << 3;
+	fakedev.bus = &fakebus;
+	fakebus.number = bus_num;
+	dbg("%s: dev %d, bus %d, pin %d, num %d\n",
+	    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
+	rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);
+	dbg("%s: rc %d\n", __FUNCTION__, rc);
+	if (!rc)
+		return !rc;
+
+	/* set the Edge Level Control Register (ELCR) */
+	temp_word = inb(0x4d0);
+	temp_word |= inb(0x4d1) << 8;
+
+	temp_word |= 0x01 << irq_num;
+
+	/* This should only be for x86 as it sets the Edge Level Control Register */
+	outb((u8) (temp_word & 0xFF), 0x4d0);
+	outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
+#endif
+	return 0;
+}
+
+/* More PCI configuration routines; this time centered around hotplug controller */
+
+
+/*
+ * pciehp_save_config
+ *
+ * Reads configuration for all slots in a PCI bus and saves info.
+ *
+ * Note:  For non-hot plug busses, the slot # saved is the device #
+ *
+ * returns 0 if success
+ */
+int pciehp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	struct pci_func *new_slot;
+	int sub_bus;
+	int max_functions;
+	int function;
+	u8 DevError;
+	int device = 0;
+	int cloop = 0;
+	int stop_it;
+	int index;
+	int is_hot_plug = num_ctlr_slots || first_device_num;
+	struct pci_bus lpci_bus, *pci_bus;
+	int FirstSupported, LastSupported;
+
+	dbg("%s: Enter\n", __FUNCTION__);
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+
+	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__,
+				num_ctlr_slots, first_device_num);
+
+	/*   Decide which slots are supported */
+	if (is_hot_plug) {
+		/*********************************
+		 *  is_hot_plug is the slot mask
+		 *********************************/
+		FirstSupported = first_device_num;
+		LastSupported = FirstSupported + num_ctlr_slots - 1;
+	} else {
+		FirstSupported = 0;
+		LastSupported = 0x1F;
+	}
+
+	dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported,
+					LastSupported);
+
+	/*   Save PCI configuration space for all devices in supported slots */
+	dbg("%s: pci_bus->number = %x\n", __FUNCTION__, pci_bus->number);
+	pci_bus->number = busnumber;
+	dbg("%s: bus = %x, dev = %x\n", __FUNCTION__, busnumber, device);
+	for (device = FirstSupported; device <= LastSupported; device++) {
+		ID = 0xFFFFFFFF;
+		rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0),
+					PCI_VENDOR_ID, &ID);
+
+		if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+			dbg("%s: ID = %x\n", __FUNCTION__, ID);
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0),
+					0x0B, &class_code);
+			if (rc)
+				return rc;
+
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0),
+					PCI_HEADER_TYPE, &header_type);
+			if (rc)
+				return rc;
+
+			dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+
+			/* If multi-function device, set max_functions to 8 */
+			if (header_type & 0x80)
+				max_functions = 8;
+			else
+				max_functions = 1;
+
+			function = 0;
+
+			do {
+				DevError = 0;
+				dbg("%s: In do loop\n", __FUNCTION__);
+
+				if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   /* P-P Bridge */
+					/* Recurse the subordinate bus
+					 * get the subordinate bus number
+					 */
+					rc = pci_bus_read_config_byte(pci_bus,
+						PCI_DEVFN(device, function), 
+						PCI_SECONDARY_BUS, &secondary_bus);
+					if (rc) {
+						return rc;
+					} else {
+						sub_bus = (int) secondary_bus;
+
+						/* Save secondary bus cfg spc with this recursive call. */
+						rc = pciehp_save_config(ctrl, sub_bus, 0, 0);
+						if (rc)
+							return rc;
+					}
+				}
+
+				index = 0;
+				new_slot = pciehp_slot_find(busnumber, device, index++);
+
+				dbg("%s: new_slot = %p bus %x dev %x fun %x\n",
+				__FUNCTION__, new_slot, busnumber, device, index-1);
+
+				while (new_slot && (new_slot->function != (u8) function)) {
+					new_slot = pciehp_slot_find(busnumber, device, index++);
+					dbg("%s: while loop, new_slot = %p bus %x dev %x fun %x\n",
+					__FUNCTION__, new_slot, busnumber, device, index-1);
+				}
+				if (!new_slot) {
+					/* Setup slot structure. */
+					new_slot = pciehp_slot_create(busnumber);
+					dbg("%s: if, new_slot = %p bus %x dev %x fun %x\n",
+					__FUNCTION__, new_slot, busnumber, device, function);
+
+					if (new_slot == NULL)
+						return(1);
+				}
+
+				new_slot->bus = (u8) busnumber;
+				new_slot->device = (u8) device;
+				new_slot->function = (u8) function;
+				new_slot->is_a_board = 1;
+				new_slot->switch_save = 0x10;
+				/* In case of unsupported board */
+				new_slot->status = DevError;
+				new_slot->pci_dev = pci_find_slot(new_slot->bus,
+					(new_slot->device << 3) | new_slot->function);
+				dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev);
+
+				for (cloop = 0; cloop < 0x20; cloop++) {
+					rc = pci_bus_read_config_dword(pci_bus,
+						PCI_DEVFN(device, function),
+						cloop << 2, 
+						(u32 *) &(new_slot->config_space [cloop]));
+					/* dbg("new_slot->config_space[%x] = %x\n",
+						cloop, new_slot->config_space[cloop]); */
+					if (rc)
+						return rc;
+				}
+
+				function++;
+
+				stop_it = 0;
+
+				/*  this loop skips to the next present function
+				 *  reading in Class Code and Header type.
+				 */
+
+				while ((function < max_functions)&&(!stop_it)) {
+					dbg("%s: In while loop \n", __FUNCTION__);
+					rc = pci_bus_read_config_dword(pci_bus,
+							PCI_DEVFN(device, function),
+							PCI_VENDOR_ID, &ID);
+
+					if (ID == 0xFFFFFFFF) {  /* nothing there. */
+						function++;
+						dbg("Nothing there\n");
+					} else {  /* Something there */
+						rc = pci_bus_read_config_byte(pci_bus,
+							PCI_DEVFN(device, function),
+							0x0B, &class_code);
+						if (rc)
+							return rc;
+
+						rc = pci_bus_read_config_byte(pci_bus,
+							PCI_DEVFN(device, function),
+							PCI_HEADER_TYPE, &header_type);
+						if (rc)
+							return rc;
+
+						dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+						stop_it++;
+					}
+				}
+
+			} while (function < max_functions);
+			/* End of IF (device in slot?) */
+		} else if (is_hot_plug) {
+			/* Setup slot structure with entry for empty slot */
+			new_slot = pciehp_slot_create(busnumber);
+
+			if (new_slot == NULL) {
+				return(1);
+			}
+			dbg("new_slot = %p, bus = %x, dev = %x, fun = %x\n", new_slot,
+				new_slot->bus, new_slot->device, new_slot->function);
+
+			new_slot->bus = (u8) busnumber;
+			new_slot->device = (u8) device;
+			new_slot->function = 0;
+			new_slot->is_a_board = 0;
+			new_slot->presence_save = 0;
+			new_slot->switch_save = 0;
+		}
+	} 			/* End of FOR loop */
+
+	dbg("%s: Exit\n", __FUNCTION__);
+	return(0);
+}
+
+
+/*
+ * pciehp_save_slot_config
+ *
+ * Saves configuration info for all PCI devices in a given slot
+ * including subordinate busses.
+ *
+ * returns 0 if success
+ */
+int pciehp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	int sub_bus;
+	int max_functions;
+	int function;
+	int cloop = 0;
+	int stop_it;
+	struct pci_bus lpci_bus, *pci_bus;
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = new_slot->bus;
+
+	ID = 0xFFFFFFFF;
+
+	pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0),
+					PCI_VENDOR_ID, &ID);
+
+	if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0),
+					0x0B, &class_code);
+
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0),
+					PCI_HEADER_TYPE, &header_type);
+
+		if (header_type & 0x80)	/* Multi-function device */
+			max_functions = 8;
+		else
+			max_functions = 1;
+
+		function = 0;
+
+		do {
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  /* PCI-PCI Bridge */
+				/*  Recurse the subordinate bus */
+				pci_bus_read_config_byte(pci_bus,
+					PCI_DEVFN(new_slot->device, function), 
+					PCI_SECONDARY_BUS, &secondary_bus);
+
+				sub_bus = (int) secondary_bus;
+
+				/* Save the config headers for the secondary bus. */
+				rc = pciehp_save_config(ctrl, sub_bus, 0, 0);
+
+				if (rc)
+					return rc;
+
+			}	/* End of IF */
+
+			new_slot->status = 0;
+
+			for (cloop = 0; cloop < 0x20; cloop++) {
+				pci_bus_read_config_dword(pci_bus,
+					PCI_DEVFN(new_slot->device, function), 
+					cloop << 2,
+					(u32 *) &(new_slot->config_space [cloop]));
+			}
+
+			function++;
+
+			stop_it = 0;
+
+			/*  this loop skips to the next present function
+			 *  reading in the Class Code and the Header type.
+			 */
+
+			while ((function < max_functions) && (!stop_it)) {
+				pci_bus_read_config_dword(pci_bus,
+					PCI_DEVFN(new_slot->device, function),
+					PCI_VENDOR_ID, &ID);
+
+				if (ID == 0xFFFFFFFF) {	 /* nothing there. */
+					function++;
+				} else {  /* Something there */
+					pci_bus_read_config_byte(pci_bus,
+						PCI_DEVFN(new_slot->device, function),
+						0x0B, &class_code);
+
+					pci_bus_read_config_byte(pci_bus,
+						PCI_DEVFN(new_slot->device, function),
+						PCI_HEADER_TYPE, &header_type);
+
+					stop_it++;
+				}
+			}
+
+		} while (function < max_functions);
+	}			/* End of IF (device in slot?) */
+	else {
+		return 2;
+	}
+
+	return 0;
+}
+
+
+/*
+ * pciehp_save_used_resources
+ *
+ * Stores used resource information for existing boards.  this is
+ * for boards that were in the system when this driver was loaded.
+ * this function is for hot plug ADD
+ *
+ * returns 0 if success
+ * if disable  == 1(DISABLE_CARD),
+ *  it loops for all functions of the slot and disables them.
+ * else, it just get resources of the function and return.
+ */
+int pciehp_save_used_resources(struct controller *ctrl, struct pci_func *func, int disable)
+{
+	u8 cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	u8 temp_byte;
+	u16 command;
+	u16 save_command;
+	u16 w_base, w_length;
+	u32 temp_register;
+	u32 save_base;
+	u32 base, length;
+	u64 base64 = 0;
+	int index = 0;
+	unsigned int devfn;
+	struct pci_resource *mem_node = NULL;
+	struct pci_resource *p_mem_node = NULL;
+	struct pci_resource *t_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_bus lpci_bus, *pci_bus;
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+
+	if (disable)
+		func = pciehp_slot_find(func->bus, func->device, index++);
+
+	while ((func != NULL) && func->is_a_board) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		/* Save the command register */
+		pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command);
+
+		if (disable) {
+			/* disable card */
+			command = 0x00;
+			pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+		}
+
+		/* Check for Bridge */
+		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+
+		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {     /* PCI-PCI Bridge */
+			dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n",
+					func->bus, func->device, save_command);
+			if (disable) {
+				/* Clear Bridge Control Register */
+				command = 0x00;
+				pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+			}
+
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
+
+			bus_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node->base = (ulong)secondary_bus;
+			bus_node->length = (ulong)(temp_byte - secondary_bus + 1);
+
+			bus_node->next = func->bus_head;
+			func->bus_head = bus_node;
+
+			/* Save IO base and Limit registers */
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &temp_byte);
+			base = temp_byte;
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &temp_byte);
+			length = temp_byte;
+
+			if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) {
+				io_node = kmalloc(sizeof(struct pci_resource),
+							GFP_KERNEL);
+				if (!io_node)
+					return -ENOMEM;
+
+				io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8;
+				io_node->length = (ulong)(length - base + 0x10) << 8;
+
+				io_node->next = func->io_head;
+				func->io_head = io_node;
+			}
+
+			/* Save memory base and Limit registers */
+			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+				mem_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+				if (!mem_node)
+					return -ENOMEM;
+
+				mem_node->base = (ulong)w_base << 16;
+				mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
+
+				mem_node->next = func->mem_head;
+				func->mem_head = mem_node;
+			}
+			/* Save prefetchable memory base and Limit registers */
+			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+				p_mem_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+				if (!p_mem_node)
+					return -ENOMEM;
+
+				p_mem_node->base = (ulong)w_base << 16;
+				p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
+
+				p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = p_mem_node;
+			}
+		} else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+			dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n",
+					func->bus, func->device, save_command);
+
+			/* Figure out IO and memory base lengths */
+			for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
+				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
+
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register);
+
+				if (!disable)
+					pci_bus_write_config_dword(pci_bus, devfn, cloop, save_base);
+
+				if (!temp_register)
+					continue;
+
+				base = temp_register;
+
+				if ((base & PCI_BASE_ADDRESS_SPACE_IO) &&
+						(!disable || (save_command & PCI_COMMAND_IO))) {
+					/* IO base */
+					/* set temp_register = amount of IO space requested */
+					base = base & 0xFFFFFFFCL;
+					base = (~base) + 1;
+
+					io_node = kmalloc(sizeof (struct pci_resource),
+								GFP_KERNEL);
+					if (!io_node)
+						return -ENOMEM;
+
+					io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK;
+					io_node->length = (ulong)base;
+					dbg("sur adapter: IO bar=0x%x(length=0x%x)\n",
+						io_node->base, io_node->length);
+
+					io_node->next = func->io_head;
+					func->io_head = io_node;
+				} else {  /* map Memory */
+					int prefetchable = 1;
+					/* struct pci_resources **res_node; */
+					char *res_type_str = "PMEM";
+					u32 temp_register2;
+
+					t_mem_node = kmalloc(sizeof (struct pci_resource),
+								GFP_KERNEL);
+					if (!t_mem_node)
+						return -ENOMEM;
+
+					if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) &&
+							(!disable || (save_command & PCI_COMMAND_MEMORY))) {
+						prefetchable = 0;
+						mem_node = t_mem_node;
+						res_type_str++;
+					} else
+						p_mem_node = t_mem_node;
+
+					base = base & 0xFFFFFFF0L;
+					base = (~base) + 1;
+
+					switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+					case PCI_BASE_ADDRESS_MEM_TYPE_32:
+						if (prefetchable) {
+							p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node->length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
+								res_type_str, 
+								p_mem_node->base,
+								p_mem_node->length);
+
+							p_mem_node->next = func->p_mem_head;
+							func->p_mem_head = p_mem_node;
+						} else {
+							mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node->length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
+								res_type_str, 
+								mem_node->base,
+								mem_node->length);
+
+							mem_node->next = func->mem_head;
+							func->mem_head = mem_node;
+						}
+						break;
+					case PCI_BASE_ADDRESS_MEM_TYPE_64:
+						pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+						base64 = temp_register2;
+						base64 = (base64 << 32) | save_base;
+
+						if (temp_register2) {
+							dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", 
+								res_type_str, temp_register2, (u32)base64);
+							base64 &= 0x00000000FFFFFFFFL;
+						}
+
+						if (prefetchable) {
+							p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node->length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
+								res_type_str, 
+								p_mem_node->base,
+								p_mem_node->length);
+
+							p_mem_node->next = func->p_mem_head;
+							func->p_mem_head = p_mem_node;
+						} else {
+							mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node->length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
+								res_type_str, 
+								mem_node->base,
+								mem_node->length);
+
+							mem_node->next = func->mem_head;
+							func->mem_head = mem_node;
+						}
+						cloop += 4;
+						break;
+					default:
+						dbg("asur: reserved BAR type=0x%x\n",
+							temp_register);
+						break;
+					}
+				} 
+			}	/* End of base register loop */
+		} else {	/* Some other unknown header type */
+			dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n",
+					func->bus, func->device);
+		}
+
+		/* find the next device in this slot */
+		if (!disable)
+			break;
+		func = pciehp_slot_find(func->bus, func->device, index++);
+	}
+
+	return 0;
+}
+
+
+/**
+ * kfree_resource_list: release memory of all list members
+ * @res: resource list to free
+ */
+static inline void
+return_resource_list(struct pci_resource **func, struct pci_resource **res)
+{
+	struct pci_resource *node;
+	struct pci_resource *t_node;
+
+	node = *func;
+	*func = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(res, node);
+		node = t_node;
+	}
+}
+
+/*
+ * pciehp_return_board_resources
+ *
+ * this routine returns all resources allocated to a board to
+ * the available pool.
+ *
+ * returns 0 if success
+ */
+int pciehp_return_board_resources(struct pci_func * func,
+				struct resource_lists * resources)
+{
+	int rc;
+
+	dbg("%s\n", __FUNCTION__);
+
+	if (!func)
+		return 1;
+
+	return_resource_list(&(func->io_head),&(resources->io_head));
+	return_resource_list(&(func->mem_head),&(resources->mem_head));
+	return_resource_list(&(func->p_mem_head),&(resources->p_mem_head));
+	return_resource_list(&(func->bus_head),&(resources->bus_head));
+
+	rc = pciehp_resource_sort_and_combine(&(resources->mem_head));
+	rc |= pciehp_resource_sort_and_combine(&(resources->p_mem_head));
+	rc |= pciehp_resource_sort_and_combine(&(resources->io_head));
+	rc |= pciehp_resource_sort_and_combine(&(resources->bus_head));
+
+	return rc;
+}
+
+/**
+ * kfree_resource_list: release memory of all list members
+ * @res: resource list to free
+ */
+static inline void
+kfree_resource_list(struct pci_resource **r)
+{
+	struct pci_resource *res, *tres;
+
+	res = *r;
+	*r = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
+/**
+ * pciehp_destroy_resource_list: put node back in the resource list
+ * @resources: list to put nodes back
+ */
+void pciehp_destroy_resource_list(struct resource_lists * resources)
+{
+	kfree_resource_list(&(resources->io_head));
+	kfree_resource_list(&(resources->mem_head));
+	kfree_resource_list(&(resources->p_mem_head));
+	kfree_resource_list(&(resources->bus_head));
+}
+
+/**
+ * pciehp_destroy_board_resources: put node back in the resource list
+ * @resources: list to put nodes back
+ */
+void pciehp_destroy_board_resources(struct pci_func * func)
+{
+	kfree_resource_list(&(func->io_head));
+	kfree_resource_list(&(func->mem_head));
+	kfree_resource_list(&(func->p_mem_head));
+	kfree_resource_list(&(func->bus_head));
+}
diff --git a/drivers/pci/hotplug/pciehprm.h b/drivers/pci/hotplug/pciehprm.h
new file mode 100644
index 0000000..966775f
--- /dev/null
+++ b/drivers/pci/hotplug/pciehprm.h
@@ -0,0 +1,52 @@
+/*
+ * PCIEHPRM : PCIEHP Resource Manager for ACPI/non-ACPI platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _PCIEHPRM_H_
+#define _PCIEHPRM_H_
+
+#ifdef	CONFIG_HOTPLUG_PCI_PCIE_PHPRM_NONACPI
+#include "pciehprm_nonacpi.h"
+#endif
+
+int pciehprm_init(enum php_ctlr_type ct);
+void pciehprm_cleanup(void);
+int pciehprm_print_pirt(void);
+int pciehprm_find_available_resources(struct controller *ctrl);
+int pciehprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type);
+void pciehprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type);
+
+#ifdef	DEBUG
+#define RES_CHECK(this, bits)	\
+	{ if (((this) & (bits - 1))) \
+		printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); }
+#else
+#define RES_CHECK(this, bits)
+#endif
+
+#endif				/* _PCIEHPRM_H_ */
diff --git a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c
new file mode 100644
index 0000000..57f4e6d
--- /dev/null
+++ b/drivers/pci/hotplug/pciehprm_acpi.c
@@ -0,0 +1,1737 @@
+/*
+ * PCIEHPRM ACPI: PHP Resource Manager for ACPI platform
+ *
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/efi.h>
+#include <linux/pci-acpi.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#ifdef	CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/actypes.h>
+#include "pciehp.h"
+#include "pciehprm.h"
+
+#define	PCI_MAX_BUS		0x100
+#define	ACPI_STA_DEVICE_PRESENT	0x01
+
+#define	METHOD_NAME__SUN	"_SUN"
+#define	METHOD_NAME__HPP	"_HPP"
+#define	METHOD_NAME_OSHP	"OSHP"
+
+/* Status code for running acpi method to gain native control */
+#define NC_NOT_RUN	0
+#define OSC_NOT_EXIST	1
+#define OSC_RUN_FAILED	2
+#define OSHP_NOT_EXIST	3
+#define OSHP_RUN_FAILED	4
+#define NC_RUN_SUCCESS	5
+
+#define	PHP_RES_BUS		0xA0
+#define	PHP_RES_IO		0xA1
+#define	PHP_RES_MEM		0xA2
+#define	PHP_RES_PMEM		0xA3
+
+#define	BRIDGE_TYPE_P2P		0x00
+#define	BRIDGE_TYPE_HOST	0x01
+
+/* this should go to drivers/acpi/include/ */
+struct acpi__hpp {
+	u8	cache_line_size;
+	u8	latency_timer;
+	u8	enable_serr;
+	u8	enable_perr;
+};
+
+struct acpi_php_slot {
+	struct acpi_php_slot	*next;
+	struct acpi_bridge	*bridge;
+	acpi_handle	handle;
+	int	seg;
+	int	bus;
+	int	dev;
+	int	fun;
+	u32	sun;
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	void	*slot_ops;	/* _STA, _EJx, etc */
+	struct slot *slot;
+};		/* per func */
+
+struct acpi_bridge {
+	struct acpi_bridge	*parent;
+	struct acpi_bridge	*next;
+	struct acpi_bridge	*child;
+	acpi_handle	handle;
+	int seg;
+	int pbus;			/* pdev->bus->number		*/
+	int pdevice;			/* PCI_SLOT(pdev->devfn)	*/
+	int pfunction;			/* PCI_DEVFN(pdev->devfn)	*/
+	int bus;			/* pdev->subordinate->number	*/
+	struct acpi__hpp		*_hpp;
+	struct acpi_php_slot	*slots;
+	struct pci_resource 	*tmem_head;	/* total from crs	*/
+	struct pci_resource 	*tp_mem_head;	/* total from crs	*/
+	struct pci_resource 	*tio_head;	/* total from crs	*/
+	struct pci_resource 	*tbus_head;	/* total from crs	*/
+	struct pci_resource 	*mem_head;	/* available	*/
+	struct pci_resource 	*p_mem_head;	/* available	*/
+	struct pci_resource 	*io_head;	/* available	*/
+	struct pci_resource 	*bus_head;	/* available	*/
+	int scanned;
+	int type;
+};
+
+static struct acpi_bridge *acpi_bridges_head;
+
+static u8 * acpi_path_name( acpi_handle	handle)
+{
+	acpi_status		status;
+	static u8		path_name[ACPI_PATHNAME_MAX];
+	struct acpi_buffer	ret_buf = { ACPI_PATHNAME_MAX, path_name };
+
+	memset(path_name, 0, sizeof (path_name));
+	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);
+
+	if (ACPI_FAILURE(status))
+		return NULL;
+	else
+		return path_name;	
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab);
+static int acpi_run_oshp ( struct acpi_bridge	*ab);
+static int osc_run_status = NC_NOT_RUN;
+static int oshp_run_status = NC_NOT_RUN;
+
+static int acpi_add_slot_to_php_slots(
+	struct acpi_bridge	*ab,
+	int			bus_num,
+	acpi_handle		handle,
+	u32			adr,
+	u32			sun
+	)
+{
+	struct acpi_php_slot	*aps;
+	static long	samesun = -1;
+
+	aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);
+	if (!aps) {
+		err ("acpi_pciehprm: alloc for aps fail\n");
+		return -1;
+	}
+	memset(aps, 0, sizeof(struct acpi_php_slot));
+
+	aps->handle = handle;
+	aps->bus = bus_num;
+	aps->dev = (adr >> 16) & 0xffff;
+	aps->fun = adr & 0xffff;
+	aps->sun = sun;
+
+	aps->next = ab->slots;	/* cling to the bridge */
+	aps->bridge = ab;
+	ab->slots = aps;
+
+	ab->scanned += 1;
+	if (!ab->_hpp)
+		acpi_get__hpp(ab);
+	
+	if (osc_run_status == OSC_NOT_EXIST)
+		oshp_run_status = acpi_run_oshp(ab);
+
+	if (sun != samesun) {
+		info("acpi_pciehprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", 
+			aps->sun, ab->seg, aps->bus, aps->dev, aps->fun);
+		samesun = sun;
+	}
+	return 0;
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			nui[4];
+	struct acpi_buffer	ret_buf = { 0, NULL};
+	union acpi_object	*ext_obj, *package;
+	u8			*path_name = acpi_path_name(ab->handle);
+	int			i, len = 0;
+
+	/* get _hpp */
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
+		if (!ret_buf.pointer) {
+			err ("acpi_pciehprm:%s alloc for _HPP fail\n", path_name);
+			return;
+		}
+		status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+		if (ACPI_SUCCESS(status))
+			break;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_pciehprm:%s _HPP fail=0x%x\n", path_name, status);
+			return;
+		}
+	}
+
+	ext_obj = (union acpi_object *) ret_buf.pointer;
+	if (ext_obj->type != ACPI_TYPE_PACKAGE) {
+		err ("acpi_pciehprm:%s _HPP obj not a package\n", path_name);
+		goto free_and_return;
+	}
+
+	len = ext_obj->package.count;
+	package = (union acpi_object *) ret_buf.pointer;
+	for ( i = 0; (i < len) || (i < 4); i++) {
+		ext_obj = (union acpi_object *) &package->package.elements[i];
+		switch (ext_obj->type) {
+		case ACPI_TYPE_INTEGER:
+			nui[i] = (u8)ext_obj->integer.value;
+			break;
+		default:
+			err ("acpi_pciehprm:%s _HPP obj type incorrect\n", path_name);
+			goto free_and_return;
+		}
+	}
+
+	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	if (!ab->_hpp) {
+		err ("acpi_pciehprm:%s alloc for _HPP failed\n", path_name);
+		goto free_and_return;
+	}
+	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
+
+	ab->_hpp->cache_line_size	= nui[0];
+	ab->_hpp->latency_timer		= nui[1];
+	ab->_hpp->enable_serr		= nui[2];
+	ab->_hpp->enable_perr		= nui[3];
+
+	dbg("  _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
+	dbg("  _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
+	dbg("  _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
+	dbg("  _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+
+free_and_return:
+	kfree(ret_buf.pointer);
+}
+
+static int acpi_run_oshp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(ab->handle);
+
+	/* run OSHP */
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
+		oshp_run_status = (status == AE_NOT_FOUND) ? OSHP_NOT_EXIST : OSHP_RUN_FAILED;
+	} else {
+		oshp_run_status = NC_RUN_SUCCESS;
+		dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);
+		dbg("acpi_pciehprm:%s oshp_run_status =0x%x\n", path_name, oshp_run_status);
+	}
+	return oshp_run_status;
+}
+
+static acpi_status acpi_evaluate_crs(
+	acpi_handle		handle,
+	struct acpi_resource	**retbuf
+	)
+{
+	acpi_status		status;
+	struct acpi_buffer	crsbuf;
+	u8			*path_name = acpi_path_name(handle);
+
+	crsbuf.length  = 0;
+	crsbuf.pointer = NULL;
+
+	status = acpi_get_current_resources (handle, &crsbuf);
+
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		break;		/* found */
+	case AE_NOT_FOUND:
+		dbg("acpi_pciehprm:%s _CRS not found\n", path_name);
+		return status;
+	default:
+		err ("acpi_pciehprm:%s _CRS fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL);
+	if (!crsbuf.pointer) {
+		err ("acpi_pciehprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name);
+		return AE_NO_MEMORY;
+	}
+
+	status = acpi_get_current_resources (handle, &crsbuf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm: %s _CRS fail=0x%x.\n", path_name, status);
+		kfree(crsbuf.pointer);
+		return status;
+	}
+
+	*retbuf = crsbuf.pointer;
+
+	return status;
+}
+
+static void free_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res, *next;
+
+	for (res = aprh; res; res = next) {
+		next = res->next;
+		kfree(res);
+	}
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res->next)
+		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
+}
+
+static void print_slot_resources( struct acpi_php_slot	*aps)
+{
+	if (aps->bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (aps->bus_head);
+	}
+
+	if (aps->io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (aps->io_head);
+	}
+
+	if (aps->mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (aps->mem_head);
+	}
+
+	if (aps->p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (aps->p_mem_head);
+	}
+}
+
+static void print_pci_resources( struct acpi_bridge	*ab)
+{
+	if (ab->tbus_head) {
+		dbg("    Total BUS Resources:\n");
+		print_pci_resource (ab->tbus_head);
+	}
+	if (ab->bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (ab->bus_head);
+	}
+
+	if (ab->tio_head) {
+		dbg("    Total IO Resources:\n");
+		print_pci_resource (ab->tio_head);
+	}
+	if (ab->io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (ab->io_head);
+	}
+
+	if (ab->tmem_head) {
+		dbg("    Total MEM Resources:\n");
+		print_pci_resource (ab->tmem_head);
+	}
+	if (ab->mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (ab->mem_head);
+	}
+
+	if (ab->tp_mem_head) {
+		dbg("    Total PMEM Resources:\n");
+		print_pci_resource (ab->tp_mem_head);
+	}
+	if (ab->p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (ab->p_mem_head);
+	}
+	if (ab->_hpp) {
+		dbg("    _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
+		dbg("    _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
+		dbg("    _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
+		dbg("    _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+	}
+}
+
+static int pciehprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	pciehp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+static int pciehprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res->next)
+		pciehprm_delete_resource(aprh, res->base, res->length);
+
+	return 0;
+}
+
+static int pciehprm_add_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+
+	for (res = *aprh; res; res = res->next) {
+		if ((res->base + res->length) == base) {
+			res->length += size;
+			size = 0L;
+			break;
+		}
+		if (res->next == *aprh)
+			break;
+	}
+
+	if (size) {
+		res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		if (!res) {
+			err ("acpi_pciehprm: alloc for res fail\n");
+			return -ENOMEM;
+		}
+		memset(res, 0, sizeof (struct pci_resource));
+
+		res->base = base;
+		res->length = size;
+		res->next = *aprh;
+		*aprh = res;
+	}
+
+	return 0;
+}
+
+static int pciehprm_add_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+	int	rc = 0;
+
+	for (res = this; res && !rc; res = res->next)
+		rc = pciehprm_add_resource(aprh, res->base, res->length);
+
+	return rc;
+}
+
+static void acpi_parse_io (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_io	*dataio;
+	dataio = (struct acpi_resource_io *) data;
+
+	dbg("Io Resource\n");
+	dbg("  %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10);
+	dbg("  Range minimum base: %08X\n", dataio->min_base_address);
+	dbg("  Range maximum base: %08X\n", dataio->max_base_address);
+	dbg("  Alignment: %08X\n", dataio->alignment);
+	dbg("  Range Length: %08X\n", dataio->range_length);
+}
+
+static void acpi_parse_fixed_io (
+	struct acpi_bridge	*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_fixed_io  *datafio;
+	datafio = (struct acpi_resource_fixed_io *) data;
+
+	dbg("Fixed Io Resource\n");
+	dbg("  Range base address: %08X", datafio->base_address);
+	dbg("  Range length: %08X", datafio->range_length);
+}
+
+static void acpi_parse_address16_32 (
+	struct acpi_bridge	*ab,
+	union acpi_resource_data	*data,
+	acpi_resource_type	id
+	)
+{
+	/* 
+	 * acpi_resource_address16 == acpi_resource_address32
+	 * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data;
+	 */
+	struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data;
+	struct pci_resource **aprh, **tprh;
+
+	if (id == ACPI_RSTYPE_ADDRESS16)
+		dbg("acpi_pciehprm:16-Bit Address Space Resource\n");
+	else
+		dbg("acpi_pciehprm:32-Bit Address Space Resource\n");
+
+	switch (data32->resource_type) {
+	case ACPI_MEMORY_RANGE: 
+		dbg("  Resource Type: Memory Range\n");
+		aprh = &ab->mem_head;
+		tprh = &ab->tmem_head;
+
+		switch (data32->attribute.memory.cache_attribute) {
+		case ACPI_NON_CACHEABLE_MEMORY:
+			dbg("  Type Specific: Noncacheable memory\n");
+			break; 
+		case ACPI_CACHABLE_MEMORY:
+			dbg("  Type Specific: Cacheable memory\n");
+			break; 
+		case ACPI_WRITE_COMBINING_MEMORY:
+			dbg("  Type Specific: Write-combining memory\n");
+			break; 
+		case ACPI_PREFETCHABLE_MEMORY:
+			aprh = &ab->p_mem_head;
+			dbg("  Type Specific: Prefetchable memory\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid cache attribute\n");
+			break;
+		}
+
+		dbg("  Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only");
+		break;
+
+	case ACPI_IO_RANGE: 
+		dbg("  Resource Type: I/O Range\n");
+		aprh = &ab->io_head;
+		tprh = &ab->tio_head;
+
+		switch (data32->attribute.io.range_attribute) {
+		case ACPI_NON_ISA_ONLY_RANGES:
+			dbg("  Type Specific: Non-ISA Io Addresses\n");
+			break; 
+		case ACPI_ISA_ONLY_RANGES:
+			dbg("  Type Specific: ISA Io Addresses\n");
+			break; 
+		case ACPI_ENTIRE_RANGE:
+			dbg("  Type Specific: ISA and non-ISA Io Addresses\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid range attribute\n");
+			break;
+		}
+		break;
+
+	case ACPI_BUS_NUMBER_RANGE: 
+		dbg("  Resource Type: Bus Number Range(fixed)\n");
+		/* fixup to be compatible with the rest of php driver */
+		data32->min_address_range++;
+		data32->address_length--;
+		aprh = &ab->bus_head;
+		tprh = &ab->tbus_head;
+		break; 
+	default: 
+		dbg("  Resource Type: Invalid resource type. Exiting.\n");
+		return;
+	}
+
+	dbg("  Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer");
+	dbg("  %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive");
+	dbg("  Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not");
+	dbg("  Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not");
+	dbg("  Granularity: %08X\n", data32->granularity);
+	dbg("  Address range min: %08X\n", data32->min_address_range);
+	dbg("  Address range max: %08X\n", data32->max_address_range);
+	dbg("  Address translation offset: %08X\n", data32->address_translation_offset);
+	dbg("  Address Length: %08X\n", data32->address_length);
+
+	if (0xFF != data32->resource_source.index) {
+		dbg("  Resource Source Index: %X\n", data32->resource_source.index);
+		/* dbg("  Resource Source: %s\n", data32->resource_source.string_ptr); */
+	}
+
+	pciehprm_add_resource(aprh, data32->min_address_range, data32->address_length);
+}
+
+static acpi_status acpi_parse_crs(
+	struct acpi_bridge	*ab,
+	struct acpi_resource	*crsbuf
+	)
+{
+	acpi_status		status = AE_OK;
+	struct acpi_resource	*resource = crsbuf;
+	u8				count = 0;
+	u8				done = 0;
+
+	while (!done) {
+		dbg("acpi_pciehprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++);
+		switch (resource->id) {
+		case ACPI_RSTYPE_IRQ:
+			dbg("Irq -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_DMA:
+			dbg("DMA -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_START_DPF:
+			dbg("Start DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_DPF:
+			dbg("End DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_IO:
+			acpi_parse_io (ab, &resource->data);
+			break; 
+		case ACPI_RSTYPE_FIXED_IO:
+			acpi_parse_fixed_io (ab, &resource->data);
+			break; 
+		case ACPI_RSTYPE_VENDOR:
+			dbg("Vendor -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_TAG:
+			dbg("End_tag -------- Resource\n");
+			done = 1;
+			break; 
+		case ACPI_RSTYPE_MEM24:
+			dbg("Mem24 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_MEM32:
+			dbg("Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_FIXED_MEM32:
+			dbg("Fixed Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_ADDRESS16:
+			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16);
+			break; 
+		case ACPI_RSTYPE_ADDRESS32:
+			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32);
+			break; 
+		case ACPI_RSTYPE_ADDRESS64:
+			info("Address64 -------- Resource unparsed\n");
+			break; 
+		case ACPI_RSTYPE_EXT_IRQ:
+			dbg("Ext Irq -------- Resource\n");
+			break; 
+		default:
+			dbg("Invalid -------- resource type 0x%x\n", resource->id);
+			break;
+		}
+
+		resource = (struct acpi_resource *) ((char *)resource + resource->length);
+	}
+
+	return status;
+}
+
+static acpi_status acpi_get_crs( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	struct acpi_resource	*crsbuf;
+
+	status = acpi_evaluate_crs(ab->handle, &crsbuf);
+	if (ACPI_SUCCESS(status)) {
+		status = acpi_parse_crs(ab, crsbuf);
+		kfree(crsbuf);
+
+		pciehp_resource_sort_and_combine(&ab->bus_head);
+		pciehp_resource_sort_and_combine(&ab->io_head);
+		pciehp_resource_sort_and_combine(&ab->mem_head);
+		pciehp_resource_sort_and_combine(&ab->p_mem_head);
+
+		pciehprm_add_resources (&ab->tbus_head, ab->bus_head);
+		pciehprm_add_resources (&ab->tio_head, ab->io_head);
+		pciehprm_add_resources (&ab->tmem_head, ab->mem_head);
+		pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
+	}
+
+	return status;
+}
+
+/* find acpi_bridge downword from ab.  */
+static struct acpi_bridge *
+find_acpi_bridge_by_bus(
+	struct acpi_bridge *ab,
+	int seg,
+	int bus		/* pdev->subordinate->number */
+	)
+{
+	struct acpi_bridge	*lab = NULL;
+
+	if (!ab)
+		return NULL;
+
+	if ((ab->bus == bus) && (ab->seg == seg))
+		return ab;
+
+	if (ab->child)
+		lab = find_acpi_bridge_by_bus(ab->child, seg, bus);
+
+	if (!lab)
+	if (ab->next)
+		lab = find_acpi_bridge_by_bus(ab->next, seg, bus);
+
+	return lab;
+}
+
+/*
+ * Build a device tree of ACPI PCI Bridges
+ */
+static void pciehprm_acpi_register_a_bridge (
+	struct acpi_bridge	**head,
+	struct acpi_bridge	*pab,	/* parent bridge to which child bridge is added */
+	struct acpi_bridge	*cab	/* child bridge to add */
+	)
+{
+	struct acpi_bridge	*lpab;
+	struct acpi_bridge	*lcab;
+
+	lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus);
+	if (!lpab) {
+		if (!(pab->type & BRIDGE_TYPE_HOST))
+			warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus);
+		pab->next = *head;
+		*head = pab;
+		lpab = pab;
+	}
+
+	if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab))
+		return;
+
+	lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus);
+	if (lcab) {
+		if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus))
+			err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus);
+		return;
+	} else
+		lcab = cab;
+
+	lcab->parent = lpab;
+	lcab->next = lpab->child;
+	lpab->child = lcab;
+}
+
+static acpi_status pciehprm_acpi_build_php_slots_callback(
+	acpi_handle		handle,
+	u32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	ulong		bus_num;
+	ulong		seg_num;
+	ulong		sun, adr;
+	ulong		padr = 0;
+	acpi_handle		phandle = NULL;
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*lab;
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get _SUN */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun);
+	switch(status) {
+	case AE_NOT_FOUND:
+		return AE_OK;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_pciehprm:%s _SUN fail=0x%x\n", path_name, status);
+			return status;
+		}
+	}
+
+	/* get _ADR. _ADR must exist if _SUN exists */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	dbg("acpi_pciehprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr);
+
+	status = acpi_get_parent(handle, &phandle);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s get_parent fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	bus_num = pab->bus;
+	seg_num = pab->seg;
+
+	if (pab->bus == bus_num) {
+		lab = pab;
+	} else {
+		dbg("WARN: pab is not parent\n");
+		lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num);
+		if (!lab) {
+			dbg("acpi_pciehprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+			lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL);
+			if (!lab) {
+				err("acpi_pciehprm: alloc for ab fail\n");
+				return AE_NO_MEMORY;
+			}
+			memset(lab, 0, sizeof(struct acpi_bridge));
+
+			lab->handle = phandle;
+			lab->pbus = pab->bus;
+			lab->pdevice = (int)(padr >> 16) & 0xffff;
+			lab->pfunction = (int)(padr & 0xffff);
+			lab->bus = (int)bus_num;
+			lab->scanned = 0;
+			lab->type = BRIDGE_TYPE_P2P;
+
+			pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab);
+		} else
+			dbg("acpi_pciehprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+	}
+
+	acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun);
+
+	return (status);
+}
+
+static int pciehprm_acpi_build_php_slots(
+	struct acpi_bridge	*ab,
+	u32			depth
+	)
+{
+	acpi_status	status;
+	u8		*path_name = acpi_path_name(ab->handle);
+
+	/* Walk down this pci bridge to get _SUNs if any behind P2P */
+	status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+				ab->handle,
+				depth,
+				pciehprm_acpi_build_php_slots_callback,
+				ab,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		dbg("acpi_pciehprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void build_a_bridge(
+	struct acpi_bridge	*pab,
+	struct acpi_bridge	*ab
+	)
+{
+	u8		*path_name = acpi_path_name(ab->handle);
+
+	pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab);
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("acpi_pciehprm: Registered PCI HOST Bridge(%02x)    on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("acpi_pciehprm: Registered PCI  P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
+		break;
+	};
+
+	/* build any immediate PHP slots under this pci bridge */
+	pciehprm_acpi_build_php_slots(ab, 1);
+}
+
+static struct acpi_bridge * add_p2p_bridge(
+	acpi_handle handle,
+	struct acpi_bridge	*pab,	/* parent */
+	ulong	adr
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_dev	*pdev;
+	ulong		devnum, funcnum;
+	u8			*path_name = acpi_path_name(handle);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_pciehprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	devnum = (adr >> 16) & 0xffff;
+	funcnum = adr & 0xffff;
+
+	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev || !pdev->subordinate) {
+		err("acpi_pciehprm:%s is not a P2P Bridge\n", path_name);
+		kfree(ab);
+		return NULL;
+	}
+
+	ab->handle = handle;
+	ab->seg = pab->seg;
+	ab->pbus = pab->bus;		/* or pdev->bus->number */
+	ab->pdevice = devnum;		/* or PCI_SLOT(pdev->devfn) */
+	ab->pfunction = funcnum;	/* or PCI_FUNC(pdev->devfn) */
+	ab->bus = pdev->subordinate->number;
+	ab->scanned = 0;
+	ab->type = BRIDGE_TYPE_P2P;
+
+	dbg("acpi_pciehprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n",
+		pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+		pab->bus, (u32)devnum, (u32)funcnum, path_name);
+
+	build_a_bridge(pab, ab);
+
+	return ab;
+}
+
+static acpi_status scan_p2p_bridge(
+	acpi_handle		handle,
+	u32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*ab;
+	acpi_status		status;
+	ulong			adr = 0;
+	u8			*path_name = acpi_path_name(handle);
+	ulong			devnum, funcnum;
+	struct pci_dev		*pdev;
+
+	/* get device, function */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND)
+			err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
+		return AE_OK;
+	}
+
+	devnum = (adr >> 16) & 0xffff;
+	funcnum = adr & 0xffff;
+
+	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev)
+		return AE_OK;
+	if (!pdev->subordinate)
+		return AE_OK;
+
+	ab = add_p2p_bridge(handle, pab, adr);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					(u32)1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static struct acpi_bridge * add_host_bridge(
+	acpi_handle handle,
+	ulong	segnum,
+	ulong	busnum
+	)
+{
+	ulong			adr = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get device, function: host br adr is always 0000 though.  */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
+		return NULL;
+	}
+	dbg("acpi_pciehprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, 
+		(u32)busnum, (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_pciehprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	ab->handle = handle;
+	ab->seg = (int)segnum;
+	ab->bus = ab->pbus = (int)busnum;
+	ab->pdevice = (int)(adr >> 16) & 0xffff;
+	ab->pfunction = (int)(adr & 0xffff);
+	ab->scanned = 0;
+	ab->type = BRIDGE_TYPE_HOST;
+
+	/* get root pci bridge's current resources */
+	status = acpi_get_crs(ab);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s evaluate _CRS fail=0x%x\n", path_name, status);
+		kfree(ab);
+		return NULL;
+	}
+
+	status = pci_osc_control_set (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); 
+	if (ACPI_FAILURE(status)) {
+		err("%s: status %x\n", __FUNCTION__, status);
+		osc_run_status = (status == AE_NOT_FOUND) ? OSC_NOT_EXIST : OSC_RUN_FAILED;
+	} else {
+		osc_run_status = NC_RUN_SUCCESS;
+	}	
+	dbg("%s: osc_run_status %x\n", __FUNCTION__, osc_run_status);
+	
+	build_a_bridge(ab, ab);
+
+	return ab;
+}
+
+static acpi_status acpi_scan_from_root_pci_callback (
+	acpi_handle	handle,
+	u32			Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		segnum = 0;
+	ulong		busnum = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			err("acpi_pciehprm:%s evaluate _SEG fail=0x%x\n", path_name, status);
+			return status;
+		}
+		segnum = 0;
+	}
+
+	/* get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s evaluate _BBN fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	ab = add_host_bridge(handle, segnum, busnum);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static int pciehprm_acpi_scan_pci (void)
+{
+	acpi_status	status;
+
+	/*
+	 * TBD: traverse LDM device tree with the help of
+	 *  unified ACPI augmented for php device population.
+	 */
+	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
+				acpi_scan_from_root_pci_callback,
+				NULL,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:get_device PCI ROOT HID fail=0x%x\n", status);
+		return -1;
+	}
+
+	return 0;
+}
+
+int pciehprm_init(enum php_ctlr_type ctlr_type)
+{
+	int	rc;
+
+	if (ctlr_type != PCI)
+		return -ENODEV;
+
+	dbg("pciehprm ACPI init <enter>\n");
+	acpi_bridges_head = NULL;
+
+	/* construct PCI bus:device tree of acpi_handles */
+	rc = pciehprm_acpi_scan_pci();
+	if (rc)
+		return rc;
+
+	if ((oshp_run_status != NC_RUN_SUCCESS) && (osc_run_status != NC_RUN_SUCCESS)) {
+		err("Fails to gain control of native hot-plug\n");
+		rc = -ENODEV;
+	}
+
+	dbg("pciehprm ACPI init %s\n", (rc)?"fail":"success");
+	return rc;
+}
+
+static void free_a_slot(struct acpi_php_slot *aps)
+{
+	dbg("        free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun);
+
+	free_pci_resource (aps->io_head);
+	free_pci_resource (aps->bus_head);
+	free_pci_resource (aps->mem_head);
+	free_pci_resource (aps->p_mem_head);
+
+	kfree(aps);
+}
+
+static void free_a_bridge( struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot	*aps, *next;
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
+		break;
+	};
+
+	/* free slots first */
+	for (aps = ab->slots; aps; aps = next) {
+		next = aps->next;
+		free_a_slot(aps);
+	}
+
+	free_pci_resource (ab->io_head);
+	free_pci_resource (ab->tio_head);
+	free_pci_resource (ab->bus_head);
+	free_pci_resource (ab->tbus_head);
+	free_pci_resource (ab->mem_head);
+	free_pci_resource (ab->tmem_head);
+	free_pci_resource (ab->p_mem_head);
+	free_pci_resource (ab->tp_mem_head);
+
+	kfree(ab);
+}
+
+static void pciehprm_free_bridges ( struct acpi_bridge	*ab)
+{
+	if (!ab)
+		return;
+
+	if (ab->child)
+		pciehprm_free_bridges (ab->child);
+
+	if (ab->next)
+		pciehprm_free_bridges (ab->next);
+
+	free_a_bridge(ab);
+}
+
+void pciehprm_cleanup(void)
+{
+	pciehprm_free_bridges (acpi_bridges_head);
+}
+
+static int get_number_of_slots (
+	struct acpi_bridge	*ab,
+	int				selfonly
+	)
+{
+	struct acpi_php_slot	*aps;
+	int	prev_slot = -1;
+	int	slot_num = 0;
+
+	for ( aps = ab->slots; aps; aps = aps->next)
+		if (aps->dev != prev_slot) {
+			prev_slot = aps->dev;
+			slot_num++;
+		}
+
+	if (ab->child)
+		slot_num += get_number_of_slots (ab->child, 0);
+
+	if (selfonly)
+		return slot_num;
+
+	if (ab->next)
+		slot_num += get_number_of_slots (ab->next, 0);
+
+	return slot_num;
+}
+
+static int print_acpi_resources (struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot		*aps;
+	int	i;
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle));
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle));
+		break;
+	};
+
+	print_pci_resources (ab);
+
+	for ( i = -1, aps = ab->slots; aps; aps = aps->next) {
+		if (aps->dev == i)
+			continue;
+		dbg("  Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun);
+		print_slot_resources(aps);
+		i = aps->dev;
+	}
+
+	if (ab->child)
+		print_acpi_resources (ab->child);
+
+	if (ab->next)
+		print_acpi_resources (ab->next);
+
+	return 0;
+}
+
+int pciehprm_print_pirt(void)
+{
+	dbg("PCIEHPRM ACPI Slots\n");
+	if (acpi_bridges_head)
+		print_acpi_resources (acpi_bridges_head);
+
+	return 0;
+}
+
+static struct acpi_php_slot * get_acpi_slot (
+	struct acpi_bridge *ab,
+	u32 sun
+	)
+{
+	struct acpi_php_slot	*aps = NULL;
+
+	for ( aps = ab->slots; aps; aps = aps->next)
+		if (aps->sun == sun)
+			return aps;
+
+	if (!aps && ab->child) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun);
+		if (aps)
+			return aps;
+	}
+
+	if (!aps && ab->next) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun);
+		if (aps)
+			return aps;
+	}
+
+	return aps;
+
+}
+
+#if 0
+void * pciehprm_get_slot(struct slot *slot)
+{
+	struct acpi_bridge	*ab = acpi_bridges_head;
+	struct acpi_php_slot	*aps = get_acpi_slot (ab, slot->number);
+
+	aps->slot = slot;
+
+	dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun);
+
+	return (void *)aps;
+}
+#endif
+
+static void pciehprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func->bus_head);
+	}
+	if (func->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func->io_head);
+	}
+	if (func->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func->mem_head);
+	}
+	if (func->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func->p_mem_head);
+	}
+}
+
+static void pciehprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl->bus_head);
+	}
+	if (ctrl->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl->io_head);
+	}
+	if (ctrl->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl->mem_head);
+	}
+	if (ctrl->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl->p_mem_head);
+	}
+}
+
+static int pciehprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = pciehprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = pciehprm_delete_resources (&ctrl->bus_head, func->bus_head);
+		rc |= pciehprm_delete_resources (&ctrl->io_head, func->io_head);
+		rc |= pciehprm_delete_resources (&ctrl->mem_head, func->mem_head);
+		rc |= pciehprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func, new_func;
+	int busn = ctrl->slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn < 32; devn++) {
+		for (funn = 0; funn < 8; funn++) {
+			/*
+			if (devn == ctrl->device && funn == ctrl->function)
+				continue;
+			*/
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+			pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid);
+
+			if (vid != 0xFFFFFFFF) {
+				dbg("%s: vid = %x\n", __FUNCTION__, vid);
+				func = pciehp_slot_find(busn, devn, funn);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					pciehprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					pciehprm_dump_func_res(func);
+				}
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int bind_pci_resources(
+	struct controller 	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int		status = 0;
+
+	if (ab->bus_head) {
+		dbg("bapr:  BUS Resources add on PCI 0x%x\n", ab->bus);
+		status = pciehprm_add_resources (&ctrl->bus_head, ab->bus_head);
+		if (pciehprm_delete_resources (&ab->bus_head, ctrl->bus_head))
+			warn("bapr:  cannot sub BUS Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No BUS Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->io_head) {
+		dbg("bapr:  IO Resources add on PCI 0x%x\n", ab->bus);
+		status = pciehprm_add_resources (&ctrl->io_head, ab->io_head);
+		if (pciehprm_delete_resources (&ab->io_head, ctrl->io_head))
+			warn("bapr:  cannot sub IO Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No  IO Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->mem_head) {
+		dbg("bapr:  MEM Resources add on PCI 0x%x\n", ab->bus);
+		status = pciehprm_add_resources (&ctrl->mem_head, ab->mem_head);
+		if (pciehprm_delete_resources (&ab->mem_head, ctrl->mem_head))
+			warn("bapr:  cannot sub MEM Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No MEM Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->p_mem_head) {
+		dbg("bapr:  PMEM Resources add on PCI 0x%x\n", ab->bus);
+		status = pciehprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head);
+		if (pciehprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head))
+			warn("bapr:  cannot sub PMEM Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No PMEM Resource on PCI 0x%x.\n", ab->bus);
+
+	return status;
+}
+
+static int no_pci_resources( struct acpi_bridge *ab)
+{
+	return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head);
+}
+
+static int find_pci_bridge_resources (
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+	struct pci_func func;
+
+	memset(&func, 0, sizeof(struct pci_func));
+
+	func.bus = ab->pbus;
+	func.device = ab->pdevice;
+	func.function = ab->pfunction;
+	func.is_a_board = 1;
+
+	/* Get used resources for this PCI bridge */
+	rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD);
+
+	ab->io_head = func.io_head;
+	ab->mem_head = func.mem_head;
+	ab->p_mem_head = func.p_mem_head;
+	ab->bus_head = func.bus_head;
+	if (ab->bus_head)
+		pciehprm_delete_resource(&ab->bus_head, ctrl->pci_dev->subordinate->number, 1);
+
+	return rc;
+}
+
+static int get_pci_resources_from_bridge(
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+
+	dbg("grfb:  Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus);
+
+	rc = find_pci_bridge_resources (ctrl, ab);
+
+	pciehp_resource_sort_and_combine(&ab->bus_head);
+	pciehp_resource_sort_and_combine(&ab->io_head);
+	pciehp_resource_sort_and_combine(&ab->mem_head);
+	pciehp_resource_sort_and_combine(&ab->p_mem_head);
+
+	pciehprm_add_resources (&ab->tbus_head, ab->bus_head);
+	pciehprm_add_resources (&ab->tio_head, ab->io_head);
+	pciehprm_add_resources (&ab->tmem_head, ab->mem_head);
+	pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
+
+	return rc;
+}
+
+static int get_pci_resources(
+	struct controller	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int	rc = 0;
+
+	if (no_pci_resources(ab)) {
+		dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus);
+		rc = get_pci_resources_from_bridge(ctrl, ab);
+	}
+
+	return rc;
+}
+
+/*
+ * Get resources for this ctrl.
+ *  1. get total resources from ACPI _CRS or bridge (this ctrl)
+ *  2. find used resources of existing adapters
+ *	3. subtract used resources from total resources
+ */
+int pciehprm_find_available_resources( struct controller *ctrl)
+{
+	int rc = 0;
+	struct acpi_bridge	*ab;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number);
+	if (!ab) {
+		err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number);
+		return -1;
+	}
+	if (no_pci_resources(ab)) {
+		rc = get_pci_resources(ctrl, ab);
+		if (rc) {
+			err("pfar:cannot get pci resources of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number);
+			return -1;
+		}
+	}
+
+	rc = bind_pci_resources(ctrl, ab);
+	dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
+	pciehprm_dump_ctrl_res(ctrl);
+
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
+	pciehprm_dump_ctrl_res(ctrl);
+
+	return rc;
+}
+
+int pciehprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_bus lpci_bus, *pci_bus;
+	int				rc = 0;
+	unsigned int	devfn;
+	u8				cls= 0x08;	/* default cache line size	*/
+	u8				lt = 0x40;	/* default latency timer	*/
+	u8				ep = 0;
+	u8				es = 0;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+
+	if (ab) {
+		if (ab->_hpp) {
+			lt  = (u8)ab->_hpp->latency_timer;
+			cls = (u8)ab->_hpp->cache_line_size;
+			ep  = (u8)ab->_hpp->enable_perr;
+			es  = (u8)ab->_hpp->enable_serr;
+		} else
+			dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
+	} else
+		dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
+
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt);
+	}
+
+	/* set base Latency Timer */
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt);
+	dbg("  set latency timer  =0x%02x: %x\n", lt, rc);
+
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls);
+	dbg("  set cache_line_size=0x%02x: %x\n", cls, rc);
+
+	return rc;
+}
+
+void pciehprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, cmd, bcommand, bcmd;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct acpi_bridge	*ab;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+	}
+
+	cmd = command  = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	bcmd = bcommand  = bcommand | PCI_BRIDGE_CTL_NO_ISA;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+	if (ab) {
+		if (ab->_hpp) {
+			if (ab->_hpp->enable_perr) {
+				command |= PCI_COMMAND_PARITY;
+				bcommand |= PCI_BRIDGE_CTL_PARITY;
+			} else {
+				command &= ~PCI_COMMAND_PARITY;
+				bcommand &= ~PCI_BRIDGE_CTL_PARITY;
+			}
+			if (ab->_hpp->enable_serr) {
+				command |= PCI_COMMAND_SERR;
+				bcommand |= PCI_BRIDGE_CTL_SERR;
+			} else {
+				command &= ~PCI_COMMAND_SERR;
+				bcommand &= ~PCI_BRIDGE_CTL_SERR;
+			}
+		} else
+			dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
+	} else
+		dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
+
+	if (command != cmd) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+	}
+	if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.c b/drivers/pci/hotplug/pciehprm_nonacpi.c
new file mode 100644
index 0000000..79a0aa6
--- /dev/null
+++ b/drivers/pci/hotplug/pciehprm_nonacpi.c
@@ -0,0 +1,501 @@
+/*
+ * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include "pciehp.h"
+#include "pciehprm.h"
+#include "pciehprm_nonacpi.h"
+
+
+void pciehprm_cleanup(void)
+{
+	return;
+}
+
+int pciehprm_print_pirt(void)
+{
+	return 0;
+}
+
+int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+
+	*sun = (u8) (ctrl->first_slot);
+	return 0;
+}
+
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res->next)
+		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
+}
+
+
+static void phprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func->bus_head);
+	}
+	if (func->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func->io_head);
+	}
+	if (func->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func->mem_head);
+	}
+	if (func->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func->p_mem_head);
+	}
+}
+
+static int phprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int phprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	pciehp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int phprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res->next)
+		phprm_delete_resource(aprh, res->base, res->length);
+
+	return 0;
+}
+
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = phprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = phprm_delete_resources (&ctrl->bus_head, func->bus_head);
+		rc |= phprm_delete_resources (&ctrl->io_head, func->io_head);
+		rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head);
+		rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int pciehprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	pciehp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func, new_func;
+	int busn = ctrl->slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn < 32; devn++) {
+		for (funn = 0; funn < 8; funn++) {
+			/*
+			if (devn == ctrl->device && funn == ctrl->function)
+				continue;
+			*/
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+
+			pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid);
+
+			if (vid != 0xFFFFFFFF) {
+				dbg("%s: vid = %x bus %x dev %x fun %x\n", __FUNCTION__,
+				vid, busn, devn, funn);
+				func = pciehp_slot_find(busn, devn, funn);
+				dbg("%s: func = %p\n", __FUNCTION__,func);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					phprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					phprm_dump_func_res(func);
+				}
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void phprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl->bus_head);
+	}
+	if (ctrl->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl->io_head);
+	}
+	if (ctrl->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl->mem_head);
+	}
+	if (ctrl->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl->p_mem_head);
+	}
+}
+
+/*
+ * phprm_find_available_resources
+ *
+ *  Finds available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *  this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */
+int pciehprm_find_available_resources(struct controller *ctrl)
+{
+	struct pci_func func;
+	u32 rc;
+
+	memset(&func, 0, sizeof(struct pci_func));
+
+	func.bus = ctrl->bus;
+	func.device = ctrl->device;
+	func.function = ctrl->function;
+	func.is_a_board = 1;
+
+	/* Get resources for this PCI bridge */
+	rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD);
+	dbg("%s: pciehp_save_used_resources rc = %d\n", __FUNCTION__, rc);
+
+	if (func.mem_head)
+		func.mem_head->next = ctrl->mem_head;
+	ctrl->mem_head = func.mem_head;
+
+	if (func.p_mem_head)
+		func.p_mem_head->next = ctrl->p_mem_head;
+	ctrl->p_mem_head = func.p_mem_head;
+
+	if (func.io_head)
+		func.io_head->next = ctrl->io_head;
+	ctrl->io_head = func.io_head;
+
+	if(func.bus_head)
+		func.bus_head->next = ctrl->bus_head;
+	ctrl->bus_head = func.bus_head;
+
+	if (ctrl->bus_head)
+		pciehprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1);
+	
+	dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
+	phprm_dump_ctrl_res(ctrl);
+
+	dbg("%s: before bind_pci_resources_to slots\n", __FUNCTION__);
+
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
+	phprm_dump_ctrl_res(ctrl);
+
+	return (rc);
+}
+
+int pciehprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type)
+{
+	u32 rc;
+	u8 temp_byte;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int	devfn;
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	temp_byte = 0x40;	/* hard coded value for LT */
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+
+		if (rc) {
+			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, 
+				func->bus, func->device, func->function);
+			return rc;
+		}
+	}
+
+	/* set base Latency Timer */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+
+	if (rc) {
+		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+		return rc;
+	}
+
+	/* set Cache Line size */
+	temp_byte = 0x08;	/* hard coded value for CLS */
+
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+
+	if (rc) {
+		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+	}
+
+	/* set enable_perr */
+	/* set enable_serr */
+
+	return rc;
+}
+
+void pciehprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, bcommand;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+
+	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
+		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+
+	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+
+		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
+			| PCI_BRIDGE_CTL_NO_ISA;
+
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
+static int legacy_pciehprm_init_pci(void)
+{
+	return 0;
+}
+
+int pciehprm_init(enum php_ctlr_type ctrl_type)
+{
+	int retval;
+
+	switch (ctrl_type) {
+	case PCI:
+		retval = legacy_pciehprm_init_pci();
+		break;
+	default:
+		retval = -ENODEV;
+		break;
+	}
+
+	return retval;
+}
diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.h b/drivers/pci/hotplug/pciehprm_nonacpi.h
new file mode 100644
index 0000000..87c90e8
--- /dev/null
+++ b/drivers/pci/hotplug/pciehprm_nonacpi.h
@@ -0,0 +1,56 @@
+/*
+ * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _PCIEHPRM_NONACPI_H_
+#define _PCIEHPRM_NONACPI_H_
+
+struct irq_info {
+	u8 bus, devfn;		/* bus, device and function */
+	struct {
+		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;	/* Available IRQs */
+	} __attribute__ ((packed)) irq[4];
+	u8 slot;		/* slot number, 0=onboard */
+	u8 rfu;
+} __attribute__ ((packed));
+
+struct irq_routing_table {
+	u32 signature;		/* PIRQ_SIGNATURE should be here */
+	u16 version;		/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
+	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;	/* Crap */
+	u8 rfu[11];
+	u8 checksum;		/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__ ((packed));
+
+#endif				/* _PCIEHPRM_NONACPI_H_ */
diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c
new file mode 100644
index 0000000..6605d6b
--- /dev/null
+++ b/drivers/pci/hotplug/pcihp_skeleton.c
@@ -0,0 +1,375 @@
+/*
+ * PCI Hot Plug Controller Skeleton Driver - 0.2
+ *
+ * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001,2003 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is to be used as a skeleton driver to be show how to interface
+ * with the pci hotplug core easily.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+
+struct slot {
+	u8 number;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head slot_list;
+};
+
+static LIST_HEAD(slot_list);
+
+#define MY_NAME	"pcihp_skeleton"
+
+#define dbg(format, arg...)					\
+	do {							\
+		if (debug)					\
+			printk (KERN_DEBUG "%s: " format "\n",	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+
+
+
+/* local variables */
+static int debug;
+static int num_slots;
+
+#define DRIVER_VERSION	"0.3"
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <greg@kroah.com>"
+#define DRIVER_DESC	"Hot Plug PCI Controller Skeleton Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int hardware_test	(struct hotplug_slot *slot, u32 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops skel_hotplug_slot_ops = {
+	.owner =		THIS_MODULE,
+	.enable_slot =		enable_slot,
+	.disable_slot =		disable_slot,
+	.set_attention_status =	set_attention_status,
+	.hardware_test =	hardware_test,
+	.get_power_status =	get_power_status,
+	.get_attention_status =	get_attention_status,
+	.get_latch_status =	get_latch_status,
+	.get_adapter_status =	get_adapter_status,
+};
+
+static int enable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/*
+	 * Fill in code here to enable the specified slot
+	 */
+
+	return retval;
+}
+
+
+static int disable_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/*
+	 * Fill in code here to disable the specified slot
+	 */
+
+	return retval;
+}
+
+static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	switch (status) {
+		case 0:
+			/*
+			 * Fill in code here to turn light off
+			 */
+			break;
+
+		case 1:
+		default:
+			/*
+			 * Fill in code here to turn light on
+			 */
+			break;
+	}
+
+	return retval;
+}
+
+static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	switch (value) {
+		case 0:
+			/* Specify a test here */
+			break;
+		case 1:
+			/* Specify another test here */
+			break;
+	}
+
+	return retval;
+}
+
+static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/*
+	 * Fill in logic to get the current power status of the specific
+	 * slot and store it in the *value location.
+	 */
+
+	return retval;
+}
+
+static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/*
+	 * Fill in logic to get the current attention status of the specific
+	 * slot and store it in the *value location.
+	 */
+
+	return retval;
+}
+
+static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/*
+	 * Fill in logic to get the current latch status of the specific
+	 * slot and store it in the *value location.
+	 */
+
+	return retval;
+}
+
+static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = hotplug_slot->private;
+	int retval = 0;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	/*
+	 * Fill in logic to get the current adapter status of the specific
+	 * slot and store it in the *value location.
+	 */
+
+	return retval;
+}
+
+static void release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	kfree(slot);
+}
+
+#define SLOT_NAME_SIZE	10
+static void make_slot_name(struct slot *slot)
+{
+	/*
+	 * Stupid way to make a filename out of the slot name.
+	 * replace this if your hardware provides a better way to name slots.
+	 */
+	snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", slot->number);
+}
+
+/**
+ * init_slots - initialize 'struct slot' structures for each slot
+ *
+ */
+static int __init init_slots(void)
+{
+	struct slot *slot;
+	struct hotplug_slot *hotplug_slot;
+	struct hotplug_slot_info *info;
+	char *name;
+	int retval = -ENOMEM;
+	int i;
+
+	/*
+	 * Create a structure for each slot, and register that slot
+	 * with the pci_hotplug subsystem.
+	 */
+	for (i = 0; i < num_slots; ++i) {
+		slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
+		if (!slot)
+			goto error;
+		memset(slot, 0, sizeof(struct slot));
+
+		hotplug_slot = kmalloc(sizeof(struct hotplug_slot),
+					GFP_KERNEL);
+		if (!hotplug_slot)
+			goto error_slot;
+		memset(hotplug_slot, 0, sizeof (struct hotplug_slot));
+		slot->hotplug_slot = hotplug_slot;
+
+		info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+		if (!info)
+			goto error_hpslot;
+		memset(info, 0, sizeof (struct hotplug_slot_info));
+		hotplug_slot->info = info;
+
+		name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!name)
+			goto error_info;
+		hotplug_slot->name = name;
+
+		slot->number = i;
+
+		hotplug_slot->private = slot;
+		hotplug_slot->release = &release_slot;
+		make_slot_name(slot);
+		hotplug_slot->ops = &skel_hotplug_slot_ops;
+		
+		/*
+		 * Initilize the slot info structure with some known
+		 * good values.
+		 */
+		info->power_status = get_power_status(slot);
+		info->attention_status = get_attention_status(slot);
+		info->latch_status = get_latch_status(slot);
+		info->adapter_status = get_adapter_status(slot);
+		
+		dbg("registering slot %d\n", i);
+		retval = pci_hp_register(slot->hotplug_slot);
+		if (retval) {
+			err("pci_hp_register failed with error %d\n", retval);
+			goto error_name;
+		}
+
+		/* add slot to our internal list */
+		list_add(&slot->slot_list, &slot_list);
+	}
+
+	return 0;
+error_name:
+	kfree(name);
+error_info:
+	kfree(info);
+error_hpslot:
+	kfree(hotplug_slot);
+error_slot:
+	kfree(slot);
+error:
+	return retval;
+}
+
+static void __exit cleanup_slots(void)
+{
+	struct list_head *tmp;
+	struct list_head *next;
+	struct slot *slot;
+
+	/*
+	 * Unregister all of our slots with the pci_hotplug subsystem.
+	 * Memory will be freed in release_slot() callback after slot's
+	 * lifespan is finished.
+	 */
+	list_for_each_safe(tmp, next, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		list_del(&slot->slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
+	}
+}
+		
+static int __init pcihp_skel_init(void)
+{
+	int retval;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+	/*
+	 * Do specific initialization stuff for your driver here
+	 * Like initializing your controller hardware (if any) and
+	 * determining the number of slots you have in the system
+	 * right now.
+	 */
+	num_slots = 5;
+
+	return init_slots();
+}
+
+static void __exit pcihp_skel_exit(void)
+{
+	/*
+	 * Clean everything up.
+	 */
+	cleanup_slots();
+}
+
+module_init(pcihp_skel_init);
+module_exit(pcihp_skel_exit);
diff --git a/drivers/pci/hotplug/rpadlpar.h b/drivers/pci/hotplug/rpadlpar.h
new file mode 100644
index 0000000..4a0a59b
--- /dev/null
+++ b/drivers/pci/hotplug/rpadlpar.h
@@ -0,0 +1,24 @@
+/*
+ * Interface for Dynamic Logical Partitioning of I/O Slots on
+ * RPA-compliant PPC64 platform.
+ *
+ * John Rose <johnrose@austin.ibm.com>
+ * October 2003
+ *
+ * Copyright (C) 2003 IBM.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#ifndef _RPADLPAR_IO_H_
+#define _RPADLPAR_IO_H_
+
+extern int dlpar_sysfs_init(void);
+extern void dlpar_sysfs_exit(void);
+
+extern int dlpar_add_slot(char *drc_name);
+extern int dlpar_remove_slot(char *drc_name);
+
+#endif
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
new file mode 100644
index 0000000..86b384e
--- /dev/null
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -0,0 +1,503 @@
+/*
+ * Interface for Dynamic Logical Partitioning of I/O Slots on
+ * RPA-compliant PPC64 platform.
+ *
+ * John Rose <johnrose@austin.ibm.com>
+ * Linda Xie <lxie@us.ibm.com>
+ *
+ * October 2003
+ *
+ * Copyright (C) 2003 IBM.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/pci-bridge.h>
+#include <asm/semaphore.h>
+#include <asm/rtas.h>
+#include "../pci.h"
+#include "rpaphp.h"
+#include "rpadlpar.h"
+
+static DECLARE_MUTEX(rpadlpar_sem);
+
+#define NODE_TYPE_VIO  1
+#define NODE_TYPE_SLOT 2
+#define NODE_TYPE_PHB  3
+
+static struct device_node *find_php_slot_vio_node(char *drc_name)
+{
+	struct device_node *child;
+	struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
+	char *loc_code;
+
+	if (!parent)
+		return NULL;
+
+	for (child = of_get_next_child(parent, NULL);
+		child; child = of_get_next_child(parent, child)) {
+		loc_code = get_property(child, "ibm,loc-code", NULL);
+		if (loc_code && !strncmp(loc_code, drc_name, strlen(drc_name)))
+			return child;
+	}
+
+	return NULL;
+}
+
+/* Find dlpar-capable pci node that contains the specified name and type */
+static struct device_node *find_php_slot_pci_node(char *drc_name,
+						  char *drc_type)
+{
+	struct device_node *np = NULL;
+	char *name;
+	char *type;
+	int rc;
+
+	while ((np = of_find_node_by_type(np, "pci"))) {
+		rc = rpaphp_get_drc_props(np, NULL, &name, &type, NULL);
+		if (rc == 0)
+			if (!strcmp(drc_name, name) && !strcmp(drc_type, type))
+				break;
+	}
+
+	return np;
+}
+
+static struct device_node *find_newly_added_node(char *drc_name, int *node_type)
+{
+	struct device_node *dn;
+
+	dn = find_php_slot_pci_node(drc_name, "SLOT");
+	if (dn) {
+		*node_type = NODE_TYPE_SLOT;
+		return dn;
+	}
+
+	dn = find_php_slot_pci_node(drc_name, "PHB");
+	if (dn) {
+		*node_type = NODE_TYPE_PHB;
+		return dn;
+	}
+
+	dn = find_php_slot_vio_node(drc_name);
+	if (dn) {
+		*node_type = NODE_TYPE_VIO;
+		return dn;
+	}
+
+	return NULL;
+}
+
+static struct slot *find_slot(char *drc_name)
+{
+	struct list_head *tmp, *n;
+	struct slot *slot;
+
+        list_for_each_safe(tmp, n, &rpaphp_slot_head) {
+                slot = list_entry(tmp, struct slot, rpaphp_slot_list);
+                if (strcmp(slot->location, drc_name) == 0)
+                        return slot;
+        }
+
+        return NULL;
+}
+
+static void rpadlpar_claim_one_bus(struct pci_bus *b)
+{
+	struct list_head *ld;
+	struct pci_bus *child_bus;
+
+	for (ld = b->devices.next; ld != &b->devices; ld = ld->next) {
+		struct pci_dev *dev = pci_dev_b(ld);
+		int i;
+
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &dev->resource[i];
+
+			if (r->parent || !r->start || !r->flags)
+				continue;
+			rpaphp_claim_resource(dev, i);
+		}
+	}
+
+	list_for_each_entry(child_bus, &b->children, node)
+		rpadlpar_claim_one_bus(child_bus);
+}
+
+static int pci_add_secondary_bus(struct device_node *dn,
+		struct pci_dev *bridge_dev)
+{
+	struct pci_controller *hose = dn->phb;
+	struct pci_bus *child;
+	u8 sec_busno;
+
+	/* Get busno of downstream bus */
+	pci_read_config_byte(bridge_dev, PCI_SECONDARY_BUS, &sec_busno);
+
+	/* Allocate and add to children of bridge_dev->bus */
+	child = pci_add_new_bus(bridge_dev->bus, bridge_dev, sec_busno);
+	if (!child) {
+		printk(KERN_ERR "%s: could not add secondary bus\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	sprintf(child->name, "PCI Bus #%02x", child->number);
+
+	/* Fixup subordinate bridge bases and resources */
+	pcibios_fixup_bus(child);
+
+	/* Claim new bus resources */
+	rpadlpar_claim_one_bus(bridge_dev->bus);
+
+	if (hose->last_busno < child->number)
+		hose->last_busno = child->number;
+
+	dn->bussubno = child->number;
+
+	/* ioremap() for child bus, which may or may not succeed */
+	remap_bus_range(child);
+
+	return 0;
+}
+
+static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
+{
+	struct pci_controller *hose = dn->phb;
+	struct pci_dev *dev = NULL;
+
+	/* Scan phb bus for EADS device, adding new one to bus->devices */
+	if (!pci_scan_single_device(hose->bus, dn->devfn)) {
+		printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__);
+		return NULL;
+	}
+
+	/* Add new devices to global lists.  Register in proc, sysfs. */
+	pci_bus_add_devices(hose->bus);
+
+	/* Confirm new bridge dev was created */
+	dev = rpaphp_find_pci_dev(dn);
+	if (!dev) {
+		printk(KERN_ERR "%s: failed to add pci device\n", __FUNCTION__);
+		return NULL;
+	}
+
+	if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+		printk(KERN_ERR "%s: unexpected header type %d\n",
+			__FUNCTION__, dev->hdr_type);
+		return NULL;
+	}
+
+	if (pci_add_secondary_bus(dn, dev))
+		return NULL;
+
+	return dev;
+}
+
+static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev)
+{
+	struct pci_bus *secondary_bus;
+
+	if (!bridge_dev) {
+		printk(KERN_ERR "%s: unexpected null device\n",
+			__FUNCTION__);
+		return -EINVAL;
+	}
+
+	secondary_bus = bridge_dev->subordinate;
+
+	if (unmap_bus_range(secondary_bus)) {
+		printk(KERN_ERR "%s: failed to unmap bus range\n",
+			__FUNCTION__);
+		return -ERANGE;
+	}
+
+	pci_remove_bus_device(bridge_dev);
+	return 0;
+}
+
+static inline int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
+{
+	struct pci_dev *dev;
+
+	/* Add pci bus */
+	dev = dlpar_pci_add_bus(dn);
+	if (!dev) {
+		printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__,
+			drc_name);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int dlpar_remove_root_bus(struct pci_controller *phb)
+{
+	struct pci_bus *phb_bus;
+	int rc;
+
+	phb_bus = phb->bus;
+	if (!(list_empty(&phb_bus->children) &&
+	      list_empty(&phb_bus->devices))) {
+		return -EBUSY;
+	}
+
+	rc = pcibios_remove_root_bus(phb);
+	if (rc)
+		return -EIO;
+
+	device_unregister(phb_bus->bridge);
+	pci_remove_bus(phb_bus);
+
+	return 0;
+}
+
+static int dlpar_remove_phb(struct slot *slot)
+{
+	struct pci_controller *phb;
+	struct device_node *dn;
+	int rc = 0;
+
+	dn = slot->dn;
+	if (!dn) {
+		printk(KERN_ERR "%s: unexpected NULL slot device node\n",
+				__FUNCTION__);
+		return -EIO;
+	}
+
+	phb = dn->phb;
+	if (!phb) {
+		printk(KERN_ERR "%s: unexpected NULL phb pointer\n",
+				__FUNCTION__);
+		return -EIO;
+	}
+
+	if (rpaphp_remove_slot(slot)) {
+		printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
+			__FUNCTION__, slot->location);
+		return -EIO;
+	}
+
+	rc = dlpar_remove_root_bus(phb);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static int dlpar_add_phb(struct device_node *dn)
+{
+	struct pci_controller *phb;
+
+	phb = init_phb_dynamic(dn);
+	if (!phb)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * dlpar_add_slot - DLPAR add an I/O Slot
+ * @drc_name: drc-name of newly added slot
+ *
+ * Make the hotplug module and the kernel aware
+ * of a newly added I/O Slot.
+ * Return Codes -
+ * 0			Success
+ * -ENODEV		Not a valid drc_name
+ * -EINVAL		Slot already added
+ * -ERESTARTSYS		Signalled before obtaining lock
+ * -EIO			Internal PCI Error
+ */
+int dlpar_add_slot(char *drc_name)
+{
+	struct device_node *dn = NULL;
+	int node_type;
+	int rc = 0;
+
+	if (down_interruptible(&rpadlpar_sem))
+		return -ERESTARTSYS;
+
+	/* Check for existing hotplug slot */
+	if (find_slot(drc_name)) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	dn = find_newly_added_node(drc_name, &node_type);
+	if (!dn) {
+		rc = -ENODEV;
+		goto exit;
+	}
+
+	switch (node_type) {
+		case NODE_TYPE_VIO:
+			/* Just add hotplug slot */
+			break;
+		case NODE_TYPE_SLOT:
+			rc = dlpar_add_pci_slot(drc_name, dn);
+			break;
+		case NODE_TYPE_PHB:
+			rc = dlpar_add_phb(dn);
+			break;
+		default:
+			printk("%s: unexpected node type\n", __FUNCTION__);
+			return -EIO;
+	}
+
+	if (!rc && rpaphp_add_slot(dn)) {
+		printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
+			__FUNCTION__, drc_name);
+		rc = -EIO;
+	}
+exit:
+	up(&rpadlpar_sem);
+	return rc;
+}
+
+/**
+ * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot
+ * @drc_name: drc-name of newly added slot
+ *
+ * Remove the kernel and hotplug representations
+ * of an I/O Slot.
+ * Return Codes:
+ * 0			Success
+ * -EIO			Internal  Error
+ */
+int dlpar_remove_vio_slot(struct slot *slot, char *drc_name)
+{
+	/* Remove hotplug slot */
+
+	if (rpaphp_remove_slot(slot)) {
+		printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
+			__FUNCTION__, drc_name);
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ * dlpar_remove_slot - DLPAR remove a PCI I/O Slot
+ * @drc_name: drc-name of newly added slot
+ *
+ * Remove the kernel and hotplug representations
+ * of a PCI I/O Slot.
+ * Return Codes:
+ * 0			Success
+ * -ENODEV		Not a valid drc_name
+ * -EIO			Internal PCI Error
+ */
+int dlpar_remove_pci_slot(struct slot *slot, char *drc_name)
+{
+	struct pci_dev *bridge_dev;
+
+	bridge_dev = slot->bridge;
+	if (!bridge_dev) {
+		printk(KERN_ERR "%s: unexpected null bridge device\n",
+			__FUNCTION__);
+		return -EIO;
+	}
+
+	/* Remove hotplug slot */
+	if (rpaphp_remove_slot(slot)) {
+		printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
+			__FUNCTION__, drc_name);
+		return -EIO;
+	}
+
+	/* Remove pci bus */
+
+	if (dlpar_pci_remove_bus(bridge_dev)) {
+		printk(KERN_ERR "%s: unable to remove pci bus %s\n",
+			__FUNCTION__, drc_name);
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ * dlpar_remove_slot - DLPAR remove an I/O Slot
+ * @drc_name: drc-name of newly added slot
+ *
+ * Remove the kernel and hotplug representations
+ * of an I/O Slot.
+ * Return Codes:
+ * 0			Success
+ * -ENODEV		Not a valid drc_name
+ * -EINVAL		Slot already removed
+ * -ERESTARTSYS		Signalled before obtaining lock
+ * -EIO			Internal Error
+ */
+int dlpar_remove_slot(char *drc_name)
+{
+	struct slot *slot;
+	int rc = 0;
+
+	if (down_interruptible(&rpadlpar_sem))
+		return -ERESTARTSYS;
+
+	if (!find_php_slot_vio_node(drc_name) &&
+	    !find_php_slot_pci_node(drc_name, "SLOT") &&
+	    !find_php_slot_pci_node(drc_name, "PHB")) {
+		rc = -ENODEV;
+		goto exit;
+	}
+
+	slot = find_slot(drc_name);
+	if (!slot) {
+		rc = -EINVAL;
+		goto exit;
+	}
+	
+	if (slot->type == PHB) {
+		rc = dlpar_remove_phb(slot);
+	} else {
+		switch (slot->dev_type) {
+			case PCI_DEV:
+				rc = dlpar_remove_pci_slot(slot, drc_name);
+				break;
+
+			case VIO_DEV:
+				rc = dlpar_remove_vio_slot(slot, drc_name);
+				break;
+		}
+	}
+exit:
+	up(&rpadlpar_sem);
+	return rc;
+}
+
+static inline int is_dlpar_capable(void)
+{
+	int rc = rtas_token("ibm,configure-connector");
+
+	return (int) (rc != RTAS_UNKNOWN_SERVICE);
+}
+
+int __init rpadlpar_io_init(void)
+{
+	int rc = 0;
+
+	if (!is_dlpar_capable()) {
+		printk(KERN_WARNING "%s: partition not DLPAR capable\n",
+			__FUNCTION__);
+		return -EPERM;
+	}
+
+	rc = dlpar_sysfs_init();
+	return rc;
+}
+
+void rpadlpar_io_exit(void)
+{
+	dlpar_sysfs_exit();
+	return;
+}
+
+module_init(rpadlpar_io_init);
+module_exit(rpadlpar_io_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
new file mode 100644
index 0000000..3285b82
--- /dev/null
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -0,0 +1,151 @@
+/*
+ * Interface for Dynamic Logical Partitioning of I/O Slots on
+ * RPA-compliant PPC64 platform.
+ *
+ * John Rose <johnrose@austin.ibm.com>
+ * October 2003
+ *
+ * Copyright (C) 2003 IBM.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include "pci_hotplug.h"
+#include "rpadlpar.h"
+
+#define DLPAR_KOBJ_NAME       "control"
+#define ADD_SLOT_ATTR_NAME    "add_slot"
+#define REMOVE_SLOT_ATTR_NAME "remove_slot"
+
+#define MAX_DRC_NAME_LEN 64
+
+/* Store return code of dlpar operation in attribute struct */
+struct dlpar_io_attr {
+	int rc;
+	struct attribute attr;
+	ssize_t (*store)(struct dlpar_io_attr *dlpar_attr, const char *buf,
+		size_t nbytes);
+};
+
+/* Common show callback for all attrs, display the return code
+ * of the dlpar op */
+static ssize_t
+dlpar_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+{
+	struct dlpar_io_attr *dlpar_attr = container_of(attr,
+						struct dlpar_io_attr, attr);
+	return sprintf(buf, "%d\n", dlpar_attr->rc);
+}
+
+static ssize_t
+dlpar_attr_store(struct kobject * kobj, struct attribute * attr,
+		 const char *buf, size_t nbytes)
+{
+	struct dlpar_io_attr *dlpar_attr = container_of(attr,
+						struct dlpar_io_attr, attr);
+	return dlpar_attr->store ?
+		dlpar_attr->store(dlpar_attr, buf, nbytes) : 0;
+}
+
+static struct sysfs_ops dlpar_attr_sysfs_ops = {
+	.show = dlpar_attr_show,
+	.store = dlpar_attr_store,
+};
+
+static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
+				const char *buf, size_t nbytes)
+{
+	char drc_name[MAX_DRC_NAME_LEN];
+	char *end;
+
+	if (nbytes > MAX_DRC_NAME_LEN)
+		return 0;
+
+	memcpy(drc_name, buf, nbytes);
+
+	end = strchr(drc_name, '\n');
+	if (!end)
+		end = &drc_name[nbytes];
+	*end = '\0';
+
+	dlpar_attr->rc = dlpar_add_slot(drc_name);
+
+	return nbytes;
+}
+
+static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
+		 		const char *buf, size_t nbytes)
+{
+	char drc_name[MAX_DRC_NAME_LEN];
+	char *end;
+
+	if (nbytes > MAX_DRC_NAME_LEN)
+		return 0;
+
+	memcpy(drc_name, buf, nbytes);
+
+	end = strchr(drc_name, '\n');
+	if (!end)
+		end = &drc_name[nbytes];
+	*end = '\0';
+
+	dlpar_attr->rc = dlpar_remove_slot(drc_name);
+
+	return nbytes;
+}
+
+static struct dlpar_io_attr add_slot_attr = {
+	.rc = 0,
+	.attr = { .name = ADD_SLOT_ATTR_NAME, .mode = 0644, },
+	.store = add_slot_store,
+};
+
+static struct dlpar_io_attr remove_slot_attr = {
+	.rc = 0,
+	.attr = { .name = REMOVE_SLOT_ATTR_NAME, .mode = 0644},
+	.store = remove_slot_store,
+};
+
+static struct attribute *default_attrs[] = {
+	&add_slot_attr.attr,
+	&remove_slot_attr.attr,
+	NULL,
+};
+
+static void dlpar_io_release(struct kobject *kobj)
+{
+	/* noop */
+	return;
+}
+
+struct kobj_type ktype_dlpar_io = {
+	.release = dlpar_io_release,
+	.sysfs_ops = &dlpar_attr_sysfs_ops,
+	.default_attrs = default_attrs,
+};
+
+struct kset dlpar_io_kset = {
+	.subsys = &pci_hotplug_slots_subsys,
+	.kobj = {.name = DLPAR_KOBJ_NAME, .ktype=&ktype_dlpar_io,},
+	.ktype = &ktype_dlpar_io,
+};
+
+int dlpar_sysfs_init(void)
+{
+	if (kset_register(&dlpar_io_kset)) {
+		printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
+				dlpar_io_kset.kobj.name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void dlpar_sysfs_exit(void)
+{
+	kset_unregister(&dlpar_io_kset);
+}
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
new file mode 100644
index 0000000..81746e6
--- /dev/null
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -0,0 +1,138 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
+ *
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>,
+ *
+ */
+
+#ifndef _PPC64PHP_H
+#define _PPC64PHP_H
+
+#include <linux/pci.h>
+#include "pci_hotplug.h"
+
+#define	PHB     2
+#define	HOTPLUG	1
+#define	EMBEDDED 0
+
+#define DR_INDICATOR 9002
+#define DR_ENTITY_SENSE 9003
+
+#define POWER_ON	100
+#define POWER_OFF	0
+
+#define LED_OFF		0
+#define LED_ON		1	/* continuous on */
+#define LED_ID		2	/* slow blinking */
+#define LED_ACTION	3	/* fast blinking */
+
+/* Sensor values from rtas_get-sensor */
+#define EMPTY           0	/* No card in slot */
+#define PRESENT         1	/* Card in slot */
+
+#define MY_NAME "rpaphp"
+extern int debug;
+#define dbg(format, arg...)					\
+	do {							\
+		if (debug)					\
+			printk(KERN_DEBUG "%s: " format,	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+
+/* slot types */
+#define VIO_DEV	1
+#define PCI_DEV	2
+
+/* slot states */
+
+#define	NOT_VALID	3
+#define	NOT_CONFIGURED	2
+#define	CONFIGURED	1
+#define	EMPTY		0
+
+struct rpaphp_pci_func {
+	struct pci_dev *pci_dev;
+	struct list_head sibling;
+};
+
+/*
+ * struct slot - slot information for each *physical* slot
+ */
+struct slot {
+	struct list_head rpaphp_slot_list;
+	int state;
+	u32 index;
+	u32 type;
+	u32 power_domain;
+	char *name;
+	char *location;
+	u8 removable;
+	u8 dev_type;		/* VIO or PCI */
+	struct device_node *dn;	/* slot's device_node in OFDT */
+				/* dn has phb info */
+	struct pci_dev *bridge;	/* slot's pci_dev in pci_devices */
+	union {
+		struct list_head *pci_devs; /* pci_devs in PCI slot */
+		struct vio_dev *vio_dev; /* vio_dev in VIO slot */
+	} dev;
+	struct hotplug_slot *hotplug_slot;
+};
+
+extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops;
+extern struct list_head rpaphp_slot_head;
+extern int num_slots;
+
+/* function prototypes */
+
+/* rpaphp_pci.c */
+extern struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn);
+extern int rpaphp_claim_resource(struct pci_dev *dev, int resource);
+extern int rpaphp_enable_pci_slot(struct slot *slot);
+extern int register_pci_slot(struct slot *slot);
+extern int rpaphp_unconfig_pci_adapter(struct slot *slot);
+extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value);
+extern struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev);
+
+/* rpaphp_core.c */
+extern int rpaphp_add_slot(struct device_node *dn);
+extern int rpaphp_remove_slot(struct slot *slot);
+extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
+		char **drc_name, char **drc_type, int *drc_power_domain);
+
+/* rpaphp_vio.c */
+extern int rpaphp_get_vio_adapter_status(struct slot *slot, int is_init, u8 * value);
+extern int rpaphp_unconfig_vio_adapter(struct slot *slot);
+extern int register_vio_slot(struct device_node *dn);
+extern int rpaphp_enable_vio_slot(struct slot *slot);
+
+/* rpaphp_slot.c */
+extern void dealloc_slot_struct(struct slot *slot);
+extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
+extern int register_slot(struct slot *slot);
+extern int deregister_slot(struct slot *slot);
+extern int rpaphp_get_power_status(struct slot *slot, u8 * value);
+extern int rpaphp_set_attention_status(struct slot *slot, u8 status);
+	
+#endif				/* _PPC64PHP_H */
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
new file mode 100644
index 0000000..29117a3
--- /dev/null
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -0,0 +1,536 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <asm/eeh.h>       /* for eeh_add_device() */
+#include <asm/rtas.h>		/* rtas_call */
+#include <asm/pci-bridge.h>	/* for pci_controller */
+#include "../pci.h"		/* for pci_add_new_bus */
+				/* and pci_do_scan_bus */
+#include "rpaphp.h"
+#include "pci_hotplug.h"
+
+int debug;
+static struct semaphore rpaphp_sem;
+LIST_HEAD(rpaphp_slot_head);
+int num_slots;
+
+#define DRIVER_VERSION	"0.1"
+#define DRIVER_AUTHOR	"Linda Xie <lxie@us.ibm.com>"
+#define DRIVER_DESC	"RPA HOT Plug PCI Controller Driver"
+
+#define MAX_LOC_CODE 128
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, 0644);
+
+static int enable_slot(struct hotplug_slot *slot);
+static int disable_slot(struct hotplug_slot *slot);
+static int set_attention_status(struct hotplug_slot *slot, u8 value);
+static int get_power_status(struct hotplug_slot *slot, u8 * value);
+static int get_attention_status(struct hotplug_slot *slot, u8 * value);
+static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
+static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
+
+struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
+	.owner = THIS_MODULE,
+	.enable_slot = enable_slot,
+	.disable_slot = disable_slot,
+	.set_attention_status = set_attention_status,
+	.get_power_status = get_power_status,
+	.get_attention_status = get_attention_status,
+	.get_adapter_status = get_adapter_status,
+	.get_max_bus_speed = get_max_bus_speed,
+};
+
+static int rpaphp_get_attention_status(struct slot *slot)
+{
+	return slot->hotplug_slot->info->attention_status;
+}
+
+/**
+ * set_attention_status - set attention LED
+ * echo 0 > attention -- set LED OFF
+ * echo 1 > attention -- set LED ON
+ * echo 2 > attention -- set LED ID(identify, light is blinking)
+ *
+ */
+static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
+{
+	int retval = 0;
+	struct slot *slot = (struct slot *)hotplug_slot->private;
+
+	down(&rpaphp_sem);
+	switch (value) {
+	case 0:
+		retval = rpaphp_set_attention_status(slot, LED_OFF);
+		hotplug_slot->info->attention_status = 0;
+		break;
+	case 1:
+	default:
+		retval = rpaphp_set_attention_status(slot, LED_ON);
+		hotplug_slot->info->attention_status = 1;
+		break;
+	case 2:
+		retval = rpaphp_set_attention_status(slot, LED_ID);
+		hotplug_slot->info->attention_status = 2;
+		break;
+	}
+	up(&rpaphp_sem);
+	return retval;
+}
+
+/**
+ * get_power_status - get power status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ *
+ */
+static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int retval;
+	struct slot *slot = (struct slot *)hotplug_slot->private;
+
+	down(&rpaphp_sem);
+	retval = rpaphp_get_power_status(slot, value);
+	up(&rpaphp_sem);
+	return retval;
+}
+
+/**
+ * get_attention_status - get attention LED status
+ *
+ *
+ */
+static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int retval = 0;
+	struct slot *slot = (struct slot *)hotplug_slot->private;
+
+	down(&rpaphp_sem);
+	*value = rpaphp_get_attention_status(slot);
+	up(&rpaphp_sem);
+	return retval;
+}
+
+static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	struct slot *slot = (struct slot *)hotplug_slot->private;
+	int retval = 0;
+
+	down(&rpaphp_sem);
+	/*  have to go through this */
+	switch (slot->dev_type) {
+	case PCI_DEV:
+		retval = rpaphp_get_pci_adapter_status(slot, 0, value);
+		break;
+	case VIO_DEV:
+		retval = rpaphp_get_vio_adapter_status(slot, 0, value);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+	up(&rpaphp_sem);
+	return retval;
+}
+
+static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = (struct slot *)hotplug_slot->private;
+
+	down(&rpaphp_sem);
+	switch (slot->type) {
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+		*value = PCI_SPEED_33MHz;	/* speed for case 1-6 */
+		break;
+	case 7:
+	case 8:
+		*value = PCI_SPEED_66MHz;
+		break;
+	case 11:
+	case 14:
+		*value = PCI_SPEED_66MHz_PCIX;
+		break;
+	case 12:
+	case 15:
+		*value = PCI_SPEED_100MHz_PCIX;
+		break;
+	case 13:
+	case 16:
+		*value = PCI_SPEED_133MHz_PCIX;
+		break;
+	default:
+		*value = PCI_SPEED_UNKNOWN;
+		break;
+
+	}
+	up(&rpaphp_sem);
+	return 0;
+}
+
+int rpaphp_remove_slot(struct slot *slot)
+{
+	return deregister_slot(slot);
+}
+
+static int get_children_props(struct device_node *dn, int **drc_indexes,
+		int **drc_names, int **drc_types, int **drc_power_domains)
+{
+	int *indexes, *names;
+	int *types, *domains;
+
+	indexes = (int *) get_property(dn, "ibm,drc-indexes", NULL);
+	names = (int *) get_property(dn, "ibm,drc-names", NULL);
+	types = (int *) get_property(dn, "ibm,drc-types", NULL);
+	domains = (int *) get_property(dn, "ibm,drc-power-domains", NULL);
+
+	if (!indexes || !names || !types || !domains) {
+		/* Slot does not have dynamically-removable children */
+		return -EINVAL;
+	}
+	if (drc_indexes)
+		*drc_indexes = indexes;
+	if (drc_names)
+		/* &drc_names[1] contains NULL terminated slot names */
+		*drc_names = names;
+	if (drc_types)
+		/* &drc_types[1] contains NULL terminated slot types */
+		*drc_types = types;
+	if (drc_power_domains)
+		*drc_power_domains = domains;
+
+	return 0;
+}
+
+/* To get the DRC props describing the current node, first obtain it's
+ * my-drc-index property.  Next obtain the DRC list from it's parent.  Use
+ * the my-drc-index for correlation, and obtain the requested properties.
+ */
+int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
+		char **drc_name, char **drc_type, int *drc_power_domain)
+{
+	int *indexes, *names;
+	int *types, *domains;
+	unsigned int *my_index;
+	char *name_tmp, *type_tmp;
+	int i, rc;
+
+	my_index = (int *) get_property(dn, "ibm,my-drc-index", NULL);
+	if (!my_index) {
+		/* Node isn't DLPAR/hotplug capable */
+		return -EINVAL;
+	}
+
+	rc = get_children_props(dn->parent, &indexes, &names, &types, &domains);
+	if (rc < 0) {
+		return -EINVAL;
+	}
+
+	name_tmp = (char *) &names[1];
+	type_tmp = (char *) &types[1];
+
+	/* Iterate through parent properties, looking for my-drc-index */
+	for (i = 0; i < indexes[0]; i++) {
+		if ((unsigned int) indexes[i + 1] == *my_index) {
+			if (drc_name)
+                		*drc_name = name_tmp;
+			if (drc_type)
+				*drc_type = type_tmp;
+			if (drc_index)
+				*drc_index = *my_index;
+			if (drc_power_domain)
+				*drc_power_domain = domains[i+1];
+			return 0;
+		}
+		name_tmp += (strlen(name_tmp) + 1);
+		type_tmp += (strlen(type_tmp) + 1);
+	}
+
+	return -EINVAL;
+}
+
+static int is_php_type(char *drc_type)
+{
+	unsigned long value;
+	char *endptr;
+
+	/* PCI Hotplug nodes have an integer for drc_type */
+	value = simple_strtoul(drc_type, &endptr, 10);
+	if (endptr == drc_type)
+		return 0;
+
+	return 1;
+}
+
+static int is_php_dn(struct device_node *dn, int **indexes, int **names,
+		int **types, int **power_domains)
+{
+	int *drc_types;
+	int rc;
+
+	rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
+	if (rc >= 0) {
+		if (is_php_type((char *) &drc_types[1])) {
+			*types = drc_types;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int is_dr_dn(struct device_node *dn, int **indexes, int **names,
+		int **types, int **power_domains, int **my_drc_index)
+{
+	int rc;
+
+	*my_drc_index = (int *) get_property(dn, "ibm,my-drc-index", NULL);
+	if(!*my_drc_index)
+		return (0);
+
+	if (!dn->parent)
+		return (0);
+
+	rc = get_children_props(dn->parent, indexes, names, types,
+				power_domains);
+	return (rc >= 0);
+}
+
+static inline int is_vdevice_root(struct device_node *dn)
+{
+	return !strcmp(dn->name, "vdevice");
+}
+
+int is_dlpar_type(const char *type_str)
+{
+	/* Only register DLPAR-capable nodes of drc-type PHB or SLOT */
+	return (!strcmp(type_str, "PHB") || !strcmp(type_str, "SLOT"));
+}
+
+/****************************************************************
+ *	rpaphp not only registers PCI hotplug slots(HOTPLUG), 
+ *	but also logical DR slots(EMBEDDED).
+ *	HOTPLUG slot: An adapter can be physically added/removed. 
+ *	EMBEDDED slot: An adapter can be logically removed/added
+ *		  from/to a partition with the slot.
+ ***************************************************************/
+int rpaphp_add_slot(struct device_node *dn)
+{
+	struct slot *slot;
+	int retval = 0;
+	int i, *my_drc_index, slot_type;
+	int *indexes, *names, *types, *power_domains;
+	char *name, *type;
+
+	dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name);
+
+	if (dn->parent && is_vdevice_root(dn->parent)) {
+		/* register a VIO device */
+		retval = register_vio_slot(dn);
+		goto exit;
+	}
+
+	/* register PCI devices */
+	if (dn->name != 0 && strcmp(dn->name, "pci") == 0) {
+		if (is_php_dn(dn, &indexes, &names, &types, &power_domains))  
+			slot_type = HOTPLUG;
+		else if (is_dr_dn(dn, &indexes, &names, &types, &power_domains, &my_drc_index)) 
+			slot_type = EMBEDDED;
+		else goto exit;
+
+		name = (char *) &names[1];
+		type = (char *) &types[1];
+		for (i = 0; i < indexes[0]; i++,
+	     		name += (strlen(name) + 1), type += (strlen(type) + 1)) {
+
+			if (slot_type == HOTPLUG ||
+			    (slot_type == EMBEDDED &&
+			     indexes[i + 1] == my_drc_index[0] &&
+			     is_dlpar_type(type))) {
+				if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name,
+					       power_domains[i + 1]))) {
+					retval = -ENOMEM;
+					goto exit;
+				}
+				if (!strcmp(type, "PHB"))
+					slot->type = PHB;
+				else if (slot_type == EMBEDDED)
+					slot->type = EMBEDDED;
+				else
+					slot->type = simple_strtoul(type, NULL, 10);
+				
+				dbg("    Found drc-index:0x%x drc-name:%s drc-type:%s\n",
+					indexes[i + 1], name, type);
+
+				retval = register_pci_slot(slot);
+				if (slot_type == EMBEDDED)
+					goto exit;
+			}
+		}
+	}
+exit:
+	dbg("%s - Exit: num_slots=%d rc[%d]\n",
+	    __FUNCTION__, num_slots, retval);
+	return retval;
+}
+
+/*
+ * init_slots - initialize 'struct slot' structures for each slot
+ *
+ */
+static void init_slots(void)
+{
+	struct device_node *dn;
+
+	for (dn = find_all_nodes(); dn; dn = dn->next)
+		rpaphp_add_slot(dn);
+}
+
+static int __init init_rpa(void)
+{
+
+	init_MUTEX(&rpaphp_sem);
+
+	/* initialize internal data structure etc. */
+	init_slots();
+	if (!num_slots)
+		return -ENODEV;
+
+	return 0;
+}
+
+static void __exit cleanup_slots(void)
+{
+	struct list_head *tmp, *n;
+	struct slot *slot;
+
+	/*
+	 * Unregister all of our slots with the pci_hotplug subsystem,
+	 * and free up all memory that we had allocated.
+	 * memory will be freed in release_slot callback. 
+	 */
+
+	list_for_each_safe(tmp, n, &rpaphp_slot_head) {
+		slot = list_entry(tmp, struct slot, rpaphp_slot_list);
+		list_del(&slot->rpaphp_slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
+	}
+	return;
+}
+
+static int __init rpaphp_init(void)
+{
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	/* read all the PRA info from the system */
+	return init_rpa();
+}
+
+static void __exit rpaphp_exit(void)
+{
+	cleanup_slots();
+}
+
+static int enable_slot(struct hotplug_slot *hotplug_slot)
+{
+	int retval = 0;
+	struct slot *slot = (struct slot *)hotplug_slot->private;
+
+	if (slot->state == CONFIGURED) {
+		dbg("%s: %s is already enabled\n", __FUNCTION__, slot->name);
+		goto exit;
+	}
+
+	dbg("ENABLING SLOT %s\n", slot->name);
+	down(&rpaphp_sem);
+	switch (slot->dev_type) {
+	case PCI_DEV:
+		retval = rpaphp_enable_pci_slot(slot);
+		break;
+	case VIO_DEV:
+		retval = rpaphp_enable_vio_slot(slot);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+	up(&rpaphp_sem);
+exit:
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+	return retval;
+}
+
+static int disable_slot(struct hotplug_slot *hotplug_slot)
+{
+	int retval = -EINVAL;
+	struct slot *slot = (struct slot *)hotplug_slot->private;
+
+	dbg("%s - Entry: slot[%s]\n", __FUNCTION__, slot->name);
+
+	if (slot->state == NOT_CONFIGURED) {
+		dbg("%s: %s is already disabled\n", __FUNCTION__, slot->name);
+		goto exit;
+	}
+
+	dbg("DISABLING SLOT %s\n", slot->name);
+	down(&rpaphp_sem);
+	switch (slot->dev_type) {
+	case PCI_DEV:
+		retval = rpaphp_unconfig_pci_adapter(slot);
+		break;
+	case VIO_DEV:
+		retval = rpaphp_unconfig_vio_adapter(slot);
+		break;
+	default:
+		retval = -ENODEV;
+	}
+	up(&rpaphp_sem);
+exit:
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+	return retval;
+}
+
+module_init(rpaphp_init);
+module_exit(rpaphp_exit);
+
+EXPORT_SYMBOL_GPL(rpaphp_add_slot);
+EXPORT_SYMBOL_GPL(rpaphp_remove_slot);
+EXPORT_SYMBOL_GPL(rpaphp_slot_head);
+EXPORT_SYMBOL_GPL(rpaphp_get_drc_props);
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
new file mode 100644
index 0000000..d8305a9
--- /dev/null
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -0,0 +1,538 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>
+ *
+ */
+#include <linux/pci.h>
+#include <asm/pci-bridge.h>
+#include <asm/rtas.h>
+#include <asm/machdep.h>
+#include "../pci.h"		/* for pci_add_new_bus */
+
+#include "rpaphp.h"
+
+struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn)
+{
+	struct pci_dev *dev = NULL;
+	char bus_id[BUS_ID_SIZE];
+
+	sprintf(bus_id, "%04x:%02x:%02x.%d", dn->phb->global_number,
+		dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn));
+	for_each_pci_dev(dev) {
+		if (!strcmp(pci_name(dev), bus_id)) {
+			break;
+		}
+	}
+	return dev;
+}
+
+EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev);
+
+int rpaphp_claim_resource(struct pci_dev *dev, int resource)
+{
+	struct resource *res = &dev->resource[resource];
+	struct resource *root = pci_find_parent_resource(dev, res);
+	char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
+	int err = -EINVAL;
+
+	if (root != NULL) {
+		err = request_resource(root, res);
+	}
+
+	if (err) {
+		err("PCI: %s region %d of %s %s [%lx:%lx]\n",
+		    root ? "Address space collision on" :
+		    "No parent found for",
+		    resource, dtype, pci_name(dev), res->start, res->end);
+	}
+	return err;
+}
+
+EXPORT_SYMBOL_GPL(rpaphp_claim_resource);
+
+static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot)
+{
+	return rpaphp_find_pci_dev(slot->dn);
+}
+
+static int rpaphp_get_sensor_state(struct slot *slot, int *state)
+{
+	int rc;
+	int setlevel;
+
+	rc = rtas_get_sensor(DR_ENTITY_SENSE, slot->index, state);
+
+	if (rc < 0) {
+		if (rc == -EFAULT || rc == -EEXIST) {
+			dbg("%s: slot must be power up to get sensor-state\n",
+			    __FUNCTION__);
+
+			/* some slots have to be powered up 
+			 * before get-sensor will succeed.
+			 */
+			rc = rtas_set_power_level(slot->power_domain, POWER_ON,
+						  &setlevel);
+			if (rc < 0) {
+				dbg("%s: power on slot[%s] failed rc=%d.\n",
+				    __FUNCTION__, slot->name, rc);
+			} else {
+				rc = rtas_get_sensor(DR_ENTITY_SENSE,
+						     slot->index, state);
+			}
+		} else if (rc == -ENODEV)
+			info("%s: slot is unusable\n", __FUNCTION__);
+		else
+			err("%s failed to get sensor state\n", __FUNCTION__);
+	}
+	return rc;
+}
+
+/**
+ * get_pci_adapter_status - get the status of a slot
+ * 
+ * 0-- slot is empty
+ * 1-- adapter is configured
+ * 2-- adapter is not configured
+ * 3-- not valid
+ */
+int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value)
+{
+	int state, rc;
+ 	struct device_node *child_dn;
+ 	struct pci_dev *child_dev = NULL;
+
+	*value = NOT_VALID;
+	rc = rpaphp_get_sensor_state(slot, &state);
+	if (rc)
+		goto exit;
+
+ 	if ((state == EMPTY) || (slot->type == PHB)) {
+ 		dbg("slot is empty\n");
+ 		*value = EMPTY;
+ 	}
+ 	else if (state == PRESENT) {
+		if (!is_init) {
+			/* at run-time slot->state can be changed by */
+			/* config/unconfig adapter */
+			*value = slot->state;
+		} else {
+ 			child_dn = slot->dn->child;
+ 			if (child_dn)
+ 				child_dev = rpaphp_find_pci_dev(child_dn);
+
+ 			if (child_dev)
+ 				*value = CONFIGURED;
+ 			else if (!child_dn)
+				dbg("%s: %s is not valid OFDT node\n",
+				    __FUNCTION__, slot->dn->full_name);
+			else {
+				err("%s: can't find pdev of adapter in slot[%s]\n", 
+					__FUNCTION__, slot->dn->full_name);
+				*value = NOT_CONFIGURED;
+			}
+		}
+	}
+exit:
+	return rc;
+}
+
+/* Must be called before pci_bus_add_devices */
+static void 
+rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		/*
+		 * Skip already-present devices (which are on the
+		 * global device list.)
+		 */
+		if (list_empty(&dev->global_list)) {
+			int i;
+			
+			/* Need to setup IOMMU tables */
+			ppc_md.iommu_dev_setup(dev);
+
+			if(fix_bus)
+				pcibios_fixup_device_resources(dev, bus);
+			pci_read_irq_line(dev);
+			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+				struct resource *r = &dev->resource[i];
+
+				if (r->parent || !r->start || !r->flags)
+					continue;
+				rpaphp_claim_resource(dev, i);
+			}
+		}
+	}
+}
+
+static int rpaphp_pci_config_bridge(struct pci_dev *dev);
+
+/*****************************************************************************
+ rpaphp_pci_config_slot() will  configure all devices under the 
+ given slot->dn and return the the first pci_dev.
+ *****************************************************************************/
+static struct pci_dev *
+rpaphp_pci_config_slot(struct device_node *dn, struct pci_bus *bus)
+{
+	struct device_node *eads_first_child = dn->child;
+	struct pci_dev *dev = NULL;
+	int num;
+	
+	dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name);
+
+	if (eads_first_child) {
+		/* pci_scan_slot should find all children of EADs */
+		num = pci_scan_slot(bus, PCI_DEVFN(PCI_SLOT(eads_first_child->devfn), 0));
+		if (num) {
+			rpaphp_fixup_new_pci_devices(bus, 1); 
+			pci_bus_add_devices(bus);
+		}
+		dev = rpaphp_find_pci_dev(eads_first_child);
+		if (!dev) {
+			err("No new device found\n");
+			return NULL;
+		}
+		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 
+			rpaphp_pci_config_bridge(dev);
+	}
+	return dev;
+}
+
+static int rpaphp_pci_config_bridge(struct pci_dev *dev)
+{
+	u8 sec_busno;
+	struct pci_bus *child_bus;
+	struct pci_dev *child_dev;
+
+	dbg("Enter %s:  BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev));
+
+	/* get busno of downstream bus */
+	pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
+		
+	/* add to children of PCI bridge dev->bus */
+	child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
+	if (!child_bus) {
+		err("%s: could not add second bus\n", __FUNCTION__);
+		return -EIO;
+	}
+	sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
+	/* do pci_scan_child_bus */
+	pci_scan_child_bus(child_bus);
+
+	list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
+		eeh_add_device_late(child_dev);
+	}
+
+	 /* fixup new pci devices without touching bus struct */
+	rpaphp_fixup_new_pci_devices(child_bus, 0);
+
+	/* Make the discovered devices available */
+	pci_bus_add_devices(child_bus);
+	return 0;
+}
+
+static void enable_eeh(struct device_node *dn)
+{
+	struct device_node *sib;
+
+	for (sib = dn->child; sib; sib = sib->sibling) 
+		enable_eeh(sib);
+	eeh_add_device_early(dn);
+	return;
+	
+}
+
+static void print_slot_pci_funcs(struct slot *slot)
+{
+	struct pci_dev *dev;
+
+	if (slot->dev_type == PCI_DEV) {
+		dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, slot->name);
+		list_for_each_entry (dev, slot->dev.pci_devs, bus_list)
+			dbg("\t%s\n", pci_name(dev));
+	}
+	return;
+}
+
+static int rpaphp_config_pci_adapter(struct slot *slot)
+{
+	struct pci_bus *pci_bus;
+	struct pci_dev *dev;
+	int rc = -ENODEV;
+
+	dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
+
+	if (slot->bridge) {
+
+		pci_bus = slot->bridge->subordinate;
+		if (!pci_bus) {
+			err("%s: can't find bus structure\n", __FUNCTION__);
+			goto exit;
+		}
+		enable_eeh(slot->dn);
+		dev = rpaphp_pci_config_slot(slot->dn, pci_bus);
+		if (!dev) {
+			err("%s: can't find any devices.\n", __FUNCTION__);
+			goto exit;
+		}
+		print_slot_pci_funcs(slot);
+		rc = 0;
+	} else {
+		/* slot is not enabled */
+		err("slot doesn't have pci_dev structure\n");
+	}
+exit:
+	dbg("Exit %s:  rc=%d\n", __FUNCTION__, rc);
+	return rc;
+}
+
+static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev)
+{
+	eeh_remove_device(dev);
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		struct pci_bus *bus = dev->subordinate;
+		struct list_head *ln;
+		if (!bus)
+			return; 
+		for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+			struct pci_dev *pdev = pci_dev_b(ln);
+			if (pdev)
+				rpaphp_eeh_remove_bus_device(pdev);
+		}
+
+	}
+	return;
+}
+
+int rpaphp_unconfig_pci_adapter(struct slot *slot)
+{
+	struct pci_dev *dev;
+	int retval = 0;
+
+	list_for_each_entry(dev, slot->dev.pci_devs, bus_list)
+		rpaphp_eeh_remove_bus_device(dev);
+
+	pci_remove_behind_bridge(slot->bridge);
+	slot->state = NOT_CONFIGURED;
+	info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__,
+	     slot->name);
+	return retval;
+}
+
+static int setup_pci_hotplug_slot_info(struct slot *slot)
+{
+	dbg("%s Initilize the PCI slot's hotplug->info structure ...\n",
+	    __FUNCTION__);
+	rpaphp_get_power_status(slot, &slot->hotplug_slot->info->power_status);
+	rpaphp_get_pci_adapter_status(slot, 1,
+				      &slot->hotplug_slot->info->
+				      adapter_status);
+	if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
+		err("%s: NOT_VALID: skip dn->full_name=%s\n",
+		    __FUNCTION__, slot->dn->full_name);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int set_phb_slot_name(struct slot *slot)
+{
+	struct device_node *dn;
+	struct pci_controller *phb;
+	struct pci_bus *bus;
+
+	dn = slot->dn;
+	if (!dn) {
+		return -EINVAL;
+	}
+	phb = dn->phb;
+	if (!phb) {
+		return -EINVAL;
+	}
+	bus = phb->bus;
+	if (!bus) {
+		return -EINVAL;
+	}
+
+	sprintf(slot->name, "%04x:%02x:%02x.%x", pci_domain_nr(bus),
+			bus->number, 0, 0);
+	return 0;
+}
+
+static int setup_pci_slot(struct slot *slot)
+{
+	struct pci_bus *bus;
+	int rc;
+
+	if (slot->type == PHB) {
+		rc = set_phb_slot_name(slot);
+		if (rc < 0) {
+			err("%s: failed to set phb slot name\n", __FUNCTION__);
+			goto exit_rc;
+		}
+	} else {
+		slot->bridge = rpaphp_find_bridge_pdev(slot);
+		if (!slot->bridge) {
+			/* slot being added doesn't have pci_dev yet */
+			err("%s: no pci_dev for bridge dn %s\n",
+					__FUNCTION__, slot->name);
+			goto exit_rc;
+		}
+
+		bus = slot->bridge->subordinate;
+		if (!bus)
+			goto exit_rc;
+		slot->dev.pci_devs = &bus->devices;
+
+		dbg("%s set slot->name to %s\n",  __FUNCTION__,
+				pci_name(slot->bridge));
+		strcpy(slot->name, pci_name(slot->bridge));
+	}
+
+	/* find slot's pci_dev if it's not empty */
+	if (slot->hotplug_slot->info->adapter_status == EMPTY) {
+		slot->state = EMPTY;	/* slot is empty */
+	} else {
+		/* slot is occupied */
+		if (!(slot->dn->child)) {
+			/* non-empty slot has to have child */
+			err("%s: slot[%s]'s device_node doesn't have child for adapter\n", 
+				__FUNCTION__, slot->name);
+			goto exit_rc;
+		}
+
+		if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) {
+			dbg("%s CONFIGURING pci adapter in slot[%s]\n",  
+				__FUNCTION__, slot->name);
+			if (rpaphp_config_pci_adapter(slot)) {
+				err("%s: CONFIG pci adapter failed\n", __FUNCTION__);
+				goto exit_rc;		
+			}
+
+		} else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) {
+			err("%s: slot[%s]'s adapter_status is NOT_VALID.\n",
+				__FUNCTION__, slot->name);
+			goto exit_rc;
+		}
+		print_slot_pci_funcs(slot);
+		if (!list_empty(slot->dev.pci_devs)) {
+			slot->state = CONFIGURED;
+		} else {
+			/* DLPAR add as opposed to 
+		 	 * boot time */
+			slot->state = NOT_CONFIGURED;
+		}
+	}
+	return 0;
+exit_rc:
+	dealloc_slot_struct(slot);
+	return -EINVAL;
+}
+
+int register_pci_slot(struct slot *slot)
+{
+	int rc = -EINVAL;
+
+	slot->dev_type = PCI_DEV;
+	if ((slot->type == EMBEDDED) || (slot->type == PHB))
+		slot->removable = 0;
+	else
+		slot->removable = 1;
+	if (setup_pci_hotplug_slot_info(slot))
+		goto exit_rc;
+	if (setup_pci_slot(slot))
+		goto exit_rc;
+	rc = register_slot(slot);
+exit_rc:
+	return rc;
+}
+
+int rpaphp_enable_pci_slot(struct slot *slot)
+{
+	int retval = 0, state;
+
+	retval = rpaphp_get_sensor_state(slot, &state);
+	if (retval)
+		goto exit;
+	dbg("%s: sensor state[%d]\n", __FUNCTION__, state);
+	/* if slot is not empty, enable the adapter */
+	if (state == PRESENT) {
+		dbg("%s : slot[%s] is occupied.\n", __FUNCTION__, slot->name);
+		retval = rpaphp_config_pci_adapter(slot);
+		if (!retval) {
+			slot->state = CONFIGURED;
+			dbg("%s: PCI devices in slot[%s] has been configured\n", 
+				__FUNCTION__, slot->name);
+		} else {
+			slot->state = NOT_CONFIGURED;
+			dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
+			    __FUNCTION__, slot->name);
+		}
+	} else if (state == EMPTY) {
+		dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot->name);
+		slot->state = EMPTY;
+	} else {
+		err("%s: slot[%s] is in invalid state\n", __FUNCTION__,
+		    slot->name);
+		slot->state = NOT_VALID;
+		retval = -EINVAL;
+	}
+exit:
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+	return retval;
+}
+
+struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev)
+{
+	struct list_head	*tmp, *n;
+	struct slot		*slot;
+
+	list_for_each_safe(tmp, n, &rpaphp_slot_head) {
+		struct pci_bus *bus;
+		struct list_head *ln;
+
+		slot = list_entry(tmp, struct slot, rpaphp_slot_list);
+		if (slot->bridge == NULL) {
+			if (slot->dev_type == PCI_DEV) {
+				printk(KERN_WARNING "PCI slot missing bridge %s %s \n", 
+				                    slot->name, slot->location);
+			}
+			continue;
+		}
+
+		bus = slot->bridge->subordinate;
+		if (!bus) {
+			continue;  /* should never happen? */
+		}
+		for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+                                struct pci_dev *pdev = pci_dev_b(ln);
+				if (pdev == dev)
+					return slot->hotplug_slot;
+		}
+	}
+
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(rpaphp_find_hotplug_slot);
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
new file mode 100644
index 0000000..ff2cbf0
--- /dev/null
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -0,0 +1,267 @@
+/*
+ * RPA Virtual I/O device functions 
+ * Copyright (C) 2004 Linda Xie <lxie@us.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/pci.h>
+#include <asm/rtas.h>
+#include "rpaphp.h"
+
+static ssize_t removable_read_file (struct hotplug_slot *php_slot, char *buf)
+{
+	u8 value;
+	int retval = -ENOENT;
+	struct slot *slot = (struct slot *)php_slot->private;
+
+	if (!slot)
+		return retval;
+
+	value = slot->removable;
+	retval = sprintf (buf, "%d\n", value);
+	return retval;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_removable = {
+	.attr = {.name = "phy_removable", .mode = S_IFREG | S_IRUGO},
+	.show = removable_read_file,
+};
+
+static void rpaphp_sysfs_add_attr_removable (struct hotplug_slot *slot)
+{
+	sysfs_create_file(&slot->kobj, &hotplug_slot_attr_removable.attr);
+}
+
+static void rpaphp_sysfs_remove_attr_removable (struct hotplug_slot *slot)
+{
+	sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_removable.attr);
+}
+
+static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
+{
+        char *value;
+        int retval = -ENOENT;
+	struct slot *slot = (struct slot *)php_slot->private;
+
+	if (!slot)
+		return retval;
+
+        value = slot->location;
+        retval = sprintf (buf, "%s\n", value);
+        return retval;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_location = {
+	.attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO},
+	.show = location_read_file,
+};
+
+static void rpaphp_sysfs_add_attr_location (struct hotplug_slot *slot)
+{
+	sysfs_create_file(&slot->kobj, &hotplug_slot_attr_location.attr);
+}
+
+static void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot)
+{
+	sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_location.attr);
+}
+
+/* free up the memory used by a slot */
+static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = (struct slot *) hotplug_slot->private;
+
+	dealloc_slot_struct(slot);
+}
+
+void dealloc_slot_struct(struct slot *slot)
+{
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	kfree(slot);
+	return;
+}
+
+struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name,
+		  int power_domain)
+{
+	struct slot *slot;
+	
+	slot = kmalloc(sizeof (struct slot), GFP_KERNEL);
+	if (!slot)
+		goto error_nomem;
+	memset(slot, 0, sizeof (struct slot));
+	slot->hotplug_slot = kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
+	if (!slot->hotplug_slot)
+		goto error_slot;	
+	memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+	slot->hotplug_slot->info = kmalloc(sizeof (struct hotplug_slot_info),
+					   GFP_KERNEL);
+	if (!slot->hotplug_slot->info)
+		goto error_hpslot;
+	memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+	slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL);
+	if (!slot->hotplug_slot->name)
+		goto error_info;	
+	slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
+	if (!slot->location)
+		goto error_name;
+	slot->name = slot->hotplug_slot->name;
+	slot->dn = dn;
+	slot->index = drc_index;
+	strcpy(slot->location, drc_name);
+	slot->power_domain = power_domain;
+	slot->hotplug_slot->private = slot;
+	slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
+	slot->hotplug_slot->release = &rpaphp_release_slot;
+	
+	return (slot);
+
+error_name:
+	kfree(slot->hotplug_slot->name);
+error_info:
+	kfree(slot->hotplug_slot->info);
+error_hpslot:
+	kfree(slot->hotplug_slot);
+error_slot:
+	kfree(slot);
+error_nomem:
+	return NULL;
+}
+
+static int is_registered(struct slot *slot)
+{
+	struct slot             *tmp_slot;
+
+	list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) {
+		if (!strcmp(tmp_slot->name, slot->name))
+			return 1;
+	}	
+	return 0;
+}
+
+int deregister_slot(struct slot *slot)
+{
+	int retval = 0;
+	struct hotplug_slot *php_slot = slot->hotplug_slot;
+
+	 dbg("%s - Entry: deregistering slot=%s\n",
+		__FUNCTION__, slot->name);
+
+	list_del(&slot->rpaphp_slot_list);
+	
+	/* remove "phy_location" file */
+	rpaphp_sysfs_remove_attr_location(php_slot);
+
+	/* remove "phy_removable" file */
+	rpaphp_sysfs_remove_attr_removable(php_slot);
+
+	retval = pci_hp_deregister(php_slot);
+	if (retval)
+		err("Problem unregistering a slot %s\n", slot->name);
+	else
+		num_slots--;
+
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+	return retval;
+}
+
+int register_slot(struct slot *slot)
+{
+	int retval;
+
+	dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", 
+		__FUNCTION__, slot->dn->full_name, slot->index, slot->name, 
+		slot->power_domain, slot->type);
+	/* should not try to register the same slot twice */
+	if (is_registered(slot)) { /* should't be here */
+		err("register_slot: slot[%s] is already registered\n", slot->name);
+		rpaphp_release_slot(slot->hotplug_slot);
+		return -EAGAIN;
+	}	
+	retval = pci_hp_register(slot->hotplug_slot);
+	if (retval) {
+		err("pci_hp_register failed with error %d\n", retval);
+		rpaphp_release_slot(slot->hotplug_slot);
+		return retval;
+	}
+	
+	/* create "phy_locatoin" file */
+	rpaphp_sysfs_add_attr_location(slot->hotplug_slot);	
+
+	/* create "phy_removable" file */
+	rpaphp_sysfs_add_attr_removable(slot->hotplug_slot);	
+
+	/* add slot to our internal list */
+	dbg("%s adding slot[%s] to rpaphp_slot_list\n",
+	    __FUNCTION__, slot->name);
+
+	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
+
+	if (slot->dev_type == VIO_DEV)
+		info("Slot [%s](VIO location=%s) registered\n",
+		     slot->name, slot->location);
+	else
+		info("Slot [%s](PCI location=%s) registered\n",
+		     slot->name, slot->location);
+	num_slots++;
+	return 0;
+}
+
+int rpaphp_get_power_status(struct slot *slot, u8 * value)
+{
+	int rc = 0, level;
+	
+	if (slot->type == HOTPLUG) {
+		rc = rtas_get_power_level(slot->power_domain, &level);
+		if (!rc) {
+			dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n",
+				__FUNCTION__, slot->name, slot->power_domain, level);
+			*value = level;
+		} else
+			err("failed to get power-level for slot(%s), rc=0x%x\n",
+				slot->location, rc);
+	} else {
+		dbg("%s report POWER_ON for EMBEDDED or PHB slot %s\n",
+			__FUNCTION__, slot->location);
+		*value = (u8) POWER_ON;
+	}
+
+	return rc;
+}
+
+int rpaphp_set_attention_status(struct slot *slot, u8 status)
+{
+	int rc;
+
+	/* status: LED_OFF or LED_ON */
+	rc = rtas_set_indicator(DR_INDICATOR, slot->index, status);
+	if (rc < 0)
+		err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n",
+		    slot->name, slot->location, slot->index, status, rc);
+
+	return rc;
+}
diff --git a/drivers/pci/hotplug/rpaphp_vio.c b/drivers/pci/hotplug/rpaphp_vio.c
new file mode 100644
index 0000000..74df6a3
--- /dev/null
+++ b/drivers/pci/hotplug/rpaphp_vio.c
@@ -0,0 +1,129 @@
+/*
+ * RPA Hot Plug Virtual I/O device functions 
+ * Copyright (C) 2004 Linda Xie <lxie@us.ibm.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <lxie@us.ibm.com>
+ *
+ */
+#include <asm/vio.h>
+#include "rpaphp.h"
+
+/*
+ * get_vio_adapter_status - get  the status of a slot
+ * 
+ * status:
+ * 
+ * 1-- adapter is configured
+ * 2-- adapter is not configured
+ * 3-- not valid
+ */
+inline int rpaphp_get_vio_adapter_status(struct slot *slot, int is_init, u8 *value)
+{
+	*value = slot->state;
+	return 0;
+}
+
+int rpaphp_unconfig_vio_adapter(struct slot *slot)
+{
+	int retval = 0;
+
+	dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
+	if (!slot->dev.vio_dev) {
+		info("%s: no VIOA in slot[%s]\n", __FUNCTION__, slot->name);
+		retval = -EINVAL;
+		goto exit;
+	}
+	/* remove the device from the vio core */
+	vio_unregister_device(slot->dev.vio_dev);
+	slot->state = NOT_CONFIGURED;
+	info("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__, slot->name);
+exit:
+	dbg("Exit %s, rc=0x%x\n", __FUNCTION__, retval);
+	return retval;
+}
+
+static int setup_vio_hotplug_slot_info(struct slot *slot)
+{
+	slot->hotplug_slot->info->power_status = 1;
+	rpaphp_get_vio_adapter_status(slot, 1,
+		&slot->hotplug_slot->info->adapter_status); 
+	return 0;
+}
+
+int register_vio_slot(struct device_node *dn)
+{
+	u32 *index;
+	char *name;
+	int rc = -EINVAL;
+	struct slot *slot = NULL;
+	
+	rc = rpaphp_get_drc_props(dn, NULL, &name, NULL, NULL);
+	if (rc < 0)
+		goto exit_rc;
+	index = (u32 *) get_property(dn, "ibm,my-drc-index", NULL);
+	if (!index)
+		goto exit_rc;
+	if (!(slot = alloc_slot_struct(dn, *index, name, 0))) {
+		rc = -ENOMEM;
+		goto exit_rc;
+	}
+	slot->dev_type = VIO_DEV;
+	slot->dev.vio_dev = vio_find_node(dn);
+	if (slot->dev.vio_dev) {
+		/*
+		 * rpaphp is the only owner of vio devices and
+		 * does not need extra reference taken by
+		 * vio_find_node
+		 */
+		put_device(&slot->dev.vio_dev->dev);
+	} else
+		slot->dev.vio_dev = vio_register_device_node(dn);
+	if (slot->dev.vio_dev)
+		slot->state = CONFIGURED;
+	else
+		slot->state = NOT_CONFIGURED;
+	if (setup_vio_hotplug_slot_info(slot))
+		goto exit_rc;
+	strcpy(slot->name, slot->dev.vio_dev->dev.bus_id);
+	info("%s: registered VIO device[name=%s vio_dev=%p]\n",
+		__FUNCTION__, slot->name, slot->dev.vio_dev); 
+	rc = register_slot(slot);
+exit_rc:
+	if (rc && slot)
+		dealloc_slot_struct(slot);
+	return (rc);
+}
+
+int rpaphp_enable_vio_slot(struct slot *slot)
+{
+	int retval = 0;
+
+	if ((slot->dev.vio_dev = vio_register_device_node(slot->dn))) {
+		info("%s: VIO adapter %s in slot[%s] has been configured\n",
+			__FUNCTION__, slot->dn->name, slot->name);
+		slot->state = CONFIGURED;
+	} else {
+		info("%s: no vio_dev struct for adapter in slot[%s]\n",
+			__FUNCTION__, slot->name);
+		slot->state = NOT_CONFIGURED;
+	}
+	
+	return retval;
+}
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
new file mode 100644
index 0000000..67b6a33
--- /dev/null
+++ b/drivers/pci/hotplug/shpchp.h
@@ -0,0 +1,463 @@
+/*
+ * Standard Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>,<dely.l.sy@intel.com>
+ *
+ */
+#ifndef _SHPCHP_H
+#define _SHPCHP_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>		
+#include "pci_hotplug.h"
+
+#if !defined(MODULE)
+	#define MY_NAME	"shpchp"
+#else
+	#define MY_NAME	THIS_MODULE->name
+#endif
+
+extern int shpchp_poll_mode;
+extern int shpchp_poll_time;
+extern int shpchp_debug;
+
+/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
+#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+
+struct pci_func {
+	struct pci_func *next;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 is_a_board;
+	u16 status;
+	u8 configured;
+	u8 switch_save;
+	u8 presence_save;
+	u8 pwr_save;
+	u32 base_length[0x06];
+	u8 base_type[0x06];
+	u16 reserved2;
+	u32 config_space[0x20];
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev* pci_dev;
+};
+
+#define SLOT_MAGIC	0x67267321
+struct slot {
+	u32 magic;
+	struct slot *next;
+	u8 bus;
+	u8 device;
+	u32 number;
+	u8 is_a_board;
+	u8 configured;
+	u8 state;
+	u8 switch_save;
+	u8 presence_save;
+	u32 capabilities;
+	u16 reserved2;
+	struct timer_list task_event;
+	u8 hp_slot;
+	struct controller *ctrl;
+	struct hpc_ops *hpc_ops;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head	slot_list;
+};
+
+struct pci_resource {
+	struct pci_resource * next;
+	u32 base;
+	u32 length;
+};
+
+struct event_info {
+	u32 event_type;
+	u8 hp_slot;
+};
+
+struct controller {
+	struct controller *next;
+	struct semaphore crit_sect;	/* critical section semaphore */
+	void * hpc_ctlr_handle;		/* HPC controller handle */
+	int num_slots;			/* Number of slots on ctlr */
+	int slot_num_inc;		/* 1 or -1 */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev *pci_dev;
+	struct pci_bus *pci_bus;
+	struct event_info event_queue[10];
+	struct slot *slot;
+	struct hpc_ops *hpc_ops;
+	wait_queue_head_t queue;	/* sleep & wake process */
+	u8 next_event;
+	u8 seg;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 rev;
+	u8 slot_device_offset;
+	u8 add_support;
+	enum pci_bus_speed speed;
+	u32 first_slot;		/* First physical slot number */
+	u8 slot_bus;		/* Bus where the slots handled by this controller sit */
+	u8 push_flag;
+	u16 ctlrcap;
+	u16 vendor_id;
+};
+
+struct irq_mapping {
+	u8 barber_pole;
+	u8 valid_INT;
+	u8 interrupt[4];
+};
+
+struct resource_lists {
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct irq_mapping *irqs;
+};
+
+/* Define AMD SHPC ID  */
+#define PCI_DEVICE_ID_AMD_GOLAM_7450	0x7450 
+
+#define INT_BUTTON_IGNORE		0
+#define INT_PRESENCE_ON			1
+#define INT_PRESENCE_OFF		2
+#define INT_SWITCH_CLOSE		3
+#define INT_SWITCH_OPEN			4
+#define INT_POWER_FAULT			5
+#define INT_POWER_FAULT_CLEAR		6
+#define INT_BUTTON_PRESS		7
+#define INT_BUTTON_RELEASE		8
+#define INT_BUTTON_CANCEL		9
+
+#define STATIC_STATE			0
+#define BLINKINGON_STATE		1
+#define BLINKINGOFF_STATE		2
+#define POWERON_STATE			3
+#define POWEROFF_STATE			4
+
+#define PCI_TO_PCI_BRIDGE_CLASS		0x00060400
+
+/* Error messages */
+#define INTERLOCK_OPEN			0x00000002
+#define ADD_NOT_SUPPORTED		0x00000003
+#define CARD_FUNCTIONING		0x00000005
+#define ADAPTER_NOT_SAME		0x00000006
+#define NO_ADAPTER_PRESENT		0x00000009
+#define NOT_ENOUGH_RESOURCES		0x0000000B
+#define DEVICE_TYPE_NOT_SUPPORTED	0x0000000C
+#define WRONG_BUS_FREQUENCY		0x0000000D
+#define POWER_FAILURE			0x0000000E
+
+#define REMOVE_NOT_SUPPORTED		0x00000003
+
+#define DISABLE_CARD			1
+
+/*
+ * error Messages
+ */
+#define msg_initialization_err	"Initialization failure, error=%d\n"
+#define msg_HPC_rev_error	"Unsupported revision of the PCI hot plug controller found.\n"
+#define msg_HPC_non_shpc	"The PCI hot plug controller is not supported by this driver.\n"
+#define msg_HPC_not_supported	"This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n"
+#define msg_unable_to_save	"Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n"
+#define msg_button_on		"PCI slot #%d - powering on due to button press.\n"
+#define msg_button_off		"PCI slot #%d - powering off due to button press.\n"
+#define msg_button_cancel	"PCI slot #%d - action canceled due to button press.\n"
+#define msg_button_ignore	"PCI slot #%d - button press ignored.  (action in progress...)\n"
+
+/* sysfs functions for the hotplug controller info */
+extern void shpchp_create_ctrl_files	(struct controller *ctrl);
+
+/* controller functions */
+extern int	shpchprm_find_available_resources(struct controller *ctrl);
+extern int	shpchp_event_start_thread(void);
+extern void	shpchp_event_stop_thread(void);
+extern struct 	pci_func *shpchp_slot_create(unsigned char busnumber);
+extern struct 	pci_func *shpchp_slot_find(unsigned char bus, unsigned char device, unsigned char index);
+extern int	shpchp_enable_slot(struct slot *slot);
+extern int	shpchp_disable_slot(struct slot *slot);
+
+extern u8	shpchp_handle_attention_button(u8 hp_slot, void *inst_id);
+extern u8	shpchp_handle_switch_change(u8 hp_slot, void *inst_id);
+extern u8	shpchp_handle_presence_change(u8 hp_slot, void *inst_id);
+extern u8	shpchp_handle_power_fault(u8 hp_slot, void *inst_id);
+
+/* resource functions */
+extern int	shpchp_resource_sort_and_combine(struct pci_resource **head);
+
+/* pci functions */
+extern int	shpchp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
+/*extern int	shpchp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/
+extern int	shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
+extern int	shpchp_save_used_resources(struct controller *ctrl, struct pci_func * func, int flag);
+extern int	shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot);
+extern void	shpchp_destroy_board_resources(struct pci_func * func);
+extern int	shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources);
+extern void	shpchp_destroy_resource_list(struct resource_lists * resources);
+extern int	shpchp_configure_device(struct controller* ctrl, struct pci_func* func);
+extern int	shpchp_unconfigure_device(struct pci_func* func);
+
+
+/* Global variables */
+extern struct controller *shpchp_ctrl_list;
+extern struct pci_func *shpchp_slot_list[256];
+
+/* These are added to support AMD shpc */
+extern u8 shpchp_nic_irq;
+extern u8 shpchp_disk_irq;
+
+struct ctrl_reg {
+	volatile u32 base_offset;
+	volatile u32 slot_avail1;
+	volatile u32 slot_avail2;
+	volatile u32 slot_config;
+	volatile u16 sec_bus_config;
+	volatile u8  msi_ctrl;
+	volatile u8  prog_interface;
+	volatile u16 cmd;
+	volatile u16 cmd_status;
+	volatile u32 intr_loc;
+	volatile u32 serr_loc;
+	volatile u32 serr_intr_enable;
+	volatile u32 slot1;
+	volatile u32 slot2;
+	volatile u32 slot3;
+	volatile u32 slot4;
+	volatile u32 slot5;
+	volatile u32 slot6;
+	volatile u32 slot7;
+	volatile u32 slot8;
+	volatile u32 slot9;
+	volatile u32 slot10;
+	volatile u32 slot11;
+	volatile u32 slot12;
+} __attribute__ ((packed));
+
+/* offsets to the controller registers based on the above structure layout */
+enum ctrl_offsets {
+	BASE_OFFSET =	offsetof(struct ctrl_reg, base_offset),
+	SLOT_AVAIL1 =	offsetof(struct ctrl_reg, slot_avail1),
+	SLOT_AVAIL2	=	offsetof(struct ctrl_reg, slot_avail2),
+	SLOT_CONFIG =	offsetof(struct ctrl_reg, slot_config),
+	SEC_BUS_CONFIG =	offsetof(struct ctrl_reg, sec_bus_config),
+	MSI_CTRL	=	offsetof(struct ctrl_reg, msi_ctrl),
+	PROG_INTERFACE =	offsetof(struct ctrl_reg, prog_interface),
+	CMD		=	offsetof(struct ctrl_reg, cmd),
+	CMD_STATUS	=	offsetof(struct ctrl_reg, cmd_status),
+	INTR_LOC	= 	offsetof(struct ctrl_reg, intr_loc),
+	SERR_LOC	= 	offsetof(struct ctrl_reg, serr_loc),
+	SERR_INTR_ENABLE =	offsetof(struct ctrl_reg, serr_intr_enable),
+	SLOT1 =		offsetof(struct ctrl_reg, slot1),
+	SLOT2 =		offsetof(struct ctrl_reg, slot2),
+	SLOT3 =		offsetof(struct ctrl_reg, slot3),
+	SLOT4 =		offsetof(struct ctrl_reg, slot4),
+	SLOT5 =		offsetof(struct ctrl_reg, slot5),
+	SLOT6 =		offsetof(struct ctrl_reg, slot6),		
+	SLOT7 =		offsetof(struct ctrl_reg, slot7),
+	SLOT8 =		offsetof(struct ctrl_reg, slot8),
+	SLOT9 =		offsetof(struct ctrl_reg, slot9),
+	SLOT10 =	offsetof(struct ctrl_reg, slot10),
+	SLOT11 =	offsetof(struct ctrl_reg, slot11),
+	SLOT12 =	offsetof(struct ctrl_reg, slot12),
+};
+typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id);
+struct php_ctlr_state_s {
+	struct php_ctlr_state_s *pnext;
+	struct pci_dev *pci_dev;
+	unsigned int irq;
+	unsigned long flags;	/* spinlock's */
+	u32 slot_device_offset;
+	u32 num_slots;
+    	struct timer_list	int_poll_timer;	/* Added for poll event */
+	php_intr_callback_t attention_button_callback;
+	php_intr_callback_t switch_change_callback;
+	php_intr_callback_t presence_change_callback;
+	php_intr_callback_t power_fault_callback;
+	void *callback_instance_id;
+	void __iomem *creg;			/* Ptr to controller register space */
+};
+/* Inline functions */
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check (struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL", function);
+		return -1;
+	}
+	if (slot->magic != SLOT_MAGIC) {
+		dbg("%s - bad magic number for slot", function);
+		return -1;
+	}
+	if (!slot->hotplug_slot) {
+		dbg("%s - slot->hotplug_slot == NULL!", function);
+		return -1;
+	}
+	return 0;
+}
+
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
+{ 
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL\n", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot->private;
+	if (slot_paranoia_check (slot, function))
+                return NULL;
+	return slot;
+}
+
+static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device)
+{
+	struct slot *p_slot, *tmp_slot = NULL;
+
+	if (!ctrl)
+		return NULL;
+
+	p_slot = ctrl->slot;
+
+	dbg("p_slot = %p\n", p_slot);
+
+	while (p_slot && (p_slot->device != device)) {
+		tmp_slot = p_slot;
+		p_slot = p_slot->next;
+		dbg("In while loop, p_slot = %p\n", p_slot);
+	}
+	if (p_slot == NULL) {
+		err("ERROR: shpchp_find_slot device=0x%x\n", device);
+		p_slot = tmp_slot;
+	}
+
+	return (p_slot);
+}
+
+static inline int wait_for_ctrl_irq (struct controller *ctrl)
+{
+    DECLARE_WAITQUEUE(wait, current);
+	int retval = 0;
+
+	dbg("%s : start\n",__FUNCTION__);
+
+	add_wait_queue(&ctrl->queue, &wait);
+
+	if (!shpchp_poll_mode) {
+		/* Sleep for up to 1 second */
+		msleep_interruptible(1000);
+	} else {
+		/* Sleep for up to 2 seconds */
+		msleep_interruptible(2000);
+	}
+	remove_wait_queue(&ctrl->queue, &wait);
+	if (signal_pending(current))
+		retval =  -EINTR;
+
+	dbg("%s : end\n", __FUNCTION__);
+	return retval;
+}
+
+/* Puts node back in the resource list pointed to by head */
+static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
+{
+	if (!node || !head)
+		return;
+	node->next = *head;
+	*head = node;
+}
+
+#define SLOT_NAME_SIZE 10
+
+static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
+{
+	snprintf(buffer, buffer_size, "%d", slot->number);
+}
+
+enum php_ctlr_type {
+	PCI,
+	ISA,
+	ACPI
+};
+
+int shpc_init( struct controller *ctrl, struct pci_dev *pdev,
+		php_intr_callback_t attention_button_callback,
+		php_intr_callback_t switch_change_callback,
+		php_intr_callback_t presence_change_callback,
+		php_intr_callback_t power_fault_callback);
+
+int shpc_get_ctlr_slot_config( struct controller *ctrl,
+		int *num_ctlr_slots,
+		int *first_device_num,
+		int *physical_slot_num,
+		int *updown,
+		int *flags);
+
+struct hpc_ops {
+	int	(*power_on_slot )		(struct slot *slot);
+	int	(*slot_enable )			(struct slot *slot);
+	int	(*slot_disable )		(struct slot *slot);
+	int	(*enable_all_slots)		(struct slot *slot);
+	int	(*pwr_on_all_slots)		(struct slot *slot);
+	int	(*set_bus_speed_mode)	(struct slot *slot, enum pci_bus_speed speed);
+	int	(*get_power_status)		(struct slot *slot, u8 *status);
+	int	(*get_attention_status)	(struct slot *slot, u8 *status);
+	int	(*set_attention_status)	(struct slot *slot, u8 status);
+	int	(*get_latch_status)		(struct slot *slot, u8 *status);
+	int	(*get_adapter_status)	(struct slot *slot, u8 *status);
+
+	int	(*get_max_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_cur_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_adapter_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_mode1_ECC_cap)	(struct slot *slot, u8 *mode);
+	int	(*get_prog_int)			(struct slot *slot, u8 *prog_int);
+
+	int	(*query_power_fault)	(struct slot *slot);
+	void	(*green_led_on)		(struct slot *slot);
+	void	(*green_led_off)	(struct slot *slot);
+	void	(*green_led_blink)	(struct slot *slot);
+	void	(*release_ctlr)		(struct controller *ctrl);
+	int (*check_cmd_status)		(struct controller *ctrl);
+};
+
+#endif				/* _SHPCHP_H */
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
new file mode 100644
index 0000000..f0c53f8
--- /dev/null
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -0,0 +1,630 @@
+/*
+ * Standard Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include "shpchp.h"
+#include "shpchprm.h"
+
+/* Global variables */
+int shpchp_debug;
+int shpchp_poll_mode;
+int shpchp_poll_time;
+struct controller *shpchp_ctrl_list;	/* = NULL */
+struct pci_func *shpchp_slot_list[256];
+
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
+#define DRIVER_DESC	"Standard Hot Plug PCI Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(shpchp_debug, bool, 0644);
+module_param(shpchp_poll_mode, bool, 0644);
+module_param(shpchp_poll_time, int, 0644);
+MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not");
+MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not");
+MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
+
+#define SHPC_MODULE_NAME "shpchp"
+
+static int shpc_start_thread (void);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+
+static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
+	.owner =		THIS_MODULE,
+	.set_attention_status =	set_attention_status,
+	.enable_slot =		enable_slot,
+	.disable_slot =		disable_slot,
+	.get_power_status =	get_power_status,
+	.get_attention_status =	get_attention_status,
+	.get_latch_status =	get_latch_status,
+	.get_adapter_status =	get_adapter_status,
+	.get_max_bus_speed =	get_max_bus_speed,
+	.get_cur_bus_speed =	get_cur_bus_speed,
+};
+
+/**
+ * release_slot - free up the memory used by a slot
+ * @hotplug_slot: slot to free
+ */
+static void release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = (struct slot *)hotplug_slot->private;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	kfree(slot->hotplug_slot->info);
+	kfree(slot->hotplug_slot->name);
+	kfree(slot->hotplug_slot);
+	kfree(slot);
+}
+
+static int init_slots(struct controller *ctrl)
+{
+	struct slot *new_slot;
+	u8 number_of_slots;
+	u8 slot_device;
+	u32 slot_number, sun;
+	int result = -ENOMEM;
+
+	dbg("%s\n",__FUNCTION__);
+
+	number_of_slots = ctrl->num_slots;
+	slot_device = ctrl->slot_device_offset;
+	slot_number = ctrl->first_slot;
+
+	while (number_of_slots) {
+		new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL);
+		if (!new_slot)
+			goto error;
+
+		memset(new_slot, 0, sizeof(struct slot));
+		new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		if (!new_slot->hotplug_slot)
+			goto error_slot;
+		memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+
+		new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if (!new_slot->hotplug_slot->info)
+			goto error_hpslot;
+		memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+		new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!new_slot->hotplug_slot->name)
+			goto error_info;
+
+		new_slot->magic = SLOT_MAGIC;
+		new_slot->ctrl = ctrl;
+		new_slot->bus = ctrl->slot_bus;
+		new_slot->device = slot_device;
+		new_slot->hpc_ops = ctrl->hpc_ops;
+
+		if (shpchprm_get_physical_slot_number(ctrl, &sun,
+					new_slot->bus, new_slot->device))
+			goto error_name;
+
+		new_slot->number = sun;
+		new_slot->hp_slot = slot_device - ctrl->slot_device_offset;
+
+		/* register this slot with the hotplug pci core */
+		new_slot->hotplug_slot->private = new_slot;
+		new_slot->hotplug_slot->release = &release_slot;
+		make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
+		new_slot->hotplug_slot->ops = &shpchp_hotplug_slot_ops;
+
+		new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status));
+		new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status));
+		new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status));
+		new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status));
+
+		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", new_slot->bus, 
+			new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset);
+		result = pci_hp_register (new_slot->hotplug_slot);
+		if (result) {
+			err ("pci_hp_register failed with error %d\n", result);
+			goto error_name;
+		}
+
+		new_slot->next = ctrl->slot;
+		ctrl->slot = new_slot;
+
+		number_of_slots--;
+		slot_device++;
+		slot_number += ctrl->slot_num_inc;
+	}
+
+	return 0;
+
+error_name:
+	kfree(new_slot->hotplug_slot->name);
+error_info:
+	kfree(new_slot->hotplug_slot->info);
+error_hpslot:
+	kfree(new_slot->hotplug_slot);
+error_slot:
+	kfree(new_slot);
+error:
+	return result;
+}
+
+static void cleanup_slots(struct controller *ctrl)
+{
+	struct slot *old_slot, *next_slot;
+
+	old_slot = ctrl->slot;
+	ctrl->slot = NULL;
+
+	while (old_slot) {
+		next_slot = old_slot->next;
+		pci_hp_deregister(old_slot->hotplug_slot);
+		old_slot = next_slot;
+	}
+}
+
+static int get_ctlr_slot_config(struct controller *ctrl)
+{
+	int num_ctlr_slots;
+	int first_device_num;
+	int physical_slot_num;
+	int updown;
+	int rc;
+	int flags;
+
+	rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &updown, &flags);
+	if (rc) {
+		err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
+		return -1;
+	}
+
+	ctrl->num_slots = num_ctlr_slots;
+	ctrl->slot_device_offset = first_device_num;
+	ctrl->first_slot = physical_slot_num;
+	ctrl->slot_num_inc = updown;		/* either -1 or 1 */
+
+	dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n",
+		__FUNCTION__, num_ctlr_slots, first_device_num, physical_slot_num, updown, ctrl->bus, ctrl->device);
+
+	return 0;
+}
+
+
+/*
+ * set_attention_status - Turns the Amber LED for a slot on, off or blink
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	hotplug_slot->info->attention_status = status;
+	slot->hpc_ops->set_attention_status(slot, status);
+
+	return 0;
+}
+
+
+static int enable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	return shpchp_enable_slot(slot);
+}
+
+
+static int disable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	return shpchp_disable_slot(slot);
+}
+
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_power_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->power_status;
+
+	return 0;
+}
+
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_attention_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->attention_status;
+
+	return 0;
+}
+
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_latch_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->latch_status;
+
+	return 0;
+}
+
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	retval = slot->hpc_ops->get_adapter_status(slot, value);
+	if (retval < 0)
+		*value = hotplug_slot->info->adapter_status;
+
+	return 0;
+}
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+	
+	retval = slot->hpc_ops->get_max_bus_speed(slot, value);
+	if (retval < 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+	
+	retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
+	if (retval < 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc;
+	struct controller *ctrl;
+	struct slot *t_slot;
+	int first_device_num;	/* first PCI device number supported by this SHPC */
+	int num_ctlr_slots;	/* number of slots supported by this SHPC */
+
+	ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
+	if (!ctrl) {
+		err("%s : out of memory\n", __FUNCTION__);
+		goto err_out_none;
+	}
+	memset(ctrl, 0, sizeof(struct controller));
+
+	dbg("DRV_thread pid = %d\n", current->pid);
+
+	rc = shpc_init(ctrl, pdev,
+			(php_intr_callback_t) shpchp_handle_attention_button,
+			(php_intr_callback_t) shpchp_handle_switch_change,
+			(php_intr_callback_t) shpchp_handle_presence_change,
+			(php_intr_callback_t) shpchp_handle_power_fault);
+	if (rc) {
+		dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME);
+		goto err_out_free_ctrl;
+	}
+
+	dbg("%s: controller initialization success\n", __FUNCTION__);
+	ctrl->pci_dev = pdev;  /* pci_dev of the P2P bridge */
+
+	pci_set_drvdata(pdev, ctrl);
+
+	ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);
+	if (!ctrl->pci_bus) {
+		err("out of memory\n");
+		rc = -ENOMEM;
+		goto err_out_unmap_mmio_region;
+	}
+	
+	memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
+	ctrl->bus = pdev->bus->number;
+	ctrl->slot_bus = pdev->subordinate->number;
+
+	ctrl->device = PCI_SLOT(pdev->devfn);
+	ctrl->function = PCI_FUNC(pdev->devfn);
+	dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
+
+	/*
+	 *	Save configuration headers for this and subordinate PCI buses
+	 */
+
+	rc = get_ctlr_slot_config(ctrl);
+	if (rc) {
+		err(msg_initialization_err, rc);
+		goto err_out_free_ctrl_bus;
+	}
+	first_device_num = ctrl->slot_device_offset;
+	num_ctlr_slots = ctrl->num_slots;
+
+	/* Store PCI Config Space for all devices on this bus */
+	rc = shpchp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num);
+	if (rc) {
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Get IO, memory, and IRQ resources for new devices */
+	rc = shpchprm_find_available_resources(ctrl);
+	ctrl->add_support = !rc;
+	
+	if (rc) {
+		dbg("shpchprm_find_available_resources = %#x\n", rc);
+		err("unable to locate PCI configuration resources for hot plug add.\n");
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Setup the slot information structures */
+	rc = init_slots(ctrl);
+	if (rc) {
+		err(msg_initialization_err, 6);
+		goto err_out_free_ctrl_slot;
+	}
+
+	/* Now hpc_functions (slot->hpc_ops->functions) are ready  */
+	t_slot = shpchp_find_slot(ctrl, first_device_num);
+
+	/* Check for operation bus speed */
+	rc = t_slot->hpc_ops->get_cur_bus_speed(t_slot, &ctrl->speed);
+	dbg("%s: t_slot->hp_slot %x\n", __FUNCTION__,t_slot->hp_slot);
+
+	if (rc || ctrl->speed == PCI_SPEED_UNKNOWN) {
+		err(SHPC_MODULE_NAME ": Can't get current bus speed. Set to 33MHz PCI.\n");
+		ctrl->speed = PCI_SPEED_33MHz;
+	}
+
+	/* Finish setting up the hot plug ctrl device */
+	ctrl->next_event = 0;
+
+	if (!shpchp_ctrl_list) {
+		shpchp_ctrl_list = ctrl;
+		ctrl->next = NULL;
+	} else {
+		ctrl->next = shpchp_ctrl_list;
+		shpchp_ctrl_list = ctrl;
+	}
+
+	shpchp_create_ctrl_files(ctrl);
+
+	return 0;
+
+err_out_free_ctrl_slot:
+	cleanup_slots(ctrl);
+err_out_free_ctrl_bus:
+	kfree(ctrl->pci_bus);
+err_out_unmap_mmio_region:
+	ctrl->hpc_ops->release_ctlr(ctrl);
+err_out_free_ctrl:
+	kfree(ctrl);
+err_out_none:
+	return -ENODEV;
+}
+
+
+static int shpc_start_thread(void)
+{
+	int loop;
+	int retval = 0;
+	
+	dbg("Initialize + Start the notification/polling mechanism \n");
+
+	retval = shpchp_event_start_thread();
+	if (retval) {
+		dbg("shpchp_event_start_thread() failed\n");
+		return retval;
+	}
+
+	dbg("Initialize slot lists\n");
+	/* One slot list for each bus in the system */
+	for (loop = 0; loop < 256; loop++) {
+		shpchp_slot_list[loop] = NULL;
+	}
+
+	return retval;
+}
+
+static inline void __exit
+free_shpchp_res(struct pci_resource *res)
+{
+	struct pci_resource *tres;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
+static void __exit unload_shpchpd(void)
+{
+	struct pci_func *next;
+	struct pci_func *TempSlot;
+	int loop;
+	struct controller *ctrl;
+	struct controller *tctrl;
+
+	ctrl = shpchp_ctrl_list;
+
+	while (ctrl) {
+		cleanup_slots(ctrl);
+
+		free_shpchp_res(ctrl->io_head);
+		free_shpchp_res(ctrl->mem_head);
+		free_shpchp_res(ctrl->p_mem_head);
+		free_shpchp_res(ctrl->bus_head);
+
+		kfree (ctrl->pci_bus);
+
+		dbg("%s: calling release_ctlr\n", __FUNCTION__);
+		ctrl->hpc_ops->release_ctlr(ctrl);
+
+		tctrl = ctrl;
+		ctrl = ctrl->next;
+
+		kfree(tctrl);
+	}
+
+	for (loop = 0; loop < 256; loop++) {
+		next = shpchp_slot_list[loop];
+		while (next != NULL) {
+			free_shpchp_res(next->io_head);
+			free_shpchp_res(next->mem_head);
+			free_shpchp_res(next->p_mem_head);
+			free_shpchp_res(next->bus_head);
+
+			TempSlot = next;
+			next = next->next;
+			kfree(TempSlot);
+		}
+	}
+
+	/* Stop the notification mechanism */
+	shpchp_event_stop_thread();
+
+}
+
+
+static struct pci_device_id shpcd_pci_tbl[] = {
+	{
+	.class =        ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00),
+	.class_mask =	~0,
+	.vendor =       PCI_ANY_ID,
+	.device =       PCI_ANY_ID,
+	.subvendor =    PCI_ANY_ID,
+	.subdevice =    PCI_ANY_ID,
+	},
+	
+	{ /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl);
+
+
+
+static struct pci_driver shpc_driver = {
+	.name =		SHPC_MODULE_NAME,
+	.id_table =	shpcd_pci_tbl,
+	.probe =	shpc_probe,
+	/* remove:	shpc_remove_one, */
+};
+
+
+
+static int __init shpcd_init(void)
+{
+	int retval = 0;
+
+#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
+	shpchp_poll_mode = 1;
+#endif
+
+	retval = shpc_start_thread();
+	if (retval)
+		goto error_hpc_init;
+
+	retval = shpchprm_init(PCI);
+	if (!retval) {
+		retval = pci_register_driver(&shpc_driver);
+		dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
+		info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+	}
+
+error_hpc_init:
+	if (retval) {
+		shpchprm_cleanup();
+		shpchp_event_stop_thread();
+	} else
+		shpchprm_print_pirt();
+
+	return retval;
+}
+
+static void __exit shpcd_cleanup(void)
+{
+	dbg("unload_shpchpd()\n");
+	unload_shpchpd();
+
+	shpchprm_cleanup();
+
+	dbg("pci_unregister_driver\n");
+	pci_unregister_driver(&shpc_driver);
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
+}
+
+module_init(shpcd_init);
+module_exit(shpcd_cleanup);
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
new file mode 100644
index 0000000..9f90eb8
--- /dev/null
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -0,0 +1,2848 @@
+/*
+ * Standard Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include "shpchp.h"
+#include "shpchprm.h"
+
+static u32 configure_new_device(struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static int configure_new_function( struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static void interrupt_event_handler(struct controller *ctrl);
+
+static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
+static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
+static int event_finished;
+static unsigned long pushbutton_pending;	/* = 0 */
+
+u8 shpchp_disk_irq;
+u8 shpchp_nic_irq;
+
+u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Attention Button Change */
+	dbg("shpchp:  Attention button interrupt received.\n");
+	
+	func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread what to do */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+
+	/*
+	 *  Button pressed - See if need to TAKE ACTION!!!
+	 */
+	info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	taskInfo->event_type = INT_BUTTON_PRESS;
+
+	if ((p_slot->state == BLINKINGON_STATE)
+	    || (p_slot->state == BLINKINGOFF_STATE)) {
+		/* Cancel if we are still blinking; this means that we press the
+		 * attention again before the 5 sec. limit expires to cancel hot-add
+		 * or hot-remove
+		 */
+		taskInfo->event_type = INT_BUTTON_CANCEL;
+		info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	} else if ((p_slot->state == POWERON_STATE)
+		   || (p_slot->state == POWEROFF_STATE)) {
+		/* Ignore if the slot is on power-on or power-off state; this 
+		 * means that the previous attention button action to hot-add or
+		 * hot-remove is undergoing
+		 */
+		taskInfo->event_type = INT_BUTTON_IGNORE;
+		info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
+	}
+
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return 0;
+
+}
+
+u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Switch Change */
+	dbg("shpchp:  Switch interrupt received.\n");
+
+	func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	dbg("%s: Card present %x Power status %x\n", __FUNCTION__,
+		func->presence_save, func->pwr_save);
+
+	if (getstatus) {
+		/*
+		 * Switch opened
+		 */
+		info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->switch_save = 0;
+		taskInfo->event_type = INT_SWITCH_OPEN;
+		if (func->pwr_save && func->presence_save) {
+			taskInfo->event_type = INT_POWER_FAULT;
+			err("Surprise Removal of card\n");
+		}
+	} else {
+		/*
+		 *  Switch closed
+		 */
+		info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->switch_save = 0x10;
+		taskInfo->event_type = INT_SWITCH_CLOSE;
+	}
+
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	/*u8 temp_byte;*/
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Presence Change */
+	dbg("shpchp:  Presence/Notify input change.\n");
+
+	func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	/* 
+	 * Save the presence state
+	 */
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	if (func->presence_save) {
+		/*
+		 * Card Present
+		 */
+		info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_PRESENCE_ON;
+	} else {
+		/*
+		 * Not Present
+		 */
+		info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_PRESENCE_OFF;
+	}
+
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Power fault */
+	dbg("shpchp:  Power fault interrupt received.\n");
+
+	func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
+	ctrl->next_event = (ctrl->next_event + 1) % 10;
+	taskInfo->hp_slot = hp_slot;
+
+	rc++;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
+		/*
+		 * Power fault Cleared
+		 */
+		info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		func->status = 0x00;
+		taskInfo->event_type = INT_POWER_FAULT_CLEAR;
+	} else {
+		/*
+		 *   Power fault
+		 */
+		info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
+		taskInfo->event_type = INT_POWER_FAULT;
+		/* set power fault status for this board */
+		func->status = 0xFF;
+		info("power fault bit %x set\n", hp_slot);
+	}
+	if (rc)
+		up(&event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+
+/*
+ * sort_by_size
+ *
+ * Sorts nodes on the list by their length.
+ * Smallest first.
+ *
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)->next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length > (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length > current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * sort_by_max_size
+ *
+ * Sorts nodes on the list by their length.
+ * Largest first.
+ *
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)->next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->length < (*head)->next->length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)->next;
+			current_res->next = (*head)->next;
+			(*head)->next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res->next && current_res->next->next) {
+			if (current_res->next->length < current_res->next->next->length) {
+				out_of_order++;
+				next_res = current_res->next;
+				current_res->next = current_res->next->next;
+				current_res = current_res->next;
+				next_res->next = current_res->next;
+				current_res->next = next_res;
+			} else
+				current_res = current_res->next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * do_pre_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 rc;
+	u32 temp_dword;
+	dbg("do_pre_bridge_resource_split\n");
+
+	if (!(*head) || !(*orig_head))
+		return(NULL);
+
+	rc = shpchp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	if ((*head)->base != (*orig_head)->base)
+		return(NULL);
+
+	if ((*head)->length == (*orig_head)->length)
+		return(NULL);
+
+
+	/* If we got here, there the bridge requires some of the resource, but
+	 *  we may be able to split some off of the front
+	 */	
+	node = *head;
+
+	if (node->length & (alignment -1)) {
+		/* This one isn't an aligned length, so we'll make a new entry
+		 * and split it up.
+		 */
+		split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+		if (!split_node)
+			return(NULL);
+
+		temp_dword = (node->length | (alignment-1)) + 1 - alignment;
+
+		split_node->base = node->base;
+		split_node->length = temp_dword;
+
+		node->length -= temp_dword;
+		node->base += split_node->length;
+
+		/* Put it in the list */
+		*head = split_node;
+		split_node->next = node;
+	}
+
+	if (node->length < alignment) {
+		return(NULL);
+	}
+
+	/* Now unlink it */
+	if (*head == node) {
+		*head = node->next;
+		node->next = NULL;
+	} else {
+		prevnode = *head;
+		while (prevnode->next != node)
+			prevnode = prevnode->next;
+
+		prevnode->next = node->next;
+		node->next = NULL;
+	}
+
+	return(node);
+}
+
+
+/*
+ * do_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	u32 rc;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	rc = shpchp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	node = *head;
+
+	while (node->next) {
+		prevnode = node;
+		node = node->next;
+		kfree(prevnode);
+	}
+
+	if (node->length < alignment) {
+		kfree(node);
+		return(NULL);
+	}
+
+	if (node->base & (alignment - 1)) {
+		/* Short circuit if adjusted size is too small */
+		temp_dword = (node->base | (alignment-1)) + 1;
+		if ((node->length - (temp_dword - node->base)) < alignment) {
+			kfree(node);
+			return(NULL);
+		}
+
+		node->length -= (temp_dword - node->base);
+		node->base = temp_dword;
+	}
+
+	if (node->length & (alignment - 1)) {
+		/* There's stuff in use after this node */
+		kfree(node);
+		return(NULL);
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_io_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length that is not in the
+ * ISA aliasing window.  If it finds a node larger than "size"
+ * it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node = NULL;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( shpchp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node->next) {
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			/* This one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (node->base | (size-1)) + 1;
+
+			/*/ Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			/* This one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if (node->base & 0x300L)
+			continue;
+
+		/* If we got here, then it is the right size 
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_max_resource
+ *
+ * Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M
+ *  This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot.
+ */
+static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+	u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 };
+	int i;
+
+	if (!(*head))
+		return(NULL);
+
+	if (shpchp_resource_sort_and_combine(head))
+		return(NULL);
+
+	if (sort_by_max_size(head))
+		return(NULL);
+
+	for (max = *head;max; max = max->next) {
+
+		/* If not big enough we could probably just bail, 
+		   instead we'll continue to the next. */
+		if (max->length < size)
+			continue;
+
+		if (max->base & (size - 1)) {
+			/* This one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (max->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max->length - (temp_dword - max->base)) < size)
+				continue;
+
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = max->base;
+			split_node->length = temp_dword - max->base;
+			max->base = temp_dword;
+			max->length -= split_node->length;
+
+			/* Put it next in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		if ((max->base + max->length) & (size - 1)) {
+			/* This one isn't end aligned properly at the top
+			   so we'll make a new entry and split it up */
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+			temp_dword = ((max->base + max->length) & ~(size - 1));
+			split_node->base = temp_dword;
+			split_node->length = max->length + max->base
+					     - split_node->base;
+			max->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = max->next;
+			max->next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max->length < size)
+			continue;
+
+		for ( i = 0; max_size[i] > size; i++) {
+			if (max->length > max_size[i]) {
+				split_node = kmalloc(sizeof(*split_node),
+							GFP_KERNEL);
+				if (!split_node)
+					break;	/* return (NULL); */
+				split_node->base = max->base + max_size[i];
+				split_node->length = max->length - max_size[i];
+				max->length = max_size[i];
+				/* Put it next in the list */
+				split_node->next = max->next;
+				max->next = split_node;
+				break;
+			}
+		}
+
+		/* Now take it out of the list */
+		temp = (struct pci_resource*) *head;
+		if (temp == max) {
+			*head = max->next;
+		} else {
+			while (temp && temp->next != max) {
+				temp = temp->next;
+			}
+
+			temp->next = max->next;
+		}
+
+		max->next = NULL;
+		return(max);
+	}
+
+	/* If we get here, we couldn't find one */
+	return(NULL);
+}
+
+
+/*
+ * get_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( shpchp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node->next) {
+		dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n",
+		    __FUNCTION__, size, node, node->base, node->length);
+		if (node->length < size)
+			continue;
+
+		if (node->base & (size - 1)) {
+			dbg("%s: not aligned\n", __FUNCTION__);
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (node->base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node->length - (temp_dword - node->base)) < size)
+				continue;
+
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base;
+			split_node->length = temp_dword - node->base;
+			node->base = temp_dword;
+			node->length -= split_node->length;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node->length > size) {
+			dbg("%s: too big\n", __FUNCTION__);
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = kmalloc(sizeof(*split_node), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node->base = node->base + size;
+			split_node->length = node->length - size;
+			node->length = size;
+
+			/* Put it in the list */
+			split_node->next = node->next;
+			node->next = split_node;
+		}  /* End of too big on top end */
+
+		dbg("%s: got one!!!\n", __FUNCTION__);
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node->next;
+		} else {
+			prevnode = *head;
+			while (prevnode->next != node)
+				prevnode = prevnode->next;
+
+			prevnode->next = node->next;
+		}
+		node->next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return(node);
+}
+
+
+/*
+ * shpchp_resource_sort_and_combine
+ *
+ * Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int shpchp_resource_sort_and_combine(struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
+
+	if (!(*head))
+		return(1);
+
+	dbg("*head->next = %p\n",(*head)->next);
+
+	if (!(*head)->next)
+		return(0);	/* only one item on the list, already sorted! */
+
+	dbg("*head->base = 0x%x\n",(*head)->base);
+	dbg("*head->next->base = 0x%x\n",(*head)->next->base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)->next) &&
+		    ((*head)->base > (*head)->next->base)) {
+			node1 = *head;
+			(*head) = (*head)->next;
+			node1->next = (*head)->next;
+			(*head)->next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1->next && node1->next->next) {
+			if (node1->next->base > node1->next->next->base) {
+				out_of_order++;
+				node2 = node1->next;
+				node1->next = node1->next->next;
+				node1 = node1->next;
+				node2->next = node1->next;
+				node1->next = node2;
+			} else
+				node1 = node1->next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 && node1->next) {
+		if ((node1->base + node1->length) == node1->next->base) {
+			/* Combine */
+			dbg("8..\n");
+			node1->length += node1->next->length;
+			node2 = node1->next;
+			node1->next = node1->next->next;
+			kfree(node2);
+		} else
+			node1 = node1->next;
+	}
+
+	return(0);
+}
+
+
+/**
+ * shpchp_slot_create - Creates a node and adds it to the proper bus.
+ * @busnumber - bus where new node is to be located
+ *
+ * Returns pointer to the new node or NULL if unsuccessful
+ */
+struct pci_func *shpchp_slot_create(u8 busnumber)
+{
+	struct pci_func *new_slot;
+	struct pci_func *next;
+
+	new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
+
+	if (new_slot == NULL) {
+		return(new_slot);
+	}
+
+	memset(new_slot, 0, sizeof(struct pci_func));
+
+	new_slot->next = NULL;
+	new_slot->configured = 1;
+
+	if (shpchp_slot_list[busnumber] == NULL) {
+		shpchp_slot_list[busnumber] = new_slot;
+	} else {
+		next = shpchp_slot_list[busnumber];
+		while (next->next != NULL)
+			next = next->next;
+		next->next = new_slot;
+	}
+	return(new_slot);
+}
+
+
+/*
+ * slot_remove - Removes a node from the linked list of slots.
+ * @old_slot: slot to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int slot_remove(struct pci_func * old_slot)
+{
+	struct pci_func *next;
+
+	if (old_slot == NULL)
+		return(1);
+
+	next = shpchp_slot_list[old_slot->bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == old_slot) {
+		shpchp_slot_list[old_slot->bus] = old_slot->next;
+		shpchp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	}
+
+	while ((next->next != old_slot) && (next->next != NULL)) {
+		next = next->next;
+	}
+
+	if (next->next == old_slot) {
+		next->next = old_slot->next;
+		shpchp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * bridge_slot_remove - Removes a node from the linked list of slots.
+ * @bridge: bridge to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int bridge_slot_remove(struct pci_func *bridge)
+{
+	u8 subordinateBus, secondaryBus;
+	u8 tempBus;
+	struct pci_func *next;
+
+	if (bridge == NULL)
+		return(1);
+
+	secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF;
+	subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF;
+
+	for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) {
+		next = shpchp_slot_list[tempBus];
+
+		while (!slot_remove(next)) {
+			next = shpchp_slot_list[tempBus];
+		}
+	}
+
+	next = shpchp_slot_list[bridge->bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == bridge) {
+		shpchp_slot_list[bridge->bus] = bridge->next;
+		kfree(bridge);
+		return(0);
+	}
+
+	while ((next->next != bridge) && (next->next != NULL)) {
+		next = next->next;
+	}
+
+	if (next->next == bridge) {
+		next->next = bridge->next;
+		kfree(bridge);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * shpchp_slot_find - Looks for a node by bus, and device, multiple functions accessed
+ * @bus: bus to find
+ * @device: device to find
+ * @index: is 0 for first function found, 1 for the second...
+ *
+ * Returns pointer to the node if successful, %NULL otherwise.
+ */
+struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index)
+{
+	int found = -1;
+	struct pci_func *func;
+
+	func = shpchp_slot_list[bus];
+
+	if ((func == NULL) || ((func->device == device) && (index == 0)))
+		return(func);
+
+	if (func->device == device)
+		found++;
+
+	while (func->next != NULL) {
+		func = func->next;
+
+		if (func->device == device)
+			found++;
+
+		if (found == index)
+			return(func);
+	}
+
+	return(NULL);
+}
+
+static int is_bridge(struct pci_func * func)
+{
+	/* Check the header type */
+	if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* The following routines constitute the bulk of the 
+   hotplug controller logic
+ */
+static u32 change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum pci_bus_speed speed)
+{ 
+	u32 rc = 0;
+
+	dbg("%s: change to speed %d\n", __FUNCTION__, speed);
+	down(&ctrl->crit_sect);
+	if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, speed))) {
+		err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+		up(&ctrl->crit_sect);
+		return WRONG_BUS_FREQUENCY;
+	}
+	wait_for_ctrl_irq (ctrl);
+		
+	if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
+		err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
+			  __FUNCTION__);
+		err("%s: Error code (%d)\n", __FUNCTION__, rc);
+		up(&ctrl->crit_sect);
+		return WRONG_BUS_FREQUENCY;
+	}
+	up(&ctrl->crit_sect);
+	return rc;
+}
+
+static u32 fix_bus_speed(struct controller *ctrl, struct slot *pslot, u8 flag, 
+enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp)
+{ 
+	u32 rc = 0;
+	
+	if (flag != 0) { /* Other slots on the same bus are occupied */
+		if ( asp < bsp ) {
+			err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bsp, asp);
+			return WRONG_BUS_FREQUENCY;
+		}
+	} else {
+		/* Other slots on the same bus are empty */
+		if (msp == bsp) {
+		/* if adapter_speed >= bus_speed, do nothing */
+			if (asp < bsp) {
+				/* 
+				* Try to lower bus speed to accommodate the adapter if other slots 
+				* on the same controller are empty
+				*/
+				if ((rc = change_bus_speed(ctrl, pslot, asp)))
+					return rc;
+			} 
+		} else {
+			if (asp < msp) {
+				if ((rc = change_bus_speed(ctrl, pslot, asp)))
+					return rc;
+			} else {
+				if ((rc = change_bus_speed(ctrl, pslot, msp)))
+					return rc;
+			}
+		}
+	}
+	return rc;
+}
+
+/**
+ * board_added - Called after a board has been added to the system.
+ *
+ * Turns power on for the board
+ * Configures board
+ *
+ */
+static u32 board_added(struct pci_func * func, struct controller * ctrl)
+{
+	u8 hp_slot;
+	u8 slots_not_empty = 0;
+	int index;
+	u32 temp_register = 0xFFFFFFFF;
+	u32 retval, rc = 0;
+	struct pci_func *new_func = NULL;
+	struct slot *p_slot;
+	struct resource_lists res_lists;
+	enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed;
+	u8 pi, mode;
+
+	p_slot = shpchp_find_slot(ctrl, func->device);
+	hp_slot = func->device - ctrl->slot_device_offset;
+
+	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
+
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	/* Power on slot without connecting to bus */
+	rc = p_slot->hpc_ops->power_on_slot(p_slot);
+	if (rc) {
+		err("%s: Failed to power on slot\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return -1;
+	}
+			
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+	
+	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+	if (rc) {
+		err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return -1;
+	}
+
+	
+	if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
+		if (slots_not_empty)
+			return WRONG_BUS_FREQUENCY;
+		
+		if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
+			err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+			up(&ctrl->crit_sect);
+			return WRONG_BUS_FREQUENCY;
+		}
+		wait_for_ctrl_irq (ctrl);
+		
+		if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
+			err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
+				  __FUNCTION__);
+			err("%s: Error code (%d)\n", __FUNCTION__, rc);
+			up(&ctrl->crit_sect);
+			return WRONG_BUS_FREQUENCY;
+		}
+		/* turn on board, blink green LED, turn off Amber LED */
+		if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
+			err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
+			up(&ctrl->crit_sect);
+			return rc;
+		}
+		wait_for_ctrl_irq (ctrl);
+
+		if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
+			err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
+			up(&ctrl->crit_sect);
+			return rc;  
+		}
+	}
+ 
+	rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed);
+	/* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */
+	/* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC,  0xa = PCI-X 133 Mhz 266, */
+	/* 0xd = PCI-X 133 Mhz 533 */
+	/* This encoding is different from the one used in cur_bus_speed & */
+	/* max_bus_speed */
+
+	if (rc  || adapter_speed == PCI_SPEED_UNKNOWN) {
+		err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return WRONG_BUS_FREQUENCY;
+	}
+
+	rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed);
+	if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
+		err("%s: Can't get bus operation speed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return WRONG_BUS_FREQUENCY;
+	}
+
+	rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed);
+	if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
+		err("%s: Can't get max bus operation speed\n", __FUNCTION__);
+		max_bus_speed = bus_speed;
+	}
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	if ((rc  = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) {
+		err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
+		pi = 1;
+	}
+
+	/* Check if there are other slots or devices on the same bus */
+	if (!list_empty(&ctrl->pci_dev->subordinate->devices))
+		slots_not_empty = 1;
+
+	dbg("%s: slots_not_empty %d, pi %d\n", __FUNCTION__, 
+		slots_not_empty, pi);
+	dbg("adapter_speed %d, bus_speed %d, max_bus_speed %d\n", 
+		adapter_speed, bus_speed, max_bus_speed);
+
+	if (pi == 2) {
+		dbg("%s: In PI = %d\n", __FUNCTION__, pi);
+		if ((rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode))) {
+			err("%s: Can't get Mode1_ECC, set mode to 0\n", __FUNCTION__);
+			mode = 0;
+		}
+
+		switch (adapter_speed) {
+		case PCI_SPEED_133MHz_PCIX_533:
+		case PCI_SPEED_133MHz_PCIX_266:
+			if ((bus_speed != adapter_speed) &&
+			   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
+				return rc;
+			break;	
+		case PCI_SPEED_133MHz_PCIX_ECC:
+		case PCI_SPEED_133MHz_PCIX:
+			if (mode) { /* Bus - Mode 1 ECC */
+				if ((bus_speed != 0x7) &&
+				   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
+					return rc;
+			} else {
+				if ((bus_speed != 0x4) &&
+				   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
+					return rc;
+			}
+			break;
+		case PCI_SPEED_66MHz_PCIX_ECC:
+		case PCI_SPEED_66MHz_PCIX:
+			if (mode) { /* Bus - Mode 1 ECC */
+				if ((bus_speed != 0x5) &&
+				   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
+					return rc;
+			} else {
+				if ((bus_speed != 0x2) &&
+				   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
+					return rc;
+			}
+			break;
+		case PCI_SPEED_66MHz:
+			if ((bus_speed != 0x1) &&
+			   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed)))) 
+				return rc;
+			break;	
+		case PCI_SPEED_33MHz:
+			if (bus_speed > 0x0) {
+				if (slots_not_empty == 0) {
+					if ((rc = change_bus_speed(ctrl, p_slot, adapter_speed)))
+						return rc;
+				} else {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+			}
+			break;
+		default:
+			err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+			return WRONG_BUS_FREQUENCY;
+		}
+	} else {
+		/* If adpater_speed == bus_speed, nothing to do here */
+		dbg("%s: In PI = %d\n", __FUNCTION__, pi);
+		if ((adapter_speed != bus_speed) &&
+		   ((rc = fix_bus_speed(ctrl, p_slot, slots_not_empty, adapter_speed, bus_speed, max_bus_speed))))
+				return rc;
+	}
+
+	down(&ctrl->crit_sect);
+	/* turn on board, blink green LED, turn off Amber LED */
+	if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
+		err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
+		up(&ctrl->crit_sect);
+		return rc;
+	}
+	wait_for_ctrl_irq (ctrl);
+
+	if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) {
+		err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
+		up(&ctrl->crit_sect);
+		return rc;  
+	}
+
+	up(&ctrl->crit_sect);
+
+	/* Wait for ~1 second */
+	dbg("%s: before long_delay\n", __FUNCTION__);
+	wait_for_ctrl_irq (ctrl);
+	dbg("%s: after long_delay\n", __FUNCTION__);
+
+	dbg("%s: func status = %x\n", __FUNCTION__, func->status);
+	/* Check for a power fault */
+	if (func->status == 0xFF) {
+		/* power fault occurred, but it was benign */
+		temp_register = 0xFFFFFFFF;
+		dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
+		rc = POWER_FAILURE;
+		func->status = 0;
+	} else {
+		/* Get vendor/device ID u32 */
+		rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), 
+			PCI_VENDOR_ID, &temp_register);
+		dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc);
+		dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register);
+
+		if (rc != 0) {
+			/* Something's wrong here */
+			temp_register = 0xFFFFFFFF;
+			dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register);
+		}
+		/* Preset return code.  It will be changed later if things go okay. */
+		rc = NO_ADAPTER_PRESENT;
+	}
+
+	/* All F's is an empty slot or an invalid board */
+	if (temp_register != 0xFFFFFFFF) {	  /* Check for a board in the slot */
+		res_lists.io_head = ctrl->io_head;
+		res_lists.mem_head = ctrl->mem_head;
+		res_lists.p_mem_head = ctrl->p_mem_head;
+		res_lists.bus_head = ctrl->bus_head;
+		res_lists.irqs = NULL;
+
+		rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0);
+		dbg("%s: back from configure_new_device\n", __FUNCTION__);
+
+		ctrl->io_head = res_lists.io_head;
+		ctrl->mem_head = res_lists.mem_head;
+		ctrl->p_mem_head = res_lists.p_mem_head;
+		ctrl->bus_head = res_lists.bus_head;
+
+		shpchp_resource_sort_and_combine(&(ctrl->mem_head));
+		shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
+		shpchp_resource_sort_and_combine(&(ctrl->io_head));
+		shpchp_resource_sort_and_combine(&(ctrl->bus_head));
+
+		if (rc) {
+			/* Wait for exclusive access to hardware */
+			down(&ctrl->crit_sect);
+
+			/* turn off slot, turn on Amber LED, turn off Green LED */
+			retval = p_slot->hpc_ops->slot_disable(p_slot);
+			if (retval) {
+				err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
+				/* Done with exclusive hardware access */
+				up(&ctrl->crit_sect);
+				return retval;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (ctrl);
+
+			retval = p_slot->hpc_ops->check_cmd_status(ctrl);
+			if (retval) {
+				err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, retval);
+				/* Done with exclusive hardware access */
+				up(&ctrl->crit_sect);
+				return retval;  
+			}
+
+			/* Done with exclusive hardware access */
+			up(&ctrl->crit_sect);
+
+			return(rc);
+		}
+		shpchp_save_slot_config(ctrl, func);
+
+		func->status = 0;
+		func->switch_save = 0x10;
+		func->is_a_board = 0x01;
+		func->pwr_save = 1;
+
+		/* Next, we will instantiate the linux pci_dev structures 
+		 * (with appropriate driver notification, if already present) 
+		 */
+		index = 0;
+		do {
+			new_func = shpchp_slot_find(ctrl->slot_bus, func->device, index++);
+			if (new_func && !new_func->pci_dev) {
+				dbg("%s:call pci_hp_configure_dev\n", __FUNCTION__);
+				shpchp_configure_device(ctrl, new_func);
+			}
+		} while (new_func);
+
+		/* Wait for exclusive access to hardware */
+		down(&ctrl->crit_sect);
+
+		p_slot->hpc_ops->green_led_on(p_slot);
+
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+
+
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+
+	} else {
+		/* Wait for exclusive access to hardware */
+		down(&ctrl->crit_sect);
+
+		/* turn off slot, turn on Amber LED, turn off Green LED */
+		rc = p_slot->hpc_ops->slot_disable(p_slot);
+		if (rc) {
+			err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+			/* Done with exclusive hardware access */
+			up(&ctrl->crit_sect);
+			return rc;
+		}
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+
+		rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+		if (rc) {
+			err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
+			/* Done with exclusive hardware access */
+			up(&ctrl->crit_sect);
+			return rc;  
+		}
+
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+
+		return(rc);
+	}
+	return 0;
+}
+
+
+/**
+ * remove_board - Turns off slot and LED's
+ *
+ */
+static u32 remove_board(struct pci_func *func, struct controller *ctrl)
+{
+	int index;
+	u8 skip = 0;
+	u8 device;
+	u8 hp_slot;
+	u32 rc;
+	struct resource_lists res_lists;
+	struct pci_func *temp_func;
+	struct slot *p_slot;
+
+	if (func == NULL)
+		return(1);
+
+	if (shpchp_unconfigure_device(func))
+		return(1);
+
+	device = func->device;
+
+	hp_slot = func->device - ctrl->slot_device_offset;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+
+	if ((ctrl->add_support) &&
+		!(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) {
+		/* Here we check to see if we've saved any of the board's
+		 * resources already.  If so, we'll skip the attempt to
+		 * determine what's being used.
+		 */
+		index = 0;
+
+		temp_func = func;
+
+		while ((temp_func = shpchp_slot_find(temp_func->bus, temp_func->device, index++))) {
+			if (temp_func->bus_head || temp_func->mem_head
+			    || temp_func->p_mem_head || temp_func->io_head) {
+				skip = 1;
+				break;
+			}
+		}
+
+		if (!skip)
+			rc = shpchp_save_used_resources(ctrl, func, DISABLE_CARD);
+	}
+	/* Change status to shutdown */
+	if (func->is_a_board)
+		func->status = 0x01;
+	func->configured = 0;
+
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	/* turn off slot, turn on Amber LED, turn off Green LED */
+	rc = p_slot->hpc_ops->slot_disable(p_slot);
+	if (rc) {
+		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+
+	rc = p_slot->hpc_ops->check_cmd_status(ctrl);
+	if (rc) {
+		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return rc;  
+	}
+	
+	rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
+	if (rc) {
+		err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&ctrl->crit_sect);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+
+	if (ctrl->add_support) {
+		while (func) {
+			res_lists.io_head = ctrl->io_head;
+			res_lists.mem_head = ctrl->mem_head;
+			res_lists.p_mem_head = ctrl->p_mem_head;
+			res_lists.bus_head = ctrl->bus_head;
+
+			dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", func->bus, 
+				func->device, func->function);
+
+			shpchp_return_board_resources(func, &res_lists);
+
+			ctrl->io_head = res_lists.io_head;
+			ctrl->mem_head = res_lists.mem_head;
+			ctrl->p_mem_head = res_lists.p_mem_head;
+			ctrl->bus_head = res_lists.bus_head;
+
+			shpchp_resource_sort_and_combine(&(ctrl->mem_head));
+			shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
+			shpchp_resource_sort_and_combine(&(ctrl->io_head));
+			shpchp_resource_sort_and_combine(&(ctrl->bus_head));
+
+			if (is_bridge(func)) {
+				dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, 
+					func->device, func->function);
+				bridge_slot_remove(func);
+			} else
+				dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, 
+					func->device, func->function);
+				slot_remove(func);
+
+			func = shpchp_slot_find(ctrl->slot_bus, device, 0);
+		}
+
+		/* Setup slot structure with entry for empty slot */
+		func = shpchp_slot_create(ctrl->slot_bus);
+
+		if (func == NULL) {
+			return(1);
+		}
+
+		func->bus = ctrl->slot_bus;
+		func->device = device;
+		func->function = 0;
+		func->configured = 0;
+		func->switch_save = 0x10;
+		func->pwr_save = 0;
+		func->is_a_board = 0;
+	}
+
+	return 0;
+}
+
+
+static void pushbutton_helper_thread (unsigned long data)
+{
+	pushbutton_pending = data;
+
+	up(&event_semaphore);
+}
+
+
+/**
+ * shpchp_pushbutton_thread
+ *
+ * Scheduled procedure to handle blocking stuff for the pushbuttons
+ * Handles all pending events and exits.
+ *
+ */
+static void shpchp_pushbutton_thread (unsigned long slot)
+{
+	struct slot *p_slot = (struct slot *) slot;
+	u8 getstatus;
+	
+	pushbutton_pending = 0;
+
+	if (!p_slot) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return;
+	}
+
+	p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (getstatus) {
+		p_slot->state = POWEROFF_STATE;
+		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		shpchp_disable_slot(p_slot);
+		p_slot->state = STATIC_STATE;
+	} else {
+		p_slot->state = POWERON_STATE;
+		dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
+
+		if (shpchp_enable_slot(p_slot)) {
+			/* Wait for exclusive access to hardware */
+			down(&p_slot->ctrl->crit_sect);
+
+			p_slot->hpc_ops->green_led_off(p_slot);
+
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot->ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&p_slot->ctrl->crit_sect);
+		}
+		p_slot->state = STATIC_STATE;
+	}
+
+	return;
+}
+
+
+/* this is the main worker thread */
+static int event_thread(void* data)
+{
+	struct controller *ctrl;
+	lock_kernel();
+	daemonize("shpchpd_event");
+	unlock_kernel();
+
+	while (1) {
+		dbg("!!!!event_thread sleeping\n");
+		down_interruptible (&event_semaphore);
+		dbg("event_thread woken finished = %d\n", event_finished);
+		if (event_finished || signal_pending(current))
+			break;
+		/* Do stuff here */
+		if (pushbutton_pending)
+			shpchp_pushbutton_thread(pushbutton_pending);
+		else
+			for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next)
+				interrupt_event_handler(ctrl);
+	}
+	dbg("event_thread signals exit\n");
+	up(&event_exit);
+	return 0;
+}
+
+int shpchp_event_start_thread (void)
+{
+	int pid;
+
+	/* initialize our semaphores */
+	init_MUTEX_LOCKED(&event_exit);
+	event_finished=0;
+
+	init_MUTEX_LOCKED(&event_semaphore);
+	pid = kernel_thread(event_thread, NULL, 0);
+
+	if (pid < 0) {
+		err ("Can't start up our event thread\n");
+		return -1;
+	}
+	dbg("Our event thread pid = %d\n", pid);
+	return 0;
+}
+
+
+void shpchp_event_stop_thread (void)
+{
+	event_finished = 1;
+	dbg("event_thread finish command given\n");
+	up(&event_semaphore);
+	dbg("wait for event_thread to exit\n");
+	down(&event_exit);
+}
+
+
+static int update_slot_info (struct slot *slot)
+{
+	struct hotplug_slot_info *info;
+	int result;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	slot->hpc_ops->get_power_status(slot, &(info->power_status));
+	slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
+	slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
+	slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
+
+	result = pci_hp_change_slot_info(slot->hotplug_slot, info);
+	kfree (info);
+	return result;
+}
+
+static void interrupt_event_handler(struct controller *ctrl)
+{
+	int loop = 0;
+	int change = 1;
+	struct pci_func *func;
+	u8 hp_slot;
+	u8 getstatus;
+	struct slot *p_slot;
+
+	dbg("%s:\n", __FUNCTION__);
+	while (change) {
+		change = 0;
+
+		for (loop = 0; loop < 10; loop++) {
+			if (ctrl->event_queue[loop].event_type != 0) {
+				dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop, 
+					ctrl->event_queue[loop].event_type);
+				hp_slot = ctrl->event_queue[loop].hp_slot;
+
+				func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0);
+
+				p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+				dbg("%s: hp_slot %d, func %p, p_slot %p\n", __FUNCTION__, hp_slot, func, p_slot);
+
+				if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
+					dbg("%s: button cancel\n", __FUNCTION__);
+					del_timer(&p_slot->task_event);
+
+					switch (p_slot->state) {
+					case BLINKINGOFF_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+
+						p_slot->hpc_ops->green_led_on(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+						break;
+					case BLINKINGON_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&ctrl->crit_sect);
+
+						p_slot->hpc_ops->green_led_off(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						p_slot->hpc_ops->set_attention_status(p_slot, 0);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						/* Done with exclusive hardware access */
+						up(&ctrl->crit_sect);
+
+						break;
+					default:
+						warn("Not a valid state\n");
+						return;
+					}
+					info(msg_button_cancel, p_slot->number);
+					p_slot->state = STATIC_STATE;
+				} else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
+					/* Button Pressed (No action on 1st press...) */
+					dbg("%s: Button pressed\n", __FUNCTION__);
+
+					p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+					if (getstatus) {
+						/* slot is on */
+						dbg("%s: slot is on\n", __FUNCTION__);
+						p_slot->state = BLINKINGOFF_STATE;
+						info(msg_button_off, p_slot->number);
+					} else {
+						/* slot is off */
+						dbg("%s: slot is off\n", __FUNCTION__);
+						p_slot->state = BLINKINGON_STATE;
+						info(msg_button_on, p_slot->number);
+					}
+
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					/* blink green LED and turn off amber */
+					p_slot->hpc_ops->green_led_blink(p_slot);
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+					
+					p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+
+					init_timer(&p_slot->task_event);
+					p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
+					p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
+					p_slot->task_event.data = (unsigned long) p_slot;
+
+					dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot);
+					add_timer(&p_slot->task_event);
+				} else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
+					/***********POWER FAULT********************/
+					dbg("%s: power fault\n", __FUNCTION__);
+					/* Wait for exclusive access to hardware */
+					down(&ctrl->crit_sect);
+
+					p_slot->hpc_ops->set_attention_status(p_slot, 1);
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+					
+					p_slot->hpc_ops->green_led_off(p_slot);
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+
+					/* Done with exclusive hardware access */
+					up(&ctrl->crit_sect);
+				} else {
+					/* refresh notification */
+					if (p_slot)
+						update_slot_info(p_slot);
+				}
+
+				ctrl->event_queue[loop].event_type = 0;
+
+				change = 1;
+			}
+		}		/* End of FOR loop */
+	}
+
+	return;
+}
+
+
+int shpchp_enable_slot (struct slot *p_slot)
+{
+	u8 getstatus = 0;
+	int rc;
+	struct pci_func *func;
+
+	func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
+	if (!func) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return 1;
+	}
+
+	/* Check to see if (latch closed, card present, power off) */
+	down(&p_slot->ctrl->crit_sect);
+	rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (rc || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return 1;
+	}
+	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	if (rc || getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return 1;
+	}
+	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (rc || getstatus) {
+		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return 1;
+	}
+	up(&p_slot->ctrl->crit_sect);
+
+	slot_remove(func);
+
+	func = shpchp_slot_create(p_slot->bus);
+	if (func == NULL)
+		return 1;
+
+	func->bus = p_slot->bus;
+	func->device = p_slot->device;
+	func->function = 0;
+	func->configured = 0;
+	func->is_a_board = 1;
+
+	/* We have to save the presence info for these slots */
+	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_power_status(p_slot, &(func->pwr_save));
+	dbg("%s: func->pwr_save %x\n", __FUNCTION__, func->pwr_save);
+	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	func->switch_save = !getstatus? 0x10:0;
+
+	rc = board_added(func, p_slot->ctrl);
+	if (rc) {
+		if (is_bridge(func))
+			bridge_slot_remove(func);
+		else
+			slot_remove(func);
+
+		/* Setup slot structure with entry for empty slot */
+		func = shpchp_slot_create(p_slot->bus);
+		if (func == NULL)
+			return (1);	/* Out of memory */
+
+		func->bus = p_slot->bus;
+		func->device = p_slot->device;
+		func->function = 0;
+		func->configured = 0;
+		func->is_a_board = 1;
+
+		/* We have to save the presence info for these slots */
+		p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+		p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+		func->switch_save = !getstatus? 0x10:0;
+	}
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return rc;
+}
+
+
+int shpchp_disable_slot (struct slot *p_slot)
+{
+	u8 class_code, header_type, BCR;
+	u8 index = 0;
+	u8 getstatus = 0;
+	u32 rc = 0;
+	int ret = 0;
+	unsigned int devfn;
+	struct pci_bus *pci_bus;
+	struct pci_func *func;
+
+	if (!p_slot->ctrl)
+		return 1;
+
+	pci_bus = p_slot->ctrl->pci_dev->subordinate;
+
+	/* Check to see if (latch closed, card present, power on) */
+	down(&p_slot->ctrl->crit_sect);
+
+	ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+	if (ret || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return 1;
+	}
+	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	if (ret || getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return 1;
+	}
+	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+	if (ret || !getstatus) {
+		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
+		up(&p_slot->ctrl->crit_sect);
+		return 1;
+	}
+	up(&p_slot->ctrl->crit_sect);
+
+	func = shpchp_slot_find(p_slot->bus, p_slot->device, index++);
+
+	/* Make sure there are no video controllers here
+	 * for all func of p_slot
+	 */
+	while (func && !rc) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		/* Check the Class Code */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+		if (rc)
+			return rc;
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY) {
+			/* Display/Video adapter (not supported) */
+			rc = REMOVE_NOT_SUPPORTED;
+		} else {
+			/* See if it's a bridge */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+			if (rc)
+				return rc;
+
+			/* If it's a bridge, check the VGA Enable bit */
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
+				if (rc)
+					return rc;
+
+				/* If the VGA Enable bit is set, remove isn't supported */
+				if (BCR & PCI_BRIDGE_CTL_VGA) {
+					rc = REMOVE_NOT_SUPPORTED;
+				}
+			}
+		}
+
+		func = shpchp_slot_find(p_slot->bus, p_slot->device, index++);
+	}
+
+	func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
+	if ((func != NULL) && !rc) {
+		rc = remove_board(func, p_slot->ctrl);
+	} else if (!rc)
+		rc = 1;
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return(rc);
+}
+
+
+/**
+ * configure_new_device - Configures the PCI header information of one board.
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Returns 0 if success
+ *
+ */
+static u32 configure_new_device (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev)
+{
+	u8 temp_byte, function, max_functions, stop_it;
+	int rc;
+	u32 ID;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	int index;
+
+	new_slot = func;
+
+	dbg("%s\n", __FUNCTION__);
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+
+	/* Check for Multi-function device */
+	rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte);
+	if (rc) {
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if (temp_byte & 0x80)	/* Multi-function device */
+		max_functions = 8;
+	else
+		max_functions = 1;
+
+	function = 0;
+
+	do {
+		rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev);
+
+		if (rc) {
+			dbg("configure_new_function failed %d\n",rc);
+			index = 0;
+
+			while (new_slot) {
+				new_slot = shpchp_slot_find(new_slot->bus, new_slot->device, index++);
+
+				if (new_slot)
+					shpchp_return_board_resources(new_slot, resources);
+			}
+
+			return(rc);
+		}
+
+		function++;
+
+		stop_it = 0;
+
+		/*  The following loop skips to the next present function
+		 *  and creates a board structure
+		 */
+
+		while ((function < max_functions) && (!stop_it)) {
+			pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
+
+			if (ID == 0xFFFFFFFF) {	  /* There's nothing there. */
+				function++;
+			} else {  /* There's something there */
+				/* Setup slot structure. */
+				new_slot = shpchp_slot_create(func->bus);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					return(1);
+				}
+
+				new_slot->bus = func->bus;
+				new_slot->device = func->device;
+				new_slot->function = function;
+				new_slot->is_a_board = 1;
+				new_slot->status = 0;
+
+				stop_it++;
+			}
+		}
+
+	} while (function < max_functions);
+	dbg("returning from configure_new_device\n");
+
+	return 0;
+}
+
+
+/*
+ * Configuration logic that involves the hotplug data structures and 
+ * their bookkeeping
+ */
+
+
+/**
+ * configure_new_function - Configures the PCI header information of one device
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Calls itself recursively for bridged devices.
+ * Returns 0 if success
+ *
+ */
+static int configure_new_function (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev)
+{
+	int cloop;
+	u8 temp_byte;
+	u8 device;
+	u8 class_code;
+	u16 temp_word;
+	u32 rc;
+	u32 temp_register;
+	u32 base;
+	u32 ID;
+	unsigned int devfn;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_resource *hold_mem_node;
+	struct pci_resource *hold_p_mem_node;
+	struct pci_resource *hold_IO_node;
+	struct pci_resource *hold_bus_node;
+	struct irq_mapping irqs;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct resource_lists temp_resources;
+#if defined(CONFIG_X86_64)
+	u8 IRQ=0;
+#endif
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	/* Check for Bridge */
+	rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte);
+	if (rc)
+		return rc;
+
+	if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+		/* set Primary bus */
+		dbg("set Primary bus = 0x%x\n", func->bus);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
+		if (rc)
+			return rc;
+
+		/* find range of busses to use */
+		bus_node = get_max_resource(&resources->bus_head, 1L);
+
+		/* If we don't have any busses to allocate, we can't continue */
+		if (!bus_node) {
+			err("Got NO bus resource to use\n");
+			return -ENOMEM;
+		}
+		dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length);
+
+		/* set Secondary bus */
+		temp_byte = (u8)bus_node->base;
+		dbg("set Secondary bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* set subordinate bus */
+		temp_byte = (u8)(bus_node->base + bus_node->length - 1);
+		dbg("set subordinate bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+		if (rc)
+			return rc;
+
+		/* Setup the IO, memory, and prefetchable windows */
+
+		io_node = get_max_resource(&(resources->io_head), 0x1000L);
+		if (io_node) {
+			dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next);
+		}
+
+		mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+		if (mem_node) {
+			dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next);
+		}
+
+		if (resources->p_mem_head)
+			p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L);
+		else {
+			/*
+			 * In some platform implementation, MEM and PMEM are not
+			 *  distinguished, and hence ACPI _CRS has only MEM entries
+			 *  for both MEM and PMEM.
+			 */
+			dbg("using MEM for PMEM\n");
+			p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L);
+		}
+		if (p_mem_node) {
+			dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next);
+		}
+
+		/* set up the IRQ info */
+		if (!resources->irqs) {
+			irqs.barber_pole = 0;
+			irqs.interrupt[0] = 0;
+			irqs.interrupt[1] = 0;
+			irqs.interrupt[2] = 0;
+			irqs.interrupt[3] = 0;
+			irqs.valid_INT = 0;
+		} else {
+			irqs.barber_pole = resources->irqs->barber_pole;
+			irqs.interrupt[0] = resources->irqs->interrupt[0];
+			irqs.interrupt[1] = resources->irqs->interrupt[1];
+			irqs.interrupt[2] = resources->irqs->interrupt[2];
+			irqs.interrupt[3] = resources->irqs->interrupt[3];
+			irqs.valid_INT = resources->irqs->valid_INT;
+		}
+
+		/* set up resource lists that are now aligned on top and bottom
+		 * for anything behind the bridge.
+		 */
+		temp_resources.bus_head = bus_node;
+		temp_resources.io_head = io_node;
+		temp_resources.mem_head = mem_node;
+		temp_resources.p_mem_head = p_mem_node;
+		temp_resources.irqs = &irqs;
+
+		/* Make copies of the nodes we are going to pass down so that
+		 * if there is a problem,we can just use these to free resources
+		 */
+		hold_bus_node = kmalloc(sizeof(*hold_bus_node), GFP_KERNEL);
+		hold_IO_node = kmalloc(sizeof(*hold_IO_node), GFP_KERNEL);
+		hold_mem_node = kmalloc(sizeof(*hold_mem_node), GFP_KERNEL);
+		hold_p_mem_node = kmalloc(sizeof(*hold_p_mem_node), GFP_KERNEL);
+
+		if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
+			kfree(hold_bus_node);
+			kfree(hold_IO_node);
+			kfree(hold_mem_node);
+			kfree(hold_p_mem_node);
+
+			return 1;
+		}
+
+		memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
+
+		bus_node->base += 1;
+		bus_node->length -= 1;
+		bus_node->next = NULL;
+
+		/* If we have IO resources copy them and fill in the bridge's
+		 * IO range registers
+		 */
+		if (io_node) {
+			memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
+			io_node->next = NULL;
+
+			/* set IO base and Limit registers */
+			RES_CHECK(io_node->base, 8);
+			temp_byte = (u8)(io_node->base >> 8);
+			rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+			RES_CHECK(io_node->base + io_node->length - 1, 8);
+			temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8);
+			rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+		} else {
+			kfree(hold_IO_node);
+			hold_IO_node = NULL;
+		}
+
+		/* If we have memory resources copy them and fill in the bridge's
+		 * memory range registers.  Otherwise, fill in the range
+		 * registers with values that disable them.
+		 */
+		if (mem_node) {
+			memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
+			mem_node->next = NULL;
+
+			/* set Mem base and Limit registers */
+			RES_CHECK(mem_node->base, 16);
+			temp_word = (u32)(mem_node->base >> 16);
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			RES_CHECK(mem_node->base + mem_node->length - 1, 16);
+			temp_word = (u32)((mem_node->base + mem_node->length - 1) >> 16);
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_mem_node);
+			hold_mem_node = NULL;
+		}
+
+		/* If we have prefetchable memory resources copy them and 
+		 * fill in the bridge's memory range registers.  Otherwise,
+		 * fill in the range registers with values that disable them.
+		 */
+		if (p_mem_node) {
+			memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
+			p_mem_node->next = NULL;
+
+			/* set Pre Mem base and Limit registers */
+			RES_CHECK(p_mem_node->base, 16);
+			temp_word = (u32)(p_mem_node->base >> 16);
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16);
+			temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16);
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_p_mem_node);
+			hold_p_mem_node = NULL;
+		}
+
+		/* Adjust this to compensate for extra adjustment in first loop */
+		irqs.barber_pole--;
+
+		rc = 0;
+
+		/* Here we actually find the devices and configure them */
+		for (device = 0; (device <= 0x1F) && !rc; device++) {
+			irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
+
+			ID = 0xFFFFFFFF;
+			pci_bus->number = hold_bus_node->base;
+			pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0),
+					PCI_VENDOR_ID, &ID);
+			pci_bus->number = func->bus;
+
+			if (ID != 0xFFFFFFFF) {	  /*  device Present */
+				/* Setup slot structure. */
+				new_slot = shpchp_slot_create(hold_bus_node->base);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					rc = -ENOMEM;
+					continue;
+				}
+
+				new_slot->bus = hold_bus_node->base;
+				new_slot->device = device;
+				new_slot->function = 0;
+				new_slot->is_a_board = 1;
+				new_slot->status = 0;
+
+				rc = configure_new_device(ctrl, new_slot, 1, &temp_resources, func->bus, func->device);
+				dbg("configure_new_device rc=0x%x\n",rc);
+			}	/* End of IF (device in slot?) */
+		}		/* End of FOR loop */
+
+		if (rc) {
+			shpchp_destroy_resource_list(&temp_resources);
+
+			return_resource(&(resources->bus_head), hold_bus_node);
+			return_resource(&(resources->io_head), hold_IO_node);
+			return_resource(&(resources->mem_head), hold_mem_node);
+			return_resource(&(resources->p_mem_head), hold_p_mem_node);
+			return(rc);
+		}
+
+		/* save the interrupt routing information */
+		if (resources->irqs) {
+			resources->irqs->interrupt[0] = irqs.interrupt[0];
+			resources->irqs->interrupt[1] = irqs.interrupt[1];
+			resources->irqs->interrupt[2] = irqs.interrupt[2];
+			resources->irqs->interrupt[3] = irqs.interrupt[3];
+			resources->irqs->valid_INT = irqs.valid_INT;
+		} else if (!behind_bridge) {
+			/* We need to hook up the interrupts here */
+			for (cloop = 0; cloop < 4; cloop++) {
+				if (irqs.valid_INT & (0x01 << cloop)) {
+					rc = shpchp_set_irq(func->bus, func->device,
+							   0x0A + cloop, irqs.interrupt[cloop]);
+					if (rc) {
+						shpchp_destroy_resource_list (&temp_resources);
+						return_resource(&(resources->bus_head), hold_bus_node);
+						return_resource(&(resources->io_head), hold_IO_node);
+						return_resource(&(resources->mem_head), hold_mem_node);
+						return_resource(&(resources->p_mem_head), hold_p_mem_node);
+						return rc;
+					}
+				}
+			}	/* end of for loop */
+		}
+
+		/* Return unused bus resources
+		 * First use the temporary node to store information for the board
+		 */
+		if (hold_bus_node && bus_node && temp_resources.bus_head) {
+			hold_bus_node->length = bus_node->base - hold_bus_node->base;
+
+			hold_bus_node->next = func->bus_head;
+			func->bus_head = hold_bus_node;
+
+			temp_byte = (u8)(temp_resources.bus_head->base - 1);
+
+			/* set subordinate bus */
+			dbg("re-set subordinate bus = 0x%x\n", temp_byte);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+
+			if (temp_resources.bus_head->length == 0) {
+				kfree(temp_resources.bus_head);
+				temp_resources.bus_head = NULL;
+			} else {
+				dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
+					func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length);
+				return_resource(&(resources->bus_head), temp_resources.bus_head);
+			}
+		}
+
+		/* If we have IO space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_IO_node && temp_resources.io_head) {
+			io_node = do_pre_bridge_resource_split(&(temp_resources.io_head),
+							       &hold_IO_node, 0x1000);
+
+			/* Check if we were able to split something off */
+			if (io_node) {
+				hold_IO_node->base = io_node->base + io_node->length;
+
+				RES_CHECK(hold_IO_node->base, 8);
+				temp_byte = (u8)((hold_IO_node->base) >> 8);
+				rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+				return_resource(&(resources->io_head), io_node);
+			}
+
+			io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000);
+
+			/*  Check if we were able to split something off */
+			if (io_node) {
+				/* First use the temporary node to store information for the board */
+				hold_IO_node->length = io_node->base - hold_IO_node->base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_IO_node->length) {
+					hold_IO_node->next = func->io_head;
+					func->io_head = hold_IO_node;
+
+					RES_CHECK(io_node->base - 1, 8);
+					temp_byte = (u8)((io_node->base - 1) >> 8);
+					rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&(resources->io_head), io_node);
+				} else {
+					/* it doesn't need any IO */
+					temp_byte = 0x00;
+					rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&(resources->io_head), io_node);
+					kfree(hold_IO_node);
+				}
+			} else {
+				/* it used most of the range */
+				hold_IO_node->next = func->io_head;
+				func->io_head = hold_IO_node;
+			}
+		} else if (hold_IO_node) {
+			/* it used the whole range */
+			hold_IO_node->next = func->io_head;
+			func->io_head = hold_IO_node;
+		}
+
+		/* If we have memory space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_mem_node && temp_resources.mem_head) {
+			mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				hold_mem_node->base = mem_node->base + mem_node->length;
+
+				RES_CHECK(hold_mem_node->base, 16);
+				temp_word = (u32)((hold_mem_node->base) >> 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+				return_resource(&(resources->mem_head), mem_node);
+			}
+
+			mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_mem_node->length = mem_node->base - hold_mem_node->base;
+
+				if (hold_mem_node->length) {
+					hold_mem_node->next = func->mem_head;
+					func->mem_head = hold_mem_node;
+
+					/* configure end address */
+					RES_CHECK(mem_node->base - 1, 16);
+					temp_word = (u32)((mem_node->base - 1) >> 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					/* Return unused resources to the pool */
+					return_resource(&(resources->mem_head), mem_node);
+				} else {
+					/* it doesn't need any Mem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->mem_head), mem_node);
+					kfree(hold_mem_node);
+				}
+			} else {
+				/* it used most of the range */
+				hold_mem_node->next = func->mem_head;
+				func->mem_head = hold_mem_node;
+			}
+		} else if (hold_mem_node) {
+			/* it used the whole range */
+			hold_mem_node->next = func->mem_head;
+			func->mem_head = hold_mem_node;
+		}
+
+		/* If we have prefetchable memory space available and there is some 
+		 * left at the end, return the unused portion
+		 */
+		if (hold_p_mem_node && temp_resources.p_mem_head) {
+			p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head),
+								  &hold_p_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				hold_p_mem_node->base = p_mem_node->base + p_mem_node->length;
+
+				RES_CHECK(hold_p_mem_node->base, 16);
+				temp_word = (u32)((hold_p_mem_node->base) >> 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+				return_resource(&(resources->p_mem_head), p_mem_node);
+			}
+
+			p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_p_mem_node->length) {
+					hold_p_mem_node->next = func->p_mem_head;
+					func->p_mem_head = hold_p_mem_node;
+
+					RES_CHECK(p_mem_node->base - 1, 16);
+					temp_word = (u32)((p_mem_node->base - 1) >> 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->p_mem_head), p_mem_node);
+				} else {
+					/* it doesn't need any PMem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&(resources->p_mem_head), p_mem_node);
+					kfree(hold_p_mem_node);
+				}
+			} else {
+				/* it used the most of the range */
+				hold_p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = hold_p_mem_node;
+			}
+		} else if (hold_p_mem_node) {
+			/* it used the whole range */
+			hold_p_mem_node->next = func->p_mem_head;
+			func->p_mem_head = hold_p_mem_node;
+		}
+
+		/* We should be configuring an IRQ and the bridge's base address
+		 * registers if it needs them.  Although we have never seen such
+		 * a device
+		 */
+
+		shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+
+		dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function);
+	} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+		/* Standard device */
+		u64	base64;
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY)
+			return (DEVICE_TYPE_NOT_SUPPORTED);
+
+		/* Figure out IO and memory needs */
+		for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
+			temp_register = 0xFFFFFFFF;
+
+			rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+			rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register);
+			dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, func->bus, func->device, 
+				func->function);
+
+			if (!temp_register)
+				continue;
+
+			base64 = 0L;
+			if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) {
+				/* Map IO */
+
+				/* set base = amount of IO space */
+				base = temp_register & 0xFFFFFFFC;
+				base = ~base + 1;
+
+				dbg("NEED IO length(0x%x)\n", base);
+				io_node = get_io_resource(&(resources->io_head),(ulong)base);
+
+				/* allocate the resource to the board */
+				if (io_node) {
+					dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length);
+					base = (u32)io_node->base;
+					io_node->next = func->io_head;
+					func->io_head = io_node;
+				} else {
+					err("Got NO IO resource(length=0x%x)\n", base);
+					return -ENOMEM;
+				}
+			} else {	/* map MEM */
+				int prefetchable = 1;
+				struct pci_resource **res_node = &func->p_mem_head;
+				char *res_type_str = "PMEM";
+				u32	temp_register2;
+
+				if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) {
+					prefetchable = 0;
+					res_node = &func->mem_head;
+					res_type_str++;
+				}
+
+				base = temp_register & 0xFFFFFFF0;
+				base = ~base + 1;
+
+				switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+				case PCI_BASE_ADDRESS_MEM_TYPE_32:
+					dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base);
+
+					if (prefetchable && resources->p_mem_head)
+						mem_node=get_resource(&(resources->p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node=get_resource(&(resources->mem_head), (ulong)base);
+					}
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base = (u32)mem_node->base; 
+						mem_node->next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, 
+							mem_node->length);
+					} else {
+						err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				case PCI_BASE_ADDRESS_MEM_TYPE_64:
+					rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+					dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, 
+						temp_register, base);
+
+					if (prefetchable && resources->p_mem_head)
+						mem_node = get_resource(&(resources->p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node = get_resource(&(resources->mem_head), (ulong)base);
+					}
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base64 = mem_node->base; 
+						mem_node->next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), 
+							(u32)base64, mem_node->length);
+					} else {
+						err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				default:
+					dbg("reserved BAR type=0x%x\n", temp_register);
+					break;
+				}
+
+			}
+
+			if (base64) {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+				cloop += 4;
+				base64 >>= 32;
+
+				if (base64) {
+					dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64);
+					base64 = 0x0L;
+				}
+
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+			} else {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base);
+			}
+		}		/* End of base register loop */
+
+#if defined(CONFIG_X86_64)
+		/* Figure out which interrupt pin this function uses */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte);
+
+		/* If this function needs an interrupt and we are behind a bridge
+		   and the pin is tied to something that's alread mapped,
+		   set this one the same
+		 */
+		if (temp_byte && resources->irqs && 
+		    (resources->irqs->valid_INT & 
+		     (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) {
+			/* We have to share with something already set up */
+			IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03];
+		} else {
+			/* Program IRQ based on card type */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+
+			if (class_code == PCI_BASE_CLASS_STORAGE) {
+				IRQ = shpchp_disk_irq;
+			} else {
+				IRQ = shpchp_nic_irq;
+			}
+		}
+
+		/* IRQ Line */
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ);
+
+		if (!behind_bridge) {
+			rc = shpchp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ);
+			if (rc)
+				return(1);
+		} else {
+			/* TBD - this code may also belong in the other clause of this If statement */
+			resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ;
+			resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03;
+		}
+#endif
+		/* Disable ROM base Address */
+		temp_word = 0x00L;
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word);
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+		if (rc)
+			return rc;
+
+		shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+
+		dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function);
+	}			/* End of Not-A-Bridge else */
+	else {
+		/* It's some strange type of PCI adapter (Cardbus?) */
+		return(DEVICE_TYPE_NOT_SUPPORTED);
+	}
+
+	func->configured = 1;
+
+	return 0;
+}
+
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
new file mode 100644
index 0000000..38c5d90
--- /dev/null
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -0,0 +1,1620 @@
+/*
+ * Standard PCI Hot Plug Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>,<dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include "shpchp.h"
+
+#ifdef DEBUG
+#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
+#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
+#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
+#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
+#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
+#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
+/* Redefine this flagword to set debug level */
+#define DEBUG_LEVEL            DBG_K_STANDARD
+
+#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
+
+#define DBG_PRINT( dbg_flags, args... )              \
+	do {                                             \
+	  if ( DEBUG_LEVEL & ( dbg_flags ) )             \
+	  {                                              \
+	    int len;                                     \
+	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
+		  __FILE__, __LINE__, __FUNCTION__ );    \
+	    sprintf( __dbg_str_buf + len, args );        \
+	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
+	  }                                              \
+	} while (0)
+
+#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
+#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
+#else
+#define DEFINE_DBG_BUFFER
+#define DBG_ENTER_ROUTINE
+#define DBG_LEAVE_ROUTINE
+#endif				/* DEBUG */
+
+/* Slot Available Register I field definition */
+#define SLOT_33MHZ		0x0000001f
+#define SLOT_66MHZ_PCIX		0x00001f00
+#define SLOT_100MHZ_PCIX	0x001f0000
+#define SLOT_133MHZ_PCIX	0x1f000000
+
+/* Slot Available Register II field definition */
+#define SLOT_66MHZ		0x0000001f
+#define SLOT_66MHZ_PCIX_266	0x00000f00
+#define SLOT_100MHZ_PCIX_266	0x0000f000
+#define SLOT_133MHZ_PCIX_266	0x000f0000
+#define SLOT_66MHZ_PCIX_533	0x00f00000
+#define SLOT_100MHZ_PCIX_533	0x0f000000
+#define SLOT_133MHZ_PCIX_533	0xf0000000
+
+
+/* Secondary Bus Configuration Register */
+/* For PI = 1, Bits 0 to 2 have been encoded as follows to show current bus speed/mode */
+#define PCI_33MHZ		0x0
+#define PCI_66MHZ		0x1
+#define PCIX_66MHZ		0x2
+#define PCIX_100MHZ		0x3
+#define PCIX_133MHZ		0x4
+
+/* For PI = 2, Bits 0 to 3 have been encoded as follows to show current bus speed/mode */
+#define PCI_33MHZ		0x0
+#define PCI_66MHZ		0x1
+#define PCIX_66MHZ		0x2
+#define PCIX_100MHZ		0x3
+#define PCIX_133MHZ		0x4
+#define PCIX_66MHZ_ECC		0x5
+#define PCIX_100MHZ_ECC		0x6
+#define PCIX_133MHZ_ECC		0x7
+#define PCIX_66MHZ_266		0x9
+#define PCIX_100MHZ_266		0xa
+#define PCIX_133MHZ_266		0xb
+#define PCIX_66MHZ_533		0x11
+#define PCIX_100MHZ_533		0x12
+#define PCIX_133MHZ_533		0x13
+
+/* Slot Configuration */
+#define SLOT_NUM		0x0000001F
+#define	FIRST_DEV_NUM		0x00001F00
+#define PSN			0x07FF0000
+#define	UPDOWN			0x20000000
+#define	MRLSENSOR		0x40000000
+#define ATTN_BUTTON		0x80000000
+
+/* Slot Status Field Definitions */
+/* Slot State */
+#define PWR_ONLY		0x0001
+#define ENABLED			0x0002
+#define DISABLED		0x0003
+
+/* Power Indicator State */
+#define PWR_LED_ON		0x0004
+#define PWR_LED_BLINK		0x0008
+#define PWR_LED_OFF		0x000c
+
+/* Attention Indicator State */
+#define ATTEN_LED_ON		0x0010
+#define	ATTEN_LED_BLINK		0x0020
+#define ATTEN_LED_OFF		0x0030
+
+/* Power Fault */
+#define pwr_fault		0x0040
+
+/* Attention Button */
+#define ATTEN_BUTTON		0x0080
+
+/* MRL Sensor */
+#define MRL_SENSOR		0x0100
+
+/* 66 MHz Capable */
+#define IS_66MHZ_CAP		0x0200
+
+/* PRSNT1#/PRSNT2# */
+#define SLOT_EMP		0x0c00
+
+/* PCI-X Capability */
+#define NON_PCIX		0x0000
+#define PCIX_66			0x1000
+#define PCIX_133		0x3000
+#define PCIX_266		0x4000  /* For PI = 2 only */
+#define PCIX_533		0x5000	/* For PI = 2 only */
+
+/* SHPC 'write' operations/commands */
+
+/* Slot operation - 0x00h to 0x3Fh */
+
+#define NO_CHANGE		0x00
+
+/* Slot state - Bits 0 & 1 of controller command register */
+#define SET_SLOT_PWR		0x01	
+#define SET_SLOT_ENABLE		0x02	
+#define SET_SLOT_DISABLE	0x03	
+
+/* Power indicator state - Bits 2 & 3 of controller command register*/
+#define SET_PWR_ON		0x04	
+#define SET_PWR_BLINK		0x08	
+#define SET_PWR_OFF		0x0C	
+
+/* Attention indicator state - Bits 4 & 5 of controller command register*/
+#define SET_ATTN_ON		0x010	
+#define SET_ATTN_BLINK		0x020
+#define SET_ATTN_OFF		0x030	
+
+/* Set bus speed/mode A - 0x40h to 0x47h */
+#define SETA_PCI_33MHZ		0x40
+#define SETA_PCI_66MHZ		0x41
+#define SETA_PCIX_66MHZ		0x42
+#define SETA_PCIX_100MHZ	0x43
+#define SETA_PCIX_133MHZ	0x44
+#define RESERV_1		0x45
+#define RESERV_2		0x46
+#define RESERV_3		0x47
+
+/* Set bus speed/mode B - 0x50h to 0x5fh */
+#define	SETB_PCI_33MHZ		0x50
+#define SETB_PCI_66MHZ		0x51
+#define SETB_PCIX_66MHZ_PM	0x52
+#define SETB_PCIX_100MHZ_PM	0x53
+#define SETB_PCIX_133MHZ_PM	0x54
+#define SETB_PCIX_66MHZ_EM	0x55
+#define SETB_PCIX_100MHZ_EM	0x56
+#define SETB_PCIX_133MHZ_EM	0x57
+#define SETB_PCIX_66MHZ_266	0x58
+#define SETB_PCIX_100MHZ_266	0x59
+#define SETB_PCIX_133MHZ_266	0x5a
+#define SETB_PCIX_66MHZ_533	0x5b
+#define SETB_PCIX_100MHZ_533	0x5c
+#define SETB_PCIX_133MHZ_533	0x5d
+
+
+/* Power-on all slots - 0x48h */
+#define SET_PWR_ON_ALL		0x48
+
+/* Enable all slots	- 0x49h */
+#define SET_ENABLE_ALL		0x49
+
+/*  SHPC controller command error code */
+#define SWITCH_OPEN		0x1
+#define INVALID_CMD		0x2
+#define INVALID_SPEED_MODE	0x4
+
+/* For accessing SHPC Working Register Set */
+#define DWORD_SELECT		0x2
+#define DWORD_DATA		0x4
+#define BASE_OFFSET		0x0
+
+/* Field Offset in Logical Slot Register - byte boundary */
+#define SLOT_EVENT_LATCH	0x2
+#define SLOT_SERR_INT_MASK	0x3
+
+static spinlock_t hpc_event_lock;
+
+DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
+static struct php_ctlr_state_s *php_ctlr_list_head;	/* HPC state linked list */
+static int ctlr_seq_num = 0;	/* Controller sequenc # */
+static spinlock_t list_lock;
+
+static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);
+
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+
+/* This is the interrupt polling timeout function. */
+static void int_poll_timeout(unsigned long lphp_ctlr)
+{
+    struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+
+    DBG_ENTER_ROUTINE
+
+    if ( !php_ctlr ) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+    }
+
+    /* Poll for interrupt events.  regs == NULL => polling */
+    shpc_isr( 0, (void *)php_ctlr, NULL );
+
+    init_timer(&php_ctlr->int_poll_timer);
+	if (!shpchp_poll_time)
+		shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+
+    start_int_poll_timer(php_ctlr, shpchp_poll_time);  
+	
+	return;
+}
+
+/* This function starts the interrupt polling timer. */
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+{
+    if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+	}
+
+    if ( ( seconds <= 0 ) || ( seconds > 60 ) )
+        seconds = 2;            /* Clamp to sane value */
+
+    php_ctlr->int_poll_timer.function = &int_poll_timeout;
+    php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
+    php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
+    add_timer(&php_ctlr->int_poll_timer);
+
+	return;
+}
+
+static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 cmd_status;
+	int retval = 0;
+	u16 temp_word;
+	int i;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	for (i = 0; i < 10; i++) {
+		cmd_status = readw(php_ctlr->creg + CMD_STATUS);
+		
+		if (!(cmd_status & 0x1))
+			break;
+		/*  Check every 0.1 sec for a total of 1 sec*/
+		msleep(100);
+	}
+
+	cmd_status = readw(php_ctlr->creg + CMD_STATUS);
+	
+	if (cmd_status & 0x1) { 
+		/* After 1 sec and and the controller is still busy */
+		err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
+		return -1;
+	}
+
+	++t_slot;
+	temp_word =  (t_slot << 8) | (cmd & 0xFF);
+	dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
+	
+	/* To make sure the Controller Busy bit is 0 before we send out the
+	 * command. 
+	 */
+	writew(temp_word, php_ctlr->creg + CMD);
+	dbg("%s: temp_word written %x\n", __FUNCTION__, temp_word);
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_check_cmd_status(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+	u16 cmd_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F;
+	
+	switch (cmd_status >> 1) {
+	case 0:
+		retval = 0;
+		break;
+	case 1:
+		retval = SWITCH_OPEN;
+		err("%s: Switch opened!\n", __FUNCTION__);
+		break;
+	case 2:
+		retval = INVALID_CMD;
+		err("%s: Invalid HPC command!\n", __FUNCTION__);
+		break;
+	case 4:
+		retval = INVALID_SPEED_MODE;
+		err("%s: Invalid bus speed/mode!\n", __FUNCTION__);
+		break;
+	default:
+		retval = cmd_status;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_attention_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 atten_led_state;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16) slot_reg;
+	atten_led_state = (slot_status & 0x0030) >> 4;
+
+	switch (atten_led_state) {
+	case 0:
+		*status = 0xFF;	/* Reserved */
+		break;
+	case 1:
+		*status = 1;	/* On */
+		break;
+	case 2:
+		*status = 2;	/* Blink */
+		break;
+	case 3:
+		*status = 0;	/* Off */
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_power_status(struct slot * slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 slot_state;
+	int	retval = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16) slot_reg;
+	slot_state = (slot_status & 0x0003);
+
+	switch (slot_state) {
+	case 0:
+		*status = 0xFF;
+		break;
+	case 1:
+		*status = 2;	/* Powered only */
+		break;
+	case 2:
+		*status = 1;	/* Enabled */
+		break;
+	case 3:
+		*status = 0;	/* Disabled */
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_latch_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16)slot_reg;
+
+	*status = ((slot_status & 0x0100) == 0) ? 0 : 1;   /* 0 -> close; 1 -> open */
+
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_adapter_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 card_state;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16)slot_reg;
+	card_state = (u8)((slot_status & 0x0C00) >> 10);
+	*status = (card_state != 0x3) ? 1 : 0;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	*prog_int = readb(php_ctlr->creg + PROG_INTERFACE);
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status, sec_bus_status;
+	u8 m66_cap, pcix_cap, pi;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	dbg("%s: pi = %d, slot_reg = %x\n", __FUNCTION__, pi, slot_reg);
+	slot_status = (u16) slot_reg;
+	dbg("%s: slot_status = %x\n", __FUNCTION__, slot_status);
+	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
+
+	pcix_cap = (u8) ((slot_status & 0x3000) >> 12);
+	dbg("%s:  pcix_cap = %x\n", __FUNCTION__, pcix_cap);
+	m66_cap = (u8) ((slot_status & 0x0200) >> 9);
+	dbg("%s:  m66_cap = %x\n", __FUNCTION__, m66_cap);
+
+
+	if (pi == 2) {
+		switch (pcix_cap) {
+		case 0:
+			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
+			break;
+		case 1:
+			*value = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			*value = PCI_SPEED_133MHz_PCIX;
+			break;
+		case 4:
+			*value = PCI_SPEED_133MHz_PCIX_266;	
+			break;
+		case 5:
+			*value = PCI_SPEED_133MHz_PCIX_533;	
+			break;
+		case 2:	/* Reserved */
+		default:
+			*value = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			break;
+		}
+	} else {
+		switch (pcix_cap) {
+		case 0:
+			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
+			break;
+		case 1:
+			*value = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			*value = PCI_SPEED_133MHz_PCIX;	
+			break;
+		case 2:	/* Reserved */
+		default:
+			*value = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			break;
+		}
+	}
+
+	dbg("Adapter speed = %d\n", *value);
+	
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u16 sec_bus_status;
+	u8 pi;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
+
+	if (pi == 2) {
+		*mode = (sec_bus_status & 0x0100) >> 7;
+	} else {
+		retval = -1;
+	}
+
+	dbg("Mode 1 ECC cap = %d\n", *mode);
+	
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_query_power_fault(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 pwr_fault_state, status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
+	slot_status = (u16) slot_reg;
+	pwr_fault_state = (slot_status & 0x0040) >> 7;
+	status = (pwr_fault_state == 1) ? 0 : 1;
+
+	DBG_LEAVE_ROUTINE
+	/* Note: Logic 0 => fault */
+	return status;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd = 0;
+	int rc = 0;
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	switch (value) {
+		case 0 :	
+			slot_cmd = 0x30;	/* OFF */
+			break;
+		case 1:
+			slot_cmd = 0x10;	/* ON */
+			break;
+		case 2:
+			slot_cmd = 0x20;	/* BLINK */
+			break;
+		default:
+			return -1;
+	}
+
+	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+	
+	return rc;
+}
+
+
+static void hpc_set_green_led_on(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	slot_cmd = 0x04;
+
+	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	return;
+}
+
+static void hpc_set_green_led_off(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	slot_cmd = 0x0C;
+
+	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	return;
+}
+
+static void hpc_set_green_led_blink(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	slot_cmd = 0x08;
+
+	shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	return;
+}
+
+int shpc_get_ctlr_slot_config(struct controller *ctrl,
+	int *num_ctlr_slots,	/* number of slots in this HPC			*/
+	int *first_device_num,	/* PCI dev num of the first slot in this SHPC	*/
+	int *physical_slot_num,	/* phy slot num of the first slot in this SHPC	*/
+	int *updown,		/* physical_slot_num increament: 1 or -1	*/
+	int *flags)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	*first_device_num = php_ctlr->slot_device_offset;	/* Obtained in shpc_init() */
+	*num_ctlr_slots = php_ctlr->num_slots;			/* Obtained in shpc_init() */
+
+	*physical_slot_num = (readl(php_ctlr->creg + SLOT_CONFIG) & PSN) >> 16;
+	dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);
+	*updown = ((readl(php_ctlr->creg + SLOT_CONFIG) & UPDOWN ) >> 29) ? 1 : -1;	
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static void hpc_release_ctlr(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle;
+	struct php_ctlr_state_s *p, *p_prev;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (shpchp_poll_mode) {
+	    del_timer(&php_ctlr->int_poll_timer);
+	} else {	
+		if (php_ctlr->irq) {
+			free_irq(php_ctlr->irq, ctrl);
+			php_ctlr->irq = 0;
+			pci_disable_msi(php_ctlr->pci_dev);
+		}
+	}
+	if (php_ctlr->pci_dev) {
+		dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__);
+		iounmap(php_ctlr->creg);
+		release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0));
+		dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__);
+		php_ctlr->pci_dev = NULL;
+	}
+
+	spin_lock(&list_lock);
+	p = php_ctlr_list_head;
+	p_prev = NULL;
+	while (p) {
+		if (p == php_ctlr) {
+			if (p_prev)
+				p_prev->pnext = p->pnext;
+			else
+				php_ctlr_list_head = p->pnext;
+			break;
+		} else {
+			p_prev = p;
+			p = p->pnext;
+		}
+	}
+	spin_unlock(&list_lock);
+
+	kfree(php_ctlr);
+
+DBG_LEAVE_ROUTINE
+			  
+}
+
+static int hpc_power_on_slot(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	slot_cmd = 0x01;
+
+	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static int hpc_slot_enable(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	/* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
+	slot_cmd = 0x3A;  
+
+	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_slot_disable(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	u8 slot_cmd;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	/* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */
+	slot_cmd = 0x1F;
+
+	retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_enable_all_slots( struct slot *slot )
+{
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = shpc_write_cmd(slot, 0, SET_ENABLE_ALL);
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static int hpc_pwr_on_all_slots(struct slot *slot)
+{
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	retval = shpc_write_cmd(slot, 0, SET_PWR_ON_ALL);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
+{
+	u8 slot_cmd;
+	u8 pi;
+	int retval = 0;
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	
+	if (pi == 1) {
+		switch (value) {
+		case 0:
+			slot_cmd = SETA_PCI_33MHZ;
+			break;
+		case 1:
+			slot_cmd = SETA_PCI_66MHZ;
+			break;
+		case 2:
+			slot_cmd = SETA_PCIX_66MHZ;
+			break;
+		case 3:
+			slot_cmd = SETA_PCIX_100MHZ;	
+			break;
+		case 4:
+			slot_cmd = SETA_PCIX_133MHZ;	
+			break;
+		default:
+			slot_cmd = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			return retval;	
+		}
+	} else {
+		switch (value) {
+		case 0:
+			slot_cmd = SETB_PCI_33MHZ;
+			break;
+		case 1:
+			slot_cmd = SETB_PCI_66MHZ;
+			break;
+		case 2:
+			slot_cmd = SETB_PCIX_66MHZ_PM;
+			break;
+		case 3:
+			slot_cmd = SETB_PCIX_100MHZ_PM;	
+			break;
+		case 4:
+			slot_cmd = SETB_PCIX_133MHZ_PM;	
+			break;
+		case 5:
+			slot_cmd = SETB_PCIX_66MHZ_EM;	
+			break;
+		case 6:
+			slot_cmd = SETB_PCIX_100MHZ_EM;	
+			break;
+		case 7:
+			slot_cmd = SETB_PCIX_133MHZ_EM;	
+			break;
+		case 8:
+			slot_cmd = SETB_PCIX_66MHZ_266;	
+			break;
+		case 0x9:
+			slot_cmd = SETB_PCIX_100MHZ_266;	
+			break;
+		case 0xa:
+			slot_cmd = SETB_PCIX_133MHZ_266;	
+			break;
+		case 0xb:
+			slot_cmd = SETB_PCIX_66MHZ_533;	
+			break;
+		case 0xc:
+			slot_cmd = SETB_PCIX_100MHZ_533;	
+			break;
+		case 0xd:
+			slot_cmd = SETB_PCIX_133MHZ_533;	
+			break;
+		default:
+			slot_cmd = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			return retval;	
+		}
+
+	}
+	retval = shpc_write_cmd(slot, 0, slot_cmd);
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
+{
+	struct controller *ctrl = NULL;
+	struct php_ctlr_state_s *php_ctlr;
+	u8 schedule_flag = 0;
+	u8 temp_byte;
+	u32 temp_dword, intr_loc, intr_loc2;
+	int hp_slot;
+
+	if (!dev_id)
+		return IRQ_NONE;
+
+	if (!shpchp_poll_mode) { 
+		ctrl = (struct controller *)dev_id;
+		php_ctlr = ctrl->hpc_ctlr_handle;
+	} else { 
+		php_ctlr = (struct php_ctlr_state_s *) dev_id;
+		ctrl = (struct controller *)php_ctlr->callback_instance_id;
+	}
+
+	if (!ctrl)
+		return IRQ_NONE;
+	
+	if (!php_ctlr || !php_ctlr->creg)
+		return IRQ_NONE;
+
+	/* Check to see if it was our interrupt */
+	intr_loc = readl(php_ctlr->creg + INTR_LOC);  
+
+	if (!intr_loc)
+		return IRQ_NONE;
+	dbg("%s: shpc_isr proceeds\n", __FUNCTION__);
+	dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); 
+
+	if(!shpchp_poll_mode) {
+		/* Mask Global Interrupt Mask - see implementation note on p. 139 */
+		/* of SHPC spec rev 1.0*/
+		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: Before masking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword |= 0x00000001;
+		dbg("%s: After masking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
+
+		intr_loc2 = readl(php_ctlr->creg + INTR_LOC);  
+		dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
+	}
+
+	if (intr_loc & 0x0001) {
+		/* 
+		 * Command Complete Interrupt Pending 
+		 * RO only - clear by writing 0 to the Command Completion
+		 * Detect bit in Controller SERR-INT register
+		 */
+		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: Before clearing CCIP, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword &= 0xfffeffff;
+		dbg("%s: After clearing CCIP, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
+		wake_up_interruptible(&ctrl->queue);
+	}
+
+	if ((intr_loc = (intr_loc >> 1)) == 0) {
+		/* Unmask Global Interrupt Mask */
+		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: 1-Before unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword &= 0xfffffffe;
+		dbg("%s: 1-After unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
+
+		return IRQ_NONE;
+	}
+
+	for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { 
+	/* To find out which slot has interrupt pending */
+		if ((intr_loc >> hp_slot) & 0x01) {
+			temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot));
+			dbg("%s: Slot %x with intr, temp_dword = %x\n",
+				__FUNCTION__, hp_slot, temp_dword); 
+			temp_byte = (temp_dword >> 16) & 0xFF;
+			dbg("%s: Slot with intr, temp_byte = %x\n",
+				__FUNCTION__, temp_byte); 
+			if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08))
+				schedule_flag += php_ctlr->switch_change_callback(
+					hp_slot, php_ctlr->callback_instance_id);
+			if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04))
+				schedule_flag += php_ctlr->attention_button_callback(
+					hp_slot, php_ctlr->callback_instance_id);
+			if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01))
+				schedule_flag += php_ctlr->presence_change_callback(
+					hp_slot , php_ctlr->callback_instance_id);
+			if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12))
+				schedule_flag += php_ctlr->power_fault_callback(
+					hp_slot, php_ctlr->callback_instance_id);
+			
+			/* Clear all slot events */
+			temp_dword = 0xe01f3fff;
+			dbg("%s: Clearing slot events, temp_dword = %x\n",
+				__FUNCTION__, temp_dword); 
+			writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot));
+
+			intr_loc2 = readl(php_ctlr->creg + INTR_LOC);  
+			dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
+		}
+	}
+	if (!shpchp_poll_mode) {
+		/* Unmask Global Interrupt Mask */
+		temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: 2-Before unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword &= 0xfffffffe;
+		dbg("%s: 2-After unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE);
+	}
+	
+	return IRQ_HANDLED;
+}
+
+static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
+	int retval = 0;
+	u8 pi;
+	u32 slot_avail1, slot_avail2;
+	int slot_num;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1);
+	slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2);
+
+	if (pi == 2) {
+		if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_533) >> 27)  ) != 0 )
+			bus_speed = PCIX_133MHZ_533;
+		else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_533) >> 23)  ) != 0 )
+			bus_speed = PCIX_100MHZ_533;
+		else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_533) >> 19)  ) != 0 )
+			bus_speed = PCIX_66MHZ_533;
+		else if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_266) >> 15)  ) != 0 )
+			bus_speed = PCIX_133MHZ_266;
+		else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_266) >> 11)  ) != 0 )
+			bus_speed = PCIX_100MHZ_266;
+		else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_266) >> 7)  ) != 0 )
+			bus_speed = PCIX_66MHZ_266;
+		else if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23)  ) != 0 )
+			bus_speed = PCIX_133MHZ;
+		else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15)  ) != 0 )
+			bus_speed = PCIX_100MHZ;
+		else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7)  ) != 0 )
+			bus_speed = PCIX_66MHZ;
+		else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 )
+			bus_speed = PCI_66MHZ;
+		else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 )
+			bus_speed = PCI_33MHZ;
+		else bus_speed = PCI_SPEED_UNKNOWN;
+	} else {
+		if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23)  ) != 0 )
+			bus_speed = PCIX_133MHZ;
+		else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15)  ) != 0 )
+			bus_speed = PCIX_100MHZ;
+		else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7)  ) != 0 )
+			bus_speed = PCIX_66MHZ;
+		else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 )
+			bus_speed = PCI_66MHZ;
+		else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 )
+			bus_speed = PCI_33MHZ;
+		else bus_speed = PCI_SPEED_UNKNOWN;
+	}
+
+	*value = bus_speed;
+	dbg("Max bus speed = %d\n", bus_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle;
+	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
+	u16 sec_bus_status;
+	int retval = 0;
+	u8 pi;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot->ctrl->hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot->hp_slot >= php_ctlr->num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr->creg + PROG_INTERFACE);
+	sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
+
+	if (pi == 2) {
+		switch (sec_bus_status & 0x000f) {
+		case 0:
+			bus_speed = PCI_SPEED_33MHz;
+			break;
+		case 1:
+			bus_speed = PCI_SPEED_66MHz;
+			break;
+		case 2:
+			bus_speed = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			bus_speed = PCI_SPEED_100MHz_PCIX;	
+			break;
+		case 4:
+			bus_speed = PCI_SPEED_133MHz_PCIX;	
+			break;
+		case 5:
+			bus_speed = PCI_SPEED_66MHz_PCIX_ECC;
+			break;
+		case 6:
+			bus_speed = PCI_SPEED_100MHz_PCIX_ECC;
+			break;
+		case 7:
+			bus_speed = PCI_SPEED_133MHz_PCIX_ECC;	
+			break;
+		case 8:
+			bus_speed = PCI_SPEED_66MHz_PCIX_266;	
+			break;
+		case 9:
+			bus_speed = PCI_SPEED_100MHz_PCIX_266;	
+			break;
+		case 0xa:
+			bus_speed = PCI_SPEED_133MHz_PCIX_266;	
+			break;
+		case 0xb:
+			bus_speed = PCI_SPEED_66MHz_PCIX_533;	
+			break;
+		case 0xc:
+			bus_speed = PCI_SPEED_100MHz_PCIX_533;	
+			break;
+		case 0xd:
+			bus_speed = PCI_SPEED_133MHz_PCIX_533;	
+			break;
+		case 0xe:
+		case 0xf:
+		default:
+			bus_speed = PCI_SPEED_UNKNOWN;
+			break;
+		}
+	} else {
+		/* In the case where pi is undefined, default it to 1 */ 
+		switch (sec_bus_status & 0x0007) {
+		case 0:
+			bus_speed = PCI_SPEED_33MHz;
+			break;
+		case 1:
+			bus_speed = PCI_SPEED_66MHz;
+			break;
+		case 2:
+			bus_speed = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			bus_speed = PCI_SPEED_100MHz_PCIX;	
+			break;
+		case 4:
+			bus_speed = PCI_SPEED_133MHz_PCIX;	
+			break;
+		case 5:
+			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
+			break;
+		case 6:
+			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
+			break;
+		case 7:
+			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */	
+			break;
+		default:
+			bus_speed = PCI_SPEED_UNKNOWN;
+			break;
+		}
+	}
+
+	*value = bus_speed;
+	dbg("Current bus speed = %d\n", bus_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static struct hpc_ops shpchp_hpc_ops = {
+	.power_on_slot			= hpc_power_on_slot,
+	.slot_enable			= hpc_slot_enable,
+	.slot_disable			= hpc_slot_disable,
+	.enable_all_slots		= hpc_enable_all_slots,
+	.pwr_on_all_slots		= hpc_pwr_on_all_slots,
+	.set_bus_speed_mode		= hpc_set_bus_speed_mode,	  
+	.set_attention_status	= hpc_set_attention_status,
+	.get_power_status		= hpc_get_power_status,
+	.get_attention_status	= hpc_get_attention_status,
+	.get_latch_status		= hpc_get_latch_status,
+	.get_adapter_status		= hpc_get_adapter_status,
+
+	.get_max_bus_speed		= hpc_get_max_bus_speed,
+	.get_cur_bus_speed		= hpc_get_cur_bus_speed,
+	.get_adapter_speed		= hpc_get_adapter_speed,
+	.get_mode1_ECC_cap		= hpc_get_mode1_ECC_cap,
+	.get_prog_int			= hpc_get_prog_int,
+
+	.query_power_fault		= hpc_query_power_fault,
+	.green_led_on			= hpc_set_green_led_on,
+	.green_led_off			= hpc_set_green_led_off,
+	.green_led_blink		= hpc_set_green_led_blink,
+	
+	.release_ctlr			= hpc_release_ctlr,
+	.check_cmd_status		= hpc_check_cmd_status,
+};
+
+int shpc_init(struct controller * ctrl,
+		struct pci_dev * pdev,
+		php_intr_callback_t attention_button_callback,
+		php_intr_callback_t switch_change_callback,
+		php_intr_callback_t presence_change_callback,
+		php_intr_callback_t power_fault_callback)
+{
+	struct php_ctlr_state_s *php_ctlr, *p;
+	void *instance_id = ctrl;
+	int rc;
+	u8 hp_slot;
+	static int first = 1;
+	u32 shpc_cap_offset, shpc_base_offset;
+	u32 tempdword, slot_reg;
+	u16 vendor_id, device_id;
+	u8 i;
+
+	DBG_ENTER_ROUTINE
+
+	spin_lock_init(&list_lock);
+	php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
+
+	if (!php_ctlr) {	/* allocate controller state data */
+		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
+		goto abort;
+	}
+
+	memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
+
+	php_ctlr->pci_dev = pdev;	/* save pci_dev in context */
+
+	rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id);
+	dbg("%s: Vendor ID: %x\n",__FUNCTION__, vendor_id);
+	if (rc) {
+		err("%s: unable to read PCI configuration data\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	rc = pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id);
+	dbg("%s: Device ID: %x\n",__FUNCTION__, device_id);
+	if (rc) {
+		err("%s: unable to read PCI configuration data\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	if ((vendor_id == PCI_VENDOR_ID_AMD) || (device_id == PCI_DEVICE_ID_AMD_GOLAM_7450)) {
+		shpc_base_offset = 0;  /* amd shpc driver doesn't use this; assume 0 */
+	} else {
+		if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) {
+			err("%s : shpc_cap_offset == 0\n", __FUNCTION__);
+			goto abort_free_ctlr;
+		}
+		dbg("%s: shpc_cap_offset = %x\n", __FUNCTION__, shpc_cap_offset);	
+	
+		rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET);
+		if (rc) {
+			err("%s : pci_word_config_byte failed\n", __FUNCTION__);
+			goto abort_free_ctlr;
+		}
+	
+		rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &shpc_base_offset);
+		if (rc) {
+			err("%s : pci_read_config_dword failed\n", __FUNCTION__);
+			goto abort_free_ctlr;
+		}
+
+		for (i = 0; i <= 14; i++) {
+			rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset +  DWORD_SELECT , i);
+			if (rc) {
+				err("%s : pci_word_config_byte failed\n", __FUNCTION__);
+				goto abort_free_ctlr;
+			}
+	
+			rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &tempdword);
+			if (rc) {
+				err("%s : pci_read_config_dword failed\n", __FUNCTION__);
+				goto abort_free_ctlr;
+			}
+			dbg("%s: offset %d: tempdword %x\n", __FUNCTION__,i, tempdword);
+		}
+	}
+
+	if (first) {
+		spin_lock_init(&hpc_event_lock);
+		first = 0;
+	}
+
+	dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, PCI_SLOT(pdev->devfn), 
+		PCI_FUNC(pdev->devfn), pdev->irq);
+	for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+		if (pci_resource_len(pdev, rc) > 0)
+			dbg("pci resource[%d] start=0x%lx(len=0x%lx), shpc_base_offset %x\n", rc,
+				pci_resource_start(pdev, rc), pci_resource_len(pdev, rc), shpc_base_offset);
+
+	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, 
+		pdev->subsystem_device);
+	
+	if (pci_enable_device(pdev))
+		goto abort_free_ctlr;
+
+	if (!request_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0), MY_NAME)) {
+		err("%s: cannot reserve MMIO region\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	php_ctlr->creg = ioremap(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
+	if (!php_ctlr->creg) {
+		err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0), 
+			pci_resource_start(pdev, 0) + shpc_base_offset);
+		release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
+		goto abort_free_ctlr;
+	}
+	dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
+	dbg("%s: physical addr %p\n", __FUNCTION__, (void*)pci_resource_start(pdev, 0));
+
+	init_MUTEX(&ctrl->crit_sect);
+	/* Setup wait queue */
+	init_waitqueue_head(&ctrl->queue);
+
+	/* Find the IRQ */
+	php_ctlr->irq = pdev->irq;
+	dbg("HPC interrupt = %d\n", php_ctlr->irq);
+
+	/* Save interrupt callback info */
+	php_ctlr->attention_button_callback = attention_button_callback;
+	php_ctlr->switch_change_callback = switch_change_callback;
+	php_ctlr->presence_change_callback = presence_change_callback;
+	php_ctlr->power_fault_callback = power_fault_callback;
+	php_ctlr->callback_instance_id = instance_id;
+
+	/* Return PCI Controller Info */
+	php_ctlr->slot_device_offset = (readl(php_ctlr->creg + SLOT_CONFIG) & FIRST_DEV_NUM ) >> 8;
+	php_ctlr->num_slots = readl(php_ctlr->creg + SLOT_CONFIG) & SLOT_NUM;
+	dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset);
+	dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots);
+
+	/* Mask Global Interrupt Mask & Command Complete Interrupt Mask */
+	tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
+	tempdword = 0x0003000f;   
+	writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE);
+	tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
+
+	/* Mask the MRL sensor SERR Mask of individual slot in
+	 * Slot SERR-INT Mask & clear all the existing event if any
+	 */
+	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
+		slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot );
+		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
+			hp_slot, slot_reg);
+		tempdword = 0xffff3fff;  
+		writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot));
+	}
+	
+	if (shpchp_poll_mode)  {/* Install interrupt polling code */
+		/* Install and start the interrupt polling timer */
+		init_timer(&php_ctlr->int_poll_timer);
+		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
+	} else {
+		/* Installs the interrupt handler */
+		rc = pci_enable_msi(pdev);
+		if (rc) {
+			info("Can't get msi for the hotplug controller\n");
+			info("Use INTx for the hotplug controller\n");
+			dbg("%s: rc = %x\n", __FUNCTION__, rc);
+		} else
+			php_ctlr->irq = pdev->irq;
+		
+		rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+		if (rc) {
+			err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+			goto abort_free_ctlr;
+		}
+		/* Execute OSHP method here */
+	}
+	dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__);
+
+	/*  Add this HPC instance into the HPC list */
+	spin_lock(&list_lock);
+	if (php_ctlr_list_head == 0) {
+		php_ctlr_list_head = php_ctlr;
+		p = php_ctlr_list_head;
+		p->pnext = NULL;
+	} else {
+		p = php_ctlr_list_head;
+
+		while (p->pnext)
+			p = p->pnext;
+
+		p->pnext = php_ctlr;
+	}
+	spin_unlock(&list_lock);
+
+
+	ctlr_seq_num++;
+	ctrl->hpc_ctlr_handle = php_ctlr;
+	ctrl->hpc_ops = &shpchp_hpc_ops;
+
+	for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
+		slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot );
+		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
+			hp_slot, slot_reg);
+		tempdword = 0xe01f3fff;  
+		writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot));
+	}
+	if (!shpchp_poll_mode) {
+		/* Unmask all general input interrupts and SERR */
+		tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		tempdword = 0x0000000a;
+		writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE);
+		tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE);
+		dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
+	}
+
+	dbg("%s: Leaving shpc_init\n", __FUNCTION__);
+	DBG_LEAVE_ROUTINE
+	return 0;
+
+	/* We end up here for the many possible ways to fail this API.  */
+abort_free_ctlr:
+	kfree(php_ctlr);
+abort:
+	DBG_LEAVE_ROUTINE
+	return -1;
+}
diff --git a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
new file mode 100644
index 0000000..90113e9
--- /dev/null
+++ b/drivers/pci/hotplug/shpchp_pci.c
@@ -0,0 +1,810 @@
+/*
+ * Standard Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include "../pci.h"
+#include "shpchp.h"
+#ifndef CONFIG_IA64
+#include "../../../arch/i386/pci/pci.h"    /* horrible hack showing how processor dependant we are... */
+#endif
+
+int shpchp_configure_device (struct controller* ctrl, struct pci_func* func)  
+{
+	unsigned char bus;
+	struct pci_bus *child;
+	int num;
+
+	if (func->pci_dev == NULL)
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
+
+	/* Still NULL ? Well then scan for it ! */
+	if (func->pci_dev == NULL) {
+		num = pci_scan_slot(ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function));
+		if (num) {
+			dbg("%s: subordiante %p number %x\n", __FUNCTION__, ctrl->pci_dev->subordinate,
+				ctrl->pci_dev->subordinate->number);
+			pci_bus_add_devices(ctrl->pci_dev->subordinate);
+		}
+		
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
+		if (func->pci_dev == NULL) {
+			dbg("ERROR: pci_dev still null\n");
+			return 0;
+		}
+	}
+
+	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
+		child = pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
+		pci_do_scan_bus(child);
+
+	}
+
+	return 0;
+}
+
+
+int shpchp_unconfigure_device(struct pci_func* func) 
+{
+	int rc = 0;
+	int j;
+	
+	dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus,
+				func->device, func->function);
+
+	for (j=0; j<8 ; j++) {
+		struct pci_dev* temp = pci_find_slot(func->bus,
+				(func->device << 3) | j);
+		if (temp) {
+			pci_remove_bus_device(temp);
+		}
+	}
+	return rc;
+}
+
+/*
+ * shpchp_set_irq
+ *
+ * @bus_num: bus number of PCI device
+ * @dev_num: device number of PCI device
+ * @slot: pointer to u8 where slot number will be returned
+ */
+int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
+{
+#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
+	int rc;
+	u16 temp_word;
+	struct pci_dev fakedev;
+	struct pci_bus fakebus;
+
+	fakedev.devfn = dev_num << 3;
+	fakedev.bus = &fakebus;
+	fakebus.number = bus_num;
+	dbg("%s: dev %d, bus %d, pin %d, num %d\n",
+	    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
+	rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);
+	dbg("%s: rc %d\n", __FUNCTION__, rc);
+	if (!rc)
+		return !rc;
+
+	/* set the Edge Level Control Register (ELCR) */
+	temp_word = inb(0x4d0);
+	temp_word |= inb(0x4d1) << 8;
+
+	temp_word |= 0x01 << irq_num;
+
+	/* This should only be for x86 as it sets the Edge Level Control Register */
+	outb((u8) (temp_word & 0xFF), 0x4d0);
+	outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
+#endif
+	return 0;
+}
+
+/* More PCI configuration routines; this time centered around hotplug controller */
+
+
+/*
+ * shpchp_save_config
+ *
+ * Reads configuration for all slots in a PCI bus and saves info.
+ *
+ * Note:  For non-hot plug busses, the slot # saved is the device #
+ *
+ * returns 0 if success
+ */
+int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	struct pci_func *new_slot;
+	int sub_bus;
+	int FirstSupported;
+	int LastSupported;
+	int max_functions;
+	int function;
+	u8 DevError;
+	int device = 0;
+	int cloop = 0;
+	int stop_it;
+	int index;
+	int is_hot_plug = num_ctlr_slots || first_device_num;
+	struct pci_bus lpci_bus, *pci_bus;
+
+	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__,
+				num_ctlr_slots, first_device_num);
+
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+
+	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__,
+				num_ctlr_slots, first_device_num);
+
+	/*   Decide which slots are supported */
+	if (is_hot_plug) {
+		/*********************************
+		 *  is_hot_plug is the slot mask
+		 *********************************/
+		FirstSupported = first_device_num;
+		LastSupported = FirstSupported + num_ctlr_slots - 1;
+	} else {
+		FirstSupported = 0;
+		LastSupported = 0x1F;
+	}
+
+	dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported,
+					LastSupported);
+
+	/*   Save PCI configuration space for all devices in supported slots */
+	pci_bus->number = busnumber;
+	for (device = FirstSupported; device <= LastSupported; device++) {
+		ID = 0xFFFFFFFF;
+		rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0),
+					PCI_VENDOR_ID, &ID);
+
+		if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0),
+					0x0B, &class_code);
+			if (rc)
+				return rc;
+
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0),
+					PCI_HEADER_TYPE, &header_type);
+			if (rc)
+				return rc;
+
+			dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+
+			/* If multi-function device, set max_functions to 8 */
+			if (header_type & 0x80)
+				max_functions = 8;
+			else
+				max_functions = 1;
+
+			function = 0;
+
+			do {
+				DevError = 0;
+
+				if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   /* P-P Bridge */
+					/* Recurse the subordinate bus
+					 * get the subordinate bus number
+					 */
+					rc = pci_bus_read_config_byte(pci_bus,
+						PCI_DEVFN(device, function), 
+						PCI_SECONDARY_BUS, &secondary_bus);
+					if (rc) {
+						return rc;
+					} else {
+						sub_bus = (int) secondary_bus;
+
+						/* Save secondary bus cfg spc with this recursive call. */
+						rc = shpchp_save_config(ctrl, sub_bus, 0, 0);
+						if (rc)
+							return rc;
+					}
+				}
+
+				index = 0;
+				new_slot = shpchp_slot_find(busnumber, device, index++);
+
+				dbg("new_slot = %p\n", new_slot);
+
+				while (new_slot && (new_slot->function != (u8) function)) {
+					new_slot = shpchp_slot_find(busnumber, device, index++);
+					dbg("new_slot = %p\n", new_slot);
+				}
+				if (!new_slot) {
+					/* Setup slot structure. */
+					new_slot = shpchp_slot_create(busnumber);
+					dbg("new_slot = %p\n", new_slot);
+
+					if (new_slot == NULL)
+						return(1);
+				}
+
+				new_slot->bus = (u8) busnumber;
+				new_slot->device = (u8) device;
+				new_slot->function = (u8) function;
+				new_slot->is_a_board = 1;
+				new_slot->switch_save = 0x10;
+				new_slot->pwr_save = 1;
+				/* In case of unsupported board */
+				new_slot->status = DevError;
+				new_slot->pci_dev = pci_find_slot(new_slot->bus,
+					(new_slot->device << 3) | new_slot->function);
+				dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev);
+
+				for (cloop = 0; cloop < 0x20; cloop++) {
+					rc = pci_bus_read_config_dword(pci_bus,
+						PCI_DEVFN(device, function), 
+						cloop << 2,
+						(u32 *) &(new_slot->config_space [cloop]));
+					/* dbg("new_slot->config_space[%x] = %x\n",
+						cloop, new_slot->config_space[cloop]); */
+					if (rc)
+						return rc;
+				}
+
+				function++;
+
+				stop_it = 0;
+
+				/*  this loop skips to the next present function
+				 *  reading in Class Code and Header type.
+				 */
+
+				while ((function < max_functions)&&(!stop_it)) {
+					rc = pci_bus_read_config_dword(pci_bus,
+						PCI_DEVFN(device, function),
+						PCI_VENDOR_ID, &ID);
+
+					if (ID == 0xFFFFFFFF) {  /* nothing there. */
+						function++;
+						dbg("Nothing there\n");
+					} else {  /* Something there */
+						rc = pci_bus_read_config_byte(pci_bus,
+							PCI_DEVFN(device, function), 
+							0x0B, &class_code);
+						if (rc)
+							return rc;
+
+						rc = pci_bus_read_config_byte(pci_bus,
+							PCI_DEVFN(device, function), 
+							PCI_HEADER_TYPE, &header_type);
+						if (rc)
+							return rc;
+
+						dbg("class_code = %x, header_type = %x\n",
+							class_code, header_type);
+						stop_it++;
+					}
+				}
+
+			} while (function < max_functions);
+			/* End of IF (device in slot?) */
+		} else if (is_hot_plug) {
+			/* Setup slot structure with entry for empty slot */
+			new_slot = shpchp_slot_create(busnumber);
+
+			if (new_slot == NULL) {
+				return(1);
+			}
+			dbg("new_slot = %p\n", new_slot);
+
+			new_slot->bus = (u8) busnumber;
+			new_slot->device = (u8) device;
+			new_slot->function = 0;
+			new_slot->is_a_board = 0;
+			new_slot->presence_save = 0;
+			new_slot->switch_save = 0;
+		}
+	}			/* End of FOR loop */
+
+	return(0);
+}
+
+
+/*
+ * shpchp_save_slot_config
+ *
+ * Saves configuration info for all PCI devices in a given slot
+ * including subordinate busses.
+ *
+ * returns 0 if success
+ */
+int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	int sub_bus;
+	int max_functions;
+	int function;
+	int cloop = 0;
+	int stop_it;
+	struct pci_bus lpci_bus, *pci_bus;
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = new_slot->bus;
+
+	ID = 0xFFFFFFFF;
+
+	pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0),
+					PCI_VENDOR_ID, &ID);
+
+	if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0),
+					0x0B, &class_code);
+
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0),
+					PCI_HEADER_TYPE, &header_type);
+
+		if (header_type & 0x80)	/* Multi-function device */
+			max_functions = 8;
+		else
+			max_functions = 1;
+
+		function = 0;
+
+		do {
+			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  /* PCI-PCI Bridge */
+				/*  Recurse the subordinate bus */
+				pci_bus_read_config_byte(pci_bus,
+					PCI_DEVFN(new_slot->device, function), 
+					PCI_SECONDARY_BUS, &secondary_bus);
+
+				sub_bus = (int) secondary_bus;
+
+				/* Save the config headers for the secondary bus. */
+				rc = shpchp_save_config(ctrl, sub_bus, 0, 0);
+
+				if (rc)
+					return rc;
+
+			}	/* End of IF */
+
+			new_slot->status = 0;
+
+			for (cloop = 0; cloop < 0x20; cloop++) {
+				pci_bus_read_config_dword(pci_bus,
+					PCI_DEVFN(new_slot->device, function), 
+					cloop << 2,
+					(u32 *) &(new_slot->config_space [cloop]));
+			}
+
+			function++;
+
+			stop_it = 0;
+
+			/*  this loop skips to the next present function
+			 *  reading in the Class Code and the Header type.
+			 */
+
+			while ((function < max_functions) && (!stop_it)) {
+				pci_bus_read_config_dword(pci_bus,
+					PCI_DEVFN(new_slot->device, function),
+					PCI_VENDOR_ID, &ID);
+
+				if (ID == 0xFFFFFFFF) {	 /* nothing there. */
+					function++;
+				} else {  /* Something there */
+					pci_bus_read_config_byte(pci_bus,
+						PCI_DEVFN(new_slot->device, function),
+						0x0B, &class_code);
+
+					pci_bus_read_config_byte(pci_bus,
+						PCI_DEVFN(new_slot->device, function),
+						PCI_HEADER_TYPE, &header_type);
+
+					stop_it++;
+				}
+			}
+
+		} while (function < max_functions);
+	}			/* End of IF (device in slot?) */
+	else {
+		return 2;
+	}
+
+	return 0;
+}
+
+
+/*
+ * shpchp_save_used_resources
+ *
+ * Stores used resource information for existing boards.  this is
+ * for boards that were in the system when this driver was loaded.
+ * this function is for hot plug ADD
+ *
+ * returns 0 if success
+ * if disable  == 1(DISABLE_CARD),
+ *  it loops for all functions of the slot and disables them.
+ * else, it just get resources of the function and return.
+ */
+int shpchp_save_used_resources(struct controller *ctrl, struct pci_func *func, int disable)
+{
+	u8 cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	u8 temp_byte;
+	u16 command;
+	u16 save_command;
+	u16 w_base, w_length;
+	u32 temp_register;
+	u32 save_base;
+	u32 base, length;
+	u64 base64 = 0;
+	int index = 0;
+	unsigned int devfn;
+	struct pci_resource *mem_node = NULL;
+	struct pci_resource *p_mem_node = NULL;
+	struct pci_resource *t_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_bus lpci_bus, *pci_bus;
+	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+
+	if (disable)
+		func = shpchp_slot_find(func->bus, func->device, index++);
+
+	while ((func != NULL) && func->is_a_board) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		/* Save the command register */
+		pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command);
+
+		if (disable) {
+			/* disable card */
+			command = 0x00;
+			pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+		}
+
+		/* Check for Bridge */
+		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
+
+		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {     /* PCI-PCI Bridge */
+			dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n",
+					func->bus, func->device, save_command);
+			if (disable) {
+				/* Clear Bridge Control Register */
+				command = 0x00;
+				pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+			}
+
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
+
+			bus_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node->base = (ulong)secondary_bus;
+			bus_node->length = (ulong)(temp_byte - secondary_bus + 1);
+
+			bus_node->next = func->bus_head;
+			func->bus_head = bus_node;
+
+			/* Save IO base and Limit registers */
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &temp_byte);
+			base = temp_byte;
+			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &temp_byte);
+			length = temp_byte;
+
+			if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) {
+				io_node = kmalloc(sizeof(struct pci_resource),
+							GFP_KERNEL);
+				if (!io_node)
+					return -ENOMEM;
+
+				io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8;
+				io_node->length = (ulong)(length - base + 0x10) << 8;
+
+				io_node->next = func->io_head;
+				func->io_head = io_node;
+			}
+
+			/* Save memory base and Limit registers */
+			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+				mem_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+				if (!mem_node)
+					return -ENOMEM;
+
+				mem_node->base = (ulong)w_base << 16;
+				mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
+
+				mem_node->next = func->mem_head;
+				func->mem_head = mem_node;
+			}
+			/* Save prefetchable memory base and Limit registers */
+			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
+
+			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
+				p_mem_node = kmalloc(sizeof(struct pci_resource),
+						GFP_KERNEL);
+				if (!p_mem_node)
+					return -ENOMEM;
+
+				p_mem_node->base = (ulong)w_base << 16;
+				p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;
+
+				p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = p_mem_node;
+			}
+		} else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+			dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n",
+					func->bus, func->device, save_command);
+
+			/* Figure out IO and memory base lengths */
+			for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
+				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
+
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register);
+
+				if (!disable)
+					pci_bus_write_config_dword(pci_bus, devfn, cloop, save_base);
+
+				if (!temp_register)
+					continue;
+
+				base = temp_register;
+
+				if ((base & PCI_BASE_ADDRESS_SPACE_IO) &&
+						(!disable || (save_command & PCI_COMMAND_IO))) {
+					/* IO base */
+					/* set temp_register = amount of IO space requested */
+					base = base & 0xFFFFFFFCL;
+					base = (~base) + 1;
+
+					io_node =  kmalloc(sizeof (struct pci_resource),
+								GFP_KERNEL);
+					if (!io_node)
+						return -ENOMEM;
+
+					io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK;
+					io_node->length = (ulong)base;
+					dbg("sur adapter: IO bar=0x%x(length=0x%x)\n",
+						io_node->base, io_node->length);
+
+					io_node->next = func->io_head;
+					func->io_head = io_node;
+				} else {  /* map Memory */
+					int prefetchable = 1;
+					/* struct pci_resources **res_node; */
+					char *res_type_str = "PMEM";
+					u32 temp_register2;
+
+					t_mem_node = kmalloc(sizeof (struct pci_resource),
+								GFP_KERNEL);
+					if (!t_mem_node)
+						return -ENOMEM;
+
+					if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) &&
+							(!disable || (save_command & PCI_COMMAND_MEMORY))) {
+						prefetchable = 0;
+						mem_node = t_mem_node;
+						res_type_str++;
+					} else
+						p_mem_node = t_mem_node;
+
+					base = base & 0xFFFFFFF0L;
+					base = (~base) + 1;
+
+					switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+					case PCI_BASE_ADDRESS_MEM_TYPE_32:
+						if (prefetchable) {
+							p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node->length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
+								res_type_str, 
+								p_mem_node->base,
+								p_mem_node->length);
+
+							p_mem_node->next = func->p_mem_head;
+							func->p_mem_head = p_mem_node;
+						} else {
+							mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node->length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
+								res_type_str, 
+								mem_node->base,
+								mem_node->length);
+
+							mem_node->next = func->mem_head;
+							func->mem_head = mem_node;
+						}
+						break;
+					case PCI_BASE_ADDRESS_MEM_TYPE_64:
+						pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
+						base64 = temp_register2;
+						base64 = (base64 << 32) | save_base;
+
+						if (temp_register2) {
+							dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", 
+								res_type_str, temp_register2, (u32)base64);
+							base64 &= 0x00000000FFFFFFFFL;
+						}
+
+						if (prefetchable) {
+							p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node->length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
+								res_type_str, 
+								p_mem_node->base,
+								p_mem_node->length);
+
+							p_mem_node->next = func->p_mem_head;
+							func->p_mem_head = p_mem_node;
+						} else {
+							mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node->length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
+								res_type_str, 
+								mem_node->base,
+								mem_node->length);
+
+							mem_node->next = func->mem_head;
+							func->mem_head = mem_node;
+						}
+						cloop += 4;
+						break;
+					default:
+						dbg("asur: reserved BAR type=0x%x\n",
+							temp_register);
+						break;
+					}
+				} 
+			}	/* End of base register loop */
+		} else {	/* Some other unknown header type */
+			dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n",
+					func->bus, func->device);
+		}
+
+		/* find the next device in this slot */
+		if (!disable)
+			break;
+		func = shpchp_slot_find(func->bus, func->device, index++);
+	}
+
+	return 0;
+}
+
+/**
+ * kfree_resource_list: release memory of all list members
+ * @res: resource list to free
+ */
+static inline void
+return_resource_list(struct pci_resource **func, struct pci_resource **res)
+{
+	struct pci_resource *node;
+	struct pci_resource *t_node;
+
+	node = *func;
+	*func = NULL;
+	while (node) {
+		t_node = node->next;
+		return_resource(res, node);
+		node = t_node;
+	}
+}
+
+/*
+ * shpchp_return_board_resources
+ *
+ * this routine returns all resources allocated to a board to
+ * the available pool.
+ *
+ * returns 0 if success
+ */
+int shpchp_return_board_resources(struct pci_func * func,
+					struct resource_lists * resources)
+{
+	int rc;
+	dbg("%s\n", __FUNCTION__);
+
+	if (!func)
+		return 1;
+
+	return_resource_list(&(func->io_head),&(resources->io_head));
+	return_resource_list(&(func->mem_head),&(resources->mem_head));
+	return_resource_list(&(func->p_mem_head),&(resources->p_mem_head));
+	return_resource_list(&(func->bus_head),&(resources->bus_head));
+
+	rc = shpchp_resource_sort_and_combine(&(resources->mem_head));
+	rc |= shpchp_resource_sort_and_combine(&(resources->p_mem_head));
+	rc |= shpchp_resource_sort_and_combine(&(resources->io_head));
+	rc |= shpchp_resource_sort_and_combine(&(resources->bus_head));
+
+	return rc;
+}
+
+/**
+ * kfree_resource_list: release memory of all list members
+ * @res: resource list to free
+ */
+static inline void
+kfree_resource_list(struct pci_resource **r)
+{
+	struct pci_resource *res, *tres;
+
+	res = *r;
+	*r = NULL;
+
+	while (res) {
+		tres = res;
+		res = res->next;
+		kfree(tres);
+	}
+}
+
+/**
+ * shpchp_destroy_resource_list: put node back in the resource list
+ * @resources: list to put nodes back
+ */
+void shpchp_destroy_resource_list(struct resource_lists *resources)
+{
+	kfree_resource_list(&(resources->io_head));
+	kfree_resource_list(&(resources->mem_head));
+	kfree_resource_list(&(resources->p_mem_head));
+	kfree_resource_list(&(resources->bus_head));
+}
+
+/**
+ * shpchp_destroy_board_resources: put node back in the resource list
+ * @resources: list to put nodes back
+ */
+void shpchp_destroy_board_resources(struct pci_func * func)
+{
+	kfree_resource_list(&(func->io_head));
+	kfree_resource_list(&(func->mem_head));
+	kfree_resource_list(&(func->p_mem_head));
+	kfree_resource_list(&(func->bus_head));
+}
diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c
new file mode 100644
index 0000000..9a1ee13
--- /dev/null
+++ b/drivers/pci/hotplug/shpchp_sysfs.c
@@ -0,0 +1,143 @@
+/*
+ * Compaq Hot Plug Controller Driver
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include "shpchp.h"
+
+
+/* A few routines that create sysfs entries for the hot plug controller */
+
+static ssize_t show_ctrl (struct device *dev, char *buf)
+{
+	struct pci_dev *pci_dev;
+	struct controller *ctrl;
+	char * out = buf;
+	int index;
+	struct pci_resource *res;
+
+	pci_dev = container_of (dev, struct pci_dev, dev);
+	ctrl = pci_get_drvdata(pci_dev);
+
+	out += sprintf(buf, "Free resources: memory\n");
+	index = 11;
+	res = ctrl->mem_head;
+	while (res && index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+		res = res->next;
+	}
+	out += sprintf(out, "Free resources: prefetchable memory\n");
+	index = 11;
+	res = ctrl->p_mem_head;
+	while (res && index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+		res = res->next;
+	}
+	out += sprintf(out, "Free resources: IO\n");
+	index = 11;
+	res = ctrl->io_head;
+	while (res && index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+		res = res->next;
+	}
+	out += sprintf(out, "Free resources: bus numbers\n");
+	index = 11;
+	res = ctrl->bus_head;
+	while (res && index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+		res = res->next;
+	}
+
+	return out - buf;
+}
+static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
+
+static ssize_t show_dev (struct device *dev, char *buf)
+{
+	struct pci_dev *pci_dev;
+	struct controller *ctrl;
+	char * out = buf;
+	int index;
+	struct pci_resource *res;
+	struct pci_func *new_slot;
+	struct slot *slot;
+
+	pci_dev = container_of (dev, struct pci_dev, dev);
+	ctrl = pci_get_drvdata(pci_dev);
+
+	slot=ctrl->slot;
+
+	while (slot) {
+		new_slot = shpchp_slot_find(slot->bus, slot->device, 0);
+		if (!new_slot)
+			break;
+		out += sprintf(out, "assigned resources: memory\n");
+		index = 11;
+		res = new_slot->mem_head;
+		while (res && index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+			res = res->next;
+		}
+		out += sprintf(out, "assigned resources: prefetchable memory\n");
+		index = 11;
+		res = new_slot->p_mem_head;
+		while (res && index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+			res = res->next;
+		}
+		out += sprintf(out, "assigned resources: IO\n");
+		index = 11;
+		res = new_slot->io_head;
+		while (res && index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+			res = res->next;
+		}
+		out += sprintf(out, "assigned resources: bus numbers\n");
+		index = 11;
+		res = new_slot->bus_head;
+		while (res && index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
+			res = res->next;
+		}
+		slot=slot->next;
+	}
+
+	return out - buf;
+}
+static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL);
+
+void shpchp_create_ctrl_files (struct controller *ctrl)
+{
+	device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
+	device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev);
+}
diff --git a/drivers/pci/hotplug/shpchprm.h b/drivers/pci/hotplug/shpchprm.h
new file mode 100644
index 0000000..88aeb97
--- /dev/null
+++ b/drivers/pci/hotplug/shpchprm.h
@@ -0,0 +1,55 @@
+/*
+ * SHPCHPRM : SHPCHP Resource Manager for ACPI/non-ACPI platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _SHPCHPRM_H_
+#define _SHPCHPRM_H_
+
+#ifdef	CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY
+#include "shpchprm_legacy.h"
+#else
+#include "shpchprm_nonacpi.h"
+#endif
+
+int shpchprm_init(enum php_ctlr_type ct);
+void shpchprm_cleanup(void);
+int shpchprm_print_pirt(void);
+int shpchprm_find_available_resources(struct controller *ctrl);
+int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type);
+void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type);
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum);
+
+#ifdef	DEBUG
+#define RES_CHECK(this, bits)	\
+	{ if (((this) & (bits - 1))) \
+		printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); }
+#else
+#define RES_CHECK(this, bits)
+#endif
+
+#endif				/* _SHPCHPRM_H_ */
diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c
new file mode 100644
index 0000000..243a51d
--- /dev/null
+++ b/drivers/pci/hotplug/shpchprm_acpi.c
@@ -0,0 +1,1713 @@
+/*
+ * SHPCHPRM ACPI: PHP Resource Manager for ACPI platform
+ *
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/efi.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#ifdef	CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/actypes.h>
+#include "shpchp.h"
+#include "shpchprm.h"
+
+#define	PCI_MAX_BUS		0x100
+#define	ACPI_STA_DEVICE_PRESENT	0x01
+
+#define	METHOD_NAME__SUN	"_SUN"
+#define	METHOD_NAME__HPP	"_HPP"
+#define	METHOD_NAME_OSHP	"OSHP"
+
+#define	PHP_RES_BUS		0xA0
+#define	PHP_RES_IO		0xA1
+#define	PHP_RES_MEM		0xA2
+#define	PHP_RES_PMEM		0xA3
+
+#define	BRIDGE_TYPE_P2P		0x00
+#define	BRIDGE_TYPE_HOST	0x01
+
+/* this should go to drivers/acpi/include/ */
+struct acpi__hpp {
+	u8	cache_line_size;
+	u8	latency_timer;
+	u8	enable_serr;
+	u8	enable_perr;
+};
+
+struct acpi_php_slot {
+	struct acpi_php_slot	*next;
+	struct acpi_bridge	*bridge;
+	acpi_handle		handle;
+	int	seg;
+	int	bus;
+	int	dev;
+	int	fun;
+	u32	sun;
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	void	*slot_ops;	/* _STA, _EJx, etc */
+	struct slot *slot;
+};		/* per func */
+
+struct acpi_bridge {
+	struct acpi_bridge	*parent;
+	struct acpi_bridge	*next;
+	struct acpi_bridge	*child;
+	acpi_handle	handle;
+	int seg;
+	int pbus;				/* pdev->bus->number		*/
+	int pdevice;				/* PCI_SLOT(pdev->devfn)	*/
+	int pfunction;				/* PCI_DEVFN(pdev->devfn)	*/
+	int bus;				/* pdev->subordinate->number	*/
+	struct acpi__hpp		*_hpp;
+	struct acpi_php_slot	*slots;
+	struct pci_resource 	*tmem_head;	/* total from crs	*/
+	struct pci_resource 	*tp_mem_head;	/* total from crs	*/
+	struct pci_resource 	*tio_head;	/* total from crs	*/
+	struct pci_resource 	*tbus_head;	/* total from crs	*/
+	struct pci_resource 	*mem_head;	/* available	*/
+	struct pci_resource 	*p_mem_head;	/* available	*/
+	struct pci_resource 	*io_head;	/* available	*/
+	struct pci_resource 	*bus_head;	/* available	*/
+	int scanned;
+	int type;
+};
+
+static struct acpi_bridge *acpi_bridges_head;
+
+static u8 * acpi_path_name( acpi_handle	handle)
+{
+	acpi_status		status;
+	static u8	path_name[ACPI_PATHNAME_MAX];
+	struct acpi_buffer		ret_buf = { ACPI_PATHNAME_MAX, path_name };
+
+	memset(path_name, 0, sizeof (path_name));
+	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);
+
+	if (ACPI_FAILURE(status))
+		return NULL;
+	else
+		return path_name;	
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab);
+static void acpi_run_oshp ( struct acpi_bridge	*ab);
+
+static int acpi_add_slot_to_php_slots(
+	struct acpi_bridge	*ab,
+	int				bus_num,
+	acpi_handle		handle,
+	u32				adr,
+	u32				sun
+	)
+{
+	struct acpi_php_slot	*aps;
+	static long	samesun = -1;
+
+	aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);
+	if (!aps) {
+		err ("acpi_shpchprm: alloc for aps fail\n");
+		return -1;
+	}
+	memset(aps, 0, sizeof(struct acpi_php_slot));
+
+	aps->handle = handle;
+	aps->bus = bus_num;
+	aps->dev = (adr >> 16) & 0xffff;
+	aps->fun = adr & 0xffff;
+	aps->sun = sun;
+
+	aps->next = ab->slots;	/* cling to the bridge */
+	aps->bridge = ab;
+	ab->slots = aps;
+
+	ab->scanned += 1;
+	if (!ab->_hpp)
+		acpi_get__hpp(ab);
+
+	acpi_run_oshp(ab);
+
+	if (sun != samesun) {
+		info("acpi_shpchprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", aps->sun, ab->seg, 
+			aps->bus, aps->dev, aps->fun);
+		samesun = sun;
+	}
+	return 0;
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			nui[4];
+	struct acpi_buffer	ret_buf = { 0, NULL};
+	union acpi_object	*ext_obj, *package;
+	u8			*path_name = acpi_path_name(ab->handle);
+	int			i, len = 0;
+
+	/* get _hpp */
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
+		if (!ret_buf.pointer) {
+			err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name);
+			return;
+		}
+		status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf);
+		if (ACPI_SUCCESS(status))
+			break;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status);
+			return;
+		}
+	}
+
+	ext_obj = (union acpi_object *) ret_buf.pointer;
+	if (ext_obj->type != ACPI_TYPE_PACKAGE) {
+		err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name);
+		goto free_and_return;
+	}
+
+	len = ext_obj->package.count;
+	package = (union acpi_object *) ret_buf.pointer;
+	for ( i = 0; (i < len) || (i < 4); i++) {
+		ext_obj = (union acpi_object *) &package->package.elements[i];
+		switch (ext_obj->type) {
+		case ACPI_TYPE_INTEGER:
+			nui[i] = (u8)ext_obj->integer.value;
+			break;
+		default:
+			err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name);
+			goto free_and_return;
+		}
+	}
+
+	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	if (!ab->_hpp) {
+		err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name);
+		goto free_and_return;
+	}
+	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
+
+	ab->_hpp->cache_line_size	= nui[0];
+	ab->_hpp->latency_timer		= nui[1];
+	ab->_hpp->enable_serr		= nui[2];
+	ab->_hpp->enable_perr		= nui[3];
+
+	dbg("  _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
+	dbg("  _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
+	dbg("  _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
+	dbg("  _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+
+free_and_return:
+	kfree(ret_buf.pointer);
+}
+
+static void acpi_run_oshp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(ab->handle);
+
+	/* run OSHP */
+	status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, NULL);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
+	} else
+		dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);
+	return;
+}
+
+static acpi_status acpi_evaluate_crs(
+	acpi_handle		handle,
+	struct acpi_resource	**retbuf
+	)
+{
+	acpi_status		status;
+	struct acpi_buffer		crsbuf;
+	u8			*path_name = acpi_path_name(handle);
+
+	crsbuf.length  = 0;
+	crsbuf.pointer = NULL;
+
+	status = acpi_get_current_resources (handle, &crsbuf);
+
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		break;		/* found */
+	case AE_NOT_FOUND:
+		dbg("acpi_shpchprm:%s _CRS not found\n", path_name);
+		return status;
+	default:
+		err ("acpi_shpchprm:%s _CRS fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL);
+	if (!crsbuf.pointer) {
+		err ("acpi_shpchprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name);
+		return AE_NO_MEMORY;
+	}
+
+	status = acpi_get_current_resources (handle, &crsbuf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm: %s _CRS fail=0x%x.\n", path_name, status);
+		kfree(crsbuf.pointer);
+		return status;
+	}
+
+	*retbuf = crsbuf.pointer;
+
+	return status;
+}
+
+static void free_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res, *next;
+
+	for (res = aprh; res; res = next) {
+		next = res->next;
+		kfree(res);
+	}
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res->next)
+		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
+}
+
+static void print_slot_resources( struct acpi_php_slot	*aps)
+{
+	if (aps->bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (aps->bus_head);
+	}
+
+	if (aps->io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (aps->io_head);
+	}
+
+	if (aps->mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (aps->mem_head);
+	}
+
+	if (aps->p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (aps->p_mem_head);
+	}
+}
+
+static void print_pci_resources( struct acpi_bridge	*ab)
+{
+	if (ab->tbus_head) {
+		dbg("    Total BUS Resources:\n");
+		print_pci_resource (ab->tbus_head);
+	}
+	if (ab->bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (ab->bus_head);
+	}
+
+	if (ab->tio_head) {
+		dbg("    Total IO Resources:\n");
+		print_pci_resource (ab->tio_head);
+	}
+	if (ab->io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (ab->io_head);
+	}
+
+	if (ab->tmem_head) {
+		dbg("    Total MEM Resources:\n");
+		print_pci_resource (ab->tmem_head);
+	}
+	if (ab->mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (ab->mem_head);
+	}
+
+	if (ab->tp_mem_head) {
+		dbg("    Total PMEM Resources:\n");
+		print_pci_resource (ab->tp_mem_head);
+	}
+	if (ab->p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (ab->p_mem_head);
+	}
+	if (ab->_hpp) {
+		dbg("    _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size);
+		dbg("    _HPP: latency timer  =0x%x\n", ab->_hpp->latency_timer);
+		dbg("    _HPP: enable SERR    =0x%x\n", ab->_hpp->enable_serr);
+		dbg("    _HPP: enable PERR    =0x%x\n", ab->_hpp->enable_perr);
+	}
+}
+
+static int shpchprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	shpchp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+static int shpchprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res->next)
+		shpchprm_delete_resource(aprh, res->base, res->length);
+
+	return 0;
+}
+
+static int shpchprm_add_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+
+	for (res = *aprh; res; res = res->next) {
+		if ((res->base + res->length) == base) {
+			res->length += size;
+			size = 0L;
+			break;
+		}
+		if (res->next == *aprh)
+			break;
+	}
+
+	if (size) {
+		res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		if (!res) {
+			err ("acpi_shpchprm: alloc for res fail\n");
+			return -ENOMEM;
+		}
+		memset(res, 0, sizeof (struct pci_resource));
+
+		res->base = base;
+		res->length = size;
+		res->next = *aprh;
+		*aprh = res;
+	}
+
+	return 0;
+}
+
+static int shpchprm_add_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+	int	rc = 0;
+
+	for (res = this; res && !rc; res = res->next)
+		rc = shpchprm_add_resource(aprh, res->base, res->length);
+
+	return rc;
+}
+
+static void acpi_parse_io (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_io	*dataio;
+	dataio = (struct acpi_resource_io *) data;
+
+	dbg("Io Resource\n");
+	dbg("  %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10);
+	dbg("  Range minimum base: %08X\n", dataio->min_base_address);
+	dbg("  Range maximum base: %08X\n", dataio->max_base_address);
+	dbg("  Alignment: %08X\n", dataio->alignment);
+	dbg("  Range Length: %08X\n", dataio->range_length);
+}
+
+static void acpi_parse_fixed_io (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_fixed_io  *datafio;
+	datafio = (struct acpi_resource_fixed_io *) data;
+
+	dbg("Fixed Io Resource\n");
+	dbg("  Range base address: %08X", datafio->base_address);
+	dbg("  Range length: %08X", datafio->range_length);
+}
+
+static void acpi_parse_address16_32 (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data,
+	acpi_resource_type		id
+	)
+{
+	/* 
+	 * acpi_resource_address16 == acpi_resource_address32
+	 * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data;
+	 */
+	struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data;
+	struct pci_resource **aprh, **tprh;
+
+	if (id == ACPI_RSTYPE_ADDRESS16)
+		dbg("acpi_shpchprm:16-Bit Address Space Resource\n");
+	else
+		dbg("acpi_shpchprm:32-Bit Address Space Resource\n");
+
+	switch (data32->resource_type) {
+	case ACPI_MEMORY_RANGE: 
+		dbg("  Resource Type: Memory Range\n");
+		aprh = &ab->mem_head;
+		tprh = &ab->tmem_head;
+
+		switch (data32->attribute.memory.cache_attribute) {
+		case ACPI_NON_CACHEABLE_MEMORY:
+			dbg("  Type Specific: Noncacheable memory\n");
+			break; 
+		case ACPI_CACHABLE_MEMORY:
+			dbg("  Type Specific: Cacheable memory\n");
+			break; 
+		case ACPI_WRITE_COMBINING_MEMORY:
+			dbg("  Type Specific: Write-combining memory\n");
+			break; 
+		case ACPI_PREFETCHABLE_MEMORY:
+			aprh = &ab->p_mem_head;
+			dbg("  Type Specific: Prefetchable memory\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid cache attribute\n");
+			break;
+		}
+
+		dbg("  Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only");
+		break;
+
+	case ACPI_IO_RANGE: 
+		dbg("  Resource Type: I/O Range\n");
+		aprh = &ab->io_head;
+		tprh = &ab->tio_head;
+
+		switch (data32->attribute.io.range_attribute) {
+		case ACPI_NON_ISA_ONLY_RANGES:
+			dbg("  Type Specific: Non-ISA Io Addresses\n");
+			break; 
+		case ACPI_ISA_ONLY_RANGES:
+			dbg("  Type Specific: ISA Io Addresses\n");
+			break; 
+		case ACPI_ENTIRE_RANGE:
+			dbg("  Type Specific: ISA and non-ISA Io Addresses\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid range attribute\n");
+			break;
+		}
+		break;
+
+	case ACPI_BUS_NUMBER_RANGE: 
+		dbg("  Resource Type: Bus Number Range(fixed)\n");
+		/* fixup to be compatible with the rest of php driver */
+		data32->min_address_range++;
+		data32->address_length--;
+		aprh = &ab->bus_head;
+		tprh = &ab->tbus_head;
+		break; 
+	default: 
+		dbg("  Resource Type: Invalid resource type. Exiting.\n");
+		return;
+	}
+
+	dbg("  Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer");
+	dbg("  %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive");
+	dbg("  Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not");
+	dbg("  Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not");
+	dbg("  Granularity: %08X\n", data32->granularity);
+	dbg("  Address range min: %08X\n", data32->min_address_range);
+	dbg("  Address range max: %08X\n", data32->max_address_range);
+	dbg("  Address translation offset: %08X\n", data32->address_translation_offset);
+	dbg("  Address Length: %08X\n", data32->address_length);
+
+	if (0xFF != data32->resource_source.index) {
+		dbg("  Resource Source Index: %X\n", data32->resource_source.index);
+		/* dbg("  Resource Source: %s\n", data32->resource_source.string_ptr); */
+	}
+
+	shpchprm_add_resource(aprh, data32->min_address_range, data32->address_length);
+}
+
+static acpi_status acpi_parse_crs(
+	struct acpi_bridge	*ab,
+	struct acpi_resource	*crsbuf
+	)
+{
+	acpi_status		status = AE_OK;
+	struct acpi_resource	*resource = crsbuf;
+	u8			count = 0;
+	u8			done = 0;
+
+	while (!done) {
+		dbg("acpi_shpchprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++);
+		switch (resource->id) {
+		case ACPI_RSTYPE_IRQ:
+			dbg("Irq -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_DMA:
+			dbg("DMA -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_START_DPF:
+			dbg("Start DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_DPF:
+			dbg("End DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_IO:
+			acpi_parse_io (ab, &resource->data);
+			break; 
+		case ACPI_RSTYPE_FIXED_IO:
+			acpi_parse_fixed_io (ab, &resource->data);
+			break; 
+		case ACPI_RSTYPE_VENDOR:
+			dbg("Vendor -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_TAG:
+			dbg("End_tag -------- Resource\n");
+			done = 1;
+			break; 
+		case ACPI_RSTYPE_MEM24:
+			dbg("Mem24 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_MEM32:
+			dbg("Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_FIXED_MEM32:
+			dbg("Fixed Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_ADDRESS16:
+			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16);
+			break; 
+		case ACPI_RSTYPE_ADDRESS32:
+			acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32);
+			break; 
+		case ACPI_RSTYPE_ADDRESS64:
+			info("Address64 -------- Resource unparsed\n");
+			break; 
+		case ACPI_RSTYPE_EXT_IRQ:
+			dbg("Ext Irq -------- Resource\n");
+			break; 
+		default:
+			dbg("Invalid -------- resource type 0x%x\n", resource->id);
+			break;
+		}
+
+		resource = (struct acpi_resource *) ((char *)resource + resource->length);
+	}
+
+	return status;
+}
+
+static acpi_status acpi_get_crs( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	struct acpi_resource	*crsbuf;
+
+	status = acpi_evaluate_crs(ab->handle, &crsbuf);
+	if (ACPI_SUCCESS(status)) {
+		status = acpi_parse_crs(ab, crsbuf);
+		kfree(crsbuf);
+
+		shpchp_resource_sort_and_combine(&ab->bus_head);
+		shpchp_resource_sort_and_combine(&ab->io_head);
+		shpchp_resource_sort_and_combine(&ab->mem_head);
+		shpchp_resource_sort_and_combine(&ab->p_mem_head);
+
+		shpchprm_add_resources (&ab->tbus_head, ab->bus_head);
+		shpchprm_add_resources (&ab->tio_head, ab->io_head);
+		shpchprm_add_resources (&ab->tmem_head, ab->mem_head);
+		shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
+	}
+
+	return status;
+}
+
+/* find acpi_bridge downword from ab.  */
+static struct acpi_bridge *
+find_acpi_bridge_by_bus(
+	struct acpi_bridge *ab,
+	int seg,
+	int bus		/* pdev->subordinate->number */
+	)
+{
+	struct acpi_bridge	*lab = NULL;
+
+	if (!ab)
+		return NULL;
+
+	if ((ab->bus == bus) && (ab->seg == seg))
+		return ab;
+
+	if (ab->child)
+		lab = find_acpi_bridge_by_bus(ab->child, seg, bus);
+
+	if (!lab)
+	if (ab->next)
+		lab = find_acpi_bridge_by_bus(ab->next, seg, bus);
+
+	return lab;
+}
+
+/*
+ * Build a device tree of ACPI PCI Bridges
+ */
+static void shpchprm_acpi_register_a_bridge (
+	struct acpi_bridge	**head,
+	struct acpi_bridge	*pab,	/* parent bridge to which child bridge is added */
+	struct acpi_bridge	*cab	/* child bridge to add */
+	)
+{
+	struct acpi_bridge	*lpab;
+	struct acpi_bridge	*lcab;
+
+	lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus);
+	if (!lpab) {
+		if (!(pab->type & BRIDGE_TYPE_HOST))
+			warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus);
+		pab->next = *head;
+		*head = pab;
+		lpab = pab;
+	}
+
+	if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab))
+		return;
+
+	lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus);
+	if (lcab) {
+		if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus))
+			err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus);
+		return;
+	} else
+		lcab = cab;
+
+	lcab->parent = lpab;
+	lcab->next = lpab->child;
+	lpab->child = lcab;
+}
+
+static acpi_status shpchprm_acpi_build_php_slots_callback(
+	acpi_handle	handle,
+	u32		Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		bus_num;
+	ulong		seg_num;
+	ulong		sun, adr;
+	ulong		padr = 0;
+	acpi_handle		phandle = NULL;
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*lab;
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get _SUN */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun);
+	switch(status) {
+	case AE_NOT_FOUND:
+		return AE_OK;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status);
+			return status;
+		}
+	}
+
+	/* get _ADR. _ADR must exist if _SUN exists */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr);
+
+	status = acpi_get_parent(handle, &phandle);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	bus_num = pab->bus;
+	seg_num = pab->seg;
+
+	if (pab->bus == bus_num) {
+		lab = pab;
+	} else {
+		dbg("WARN: pab is not parent\n");
+		lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num);
+		if (!lab) {
+			dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+			lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL);
+			if (!lab) {
+				err("acpi_shpchprm: alloc for ab fail\n");
+				return AE_NO_MEMORY;
+			}
+			memset(lab, 0, sizeof(struct acpi_bridge));
+
+			lab->handle = phandle;
+			lab->pbus = pab->bus;
+			lab->pdevice = (int)(padr >> 16) & 0xffff;
+			lab->pfunction = (int)(padr & 0xffff);
+			lab->bus = (int)bus_num;
+			lab->scanned = 0;
+			lab->type = BRIDGE_TYPE_P2P;
+
+			shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab);
+		} else
+			dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+	}
+
+	acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun);
+	return (status);
+}
+
+static int shpchprm_acpi_build_php_slots(
+	struct acpi_bridge	*ab,
+	u32			depth
+	)
+{
+	acpi_status	status;
+	u8		*path_name = acpi_path_name(ab->handle);
+
+	/* Walk down this pci bridge to get _SUNs if any behind P2P */
+	status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+				ab->handle,
+				depth,
+				shpchprm_acpi_build_php_slots_callback,
+				ab,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void build_a_bridge(
+	struct acpi_bridge	*pab,
+	struct acpi_bridge	*ab
+	)
+{
+	u8		*path_name = acpi_path_name(ab->handle);
+
+	shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab);
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x)    on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("acpi_shpchprm: Registered PCI  P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name);
+		break;
+	};
+
+	/* build any immediate PHP slots under this pci bridge */
+	shpchprm_acpi_build_php_slots(ab, 1);
+}
+
+static struct acpi_bridge * add_p2p_bridge(
+	acpi_handle handle,
+	struct acpi_bridge	*pab,	/* parent */
+	ulong	adr
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_dev	*pdev;
+	ulong		devnum, funcnum;
+	u8			*path_name = acpi_path_name(handle);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_shpchprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	devnum = (adr >> 16) & 0xffff;
+	funcnum = adr & 0xffff;
+
+	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev || !pdev->subordinate) {
+		err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name);
+		kfree(ab);
+		return NULL;
+	}
+
+	ab->handle = handle;
+	ab->seg = pab->seg;
+	ab->pbus = pab->bus;		/* or pdev->bus->number */
+	ab->pdevice = devnum;		/* or PCI_SLOT(pdev->devfn) */
+	ab->pfunction = funcnum;	/* or PCI_FUNC(pdev->devfn) */
+	ab->bus = pdev->subordinate->number;
+	ab->scanned = 0;
+	ab->type = BRIDGE_TYPE_P2P;
+
+	dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n",
+		pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+		pab->bus, (u32)devnum, (u32)funcnum, path_name);
+
+	build_a_bridge(pab, ab);
+
+	return ab;
+}
+
+static acpi_status scan_p2p_bridge(
+	acpi_handle		handle,
+	u32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*ab;
+	acpi_status		status;
+	ulong		adr = 0;
+	u8			*path_name = acpi_path_name(handle);
+	ulong		devnum, funcnum;
+	struct pci_dev	*pdev;
+
+	/* get device, function */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND)
+			err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
+		return AE_OK;
+	}
+
+	devnum = (adr >> 16) & 0xffff;
+	funcnum = adr & 0xffff;
+
+	pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev)
+		return AE_OK;
+	if (!pdev->subordinate)
+		return AE_OK;
+
+	ab = add_p2p_bridge(handle, pab, adr);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					(u32)1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static struct acpi_bridge * add_host_bridge(
+	acpi_handle handle,
+	ulong	segnum,
+	ulong	busnum
+	)
+{
+	ulong			adr = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get device, function: host br adr is always 0000 though.  */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
+		return NULL;
+	}
+	dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, 
+		(u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_shpchprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	ab->handle = handle;
+	ab->seg = (int)segnum;
+	ab->bus = ab->pbus = (int)busnum;
+	ab->pdevice = (int)(adr >> 16) & 0xffff;
+	ab->pfunction = (int)(adr & 0xffff);
+	ab->scanned = 0;
+	ab->type = BRIDGE_TYPE_HOST;
+
+	/* get root pci bridge's current resources */
+	status = acpi_get_crs(ab);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s evaluate _CRS fail=0x%x\n", path_name, status);
+		kfree(ab);
+		return NULL;
+	}
+	build_a_bridge(ab, ab);
+
+	return ab;
+}
+
+static acpi_status acpi_scan_from_root_pci_callback (
+	acpi_handle	handle,
+	u32			Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		segnum = 0;
+	ulong		busnum = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status);
+			return status;
+		}
+		segnum = 0;
+	}
+
+	/* get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	ab = add_host_bridge(handle, segnum, busnum);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static int shpchprm_acpi_scan_pci (void)
+{
+	acpi_status	status;
+
+	/*
+	 * TBD: traverse LDM device tree with the help of
+	 *  unified ACPI augmented for php device population.
+	 */
+	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
+				acpi_scan_from_root_pci_callback,
+				NULL,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status);
+		return -1;
+	}
+
+	return 0;
+}
+
+int shpchprm_init(enum php_ctlr_type ctlr_type)
+{
+	int	rc;
+
+	if (ctlr_type != PCI)
+		return -ENODEV;
+
+	dbg("shpchprm ACPI init <enter>\n");
+	acpi_bridges_head = NULL;
+
+	/* construct PCI bus:device tree of acpi_handles */
+	rc = shpchprm_acpi_scan_pci();
+	if (rc)
+		return rc;
+
+	dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success");
+	return rc;
+}
+
+static void free_a_slot(struct acpi_php_slot *aps)
+{
+	dbg("        free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun);
+
+	free_pci_resource (aps->io_head);
+	free_pci_resource (aps->bus_head);
+	free_pci_resource (aps->mem_head);
+	free_pci_resource (aps->p_mem_head);
+
+	kfree(aps);
+}
+
+static void free_a_bridge( struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot	*aps, *next;
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction);
+		break;
+	};
+
+	/* free slots first */
+	for (aps = ab->slots; aps; aps = next) {
+		next = aps->next;
+		free_a_slot(aps);
+	}
+
+	free_pci_resource (ab->io_head);
+	free_pci_resource (ab->tio_head);
+	free_pci_resource (ab->bus_head);
+	free_pci_resource (ab->tbus_head);
+	free_pci_resource (ab->mem_head);
+	free_pci_resource (ab->tmem_head);
+	free_pci_resource (ab->p_mem_head);
+	free_pci_resource (ab->tp_mem_head);
+
+	kfree(ab);
+}
+
+static void shpchprm_free_bridges ( struct acpi_bridge	*ab)
+{
+	if (!ab)
+		return;
+
+	if (ab->child)
+		shpchprm_free_bridges (ab->child);
+
+	if (ab->next)
+		shpchprm_free_bridges (ab->next);
+
+	free_a_bridge(ab);
+}
+
+void shpchprm_cleanup(void)
+{
+	shpchprm_free_bridges (acpi_bridges_head);
+}
+
+static int get_number_of_slots (
+	struct acpi_bridge	*ab,
+	int				selfonly
+	)
+{
+	struct acpi_php_slot	*aps;
+	int	prev_slot = -1;
+	int	slot_num = 0;
+
+	for ( aps = ab->slots; aps; aps = aps->next)
+		if (aps->dev != prev_slot) {
+			prev_slot = aps->dev;
+			slot_num++;
+		}
+
+	if (ab->child)
+		slot_num += get_number_of_slots (ab->child, 0);
+
+	if (selfonly)
+		return slot_num;
+
+	if (ab->next)
+		slot_num += get_number_of_slots (ab->next, 0);
+
+	return slot_num;
+}
+
+static int print_acpi_resources (struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot	*aps;
+	int	i;
+
+	switch (ab->type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle));
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle));
+		break;
+	};
+
+	print_pci_resources (ab);
+
+	for ( i = -1, aps = ab->slots; aps; aps = aps->next) {
+		if (aps->dev == i)
+			continue;
+		dbg("  Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun);
+		print_slot_resources(aps);
+		i = aps->dev;
+	}
+
+	if (ab->child)
+		print_acpi_resources (ab->child);
+
+	if (ab->next)
+		print_acpi_resources (ab->next);
+
+	return 0;
+}
+
+int shpchprm_print_pirt(void)
+{
+	dbg("SHPCHPRM ACPI Slots\n");
+	if (acpi_bridges_head)
+		print_acpi_resources (acpi_bridges_head);
+	return 0;
+}
+
+static struct acpi_php_slot * get_acpi_slot (
+	struct acpi_bridge *ab,
+	u32 sun
+	)
+{
+	struct acpi_php_slot	*aps = NULL;
+
+	for ( aps = ab->slots; aps; aps = aps->next)
+		if (aps->sun == sun)
+			return aps;
+
+	if (!aps && ab->child) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun);
+		if (aps)
+			return aps;
+	}
+
+	if (!aps && ab->next) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun);
+		if (aps)
+			return aps;
+	}
+
+	return aps;
+
+}
+
+#if 0
+static void * shpchprm_get_slot(struct slot *slot)
+{
+	struct acpi_bridge	*ab = acpi_bridges_head;
+	struct acpi_php_slot	*aps = get_acpi_slot (ab, slot->number);
+
+	aps->slot = slot;
+
+	dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun);
+
+	return (void *)aps;
+}
+#endif
+
+static void shpchprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func->bus_head);
+	}
+	if (func->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func->io_head);
+	}
+	if (func->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func->mem_head);
+	}
+	if (func->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func->p_mem_head);
+	}
+}
+
+static void shpchprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl->bus_head);
+	}
+	if (ctrl->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl->io_head);
+	}
+	if (ctrl->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl->mem_head);
+	}
+	if (ctrl->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl->p_mem_head);
+	}
+}
+
+static int shpchprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = shpchprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = shpchprm_delete_resources (&ctrl->bus_head, func->bus_head);
+		rc |= shpchprm_delete_resources (&ctrl->io_head, func->io_head);
+		rc |= shpchprm_delete_resources (&ctrl->mem_head, func->mem_head);
+		rc |= shpchprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func, new_func;
+	int busn = ctrl->slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn < 32; devn++) {
+		for (funn = 0; funn < 8; funn++) {
+			/*
+			if (devn == ctrl->device && funn == ctrl->function)
+				continue;
+			*/
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+			pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid);
+
+			if (vid != 0xFFFFFFFF) {
+				func = shpchp_slot_find(busn, devn, funn);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					shpchprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					shpchprm_dump_func_res(func);
+				}
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int bind_pci_resources(
+	struct controller 	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int	status = 0;
+
+	if (ab->bus_head) {
+		dbg("bapr:  BUS Resources add on PCI 0x%x\n", ab->bus);
+		status = shpchprm_add_resources (&ctrl->bus_head, ab->bus_head);
+		if (shpchprm_delete_resources (&ab->bus_head, ctrl->bus_head))
+			warn("bapr:  cannot sub BUS Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No BUS Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->io_head) {
+		dbg("bapr:  IO Resources add on PCI 0x%x\n", ab->bus);
+		status = shpchprm_add_resources (&ctrl->io_head, ab->io_head);
+		if (shpchprm_delete_resources (&ab->io_head, ctrl->io_head))
+			warn("bapr:  cannot sub IO Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No  IO Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->mem_head) {
+		dbg("bapr:  MEM Resources add on PCI 0x%x\n", ab->bus);
+		status = shpchprm_add_resources (&ctrl->mem_head, ab->mem_head);
+		if (shpchprm_delete_resources (&ab->mem_head, ctrl->mem_head))
+			warn("bapr:  cannot sub MEM Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No MEM Resource on PCI 0x%x.\n", ab->bus);
+
+	if (ab->p_mem_head) {
+		dbg("bapr:  PMEM Resources add on PCI 0x%x\n", ab->bus);
+		status = shpchprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head);
+		if (shpchprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head))
+			warn("bapr:  cannot sub PMEM Resource on PCI 0x%x\n", ab->bus);
+		if (status) {
+			err("bapr:  PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No PMEM Resource on PCI 0x%x.\n", ab->bus);
+
+	return status;
+}
+
+static int no_pci_resources( struct acpi_bridge *ab)
+{
+	return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head);
+}
+
+static int find_pci_bridge_resources (
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+	struct pci_func func;
+
+	memset(&func, 0, sizeof(struct pci_func));
+
+	func.bus = ab->pbus;
+	func.device = ab->pdevice;
+	func.function = ab->pfunction;
+	func.is_a_board = 1;
+
+	/* Get used resources for this PCI bridge */
+	rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD);
+
+	ab->io_head = func.io_head;
+	ab->mem_head = func.mem_head;
+	ab->p_mem_head = func.p_mem_head;
+	ab->bus_head = func.bus_head;
+	if (ab->bus_head)
+		shpchprm_delete_resource(&ab->bus_head, ctrl->bus, 1);
+
+	return rc;
+}
+
+static int get_pci_resources_from_bridge(
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+
+	dbg("grfb:  Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus);
+
+	rc = find_pci_bridge_resources (ctrl, ab);
+
+	shpchp_resource_sort_and_combine(&ab->bus_head);
+	shpchp_resource_sort_and_combine(&ab->io_head);
+	shpchp_resource_sort_and_combine(&ab->mem_head);
+	shpchp_resource_sort_and_combine(&ab->p_mem_head);
+
+	shpchprm_add_resources (&ab->tbus_head, ab->bus_head);
+	shpchprm_add_resources (&ab->tio_head, ab->io_head);
+	shpchprm_add_resources (&ab->tmem_head, ab->mem_head);
+	shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head);
+
+	return rc;
+}
+
+static int get_pci_resources(
+	struct controller	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int	rc = 0;
+
+	if (no_pci_resources(ab)) {
+		dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus);
+		rc = get_pci_resources_from_bridge(ctrl, ab);
+	}
+
+	return rc;
+}
+
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+	int offset = devnum - ctrl->slot_device_offset;
+
+	dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl->slot_num_inc, offset);
+	*sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc *offset);
+	return 0;
+}
+
+/*
+ * Get resources for this ctrl.
+ *  1. get total resources from ACPI _CRS or bridge (this ctrl)
+ *  2. find used resources of existing adapters
+ *	3. subtract used resources from total resources
+ */
+int shpchprm_find_available_resources( struct controller *ctrl)
+{
+	int rc = 0;
+	struct acpi_bridge	*ab;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number);
+	if (!ab) {
+		err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number);
+		return -1;
+	}
+	if (no_pci_resources(ab)) {
+		rc = get_pci_resources(ctrl, ab);
+		if (rc) {
+			err("pfar:cannot get pci resources of PCI 0x%x.\n",ctrl->pci_dev->subordinate->number);
+			return -1;
+		}
+	}
+
+	rc = bind_pci_resources(ctrl, ab);
+	dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
+	shpchprm_dump_ctrl_res(ctrl);
+
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number);
+	shpchprm_dump_ctrl_res(ctrl);
+
+	return rc;
+}
+
+int shpchprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_bus lpci_bus, *pci_bus;
+	int				rc = 0;
+	unsigned int	devfn;
+	u8				cls= 0x08;	/* default cache line size	*/
+	u8				lt = 0x40;	/* default latency timer	*/
+	u8				ep = 0;
+	u8				es = 0;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+
+	if (ab) {
+		if (ab->_hpp) {
+			lt  = (u8)ab->_hpp->latency_timer;
+			cls = (u8)ab->_hpp->cache_line_size;
+			ep  = (u8)ab->_hpp->enable_perr;
+			es  = (u8)ab->_hpp->enable_serr;
+		} else
+			dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
+	} else
+		dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function);
+
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt);
+	}
+
+	/* set base Latency Timer */
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt);
+	dbg("  set latency timer  =0x%02x: %x\n", lt, rc);
+
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls);
+	dbg("  set cache_line_size=0x%02x: %x\n", cls, rc);
+
+	return rc;
+}
+
+void shpchprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, cmd, bcommand, bcmd;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct acpi_bridge	*ab;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+	}
+
+	cmd = command  = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	bcmd = bcommand  = bcommand | PCI_BRIDGE_CTL_NO_ISA;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus);
+	if (ab) {
+		if (ab->_hpp) {
+			if (ab->_hpp->enable_perr) {
+				command |= PCI_COMMAND_PARITY;
+				bcommand |= PCI_BRIDGE_CTL_PARITY;
+			} else {
+				command &= ~PCI_COMMAND_PARITY;
+				bcommand &= ~PCI_BRIDGE_CTL_PARITY;
+			}
+			if (ab->_hpp->enable_serr) {
+				command |= PCI_COMMAND_SERR;
+				bcommand |= PCI_BRIDGE_CTL_SERR;
+			} else {
+				command &= ~PCI_COMMAND_SERR;
+				bcommand &= ~PCI_BRIDGE_CTL_SERR;
+			}
+		} else
+			dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
+	} else
+		dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function);
+
+	if (command != cmd) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+	}
+	if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
diff --git a/drivers/pci/hotplug/shpchprm_legacy.c b/drivers/pci/hotplug/shpchprm_legacy.c
new file mode 100644
index 0000000..37fa77a
--- /dev/null
+++ b/drivers/pci/hotplug/shpchprm_legacy.c
@@ -0,0 +1,439 @@
+/*
+ * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>,<dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include "shpchp.h"
+#include "shpchprm.h"
+#include "shpchprm_legacy.h"
+
+static void __iomem *shpchp_rom_start;
+static u16 unused_IRQ;
+
+void shpchprm_cleanup(void)
+{
+	if (shpchp_rom_start)
+		iounmap(shpchp_rom_start);
+}
+
+int shpchprm_print_pirt(void)
+{
+	return 0;
+}
+
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+	int	offset = devnum - ctrl->slot_device_offset;
+
+	*sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc * offset);
+	return 0;
+}
+
+/* Find the Hot Plug Resource Table in the specified region of memory */
+static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end)
+{
+	void __iomem *fp;
+	void __iomem *endp;
+	u8 temp1, temp2, temp3, temp4;
+	int status = 0;
+
+	endp = (end - sizeof(struct hrt) + 1);
+
+	for (fp = begin; fp <= endp; fp += 16) {
+		temp1 = readb(fp + SIG0);
+		temp2 = readb(fp + SIG1);
+		temp3 = readb(fp + SIG2);
+		temp4 = readb(fp + SIG3);
+		if (temp1 == '$' && temp2 == 'H' && temp3 == 'R' && temp4 == 'T') {
+			status = 1;
+			break;
+		}
+	}
+
+	if (!status)
+		fp = NULL;
+
+	dbg("Discovered Hotplug Resource Table at %p\n", fp);
+	return fp;
+}
+
+/*
+ * shpchprm_find_available_resources
+ *
+ *  Finds available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *  this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */
+int shpchprm_find_available_resources(struct controller *ctrl)
+{
+	u8 populated_slot;
+	u8 bridged_slot;
+	void __iomem *one_slot;
+	struct pci_func *func = NULL;
+	int i = 10, index = 0;
+	u32 temp_dword, rc;
+	ulong temp_ulong;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	void __iomem *rom_resource_table;
+	struct pci_bus lpci_bus, *pci_bus;
+	u8 cfgspc_irq, temp;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	rom_resource_table = detect_HRT_floating_pointer(shpchp_rom_start, shpchp_rom_start + 0xffff);
+	dbg("rom_resource_table = %p\n", rom_resource_table);
+	if (rom_resource_table == NULL)
+		return -ENODEV;
+
+	/* Sum all resources and setup resource maps */
+	unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
+	dbg("unused_IRQ = %x\n", unused_IRQ);
+
+	temp = 0;
+	while (unused_IRQ) {
+		if (unused_IRQ & 1) {
+			shpchp_disk_irq = temp;
+			break;
+		}
+		unused_IRQ = unused_IRQ >> 1;
+		temp++;
+	}
+
+	dbg("shpchp_disk_irq= %d\n", shpchp_disk_irq);
+	unused_IRQ = unused_IRQ >> 1;
+	temp++;
+
+	while (unused_IRQ) {
+		if (unused_IRQ & 1) {
+			shpchp_nic_irq = temp;
+			break;
+		}
+		unused_IRQ = unused_IRQ >> 1;
+		temp++;
+	}
+
+	dbg("shpchp_nic_irq= %d\n", shpchp_nic_irq);
+	unused_IRQ = readl(rom_resource_table + PCIIRQ);
+
+	temp = 0;
+
+	pci_read_config_byte(ctrl->pci_dev, PCI_INTERRUPT_LINE, &cfgspc_irq);
+
+	if (!shpchp_nic_irq) {
+		shpchp_nic_irq = cfgspc_irq;
+	}
+
+	if (!shpchp_disk_irq) {
+		shpchp_disk_irq = cfgspc_irq;
+	}
+
+	dbg("shpchp_disk_irq, shpchp_nic_irq= %d, %d\n", shpchp_disk_irq, shpchp_nic_irq);
+
+	one_slot = rom_resource_table + sizeof(struct hrt);
+
+	i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
+	dbg("number_of_entries = %d\n", i);
+
+	if (!readb(one_slot + SECONDARY_BUS))
+		return (1);
+
+	dbg("dev|IO base|length|MEMbase|length|PM base|length|PB SB MB\n");
+
+	while (i && readb(one_slot + SECONDARY_BUS)) {
+		u8 dev_func = readb(one_slot + DEV_FUNC);
+		u8 primary_bus = readb(one_slot + PRIMARY_BUS);
+		u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
+		u8 max_bus = readb(one_slot + MAX_BUS);
+		u16 io_base = readw(one_slot + IO_BASE);
+		u16 io_length = readw(one_slot + IO_LENGTH);
+		u16 mem_base = readw(one_slot + MEM_BASE);
+		u16 mem_length = readw(one_slot + MEM_LENGTH);
+		u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
+		u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
+
+		dbg("%2.2x |  %4.4x | %4.4x |  %4.4x | %4.4x |  %4.4x | %4.4x |%2.2x %2.2x %2.2x\n",
+				dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
+				primary_bus, secondary_bus, max_bus);
+
+		/* If this entry isn't for our controller's bus, ignore it */
+		if (primary_bus != ctrl->slot_bus) {
+			i--;
+			one_slot += sizeof(struct slot_rt);
+			continue;
+		}
+		/* find out if this entry is for an occupied slot */
+		temp_dword = 0xFFFFFFFF;
+		pci_bus->number = primary_bus;
+		pci_bus_read_config_dword(pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
+
+		dbg("temp_D_word = %x\n", temp_dword);
+
+		if (temp_dword != 0xFFFFFFFF) {
+			index = 0;
+			func = shpchp_slot_find(primary_bus, dev_func >> 3, 0);
+
+			while (func && (func->function != (dev_func & 0x07))) {
+				dbg("func = %p b:d:f(%x:%x:%x)\n", func, primary_bus, dev_func >> 3, index);
+				func = shpchp_slot_find(primary_bus, dev_func >> 3, index++);
+			}
+
+			/* If we can't find a match, skip this table entry */
+			if (!func) {
+				i--;
+				one_slot += sizeof(struct slot_rt);
+				continue;
+			}
+			/* this may not work and shouldn't be used */
+			if (secondary_bus != primary_bus)
+				bridged_slot = 1;
+			else
+				bridged_slot = 0;
+
+			populated_slot = 1;
+		} else {
+			populated_slot = 0;
+			bridged_slot = 0;
+		}
+		dbg("slot populated =%s \n", populated_slot?"yes":"no");
+
+		/* If we've got a valid IO base, use it */
+
+		temp_ulong = io_base + io_length;
+
+		if ((io_base) && (temp_ulong <= 0x10000)) {
+			io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!io_node)
+				return -ENOMEM;
+
+			io_node->base = (ulong)io_base;
+			io_node->length = (ulong)io_length;
+			dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length);
+
+			if (!populated_slot) {
+				io_node->next = ctrl->io_head;
+				ctrl->io_head = io_node;
+			} else {
+				io_node->next = func->io_head;
+				func->io_head = io_node;
+			}
+		}
+
+		/* If we've got a valid memory base, use it */
+		temp_ulong = mem_base + mem_length;
+		if ((mem_base) && (temp_ulong <= 0x10000)) {
+			mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!mem_node)
+				return -ENOMEM;
+
+			mem_node->base = (ulong)mem_base << 16;
+			mem_node->length = (ulong)(mem_length << 16);
+			dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length);
+
+			if (!populated_slot) {
+				mem_node->next = ctrl->mem_head;
+				ctrl->mem_head = mem_node;
+			} else {
+				mem_node->next = func->mem_head;
+				func->mem_head = mem_node;
+			}
+		}
+
+		/*
+		 * If we've got a valid prefetchable memory base, and
+		 * the base + length isn't greater than 0xFFFF
+		 */
+		temp_ulong = pre_mem_base + pre_mem_length;
+		if ((pre_mem_base) && (temp_ulong <= 0x10000)) {
+			p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!p_mem_node)
+				return -ENOMEM;
+
+			p_mem_node->base = (ulong)pre_mem_base << 16;
+			p_mem_node->length = (ulong)pre_mem_length << 16;
+			dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length);
+
+			if (!populated_slot) {
+				p_mem_node->next = ctrl->p_mem_head;
+				ctrl->p_mem_head = p_mem_node;
+			} else {
+				p_mem_node->next = func->p_mem_head;
+				func->p_mem_head = p_mem_node;
+			}
+		}
+
+		/*
+		 * If we've got a valid bus number, use it
+		 * The second condition is to ignore bus numbers on
+		 * populated slots that don't have PCI-PCI bridges
+		 */
+		if (secondary_bus && (secondary_bus != primary_bus)) {
+			bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node->base = (ulong)secondary_bus;
+			bus_node->length = (ulong)(max_bus - secondary_bus + 1);
+			dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length);
+
+			if (!populated_slot) {
+				bus_node->next = ctrl->bus_head;
+				ctrl->bus_head = bus_node;
+			} else {
+				bus_node->next = func->bus_head;
+				func->bus_head = bus_node;
+			}
+		}
+
+		i--;
+		one_slot += sizeof(struct slot_rt);
+	}
+
+	/* If all of the following fail, we don't have any resources for hot plug add */
+	rc = 1;
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head));
+
+	return (rc);
+}
+
+int shpchprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type)
+{
+	u32 rc;
+	u8 temp_byte;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int	devfn;
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	temp_byte = 0x40;	/* hard coded value for LT */
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+		if (rc) {
+			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, 
+				func->device, func->function);
+			return rc;
+		}
+	}
+
+	/* set base Latency Timer */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+	if (rc) {
+		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+		return rc;
+	}
+
+	/* set Cache Line size */
+	temp_byte = 0x08;	/* hard coded value for CLS */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+	if (rc) {
+		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+	}
+
+	/* set enable_perr */
+	/* set enable_serr */
+
+	return rc;
+}
+
+void shpchprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, bcommand;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
+		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
+			| PCI_BRIDGE_CTL_NO_ISA;
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
+static int legacy_shpchprm_init_pci(void)
+{
+	shpchp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN);
+	if (!shpchp_rom_start) {
+		err("Could not ioremap memory region for ROM\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int shpchprm_init(enum php_ctlr_type ctrl_type)
+{
+	int retval;
+
+	switch (ctrl_type) {
+	case PCI:
+		retval = legacy_shpchprm_init_pci();
+		break;
+	default:
+		retval = -ENODEV;
+		break;
+	}
+
+	return retval;
+}
diff --git a/drivers/pci/hotplug/shpchprm_legacy.h b/drivers/pci/hotplug/shpchprm_legacy.h
new file mode 100644
index 0000000..29ccea5
--- /dev/null
+++ b/drivers/pci/hotplug/shpchprm_legacy.h
@@ -0,0 +1,113 @@
+/*
+ * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform using HRT
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _SHPCHPRM_LEGACY_H_
+#define _SHPCHPRM_LEGACY_H_
+
+#define ROM_PHY_ADDR	0x0F0000
+#define ROM_PHY_LEN	0x00FFFF
+
+struct slot_rt {
+	u8 dev_func;
+	u8 primary_bus;
+	u8 secondary_bus;
+	u8 max_bus;
+	u16 io_base;
+	u16 io_length;
+	u16 mem_base;
+	u16 mem_length;
+	u16 pre_mem_base;
+	u16 pre_mem_length;
+} __attribute__ ((packed));
+
+/* offsets to the hotplug slot resource table registers based on the above structure layout */
+enum slot_rt_offsets {
+	DEV_FUNC = offsetof(struct slot_rt, dev_func),
+	PRIMARY_BUS = offsetof(struct slot_rt, primary_bus),
+	SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus),
+	MAX_BUS = offsetof(struct slot_rt, max_bus),
+	IO_BASE = offsetof(struct slot_rt, io_base),
+	IO_LENGTH = offsetof(struct slot_rt, io_length),
+	MEM_BASE = offsetof(struct slot_rt, mem_base),
+	MEM_LENGTH = offsetof(struct slot_rt, mem_length),
+	PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base),
+	PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length),
+};
+
+struct hrt {
+	char sig0;
+	char sig1;
+	char sig2;
+	char sig3;
+	u16 unused_IRQ;
+	u16 PCIIRQ;
+	u8 number_of_entries;
+	u8 revision;
+	u16 reserved1;
+	u32 reserved2;
+} __attribute__ ((packed));
+
+/* offsets to the hotplug resource table registers based on the above structure layout */
+enum hrt_offsets {
+	SIG0 = offsetof(struct hrt, sig0),
+	SIG1 = offsetof(struct hrt, sig1),
+	SIG2 = offsetof(struct hrt, sig2),
+	SIG3 = offsetof(struct hrt, sig3),
+	UNUSED_IRQ = offsetof(struct hrt, unused_IRQ),
+	PCIIRQ = offsetof(struct hrt, PCIIRQ),
+	NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries),
+	REVISION = offsetof(struct hrt, revision),
+	HRT_RESERVED1 = offsetof(struct hrt, reserved1),
+	HRT_RESERVED2 = offsetof(struct hrt, reserved2),
+};
+
+struct irq_info {
+	u8 bus, devfn;		/* bus, device and function */
+	struct {
+		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;	/* Available IRQs */
+	} __attribute__ ((packed)) irq[4];
+	u8 slot;		/* slot number, 0=onboard */
+	u8 rfu;
+} __attribute__ ((packed));
+
+struct irq_routing_table {
+	u32 signature;		/* PIRQ_SIGNATURE should be here */
+	u16 version;		/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
+	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;	/* Crap */
+	u8 rfu[11];
+	u8 checksum;		/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__ ((packed));
+
+#endif				/* _SHPCHPRM_LEGACY_H_ */
diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.c b/drivers/pci/hotplug/shpchprm_nonacpi.c
new file mode 100644
index 0000000..88f4d9f
--- /dev/null
+++ b/drivers/pci/hotplug/shpchprm_nonacpi.c
@@ -0,0 +1,434 @@
+/*
+ * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
+#include "shpchp.h"
+#include "shpchprm.h"
+#include "shpchprm_nonacpi.h"
+
+void shpchprm_cleanup(void)
+{
+	return;
+}
+
+int shpchprm_print_pirt(void)
+{
+	return 0;
+}
+
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+	int	offset = devnum - ctrl->slot_device_offset;
+
+	dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl->slot_num_inc, offset);
+	*sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc * offset);
+	return 0;
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res->next)
+		dbg("        base= 0x%x length= 0x%x\n", res->base, res->length);
+}
+
+
+static void phprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func->bus_head);
+	}
+	if (func->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func->io_head);
+	}
+	if (func->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func->mem_head);
+	}
+	if (func->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func->p_mem_head);
+	}
+}
+
+static int phprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int phprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	shpchp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res->next) {
+		if (res->base > base)
+			continue;
+
+		if ((res->base + res->length) < (base + size))
+			continue;
+
+		if (res->base < base) {
+			tbase = base;
+
+			if ((res->length - (tbase - res->base)) < size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base;
+			split_node->length = tbase - res->base;
+			res->base = tbase;
+			res->length -= split_node->length;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (res->length >= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node->base = res->base + size;
+			split_node->length = res->length - size;
+			res->length = size;
+
+			split_node->next = res->next;
+			res->next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res->next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode->next != res)
+				prevnode = prevnode->next;
+
+			prevnode->next = res->next;
+		}
+		res->next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int phprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res->next)
+		phprm_delete_resource(aprh, res->base, res->length);
+
+	return 0;
+}
+
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = phprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = phprm_delete_resources (&ctrl->bus_head, func->bus_head);
+		rc |= phprm_delete_resources (&ctrl->io_head, func->io_head);
+		rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head);
+		rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func, new_func;
+	int busn = ctrl->slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn < 32; devn++) {
+		for (funn = 0; funn < 8; funn++) {
+			/*
+			if (devn == ctrl->device && funn == ctrl->function)
+				continue;
+			 */
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+
+			pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid);
+
+			if (vid != 0xFFFFFFFF) {
+				func = shpchp_slot_find(busn, devn, funn);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					phprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					phprm_dump_func_res(func);
+				}
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void phprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl->bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl->bus_head);
+	}
+	if (ctrl->io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl->io_head);
+	}
+	if (ctrl->mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl->mem_head);
+	}
+	if (ctrl->p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl->p_mem_head);
+	}
+}
+
+/*
+ * phprm_find_available_resources
+ *
+ *  Finds available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *  this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */
+int shpchprm_find_available_resources(struct controller *ctrl)
+{
+	struct pci_func func;
+	u32 rc;
+
+	memset(&func, 0, sizeof(struct pci_func));
+
+	func.bus = ctrl->bus;
+	func.device = ctrl->device;
+	func.function = ctrl->function;
+	func.is_a_board = 1;
+
+	/* Get resources for this PCI bridge */
+	rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD);
+	dbg("%s: shpchp_save_used_resources rc = %d\n", __FUNCTION__, rc);
+
+	if (func.mem_head)
+		func.mem_head->next = ctrl->mem_head;
+	ctrl->mem_head = func.mem_head;
+
+	if (func.p_mem_head)
+		func.p_mem_head->next = ctrl->p_mem_head;
+	ctrl->p_mem_head = func.p_mem_head;
+
+	if (func.io_head)
+		func.io_head->next = ctrl->io_head;
+	ctrl->io_head = func.io_head;
+
+	if(func.bus_head)
+		func.bus_head->next = ctrl->bus_head;
+	ctrl->bus_head = func.bus_head;
+	if (ctrl->bus_head)
+		phprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1);
+
+	dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
+	phprm_dump_ctrl_res(ctrl);
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus);
+	phprm_dump_ctrl_res(ctrl);
+
+
+	/* If all of the following fail, we don't have any resources for hot plug add */
+	rc = 1;
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head));
+	rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head));
+
+	return (rc);
+}
+
+int shpchprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type)
+{
+	u32 rc;
+	u8 temp_byte;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int	devfn;
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	temp_byte = 0x40;	/* hard coded value for LT */
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+
+		if (rc) {
+			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, 
+				func->device, func->function);
+			return rc;
+		}
+	}
+
+	/* set base Latency Timer */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+
+	if (rc) {
+		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+		return rc;
+	}
+
+	/* set Cache Line size */
+	temp_byte = 0x08;	/* hard coded value for CLS */
+
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+
+	if (rc) {
+		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function);
+	}
+
+	/* set enable_perr */
+	/* set enable_serr */
+
+	return rc;
+}
+
+void shpchprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, bcommand;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus));
+	pci_bus = &lpci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command);
+
+	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
+		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+
+	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand);
+
+		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
+			| PCI_BRIDGE_CTL_NO_ISA;
+
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
+static int legacy_shpchprm_init_pci(void)
+{
+	return 0;
+}
+
+int shpchprm_init(enum php_ctlr_type ctrl_type)
+{
+	int retval;
+
+	switch (ctrl_type) {
+	case PCI:
+		retval = legacy_shpchprm_init_pci();
+		break;
+	default:
+		retval = -ENODEV;
+		break;
+	}
+
+	return retval;
+}
diff --git a/drivers/pci/hotplug/shpchprm_nonacpi.h b/drivers/pci/hotplug/shpchprm_nonacpi.h
new file mode 100644
index 0000000..6bc8668
--- /dev/null
+++ b/drivers/pci/hotplug/shpchprm_nonacpi.h
@@ -0,0 +1,56 @@
+/*
+ * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <greg@kroah.com>, <dely.l.sy@intel.com>
+ *
+ */
+
+#ifndef _SHPCHPRM_NONACPI_H_
+#define _SHPCHPRM_NONACPI_H_
+
+struct irq_info {
+	u8 bus, devfn;		/* bus, device and function */
+	struct {
+		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;	/* Available IRQs */
+	} __attribute__ ((packed)) irq[4];
+	u8 slot;		/* slot number, 0=onboard */
+	u8 rfu;
+} __attribute__ ((packed));
+
+struct irq_routing_table {
+	u32 signature;		/* PIRQ_SIGNATURE should be here */
+	u16 version;		/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
+	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;	/* Crap */
+	u8 rfu[11];
+	u8 checksum;		/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__ ((packed));
+
+#endif				/* _SHPCHPRM_NONACPI_H_ */
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
new file mode 100644
index 0000000..22ecd3b
--- /dev/null
+++ b/drivers/pci/msi.c
@@ -0,0 +1,1151 @@
+/*
+ * File:	msi.c
+ * Purpose:	PCI Message Signaled Interrupt (MSI)
+ *
+ * Copyright (C) 2003-2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/ioport.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+
+#include "pci.h"
+#include "msi.h"
+
+static DEFINE_SPINLOCK(msi_lock);
+static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
+static kmem_cache_t* msi_cachep;
+
+static int pci_msi_enable = 1;
+static int last_alloc_vector = 0;
+static int nr_released_vectors = 0;
+static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS;
+static int nr_msix_devices = 0;
+
+#ifndef CONFIG_X86_IO_APIC
+int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
+u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
+#endif
+
+static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
+{
+	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
+}
+
+static int msi_cache_init(void)
+{
+	msi_cachep = kmem_cache_create("msi_cache",
+			NR_IRQS * sizeof(struct msi_desc),
+		       	0, SLAB_HWCACHE_ALIGN, msi_cache_ctor, NULL);
+	if (!msi_cachep)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void msi_set_mask_bit(unsigned int vector, int flag)
+{
+	struct msi_desc *entry;
+
+	entry = (struct msi_desc *)msi_desc[vector];
+	if (!entry || !entry->dev || !entry->mask_base)
+		return;
+	switch (entry->msi_attrib.type) {
+	case PCI_CAP_ID_MSI:
+	{
+		int		pos;
+		u32		mask_bits;
+
+		pos = (long)entry->mask_base;
+		pci_read_config_dword(entry->dev, pos, &mask_bits);
+		mask_bits &= ~(1);
+		mask_bits |= flag;
+		pci_write_config_dword(entry->dev, pos, mask_bits);
+		break;
+	}
+	case PCI_CAP_ID_MSIX:
+	{
+		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
+		writel(flag, entry->mask_base + offset);
+		break;
+	}
+	default:
+		break;
+	}
+}
+
+#ifdef CONFIG_SMP
+static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
+{
+	struct msi_desc *entry;
+	struct msg_address address;
+
+	entry = (struct msi_desc *)msi_desc[vector];
+	if (!entry || !entry->dev)
+		return;
+
+	switch (entry->msi_attrib.type) {
+	case PCI_CAP_ID_MSI:
+	{
+		int pos;
+
+   		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
+			return;
+
+		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
+			&address.lo_address.value);
+		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
+		address.lo_address.value |= (cpu_mask_to_apicid(cpu_mask) <<
+			MSI_TARGET_CPU_SHIFT);
+		entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
+		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
+			address.lo_address.value);
+		break;
+	}
+	case PCI_CAP_ID_MSIX:
+	{
+		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+		address.lo_address.value = readl(entry->mask_base + offset);
+		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
+		address.lo_address.value |= (cpu_mask_to_apicid(cpu_mask) <<
+			MSI_TARGET_CPU_SHIFT);
+		entry->msi_attrib.current_cpu = cpu_mask_to_apicid(cpu_mask);
+		writel(address.lo_address.value, entry->mask_base + offset);
+		break;
+	}
+	default:
+		break;
+	}
+}
+
+#ifdef CONFIG_IRQBALANCE
+static inline void move_msi(int vector)
+{
+	if (!cpus_empty(pending_irq_balance_cpumask[vector])) {
+		set_msi_affinity(vector, pending_irq_balance_cpumask[vector]);
+		cpus_clear(pending_irq_balance_cpumask[vector]);
+	}
+}
+#endif /* CONFIG_IRQBALANCE */
+#endif /* CONFIG_SMP */
+
+static void mask_MSI_irq(unsigned int vector)
+{
+	msi_set_mask_bit(vector, 1);
+}
+
+static void unmask_MSI_irq(unsigned int vector)
+{
+	msi_set_mask_bit(vector, 0);
+}
+
+static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector)
+{
+	struct msi_desc *entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msi_lock, flags);
+	entry = msi_desc[vector];
+	if (!entry || !entry->dev) {
+		spin_unlock_irqrestore(&msi_lock, flags);
+		return 0;
+	}
+	entry->msi_attrib.state = 1;	/* Mark it active */
+	spin_unlock_irqrestore(&msi_lock, flags);
+
+	return 0;	/* never anything pending */
+}
+
+static void release_msi(unsigned int vector);
+static void shutdown_msi_irq(unsigned int vector)
+{
+	release_msi(vector);
+}
+
+#define shutdown_msi_irq_wo_maskbit	shutdown_msi_irq
+static void enable_msi_irq_wo_maskbit(unsigned int vector) {}
+static void disable_msi_irq_wo_maskbit(unsigned int vector) {}
+static void ack_msi_irq_wo_maskbit(unsigned int vector) {}
+static void end_msi_irq_wo_maskbit(unsigned int vector)
+{
+	move_msi(vector);
+	ack_APIC_irq();
+}
+
+static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
+{
+	struct msi_desc *entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msi_lock, flags);
+	entry = msi_desc[vector];
+	if (!entry || !entry->dev) {
+		spin_unlock_irqrestore(&msi_lock, flags);
+		return 0;
+	}
+	entry->msi_attrib.state = 1;	/* Mark it active */
+	spin_unlock_irqrestore(&msi_lock, flags);
+
+	unmask_MSI_irq(vector);
+	return 0;	/* never anything pending */
+}
+
+#define shutdown_msi_irq_w_maskbit	shutdown_msi_irq
+#define enable_msi_irq_w_maskbit	unmask_MSI_irq
+#define disable_msi_irq_w_maskbit	mask_MSI_irq
+#define ack_msi_irq_w_maskbit		mask_MSI_irq
+
+static void end_msi_irq_w_maskbit(unsigned int vector)
+{
+	move_msi(vector);
+	unmask_MSI_irq(vector);
+	ack_APIC_irq();
+}
+
+/*
+ * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI-X Capability Structure.
+ */
+static struct hw_interrupt_type msix_irq_type = {
+	.typename	= "PCI-MSI-X",
+	.startup	= startup_msi_irq_w_maskbit,
+	.shutdown	= shutdown_msi_irq_w_maskbit,
+	.enable		= enable_msi_irq_w_maskbit,
+	.disable	= disable_msi_irq_w_maskbit,
+	.ack		= ack_msi_irq_w_maskbit,
+	.end		= end_msi_irq_w_maskbit,
+	.set_affinity	= set_msi_irq_affinity
+};
+
+/*
+ * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI Capability Structure with
+ * Mask-and-Pending Bits.
+ */
+static struct hw_interrupt_type msi_irq_w_maskbit_type = {
+	.typename	= "PCI-MSI",
+	.startup	= startup_msi_irq_w_maskbit,
+	.shutdown	= shutdown_msi_irq_w_maskbit,
+	.enable		= enable_msi_irq_w_maskbit,
+	.disable	= disable_msi_irq_w_maskbit,
+	.ack		= ack_msi_irq_w_maskbit,
+	.end		= end_msi_irq_w_maskbit,
+	.set_affinity	= set_msi_irq_affinity
+};
+
+/*
+ * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI Capability Structure without
+ * Mask-and-Pending Bits.
+ */
+static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
+	.typename	= "PCI-MSI",
+	.startup	= startup_msi_irq_wo_maskbit,
+	.shutdown	= shutdown_msi_irq_wo_maskbit,
+	.enable		= enable_msi_irq_wo_maskbit,
+	.disable	= disable_msi_irq_wo_maskbit,
+	.ack		= ack_msi_irq_wo_maskbit,
+	.end		= end_msi_irq_wo_maskbit,
+	.set_affinity	= set_msi_irq_affinity
+};
+
+static void msi_data_init(struct msg_data *msi_data,
+			  unsigned int vector)
+{
+	memset(msi_data, 0, sizeof(struct msg_data));
+	msi_data->vector = (u8)vector;
+	msi_data->delivery_mode = MSI_DELIVERY_MODE;
+	msi_data->level = MSI_LEVEL_MODE;
+	msi_data->trigger = MSI_TRIGGER_MODE;
+}
+
+static void msi_address_init(struct msg_address *msi_address)
+{
+	unsigned int	dest_id;
+
+	memset(msi_address, 0, sizeof(struct msg_address));
+	msi_address->hi_address = (u32)0;
+	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
+	msi_address->lo_address.u.dest_mode = MSI_DEST_MODE;
+	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
+	msi_address->lo_address.u.dest_id = dest_id;
+	msi_address->lo_address.value |= (MSI_TARGET_CPU << MSI_TARGET_CPU_SHIFT);
+}
+
+static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
+static int assign_msi_vector(void)
+{
+	static int new_vector_avail = 1;
+	int vector;
+	unsigned long flags;
+
+	/*
+	 * msi_lock is provided to ensure that successful allocation of MSI
+	 * vector is assigned unique among drivers.
+	 */
+	spin_lock_irqsave(&msi_lock, flags);
+
+	if (!new_vector_avail) {
+		int free_vector = 0;
+
+		/*
+	 	 * vector_irq[] = -1 indicates that this specific vector is:
+	 	 * - assigned for MSI (since MSI have no associated IRQ) or
+	 	 * - assigned for legacy if less than 16, or
+	 	 * - having no corresponding 1:1 vector-to-IOxAPIC IRQ mapping
+	 	 * vector_irq[] = 0 indicates that this vector, previously
+		 * assigned for MSI, is freed by hotplug removed operations.
+		 * This vector will be reused for any subsequent hotplug added
+		 * operations.
+	 	 * vector_irq[] > 0 indicates that this vector is assigned for
+		 * IOxAPIC IRQs. This vector and its value provides a 1-to-1
+		 * vector-to-IOxAPIC IRQ mapping.
+	 	 */
+		for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
+			if (vector_irq[vector] != 0)
+				continue;
+			free_vector = vector;
+			if (!msi_desc[vector])
+			      	break;
+			else
+				continue;
+		}
+		if (!free_vector) {
+			spin_unlock_irqrestore(&msi_lock, flags);
+			return -EBUSY;
+		}
+		vector_irq[free_vector] = -1;
+		nr_released_vectors--;
+		spin_unlock_irqrestore(&msi_lock, flags);
+		if (msi_desc[free_vector] != NULL) {
+			struct pci_dev *dev;
+			int tail;
+
+			/* free all linked vectors before re-assign */
+			do {
+				spin_lock_irqsave(&msi_lock, flags);
+				dev = msi_desc[free_vector]->dev;
+				tail = msi_desc[free_vector]->link.tail;
+				spin_unlock_irqrestore(&msi_lock, flags);
+				msi_free_vector(dev, tail, 1);
+			} while (free_vector != tail);
+		}
+
+		return free_vector;
+	}
+	vector = assign_irq_vector(AUTO_ASSIGN);
+	last_alloc_vector = vector;
+	if (vector  == LAST_DEVICE_VECTOR)
+		new_vector_avail = 0;
+
+	spin_unlock_irqrestore(&msi_lock, flags);
+	return vector;
+}
+
+static int get_new_vector(void)
+{
+	int vector;
+
+	if ((vector = assign_msi_vector()) > 0)
+		set_intr_gate(vector, interrupt[vector]);
+
+	return vector;
+}
+
+static int msi_init(void)
+{
+	static int status = -ENOMEM;
+
+	if (!status)
+		return status;
+
+	if (pci_msi_quirk) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
+	if ((status = msi_cache_init()) < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING "PCI: MSI cache init failed\n");
+		return status;
+	}
+	last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
+	if (last_alloc_vector < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n");
+		status = -EBUSY;
+		return status;
+	}
+	vector_irq[last_alloc_vector] = 0;
+	nr_released_vectors++;
+
+	return status;
+}
+
+static int get_msi_vector(struct pci_dev *dev)
+{
+	return get_new_vector();
+}
+
+static struct msi_desc* alloc_msi_entry(void)
+{
+	struct msi_desc *entry;
+
+	entry = (struct msi_desc*) kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
+	if (!entry)
+		return NULL;
+
+	memset(entry, 0, sizeof(struct msi_desc));
+	entry->link.tail = entry->link.head = 0;	/* single message */
+	entry->dev = NULL;
+
+	return entry;
+}
+
+static void attach_msi_entry(struct msi_desc *entry, int vector)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&msi_lock, flags);
+	msi_desc[vector] = entry;
+	spin_unlock_irqrestore(&msi_lock, flags);
+}
+
+static void irq_handler_init(int cap_id, int pos, int mask)
+{
+	spin_lock(&irq_desc[pos].lock);
+	if (cap_id == PCI_CAP_ID_MSIX)
+		irq_desc[pos].handler = &msix_irq_type;
+	else {
+		if (!mask)
+			irq_desc[pos].handler = &msi_irq_wo_maskbit_type;
+		else
+			irq_desc[pos].handler = &msi_irq_w_maskbit_type;
+	}
+	spin_unlock(&irq_desc[pos].lock);
+}
+
+static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
+{
+	u16 control;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (type == PCI_CAP_ID_MSI) {
+		/* Set enabled bits to single MSI & enable MSI_enable bit */
+		msi_enable(control, 1);
+		pci_write_config_word(dev, msi_control_reg(pos), control);
+	} else {
+		msix_enable(control);
+		pci_write_config_word(dev, msi_control_reg(pos), control);
+	}
+    	if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
+		/* PCI Express Endpoint device detected */
+		u16 cmd;
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+}
+
+static void disable_msi_mode(struct pci_dev *dev, int pos, int type)
+{
+	u16 control;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (type == PCI_CAP_ID_MSI) {
+		/* Set enabled bits to single MSI & enable MSI_enable bit */
+		msi_disable(control);
+		pci_write_config_word(dev, msi_control_reg(pos), control);
+	} else {
+		msix_disable(control);
+		pci_write_config_word(dev, msi_control_reg(pos), control);
+	}
+    	if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
+		/* PCI Express Endpoint device detected */
+		u16 cmd;
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		cmd &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+}
+
+static int msi_lookup_vector(struct pci_dev *dev, int type)
+{
+	int vector;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msi_lock, flags);
+	for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
+		if (!msi_desc[vector] || msi_desc[vector]->dev != dev ||
+			msi_desc[vector]->msi_attrib.type != type ||
+			msi_desc[vector]->msi_attrib.default_vector != dev->irq)
+			continue;
+		spin_unlock_irqrestore(&msi_lock, flags);
+		/* This pre-assigned MSI vector for this device
+		   already exits. Override dev->irq with this vector */
+		dev->irq = vector;
+		return 0;
+	}
+	spin_unlock_irqrestore(&msi_lock, flags);
+
+	return -EACCES;
+}
+
+void pci_scan_msi_device(struct pci_dev *dev)
+{
+	if (!dev)
+		return;
+
+   	if (pci_find_capability(dev, PCI_CAP_ID_MSIX) > 0)
+		nr_msix_devices++;
+	else if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0)
+		nr_reserved_vectors++;
+}
+
+/**
+ * msi_capability_init - configure device's MSI capability structure
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * Setup the MSI capability structure of device funtion with a single
+ * MSI vector, regardless of device function is capable of handling
+ * multiple messages. A return of zero indicates the successful setup
+ * of an entry zero with the new MSI vector or non-zero for otherwise.
+ **/
+static int msi_capability_init(struct pci_dev *dev)
+{
+	struct msi_desc *entry;
+	struct msg_address address;
+	struct msg_data data;
+	int pos, vector;
+	u16 control;
+
+   	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	/* MSI Entry Initialization */
+	if (!(entry = alloc_msi_entry()))
+		return -ENOMEM;
+
+	if ((vector = get_msi_vector(dev)) < 0) {
+		kmem_cache_free(msi_cachep, entry);
+		return -EBUSY;
+	}
+	entry->link.head = vector;
+	entry->link.tail = vector;
+	entry->msi_attrib.type = PCI_CAP_ID_MSI;
+	entry->msi_attrib.state = 0;			/* Mark it not active */
+	entry->msi_attrib.entry_nr = 0;
+	entry->msi_attrib.maskbit = is_mask_bit_support(control);
+	entry->msi_attrib.default_vector = dev->irq;	/* Save IOAPIC IRQ */
+	dev->irq = vector;
+	entry->dev = dev;
+	if (is_mask_bit_support(control)) {
+		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
+				is_64bit_address(control));
+	}
+	/* Replace with MSI handler */
+	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
+	/* Configure MSI capability structure */
+	msi_address_init(&address);
+	msi_data_init(&data, vector);
+	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
+				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
+	pci_write_config_dword(dev, msi_lower_address_reg(pos),
+			address.lo_address.value);
+	if (is_64bit_address(control)) {
+		pci_write_config_dword(dev,
+			msi_upper_address_reg(pos), address.hi_address);
+		pci_write_config_word(dev,
+			msi_data_reg(pos, 1), *((u32*)&data));
+	} else
+		pci_write_config_word(dev,
+			msi_data_reg(pos, 0), *((u32*)&data));
+	if (entry->msi_attrib.maskbit) {
+		unsigned int maskbits, temp;
+		/* All MSIs are unmasked by default, Mask them all */
+		pci_read_config_dword(dev,
+			msi_mask_bits_reg(pos, is_64bit_address(control)),
+			&maskbits);
+		temp = (1 << multi_msi_capable(control));
+		temp = ((temp - 1) & ~temp);
+		maskbits |= temp;
+		pci_write_config_dword(dev,
+			msi_mask_bits_reg(pos, is_64bit_address(control)),
+			maskbits);
+	}
+	attach_msi_entry(entry, vector);
+	/* Set MSI enabled bits	 */
+	enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+
+	return 0;
+}
+
+/**
+ * msix_capability_init - configure device's MSI-X capability
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+ *
+ * Setup the MSI-X capability structure of device funtion with a
+ * single MSI-X vector. A return of zero indicates the successful setup of
+ * requested MSI-X entries with allocated vectors or non-zero for otherwise.
+ **/
+static int msix_capability_init(struct pci_dev *dev,
+				struct msix_entry *entries, int nvec)
+{
+	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
+	struct msg_address address;
+	struct msg_data data;
+	int vector, pos, i, j, nr_entries, temp = 0;
+	u32 phys_addr, table_offset;
+ 	u16 control;
+	u8 bir;
+	void __iomem *base;
+
+   	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+	/* Request & Map MSI-X table region */
+ 	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	nr_entries = multi_msix_capable(control);
+ 	pci_read_config_dword(dev, msix_table_offset_reg(pos),
+ 		&table_offset);
+	bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
+	phys_addr = pci_resource_start (dev, bir);
+	phys_addr += (u32)(table_offset & ~PCI_MSIX_FLAGS_BIRMASK);
+	base = ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
+	if (base == NULL)
+		return -ENOMEM;
+
+	/* MSI-X Table Initialization */
+	for (i = 0; i < nvec; i++) {
+		entry = alloc_msi_entry();
+		if (!entry)
+			break;
+		if ((vector = get_msi_vector(dev)) < 0)
+			break;
+
+ 		j = entries[i].entry;
+ 		entries[i].vector = vector;
+		entry->msi_attrib.type = PCI_CAP_ID_MSIX;
+ 		entry->msi_attrib.state = 0;		/* Mark it not active */
+		entry->msi_attrib.entry_nr = j;
+		entry->msi_attrib.maskbit = 1;
+		entry->msi_attrib.default_vector = dev->irq;
+		entry->dev = dev;
+		entry->mask_base = base;
+		if (!head) {
+			entry->link.head = vector;
+			entry->link.tail = vector;
+			head = entry;
+		} else {
+			entry->link.head = temp;
+			entry->link.tail = tail->link.tail;
+			tail->link.tail = vector;
+			head->link.head = vector;
+		}
+		temp = vector;
+		tail = entry;
+		/* Replace with MSI-X handler */
+		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
+		/* Configure MSI-X capability structure */
+		msi_address_init(&address);
+		msi_data_init(&data, vector);
+		entry->msi_attrib.current_cpu =
+			((address.lo_address.u.dest_id >>
+			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
+		writel(address.lo_address.value,
+			base + j * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+		writel(address.hi_address,
+			base + j * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+		writel(*(u32*)&data,
+			base + j * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_DATA_OFFSET);
+		attach_msi_entry(entry, vector);
+	}
+	if (i != nvec) {
+		i--;
+		for (; i >= 0; i--) {
+			vector = (entries + i)->vector;
+			msi_free_vector(dev, vector, 0);
+			(entries + i)->vector = 0;
+		}
+		return -EBUSY;
+	}
+	/* Set MSI-X enabled bits */
+	enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+
+	return 0;
+}
+
+/**
+ * pci_enable_msi - configure device's MSI capability structure
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * Setup the MSI capability structure of device function with
+ * a single MSI vector upon its software driver call to request for
+ * MSI mode enabled on its hardware device function. A return of zero
+ * indicates the successful setup of an entry zero with the new MSI
+ * vector or non-zero for otherwise.
+ **/
+int pci_enable_msi(struct pci_dev* dev)
+{
+	int pos, temp, status = -EINVAL;
+	u16 control;
+
+	if (!pci_msi_enable || !dev)
+ 		return status;
+
+	temp = dev->irq;
+
+	if ((status = msi_init()) < 0)
+		return status;
+
+   	if (!(pos = pci_find_capability(dev, PCI_CAP_ID_MSI)))
+		return -EINVAL;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (control & PCI_MSI_FLAGS_ENABLE)
+		return 0;			/* Already in MSI mode */
+
+	if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
+		/* Lookup Sucess */
+		unsigned long flags;
+
+		spin_lock_irqsave(&msi_lock, flags);
+		if (!vector_irq[dev->irq]) {
+			msi_desc[dev->irq]->msi_attrib.state = 0;
+			vector_irq[dev->irq] = -1;
+			nr_released_vectors--;
+			spin_unlock_irqrestore(&msi_lock, flags);
+			enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+			return 0;
+		}
+		spin_unlock_irqrestore(&msi_lock, flags);
+		dev->irq = temp;
+	}
+	/* Check whether driver already requested for MSI-X vectors */
+   	if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)) > 0 &&
+		!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+			printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
+			       "Device already has MSI-X vectors assigned\n",
+			       pci_name(dev));
+			dev->irq = temp;
+			return -EINVAL;
+	}
+	status = msi_capability_init(dev);
+	if (!status) {
+   		if (!pos)
+			nr_reserved_vectors--;	/* Only MSI capable */
+		else if (nr_msix_devices > 0)
+			nr_msix_devices--;	/* Both MSI and MSI-X capable,
+						   but choose enabling MSI */
+	}
+
+	return status;
+}
+
+void pci_disable_msi(struct pci_dev* dev)
+{
+	struct msi_desc *entry;
+	int pos, default_vector;
+	u16 control;
+	unsigned long flags;
+
+   	if (!dev || !(pos = pci_find_capability(dev, PCI_CAP_ID_MSI)))
+		return;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (!(control & PCI_MSI_FLAGS_ENABLE))
+		return;
+
+	spin_lock_irqsave(&msi_lock, flags);
+	entry = msi_desc[dev->irq];
+	if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
+		spin_unlock_irqrestore(&msi_lock, flags);
+		return;
+	}
+	if (entry->msi_attrib.state) {
+		spin_unlock_irqrestore(&msi_lock, flags);
+		printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
+		       "free_irq() on MSI vector %d\n",
+		       pci_name(dev), dev->irq);
+		BUG_ON(entry->msi_attrib.state > 0);
+	} else {
+		vector_irq[dev->irq] = 0; /* free it */
+		nr_released_vectors++;
+		default_vector = entry->msi_attrib.default_vector;
+		spin_unlock_irqrestore(&msi_lock, flags);
+		/* Restore dev->irq to its default pin-assertion vector */
+		dev->irq = default_vector;
+		disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
+					PCI_CAP_ID_MSI);
+	}
+}
+
+static void release_msi(unsigned int vector)
+{
+	struct msi_desc *entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msi_lock, flags);
+	entry = msi_desc[vector];
+	if (entry && entry->dev)
+		entry->msi_attrib.state = 0;	/* Mark it not active */
+	spin_unlock_irqrestore(&msi_lock, flags);
+}
+
+static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
+{
+	struct msi_desc *entry;
+	int head, entry_nr, type;
+	void __iomem *base;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msi_lock, flags);
+	entry = msi_desc[vector];
+	if (!entry || entry->dev != dev) {
+		spin_unlock_irqrestore(&msi_lock, flags);
+		return -EINVAL;
+	}
+	type = entry->msi_attrib.type;
+	entry_nr = entry->msi_attrib.entry_nr;
+	head = entry->link.head;
+	base = entry->mask_base;
+	msi_desc[entry->link.head]->link.tail = entry->link.tail;
+	msi_desc[entry->link.tail]->link.head = entry->link.head;
+	entry->dev = NULL;
+	if (!reassign) {
+		vector_irq[vector] = 0;
+		nr_released_vectors++;
+	}
+	msi_desc[vector] = NULL;
+	spin_unlock_irqrestore(&msi_lock, flags);
+
+	kmem_cache_free(msi_cachep, entry);
+
+	if (type == PCI_CAP_ID_MSIX) {
+		if (!reassign)
+			writel(1, base +
+				entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+
+		if (head == vector) {
+			/*
+			 * Detect last MSI-X vector to be released.
+			 * Release the MSI-X memory-mapped table.
+			 */
+			int pos, nr_entries;
+			u32 phys_addr, table_offset;
+			u16 control;
+			u8 bir;
+
+   			pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+			pci_read_config_word(dev, msi_control_reg(pos),
+				&control);
+			nr_entries = multi_msix_capable(control);
+			pci_read_config_dword(dev, msix_table_offset_reg(pos),
+				&table_offset);
+			bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
+			phys_addr = pci_resource_start (dev, bir);
+			phys_addr += (u32)(table_offset &
+				~PCI_MSIX_FLAGS_BIRMASK);
+			iounmap(base);
+		}
+	}
+
+	return 0;
+}
+
+static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
+{
+	int vector = head, tail = 0;
+	int i, j = 0, nr_entries = 0;
+	void __iomem *base;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msi_lock, flags);
+	while (head != tail) {
+		nr_entries++;
+		tail = msi_desc[vector]->link.tail;
+		if (entries[0].entry == msi_desc[vector]->msi_attrib.entry_nr)
+			j = vector;
+		vector = tail;
+	}
+	if (*nvec > nr_entries) {
+		spin_unlock_irqrestore(&msi_lock, flags);
+		*nvec = nr_entries;
+		return -EINVAL;
+	}
+	vector = ((j > 0) ? j : head);
+	for (i = 0; i < *nvec; i++) {
+		j = msi_desc[vector]->msi_attrib.entry_nr;
+		msi_desc[vector]->msi_attrib.state = 0;	/* Mark it not active */
+		vector_irq[vector] = -1;		/* Mark it busy */
+		nr_released_vectors--;
+		entries[i].vector = vector;
+		if (j != (entries + i)->entry) {
+			base = msi_desc[vector]->mask_base;
+			msi_desc[vector]->msi_attrib.entry_nr =
+				(entries + i)->entry;
+			writel( readl(base + j * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET), base +
+				(entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+			writel(	readl(base + j * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET), base +
+				(entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+			writel( (readl(base + j * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_DATA_OFFSET) & 0xff00) | vector,
+				base + (entries+i)->entry*PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_DATA_OFFSET);
+		}
+		vector = msi_desc[vector]->link.tail;
+	}
+	spin_unlock_irqrestore(&msi_lock, flags);
+
+	return 0;
+}
+
+/**
+ * pci_enable_msix - configure device's MSI-X capability structure
+ * @dev: pointer to the pci_dev data structure of MSI-X device function
+ * @data: pointer to an array of MSI-X entries
+ * @nvec: number of MSI-X vectors requested for allocation by device driver
+ *
+ * Setup the MSI-X capability structure of device function with the number
+ * of requested vectors upon its software driver call to request for
+ * MSI-X mode enabled on its hardware device function. A return of zero
+ * indicates the successful configuration of MSI-X capability structure
+ * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
+ * Or a return of > 0 indicates that driver request is exceeding the number
+ * of vectors available. Driver should use the returned value to re-send
+ * its request.
+ **/
+int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
+{
+	int status, pos, nr_entries, free_vectors;
+	int i, j, temp;
+	u16 control;
+	unsigned long flags;
+
+	if (!pci_msi_enable || !dev || !entries)
+ 		return -EINVAL;
+
+	if ((status = msi_init()) < 0)
+		return status;
+
+   	if (!(pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)))
+ 		return -EINVAL;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (control & PCI_MSIX_FLAGS_ENABLE)
+		return -EINVAL;			/* Already in MSI-X mode */
+
+	nr_entries = multi_msix_capable(control);
+	if (nvec > nr_entries)
+		return -EINVAL;
+
+	/* Check for any invalid entries */
+	for (i = 0; i < nvec; i++) {
+		if (entries[i].entry >= nr_entries)
+			return -EINVAL;		/* invalid entry */
+		for (j = i + 1; j < nvec; j++) {
+			if (entries[i].entry == entries[j].entry)
+				return -EINVAL;	/* duplicate entry */
+		}
+	}
+	temp = dev->irq;
+	if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+		/* Lookup Sucess */
+		nr_entries = nvec;
+		/* Reroute MSI-X table */
+		if (reroute_msix_table(dev->irq, entries, &nr_entries)) {
+			/* #requested > #previous-assigned */
+			dev->irq = temp;
+			return nr_entries;
+		}
+		dev->irq = temp;
+		enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+		return 0;
+	}
+	/* Check whether driver already requested for MSI vector */
+   	if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
+		!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
+		printk(KERN_INFO "PCI: %s: Can't enable MSI-X.  "
+		       "Device already has an MSI vector assigned\n",
+		       pci_name(dev));
+		dev->irq = temp;
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&msi_lock, flags);
+	/*
+	 * msi_lock is provided to ensure that enough vectors resources are
+	 * available before granting.
+	 */
+	free_vectors = pci_vector_resources(last_alloc_vector,
+				nr_released_vectors);
+	/* Ensure that each MSI/MSI-X device has one vector reserved by
+	   default to avoid any MSI-X driver to take all available
+ 	   resources */
+	free_vectors -= nr_reserved_vectors;
+	/* Find the average of free vectors among MSI-X devices */
+	if (nr_msix_devices > 0)
+		free_vectors /= nr_msix_devices;
+	spin_unlock_irqrestore(&msi_lock, flags);
+
+	if (nvec > free_vectors) {
+		if (free_vectors > 0)
+			return free_vectors;
+		else
+			return -EBUSY;
+	}
+
+	status = msix_capability_init(dev, entries, nvec);
+	if (!status && nr_msix_devices > 0)
+		nr_msix_devices--;
+
+	return status;
+}
+
+void pci_disable_msix(struct pci_dev* dev)
+{
+	int pos, temp;
+	u16 control;
+
+   	if (!dev || !(pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)))
+		return;
+
+	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	if (!(control & PCI_MSIX_FLAGS_ENABLE))
+		return;
+
+	temp = dev->irq;
+	if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+		int state, vector, head, tail = 0, warning = 0;
+		unsigned long flags;
+
+		vector = head = dev->irq;
+		spin_lock_irqsave(&msi_lock, flags);
+		while (head != tail) {
+			state = msi_desc[vector]->msi_attrib.state;
+			if (state)
+				warning = 1;
+			else {
+				vector_irq[vector] = 0; /* free it */
+				nr_released_vectors++;
+			}
+			tail = msi_desc[vector]->link.tail;
+			vector = tail;
+		}
+		spin_unlock_irqrestore(&msi_lock, flags);
+		if (warning) {
+			dev->irq = temp;
+			printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
+			       "free_irq() on all MSI-X vectors\n",
+			       pci_name(dev));
+			BUG_ON(warning > 0);
+		} else {
+			dev->irq = temp;
+			disable_msi_mode(dev,
+				pci_find_capability(dev, PCI_CAP_ID_MSIX),
+				PCI_CAP_ID_MSIX);
+
+		}
+	}
+}
+
+/**
+ * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
+ * @dev: pointer to the pci_dev data structure of MSI(X) device function
+ *
+ * Being called during hotplug remove, from which the device funciton
+ * is hot-removed. All previous assigned MSI/MSI-X vectors, if
+ * allocated for this device function, are reclaimed to unused state,
+ * which may be used later on.
+ **/
+void msi_remove_pci_irq_vectors(struct pci_dev* dev)
+{
+	int state, pos, temp;
+	unsigned long flags;
+
+	if (!pci_msi_enable || !dev)
+ 		return;
+
+	temp = dev->irq;		/* Save IOAPIC IRQ */
+   	if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) > 0 &&
+		!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
+		spin_lock_irqsave(&msi_lock, flags);
+		state = msi_desc[dev->irq]->msi_attrib.state;
+		spin_unlock_irqrestore(&msi_lock, flags);
+		if (state) {
+			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
+			       "called without free_irq() on MSI vector %d\n",
+			       pci_name(dev), dev->irq);
+			BUG_ON(state > 0);
+		} else /* Release MSI vector assigned to this device */
+			msi_free_vector(dev, dev->irq, 0);
+		dev->irq = temp;		/* Restore IOAPIC IRQ */
+	}
+   	if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSIX)) > 0 &&
+		!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+		int vector, head, tail = 0, warning = 0;
+		void __iomem *base = NULL;
+
+		vector = head = dev->irq;
+		while (head != tail) {
+			spin_lock_irqsave(&msi_lock, flags);
+			state = msi_desc[vector]->msi_attrib.state;
+			tail = msi_desc[vector]->link.tail;
+			base = msi_desc[vector]->mask_base;
+			spin_unlock_irqrestore(&msi_lock, flags);
+			if (state)
+				warning = 1;
+			else if (vector != head) /* Release MSI-X vector */
+				msi_free_vector(dev, vector, 0);
+			vector = tail;
+		}
+		msi_free_vector(dev, vector, 0);
+		if (warning) {
+			/* Force to release the MSI-X memory-mapped table */
+			u32 phys_addr, table_offset;
+			u16 control;
+			u8 bir;
+
+			pci_read_config_word(dev, msi_control_reg(pos),
+				&control);
+			pci_read_config_dword(dev, msix_table_offset_reg(pos),
+				&table_offset);
+			bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
+			phys_addr = pci_resource_start (dev, bir);
+			phys_addr += (u32)(table_offset &
+				~PCI_MSIX_FLAGS_BIRMASK);
+			iounmap(base);
+			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
+			       "called without free_irq() on all MSI-X vectors\n",
+			       pci_name(dev));
+			BUG_ON(warning > 0);
+		}
+		dev->irq = temp;		/* Restore IOAPIC IRQ */
+	}
+}
+
+EXPORT_SYMBOL(pci_enable_msi);
+EXPORT_SYMBOL(pci_disable_msi);
+EXPORT_SYMBOL(pci_enable_msix);
+EXPORT_SYMBOL(pci_disable_msix);
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
new file mode 100644
index 0000000..bef21ae
--- /dev/null
+++ b/drivers/pci/msi.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2003-2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#ifndef MSI_H
+#define MSI_H
+
+#include <asm/msi.h>
+
+/*
+ * Assume the maximum number of hot plug slots supported by the system is about
+ * ten. The worstcase is that each of these slots is hot-added with a device,
+ * which has two MSI/MSI-X capable functions. To avoid any MSI-X driver, which
+ * attempts to request all available vectors, NR_HP_RESERVED_VECTORS is defined
+ * as below to ensure at least one message is assigned to each detected MSI/
+ * MSI-X device function.
+ */
+#define NR_HP_RESERVED_VECTORS 	20
+
+extern int vector_irq[NR_VECTORS];
+extern cpumask_t pending_irq_balance_cpumask[NR_IRQS];
+extern void (*interrupt[NR_IRQS])(void);
+extern int pci_vector_resources(int last, int nr_released);
+
+#ifdef CONFIG_SMP
+#define set_msi_irq_affinity	set_msi_affinity
+#else
+#define set_msi_irq_affinity	NULL
+#endif
+
+#ifndef CONFIG_IRQBALANCE
+static inline void move_msi(int vector) {}
+#endif
+
+/*
+ * MSI-X Address Register
+ */
+#define PCI_MSIX_FLAGS_QSIZE		0x7FF
+#define PCI_MSIX_FLAGS_ENABLE		(1 << 15)
+#define PCI_MSIX_FLAGS_BIRMASK		(7 << 0)
+#define PCI_MSIX_FLAGS_BITMASK		(1 << 0)
+
+#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET	0
+#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET	4
+#define PCI_MSIX_ENTRY_DATA_OFFSET		8
+#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET	12
+#define PCI_MSIX_ENTRY_SIZE			16
+
+#define msi_control_reg(base)		(base + PCI_MSI_FLAGS)
+#define msi_lower_address_reg(base)	(base + PCI_MSI_ADDRESS_LO)
+#define msi_upper_address_reg(base)	(base + PCI_MSI_ADDRESS_HI)
+#define msi_data_reg(base, is64bit)	\
+	( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 )
+#define msi_mask_bits_reg(base, is64bit) \
+	( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4)
+#define msi_disable(control)		control &= ~PCI_MSI_FLAGS_ENABLE
+#define multi_msi_capable(control) \
+	(1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
+#define multi_msi_enable(control, num) \
+	control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
+#define is_64bit_address(control)	(control & PCI_MSI_FLAGS_64BIT)
+#define is_mask_bit_support(control)	(control & PCI_MSI_FLAGS_MASKBIT)
+#define msi_enable(control, num) multi_msi_enable(control, num); \
+	control |= PCI_MSI_FLAGS_ENABLE
+
+#define msix_control_reg		msi_control_reg
+#define msix_table_offset_reg(base)	(base + 0x04)
+#define msix_pba_offset_reg(base)	(base + 0x08)
+#define msix_enable(control)	 	control |= PCI_MSIX_FLAGS_ENABLE
+#define msix_disable(control)	 	control &= ~PCI_MSIX_FLAGS_ENABLE
+#define msix_table_size(control) 	((control & PCI_MSIX_FLAGS_QSIZE)+1)
+#define multi_msix_capable		msix_table_size
+#define msix_unmask(address)	 	(address & ~PCI_MSIX_FLAGS_BITMASK)
+#define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
+#define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
+
+/*
+ * MSI Defined Data Structures
+ */
+#define MSI_ADDRESS_HEADER		0xfee
+#define MSI_ADDRESS_HEADER_SHIFT	12
+#define MSI_ADDRESS_HEADER_MASK		0xfff000
+#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
+#define MSI_TARGET_CPU_MASK		0xff
+#define MSI_DELIVERY_MODE		0
+#define MSI_LEVEL_MODE			1	/* Edge always assert */
+#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
+#define MSI_PHYSICAL_MODE		0
+#define MSI_LOGICAL_MODE		1
+#define MSI_REDIRECTION_HINT_MODE	0
+
+struct msg_data {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u32	vector		:  8;
+	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
+	__u32	reserved_1	:  3;
+	__u32	level		:  1;	/* 0: deassert | 1: assert */
+	__u32	trigger		:  1;	/* 0: edge | 1: level */
+	__u32	reserved_2	: 16;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	__u32	reserved_2	: 16;
+	__u32	trigger		:  1;	/* 0: edge | 1: level */
+	__u32	level		:  1;	/* 0: deassert | 1: assert */
+	__u32	reserved_1	:  3;
+	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
+	__u32	vector		:  8;
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+} __attribute__ ((packed));
+
+struct msg_address {
+	union {
+		struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+			__u32	reserved_1	:  2;
+			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
+			__u32	redirection_hint:  1;  	/*0: dedicated CPU
+							  1: lowest priority */
+			__u32	reserved_2	:  4;
+ 			__u32	dest_id		: 24;	/* Destination ID */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ 			__u32	dest_id		: 24;	/* Destination ID */
+			__u32	reserved_2	:  4;
+			__u32	redirection_hint:  1;  	/*0: dedicated CPU
+							  1: lowest priority */
+			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
+			__u32	reserved_1	:  2;
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+      		}u;
+       		__u32  value;
+	}lo_address;
+	__u32 	hi_address;
+} __attribute__ ((packed));
+
+struct msi_desc {
+	struct {
+		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
+		__u8	maskbit	: 1; 	/* mask-pending bit supported ?   */
+		__u8	state	: 1; 	/* {0: free, 1: busy}		  */
+		__u8	reserved: 1; 	/* reserved			  */
+		__u8	entry_nr;    	/* specific enabled entry 	  */
+		__u8	default_vector; /* default pre-assigned vector    */
+		__u8	current_cpu; 	/* current destination cpu	  */
+	}msi_attrib;
+
+	struct {
+		__u16	head;
+		__u16	tail;
+	}link;
+
+	void __iomem *mask_base;
+	struct pci_dev *dev;
+};
+
+#endif /* MSI_H */
diff --git a/drivers/pci/names.c b/drivers/pci/names.c
new file mode 100644
index 0000000..ad224aa
--- /dev/null
+++ b/drivers/pci/names.c
@@ -0,0 +1,137 @@
+/*
+ *	PCI Class and Device Name Tables
+ *
+ *	Copyright 1993--1999 Drew Eckhardt, Frederic Potter,
+ *	David Mosberger-Tang, Martin Mares
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_PCI_NAMES
+
+struct pci_device_info {
+	unsigned short device;
+	unsigned short seen;
+	const char *name;
+};
+
+struct pci_vendor_info {
+	unsigned short vendor;
+	unsigned short nr;
+	const char *name;
+	struct pci_device_info *devices;
+};
+
+/*
+ * This is ridiculous, but we want the strings in
+ * the .init section so that they don't take up
+ * real memory.. Parse the same file multiple times
+ * to get all the info.
+ */
+#define VENDOR( vendor, name )		static char __vendorstr_##vendor[] __devinitdata = name;
+#define ENDVENDOR()
+#define DEVICE( vendor, device, name ) 	static char __devicestr_##vendor##device[] __devinitdata = name;
+#include "devlist.h"
+
+
+#define VENDOR( vendor, name )		static struct pci_device_info __devices_##vendor[] __devinitdata = {
+#define ENDVENDOR()			};
+#define DEVICE( vendor, device, name )	{ 0x##device, 0, __devicestr_##vendor##device },
+#include "devlist.h"
+
+static struct pci_vendor_info __devinitdata pci_vendor_list[] = {
+#define VENDOR( vendor, name )		{ 0x##vendor, sizeof(__devices_##vendor) / sizeof(struct pci_device_info), __vendorstr_##vendor, __devices_##vendor },
+#define ENDVENDOR()
+#define DEVICE( vendor, device, name )
+#include "devlist.h"
+};
+
+#define VENDORS (sizeof(pci_vendor_list)/sizeof(struct pci_vendor_info))
+
+void __devinit pci_name_device(struct pci_dev *dev)
+{
+	const struct pci_vendor_info *vendor_p = pci_vendor_list;
+	int i = VENDORS;
+	char *name = dev->pretty_name;
+
+	do {
+		if (vendor_p->vendor == dev->vendor)
+			goto match_vendor;
+		vendor_p++;
+	} while (--i);
+
+	/* Couldn't find either the vendor nor the device */
+	sprintf(name, "PCI device %04x:%04x", dev->vendor, dev->device);
+	return;
+
+	match_vendor: {
+		struct pci_device_info *device_p = vendor_p->devices;
+		int i = vendor_p->nr;
+
+		while (i > 0) {
+			if (device_p->device == dev->device)
+				goto match_device;
+			device_p++;
+			i--;
+		}
+
+		/* Ok, found the vendor, but unknown device */
+		sprintf(name, "PCI device %04x:%04x (%." PCI_NAME_HALF "s)",
+				dev->vendor, dev->device, vendor_p->name);
+		return;
+
+		/* Full match */
+		match_device: {
+			char *n = name + sprintf(name, "%s %s",
+					vendor_p->name, device_p->name);
+			int nr = device_p->seen + 1;
+			device_p->seen = nr;
+			if (nr > 1)
+				sprintf(n, " (#%d)", nr);
+		}
+	}
+}
+
+/*
+ *  Class names. Not in .init section as they are needed in runtime.
+ */
+
+static u16 pci_class_numbers[] = {
+#define CLASS(x,y) 0x##x,
+#include "classlist.h"
+};
+
+static char *pci_class_names[] = {
+#define CLASS(x,y) y,
+#include "classlist.h"
+};
+
+char *
+pci_class_name(u32 class)
+{
+	int i;
+
+	for(i=0; i<sizeof(pci_class_numbers)/sizeof(pci_class_numbers[0]); i++)
+		if (pci_class_numbers[i] == class)
+			return pci_class_names[i];
+	return NULL;
+}
+
+#else
+
+void __devinit pci_name_device(struct pci_dev *dev)
+{
+}
+
+char *
+pci_class_name(u32 class)
+{
+	return NULL;
+}
+
+#endif /* CONFIG_PCI_NAMES */
+
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
new file mode 100644
index 0000000..968eb32
--- /dev/null
+++ b/drivers/pci/pci-acpi.c
@@ -0,0 +1,209 @@
+/*
+ * File:	pci-acpi.c
+ * Purpose:	Provide PCI supports in ACPI
+ *
+ * Copyright (C) 2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acresrc.h>
+#include <acpi/acpi_bus.h>
+
+#include <linux/pci-acpi.h>
+
+static u32 ctrlset_buf[3] = {0, 0, 0};
+static u32 global_ctrlsets = 0;
+u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
+
+static acpi_status  
+acpi_query_osc (
+	acpi_handle	handle,
+	u32		level,
+	void		*context,
+	void		**retval )
+{
+	acpi_status		status;
+	struct acpi_object_list	input;
+	union acpi_object 	in_params[4];
+	struct acpi_buffer	output;
+	union acpi_object 	out_obj;	
+	u32			osc_dw0;
+
+	/* Setting up output buffer */
+	output.length = sizeof(out_obj) + 3*sizeof(u32);  
+	output.pointer = &out_obj;
+	
+	/* Setting up input parameters */
+	input.count = 4;
+	input.pointer = in_params;
+	in_params[0].type 		= ACPI_TYPE_BUFFER;
+	in_params[0].buffer.length 	= 16;
+	in_params[0].buffer.pointer	= OSC_UUID;
+	in_params[1].type 		= ACPI_TYPE_INTEGER;
+	in_params[1].integer.value 	= 1;
+	in_params[2].type 		= ACPI_TYPE_INTEGER;
+	in_params[2].integer.value	= 3;
+	in_params[3].type		= ACPI_TYPE_BUFFER;
+	in_params[3].buffer.length 	= 12;
+	in_params[3].buffer.pointer 	= (u8 *)context;
+
+	status = acpi_evaluate_object(handle, "_OSC", &input, &output);
+	if (ACPI_FAILURE (status)) {
+		printk(KERN_DEBUG  
+			"Evaluate _OSC Set fails. Status = 0x%04x\n", status);
+		return status;
+	}
+	if (out_obj.type != ACPI_TYPE_BUFFER) {
+		printk(KERN_DEBUG  
+			"Evaluate _OSC returns wrong type\n");
+		return AE_TYPE;
+	}
+	osc_dw0 = *((u32 *) out_obj.buffer.pointer);
+	if (osc_dw0) {
+		if (osc_dw0 & OSC_REQUEST_ERROR)
+			printk(KERN_DEBUG "_OSC request fails\n"); 
+		if (osc_dw0 & OSC_INVALID_UUID_ERROR)
+			printk(KERN_DEBUG "_OSC invalid UUID\n"); 
+		if (osc_dw0 & OSC_INVALID_REVISION_ERROR)
+			printk(KERN_DEBUG "_OSC invalid revision\n"); 
+		if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
+			/* Update Global Control Set */
+			global_ctrlsets = *((u32 *)(out_obj.buffer.pointer+8));
+			return AE_OK;
+		}
+		return AE_ERROR;
+	}
+
+	/* Update Global Control Set */
+	global_ctrlsets = *((u32 *)(out_obj.buffer.pointer + 8));
+	return AE_OK;
+}
+
+
+static acpi_status  
+acpi_run_osc (
+	acpi_handle	handle,
+	u32		level,
+	void		*context,
+	void		**retval )
+{
+	acpi_status		status;
+	struct acpi_object_list	input;
+	union acpi_object 	in_params[4];
+	struct acpi_buffer	output;
+	union acpi_object 	out_obj;	
+	u32			osc_dw0;
+
+	/* Setting up output buffer */
+	output.length = sizeof(out_obj) + 3*sizeof(u32);  
+	output.pointer = &out_obj;
+	
+	/* Setting up input parameters */
+	input.count = 4;
+	input.pointer = in_params;
+	in_params[0].type 		= ACPI_TYPE_BUFFER;
+	in_params[0].buffer.length 	= 16;
+	in_params[0].buffer.pointer	= OSC_UUID;
+	in_params[1].type 		= ACPI_TYPE_INTEGER;
+	in_params[1].integer.value 	= 1;
+	in_params[2].type 		= ACPI_TYPE_INTEGER;
+	in_params[2].integer.value	= 3;
+	in_params[3].type		= ACPI_TYPE_BUFFER;
+	in_params[3].buffer.length 	= 12;
+	in_params[3].buffer.pointer 	= (u8 *)context;
+
+	status = acpi_evaluate_object(handle, "_OSC", &input, &output);
+	if (ACPI_FAILURE (status)) {
+		printk(KERN_DEBUG  
+			"Evaluate _OSC Set fails. Status = 0x%04x\n", status);
+		return status;
+	}
+	if (out_obj.type != ACPI_TYPE_BUFFER) {
+		printk(KERN_DEBUG  
+			"Evaluate _OSC returns wrong type\n");
+		return AE_TYPE;
+	}
+	osc_dw0 = *((u32 *) out_obj.buffer.pointer);
+	if (osc_dw0) {
+		if (osc_dw0 & OSC_REQUEST_ERROR)
+			printk(KERN_DEBUG "_OSC request fails\n"); 
+		if (osc_dw0 & OSC_INVALID_UUID_ERROR)
+			printk(KERN_DEBUG "_OSC invalid UUID\n"); 
+		if (osc_dw0 & OSC_INVALID_REVISION_ERROR)
+			printk(KERN_DEBUG "_OSC invalid revision\n"); 
+		if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) {
+			printk(KERN_DEBUG "_OSC FW not grant req. control\n");
+			return AE_SUPPORT;
+		}
+		return AE_ERROR;
+	}
+	return AE_OK;
+}
+
+/**
+ * pci_osc_support_set - register OS support to Firmware
+ * @flags: OS support bits
+ *
+ * Update OS support fields and doing a _OSC Query to obtain an update
+ * from Firmware on supported control bits.
+ **/
+acpi_status pci_osc_support_set(u32 flags)
+{
+	u32 temp;
+
+	if (!(flags & OSC_SUPPORT_MASKS)) {
+		return AE_TYPE;
+	}
+	ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS);
+
+	/* do _OSC query for all possible controls */
+	temp = ctrlset_buf[OSC_CONTROL_TYPE];
+	ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
+	ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
+	acpi_get_devices ( PCI_ROOT_HID_STRING,
+			acpi_query_osc,
+			ctrlset_buf,
+			NULL );
+	ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE;
+	ctrlset_buf[OSC_CONTROL_TYPE] = temp;
+	return AE_OK;
+}
+EXPORT_SYMBOL(pci_osc_support_set);
+
+/**
+ * pci_osc_control_set - commit requested control to Firmware
+ * @flags: driver's requested control bits
+ *
+ * Attempt to take control from Firmware on requested control bits.
+ **/
+acpi_status pci_osc_control_set(u32 flags)
+{
+	acpi_status	status;
+	u32		ctrlset;
+
+	ctrlset = (flags & OSC_CONTROL_MASKS);
+	if (!ctrlset) {
+		return AE_TYPE;
+	}
+	if (ctrlset_buf[OSC_SUPPORT_TYPE] && 
+	 	((global_ctrlsets & ctrlset) != ctrlset)) {
+		return AE_SUPPORT;
+	}
+	ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset;
+	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
+				acpi_run_osc,
+				ctrlset_buf,
+				NULL );
+	if (ACPI_FAILURE (status)) {
+		ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset;
+	}
+	
+	return status;
+}
+EXPORT_SYMBOL(pci_osc_control_set);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
new file mode 100644
index 0000000..37b7961
--- /dev/null
+++ b/drivers/pci/pci-driver.c
@@ -0,0 +1,531 @@
+/*
+ * drivers/pci/pci-driver.c
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/pci-dynids.h>
+#include "pci.h"
+
+/*
+ *  Registration of PCI drivers and handling of hot-pluggable devices.
+ */
+
+/*
+ * Dynamic device IDs are disabled for !CONFIG_HOTPLUG
+ */
+
+#ifdef CONFIG_HOTPLUG
+/**
+ * pci_device_probe_dynamic()
+ *
+ * Walk the dynamic ID list looking for a match.
+ * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error.
+ */
+static int
+pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
+{
+	int error = -ENODEV;
+	struct list_head *pos;
+	struct dynid *dynid;
+
+	spin_lock(&drv->dynids.lock);
+	list_for_each(pos, &drv->dynids.list) {
+		dynid = list_entry(pos, struct dynid, node);
+		if (pci_match_one_device(&dynid->id, pci_dev)) {
+			spin_unlock(&drv->dynids.lock);
+			error = drv->probe(pci_dev, &dynid->id);
+			if (error >= 0) {
+				pci_dev->driver = drv;
+				return 0;
+			}
+			return error;
+		}
+	}
+	spin_unlock(&drv->dynids.lock);
+	return error;
+}
+
+/**
+ * store_new_id
+ *
+ * Adds a new dynamic pci device ID to this driver,
+ * and causes the driver to probe for all devices again.
+ */
+static inline ssize_t
+store_new_id(struct device_driver *driver, const char *buf, size_t count)
+{
+	struct dynid *dynid;
+	struct bus_type * bus;
+	struct pci_driver *pdrv = to_pci_driver(driver);
+	__u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID,
+		subdevice=PCI_ANY_ID, class=0, class_mask=0;
+	unsigned long driver_data=0;
+	int fields=0;
+
+	fields = sscanf(buf, "%x %x %x %x %x %x %lux",
+			&vendor, &device, &subvendor, &subdevice,
+			&class, &class_mask, &driver_data);
+	if (fields < 0)
+		return -EINVAL;
+
+	dynid = kmalloc(sizeof(*dynid), GFP_KERNEL);
+	if (!dynid)
+		return -ENOMEM;
+
+	memset(dynid, 0, sizeof(*dynid));
+	INIT_LIST_HEAD(&dynid->node);
+	dynid->id.vendor = vendor;
+	dynid->id.device = device;
+	dynid->id.subvendor = subvendor;
+	dynid->id.subdevice = subdevice;
+	dynid->id.class = class;
+	dynid->id.class_mask = class_mask;
+	dynid->id.driver_data = pdrv->dynids.use_driver_data ?
+		driver_data : 0UL;
+
+	spin_lock(&pdrv->dynids.lock);
+	list_add_tail(&pdrv->dynids.list, &dynid->node);
+	spin_unlock(&pdrv->dynids.lock);
+
+	bus = get_bus(pdrv->driver.bus);
+	if (bus) {
+		if (get_driver(&pdrv->driver)) {
+			down_write(&bus->subsys.rwsem);
+			driver_attach(&pdrv->driver);
+			up_write(&bus->subsys.rwsem);
+			put_driver(&pdrv->driver);
+		}
+		put_bus(bus);
+	}
+
+	return count;
+}
+
+static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+static inline void
+pci_init_dynids(struct pci_dynids *dynids)
+{
+	spin_lock_init(&dynids->lock);
+	INIT_LIST_HEAD(&dynids->list);
+}
+
+static void
+pci_free_dynids(struct pci_driver *drv)
+{
+	struct list_head *pos, *n;
+	struct dynid *dynid;
+
+	spin_lock(&drv->dynids.lock);
+	list_for_each_safe(pos, n, &drv->dynids.list) {
+		dynid = list_entry(pos, struct dynid, node);
+		list_del(&dynid->node);
+		kfree(dynid);
+	}
+	spin_unlock(&drv->dynids.lock);
+}
+
+static int
+pci_create_newid_file(struct pci_driver *drv)
+{
+	int error = 0;
+	if (drv->probe != NULL)
+		error = sysfs_create_file(&drv->driver.kobj,
+					  &driver_attr_new_id.attr);
+	return error;
+}
+
+static int
+pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv)
+{
+	struct list_head *pos;
+	struct dynid *dynid;
+
+	spin_lock(&pci_drv->dynids.lock);
+	list_for_each(pos, &pci_drv->dynids.list) {
+		dynid = list_entry(pos, struct dynid, node);
+		if (pci_match_one_device(&dynid->id, pci_dev)) {
+			spin_unlock(&pci_drv->dynids.lock);
+			return 1;
+		}
+	}
+	spin_unlock(&pci_drv->dynids.lock);
+	return 0;
+}
+
+#else /* !CONFIG_HOTPLUG */
+static inline int pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
+{
+	return -ENODEV;
+}
+static inline void pci_init_dynids(struct pci_dynids *dynids) {}
+static inline void pci_free_dynids(struct pci_driver *drv) {}
+static inline int pci_create_newid_file(struct pci_driver *drv)
+{
+	return 0;
+}
+static inline int pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv)
+{
+	return 0;
+}
+#endif
+
+/**
+ * pci_match_device - Tell if a PCI device structure has a matching
+ *                    PCI device id structure
+ * @ids: array of PCI device id structures to search in
+ * @dev: the PCI device structure to match against
+ * 
+ * Used by a driver to check whether a PCI device present in the
+ * system is in its list of supported devices.Returns the matching
+ * pci_device_id structure or %NULL if there is no match.
+ */
+const struct pci_device_id *
+pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
+{
+	while (ids->vendor || ids->subvendor || ids->class_mask) {
+		if (pci_match_one_device(ids, dev))
+			return ids;
+		ids++;
+	}
+	return NULL;
+}
+
+/**
+ * pci_device_probe_static()
+ * 
+ * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error.
+ */
+static int
+pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev)
+{		   
+	int error = -ENODEV;
+	const struct pci_device_id *id;
+
+	if (!drv->id_table)
+		return error;
+	id = pci_match_device(drv->id_table, pci_dev);
+	if (id)
+		error = drv->probe(pci_dev, id);
+	if (error >= 0) {
+		pci_dev->driver = drv;
+		error = 0;
+	}
+	return error;
+}
+
+/**
+ * __pci_device_probe()
+ * 
+ * returns 0  on success, else error.
+ * side-effect: pci_dev->driver is set to drv when drv claims pci_dev.
+ */
+static int
+__pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
+{		   
+	int error = 0;
+
+	if (!pci_dev->driver && drv->probe) {
+		error = pci_device_probe_static(drv, pci_dev);
+		if (error == -ENODEV)
+			error = pci_device_probe_dynamic(drv, pci_dev);
+	}
+	return error;
+}
+
+static int pci_device_probe(struct device * dev)
+{
+	int error = 0;
+	struct pci_driver *drv;
+	struct pci_dev *pci_dev;
+
+	drv = to_pci_driver(dev->driver);
+	pci_dev = to_pci_dev(dev);
+	pci_dev_get(pci_dev);
+	error = __pci_device_probe(drv, pci_dev);
+	if (error)
+		pci_dev_put(pci_dev);
+
+	return error;
+}
+
+static int pci_device_remove(struct device * dev)
+{
+	struct pci_dev * pci_dev = to_pci_dev(dev);
+	struct pci_driver * drv = pci_dev->driver;
+
+	if (drv) {
+		if (drv->remove)
+			drv->remove(pci_dev);
+		pci_dev->driver = NULL;
+	}
+
+	/*
+	 * We would love to complain here if pci_dev->is_enabled is set, that
+	 * the driver should have called pci_disable_device(), but the
+	 * unfortunate fact is there are too many odd BIOS and bridge setups
+	 * that don't like drivers doing that all of the time.  
+	 * Oh well, we can dream of sane hardware when we sleep, no matter how
+	 * horrible the crap we have to deal with is when we are awake...
+	 */
+
+	pci_dev_put(pci_dev);
+	return 0;
+}
+
+static int pci_device_suspend(struct device * dev, pm_message_t state)
+{
+	struct pci_dev * pci_dev = to_pci_dev(dev);
+	struct pci_driver * drv = pci_dev->driver;
+	int i = 0;
+
+	if (drv && drv->suspend)
+		i = drv->suspend(pci_dev, state);
+	else
+		pci_save_state(pci_dev);
+	return i;
+}
+
+
+/* 
+ * Default resume method for devices that have no driver provided resume,
+ * or not even a driver at all.
+ */
+static void pci_default_resume(struct pci_dev *pci_dev)
+{
+	/* restore the PCI config space */
+	pci_restore_state(pci_dev);
+	/* if the device was enabled before suspend, reenable */
+	if (pci_dev->is_enabled)
+		pci_enable_device(pci_dev);
+	/* if the device was busmaster before the suspend, make it busmaster again */
+	if (pci_dev->is_busmaster)
+		pci_set_master(pci_dev);
+}
+
+static int pci_device_resume(struct device * dev)
+{
+	struct pci_dev * pci_dev = to_pci_dev(dev);
+	struct pci_driver * drv = pci_dev->driver;
+
+	if (drv && drv->resume)
+		drv->resume(pci_dev);
+	else
+		pci_default_resume(pci_dev);
+	return 0;
+}
+
+
+#define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj)
+#define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr)
+
+static ssize_t
+pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
+{
+	struct device_driver *driver = kobj_to_pci_driver(kobj);
+	struct driver_attribute *dattr = attr_to_driver_attribute(attr);
+	ssize_t ret = 0;
+
+	if (get_driver(driver)) {
+		if (dattr->show)
+			ret = dattr->show(driver, buf);
+		put_driver(driver);
+	}
+	return ret;
+}
+
+static ssize_t
+pci_driver_attr_store(struct kobject * kobj, struct attribute *attr,
+		      const char *buf, size_t count)
+{
+	struct device_driver *driver = kobj_to_pci_driver(kobj);
+	struct driver_attribute *dattr = attr_to_driver_attribute(attr);
+	ssize_t ret = 0;
+
+	if (get_driver(driver)) {
+		if (dattr->store)
+			ret = dattr->store(driver, buf, count);
+		put_driver(driver);
+	}
+	return ret;
+}
+
+static struct sysfs_ops pci_driver_sysfs_ops = {
+	.show = pci_driver_attr_show,
+	.store = pci_driver_attr_store,
+};
+static struct kobj_type pci_driver_kobj_type = {
+	.sysfs_ops = &pci_driver_sysfs_ops,
+};
+
+static int
+pci_populate_driver_dir(struct pci_driver *drv)
+{
+	return pci_create_newid_file(drv);
+}
+
+/**
+ * pci_register_driver - register a new pci driver
+ * @drv: the driver structure to register
+ * 
+ * Adds the driver structure to the list of registered drivers.
+ * Returns a negative value on error, otherwise 0. 
+ * If no error occured, the driver remains registered even if 
+ * no device was claimed during registration.
+ */
+int pci_register_driver(struct pci_driver *drv)
+{
+	int error;
+
+	/* initialize common driver fields */
+	drv->driver.name = drv->name;
+	drv->driver.bus = &pci_bus_type;
+	drv->driver.probe = pci_device_probe;
+	drv->driver.remove = pci_device_remove;
+	drv->driver.owner = drv->owner;
+	drv->driver.kobj.ktype = &pci_driver_kobj_type;
+	pci_init_dynids(&drv->dynids);
+
+	/* register with core */
+	error = driver_register(&drv->driver);
+
+	if (!error)
+		pci_populate_driver_dir(drv);
+
+	return error;
+}
+
+/**
+ * pci_unregister_driver - unregister a pci driver
+ * @drv: the driver structure to unregister
+ * 
+ * Deletes the driver structure from the list of registered PCI drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+
+void
+pci_unregister_driver(struct pci_driver *drv)
+{
+	driver_unregister(&drv->driver);
+	pci_free_dynids(drv);
+}
+
+static struct pci_driver pci_compat_driver = {
+	.name = "compat"
+};
+
+/**
+ * pci_dev_driver - get the pci_driver of a device
+ * @dev: the device to query
+ *
+ * Returns the appropriate pci_driver structure or %NULL if there is no 
+ * registered driver for the device.
+ */
+struct pci_driver *
+pci_dev_driver(const struct pci_dev *dev)
+{
+	if (dev->driver)
+		return dev->driver;
+	else {
+		int i;
+		for(i=0; i<=PCI_ROM_RESOURCE; i++)
+			if (dev->resource[i].flags & IORESOURCE_BUSY)
+				return &pci_compat_driver;
+	}
+	return NULL;
+}
+
+/**
+ * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure
+ * @ids: array of PCI device id structures to search in
+ * @dev: the PCI device structure to match against
+ * 
+ * Used by a driver to check whether a PCI device present in the
+ * system is in its list of supported devices.Returns the matching
+ * pci_device_id structure or %NULL if there is no match.
+ */
+static int pci_bus_match(struct device * dev, struct device_driver * drv) 
+{
+	const struct pci_dev * pci_dev = to_pci_dev(dev);
+	struct pci_driver * pci_drv = to_pci_driver(drv);
+	const struct pci_device_id * ids = pci_drv->id_table;
+	const struct pci_device_id *found_id;
+
+	if (!ids)
+		return 0;
+
+	found_id = pci_match_device(ids, pci_dev);
+	if (found_id)
+		return 1;
+
+	return pci_bus_match_dynids(pci_dev, pci_drv);
+}
+
+/**
+ * pci_dev_get - increments the reference count of the pci device structure
+ * @dev: the device being referenced
+ *
+ * Each live reference to a device should be refcounted.
+ *
+ * Drivers for PCI devices should normally record such references in
+ * their probe() methods, when they bind to a device, and release
+ * them by calling pci_dev_put(), in their disconnect() methods.
+ *
+ * A pointer to the device with the incremented reference counter is returned.
+ */
+struct pci_dev *pci_dev_get(struct pci_dev *dev)
+{
+	if (dev)
+		get_device(&dev->dev);
+	return dev;
+}
+
+/**
+ * pci_dev_put - release a use of the pci device structure
+ * @dev: device that's been disconnected
+ *
+ * Must be called when a user of a device is finished with it.  When the last
+ * user of the device calls this function, the memory of the device is freed.
+ */
+void pci_dev_put(struct pci_dev *dev)
+{
+	if (dev)
+		put_device(&dev->dev);
+}
+
+#ifndef CONFIG_HOTPLUG
+int pci_hotplug (struct device *dev, char **envp, int num_envp,
+		 char *buffer, int buffer_size)
+{
+	return -ENODEV;
+}
+#endif
+
+struct bus_type pci_bus_type = {
+	.name		= "pci",
+	.match		= pci_bus_match,
+	.hotplug	= pci_hotplug,
+	.suspend	= pci_device_suspend,
+	.resume		= pci_device_resume,
+	.dev_attrs	= pci_dev_attrs,
+};
+
+static int __init pci_driver_init(void)
+{
+	return bus_register(&pci_bus_type);
+}
+
+postcore_initcall(pci_driver_init);
+
+EXPORT_SYMBOL(pci_match_device);
+EXPORT_SYMBOL(pci_register_driver);
+EXPORT_SYMBOL(pci_unregister_driver);
+EXPORT_SYMBOL(pci_dev_driver);
+EXPORT_SYMBOL(pci_bus_type);
+EXPORT_SYMBOL(pci_dev_get);
+EXPORT_SYMBOL(pci_dev_put);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
new file mode 100644
index 0000000..d57ae71
--- /dev/null
+++ b/drivers/pci/pci-sysfs.c
@@ -0,0 +1,490 @@
+/*
+ * drivers/pci/pci-sysfs.c
+ *
+ * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com>
+ * (C) Copyright 2002-2004 IBM Corp.
+ * (C) Copyright 2003 Matthew Wilcox
+ * (C) Copyright 2003 Hewlett-Packard
+ * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
+ * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
+ *
+ * File attributes for PCI devices
+ *
+ * Modeled after usb's driverfs.c 
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/stat.h>
+#include <linux/topology.h>
+#include <linux/mm.h>
+
+#include "pci.h"
+
+static int sysfs_initialized;	/* = 0 */
+
+/* show configuration fields */
+#define pci_config_attr(field, format_string)				\
+static ssize_t								\
+field##_show(struct device *dev, char *buf)				\
+{									\
+	struct pci_dev *pdev;						\
+									\
+	pdev = to_pci_dev (dev);					\
+	return sprintf (buf, format_string, pdev->field);		\
+}
+
+pci_config_attr(vendor, "0x%04x\n");
+pci_config_attr(device, "0x%04x\n");
+pci_config_attr(subsystem_vendor, "0x%04x\n");
+pci_config_attr(subsystem_device, "0x%04x\n");
+pci_config_attr(class, "0x%06x\n");
+pci_config_attr(irq, "%u\n");
+
+static ssize_t local_cpus_show(struct device *dev, char *buf)
+{		
+	cpumask_t mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);
+	int len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
+	strcat(buf,"\n"); 
+	return 1+len;
+}
+
+/* show resources */
+static ssize_t
+resource_show(struct device * dev, char * buf)
+{
+	struct pci_dev * pci_dev = to_pci_dev(dev);
+	char * str = buf;
+	int i;
+	int max = 7;
+
+	if (pci_dev->subordinate)
+		max = DEVICE_COUNT_RESOURCE;
+
+	for (i = 0; i < max; i++) {
+		str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n",
+			       pci_resource_start(pci_dev,i),
+			       pci_resource_end(pci_dev,i),
+			       pci_resource_flags(pci_dev,i));
+	}
+	return (str - buf);
+}
+
+struct device_attribute pci_dev_attrs[] = {
+	__ATTR_RO(resource),
+	__ATTR_RO(vendor),
+	__ATTR_RO(device),
+	__ATTR_RO(subsystem_vendor),
+	__ATTR_RO(subsystem_device),
+	__ATTR_RO(class),
+	__ATTR_RO(irq),
+	__ATTR_RO(local_cpus),
+	__ATTR_NULL,
+};
+
+static ssize_t
+pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
+	unsigned int size = 64;
+	loff_t init_off = off;
+
+	/* Several chips lock up trying to read undefined config space */
+	if (capable(CAP_SYS_ADMIN)) {
+		size = dev->cfg_size;
+	} else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
+		size = 128;
+	}
+
+	if (off > size)
+		return 0;
+	if (off + count > size) {
+		size -= off;
+		count = size;
+	} else {
+		size = count;
+	}
+
+	while (off & 3) {
+		unsigned char val;
+		pci_read_config_byte(dev, off, &val);
+		buf[off - init_off] = val;
+		off++;
+		if (--size == 0)
+			break;
+	}
+
+	while (size > 3) {
+		unsigned int val;
+		pci_read_config_dword(dev, off, &val);
+		buf[off - init_off] = val & 0xff;
+		buf[off - init_off + 1] = (val >> 8) & 0xff;
+		buf[off - init_off + 2] = (val >> 16) & 0xff;
+		buf[off - init_off + 3] = (val >> 24) & 0xff;
+		off += 4;
+		size -= 4;
+	}
+
+	while (size > 0) {
+		unsigned char val;
+		pci_read_config_byte(dev, off, &val);
+		buf[off - init_off] = val;
+		off++;
+		--size;
+	}
+
+	return count;
+}
+
+static ssize_t
+pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
+	unsigned int size = count;
+	loff_t init_off = off;
+
+	if (off > dev->cfg_size)
+		return 0;
+	if (off + count > dev->cfg_size) {
+		size = dev->cfg_size - off;
+		count = size;
+	}
+
+	while (off & 3) {
+		pci_write_config_byte(dev, off, buf[off - init_off]);
+		off++;
+		if (--size == 0)
+			break;
+	}
+
+	while (size > 3) {
+		unsigned int val = buf[off - init_off];
+		val |= (unsigned int) buf[off - init_off + 1] << 8;
+		val |= (unsigned int) buf[off - init_off + 2] << 16;
+		val |= (unsigned int) buf[off - init_off + 3] << 24;
+		pci_write_config_dword(dev, off, val);
+		off += 4;
+		size -= 4;
+	}
+
+	while (size > 0) {
+		pci_write_config_byte(dev, off, buf[off - init_off]);
+		off++;
+		--size;
+	}
+
+	return count;
+}
+
+#ifdef HAVE_PCI_LEGACY
+/**
+ * pci_read_legacy_io - read byte(s) from legacy I/O port space
+ * @kobj: kobject corresponding to file to read from
+ * @buf: buffer to store results
+ * @off: offset into legacy I/O port space
+ * @count: number of bytes to read
+ *
+ * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific
+ * callback routine (pci_legacy_read).
+ */
+ssize_t
+pci_read_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+        struct pci_bus *bus = to_pci_bus(container_of(kobj,
+                                                      struct class_device,
+						      kobj));
+
+        /* Only support 1, 2 or 4 byte accesses */
+        if (count != 1 && count != 2 && count != 4)
+                return -EINVAL;
+
+        return pci_legacy_read(bus, off, (u32 *)buf, count);
+}
+
+/**
+ * pci_write_legacy_io - write byte(s) to legacy I/O port space
+ * @kobj: kobject corresponding to file to read from
+ * @buf: buffer containing value to be written
+ * @off: offset into legacy I/O port space
+ * @count: number of bytes to write
+ *
+ * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific
+ * callback routine (pci_legacy_write).
+ */
+ssize_t
+pci_write_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+        struct pci_bus *bus = to_pci_bus(container_of(kobj,
+						      struct class_device,
+						      kobj));
+        /* Only support 1, 2 or 4 byte accesses */
+        if (count != 1 && count != 2 && count != 4)
+                return -EINVAL;
+
+        return pci_legacy_write(bus, off, *(u32 *)buf, count);
+}
+
+/**
+ * pci_mmap_legacy_mem - map legacy PCI memory into user memory space
+ * @kobj: kobject corresponding to device to be mapped
+ * @attr: struct bin_attribute for this file
+ * @vma: struct vm_area_struct passed to mmap
+ *
+ * Uses an arch specific callback, pci_mmap_legacy_page_range, to mmap
+ * legacy memory space (first meg of bus space) into application virtual
+ * memory space.
+ */
+int
+pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
+                    struct vm_area_struct *vma)
+{
+        struct pci_bus *bus = to_pci_bus(container_of(kobj,
+                                                      struct class_device,
+						      kobj));
+
+        return pci_mmap_legacy_page_range(bus, vma);
+}
+#endif /* HAVE_PCI_LEGACY */
+
+#ifdef HAVE_PCI_MMAP
+/**
+ * pci_mmap_resource - map a PCI resource into user memory space
+ * @kobj: kobject for mapping
+ * @attr: struct bin_attribute for the file being mapped
+ * @vma: struct vm_area_struct passed into the mmap
+ *
+ * Use the regular PCI mapping routines to map a PCI resource into userspace.
+ * FIXME: write combining?  maybe automatic for prefetchable regions?
+ */
+static int
+pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
+		  struct vm_area_struct *vma)
+{
+	struct pci_dev *pdev = to_pci_dev(container_of(kobj,
+						       struct device, kobj));
+	struct resource *res = (struct resource *)attr->private;
+	enum pci_mmap_state mmap_type;
+
+	vma->vm_pgoff += res->start >> PAGE_SHIFT;
+	mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
+
+	return pci_mmap_page_range(pdev, vma, mmap_type, 0);
+}
+
+/**
+ * pci_create_resource_files - create resource files in sysfs for @dev
+ * @dev: dev in question
+ *
+ * Walk the resources in @dev creating files for each resource available.
+ */
+static void
+pci_create_resource_files(struct pci_dev *pdev)
+{
+	int i;
+
+	/* Expose the PCI resources from this device as files */
+	for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+		struct bin_attribute *res_attr;
+
+		/* skip empty resources */
+		if (!pci_resource_len(pdev, i))
+			continue;
+
+		res_attr = kmalloc(sizeof(*res_attr) + 10, GFP_ATOMIC);
+		if (res_attr) {
+			memset(res_attr, 0, sizeof(*res_attr) + 10);
+			pdev->res_attr[i] = res_attr;
+			/* Allocated above after the res_attr struct */
+			res_attr->attr.name = (char *)(res_attr + 1);
+			sprintf(res_attr->attr.name, "resource%d", i);
+			res_attr->size = pci_resource_len(pdev, i);
+			res_attr->attr.mode = S_IRUSR | S_IWUSR;
+			res_attr->attr.owner = THIS_MODULE;
+			res_attr->mmap = pci_mmap_resource;
+			res_attr->private = &pdev->resource[i];
+			sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
+		}
+	}
+}
+
+/**
+ * pci_remove_resource_files - cleanup resource files
+ * @dev: dev to cleanup
+ *
+ * If we created resource files for @dev, remove them from sysfs and
+ * free their resources.
+ */
+static void
+pci_remove_resource_files(struct pci_dev *pdev)
+{
+	int i;
+
+	for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+		struct bin_attribute *res_attr;
+
+		res_attr = pdev->res_attr[i];
+		if (res_attr) {
+			sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
+			kfree(res_attr);
+		}
+	}
+}
+#else /* !HAVE_PCI_MMAP */
+static inline void pci_create_resource_files(struct pci_dev *dev) { return; }
+static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
+#endif /* HAVE_PCI_MMAP */
+
+/**
+ * pci_write_rom - used to enable access to the PCI ROM display
+ * @kobj: kernel object handle
+ * @buf: user input
+ * @off: file offset
+ * @count: number of byte in input
+ *
+ * writing anything except 0 enables it
+ */
+static ssize_t
+pci_write_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
+
+	if ((off ==  0) && (*buf == '0') && (count == 2))
+		pdev->rom_attr_enabled = 0;
+	else
+		pdev->rom_attr_enabled = 1;
+
+	return count;
+}
+
+/**
+ * pci_read_rom - read a PCI ROM
+ * @kobj: kernel object handle
+ * @buf: where to put the data we read from the ROM
+ * @off: file offset
+ * @count: number of bytes to read
+ *
+ * Put @count bytes starting at @off into @buf from the ROM in the PCI
+ * device corresponding to @kobj.
+ */
+static ssize_t
+pci_read_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
+	void __iomem *rom;
+	size_t size;
+
+	if (!pdev->rom_attr_enabled)
+		return -EINVAL;
+	
+	rom = pci_map_rom(pdev, &size);	/* size starts out as PCI window size */
+	if (!rom)
+		return 0;
+		
+	if (off >= size)
+		count = 0;
+	else {
+		if (off + count > size)
+			count = size - off;
+		
+		memcpy_fromio(buf, rom + off, count);
+	}
+	pci_unmap_rom(pdev, rom);
+		
+	return count;
+}
+
+static struct bin_attribute pci_config_attr = {
+	.attr =	{
+		.name = "config",
+		.mode = S_IRUGO | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = 256,
+	.read = pci_read_config,
+	.write = pci_write_config,
+};
+
+static struct bin_attribute pcie_config_attr = {
+	.attr =	{
+		.name = "config",
+		.mode = S_IRUGO | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = 4096,
+	.read = pci_read_config,
+	.write = pci_write_config,
+};
+
+int pci_create_sysfs_dev_files (struct pci_dev *pdev)
+{
+	if (!sysfs_initialized)
+		return -EACCES;
+
+	if (pdev->cfg_size < 4096)
+		sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
+	else
+		sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+
+	pci_create_resource_files(pdev);
+
+	/* If the device has a ROM, try to expose it in sysfs. */
+	if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
+		struct bin_attribute *rom_attr;
+		
+		rom_attr = kmalloc(sizeof(*rom_attr), GFP_ATOMIC);
+		if (rom_attr) {
+			memset(rom_attr, 0x00, sizeof(*rom_attr));
+			pdev->rom_attr = rom_attr;
+			rom_attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+			rom_attr->attr.name = "rom";
+			rom_attr->attr.mode = S_IRUSR;
+			rom_attr->attr.owner = THIS_MODULE;
+			rom_attr->read = pci_read_rom;
+			rom_attr->write = pci_write_rom;
+			sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
+		}
+	}
+	/* add platform-specific attributes */
+	pcibios_add_platform_entries(pdev);
+	
+	return 0;
+}
+
+/**
+ * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
+ * @pdev: device whose entries we should free
+ *
+ * Cleanup when @pdev is removed from sysfs.
+ */
+void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
+{
+	if (pdev->cfg_size < 4096)
+		sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
+	else
+		sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+
+	pci_remove_resource_files(pdev);
+
+	if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
+		if (pdev->rom_attr) {
+			sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
+			kfree(pdev->rom_attr);
+		}
+	}
+}
+
+static int __init pci_sysfs_init(void)
+{
+	struct pci_dev *pdev = NULL;
+	
+	sysfs_initialized = 1;
+	for_each_pci_dev(pdev)
+		pci_create_sysfs_dev_files(pdev);
+
+	return 0;
+}
+
+__initcall(pci_sysfs_init);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
new file mode 100644
index 0000000..bfbff83
--- /dev/null
+++ b/drivers/pci/pci.c
@@ -0,0 +1,837 @@
+/*
+ *	$Id: pci.c,v 1.91 1999/01/21 13:34:01 davem Exp $
+ *
+ *	PCI Bus Services, see include/linux/pci.h for further explanation.
+ *
+ *	Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
+ *	David Mosberger-Tang
+ *
+ *	Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/dma.h>	/* isa_dma_bridge_buggy */
+
+
+/**
+ * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
+ * @bus: pointer to PCI bus structure to search
+ *
+ * Given a PCI bus, returns the highest PCI bus number present in the set
+ * including the given PCI bus and its list of child PCI buses.
+ */
+unsigned char __devinit
+pci_bus_max_busnr(struct pci_bus* bus)
+{
+	struct list_head *tmp;
+	unsigned char max, n;
+
+	max = bus->number;
+	list_for_each(tmp, &bus->children) {
+		n = pci_bus_max_busnr(pci_bus_b(tmp));
+		if(n > max)
+			max = n;
+	}
+	return max;
+}
+
+/**
+ * pci_max_busnr - returns maximum PCI bus number
+ *
+ * Returns the highest PCI bus number present in the system global list of
+ * PCI buses.
+ */
+unsigned char __devinit
+pci_max_busnr(void)
+{
+	struct pci_bus *bus = NULL;
+	unsigned char max, n;
+
+	max = 0;
+	while ((bus = pci_find_next_bus(bus)) != NULL) {
+		n = pci_bus_max_busnr(bus);
+		if(n > max)
+			max = n;
+	}
+	return max;
+}
+
+static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap)
+{
+	u16 status;
+	u8 pos, id;
+	int ttl = 48;
+
+	pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
+	if (!(status & PCI_STATUS_CAP_LIST))
+		return 0;
+
+	switch (hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+	case PCI_HEADER_TYPE_BRIDGE:
+		pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos);
+		break;
+	case PCI_HEADER_TYPE_CARDBUS:
+		pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &pos);
+		break;
+	default:
+		return 0;
+	}
+	while (ttl-- && pos >= 0x40) {
+		pos &= ~3;
+		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos);
+	}
+	return 0;
+}
+
+/**
+ * pci_find_capability - query for devices' capabilities 
+ * @dev: PCI device to query
+ * @cap: capability code
+ *
+ * Tell if a device supports a given PCI capability.
+ * Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it.  Possible values for @cap:
+ *
+ *  %PCI_CAP_ID_PM           Power Management 
+ *  %PCI_CAP_ID_AGP          Accelerated Graphics Port 
+ *  %PCI_CAP_ID_VPD          Vital Product Data 
+ *  %PCI_CAP_ID_SLOTID       Slot Identification 
+ *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
+ *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
+ *  %PCI_CAP_ID_PCIX         PCI-X
+ *  %PCI_CAP_ID_EXP          PCI Express
+ */
+int pci_find_capability(struct pci_dev *dev, int cap)
+{
+	return __pci_bus_find_cap(dev->bus, dev->devfn, dev->hdr_type, cap);
+}
+
+/**
+ * pci_bus_find_capability - query for devices' capabilities 
+ * @bus:   the PCI bus to query
+ * @devfn: PCI device to query
+ * @cap:   capability code
+ *
+ * Like pci_find_capability() but works for pci devices that do not have a
+ * pci_dev structure set up yet. 
+ *
+ * Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it.
+ */
+int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
+{
+	u8 hdr_type;
+
+	pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
+
+	return __pci_bus_find_cap(bus, devfn, hdr_type & 0x7f, cap);
+}
+
+/**
+ * pci_find_ext_capability - Find an extended capability
+ * @dev: PCI device to query
+ * @cap: capability code
+ *
+ * Returns the address of the requested extended capability structure
+ * within the device's PCI configuration space or 0 if the device does
+ * not support it.  Possible values for @cap:
+ *
+ *  %PCI_EXT_CAP_ID_ERR		Advanced Error Reporting
+ *  %PCI_EXT_CAP_ID_VC		Virtual Channel
+ *  %PCI_EXT_CAP_ID_DSN		Device Serial Number
+ *  %PCI_EXT_CAP_ID_PWR		Power Budgeting
+ */
+int pci_find_ext_capability(struct pci_dev *dev, int cap)
+{
+	u32 header;
+	int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
+	int pos = 0x100;
+
+	if (dev->cfg_size <= 256)
+		return 0;
+
+	if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
+		return 0;
+
+	/*
+	 * If we have no capabilities, this is indicated by cap ID,
+	 * cap version and next pointer all being 0.
+	 */
+	if (header == 0)
+		return 0;
+
+	while (ttl-- > 0) {
+		if (PCI_EXT_CAP_ID(header) == cap)
+			return pos;
+
+		pos = PCI_EXT_CAP_NEXT(header);
+		if (pos < 0x100)
+			break;
+
+		if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
+			break;
+	}
+
+	return 0;
+}
+
+/**
+ * pci_find_parent_resource - return resource region of parent bus of given region
+ * @dev: PCI device structure contains resources to be searched
+ * @res: child resource record for which parent is sought
+ *
+ *  For given resource region of given device, return the resource
+ *  region of parent bus the given region is contained in or where
+ *  it should be allocated from.
+ */
+struct resource *
+pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
+{
+	const struct pci_bus *bus = dev->bus;
+	int i;
+	struct resource *best = NULL;
+
+	for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+		struct resource *r = bus->resource[i];
+		if (!r)
+			continue;
+		if (res->start && !(res->start >= r->start && res->end <= r->end))
+			continue;	/* Not contained */
+		if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
+			continue;	/* Wrong type */
+		if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
+			return r;	/* Exact match */
+		if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))
+			best = r;	/* Approximating prefetchable by non-prefetchable */
+	}
+	return best;
+}
+
+/**
+ * pci_set_power_state - Set the power state of a PCI device
+ * @dev: PCI device to be suspended
+ * @state: PCI power state (D0, D1, D2, D3hot, D3cold) we're entering
+ *
+ * Transition a device to a new power state, using the Power Management 
+ * Capabilities in the device's config space.
+ *
+ * RETURN VALUE: 
+ * -EINVAL if trying to enter a lower state than we're already in.
+ * 0 if we're already in the requested state.
+ * -EIO if device does not support PCI PM.
+ * 0 if we can successfully change the power state.
+ */
+
+int
+pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+{
+	int pm;
+	u16 pmcsr, pmc;
+
+	/* bound the state we're entering */
+	if (state > PCI_D3hot)
+		state = PCI_D3hot;
+
+	/* Validate current state:
+	 * Can enter D0 from any state, but if we can only go deeper 
+	 * to sleep if we're already in a low power state
+	 */
+	if (state != PCI_D0 && dev->current_state > state)
+		return -EINVAL;
+	else if (dev->current_state == state) 
+		return 0;        /* we're already there */
+
+	/* find PCI PM capability in list */
+	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+	
+	/* abort if the device doesn't support PM capabilities */
+	if (!pm)
+		return -EIO; 
+
+	pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc);
+	if ((pmc & PCI_PM_CAP_VER_MASK) > 2) {
+		printk(KERN_DEBUG
+		       "PCI: %s has unsupported PM cap regs version (%u)\n",
+		       pci_name(dev), pmc & PCI_PM_CAP_VER_MASK);
+		return -EIO;
+	}
+
+	/* check if this device supports the desired state */
+	if (state == PCI_D1 || state == PCI_D2) {
+		if (state == PCI_D1 && !(pmc & PCI_PM_CAP_D1))
+			return -EIO;
+		else if (state == PCI_D2 && !(pmc & PCI_PM_CAP_D2))
+			return -EIO;
+	}
+
+	/* If we're in D3, force entire word to 0.
+	 * This doesn't affect PME_Status, disables PME_En, and
+	 * sets PowerState to 0.
+	 */
+	if (dev->current_state >= PCI_D3hot)
+		pmcsr = 0;
+	else {
+		pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		pmcsr |= state;
+	}
+
+	/* enter specified state */
+	pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
+
+	/* Mandatory power management transition delays */
+	/* see PCI PM 1.1 5.6.1 table 18 */
+	if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
+		msleep(10);
+	else if (state == PCI_D2 || dev->current_state == PCI_D2)
+		udelay(200);
+	dev->current_state = state;
+
+	return 0;
+}
+
+/**
+ * pci_choose_state - Choose the power state of a PCI device
+ * @dev: PCI device to be suspended
+ * @state: target sleep state for the whole system. This is the value
+ *	that is passed to suspend() function.
+ *
+ * Returns PCI power state suitable for given device and given system
+ * message.
+ */
+
+pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
+{
+	if (!pci_find_capability(dev, PCI_CAP_ID_PM))
+		return PCI_D0;
+
+	switch (state) {
+	case 0: return PCI_D0;
+	case 3: return PCI_D3hot;
+	default:
+		printk("They asked me for state %d\n", state);
+		BUG();
+	}
+	return PCI_D0;
+}
+
+EXPORT_SYMBOL(pci_choose_state);
+
+/**
+ * pci_save_state - save the PCI configuration space of a device before suspending
+ * @dev: - PCI device that we're dealing with
+ * @buffer: - buffer to hold config space context
+ *
+ * @buffer must be large enough to hold the entire PCI 2.2 config space 
+ * (>= 64 bytes).
+ */
+int
+pci_save_state(struct pci_dev *dev)
+{
+	int i;
+	/* XXX: 100% dword access ok here? */
+	for (i = 0; i < 16; i++)
+		pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
+	return 0;
+}
+
+/** 
+ * pci_restore_state - Restore the saved state of a PCI device
+ * @dev: - PCI device that we're dealing with
+ * @buffer: - saved PCI config space
+ *
+ */
+int 
+pci_restore_state(struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		pci_write_config_dword(dev,i * 4, dev->saved_config_space[i]);
+	return 0;
+}
+
+/**
+ * pci_enable_device_bars - Initialize some of a device for use
+ * @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable selected I/O and memory resources. Wake up the device if it 
+ *  was suspended. Beware, this function can fail.
+ */
+ 
+int
+pci_enable_device_bars(struct pci_dev *dev, int bars)
+{
+	int err;
+
+	pci_set_power_state(dev, PCI_D0);
+	if ((err = pcibios_enable_device(dev, bars)) < 0)
+		return err;
+	return 0;
+}
+
+/**
+ * pci_enable_device - Initialize device before it's used by a driver.
+ * @dev: PCI device to be initialized
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable I/O and memory. Wake up the device if it was suspended.
+ *  Beware, this function can fail.
+ */
+int
+pci_enable_device(struct pci_dev *dev)
+{
+	int err;
+
+	dev->is_enabled = 1;
+	if ((err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1)))
+		return err;
+	pci_fixup_device(pci_fixup_enable, dev);
+	return 0;
+}
+
+/**
+ * pcibios_disable_device - disable arch specific PCI resources for device dev
+ * @dev: the PCI device to disable
+ *
+ * Disables architecture specific PCI resources for the device. This
+ * is the default implementation. Architecture implementations can
+ * override this.
+ */
+void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
+
+/**
+ * pci_disable_device - Disable PCI device after use
+ * @dev: PCI device to be disabled
+ *
+ * Signal to the system that the PCI device is not in use by the system
+ * anymore.  This only involves disabling PCI bus-mastering, if active.
+ */
+void
+pci_disable_device(struct pci_dev *dev)
+{
+	u16 pci_command;
+	
+	dev->is_enabled = 0;
+	dev->is_busmaster = 0;
+
+	pci_read_config_word(dev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_MASTER) {
+		pci_command &= ~PCI_COMMAND_MASTER;
+		pci_write_config_word(dev, PCI_COMMAND, pci_command);
+	}
+
+	pcibios_disable_device(dev);
+}
+
+/**
+ * pci_enable_wake - enable device to generate PME# when suspended
+ * @dev: - PCI device to operate on
+ * @state: - Current state of device.
+ * @enable: - Flag to enable or disable generation
+ * 
+ * Set the bits in the device's PM Capabilities to generate PME# when
+ * the system is suspended. 
+ *
+ * -EIO is returned if device doesn't have PM Capabilities. 
+ * -EINVAL is returned if device supports it, but can't generate wake events.
+ * 0 if operation is successful.
+ * 
+ */
+int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
+{
+	int pm;
+	u16 value;
+
+	/* find PCI PM capability in list */
+	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+
+	/* If device doesn't support PM Capabilities, but request is to disable
+	 * wake events, it's a nop; otherwise fail */
+	if (!pm) 
+		return enable ? -EIO : 0; 
+
+	/* Check device's ability to generate PME# */
+	pci_read_config_word(dev,pm+PCI_PM_PMC,&value);
+
+	value &= PCI_PM_CAP_PME_MASK;
+	value >>= ffs(PCI_PM_CAP_PME_MASK) - 1;   /* First bit of mask */
+
+	/* Check if it can generate PME# from requested state. */
+	if (!value || !(value & (1 << state))) 
+		return enable ? -EINVAL : 0;
+
+	pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
+
+	/* Clear PME_Status by writing 1 to it and enable PME# */
+	value |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE;
+
+	if (!enable)
+		value &= ~PCI_PM_CTRL_PME_ENABLE;
+
+	pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
+	
+	return 0;
+}
+
+int
+pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
+{
+	u8 pin;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	if (!pin)
+		return -1;
+	pin--;
+	while (dev->bus->self) {
+		pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+		dev = dev->bus->self;
+	}
+	*bridge = dev;
+	return pin;
+}
+
+/**
+ *	pci_release_region - Release a PCI bar
+ *	@pdev: PCI device whose resources were previously reserved by pci_request_region
+ *	@bar: BAR to release
+ *
+ *	Releases the PCI I/O and memory resources previously reserved by a
+ *	successful call to pci_request_region.  Call this function only
+ *	after all use of the PCI regions has ceased.
+ */
+void pci_release_region(struct pci_dev *pdev, int bar)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return;
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+		release_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+		release_mem_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+}
+
+/**
+ *	pci_request_region - Reserved PCI I/O and memory resource
+ *	@pdev: PCI device whose resources are to be reserved
+ *	@bar: BAR to be reserved
+ *	@res_name: Name to be associated with resource.
+ *
+ *	Mark the PCI region associated with PCI device @pdev BR @bar as
+ *	being reserved by owner @res_name.  Do not access any
+ *	address inside the PCI regions unless this call returns
+ *	successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int pci_request_region(struct pci_dev *pdev, int bar, char *res_name)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return 0;
+		
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
+		if (!request_region(pci_resource_start(pdev, bar),
+			    pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+		if (!request_mem_region(pci_resource_start(pdev, bar),
+				        pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	
+	return 0;
+
+err_out:
+	printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+		pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
+		bar + 1, /* PCI BAR # */
+		pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
+		pci_name(pdev));
+	return -EBUSY;
+}
+
+
+/**
+ *	pci_release_regions - Release reserved PCI I/O and memory resources
+ *	@pdev: PCI device whose resources were previously reserved by pci_request_regions
+ *
+ *	Releases all PCI I/O and memory resources previously reserved by a
+ *	successful call to pci_request_regions.  Call this function only
+ *	after all use of the PCI regions has ceased.
+ */
+
+void pci_release_regions(struct pci_dev *pdev)
+{
+	int i;
+	
+	for (i = 0; i < 6; i++)
+		pci_release_region(pdev, i);
+}
+
+/**
+ *	pci_request_regions - Reserved PCI I/O and memory resources
+ *	@pdev: PCI device whose resources are to be reserved
+ *	@res_name: Name to be associated with resource.
+ *
+ *	Mark all PCI regions associated with PCI device @pdev as
+ *	being reserved by owner @res_name.  Do not access any
+ *	address inside the PCI regions unless this call returns
+ *	successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int pci_request_regions(struct pci_dev *pdev, char *res_name)
+{
+	int i;
+	
+	for (i = 0; i < 6; i++)
+		if(pci_request_region(pdev, i, res_name))
+			goto err_out;
+	return 0;
+
+err_out:
+	while(--i >= 0)
+		pci_release_region(pdev, i);
+		
+	return -EBUSY;
+}
+
+/**
+ * pci_set_master - enables bus-mastering for device dev
+ * @dev: the PCI device to enable
+ *
+ * Enables bus-mastering on the device and calls pcibios_set_master()
+ * to do the needed arch specific settings.
+ */
+void
+pci_set_master(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if (! (cmd & PCI_COMMAND_MASTER)) {
+		pr_debug("PCI: Enabling bus mastering for device %s\n", pci_name(dev));
+		cmd |= PCI_COMMAND_MASTER;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	dev->is_busmaster = 1;
+	pcibios_set_master(dev);
+}
+
+#ifndef HAVE_ARCH_PCI_MWI
+/* This can be overridden by arch code. */
+u8 pci_cache_line_size = L1_CACHE_BYTES >> 2;
+
+/**
+ * pci_generic_prep_mwi - helper function for pci_set_mwi
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Helper function for generic implementation of pcibios_prep_mwi
+ * function.  Originally copied from drivers/net/acenic.c.
+ * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+static int
+pci_generic_prep_mwi(struct pci_dev *dev)
+{
+	u8 cacheline_size;
+
+	if (!pci_cache_line_size)
+		return -EINVAL;		/* The system doesn't support MWI. */
+
+	/* Validate current setting: the PCI_CACHE_LINE_SIZE must be
+	   equal to or multiple of the right value. */
+	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);
+	if (cacheline_size >= pci_cache_line_size &&
+	    (cacheline_size % pci_cache_line_size) == 0)
+		return 0;
+
+	/* Write the correct value. */
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
+	/* Read it back. */
+	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cacheline_size);
+	if (cacheline_size == pci_cache_line_size)
+		return 0;
+
+	printk(KERN_DEBUG "PCI: cache line size of %d is not supported "
+	       "by device %s\n", pci_cache_line_size << 2, pci_name(dev));
+
+	return -EINVAL;
+}
+#endif /* !HAVE_ARCH_PCI_MWI */
+
+/**
+ * pci_set_mwi - enables memory-write-invalidate PCI transaction
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND,
+ * and then calls @pcibios_set_mwi to do the needed arch specific
+ * operations or a generic mwi-prep function.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int
+pci_set_mwi(struct pci_dev *dev)
+{
+	int rc;
+	u16 cmd;
+
+#ifdef HAVE_ARCH_PCI_MWI
+	rc = pcibios_prep_mwi(dev);
+#else
+	rc = pci_generic_prep_mwi(dev);
+#endif
+
+	if (rc)
+		return rc;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if (! (cmd & PCI_COMMAND_INVALIDATE)) {
+		pr_debug("PCI: Enabling Mem-Wr-Inval for device %s\n", pci_name(dev));
+		cmd |= PCI_COMMAND_INVALIDATE;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	
+	return 0;
+}
+
+/**
+ * pci_clear_mwi - disables Memory-Write-Invalidate for device dev
+ * @dev: the PCI device to disable
+ *
+ * Disables PCI Memory-Write-Invalidate transaction on the device
+ */
+void
+pci_clear_mwi(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if (cmd & PCI_COMMAND_INVALIDATE) {
+		cmd &= ~PCI_COMMAND_INVALIDATE;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+}
+
+#ifndef HAVE_ARCH_PCI_SET_DMA_MASK
+/*
+ * These can be overridden by arch-specific implementations
+ */
+int
+pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+	if (!pci_dma_supported(dev, mask))
+		return -EIO;
+
+	dev->dma_mask = mask;
+
+	return 0;
+}
+    
+int
+pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+	if (!pci_dac_dma_supported(dev, mask))
+		return -EIO;
+
+	dev->dma_mask = mask;
+
+	return 0;
+}
+
+int
+pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
+{
+	if (!pci_dma_supported(dev, mask))
+		return -EIO;
+
+	dev->dev.coherent_dma_mask = mask;
+
+	return 0;
+}
+#endif
+     
+static int __devinit pci_init(void)
+{
+	struct pci_dev *dev = NULL;
+
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		pci_fixup_device(pci_fixup_final, dev);
+	}
+	return 0;
+}
+
+static int __devinit pci_setup(char *str)
+{
+	while (str) {
+		char *k = strchr(str, ',');
+		if (k)
+			*k++ = 0;
+		if (*str && (str = pcibios_setup(str)) && *str) {
+			/* PCI layer options should be handled here */
+			printk(KERN_ERR "PCI: Unknown option `%s'\n", str);
+		}
+		str = k;
+	}
+	return 1;
+}
+
+device_initcall(pci_init);
+
+__setup("pci=", pci_setup);
+
+#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
+/* FIXME: Some boxes have multiple ISA bridges! */
+struct pci_dev *isa_bridge;
+EXPORT_SYMBOL(isa_bridge);
+#endif
+
+EXPORT_SYMBOL(pci_enable_device_bars);
+EXPORT_SYMBOL(pci_enable_device);
+EXPORT_SYMBOL(pci_disable_device);
+EXPORT_SYMBOL(pci_max_busnr);
+EXPORT_SYMBOL(pci_bus_max_busnr);
+EXPORT_SYMBOL(pci_find_capability);
+EXPORT_SYMBOL(pci_bus_find_capability);
+EXPORT_SYMBOL(pci_release_regions);
+EXPORT_SYMBOL(pci_request_regions);
+EXPORT_SYMBOL(pci_release_region);
+EXPORT_SYMBOL(pci_request_region);
+EXPORT_SYMBOL(pci_set_master);
+EXPORT_SYMBOL(pci_set_mwi);
+EXPORT_SYMBOL(pci_clear_mwi);
+EXPORT_SYMBOL(pci_set_dma_mask);
+EXPORT_SYMBOL(pci_dac_set_dma_mask);
+EXPORT_SYMBOL(pci_set_consistent_dma_mask);
+EXPORT_SYMBOL(pci_assign_resource);
+EXPORT_SYMBOL(pci_find_parent_resource);
+
+EXPORT_SYMBOL(pci_set_power_state);
+EXPORT_SYMBOL(pci_save_state);
+EXPORT_SYMBOL(pci_restore_state);
+EXPORT_SYMBOL(pci_enable_wake);
+
+/* Quirk info */
+
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
+EXPORT_SYMBOL(pci_pci_problems);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
new file mode 100644
index 0000000..79cdc16
--- /dev/null
+++ b/drivers/pci/pci.h
@@ -0,0 +1,96 @@
+/* Functions internal to the PCI core code */
+
+extern int pci_hotplug (struct device *dev, char **envp, int num_envp,
+			 char *buffer, int buffer_size);
+extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
+extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
+extern void pci_cleanup_rom(struct pci_dev *dev);
+extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+				  unsigned long size, unsigned long align,
+				  unsigned long min, unsigned int type_mask,
+				  void (*alignf)(void *, struct resource *,
+					  	 unsigned long, unsigned long),
+				  void *alignf_data);
+/* PCI /proc functions */
+#ifdef CONFIG_PROC_FS
+extern int pci_proc_attach_device(struct pci_dev *dev);
+extern int pci_proc_detach_device(struct pci_dev *dev);
+extern int pci_proc_attach_bus(struct pci_bus *bus);
+extern int pci_proc_detach_bus(struct pci_bus *bus);
+#else
+static inline int pci_proc_attach_device(struct pci_dev *dev) { return 0; }
+static inline int pci_proc_detach_device(struct pci_dev *dev) { return 0; }
+static inline int pci_proc_attach_bus(struct pci_bus *bus) { return 0; }
+static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
+#endif
+
+/* Functions for PCI Hotplug drivers to use */
+extern struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
+extern unsigned int pci_do_scan_bus(struct pci_bus *bus);
+extern int pci_remove_device_safe(struct pci_dev *dev);
+extern unsigned char pci_max_busnr(void);
+extern unsigned char pci_bus_max_busnr(struct pci_bus *bus);
+extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
+
+struct pci_dev_wrapped {
+	struct pci_dev	*dev;
+	void		*data;
+};
+
+struct pci_bus_wrapped {
+	struct pci_bus	*bus;
+	void		*data;
+};
+
+struct pci_visit {
+	int (* pre_visit_pci_bus)	(struct pci_bus_wrapped *,
+					 struct pci_dev_wrapped *);
+	int (* post_visit_pci_bus)	(struct pci_bus_wrapped *,
+					 struct pci_dev_wrapped *);
+
+	int (* pre_visit_pci_dev)	(struct pci_dev_wrapped *,
+					 struct pci_bus_wrapped *);
+	int (* visit_pci_dev)		(struct pci_dev_wrapped *,
+					 struct pci_bus_wrapped *);
+	int (* post_visit_pci_dev)	(struct pci_dev_wrapped *,
+					 struct pci_bus_wrapped *);
+};
+
+extern int pci_visit_dev(struct pci_visit *fn,
+			 struct pci_dev_wrapped *wrapped_dev,
+			 struct pci_bus_wrapped *wrapped_parent);
+extern void pci_remove_legacy_files(struct pci_bus *bus);
+
+/* Lock for read/write access to pci device and bus lists */
+extern spinlock_t pci_bus_lock;
+
+#ifdef CONFIG_X86_IO_APIC
+extern int pci_msi_quirk;
+#else
+#define pci_msi_quirk 0
+#endif
+
+extern int pcie_mch_quirk;
+extern struct device_attribute pci_dev_attrs[];
+extern struct class_device_attribute class_device_attr_cpuaffinity;
+
+/**
+ * pci_match_one_device - Tell if a PCI device structure has a matching
+ *                        PCI device id structure
+ * @id: single PCI device id structure to match
+ * @dev: the PCI device structure to match against
+ * 
+ * Returns the matching pci_device_id structure or %NULL if there is no match.
+ */
+static inline const struct pci_device_id *
+pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
+{
+	if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
+	    (id->device == PCI_ANY_ID || id->device == dev->device) &&
+	    (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&
+	    (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&
+	    !((id->class ^ dev->class) & id->class_mask))
+		return id;
+	return NULL;
+}
+
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
new file mode 100644
index 0000000..93481b4
--- /dev/null
+++ b/drivers/pci/pci.ids
@@ -0,0 +1,10179 @@
+#
+#	List of PCI ID's
+#
+#	Maintained by Martin Mares <mj@ucw.cz> and other volunteers from the
+#	Linux PCI ID's Project at http://pciids.sf.net/. New data are always
+#	welcome (if they are accurate), we're eagerly expecting new entries,
+#	so if you have anything to contribute, please visit the home page or
+#	send a diff -u against the most recent pci.ids to pci-ids@ucw.cz.
+#
+#	Daily snapshot on Tue 2005-03-08 10:11:48
+#
+
+# Vendors, devices and subsystems. Please keep sorted.
+
+# Syntax:
+# vendor  vendor_name
+#	device  device_name				<-- single tab
+#		subvendor subdevice  subsystem_name	<-- two tabs
+
+0000  Gammagraphx, Inc.
+001a  Ascend Communications, Inc.
+0033  Paradyne corp.
+003d  Lockheed Martin-Marietta Corp
+# Real TJN ID is e159, but they got it wrong several times --mj
+0059  Tiger Jet Network Inc. (Wrong ID)
+0070  Hauppauge computer works Inc.
+	4000  WinTV PVR-350
+	4001  WinTV PVR-250 (v1)
+	4009  WinTV PVR-250
+	4801  WinTV PVR-250 MCE
+0071  Nebula Electronics Ltd.
+0095  Silicon Image, Inc. (Wrong ID)
+	0680  Ultra ATA/133 IDE RAID CONTROLLER CARD
+0100  Ncipher Corp Ltd
+# 018a is not LevelOne but there is a board misprogrammed
+018a  LevelOne
+	0106  FPC-0106TX misprogrammed [RTL81xx]
+# 021b is not Compaq but there is a board misprogrammed
+021b  Compaq Computer Corporation
+	8139  HNE-300 (RealTek RTL8139c) [iPaq Networking]
+# http://www.davicom.com.tw/
+0291  Davicom Semiconductor, Inc.
+	8212  DM9102A(DM9102AE, SM9102AF) Ethernet 100/10 MBit(Rev 40)
+# SpeedStream is Efficient Networks, Inc, a Siemens Company
+02ac  SpeedStream
+	1012  1012 PCMCIA 10/100 Ethernet Card [RTL81xx]
+0357  TTTech AG
+	000a  TTP-Monitoring Card V2.0
+0432  SCM Microsystems, Inc.
+	0001  Pluto2 DVB-T Receiver for PCMCIA [EasyWatch MobilSet]
+05e3  CyberDoor
+	0701  CBD516
+0675  Dynalink
+	1700  IS64PH ISDN Adapter
+	1702  IS64PH ISDN Adapter
+# Wrong ID used in subsystem ID of VIA USB controllers.
+0925  VIA Technologies, Inc. (Wrong ID)
+09c1  Arris
+	0704  CM 200E Cable Modem
+0a89  BREA Technologies Inc
+0b49  ASCII Corporation
+# see http://homepage1.nifty.com/mcn/lab/machines/trance_vibrator/usbview.vib.txt
+	064f  Trance Vibrator
+0e11  Compaq Computer Corporation
+	0001  PCI to EISA Bridge
+	0002  PCI to ISA Bridge
+	0046  Smart Array 64xx
+		0e11 409a  Smart Array 641
+		0e11 409b  Smart Array 642
+		0e11 409c  Smart Array 6400
+		0e11 409d  Smart Array 6400 EM
+	0049  NC7132 Gigabit Upgrade Module
+	004a  NC6136 Gigabit Server Adapter
+	007c  NC7770 1000BaseTX
+	007d  NC6770 1000BaseTX
+	0085  NC7780 1000BaseTX
+	00bb  NC7760
+	00ca  NC7771
+	00cb  NC7781
+	00cf  NC7772
+	00d0  NC7782
+	00d1  NC7783
+	00e3  NC7761
+	0508  Netelligent 4/16 Token Ring
+	1000  Triflex/Pentium Bridge, Model 1000
+	2000  Triflex/Pentium Bridge, Model 2000
+	3032  QVision 1280/p
+	3033  QVision 1280/p
+	3034  QVision 1280/p
+	4000  4000 [Triflex]
+	4030  SMART-2/P
+	4031  SMART-2SL
+	4032  Smart Array 3200
+	4033  Smart Array 3100ES
+	4034  Smart Array 221
+	4040  Integrated Array
+	4048  Compaq Raid LC2
+	4050  Smart Array 4200
+	4051  Smart Array 4250ES
+	4058  Smart Array 431
+	4070  Smart Array 5300
+	4080  Smart Array 5i
+	4082  Smart Array 532
+	4083  Smart Array 5312
+	4091  Smart Array 6i
+	409a  Smart Array 641
+	409b  Smart Array 642
+	409c  Smart Array 6400
+	409d  Smart Array 6400 EM
+	6010  HotPlug PCI Bridge 6010
+	7020  USB Controller
+	a0ec  Fibre Channel Host Controller
+	a0f0  Advanced System Management Controller
+	a0f3  Triflex PCI to ISA Bridge
+	a0f7  PCI Hotplug Controller
+		8086 002a  PCI Hotplug Controller A
+		8086 002b  PCI Hotplug Controller B
+	a0f8  ZFMicro Chipset USB
+	a0fc  FibreChannel HBA Tachyon
+	ae10  Smart-2/P RAID Controller
+		0e11 4030  Smart-2/P Array Controller
+		0e11 4031  Smart-2SL Array Controller
+		0e11 4032  Smart Array Controller
+		0e11 4033  Smart 3100ES Array Controller
+	ae29  MIS-L
+	ae2a  MPC
+	ae2b  MIS-E
+	ae31  System Management Controller
+	ae32  Netelligent 10/100 TX PCI UTP
+	ae33  Triflex Dual EIDE Controller
+	ae34  Netelligent 10 T PCI UTP
+	ae35  Integrated NetFlex-3/P
+	ae40  Netelligent Dual 10/100 TX PCI UTP
+	ae43  Netelligent Integrated 10/100 TX UTP
+	ae69  CETUS-L
+	ae6c  Northstar
+	ae6d  NorthStar CPU to PCI Bridge
+	b011  Netelligent 10/100 TX Embedded UTP
+	b012  Netelligent 10 T/2 PCI UTP/Coax
+	b01e  NC3120 Fast Ethernet NIC
+	b01f  NC3122 Fast Ethernet NIC
+	b02f  NC1120 Ethernet NIC
+	b030  Netelligent 10/100 TX UTP
+	b04a  10/100 TX PCI Intel WOL UTP Controller
+	b060  Smart Array 5300 Controller
+	b0c6  NC3161 Fast Ethernet NIC
+	b0c7  NC3160 Fast Ethernet NIC
+	b0d7  NC3121 Fast Ethernet NIC
+	b0dd  NC3131 Fast Ethernet NIC
+	b0de  NC3132 Fast Ethernet Module
+	b0df  NC6132 Gigabit Module
+	b0e0  NC6133 Gigabit Module
+	b0e1  NC3133 Fast Ethernet Module
+	b123  NC6134 Gigabit NIC
+	b134  NC3163 Fast Ethernet NIC
+	b13c  NC3162 Fast Ethernet NIC
+	b144  NC3123 Fast Ethernet NIC
+	b163  NC3134 Fast Ethernet NIC
+	b164  NC3165 Fast Ethernet Upgrade Module
+	b178  Smart Array 5i/532
+		0e11 4080  Smart Array 5i
+		0e11 4082  Smart Array 532
+		0e11 4083  Smart Array 5312
+	b1a4  NC7131 Gigabit Server Adapter
+# HP Memory Hot-Plug Controller
+	b200  Memory Hot-Plug Controller
+	b203  Integrated Lights Out Controller
+	b204  Integrated Lights Out  Processor
+	f130  NetFlex-3/P ThunderLAN 1.0
+	f150  NetFlex-3/P ThunderLAN 2.3
+0e55  HaSoTec GmbH
+# Formerly NCR
+1000  LSI Logic / Symbios Logic
+	0001  53c810
+		1000 1000  LSI53C810AE PCI to SCSI I/O Processor
+	0002  53c820
+	0003  53c825
+		1000 1000  LSI53C825AE PCI to SCSI I/O Processor (Ultra Wide)
+	0004  53c815
+	0005  53c810AP
+	0006  53c860
+		1000 1000  LSI53C860E PCI to Ultra SCSI I/O Processor
+	000a  53c1510
+		1000 1000  LSI53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Nonintelligent mode)
+	000b  53C896/897
+		0e11 6004  EOB003 Series SCSI host adapter
+		1000 1000  LSI53C896/7 PCI to Dual Channel Ultra2 SCSI Multifunction Controller
+		1000 1010  LSI22910 PCI to Dual Channel Ultra2 SCSI host adapter
+		1000 1020  LSI21002 PCI to Dual Channel Ultra2 SCSI host adapter
+# multifunction PCI card: Dual U2W SCSI, dual 10/100TX, graphics
+		13e9 1000  6221L-4U
+	000c  53c895
+		1000 1010  LSI8951U PCI to Ultra2 SCSI host adapter
+		1000 1020  LSI8952U PCI to Ultra2 SCSI host adapter
+		1de1 3906  DC-390U2B SCSI adapter
+		1de1 3907  DC-390U2W
+	000d  53c885
+	000f  53c875
+		0e11 7004  Embedded Ultra Wide SCSI Controller
+		1000 1000  LSI53C876/E PCI to Dual Channel SCSI Controller
+		1000 1010  LSI22801 PCI to Dual Channel Ultra SCSI host adapter
+		1000 1020  LSI22802 PCI to Dual Channel Ultra SCSI host adapter
+		1092 8760  FirePort 40 Dual SCSI Controller
+		1de1 3904  DC390F/U Ultra Wide SCSI Adapter
+		4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard
+		4c53 1050  CT7 mainboard
+	0010  53C1510
+		0e11 4040  Integrated Array Controller
+		0e11 4048  RAID LC2 Controller
+		1000 1000  53C1510 PCI to Dual Channel Wide Ultra2 SCSI Controller (Intelligent mode)
+	0012  53c895a
+		1000 1000  LSI53C895A PCI to Ultra2 SCSI Controller
+	0013  53c875a
+		1000 1000  LSI53C875A PCI to Ultra SCSI Controller
+	0020  53c1010 Ultra3 SCSI Adapter
+		1000 1000  LSI53C1010-33 PCI to Dual Channel Ultra160 SCSI Controller
+		1de1 1020  DC-390U3W
+	0021  53c1010 66MHz  Ultra3 SCSI Adapter
+		1000 1000  LSI53C1000/1000R/1010R/1010-66 PCI to Ultra160 SCSI Controller
+		1000 1010  Asus TR-DLS onboard 53C1010-66
+		124b 1070  PMC-USCSI3
+		4c53 1080  CT8 mainboard
+		4c53 1300  P017 mezzanine (32-bit PMC)
+		4c53 1310  P017 mezzanine (64-bit PMC)
+	0030  53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI
+		1028 0123  PowerEdge 2600
+		1028 014a  PowerEdge 1750
+		1028 016c  PowerEdge 1850 MPT Fusion SCSI/RAID (Perc 4)
+		1028 0183  PowerEdge 1800
+		1028 1010  LSI U320 SCSI Controller
+	0031  53c1030ZC PCI-X Fusion-MPT Dual Ultra320 SCSI
+	0032  53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI
+		1000 1000  LSI53C1020/1030 PCI-X to Ultra320 SCSI Controller
+	0033  1030ZC_53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI
+	0040  53c1035 PCI-X Fusion-MPT Dual Ultra320 SCSI
+		1000 0033  MegaRAID SCSI 320-2XR
+		1000 0066  MegaRAID SCSI 320-2XRWS
+	0041  53C1035ZC PCI-X Fusion-MPT Dual Ultra320 SCSI
+	008f  53c875J
+		1092 8000  FirePort 40 SCSI Controller
+		1092 8760  FirePort 40 Dual SCSI Host Adapter
+	0407  MegaRAID
+		1000 0530  MegaRAID 530 SCSI 320-0X RAID Controller
+		1000 0531  MegaRAID 531 SCSI 320-4X RAID Controller
+		1000 0532  MegaRAID 532 SCSI 320-2X RAID Controller
+		1028 0531  PowerEdge Expandable RAID Controller 4/QC
+		1028 0533  PowerEdge Expandable RAID Controller 4/QC
+		8086 0530  MegaRAID Intel RAID Controller SRCZCRX
+		8086 0532  MegaRAID Intel RAID Controller SRCU42X
+	0408  MegaRAID
+		1000 0001  MegaRAID SCSI 320-1E RAID Controller
+		1000 0002  MegaRAID SCSI 320-2E RAID Controller
+		1025 004d  MegaRAID ACER ROMB-2E RAID Controller
+		1028 0001  PowerEdge RAID Controller PERC4e/SC
+		1028 0002  PowerEdge RAID Controller PERC4e/DC
+		1734 1065  FSC MegaRAID PCI Express ROMB
+		8086 0002  MegaRAID Intel RAID Controller SRCU42E
+	0409  MegaRAID
+		1000 3004  MegaRAID SATA 300-4X RAID Controller
+		1000 3008  MegaRAID SATA 300-8X RAID Controller
+		8086 3008  MegaRAID RAID Controller SRCS28X
+		8086 3431  MegaRAID RAID Controller Alief SROMBU42E
+		8086 3499  MegaRAID RAID Controller Harwich SROMBU42E
+	0621  FC909 Fibre Channel Adapter
+	0622  FC929 Fibre Channel Adapter
+		1000 1020  44929 O Dual Fibre Channel card
+	0623  FC929 LAN
+	0624  FC919 Fibre Channel Adapter
+	0625  FC919 LAN
+	0626  FC929X Fibre Channel Adapter
+		1000 1010  7202-XP-LC Dual Fibre Channel card
+	0627  FC929X LAN
+	0628  FC919X Fibre Channel Adapter
+	0629  FC919X LAN
+	0701  83C885 NT50 DigitalScape Fast Ethernet
+	0702  Yellowfin G-NIC gigabit ethernet
+		1318 0000  PEI100X
+	0804  SA2010
+	0805  SA2010ZC
+	0806  SA2020
+	0807  SA2020ZC
+	0901  61C102
+	1000  63C815
+	1960  MegaRAID
+		1000 0518  MegaRAID 518 SCSI 320-2 Controller
+		1000 0520  MegaRAID 520 SCSI 320-1 Controller
+		1000 0522  MegaRAID 522 i4 133 RAID Controller
+		1000 0523  MegaRAID SATA 150-6 RAID Controller
+		1000 4523  MegaRAID SATA 150-4 RAID Controller
+		1000 a520  MegaRAID ZCR SCSI 320-0 Controller
+		1028 0518  MegaRAID 518 DELL PERC 4/DC RAID Controller
+		1028 0520  MegaRAID 520 DELL PERC 4/SC RAID Controller
+		1028 0531  PowerEdge Expandable RAID Controller 4/QC
+		1028 0533  PowerEdge Expandable RAID Controller 4/QC
+		8086 0520  MegaRAIDRAID Controller SRCU41L
+		8086 0523  MegaRAID RAID Controller SRCS16
+1001  Kolter Electronic
+	0010  PCI 1616 Measurement card with 32 digital I/O lines
+	0011  OPTO-PCI Opto-Isolated digital I/O board
+	0012  PCI-AD/DA Analogue I/O board
+	0013  PCI-OPTO-RELAIS Digital I/O board with relay outputs
+	0014  PCI-Counter/Timer Counter Timer board
+	0015  PCI-DAC416 Analogue output board
+	0016  PCI-MFB Analogue I/O board
+	0017  PROTO-3 PCI Prototyping board
+	9100  INI-9100/9100W SCSI Host
+1002  ATI Technologies Inc
+	3150  M24 1P [Radeon Mobility X600]
+	3154  M24 1T [FireGL M24 GL]
+	3e50  RV380 0x3e50 [Radeon X600]
+	3e54  RV380 0x3e54 [FireGL V3200]
+	3e70  RV380 [Radeon X600] Secondary
+	4136  Radeon IGP 320 M
+	4137  Radeon IGP330/340/350
+	4144  R300 AD [Radeon 9500 Pro]
+# New PCI ID provided by ATI developer relations (correction to above)
+	4145  R300 AE [Radeon 9700 Pro]
+# New PCI ID provided by ATI developer relations (oops, correction to above)
+	4146  R300 AF [Radeon 9700 Pro]
+	4147  R300 AG [FireGL Z1/X1]
+	4148  R350 AH [Radeon 9800]
+	4149  R350 AI [Radeon 9800]
+	414a  R350 AJ [Radeon 9800]
+	414b  R350 AK [Fire GL X2]
+# New PCI ID provided by ATI developer relations
+	4150  RV350 AP [Radeon 9600]
+		1002 0002  R9600 Pro primary (Asus OEM for HP)
+		1002 0003  R9600 Pro secondary (Asus OEM for HP)
+		1458 4024  Giga-Byte GV-R96128D Primary
+		148c 2064  PowerColor R96A-C3N
+		148c 2066  PowerColor R96A-C3N
+		174b 7c19  Sapphire Atlantis Radeon 9600 Pro
+		174b 7c29  GC-R9600PRO Primary [Sapphire]
+		17ee 2002  Radeon 9600 256Mb Primary
+		18bc 0101  GC-R9600PRO Primary
+# New PCI ID provided by ATI developer relations
+	4151  RV350 AQ [Radeon 9600]
+		1043 c004  A9600SE
+# New PCI ID provided by ATI developer relations
+	4152  RV350 AR [Radeon 9600]
+		1002 0002  Radeon 9600XT
+		1043 c002  Radeon 9600 XT TVD
+		174b 7c29  Sapphire Radeon 9600XT
+		1787 4002  Radeon 9600 XT
+	4153  RV350 AS [Radeon 9600 AS]
+	4154  RV350 AT [Fire GL T2]
+	4155  RV350 AU [Fire GL T2]
+	4156  RV350 AV [Fire GL T2]
+	4157  RV350 AW [Fire GL T2]
+	4158  68800AX [Mach32]
+# The PCI ID is unrelated to any DVI output.
+	4164  R300 AD [Radeon 9500 Pro] (Secondary)
+# New PCI ID info provided by ATI developer relations
+	4165  R300 AE [Radeon 9700 Pro] (Secondary)
+# New PCI ID info provided by ATI developer relations
+	4166  R300 AF [Radeon 9700 Pro] (Secondary)
+# New PCI ID provided by ATI developer relations
+	4168  Radeon R350 [Radeon 9800] (Secondary)
+# New PCI ID provided by ATI developer relations (correction to above)
+	4170  RV350 AP [Radeon 9600] (Secondary)
+		1458 4025  Giga-Byte GV-R96128D Secondary
+		148c 2067  PowerColor R96A-C3N (Secondary)
+		174b 7c28  GC-R9600PRO Secondary [Sapphire]
+		17ee 2003  Radeon 9600 256Mb Secondary
+		18bc 0100  GC-R9600PRO Secondary
+# New PCI ID provided by ATI developer relations (correction to above)
+	4171  RV350 AQ [Radeon 9600] (Secondary)
+		1043 c005  A9600SE (Secondary)
+# New PCI ID provided by ATI developer relations (correction to above)
+	4172  RV350 AR [Radeon 9600] (Secondary)
+		1002 0003  Radeon 9600XT (Secondary)
+		1043 c003  A9600XT (Secondary)
+		174b 7c28  Sapphire Radeon 9600XT (Secondary)
+		1787 4003  Radeon 9600 XT (Secondary)
+	4173  RV350 ?? [Radeon 9550] (Secondary)
+	4237  Radeon 7000 IGP
+	4242  R200 BB [Radeon All in Wonder 8500DV]
+		1002 02aa  Radeon 8500 AIW DV Edition
+	4243  R200 BC [Radeon All in Wonder 8500]
+	4336  Radeon Mobility U1
+		103c 0024  Pavilion ze4400 builtin Video
+	4337  Radeon IGP 330M/340M/350M
+		1014 053a  ThinkPad R40e (2684-HVG) builtin VGA controller
+		103c 0850  Radeon IGP 345M
+	4341  IXP150 AC'97 Audio Controller
+	4345  EHCI USB Controller
+	4347  OHCI USB Controller #1
+	4348  OHCI USB Controller #2
+	4349  ATI Dual Channel Bus Master PCI IDE Controller
+	434d  IXP AC'97 Modem
+	4353  ATI SMBus
+	4354  215CT [Mach64 CT]
+	4358  210888CX [Mach64 CX]
+	4363  ATI SMBus
+	436e  ATI 436E Serial ATA Controller
+	4372  ATI SMBus
+	4376  Standard Dual Channel PCI IDE Controller ATI
+	4379  ATI 4379 Serial ATA Controller
+	437a  ATI 437A Serial ATA Controller
+	4437  Radeon Mobility 7000 IGP
+	4554  210888ET [Mach64 ET]
+	4654  Mach64 VT
+	4742  3D Rage Pro AGP 1X/2X
+		1002 0040  Rage Pro Turbo AGP 2X
+		1002 0044  Rage Pro Turbo AGP 2X
+		1002 0061  Rage Pro AIW AGP 2X
+		1002 0062  Rage Pro AIW AGP 2X
+		1002 0063  Rage Pro AIW AGP 2X
+		1002 0080  Rage Pro Turbo AGP 2X
+		1002 0084  Rage Pro Turbo AGP 2X
+		1002 4742  Rage Pro Turbo AGP 2X
+		1002 8001  Rage Pro Turbo AGP 2X
+		1028 0082  Rage Pro Turbo AGP 2X
+		1028 4082  Optiplex GX1 Onboard Display Adapter
+		1028 8082  Rage Pro Turbo AGP 2X
+		1028 c082  Rage Pro Turbo AGP 2X
+		8086 4152  Xpert 98D AGP 2X
+		8086 464a  Rage Pro Turbo AGP 2X
+	4744  3D Rage Pro AGP 1X
+		1002 4744  Rage Pro Turbo AGP
+	4747  3D Rage Pro
+	4749  3D Rage Pro
+		1002 0061  Rage Pro AIW
+		1002 0062  Rage Pro AIW
+	474c  Rage XC
+	474d  Rage XL AGP 2X
+		1002 0004  Xpert 98 RXL AGP 2X
+		1002 0008  Xpert 98 RXL AGP 2X
+		1002 0080  Rage XL AGP 2X
+		1002 0084  Xpert 98 AGP 2X
+		1002 474d  Rage XL AGP
+		1033 806a  Rage XL AGP
+	474e  Rage XC AGP
+		1002 474e  Rage XC AGP
+	474f  Rage XL
+		1002 0008  Rage XL
+		1002 474f  Rage XL
+	4750  3D Rage Pro 215GP
+		1002 0040  Rage Pro Turbo
+		1002 0044  Rage Pro Turbo
+		1002 0080  Rage Pro Turbo
+		1002 0084  Rage Pro Turbo
+		1002 4750  Rage Pro Turbo
+	4751  3D Rage Pro 215GQ
+	4752  Rage XL
+		1002 0008  Rage XL
+		1002 4752  Rage XL
+		1002 8008  Rage XL
+		1028 00ce  PowerEdge 1400
+		1028 00d1  PowerEdge 2550
+		1028 00d9  PowerEdge 2500
+		8086 3411  SDS2 Mainboard
+		8086 3427  S875WP1-E mainboard
+	4753  Rage XC
+		1002 4753  Rage XC
+	4754  3D Rage I/II 215GT [Mach64 GT]
+	4755  3D Rage II+ 215GTB [Mach64 GTB]
+	4756  3D Rage IIC 215IIC [Mach64 GT IIC]
+		1002 4756  Rage IIC
+	4757  3D Rage IIC AGP
+		1002 4757  Rage IIC AGP
+		1028 0089  Rage 3D IIC
+		1028 4082  Rage 3D IIC
+		1028 8082  Rage 3D IIC
+		1028 c082  Rage 3D IIC
+	4758  210888GX [Mach64 GX]
+	4759  3D Rage IIC
+	475a  3D Rage IIC AGP
+		1002 0084  Rage 3D Pro AGP 2x XPERT 98
+		1002 0087  Rage 3D IIC
+		1002 475a  Rage IIC AGP
+	4964  Radeon RV250 Id [Radeon 9000]
+	4965  Radeon RV250 Ie [Radeon 9000]
+	4966  Radeon RV250 If [Radeon 9000]
+		10f1 0002  RV250 If [Tachyon G9000 PRO]
+		148c 2039  RV250 If [Radeon 9000 Pro "Evil Commando"]
+		1509 9a00  RV250 If [Radeon 9000 "AT009"]
+# New subdevice - 3D Prophet 9000 PCI by Hercules. AGP version probably would have same ID, so not specified.
+		1681 0040  RV250 If [3D prophet 9000]
+		174b 7176  RV250 If [Sapphire Radeon 9000 Pro]
+		174b 7192  RV250 If [Radeon 9000 "Atlantis"]
+		17af 2005  RV250 If [Excalibur Radeon 9000 Pro]
+		17af 2006  RV250 If [Excalibur Radeon 9000]
+	4967  Radeon RV250 Ig [Radeon 9000]
+	496e  Radeon RV250 [Radeon 9000] (Secondary)
+	4a48  R420 JH [Radeon X800]
+	4a49  R420 JI [Radeon X800PRO]
+	4a4a  R420 JJ [Radeon X800SE]
+	4a4b  R420 JK [Radeon X800]
+	4a4c  R420 JL [Radeon X800]
+	4a4d  R420 JM [FireGL X3]
+	4a4e  M18 JN [Radeon Mobility 9800]
+	4a50  R420 JP [Radeon X800XT]
+	4a70  R420 [X800XT-PE] (Secondary)
+	4c42  3D Rage LT Pro AGP-133
+		0e11 b0e7  Rage LT Pro (Compaq Presario 5240)
+		0e11 b0e8  Rage 3D LT Pro
+		0e11 b10e  3D Rage LT Pro (Compaq Armada 1750)
+		1002 0040  Rage LT Pro AGP 2X
+		1002 0044  Rage LT Pro AGP 2X
+		1002 4c42  Rage LT Pro AGP 2X
+		1002 8001  Rage LT Pro AGP 2X
+		1028 0085  Rage 3D LT Pro
+	4c44  3D Rage LT Pro AGP-66
+	4c45  Rage Mobility M3 AGP
+	4c46  Rage Mobility M3 AGP 2x
+		1028 00b1  Latitude C600
+	4c47  3D Rage LT-G 215LG
+	4c49  3D Rage LT Pro
+		1002 0004  Rage LT Pro
+		1002 0040  Rage LT Pro
+		1002 0044  Rage LT Pro
+		1002 4c49  Rage LT Pro
+	4c4d  Rage Mobility P/M AGP 2x
+		0e11 b111  Armada M700
+		0e11 b160  Armada E500
+		1002 0084  Xpert 98 AGP 2X (Mobility)
+		1014 0154  ThinkPad A20m
+		1028 00aa  Latitude CPt
+		1028 00bb  Latitude CPx
+	4c4e  Rage Mobility L AGP 2x
+	4c50  3D Rage LT Pro
+		1002 4c50  Rage LT Pro
+	4c51  3D Rage LT Pro
+	4c52  Rage Mobility P/M
+		1033 8112  Versa Note VXi
+	4c53  Rage Mobility L
+	4c54  264LT [Mach64 LT]
+	4c57  Radeon Mobility M7 LW [Radeon Mobility 7500]
+		1014 0517  ThinkPad T30
+		1028 00e6  Radeon Mobility M7 LW (Dell Inspiron 8100)
+		1028 012a  Latitude C640
+		144d c006  Radeon Mobility M7 LW in vpr Matrix 170B4
+	4c58  Radeon RV200 LX [Mobility FireGL 7800 M7]
+	4c59  Radeon Mobility M6 LY
+		1014 0235  ThinkPad A30/A30p (2652/2653)
+		1014 0239  ThinkPad X22/X23/X24
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+	4c5a  Radeon Mobility M6 LZ
+	4c64  Radeon R250 Ld [Radeon Mobility 9000 M9]
+	4c65  Radeon R250 Le [Radeon Mobility 9000 M9]
+	4c66  Radeon R250 Lf [FireGL 9000]
+	4c67  Radeon R250 Lg [Radeon Mobility 9000 M9]
+# Secondary chip to the Lf
+	4c6e  Radeon R250 Ln [Radeon Mobility 9000 M9] [Secondary]
+	4d46  Rage Mobility M4 AGP
+	4d4c  Rage Mobility M4 AGP
+	4e44  Radeon R300 ND [Radeon 9700 Pro]
+	4e45  Radeon R300 NE [Radeon 9500 Pro]
+		1002 0002  Radeon R300 NE [Radeon 9500 Pro]
+		1681 0002  Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro]
+# New PCI ID provided by ATI developer relations (correction to above)
+	4e46  RV350 NF [Radeon 9600]
+	4e47  Radeon R300 NG [FireGL X1]
+# (added pro)
+	4e48  Radeon R350 [Radeon 9800 Pro]
+# New PCI ID provided by ATI developer relations
+	4e49  Radeon R350 [Radeon 9800]
+	4e4a  RV350 NJ [Radeon 9800 XT]
+	4e4b  R350 NK [Fire GL X2]
+# New PCI ID provided by ATI developer relations
+	4e50  RV350 [Mobility Radeon 9600 M10]
+		1025 005a  TravelMate 290
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1734 1055  Amilo M1420W
+	4e51  M10 NQ [Radeon Mobility 9600]
+	4e52  RV350 [Mobility Radeon 9600 M10]
+	4e53  M10 NS [Radeon Mobility 9600]
+	4e54  M10 NT [FireGL Mobility T2]
+	4e56  M11 NV [FireGL Mobility T2e]
+	4e64  Radeon R300 [Radeon 9700 Pro] (Secondary)
+	4e65  Radeon R300 [Radeon 9500 Pro] (Secondary)
+		1002 0003  Radeon R300 NE [Radeon 9500 Pro]
+		1681 0003  Hercules 3D Prophet 9500 PRO [Radeon 9500 Pro] (Secondary)
+# New PCI ID provided by ATI developer relations (correction to above)
+	4e66  RV350 NF [Radeon 9600] (Secondary)
+	4e67  Radeon R300 [FireGL X1] (Secondary)
+# (added pro)
+	4e68  Radeon R350 [Radeon 9800 Pro] (Secondary)
+# New PCI ID provided by ATI developer relations
+	4e69  Radeon R350 [Radeon 9800] (Secondary)
+	4e6a  RV350 NJ [Radeon 9800 XT] (Secondary)
+		1002 4e71  ATI Technologies Inc M10 NQ [Radeon Mobility 9600]
+	5041  Rage 128 PA/PRO
+	5042  Rage 128 PB/PRO AGP 2x
+	5043  Rage 128 PC/PRO AGP 4x
+	5044  Rage 128 PD/PRO TMDS
+		1002 0028  Rage 128 AIW
+		1002 0029  Rage 128 AIW
+	5045  Rage 128 PE/PRO AGP 2x TMDS
+	5046  Rage 128 PF/PRO AGP 4x TMDS
+		1002 0004  Rage Fury Pro
+		1002 0008  Rage Fury Pro/Xpert 2000 Pro
+		1002 0014  Rage Fury Pro
+		1002 0018  Rage Fury Pro/Xpert 2000 Pro
+		1002 0028  Rage 128 Pro AIW AGP
+		1002 002a  Rage 128 Pro AIW AGP
+		1002 0048  Rage Fury Pro
+		1002 2000  Rage Fury MAXX AGP 4x (TMDS) (VGA device)
+		1002 2001  Rage Fury MAXX AGP 4x (TMDS) (Extra device?!)
+	5047  Rage 128 PG/PRO
+	5048  Rage 128 PH/PRO AGP 2x
+	5049  Rage 128 PI/PRO AGP 4x
+	504a  Rage 128 PJ/PRO TMDS
+	504b  Rage 128 PK/PRO AGP 2x TMDS
+	504c  Rage 128 PL/PRO AGP 4x TMDS
+	504d  Rage 128 PM/PRO
+	504e  Rage 128 PN/PRO AGP 2x
+	504f  Rage 128 PO/PRO AGP 4x
+	5050  Rage 128 PP/PRO TMDS [Xpert 128]
+		1002 0008  Xpert 128
+	5051  Rage 128 PQ/PRO AGP 2x TMDS
+	5052  Rage 128 PR/PRO AGP 4x TMDS
+	5053  Rage 128 PS/PRO
+	5054  Rage 128 PT/PRO AGP 2x
+	5055  Rage 128 PU/PRO AGP 4x
+	5056  Rage 128 PV/PRO TMDS
+	5057  Rage 128 PW/PRO AGP 2x TMDS
+	5058  Rage 128 PX/PRO AGP 4x TMDS
+	5144  Radeon R100 QD [Radeon 7200]
+		1002 0008  Radeon 7000/Radeon VE
+		1002 0009  Radeon 7000/Radeon
+		1002 000a  Radeon 7000/Radeon
+		1002 001a  Radeon 7000/Radeon
+		1002 0029  Radeon AIW
+		1002 0038  Radeon 7000/Radeon
+		1002 0039  Radeon 7000/Radeon
+		1002 008a  Radeon 7000/Radeon
+		1002 00ba  Radeon 7000/Radeon
+		1002 0139  Radeon 7000/Radeon
+		1002 028a  Radeon 7000/Radeon
+		1002 02aa  Radeon AIW
+		1002 053a  Radeon 7000/Radeon
+	5145  Radeon R100 QE
+	5146  Radeon R100 QF
+	5147  Radeon R100 QG
+	5148  Radeon R200 QH [Radeon 8500]
+		1002 010a  FireGL 8800 64Mb
+		1002 0152  FireGL 8800 128Mb
+		1002 0162  FireGL 8700 32Mb
+		1002 0172  FireGL 8700 64Mb
+	5149  Radeon R200 QI
+	514a  Radeon R200 QJ
+	514b  Radeon R200 QK
+	514c  Radeon R200 QL [Radeon 8500 LE]
+		1002 003a  Radeon R200 QL [Radeon 8500 LE]
+		1002 013a  Radeon 8500
+		148c 2026  R200 QL [Radeon 8500 Evil Master II Multi Display Edition]
+		1681 0010  Radeon 8500 [3D Prophet 8500 128Mb]
+		174b 7149  Radeon R200 QL [Sapphire Radeon 8500 LE]
+	514d  Radeon R200 QM [Radeon 9100]
+	514e  Radeon R200 QN [Radeon 8500LE]
+	514f  Radeon R200 QO [Radeon 8500LE]
+	5154  R200 QT [Radeon 8500]
+	5155  R200 QU [Radeon 9100]
+	5157  Radeon RV200 QW [Radeon 7500]
+		1002 013a  Radeon 7500
+		1002 103a  Dell Optiplex GX260
+		1458 4000  RV200 QW [RADEON 7500 PRO MAYA AR]
+		148c 2024  RV200 QW [Radeon 7500LE Dual Display]
+		148c 2025  RV200 QW [Radeon 7500 Evil Master Multi Display Edition]
+		148c 2036  RV200 QW [Radeon 7500 PCI Dual Display]
+		174b 7146  RV200 QW [Radeon 7500 LE]
+		174b 7147  RV200 QW [Sapphire Radeon 7500LE]
+		174b 7161  Radeon RV200 QW [Radeon 7500 LE]
+		17af 0202  RV200 QW [Excalibur Radeon 7500LE]
+	5158  Radeon RV200 QX [Radeon 7500]
+	5159  Radeon RV100 QY [Radeon 7000/VE]
+		1002 000a  Radeon 7000/Radeon VE
+		1002 000b  Radeon 7000
+		1002 0038  Radeon 7000/Radeon VE
+		1002 003a  Radeon 7000/Radeon VE
+		1002 00ba  Radeon 7000/Radeon VE
+		1002 013a  Radeon 7000/Radeon VE
+		1458 4002  RV100 QY [RADEON 7000 PRO MAYA AV Series]
+		148c 2003  RV100 QY [Radeon 7000 Multi-Display Edition]
+		148c 2023  RV100 QY [Radeon 7000 Evil Master Multi-Display]
+		174b 7112  RV100 QY [Sapphire Radeon VE 7000]
+		174b 7c28  Sapphire Radeon VE 7000 DDR
+		1787 0202  RV100 QY [Excalibur Radeon 7000]
+	515a  Radeon RV100 QZ [Radeon 7000/VE]
+	5168  Radeon R200 Qh
+	5169  Radeon R200 Qi
+	516a  Radeon R200 Qj
+	516b  Radeon R200 Qk
+# This one is not in ATI documentation, but is in XFree86 source code
+	516c  Radeon R200 Ql
+	5245  Rage 128 RE/SG
+		1002 0008  Xpert 128
+		1002 0028  Rage 128 AIW
+		1002 0029  Rage 128 AIW
+		1002 0068  Rage 128 AIW
+	5246  Rage 128 RF/SG AGP
+		1002 0004  Magnum/Xpert 128/Xpert 99
+		1002 0008  Magnum/Xpert128/X99/Xpert2000
+		1002 0028  Rage 128 AIW AGP
+		1002 0044  Rage Fury/Xpert 128/Xpert 2000
+		1002 0068  Rage 128 AIW AGP
+		1002 0448  Rage Fury
+	5247  Rage 128 RG
+	524b  Rage 128 RK/VR
+	524c  Rage 128 RL/VR AGP
+		1002 0008  Xpert 99/Xpert 2000
+		1002 0088  Xpert 99
+	5345  Rage 128 SE/4x
+	5346  Rage 128 SF/4x AGP 2x
+		1002 0048  RAGE 128 16MB VGA TVOUT AMC PAL
+	5347  Rage 128 SG/4x AGP 4x
+	5348  Rage 128 SH
+	534b  Rage 128 SK/4x
+	534c  Rage 128 SL/4x AGP 2x
+	534d  Rage 128 SM/4x AGP 4x
+		1002 0008  Xpert 99/Xpert 2000
+		1002 0018  Xpert 2000
+	534e  Rage 128 4x
+	5354  Mach 64 VT
+		1002 5654  Mach 64 reference
+	5446  Rage 128 Pro Ultra TF
+		1002 0004  Rage Fury Pro
+		1002 0008  Rage Fury Pro/Xpert 2000 Pro
+		1002 0018  Rage Fury Pro/Xpert 2000 Pro
+		1002 0028  Rage 128 AIW Pro AGP
+		1002 0029  Rage 128 AIW
+		1002 002a  Rage 128 AIW Pro AGP
+		1002 002b  Rage 128 AIW
+		1002 0048  Xpert 2000 Pro
+	544c  Rage 128 Pro Ultra TL
+	5452  Rage 128 Pro Ultra TR
+		1002 001c  Rage 128 Pro 4XL
+		103c 1279  Rage 128 Pro 4XL
+	5453  Rage 128 Pro Ultra TS
+	5454  Rage 128 Pro Ultra TT
+	5455  Rage 128 Pro Ultra TU
+	5460  M22 [Radeon Mobility M300]
+	5464  M22 [FireGL GL]
+	5548  R423 UH [Radeon X800 (PCIE)]
+	5549  R423 UI [Radeon X800PRO (PCIE)]
+	554a  R423 UJ [Radeon X800LE (PCIE)]
+	554b  R423 UK [Radeon X800SE (PCIE)]
+	5551  R423 UQ [FireGL V7200 (PCIE)]
+	5552  R423 UR [FireGL V5100 (PCIE)]
+	5554  R423 UT [FireGL V7100 (PCIE)]
+	556b  Radeon R423 UK (PCIE) [X800 SE] (Secondary)
+	5654  264VT [Mach64 VT]
+		1002 5654  Mach64VT Reference
+	5655  264VT3 [Mach64 VT3]
+	5656  264VT4 [Mach64 VT4]
+	5830  RS300 Host Bridge
+	5831  RS300 Host Bridge
+	5832  RS300 Host Bridge
+	5833  Radeon 9100 IGP Host Bridge
+	5834  Radeon 9100 IGP
+	5835  RS300M AGP [Radeon Mobility 9100IGP]
+	5838  Radeon 9100 IGP AGP Bridge
+	5941  RV280 [Radeon 9200] (Secondary)
+		1458 4019  Gigabyte Radeon 9200
+		174b 7c12  Sapphire Radeon 9200
+# http://www.hightech.com.hk/html/9200.htm
+		17af 200d  Excalibur Radeon 9200
+		18bc 0050  GeXcube GC-R9200-C3 (Secondary)
+	5944  RV280 [Radeon 9200 SE (PCI)]
+	5960  RV280 [Radeon 9200 PRO]
+	5961  RV280 [Radeon 9200]
+		1002 2f72  All-in-Wonder 9200 Series
+		1019 4c30  Radeon 9200 VIVO
+		12ab 5961  YUAN SMARTVGA Radeon 9200
+		1458 4018  Gigabyte Radeon 9200
+		174b 7c13  Sapphire Radeon 9200
+# http://www.hightech.com.hk/html/9200.htm
+		17af 200c  Excalibur Radeon 9200
+		18bc 0050  Radeon 9200 Game Buster
+		18bc 0051  GeXcube GC-R9200-C3
+		18bc 0053  Radeon 9200 Game Buster VIVO
+	5962  RV280 [Radeon 9200]
+	5964  RV280 [Radeon 9200 SE]
+		1043 c006  ASUS Radeon 9200 SE / TD / 128M
+		1458 4018  Radeon 9200 SE
+		148c 2073  CN-AG92E
+		174b 7c13  Sapphire Radeon 9200 SE
+		1787 5964  Excalibur 9200SE VIVO 128M
+		17af 2012  Radeon 9200 SE Excalibur
+		18bc 0170  Sapphire Radeon 9200 SE 128MB Game Buster
+# 128MB DDR, DVI/VGA/TV out
+		18bc 0173  GC-R9200L(SE)-C3H [Radeon 9200 Game Buster]
+	5b60  RV370 5B60 [Radeon X300 (PCIE)]
+		1043 002a  Extreme AX300SE-X
+		1043 032e  Extreme AX300/TD
+	5b62  RV370 5B62 [Radeon X600 (PCIE)]
+	5b64  RV370 5B64 [FireGL V3100 (PCIE)]
+	5b65  RV370 5B65 [FireGL D1100 (PCIE)]
+	5c61  M9+ 5C61 [Radeon Mobility 9200 (AGP)]
+	5c63  M9+ 5C63 [Radeon Mobility 9200 (AGP)]
+	5d44  RV280 [Radeon 9200 SE] (Secondary)
+		1458 4019  Radeon 9200 SE (Secondary)
+		174b 7c12  Sapphire Radeon 9200 SE (Secondary)
+		1787 5965  Excalibur 9200SE VIVO 128M (Secondary)
+		17af 2013  Radeon 9200 SE Excalibur (Secondary)
+		18bc 0171  Radeon 9200 SE 128MB Game Buster (Secondary)
+		18bc 0172  GC-R9200L(SE)-C3H [Radeon 9200 Game Buster]
+	5d4d  R480 [Radeon X850XT Platinum]
+	5d57  R423 5F57 [Radeon X800XT (PCIE)]
+	700f  PCI Bridge [IGP 320M]
+	7010  PCI Bridge [IGP 340M]
+	7834  Radeon 9100 PRO IGP
+	7835  Radeon Mobility 9200 IGP
+	7c37  RV350 AQ [Radeon 9600 SE]
+	cab0  AGP Bridge [IGP 320M]
+	cab2  RS200/RS200M AGP Bridge [IGP 340M]
+	cbb2  RS200/RS200M AGP Bridge [IGP 340M]
+1003  ULSI Systems
+	0201  US201
+1004  VLSI Technology Inc
+	0005  82C592-FC1
+	0006  82C593-FC1
+	0007  82C594-AFC2
+	0008  82C596/7 [Wildcat]
+	0009  82C597-AFC2
+	000c  82C541 [Lynx]
+	000d  82C543 [Lynx]
+	0101  82C532
+	0102  82C534 [Eagle]
+	0103  82C538
+	0104  82C535
+	0105  82C147
+	0200  82C975
+	0280  82C925
+	0304  QSound ThunderBird PCI Audio
+		1004 0304  QSound ThunderBird PCI Audio
+		122d 1206  DSP368 Audio
+		1483 5020  XWave Thunder 3D Audio
+	0305  QSound ThunderBird PCI Audio Gameport
+		1004 0305  QSound ThunderBird PCI Audio Gameport
+		122d 1207  DSP368 Audio Gameport
+		1483 5021  XWave Thunder 3D Audio Gameport
+	0306  QSound ThunderBird PCI Audio Support Registers
+		1004 0306  QSound ThunderBird PCI Audio Support Registers
+		122d 1208  DSP368 Audio Support Registers
+		1483 5022  XWave Thunder 3D Audio Support Registers
+	0307  Thunderbird
+	0308  Thunderbird
+	0702  VAS96011 [Golden Gate II]
+	0703  Tollgate
+1005  Avance Logic Inc. [ALI]
+	2064  ALG2032/2064
+	2128  ALG2364A
+	2301  ALG2301
+	2302  ALG2302
+	2364  ALG2364
+	2464  ALG2364A
+	2501  ALG2564A/25128A
+1006  Reply Group
+1007  NetFrame Systems Inc
+1008  Epson
+100a  Phoenix Technologies
+100b  National Semiconductor Corporation
+	0001  DP83810
+	0002  87415/87560 IDE
+	000e  87560 Legacy I/O
+	000f  FireWire Controller
+	0011  NS87560 National PCI System I/O
+	0012  USB Controller
+	0020  DP83815 (MacPhyter) Ethernet Controller
+		103c 0024  Pavilion ze4400 builtin Network
+		1385 f311  FA311 / FA312 (FA311 with WoL HW)
+	0022  DP83820 10/100/1000 Ethernet Controller
+	0028  Geode GX2 Host Bridge
+	002a  CS5535 South Bridge
+	002b  CS5535 ISA bridge
+	002d  CS5535 IDE
+	002e  CS5535 Audio
+	002f  CS5535 USB
+	0030  Geode GX2 Graphics Processor
+	0035  DP83065 [Saturn] 10/100/1000 Ethernet Controller
+	0500  SCx200 Bridge
+	0501  SCx200 SMI
+	0502  SCx200 IDE
+	0503  SCx200 Audio
+	0504  SCx200 Video
+	0505  SCx200 XBus
+	0510  SC1100 Bridge
+	0511  SC1100 SMI
+	0515  SC1100 XBus
+	d001  87410 IDE
+100c  Tseng Labs Inc
+	3202  ET4000/W32p rev A
+	3205  ET4000/W32p rev B
+	3206  ET4000/W32p rev C
+	3207  ET4000/W32p rev D
+	3208  ET6000
+	4702  ET6300
+100d  AST Research Inc
+100e  Weitek
+	9000  P9000 Viper
+	9001  P9000 Viper
+	9002  P9000 Viper
+	9100  P9100 Viper Pro/SE
+1010  Video Logic, Ltd.
+1011  Digital Equipment Corporation
+	0001  DECchip 21050
+	0002  DECchip 21040 [Tulip]
+	0004  DECchip 21030 [TGA]
+	0007  NVRAM [Zephyr NVRAM]
+	0008  KZPSA [KZPSA]
+	0009  DECchip 21140 [FasterNet]
+		1025 0310  21140 Fast Ethernet
+		10b8 2001  SMC9332BDT EtherPower 10/100
+		10b8 2002  SMC9332BVT EtherPower T4 10/100
+		10b8 2003  SMC9334BDT EtherPower 10/100 (1-port)
+		1109 2400  ANA-6944A/TX Fast Ethernet
+		1112 2300  RNS2300 Fast Ethernet
+		1112 2320  RNS2320 Fast Ethernet
+		1112 2340  RNS2340 Fast Ethernet
+		1113 1207  EN-1207-TX Fast Ethernet
+		1186 1100  DFE-500TX Fast Ethernet
+		1186 1112  DFE-570TX Fast Ethernet
+		1186 1140  DFE-660 Cardbus Ethernet 10/100
+		1186 1142  DFE-660 Cardbus Ethernet 10/100
+		11f6 0503  Freedomline Fast Ethernet
+		1282 9100  AEF-380TXD Fast Ethernet
+		1385 1100  FA310TX Fast Ethernet
+		2646 0001  KNE100TX Fast Ethernet
+	000a  21230 Video Codec
+	000d  PBXGB [TGA2]
+	000f  DEFPA
+	0014  DECchip 21041 [Tulip Pass 3]
+		1186 0100  DE-530+
+	0016  DGLPB [OPPO]
+	0017  PV-PCI Graphics Controller (ZLXp-L)
+	0019  DECchip 21142/43
+		1011 500a  DE500A Fast Ethernet
+		1011 500b  DE500B Fast Ethernet
+		1014 0001  10/100 EtherJet Cardbus
+		1025 0315  ALN315 Fast Ethernet
+		1033 800c  PC-9821-CS01 100BASE-TX Interface Card
+		1033 800d  PC-9821NR-B06 100BASE-TX Interface Card
+		108d 0016  Rapidfire 2327 10/100 Ethernet
+		108d 0017  GoCard 2250 Ethernet 10/100 Cardbus
+		10b8 2005  SMC8032DT Extreme Ethernet 10/100
+		10b8 8034  SMC8034 Extreme Ethernet 10/100
+		10ef 8169  Cardbus Fast Ethernet
+		1109 2a00  ANA-6911A/TX Fast Ethernet
+		1109 2b00  ANA-6911A/TXC Fast Ethernet
+		1109 3000  ANA-6922/TX Fast Ethernet
+		1113 1207  Cheetah Fast Ethernet
+		1113 2220  Cardbus Fast Ethernet
+		115d 0002  Cardbus Ethernet 10/100
+		1179 0203  Fast Ethernet
+		1179 0204  Cardbus Fast Ethernet
+		1186 1100  DFE-500TX Fast Ethernet
+		1186 1101  DFE-500TX Fast Ethernet
+		1186 1102  DFE-500TX Fast Ethernet
+		1186 1112  DFE-570TX Quad Fast Ethernet
+		1259 2800  AT-2800Tx Fast Ethernet
+		1266 0004  Eagle Fast EtherMAX
+		12af 0019  NetFlyer Cardbus Fast Ethernet
+		1374 0001  Cardbus Ethernet Card 10/100
+		1374 0002  Cardbus Ethernet Card 10/100
+		1374 0007  Cardbus Ethernet Card 10/100
+		1374 0008  Cardbus Ethernet Card 10/100
+		1385 2100  FA510
+		1395 0001  10/100 Ethernet CardBus PC Card
+		13d1 ab01  EtherFast 10/100 Cardbus (PCMPC200)
+		14cb 0100  LNDL-100N 100Base-TX Ethernet PC Card
+		8086 0001  EtherExpress PRO/100 Mobile CardBus 32
+	001a  Farallon PN9000SX Gigabit Ethernet
+	0021  DECchip 21052
+	0022  DECchip 21150
+	0023  DECchip 21150
+	0024  DECchip 21152
+	0025  DECchip 21153
+	0026  DECchip 21154
+	0034  56k Modem Cardbus
+		1374 0003  56k Modem Cardbus
+	0045  DECchip 21553
+	0046  DECchip 21554
+		0e11 4050  Integrated Smart Array
+		0e11 4051  Integrated Smart Array
+		0e11 4058  Integrated Smart Array
+		103c 10c2  Hewlett-Packard NetRAID-4M
+		12d9 000a  IP Telephony card
+		4c53 1050  CT7 mainboard
+		4c53 1051  CE7 mainboard
+		9005 0364  5400S (Mustang)
+		9005 0365  5400S (Mustang)
+		9005 1364  Dell PowerEdge RAID Controller 2
+		9005 1365  Dell PowerEdge RAID Controller 2
+		e4bf 1000  CC8-1-BLUES
+	1065  StrongARM DC21285
+		1069 0020  DAC960P / DAC1164P
+1012  Micronics Computers Inc
+1013  Cirrus Logic
+	0038  GD 7548
+	0040  GD 7555 Flat Panel GUI Accelerator
+	004c  GD 7556 Video/Graphics LCD/CRT Ctrlr
+	00a0  GD 5430/40 [Alpine]
+	00a2  GD 5432 [Alpine]
+	00a4  GD 5434-4 [Alpine]
+	00a8  GD 5434-8 [Alpine]
+	00ac  GD 5436 [Alpine]
+	00b0  GD 5440
+	00b8  GD 5446
+	00bc  GD 5480
+		1013 00bc  CL-GD5480
+	00d0  GD 5462
+	00d2  GD 5462 [Laguna I]
+	00d4  GD 5464 [Laguna]
+	00d5  GD 5464 BD [Laguna]
+	00d6  GD 5465 [Laguna]
+		13ce 8031  Barco Metheus 2 Megapixel, Dual Head
+		13cf 8031  Barco Metheus 2 Megapixel, Dual Head
+	00e8  GD 5436U
+	1100  CL 6729
+	1110  PD 6832 PCMCIA/CardBus Ctrlr
+	1112  PD 6834 PCMCIA/CardBus Ctrlr
+	1113  PD 6833 PCMCIA/CardBus Ctrlr
+	1200  GD 7542 [Nordic]
+	1202  GD 7543 [Viking]
+	1204  GD 7541 [Nordic Light]
+	4000  MD 5620 [CLM Data Fax Voice]
+	4400  CD 4400
+	6001  CS 4610/11 [CrystalClear SoundFusion Audio Accelerator]
+		1014 1010  CS4610 SoundFusion Audio Accelerator
+	6003  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
+		1013 4280  Crystal SoundFusion PCI Audio Accelerator
+		153b 1136  SiXPack 5.1+
+		1681 0050  Game Theater XP
+		1681 a011  Fortissimo III 7.1
+	6004  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
+	6005  Crystal CS4281 PCI Audio
+		1013 4281  Crystal CS4281 PCI Audio
+		10cf 10a8  Crystal CS4281 PCI Audio
+		10cf 10a9  Crystal CS4281 PCI Audio
+		10cf 10aa  Crystal CS4281 PCI Audio
+		10cf 10ab  Crystal CS4281 PCI Audio
+		10cf 10ac  Crystal CS4281 PCI Audio
+		10cf 10ad  Crystal CS4281 PCI Audio
+		10cf 10b4  Crystal CS4281 PCI Audio
+		1179 0001  Crystal CS4281 PCI Audio
+		14c0 000c  Crystal CS4281 PCI Audio
+1014  IBM
+	0002  PCI to MCA Bridge
+	0005  Alta Lite
+	0007  Alta MP
+	000a  Fire Coral
+	0017  CPU to PCI Bridge
+	0018  TR Auto LANstreamer
+	001b  GXT-150P
+	001c  Carrera
+	001d  82G2675
+	0020  GXT1000 Graphics Adapter
+	0022  IBM27-82351
+	002d  Python
+# [official name in AIX 5]
+	002e  SCSI RAID Adapter [ServeRAID]
+		1014 002e  ServeRAID-3x
+		1014 022e  ServeRAID-4H
+	0031  2 Port Serial Adapter
+# AS400 iSeries PCI sync serial card
+		1014 0031  2721 WAN IOA - 2 Port Sync Serial Adapter
+	0036  Miami
+	0037  82660 CPU to PCI Bridge
+	003a  CPU to PCI Bridge
+	003c  GXT250P/GXT255P Graphics Adapter
+	003e  16/4 Token ring UTP/STP controller
+		1014 003e  Token-Ring Adapter
+		1014 00cd  Token-Ring Adapter + Wake-On-LAN
+		1014 00ce  16/4 Token-Ring Adapter 2
+		1014 00cf  16/4 Token-Ring Adapter Special
+		1014 00e4  High-Speed 100/16/4 Token-Ring Adapter
+		1014 00e5  16/4 Token-Ring Adapter 2 + Wake-On-LAN
+		1014 016d  iSeries 2744 Card
+	0045  SSA Adapter
+	0046  MPIC interrupt controller
+	0047  PCI to PCI Bridge
+	0048  PCI to PCI Bridge
+	0049  Warhead SCSI Controller
+	004e  ATM Controller (14104e00)
+	004f  ATM Controller (14104f00)
+	0050  ATM Controller (14105000)
+	0053  25 MBit ATM Controller
+	0054  GXT500P/GXT550P Graphics Adapter
+	0057  MPEG PCI Bridge
+	005c  i82557B 10/100
+	005e  GXT800P Graphics Adapter
+	007c  ATM Controller (14107c00)
+	007d  3780IDSP [MWave]
+	008b  EADS PCI to PCI Bridge
+	008e  GXT3000P Graphics Adapter
+	0090  GXT 3000P
+		1014 008e  GXT-3000P
+	0091  SSA Adapter
+	0095  20H2999 PCI Docking Bridge
+	0096  Chukar chipset SCSI controller
+		1014 0097  iSeries 2778 DASD IOA
+		1014 0098  iSeries 2763 DASD IOA
+		1014 0099  iSeries 2748 DASD IOA
+	009f  PCI 4758 Cryptographic Accelerator
+	00a5  ATM Controller (1410a500)
+	00a6  ATM 155MBPS MM Controller (1410a600)
+	00b7  256-bit Graphics Rasterizer [Fire GL1]
+		1092 00b8  FireGL1 AGP 32Mb
+	00b8  GXT2000P Graphics Adapter
+	00be  ATM 622MBPS Controller (1410be00)
+	00dc  Advanced Systems Management Adapter (ASMA)
+	00fc  CPC710 Dual Bridge and Memory Controller (PCI-64)
+	0104  Gigabit Ethernet-SX Adapter
+	0105  CPC710 Dual Bridge and Memory Controller (PCI-32)
+	010f  Remote Supervisor Adapter (RSA)
+	0142  Yotta Video Compositor Input
+		1014 0143  Yotta Input Controller (ytin)
+	0144  Yotta Video Compositor Output
+		1014 0145  Yotta Output Controller (ytout)
+	0156  405GP PLB to PCI Bridge
+	015e  622Mbps ATM PCI Adapter
+	0160  64bit/66MHz PCI ATM 155 MMF
+	016e  GXT4000P Graphics Adapter
+	0170  GXT6000P Graphics Adapter
+	017d  GXT300P Graphics Adapter
+	0180  Snipe chipset SCSI controller
+		1014 0241  iSeries 2757 DASD IOA
+		1014 0264  Quad Channel PCI-X U320 SCSI RAID Adapter (2780)
+	0188  EADS-X PCI-X to PCI-X Bridge
+	01a7  PCI-X to PCI-X Bridge
+	01bd  ServeRAID Controller
+		1014 01be  ServeRAID-4M
+		1014 01bf  ServeRAID-4L
+		1014 0208  ServeRAID-4Mx
+		1014 020e  ServeRAID-4Lx
+		1014 022e  ServeRAID-4H
+		1014 0258  ServeRAID-5i
+		1014 0259  ServeRAID-5i
+	01c1  64bit/66MHz PCI ATM 155 UTP
+	01e6  Cryptographic Accelerator
+	01ff  10/100 Mbps Ethernet
+	0219  Multiport Serial Adapter
+		1014 021a  Dual RVX
+		1014 0251  Internal Modem/RVX
+		1014 0252  Quad Internal Modem
+	021b  GXT6500P Graphics Adapter
+	021c  GXT4500P Graphics Adapter
+	0233  GXT135P Graphics Adapter
+	0266  PCI-X Dual Channel SCSI
+	0268  Gigabit Ethernet-SX Adapter (PCI-X)
+	0269  10/100/1000 Base-TX Ethernet Adapter (PCI-X)
+	028c  Citrine chipset SCSI controller
+		1014 028D  Dual Channel PCI-X DDR SAS RAID Adapter (572E)
+		1014 02BE  Dual Channel PCI-X DDR U320 SCSI RAID Adapter (571B)
+		1014 02C0  Dual Channel PCI-X DDR U320 SCSI Adapter (571A)
+	0302  X-Architecture Bridge [Summit]
+	0314  ZISC 036 Neural accelerator card
+	ffff  MPIC-2 interrupt controller
+1015  LSI Logic Corp of Canada
+1016  ICL Personal Systems
+1017  SPEA Software AG
+	5343  SPEA 3D Accelerator
+1018  Unisys Systems
+1019  Elitegroup Computer Systems
+101a  AT&T GIS (NCR)
+	0005  100VG ethernet
+101b  Vitesse Semiconductor
+101c  Western Digital
+	0193  33C193A
+	0196  33C196A
+	0197  33C197A
+	0296  33C296A
+	3193  7193
+	3197  7197
+	3296  33C296A
+	4296  34C296
+	9710  Pipeline 9710
+	9712  Pipeline 9712
+	c24a  90C
+101e  American Megatrends Inc.
+	1960  MegaRAID
+		101e 0471  MegaRAID 471 Enterprise 1600 RAID Controller
+		101e 0475  MegaRAID 475 Express 500/500LC RAID Controller
+		101e 0477  MegaRAID 477 Elite 3100 RAID Controller
+		101e 0493  MegaRAID 493 Elite 1600 RAID Controller
+		101e 0494  MegaRAID 494 Elite 1650 RAID Controller
+		101e 0503  MegaRAID 503 Enterprise 1650 RAID Controller
+		101e 0511  MegaRAID 511 i4 IDE RAID Controller
+		101e 0522  MegaRAID 522 i4133 RAID Controller
+		1028 0471  PowerEdge RAID Controller 3/QC
+		1028 0475  PowerEdge RAID Controller 3/SC
+		1028 0493  PowerEdge RAID Controller 3/DC
+		1028 0511  PowerEdge Cost Effective RAID Controller ATA100/4Ch
+	9010  MegaRAID 428 Ultra RAID Controller
+	9030  EIDE Controller
+	9031  EIDE Controller
+	9032  EIDE & SCSI Controller
+	9033  SCSI Controller
+	9040  Multimedia card
+	9060  MegaRAID 434 Ultra GT RAID Controller
+	9063  MegaRAC
+		101e 0767  Dell Remote Assistant Card 2
+101f  PictureTel
+1020  Hitachi Computer Products
+1021  OKI Electric Industry Co. Ltd.
+1022  Advanced Micro Devices [AMD]
+	1100  K8 [Athlon64/Opteron] HyperTransport Technology Configuration
+	1101  K8 [Athlon64/Opteron] Address Map
+	1102  K8 [Athlon64/Opteron] DRAM Controller
+	1103  K8 [Athlon64/Opteron] Miscellaneous Control
+	2000  79c970 [PCnet32 LANCE]
+		1014 2000  NetFinity 10/100 Fast Ethernet
+		1022 2000  PCnet - Fast 79C971
+		103c 104c  Ethernet with LAN remote power Adapter
+		103c 1064  Ethernet with LAN remote power Adapter
+		103c 1065  Ethernet with LAN remote power Adapter
+		103c 106c  Ethernet with LAN remote power Adapter
+		103c 106e  Ethernet with LAN remote power Adapter
+		103c 10ea  Ethernet with LAN remote power Adapter
+		1113 1220  EN1220 10/100 Fast Ethernet
+		1259 2450  AT-2450 10/100 Fast Ethernet
+		1259 2454  AT-2450v4 10Mb Ethernet Adapter
+		1259 2700  AT-2700TX 10/100 Fast Ethernet
+		1259 2701  AT-2700FX 100Mb Ethernet
+		4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard
+		4c53 1010  CP5/CR6 mainboard
+		4c53 1020  VR6 mainboard
+		4c53 1030  PC5 mainboard
+		4c53 1040  CL7 mainboard
+		4c53 1060  PC7 mainboard
+	2001  79c978 [HomePNA]
+		1092 0a78  Multimedia Home Network Adapter
+		1668 0299  ActionLink Home Network Adapter
+	2003  Am 1771 MBW [Alchemy]
+	2020  53c974 [PCscsi]
+	2040  79c974
+	3000  ELanSC520 Microcontroller
+	7006  AMD-751 [Irongate] System Controller
+	7007  AMD-751 [Irongate] AGP Bridge
+	700a  AMD-IGR4 AGP Host to PCI Bridge
+	700b  AMD-IGR4 PCI to PCI Bridge
+	700c  AMD-760 MP [IGD4-2P] System Controller
+	700d  AMD-760 MP [IGD4-2P] AGP Bridge
+	700e  AMD-760 [IGD4-1P] System Controller
+	700f  AMD-760 [IGD4-1P] AGP Bridge
+	7400  AMD-755 [Cobra] ISA
+	7401  AMD-755 [Cobra] IDE
+	7403  AMD-755 [Cobra] ACPI
+	7404  AMD-755 [Cobra] USB
+	7408  AMD-756 [Viper] ISA
+	7409  AMD-756 [Viper] IDE
+	740b  AMD-756 [Viper] ACPI
+	740c  AMD-756 [Viper] USB
+	7410  AMD-766 [ViperPlus] ISA
+	7411  AMD-766 [ViperPlus] IDE
+	7413  AMD-766 [ViperPlus] ACPI
+	7414  AMD-766 [ViperPlus] USB
+	7440  AMD-768 [Opus] ISA
+		1043 8044  A7M-D Mainboard
+	7441  AMD-768 [Opus] IDE
+	7443  AMD-768 [Opus] ACPI
+		1043 8044  A7M-D Mainboard
+	7445  AMD-768 [Opus] Audio
+	7446  AMD-768 [Opus] MC97 Modem (Smart Link HAMR5600 compatible)
+	7448  AMD-768 [Opus] PCI
+	7449  AMD-768 [Opus] USB
+	7450  AMD-8131 PCI-X Bridge
+	7451  AMD-8131 PCI-X APIC
+	7454  AMD-8151 System Controller
+	7455  AMD-8151 AGP Bridge
+	7460  AMD-8111 PCI
+		161f 3017  HDAMB
+	7461  AMD-8111 USB
+	7462  AMD-8111 Ethernet
+	7464  AMD-8111 USB
+		161f 3017  HDAMB
+	7468  AMD-8111 LPC
+		161f 3017  HDAMB
+	7469  AMD-8111 IDE
+		161f 3017  HDAMB
+	746a  AMD-8111 SMBus 2.0
+	746b  AMD-8111 ACPI
+		161f 3017  HDAMB
+	746d  AMD-8111 AC97 Audio
+		161f 3017  HDAMB
+	746e  AMD-8111 MC97 Modem
+	756b  AMD-8111 ACPI
+1023  Trident Microsystems
+	0194  82C194
+	2000  4DWave DX
+	2001  4DWave NX
+		122d 1400  Trident PCI288-Q3DII (NX)
+	2100  CyberBlade XP4m32
+	2200  XGI Volari XP5
+	8400  CyberBlade/i7
+		1023 8400  CyberBlade i7 AGP
+	8420  CyberBlade/i7d
+		0e11 b15a  CyberBlade i7 AGP
+	8500  CyberBlade/i1
+	8520  CyberBlade i1
+		0e11 b16e  CyberBlade i1 AGP
+		1023 8520  CyberBlade i1 AGP
+	8620  CyberBlade/i1
+		1014 0502  ThinkPad R30/T30
+	8820  CyberBlade XPAi1
+	9320  TGUI 9320
+	9350  GUI Accelerator
+	9360  Flat panel GUI Accelerator
+	9382  Cyber 9382 [Reference design]
+	9383  Cyber 9383 [Reference design]
+	9385  Cyber 9385 [Reference design]
+	9386  Cyber 9386
+	9388  Cyber 9388
+	9397  Cyber 9397
+	939a  Cyber 9397DVD
+	9420  TGUI 9420
+	9430  TGUI 9430
+	9440  TGUI 9440
+	9460  TGUI 9460
+	9470  TGUI 9470
+	9520  Cyber 9520
+	9525  Cyber 9525
+		10cf 1094  Lifebook C6155
+	9540  Cyber 9540
+	9660  TGUI 9660/938x/968x
+	9680  TGUI 9680
+	9682  TGUI 9682
+	9683  TGUI 9683
+	9685  ProVIDIA 9685
+	9750  3DImage 9750
+		1014 9750  3DImage 9750
+		1023 9750  3DImage 9750
+	9753  TGUI 9753
+	9754  TGUI 9754
+	9759  TGUI 975
+	9783  TGUI 9783
+	9785  TGUI 9785
+	9850  3DImage 9850
+	9880  Blade 3D PCI/AGP
+		1023 9880  Blade 3D
+	9910  CyberBlade/XP
+	9930  CyberBlade/XPm
+1024  Zenith Data Systems
+1025  Acer Incorporated [ALI]
+	1435  M1435
+	1445  M1445
+	1449  M1449
+	1451  M1451
+	1461  M1461
+	1489  M1489
+	1511  M1511
+	1512  ALI M1512 Aladdin
+	1513  M1513
+	1521  ALI M1521 Aladdin III CPU Bridge
+		10b9 1521  ALI M1521 Aladdin III CPU Bridge
+	1523  ALI M1523 ISA Bridge
+		10b9 1523  ALI M1523 ISA Bridge
+	1531  M1531 Northbridge [Aladdin IV/IV+]
+	1533  M1533 PCI-to-ISA Bridge
+		10b9 1533  ALI M1533 Aladdin IV/V ISA South Bridge
+	1535  M1535 PCI Bridge + Super I/O + FIR
+	1541  M1541 Northbridge [Aladdin V]
+		10b9 1541  ALI M1541 Aladdin V/V+ AGP+PCI North Bridge
+	1542  M1542 Northbridge [Aladdin V]
+	1543  M1543 PCI-to-ISA Bridge + Super I/O + FIR
+	1561  M1561 Northbridge [Aladdin 7]
+	1621  M1621 Northbridge [Aladdin-Pro II]
+	1631  M1631 Northbridge+3D Graphics [Aladdin TNT2]
+	1641  M1641 Northbridge [Aladdin-Pro IV]
+	1647  M1647 [MaGiK1] PCI North Bridge
+	1671  M1671 Northbridge [ALADDiN-P4]
+	1672  Northbridge [CyberALADDiN-P4]
+	3141  M3141
+	3143  M3143
+	3145  M3145
+	3147  M3147
+	3149  M3149
+	3151  M3151
+	3307  M3307 MPEG-I Video Controller
+	3309  M3309 MPEG-II Video w/ Software Audio Decoder
+	3321  M3321 MPEG-II Audio/Video Decoder
+	5212  M4803
+	5215  ALI PCI EIDE Controller
+	5217  M5217H
+	5219  M5219
+	5225  M5225
+	5229  M5229
+	5235  M5235
+	5237  M5237 PCI USB Host Controller
+	5240  EIDE Controller
+	5241  PCMCIA Bridge
+	5242  General Purpose Controller
+	5243  PCI to PCI Bridge Controller
+	5244  Floppy Disk Controller
+	5247  M1541 PCI to PCI Bridge
+	5251  M5251 P1394 Controller
+	5427  PCI to AGP Bridge
+	5451  M5451 PCI AC-Link Controller Audio Device
+	5453  M5453 PCI AC-Link Controller Modem Device
+	7101  M7101 PCI PMU Power Management Controller
+		10b9 7101  M7101 PCI PMU Power Management Controller
+1028  Dell
+	0001  PowerEdge Expandable RAID Controller 2/Si
+		1028 0001  PowerEdge 2400
+	0002  PowerEdge Expandable RAID Controller 3/Di
+		1028 0002  PowerEdge 4400
+	0003  PowerEdge Expandable RAID Controller 3/Si
+		1028 0003  PowerEdge 2450
+	0006  PowerEdge Expandable RAID Controller 3/Di
+	0007  Remote Access Card III
+	0008  Remote Access Card III
+	0009  Remote Access Card III: BMC/SMIC device not present
+	000a  PowerEdge Expandable RAID Controller 3/Di
+	000c  Embedded Remote Access or ERA/O
+	000d  Embedded Remote Access: BMC/SMIC device
+	000e  PowerEdge Expandable RAID controller 4/Di
+	000f  PowerEdge Expandable RAID controller 4/Di
+	0010  Remote Access Card 4
+	0011  Remote Access Card 4 Daughter Card
+	0012  Remote Access Card 4 Daughter Card Virtual UART
+	0013  PowerEdge Expandable RAID controller 4
+		1028 016c  PowerEdge Expandable RAID Controller 4e/Si
+		1028 016d  PowerEdge Expandable RAID Controller 4e/Di
+		1028 016e  PowerEdge Expandable RAID Controller 4e/Di
+		1028 016f  PowerEdge Expandable RAID Controller 4e/Di
+		1028 0170  PowerEdge Expandable RAID Controller 4e/Di
+	0014  Remote Access Card 4 Daughter Card SMIC interface
+1029  Siemens Nixdorf IS
+102a  LSI Logic
+	0000  HYDRA
+	0010  ASPEN
+	001f  AHA-2940U2/U2W /7890/7891 SCSI Controllers
+		9005 000f  2940U2W SCSI Controller
+		9005 0106  2940U2W SCSI Controller
+		9005 a180  2940U2W SCSI Controller
+	00c5  AIC-7899 U160/m SCSI Controller
+		1028 00c5  PowerEdge 2550/2650/4600
+	00cf  AIC-7899P U160/m
+		1028 0106  PowerEdge 4600
+		1028 0121  PowerEdge 2650
+102b  Matrox Graphics, Inc.
+# DJ: I've a suspicion that 0010 is a duplicate of 0d10.
+	0010  MGA-I [Impression?]
+	0100  MGA 1064SG [Mystique]
+	0518  MGA-II [Athena]
+	0519  MGA 2064W [Millennium]
+	051a  MGA 1064SG [Mystique]
+		102b 0100  MGA-1064SG Mystique
+		102b 1100  MGA-1084SG Mystique
+		102b 1200  MGA-1084SG Mystique
+		1100 102b  MGA-1084SG Mystique
+		110a 0018  Scenic Pro C5 (D1025)
+	051b  MGA 2164W [Millennium II]
+		102b 051b  MGA-2164W Millennium II
+		102b 1100  MGA-2164W Millennium II
+		102b 1200  MGA-2164W Millennium II
+	051e  MGA 1064SG [Mystique] AGP
+	051f  MGA 2164W [Millennium II] AGP
+	0520  MGA G200
+		102b dbc2  G200 Multi-Monitor
+		102b dbc8  G200 Multi-Monitor
+		102b dbe2  G200 Multi-Monitor
+		102b dbe8  G200 Multi-Monitor
+		102b ff03  Millennium G200 SD
+		102b ff04  Marvel G200
+	0521  MGA G200 AGP
+		1014 ff03  Millennium G200 AGP
+		102b 48e9  Mystique G200 AGP
+		102b 48f8  Millennium G200 SD AGP
+		102b 4a60  Millennium G200 LE AGP
+		102b 4a64  Millennium G200 AGP
+		102b c93c  Millennium G200 AGP
+		102b c9b0  Millennium G200 AGP
+		102b c9bc  Millennium G200 AGP
+		102b ca60  Millennium G250 LE AGP
+		102b ca6c  Millennium G250 AGP
+		102b dbbc  Millennium G200 AGP
+		102b dbc2  Millennium G200 MMS (Dual G200)
+		102b dbc3  G200 Multi-Monitor
+		102b dbc8  Millennium G200 MMS (Dual G200)
+		102b dbd2  G200 Multi-Monitor
+		102b dbd3  G200 Multi-Monitor
+		102b dbd4  G200 Multi-Monitor
+		102b dbd5  G200 Multi-Monitor
+		102b dbd8  G200 Multi-Monitor
+		102b dbd9  G200 Multi-Monitor
+		102b dbe2  Millennium G200 MMS (Quad G200)
+		102b dbe3  G200 Multi-Monitor
+		102b dbe8  Millennium G200 MMS (Quad G200)
+		102b dbf2  G200 Multi-Monitor
+		102b dbf3  G200 Multi-Monitor
+		102b dbf4  G200 Multi-Monitor
+		102b dbf5  G200 Multi-Monitor
+		102b dbf8  G200 Multi-Monitor
+		102b dbf9  G200 Multi-Monitor
+		102b f806  Mystique G200 Video AGP
+		102b ff00  MGA-G200 AGP
+		102b ff02  Mystique G200 AGP
+		102b ff03  Millennium G200 AGP
+		102b ff04  Marvel G200 AGP
+		110a 0032  MGA-G200 AGP
+	0525  MGA G400 AGP
+		0e11 b16f  MGA-G400 AGP
+		102b 0328  Millennium G400 16Mb SDRAM
+		102b 0338  Millennium G400 16Mb SDRAM
+		102b 0378  Millennium G400 32Mb SDRAM
+		102b 0541  Millennium G450 Dual Head
+		102b 0542  Millennium G450 Dual Head LX
+		102b 0543  Millennium G450 Single Head LX
+		102b 0641  Millennium G450 32Mb SDRAM Dual Head
+		102b 0642  Millennium G450 32Mb SDRAM Dual Head LX
+		102b 0643  Millennium G450 32Mb SDRAM Single Head LX
+		102b 07c0  Millennium G450 Dual Head LE
+		102b 07c1  Millennium G450 SDR Dual Head LE
+		102b 0d41  Millennium G450 Dual Head PCI
+		102b 0d42  Millennium G450 Dual Head LX PCI
+		102b 0d43  Millennium G450 32Mb Dual Head PCI
+		102b 0e00  Marvel G450 eTV
+		102b 0e01  Marvel G450 eTV
+		102b 0e02  Marvel G450 eTV
+		102b 0e03  Marvel G450 eTV
+		102b 0f80  Millennium G450 Low Profile
+		102b 0f81  Millennium G450 Low Profile
+		102b 0f82  Millennium G450 Low Profile DVI
+		102b 0f83  Millennium G450 Low Profile DVI
+		102b 19d8  Millennium G400 16Mb SGRAM
+		102b 19f8  Millennium G400 32Mb SGRAM
+		102b 2159  Millennium G400 Dual Head 16Mb
+		102b 2179  Millennium G400 MAX/Dual Head 32Mb
+		102b 217d  Millennium G400 Dual Head Max
+		102b 23c0  Millennium G450
+		102b 23c1  Millennium G450
+		102b 23c2  Millennium G450 DVI
+		102b 23c3  Millennium G450 DVI
+		102b 2f58  Millennium G400
+		102b 2f78  Millennium G400
+		102b 3693  Marvel G400 AGP
+		102b 5dd0  4Sight II
+		102b 5f50  4Sight II
+		102b 5f51  4Sight II
+		102b 5f52  4Sight II
+		102b 9010  Millennium G400 Dual Head
+		1458 0400  GA-G400
+		1705 0001  Millennium G450 32MB SGRAM
+		1705 0002  Millennium G450 16MB SGRAM
+		1705 0003  Millennium G450 32MB
+		1705 0004  Millennium G450 16MB
+	0527  MGA Parhelia AGP
+		102b 0840  Parhelia 128Mb
+	0d10  MGA Ultima/Impression
+	1000  MGA G100 [Productiva]
+		102b ff01  Productiva G100
+		102b ff05  Productiva G100 Multi-Monitor
+	1001  MGA G100 [Productiva] AGP
+		102b 1001  MGA-G100 AGP
+		102b ff00  MGA-G100 AGP
+		102b ff01  MGA-G100 Productiva AGP
+		102b ff03  Millennium G100 AGP
+		102b ff04  MGA-G100 AGP
+		102b ff05  MGA-G100 Productiva AGP Multi-Monitor
+		110a 001e  MGA-G100 AGP
+	2007  MGA Mistral
+	2527  MGA G550 AGP
+		102b 0f83  Millennium G550
+		102b 0f84  Millennium G550 Dual Head DDR 32Mb
+		102b 1e41  Millennium G550
+	2537  MGA G650 AGP
+	4536  VIA Framegrabber
+	6573  Shark 10/100 Multiport SwitchNIC
+102c  Chips and Technologies
+	00b8  F64310
+	00c0  F69000 HiQVideo
+		102c 00c0  F69000 HiQVideo
+		4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard
+		4c53 1010  CP5/CR6 mainboard
+		4c53 1020  VR6 mainboard
+		4c53 1030  PC5 mainboard
+		4c53 1050  CT7 mainboard
+		4c53 1051  CE7 mainboard
+	00d0  F65545
+	00d8  F65545
+	00dc  F65548
+	00e0  F65550
+	00e4  F65554
+	00e5  F65555 HiQVPro
+		0e11 b049  Armada 1700 Laptop Display Controller
+	00f0  F68554
+	00f4  F68554 HiQVision
+	00f5  F68555
+	0c30  F69030
+		4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard
+		4c53 1050  CT7 mainboard
+		4c53 1051  CE7 mainboard
+# C5C project cancelled
+		4c53 1080  CT8 mainboard
+102d  Wyse Technology Inc.
+	50dc  3328 Audio
+102e  Olivetti Advanced Technology
+102f  Toshiba America
+	0009  r4x00
+	000a  TX3927 MIPS RISC PCI Controller
+	0020  ATM Meteor 155
+		102f 00f8  ATM Meteor 155
+	0030  TC35815CF PCI 10/100 Mbit Ethernet Controller
+	0031  TC35815CF PCI 10/100 Mbit Ethernet Controller with WOL
+	0105  TC86C001 [goku-s] IDE
+	0106  TC86C001 [goku-s] USB 1.1 Host
+	0107  TC86C001 [goku-s] USB Device Controller
+	0108  TC86C001 [goku-s] I2C/SIO/GPIO Controller
+	0180  TX4927/38 MIPS RISC PCI Controller
+	0181  TX4925 MIPS RISC PCI Controller
+	0182  TX4937 MIPS RISC PCI Controller
+1030  TMC Research
+1031  Miro Computer Products AG
+	5601  DC20 ASIC
+	5607  Video I/O & motion JPEG compressor
+	5631  Media 3D
+	6057  MiroVideo DC10/DC30+
+1032  Compaq
+1033  NEC Corporation
+	0000  Vr4181A USB Host or Function Control Unit
+	0001  PCI to 486-like bus Bridge
+	0002  PCI to VL98 Bridge
+	0003  ATM Controller
+	0004  R4000 PCI Bridge
+	0005  PCI to 486-like bus Bridge
+	0006  PC-9800 Graphic Accelerator
+	0007  PCI to UX-Bus Bridge
+	0008  PC-9800 Graphic Accelerator
+	0009  PCI to PC9800 Core-Graph Bridge
+	0016  PCI to VL Bridge
+	001a  [Nile II]
+	0021  Vrc4373 [Nile I]
+	0029  PowerVR PCX1
+	002a  PowerVR 3D
+	002c  Star Alpha 2
+	002d  PCI to C-bus Bridge
+	0035  USB
+		1179 0001  USB
+		12ee 7000  Root Hub
+		1799 0001  Root Hub
+		807d 0035  PCI-USB2 (OHCI subsystem)
+	003b  PCI to C-bus Bridge
+	003e  NAPCCARD Cardbus Controller
+	0046  PowerVR PCX2 [midas]
+	005a  Vrc5074 [Nile 4]
+	0063  Firewarden
+	0067  PowerVR Neon 250 Chipset
+		1010 0020  PowerVR Neon 250 AGP 32Mb
+		1010 0080  PowerVR Neon 250 AGP 16Mb
+		1010 0088  PowerVR Neon 250 16Mb
+		1010 0090  PowerVR Neon 250 AGP 16Mb
+		1010 0098  PowerVR Neon 250 16Mb
+		1010 00a0  PowerVR Neon 250 AGP 32Mb
+		1010 00a8  PowerVR Neon 250 32Mb
+		1010 0120  PowerVR Neon 250 AGP 32Mb
+	0072  uPD72874 IEEE1394 OHCI 1.1 3-port PHY-Link Ctrlr
+	0074  56k Voice Modem
+		1033 8014  RCV56ACF 56k Voice Modem
+	009b  Vrc5476
+	00a5  VRC4173
+	00a6  VRC5477 AC97
+	00cd  IEEE 1394 [OrangeLink] Host Controller
+		12ee 8011  Root hub
+	00ce  IEEE 1394 Host Controller
+	00df  Vr4131
+	00e0  USB 2.0
+		0ee4 3383  Sitecom IEEE 1394 / USB2.0 Combo Card
+		12ee 7001  Root hub
+		1799 0002  Root Hub
+		807d 1043  PCI-USB2 (EHCI subsystem)
+	00e7  IEEE 1394 Host Controller
+	00f2  uPD72874 IEEE1394 OHCI 1.1 3-port PHY-Link Ctrlr
+	00f3  uPD6113x Multimedia Decoder/Processor [EMMA2]
+	010c  VR7701
+1034  Framatome Connectors USA Inc.
+1035  Comp. & Comm. Research Lab
+1036  Future Domain Corp.
+	0000  TMC-18C30 [36C70]
+1037  Hitachi Micro Systems
+1038  AMP, Inc
+1039  Silicon Integrated Systems [SiS]
+	0001  Virtual PCI-to-PCI bridge (AGP)
+	0002  SG86C202
+	0006  85C501/2/3
+	0008  SiS85C503/5513 (LPC Bridge)
+	0009  ACPI
+# source: http://members.datafast.net.au/dft0802/downloads/pcidevs.txt
+	0016  SiS961/2 SMBus Controller
+	0018  SiS85C503/5513 (LPC Bridge)
+# Controller for 2 PATA and 2 SATA channels
+	0180  RAID bus controller 180 SATA/PATA  [SiS]
+	0181  SiS SATA
+	0200  5597/5598/6326 VGA
+		1039 0000  SiS5597 SVGA (Shared RAM)
+	0204  82C204
+	0205  SG86C205
+	0300  300/305 PCI/AGP VGA Display Adapter
+		107d 2720  Leadtek WinFast VR300
+	0310  315H PCI/AGP VGA Display Adapter
+	0315  315 PCI/AGP VGA Display Adapter
+	0325  315PRO PCI/AGP VGA Display Adapter
+	0330  330 [Xabre] PCI/AGP VGA Display Adapter
+	0406  85C501/2
+	0496  85C496
+	0530  530 Host
+	0540  540 Host
+	0550  550 Host
+	0597  5513C
+	0601  85C601
+	0620  620 Host
+	0630  630 Host
+	0633  633 Host
+	0635  635 Host
+	0645  SiS645 Host & Memory & AGP Controller
+	0646  SiS645DX Host & Memory & AGP Controller
+	0648  SiS 645xx
+	0650  650/M650 Host
+	0651  651 Host
+	0655  655 Host
+	0660  660 Host
+	0661  661FX/M661FX/M661MX Host
+	0730  730 Host
+	0733  733 Host
+	0735  735 Host
+	0740  740 Host
+	0741  741/741GX/M741 Host
+	0745  745 Host
+	0746  746 Host
+	0755  755 Host
+	0760  760/M760 Host
+	0900  SiS900 PCI Fast Ethernet
+		1019 0a14  K7S5A motherboard
+		1039 0900  SiS900 10/100 Ethernet Adapter
+		1043 8035  CUSI-FX motherboard
+	0961  SiS961 [MuTIOL Media IO]
+	0962  SiS962 [MuTIOL Media IO]
+	0963  SiS963 [MuTIOL Media IO]
+	0964  SiS964 [MuTIOL Media IO]
+	0965  SiS965 [MuTIOL Media IO]
+	3602  83C602
+	5107  5107
+	5300  SiS540 PCI Display Adapter
+	5315  550 PCI/AGP VGA Display Adapter
+	5401  486 PCI Chipset
+	5511  5511/5512
+	5513  5513 [IDE]
+		1019 0970  P6STP-FL motherboard
+		1039 5513  SiS5513 EIDE Controller (A,B step)
+		1043 8035  CUSI-FX motherboard
+	5517  5517
+	5571  5571
+	5581  5581 Pentium Chipset
+	5582  5582
+	5591  5591/5592 Host
+	5596  5596 Pentium Chipset
+	5597  5597 [SiS5582]
+	5600  5600 Host
+	6204  Video decoder & MPEG interface
+	6205  VGA Controller
+	6236  6236 3D-AGP
+	6300  630/730 PCI/AGP VGA Display Adapter
+		1019 0970  P6STP-FL motherboard
+		1043 8035  CUSI-FX motherboard
+	6306  530/620 PCI/AGP VGA Display Adapter
+		1039 6306  SiS530,620 GUI Accelerator+3D
+	6325  65x/M650/740 PCI/AGP VGA Display Adapter
+	6326  86C326 5598/6326
+		1039 6326  SiS6326 GUI Accelerator
+		1092 0a50  SpeedStar A50
+		1092 0a70  SpeedStar A70
+		1092 4910  SpeedStar A70
+		1092 4920  SpeedStar A70
+		1569 6326  SiS6326 GUI Accelerator
+	6330  661/741/760 PCI/AGP VGA Display Adapter
+		1039 6330  [M]661xX/[M]741[GX]/[M]760 PCI/AGP VGA Adapter
+	7001  USB 1.0 Controller
+		1019 0a14  K7S5A motherboard
+		1039 7000  Onboard USB Controller
+	7002  USB 2.0 Controller
+		1509 7002  Onboard USB Controller
+	7007  FireWire Controller
+	7012  Sound Controller
+# There are may be different modem codecs here (Intel537 compatible and incompatible)
+	7013  AC'97 Modem Controller
+	7016  SiS7016 PCI Fast Ethernet Adapter
+		1039 7016  SiS7016 10/100 Ethernet Adapter
+	7018  SiS PCI Audio Accelerator
+		1014 01b6  SiS PCI Audio Accelerator
+		1014 01b7  SiS PCI Audio Accelerator
+		1019 7018  SiS PCI Audio Accelerator
+		1025 000e  SiS PCI Audio Accelerator
+		1025 0018  SiS PCI Audio Accelerator
+		1039 7018  SiS PCI Audio Accelerator
+		1043 800b  SiS PCI Audio Accelerator
+		1054 7018  SiS PCI Audio Accelerator
+		107d 5330  SiS PCI Audio Accelerator
+		107d 5350  SiS PCI Audio Accelerator
+		1170 3209  SiS PCI Audio Accelerator
+		1462 400a  SiS PCI Audio Accelerator
+		14a4 2089  SiS PCI Audio Accelerator
+		14cd 2194  SiS PCI Audio Accelerator
+		14ff 1100  SiS PCI Audio Accelerator
+		152d 8808  SiS PCI Audio Accelerator
+		1558 1103  SiS PCI Audio Accelerator
+		1558 2200  SiS PCI Audio Accelerator
+		1563 7018  SiS PCI Audio Accelerator
+		15c5 0111  SiS PCI Audio Accelerator
+		270f a171  SiS PCI Audio Accelerator
+		a0a0 0022  SiS PCI Audio Accelerator
+	7019  SiS7019 Audio Accelerator
+103a  Seiko Epson Corporation
+103b  Tatung Co. of America
+103c  Hewlett-Packard Company
+	1005  A4977A Visualize EG
+	1006  Visualize FX6
+	1008  Visualize FX4
+	100a  Visualize FX2
+	1028  Tach TL Fibre Channel Host Adapter
+	1029  Tach XL2 Fibre Channel Host Adapter
+		107e 000f  Interphase 5560 Fibre Channel Adapter
+		9004 9210  1Gb/2Gb Family Fibre Channel Controller
+		9004 9211  1Gb/2Gb Family Fibre Channel Controller
+	102a  Tach TS Fibre Channel Host Adapter
+		107e 000e  Interphase 5540/5541 Fibre Channel Adapter
+		9004 9110  1Gb/2Gb Family Fibre Channel Controller
+		9004 9111  1Gb/2Gb Family Fibre Channel Controller
+	1030  J2585A DeskDirect 10/100VG NIC
+	1031  J2585B HP 10/100VG PCI LAN Adapter
+		103c 1040  J2973A DeskDirect 10BaseT NIC
+		103c 1041  J2585B DeskDirect 10/100VG NIC
+		103c 1042  J2970A DeskDirect 10BaseT/2 NIC
+	1040  J2973A DeskDirect 10BaseT NIC
+	1041  J2585B DeskDirect 10/100 NIC
+	1042  J2970A DeskDirect 10BaseT/2 NIC
+	1048  Diva Serial [GSP] Multiport UART
+		103c 1049  Tosca Console
+		103c 104a  Tosca Secondary
+		103c 104b  Maestro SP2
+		103c 1223  Superdome Console
+		103c 1226  Keystone SP2
+		103c 1227  Powerbar SP2
+		103c 1282  Everest SP2
+		103c 1301  Diva RMP3
+	1054  PCI Local Bus Adapter
+	1064  79C970 PCnet Ethernet Controller
+	108b  Visualize FXe
+	10c1  NetServer Smart IRQ Router
+	10ed  TopTools Remote Control
+	10f0  rio System Bus Adapter
+	10f1  rio I/O Controller
+	1200  82557B 10/100 NIC
+	1219  NetServer PCI Hot-Plug Controller
+	121a  NetServer SMIC Controller
+	121b  NetServer Legacy COM Port Decoder
+	121c  NetServer PCI COM Port Decoder
+	1229  zx1 System Bus Adapter
+	122a  zx1 I/O Controller
+	122e  zx1 Local Bus Adapter
+	127c  sx1000 I/O Controller
+	1290  Auxiliary Diva Serial Port
+	12b4  zx1 QuickSilver AGP8x Local Bus Adapter
+	2910  E2910A PCIBus Exerciser
+	2925  E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer
+103e  Solliday Engineering
+103f  Synopsys/Logic Modeling Group
+1040  Accelgraphics Inc.
+1041  Computrend
+1042  Micron
+	1000  PC Tech RZ1000
+	1001  PC Tech RZ1001
+	3000  Samurai_0
+	3010  Samurai_1
+	3020  Samurai_IDE
+1043  ASUSTeK Computer Inc.
+	0675  ISDNLink P-IN100-ST-D
+	4015  v7100 SDRAM [GeForce2 MX]
+	4021  v7100 Combo Deluxe [GeForce2 MX + TV tuner]
+	4057  v8200 GeForce 3
+	8043  v8240 PAL 128M [P4T] Motherboard
+	807b  v9280/TD [Geforce4 TI4200 8X With TV-Out and DVI]
+	80bb  v9180 Magic/T [GeForce4 MX440 AGP 8x 64MB TV-out]
+	80c5  nForce3 chipset motherboard [SK8N]
+	80df  v9520 Magic/T
+1044  Adaptec (formerly DPT)
+	1012  Domino RAID Engine
+	a400  SmartCache/Raid I-IV Controller
+	a500  PCI Bridge
+	a501  SmartRAID V Controller
+		1044 c001  PM1554U2 Ultra2 Single Channel
+		1044 c002  PM1654U2 Ultra2 Single Channel
+		1044 c003  PM1564U3 Ultra3 Single Channel
+		1044 c004  PM1564U3 Ultra3 Dual Channel
+		1044 c005  PM1554U2 Ultra2 Single Channel (NON ACPI)
+		1044 c00a  PM2554U2 Ultra2 Single Channel
+		1044 c00b  PM2654U2 Ultra2 Single Channel
+		1044 c00c  PM2664U3 Ultra3 Single Channel
+		1044 c00d  PM2664U3 Ultra3 Dual Channel
+		1044 c00e  PM2554U2 Ultra2 Single Channel (NON ACPI)
+		1044 c00f  PM2654U2 Ultra2 Single Channel (NON ACPI)
+		1044 c014  PM3754U2 Ultra2 Single Channel (NON ACPI)
+		1044 c015  PM3755U2B Ultra2 Single Channel (NON ACPI)
+		1044 c016  PM3755F Fibre Channel (NON ACPI)
+		1044 c01e  PM3757U2 Ultra2 Single Channel
+		1044 c01f  PM3757U2 Ultra2 Dual Channel
+		1044 c020  PM3767U3 Ultra3 Dual Channel
+		1044 c021  PM3767U3 Ultra3 Quad Channel
+		1044 c028  PM2865U3 Ultra3 Single Channel
+		1044 c029  PM2865U3 Ultra3 Dual Channel
+		1044 c02a  PM2865F Fibre Channel
+		1044 c03c  2000S Ultra3 Single Channel
+		1044 c03d  2000S Ultra3 Dual Channel
+		1044 c03e  2000F Fibre Channel
+		1044 c046  3000S Ultra3 Single Channel
+		1044 c047  3000S Ultra3 Dual Channel
+		1044 c048  3000F Fibre Channel
+		1044 c050  5000S Ultra3 Single Channel
+		1044 c051  5000S Ultra3 Dual Channel
+		1044 c052  5000F Fibre Channel
+		1044 c05a  2400A UDMA Four Channel
+		1044 c05b  2400A UDMA Four Channel DAC
+		1044 c064  3010S Ultra3 Dual Channel
+		1044 c065  3410S Ultra160 Four Channel
+		1044 c066  3010S Fibre Channel
+	a511  SmartRAID V Controller
+		1044 c032  ASR-2005S I2O Zero Channel
+1045  OPTi Inc.
+	a0f8  82C750 [Vendetta] USB Controller
+	c101  92C264
+	c178  92C178
+	c556  82X556 [Viper]
+	c557  82C557 [Viper-M]
+	c558  82C558 [Viper-M ISA+IDE]
+	c567  82C750 [Vendetta], device 0
+	c568  82C750 [Vendetta], device 1
+	c569  82C579 [Viper XPress+ Chipset]
+	c621  82C621 [Viper-M/N+]
+	c700  82C700 [FireStar]
+	c701  82C701 [FireStar Plus]
+	c814  82C814 [Firebridge 1]
+	c822  82C822
+	c824  82C824
+	c825  82C825 [Firebridge 2]
+	c832  82C832
+	c861  82C861
+	c895  82C895
+	c935  EV1935 ECTIVA MachOne PCIAudio
+	d568  82C825 [Firebridge 2]
+	d721  IDE [FireStar]
+1046  IPC Corporation, Ltd.
+1047  Genoa Systems Corp
+1048  Elsa AG
+	0c60  Gladiac MX
+	0d22  Quadro4 900XGL [ELSA GLoria4 900XGL]
+	1000  QuickStep 1000
+	3000  QuickStep 3000
+	8901  Gloria XL
+1049  Fountain Technologies, Inc.
+# # nee SGS Thomson Microelectronics
+104a  STMicroelectronics
+	0008  STG 2000X
+	0009  STG 1764X
+	0010  STG4000 [3D Prophet Kyro Series]
+	0209  STPC Consumer/Industrial North- and Southbridge
+	020a  STPC Atlas/ConsumerS/Consumer IIA Northbridge
+# From <http://gatekeeper.dec.com/pub/BSD/FreeBSD/FreeBSD-stable/src/share/misc/pci_vendors>
+	0210  STPC Atlas ISA Bridge
+	021a  STPC Consumer S Southbridge
+	021b  STPC Consumer IIA Southbridge
+	0500  ST70137 [Unicorn] ADSL DMT Transceiver
+	0564  STPC Client Northbridge
+	0981  21x4x DEC-Tulip compatible 10/100 Ethernet
+	1746  STG 1764X
+	2774  21x4x DEC-Tulip compatible 10/100 Ethernet
+	3520  MPEG-II decoder card
+	55cc  STPC Client Southbridge
+104b  BusLogic
+	0140  BT-946C (old) [multimaster  01]
+	1040  BT-946C (BA80C30) [MultiMaster 10]
+	8130  Flashpoint LT
+104c  Texas Instruments
+	0500  100 MBit LAN Controller
+	0508  TMS380C2X Compressor Interface
+	1000  Eagle i/f AS
+	104c  PCI1510 PC card Cardbus Controller
+	3d04  TVP4010 [Permedia]
+	3d07  TVP4020 [Permedia 2]
+		1011 4d10  Comet
+		1040 000f  AccelStar II
+		1040 0011  AccelStar II
+		1048 0a31  WINNER 2000
+		1048 0a32  GLoria Synergy
+		1048 0a35  GLoria Synergy
+		107d 2633  WinFast 3D L2300
+		1092 0127  FIRE GL 1000 PRO
+		1092 0136  FIRE GL 1000 PRO
+		1092 0141  FIRE GL 1000 PRO
+		1092 0146  FIRE GL 1000 PRO
+		1092 0148  FIRE GL 1000 PRO
+		1092 0149  FIRE GL 1000 PRO
+		1092 0152  FIRE GL 1000 PRO
+		1092 0154  FIRE GL 1000 PRO
+		1092 0155  FIRE GL 1000 PRO
+		1092 0156  FIRE GL 1000 PRO
+		1092 0157  FIRE GL 1000 PRO
+		1097 3d01  Jeronimo Pro
+		1102 100f  Graphics Blaster Extreme
+		3d3d 0100  Reference Permedia 2 3D
+	8000  PCILynx/PCILynx2 IEEE 1394 Link Layer Controller
+		e4bf 1010  CF1-1-SNARE
+		e4bf 1020  CF1-2-SNARE
+	8009  FireWire Controller
+		104d 8032  8032 OHCI i.LINK (IEEE 1394) Controller
+	8017  PCI4410 FireWire Controller
+	8019  TSB12LV23 IEEE-1394 Controller
+		11bd 000a  Studio DV500-1394
+		11bd 000e  Studio DV
+		e4bf 1010  CF2-1-CYMBAL
+	8020  TSB12LV26 IEEE-1394 Controller (Link)
+		11bd 000f  Studio DV500-1394
+	8021  TSB43AA22 IEEE-1394 Controller (PHY/Link Integrated)
+		104d 80df  Vaio PCG-FX403
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+	8022  TSB43AB22 IEEE-1394a-2000 Controller (PHY/Link)
+	8023  TSB43AB22/A IEEE-1394a-2000 Controller (PHY/Link)
+		103c 088c  nc8000 laptop
+	8024  TSB43AB23 IEEE-1394a-2000 Controller (PHY/Link)
+	8025  TSB82AA2 IEEE-1394b Link Layer Controller
+		55aa 55aa  FireWire 800 PCI Card
+	8026  TSB43AB21 IEEE-1394a-2000 Controller (PHY/Link)
+	8027  PCI4451 IEEE-1394 Controller
+		1028 00e6  PCI4451 IEEE-1394 Controller (Dell Inspiron 8100)
+	8029  PCI4510 IEEE-1394 Controller
+		1028 0163  Latitude D505
+		1071 8160  MIM2900
+	802b  PCI7410,7510,7610 OHCI-Lynx Controller
+		1028 014e  PCI7410,7510,7610 OHCI-Lynx Controller (Dell Latitude D800)
+	802e  PCI7x20 1394a-2000 OHCI Two-Port PHY/Link-Layer Controller
+	8031  Texas Instruments PCIxx21/x515 Cardbus Controller
+	8032  Texas Instruments OHCI Compliant IEEE 1394 Host Controller
+	8033  Texas Instruments PCIxx21 Integrated FlashMedia Controller
+	8034  Texas Instruments PCI6411, PCI6421, PCI6611, PCI6621, PCI7411, PCI7421, PCI7611, PCI7621 Secure Digital (SD) Controller
+	8035  Texas Instruments PCI6411, PCI6421, PCI6611, PCI6621, PCI7411, PCI7421, PCI7611, PCI7621 Smart Card Controller (SMC)
+	8201  PCI1620 Firmware Loading Function
+	8204  PCI7410,7510,7610 PCI Firmware Loading Function
+		1028 014e  Latitude D800
+	8400  ACX 100 22Mbps Wireless Interface
+		00fc 16ec  U.S. Robotics 22 Mbps Wireless PC Card (model 2210)
+		00fd 16ec  U.S. Robotics 22Mbps Wireless PCI Adapter (model 2216)
+		1186 3b00  DWL-650+ PC Card cardbus 22Mbs Wireless Adapter [AirPlus]
+		1186 3b01  DWL-520+ 22Mbps PCI Wireless Adapter
+	8401  ACX 100 22Mbps Wireless Interface
+# OK, this info is almost useless as is, but at least it's known that it's a wireless card. More info requested from reporter (whi
+	9000  Wireless Interface (of unknown type)
+	9066  ACX 111 54Mbps Wireless Interface
+	a001  TDC1570
+	a100  TDC1561
+	a102  TNETA1575 HyperSAR Plus w/PCI Host i/f & UTOPIA i/f
+	a106  TMS320C6205 Fixed Point DSP
+		175c 5000  ASI50xx Audio Adapter
+		175c 8700  ASI87xx Radio Tuner card
+	ac10  PCI1050
+	ac11  PCI1053
+	ac12  PCI1130
+	ac13  PCI1031
+	ac15  PCI1131
+	ac16  PCI1250
+		1014 0092  ThinkPad 600
+	ac17  PCI1220
+	ac18  PCI1260
+	ac19  PCI1221
+	ac1a  PCI1210
+	ac1b  PCI1450
+		0e11 b113  Armada M700
+	ac1c  PCI1225
+		0e11 b121  Armada E500
+		1028 0088  Dell  Computer Corporation  Latitude CPi A400XT
+	ac1d  PCI1251A
+	ac1e  PCI1211
+	ac1f  PCI1251B
+	ac20  TI 2030
+	ac21  PCI2031
+	ac22  PCI2032 PCI Docking Bridge
+	ac23  PCI2250 PCI-to-PCI Bridge
+	ac28  PCI2050 PCI-to-PCI Bridge
+	ac30  PCI1260 PC card Cardbus Controller
+	ac40  PCI4450 PC card Cardbus Controller
+	ac41  PCI4410 PC card Cardbus Controller
+	ac42  PCI4451 PC card Cardbus Controller
+		1028 00e6  PCI4451 PC card CardBus Controller (Dell Inspiron 8100)
+	ac44  PCI4510 PC card Cardbus Controller
+		1028 0163  Latitude D505
+		1071 8160  MIM2000
+	ac46  PCI4520 PC card Cardbus Controller
+	ac47  PCI7510 PC card Cardbus Controller
+		1028 014e  Latitude D800
+	ac4a  PCI7510,7610 PC card Cardbus Controller
+		1028 014e  Latitude D800
+	ac50  PCI1410 PC card Cardbus Controller
+	ac51  PCI1420
+		1014 023b  ThinkPad T23 (2647-4MG)
+		1028 00b1  Latitude C600
+		1028 012a  Latitude C640
+		1033 80cd  Versa Note VXi
+		10cf 1095  Lifebook C6155
+		e4bf 1000  CP2-2-HIPHOP
+	ac52  PCI1451 PC card Cardbus Controller
+	ac53  PCI1421 PC card Cardbus Controller
+	ac54  PCI1620 PC Card Controller
+	ac55  PCI1520 PC card Cardbus Controller
+		1014 0512  ThinkPad T30/T40
+	ac56  PCI1510 PC card Cardbus Controller
+		1014 0528  ThinkPad R40e (2684-HVG) Cardbus Controller
+	ac60  PCI2040 PCI to DSP Bridge Controller
+		175c 5100  ASI51xx Audio Adapter
+		175c 6100  ASI61xx Audio Adapter
+		175c 6200  ASI62xx Audio Adapter
+	ac8d  PCI 7620
+	ac8e  PCI7420 CardBus Controller
+	ac8f  PCI7420/PCI7620 Dual Socket CardBus and Smart Card Cont. w/ 1394a-2000 OHCI Two-Port  PHY/Link-Layer Cont. and SD/MS-Pro Sockets
+	fe00  FireWire Host Controller
+	fe03  12C01A FireWire Host Controller
+104d  Sony Corporation
+	8004  DTL-H2500 [Playstation development board]
+	8009  CXD1947Q i.LINK Controller
+	8039  CXD3222 i.LINK Controller
+	8056  Rockwell HCF 56K modem
+	808a  Memory Stick Controller
+104e  Oak Technology, Inc
+	0017  OTI-64017
+	0107  OTI-107 [Spitfire]
+	0109  Video Adapter
+	0111  OTI-64111 [Spitfire]
+	0217  OTI-64217
+	0317  OTI-64317
+104f  Co-time Computer Ltd
+1050  Winbond Electronics Corp
+	0000  NE2000
+	0001  W83769F
+	0105  W82C105
+	0840  W89C840
+		1050 0001  W89C840 Ethernet Adapter
+		1050 0840  W89C840 Ethernet Adapter
+	0940  W89C940
+	5a5a  W89C940F
+	6692  W6692
+	9921  W99200F MPEG-1 Video Encoder
+	9922  W99200F/W9922PF MPEG-1/2 Video Encoder
+	9970  W9970CF
+1051  Anigma, Inc.
+1052  ?Young Micro Systems
+1053  Young Micro Systems
+1054  Hitachi, Ltd
+1055  Efar Microsystems
+	9130  SLC90E66 [Victory66] IDE
+	9460  SLC90E66 [Victory66] ISA
+	9462  SLC90E66 [Victory66] USB
+	9463  SLC90E66 [Victory66] ACPI
+1056  ICL
+# Motorola made a mistake and used 1507 instead of 1057 in some chips. Please look at the 1507 entry as well when updating this.
+1057  Motorola
+	0001  MPC105 [Eagle]
+	0002  MPC106 [Grackle]
+	0003  MPC8240 [Kahlua]
+	0004  MPC107
+	0006  MPC8245 [Unity]
+	0008  MPC8540
+	0009  MPC8560
+	0100  MC145575 [HFC-PCI]
+	0431  KTI829c 100VG
+	1801  DSP56301 Digital Signal Processor
+		14fb 0101  Transas Radar Imitator Board [RIM]
+		14fb 0102  Transas Radar Imitator Board [RIM-2]
+		14fb 0202  Transas Radar Integrator Board [RIB-2]
+		14fb 0611  1 channel CAN bus Controller [CanPci-1]
+		14fb 0612  2 channels CAN bus Controller [CanPci-2]
+		14fb 0613  3 channels CAN bus Controller [CanPci-3]
+		14fb 0614  4 channels CAN bus Controller [CanPci-4]
+		14fb 0621  1 channel CAN bus Controller [CanPci2-1]
+		14fb 0622  2 channels CAN bus Controller [CanPci2-2]
+		14fb 0810  Transas VTS Radar Integrator Board [RIB-4]
+		175c 4200  ASI4215 Audio Adapter
+		175c 4300  ASI43xx Audio Adapter
+		175c 4400  ASI4401 Audio Adapter
+		ecc0 0010  Darla
+		ecc0 0020  Gina
+		ecc0 0030  Layla rev.0
+		ecc0 0031  Layla rev.1
+		ecc0 0040  Darla24 rev.0
+		ecc0 0041  Darla24 rev.1
+		ecc0 0050  Gina24 rev.0
+		ecc0 0051  Gina24 rev.1
+		ecc0 0070  Mona rev.0
+		ecc0 0071  Mona rev.1
+		ecc0 0072  Mona rev.2
+	18c0  MPC8265A/MPC8266
+	18c1  MPC8271/MPC8272
+	3410  DSP56361 Digital Signal Processor
+		ecc0 0050  Gina24 rev.0
+		ecc0 0051  Gina24 rev.1
+		ecc0 0060  Layla24
+		ecc0 0070  Mona rev.0
+		ecc0 0071  Mona rev.1
+		ecc0 0072  Mona rev.2
+		ecc0 0080  Mia rev.0
+		ecc0 0081  Mia rev.1
+		ecc0 0090  Indigo
+		ecc0 00a0  Indigo IO
+		ecc0 00b0  Indigo DJ
+		ecc0 0100  3G
+	4801  Raven
+	4802  Falcon
+	4803  Hawk
+	4806  CPX8216
+	4d68  20268
+	5600  SM56 PCI Modem
+		1057 0300  SM56 PCI Speakerphone Modem
+		1057 0301  SM56 PCI Voice Modem
+		1057 0302  SM56 PCI Fax Modem
+		1057 5600  SM56 PCI Voice modem
+		13d2 0300  SM56 PCI Speakerphone Modem
+		13d2 0301  SM56 PCI Voice modem
+		13d2 0302  SM56 PCI Fax Modem
+		1436 0300  SM56 PCI Speakerphone Modem
+		1436 0301  SM56 PCI Voice modem
+		1436 0302  SM56 PCI Fax Modem
+		144f 100c  SM56 PCI Fax Modem
+		1494 0300  SM56 PCI Speakerphone Modem
+		1494 0301  SM56 PCI Voice modem
+		14c8 0300  SM56 PCI Speakerphone Modem
+		14c8 0302  SM56 PCI Fax Modem
+		1668 0300  SM56 PCI Speakerphone Modem
+		1668 0302  SM56 PCI Fax Modem
+	5803  MPC5200
+	6400  MPC190 Security Processor (S1 family, encryption)
+	6405  MPC184 Security Processor (S1 family)
+1058  Electronics & Telecommunications RSH
+1059  Teknor Industrial Computers Inc
+105a  Promise Technology, Inc.
+# more correct description from promise linux sources
+	0d30  PDC20265 (FastTrak100 Lite/Ultra100)
+		105a 4d33  Ultra100
+	0d38  20263
+		105a 4d39  Fasttrak66
+	1275  20275
+	3318  PDC20318 (SATA150 TX4)
+	3319  PDC20319 (FastTrak S150 TX4)
+		8086 3427  S875WP1-E mainboard
+	3371  PDC20371 (FastTrak S150 TX2plus)
+	3373  PDC20378 (FastTrak 378/SATA 378)
+		1043 80f5  K8V Deluxe/PC-DL Deluxe motherboard
+		1462 702e  K8T NEO FIS2R motherboard
+	3375  PDC20375 (SATA150 TX2plus)
+	3376  PDC20376 (FastTrak 376)
+		1043 809e  A7V8X motherboard
+	3574  PDC20579 SATAII 150 IDE Controller
+	3d18  PDC20518/PDC40518 (SATAII 150 TX4)
+	3d75  PDC20575 (SATAII150 TX2plus)
+	4d30  PDC20267 (FastTrak100/Ultra100)
+		105a 4d33  Ultra100
+		105a 4d39  FastTrak100
+	4d33  20246
+		105a 4d33  20246 IDE Controller
+	4d38  PDC20262 (FastTrak66/Ultra66)
+		105a 4d30  Ultra Device on SuperTrak
+		105a 4d33  Ultra66
+		105a 4d39  FastTrak66
+	4d68  PDC20268 (Ultra100 TX2)
+		105a 4d68  Ultra100TX2
+	4d69  20269
+		105a 4d68  Ultra133TX2
+	5275  PDC20276 (MBFastTrak133 Lite)
+		105a 0275  SuperTrak SX6000 IDE
+		105a 1275  MBFastTrak133 Lite (tm) Controller (RAID mode)
+		1458 b001  MBUltra 133
+	5300  DC5300
+	6268  PDC20270 (FastTrak100 LP/TX2/TX4)
+		105a 4d68  FastTrak100 TX2
+	6269  PDC20271 (FastTrak TX2000)
+		105a 6269  FastTrak TX2/TX2000
+	6621  PDC20621 (FastTrak S150 SX4/FastTrak SX4000 lite)
+	6622  PDC20621 [SATA150 SX4] 4 Channel IDE RAID Controller
+	6626  PDC20618 (Ultra 618)
+	6629  PDC20619 (FastTrak TX4000)
+	7275  PDC20277 (SBFastTrak133 Lite)
+105b  Foxconn International, Inc.
+105c  Wipro Infotech Limited
+105d  Number 9 Computer Company
+	2309  Imagine 128
+	2339  Imagine 128-II
+		105d 0000  Imagine 128 series 2 4Mb VRAM
+		105d 0001  Imagine 128 series 2 4Mb VRAM
+		105d 0002  Imagine 128 series 2 4Mb VRAM
+		105d 0003  Imagine 128 series 2 4Mb VRAM
+		105d 0004  Imagine 128 series 2 4Mb VRAM
+		105d 0005  Imagine 128 series 2 4Mb VRAM
+		105d 0006  Imagine 128 series 2 4Mb VRAM
+		105d 0007  Imagine 128 series 2 4Mb VRAM
+		105d 0008  Imagine 128 series 2e 4Mb DRAM
+		105d 0009  Imagine 128 series 2e 4Mb DRAM
+		105d 000a  Imagine 128 series 2 8Mb VRAM
+		105d 000b  Imagine 128 series 2 8Mb H-VRAM
+		11a4 000a  Barco Metheus 5 Megapixel
+		13cc 0000  Barco Metheus 5 Megapixel
+		13cc 0004  Barco Metheus 5 Megapixel
+		13cc 0005  Barco Metheus 5 Megapixel
+		13cc 0006  Barco Metheus 5 Megapixel
+		13cc 0008  Barco Metheus 5 Megapixel
+		13cc 0009  Barco Metheus 5 Megapixel
+		13cc 000a  Barco Metheus 5 Megapixel
+		13cc 000c  Barco Metheus 5 Megapixel
+	493d  Imagine 128 T2R [Ticket to Ride]
+		11a4 000a  Barco Metheus 5 Megapixel, Dual Head
+		11a4 000b  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0002  Barco Metheus 4 Megapixel, Dual Head
+		13cc 0003  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0007  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0008  Barco Metheus 5 Megapixel, Dual Head
+		13cc 0009  Barco Metheus 5 Megapixel, Dual Head
+		13cc 000a  Barco Metheus 5 Megapixel, Dual Head
+	5348  Revolution 4
+		105d 0037  Revolution IV-FP AGP (For SGI 1600SW)
+105e  Vtech Computers Ltd
+105f  Infotronic America Inc
+1060  United Microelectronics [UMC]
+	0001  UM82C881
+	0002  UM82C886
+	0101  UM8673F
+	0881  UM8881
+	0886  UM8886F
+	0891  UM8891A
+	1001  UM886A
+	673a  UM8886BF
+	673b  EIDE Master/DMA
+	8710  UM8710
+	886a  UM8886A
+	8881  UM8881F
+	8886  UM8886F
+	888a  UM8886A
+	8891  UM8891A
+	9017  UM9017F
+	9018  UM9018
+	9026  UM9026
+	e881  UM8881N
+	e886  UM8886N
+	e88a  UM8886N
+	e891  UM8891N
+1061  I.I.T.
+	0001  AGX016
+	0002  IIT3204/3501
+1062  Maspar Computer Corp
+1063  Ocean Office Automation
+1064  Alcatel
+1065  Texas Microsystems
+1066  PicoPower Technology
+	0000  PT80C826
+	0001  PT86C521 [Vesuvius v1] Host Bridge
+	0002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Master
+	0003  PT86C524 [Nile] PCI-to-PCI Bridge
+	0004  PT86C525 [Nile-II] PCI-to-PCI Bridge
+	0005  National PC87550 System Controller
+	8002  PT86C523 [Vesuvius v3] PCI-ISA Bridge Slave
+1067  Mitsubishi Electric
+	0301  AccelGraphics AccelECLIPSE
+	0304  AccelGALAXY A2100 [OEM Evans & Sutherland]
+	0308  Tornado 3000 [OEM Evans & Sutherland]
+	1002  VG500 [VolumePro Volume Rendering Accelerator]
+1068  Diversified Technology
+1069  Mylex Corporation
+	0001  DAC960P
+	0002  DAC960PD
+	0010  DAC960PG
+	0020  DAC960LA
+	0050  AcceleRAID 352/170/160 support Device
+	b166  Gemstone chipset SCSI controller
+		1014 0242  iSeries 2872 DASD IOA
+		1014 0266  Dual Channel PCI-X U320 SCSI Adapter
+		1014 0278  Dual Channel PCI-X U320 SCSI RAID Adapter
+		1014 02d3  Dual Channel PCI-X U320 SCSI Adapter
+		1014 02d4  Dual Channel PCI-X U320 SCSI RAID Adapter
+	ba55  eXtremeRAID 1100 support Device
+	ba56  eXtremeRAID 2000/3000 support Device
+106a  Aten Research Inc
+106b  Apple Computer Inc.
+	0001  Bandit PowerPC host bridge
+	0002  Grand Central I/O
+	0003  Control Video
+	0004  PlanB Video-In
+	0007  O'Hare I/O
+	000c  DOS on Mac
+	000e  Hydra Mac I/O
+	0010  Heathrow Mac I/O
+	0017  Paddington Mac I/O
+	0018  UniNorth FireWire
+	0019  KeyLargo USB
+	001e  UniNorth Internal PCI
+	001f  UniNorth PCI
+	0020  UniNorth AGP
+	0021  UniNorth GMAC (Sun GEM)
+	0022  KeyLargo Mac I/O
+	0024  UniNorth/Pangea GMAC (Sun GEM)
+	0025  KeyLargo/Pangea Mac I/O
+	0026  KeyLargo/Pangea USB
+	0027  UniNorth/Pangea AGP
+	0028  UniNorth/Pangea PCI
+	0029  UniNorth/Pangea Internal PCI
+	002d  UniNorth 1.5 AGP
+	002e  UniNorth 1.5 PCI
+	002f  UniNorth 1.5 Internal PCI
+	0030  UniNorth/Pangea FireWire
+	0031  UniNorth 2 FireWire
+	0032  UniNorth 2 GMAC (Sun GEM)
+	0033  UniNorth 2 ATA/100
+	0034  UniNorth 2 AGP
+	0035  UniNorth 2 PCI
+	0036  UniNorth 2 Internal PCI
+	003b  UniNorth/Intrepid ATA/100
+	003e  KeyLargo/Intrepid Mac I/O
+	003f  KeyLargo/Intrepid USB
+	0040  K2 KeyLargo USB
+	0041  K2 KeyLargo Mac/IO
+	0042  K2 FireWire
+	0043  K2 ATA/100
+	0045  K2 HT-PCI Bridge
+	0046  K2 HT-PCI Bridge
+	0047  K2 HT-PCI Bridge
+	0048  K2 HT-PCI Bridge
+	0049  K2 HT-PCI Bridge
+	004b  U3 AGP
+	004c  K2 GMAC (Sun GEM)
+	004f  Shasta Mac I/O
+	0050  Shasta IDE
+	0051  Shasta (Sun GEM)
+	0052  Shasta Firewire
+	0053  Shasta PCI Bridge
+	0054  Shasta PCI Bridge
+	0055  Shasta PCI Bridge
+	0058  U3L AGP Bridge
+	1645  Tigon3 Gigabit Ethernet NIC (BCM5701)
+106c  Hynix Semiconductor
+	8801  Dual Pentium ISA/PCI Motherboard
+	8802  PowerPC ISA/PCI Motherboard
+	8803  Dual Window Graphics Accelerator
+	8804  LAN Controller
+	8805  100-BaseT LAN
+106d  Sequent Computer Systems
+106e  DFI, Inc
+106f  City Gate Development Ltd
+1070  Daewoo Telecom Ltd
+1071  Mitac
+	8160  Mitac 8060B Mobile Platform
+1072  GIT Co Ltd
+1073  Yamaha Corporation
+	0001  3D GUI Accelerator
+	0002  YGV615 [RPA3 3D-Graphics Controller]
+	0003  YMF-740
+	0004  YMF-724
+		1073 0004  YMF724-Based PCI Audio Adapter
+	0005  DS1 Audio
+		1073 0005  DS-XG PCI Audio CODEC
+	0006  DS1 Audio
+	0008  DS1 Audio
+		1073 0008  DS-XG PCI Audio CODEC
+	000a  DS1L Audio
+		1073 0004  DS-XG PCI Audio CODEC
+		1073 000a  DS-XG PCI Audio CODEC
+	000c  YMF-740C [DS-1L Audio Controller]
+		107a 000c  DS-XG PCI Audio CODEC
+	000d  YMF-724F [DS-1 Audio Controller]
+		1073 000d  DS-XG PCI Audio CODEC
+	0010  YMF-744B [DS-1S Audio Controller]
+		1073 0006  DS-XG PCI Audio CODEC
+		1073 0010  DS-XG PCI Audio CODEC
+	0012  YMF-754 [DS-1E Audio Controller]
+		1073 0012  DS-XG PCI Audio Codec
+	0020  DS-1 Audio
+	2000  DS2416 Digital Mixing Card
+		1073 2000  DS2416 Digital Mixing Card
+1074  NexGen Microsystems
+	4e78  82c500/1
+1075  Advanced Integrations Research
+1076  Chaintech Computer Co. Ltd
+1077  QLogic Corp.
+	1016  ISP10160 Single Channel Ultra3 SCSI Processor
+	1020  ISP1020 Fast-wide SCSI
+	1022  ISP1022 Fast-wide SCSI
+	1080  ISP1080 SCSI Host Adapter
+	1216  ISP12160 Dual Channel Ultra3 SCSI Processor
+		101e 8471  QLA12160 on AMI MegaRAID
+		101e 8493  QLA12160 on AMI MegaRAID
+	1240  ISP1240 SCSI Host Adapter
+	1280  ISP1280 SCSI Host Adapter
+	2020  ISP2020A Fast!SCSI Basic Adapter
+	2100  QLA2100 64-bit Fibre Channel Adapter
+		1077 0001  QLA2100 64-bit Fibre Channel Adapter
+	2200  QLA2200 64-bit Fibre Channel Adapter
+		1077 0002  QLA2200
+	2300  QLA2300 64-bit Fibre Channel Adapter
+	2312  QLA2312 Fibre Channel Adapter
+1078  Cyrix Corporation
+	0000  5510 [Grappa]
+	0001  PCI Master
+	0002  5520 [Cognac]
+	0100  5530 Legacy [Kahlua]
+	0101  5530 SMI [Kahlua]
+	0102  5530 IDE [Kahlua]
+	0103  5530 Audio [Kahlua]
+	0104  5530 Video [Kahlua]
+	0400  ZFMicro PCI Bridge
+	0401  ZFMicro Chipset SMI
+	0402  ZFMicro Chipset IDE
+	0403  ZFMicro Expansion Bus
+1079  I-Bus
+107a  NetWorth
+107b  Gateway 2000
+107c  LG Electronics [Lucky Goldstar Co. Ltd]
+107d  LeadTek Research Inc.
+	0000  P86C850
+	2134  WinFast 3D S320 II
+	2971  [GeForce FX 5900] WinFast A350 TDH MyViVo
+107e  Interphase Corporation
+	0001  5515 ATM Adapter [Flipper]
+	0002  100 VG AnyLan Controller
+	0004  5526 Fibre Channel Host Adapter
+	0005  x526 Fibre Channel Host Adapter
+	0008  5525/5575 ATM Adapter (155 Mbit) [Atlantic]
+	9003  5535-4P-BRI-ST
+	9007  5535-4P-BRI-U
+	9008  5535-1P-SR
+	900c  5535-1P-SR-ST
+	900e  5535-1P-SR-U
+	9011  5535-1P-PRI
+	9013  5535-2P-PRI
+	9023  5536-4P-BRI-ST
+	9027  5536-4P-BRI-U
+	9031  5536-1P-PRI
+	9033  5536-2P-PRI
+107f  Data Technology Corporation
+	0802  SL82C105
+1080  Contaq Microsystems
+	0600  82C599
+	c691  Cypress CY82C691
+	c693  82c693
+1081  Supermac Technology
+	0d47  Radius PCI to NuBUS Bridge
+1082  EFA Corporation of America
+1083  Forex Computer Corporation
+	0001  FR710
+1084  Parador
+1085  Tulip Computers Int.B.V.
+1086  J. Bond Computer Systems
+1087  Cache Computer
+1088  Microcomputer Systems (M) Son
+1089  Data General Corporation
+# Formerly Bit3 Computer Corp.
+108a  SBS Technologies
+	0001  VME Bridge Model 617
+	0010  VME Bridge Model 618
+	0040  dataBLIZZARD
+	3000  VME Bridge Model 2706
+108c  Oakleigh Systems Inc.
+108d  Olicom
+	0001  Token-Ring 16/4 PCI Adapter (3136/3137)
+	0002  16/4 Token Ring
+	0004  RapidFire 3139 Token-Ring 16/4 PCI Adapter
+		108d 0004  OC-3139/3140 RapidFire Token-Ring 16/4 Adapter
+	0005  GoCard 3250 Token-Ring 16/4 CardBus PC Card
+	0006  OC-3530 RapidFire Token-Ring 100
+	0007  RapidFire 3141 Token-Ring 16/4 PCI Fiber Adapter
+		108d 0007  OC-3141 RapidFire Token-Ring 16/4 Adapter
+	0008  RapidFire 3540 HSTR 100/16/4 PCI Adapter
+		108d 0008  OC-3540 RapidFire HSTR 100/16/4 Adapter
+	0011  OC-2315
+	0012  OC-2325
+	0013  OC-2183/2185
+	0014  OC-2326
+	0019  OC-2327/2250 10/100 Ethernet Adapter
+		108d 0016  OC-2327 Rapidfire 10/100 Ethernet Adapter
+		108d 0017  OC-2250 GoCard 10/100 Ethernet Adapter
+	0021  OC-6151/6152 [RapidFire ATM 155]
+	0022  ATM Adapter
+108e  Sun Microsystems Computer Corp.
+	0001  EBUS
+	1000  EBUS
+	1001  Happy Meal
+	1100  RIO EBUS
+	1101  RIO GEM
+	1102  RIO 1394
+	1103  RIO USB
+	1648  [bge] Gigabit Ethernet
+	2bad  GEM
+	5000  Simba Advanced PCI Bridge
+	5043  SunPCI Co-processor
+	8000  Psycho PCI Bus Module
+	8001  Schizo PCI Bus Module
+	8002  Schizo+ PCI Bus Module
+	a000  Ultra IIi
+	a001  Ultra IIe
+	a801  Tomatillo PCI Bus Module
+	abba  Cassini 10/100/1000
+108f  Systemsoft
+1090  Encore Computer Corporation
+1091  Intergraph Corporation
+	0020  3D graphics processor
+	0021  3D graphics processor w/Texturing
+	0040  3D graphics frame buffer
+	0041  3D graphics frame buffer
+	0060  Proprietary bus bridge
+	00e4  Powerstorm 4D50T
+	0720  Motion JPEG codec
+	07a0  Sun Expert3D-Lite Graphics Accelerator
+	1091  Sun Expert3D Graphics Accelerator
+1092  Diamond Multimedia Systems
+	00a0  Speedstar Pro SE
+	00a8  Speedstar 64
+	0550  Viper V550
+	08d4  Supra 2260 Modem
+	094c  SupraExpress 56i Pro
+	1092  Viper V330
+	6120  Maximum DVD
+	8810  Stealth SE
+	8811  Stealth 64/SE
+	8880  Stealth
+	8881  Stealth
+	88b0  Stealth 64
+	88b1  Stealth 64
+	88c0  Stealth 64
+	88c1  Stealth 64
+	88d0  Stealth 64
+	88d1  Stealth 64
+	88f0  Stealth 64
+	88f1  Stealth 64
+	9999  DMD-I0928-1 "Monster sound" sound chip
+1093  National Instruments
+	0160  PCI-DIO-96
+	0162  PCI-MIO-16XE-50
+	1170  PCI-MIO-16XE-10
+	1180  PCI-MIO-16E-1
+	1190  PCI-MIO-16E-4
+	1310  PCI-6602
+	1330  PCI-6031E
+	1350  PCI-6071E
+	14e0  PCI-6110
+	14f0  PCI-6111
+	17d0  PCI-6503
+	1870  PCI-6713
+	1880  PCI-6711
+	18b0  PCI-6052E
+	2410  PCI-6733
+	2890  PCI-6036E
+	2a60  PCI-6023E
+	2a70  PCI-6024E
+	2a80  PCI-6025E
+	2c80  PCI-6035E
+	2ca0  PCI-6034E
+	70b8  PCI-6251 [M Series - High Speed Multifunction DAQ]
+	b001  IMAQ-PCI-1408
+	b011  IMAQ-PXI-1408
+	b021  IMAQ-PCI-1424
+	b031  IMAQ-PCI-1413
+	b041  IMAQ-PCI-1407
+	b051  IMAQ-PXI-1407
+	b061  IMAQ-PCI-1411
+	b071  IMAQ-PCI-1422
+	b081  IMAQ-PXI-1422
+	b091  IMAQ-PXI-1411
+	c801  PCI-GPIB
+	c831  PCI-GPIB bridge
+1094  First International Computers [FIC]
+1095  Silicon Image, Inc. (formerly CMD Technology Inc)
+	0240  Adaptec AAR-1210SA SATA HostRAID Controller
+	0640  PCI0640
+	0643  PCI0643
+	0646  PCI0646
+	0647  PCI0647
+	0648  PCI0648
+	0649  SiI 0649 Ultra ATA/100 PCI to ATA Host Controller
+		0e11 005d  Integrated Ultra ATA-100 Dual Channel Controller
+		0e11 007e  Integrated Ultra ATA-100 IDE RAID Controller
+		101e 0649  AMI MegaRAID IDE 100 Controller
+	0650  PBC0650A
+	0670  USB0670
+		1095 0670  USB0670
+	0673  USB0673
+	0680  PCI0680 Ultra ATA-133 Host Controller
+		1095 3680  Winic W-680 (Silicon Image 680 based)
+	3112  SiI 3112 [SATALink/SATARaid] Serial ATA Controller
+		1095 3112  SiI 3112 SATALink Controller
+		1095 6112  SiI 3112 SATARaid Controller
+	3114  SiI 3114 [SATALink/SATARaid] Serial ATA Controller
+		1095 3114  SiI 3114 SATALink Controller
+		1095 6114  SiI 3114 SATARaid Controller
+	3124  SiI 3124 PCI-X Serial ATA Controller
+		1095 3124  SiI 3124 PCI-X Serial ATA Controller
+	3512  SiI 3512 [SATALink/SATARaid] Serial ATA Controller
+		1095 3512  SiI 3512 SATALink Controller
+		1095 6512  SiI 3512 SATARaid Controller
+1096  Alacron
+1097  Appian Technology
+1098  Quantum Designs (H.K.) Ltd
+	0001  QD-8500
+	0002  QD-8580
+1099  Samsung Electronics Co., Ltd
+109a  Packard Bell
+109b  Gemlight Computer Ltd.
+109c  Megachips Corporation
+109d  Zida Technologies Ltd.
+109e  Brooktree Corporation
+	0350  Bt848 Video Capture
+	0351  Bt849A Video capture
+	0369  Bt878 Video Capture
+		1002 0001  TV-Wonder
+		1002 0003  TV-Wonder/VE
+	036c  Bt879(??) Video Capture
+		13e9 0070  Win/TV (Video Section)
+	036e  Bt878 Video Capture
+		0070 13eb  WinTV Series
+		0070 ff01  Viewcast Osprey 200
+		0071 0101  DigiTV PCI
+		107d 6606  WinFast TV 2000
+		11bd 0012  PCTV pro (TV + FM stereo receiver)
+		11bd 001c  PCTV Sat (DBC receiver)
+		127a 0001  Bt878 Mediastream Controller NTSC
+		127a 0002  Bt878 Mediastream Controller PAL BG
+		127a 0003  Bt878a Mediastream Controller PAL BG
+		127a 0048  Bt878/832 Mediastream Controller
+		144f 3000  MagicTView CPH060 - Video
+		1461 0002  TV98 Series (TV/No FM/Remote)
+		1461 0003  AverMedia UltraTV PCI 350
+		1461 0004  AVerTV WDM Video Capture
+		1461 0761  AverTV DVB-T
+		14f1 0001  Bt878 Mediastream Controller NTSC
+		14f1 0002  Bt878 Mediastream Controller PAL BG
+		14f1 0003  Bt878a Mediastream Controller PAL BG
+		14f1 0048  Bt878/832 Mediastream Controller
+		1822 0001  VisionPlus DVB card
+		1851 1850  FlyVideo'98 - Video
+		1851 1851  FlyVideo II
+		1852 1852  FlyVideo'98 - Video (with FM Tuner)
+		270f fc00  Digitop DTT-1000
+		bd11 1200  PCTV pro (TV + FM stereo receiver)
+	036f  Bt879 Video Capture
+		127a 0044  Bt879 Video Capture NTSC
+		127a 0122  Bt879 Video Capture PAL I
+		127a 0144  Bt879 Video Capture NTSC
+		127a 0222  Bt879 Video Capture PAL BG
+		127a 0244  Bt879a Video Capture NTSC
+		127a 0322  Bt879 Video Capture NTSC
+		127a 0422  Bt879 Video Capture NTSC
+		127a 1122  Bt879 Video Capture PAL I
+		127a 1222  Bt879 Video Capture PAL BG
+		127a 1322  Bt879 Video Capture NTSC
+		127a 1522  Bt879a Video Capture PAL I
+		127a 1622  Bt879a Video Capture PAL BG
+		127a 1722  Bt879a Video Capture NTSC
+		14f1 0044  Bt879 Video Capture NTSC
+		14f1 0122  Bt879 Video Capture PAL I
+		14f1 0144  Bt879 Video Capture NTSC
+		14f1 0222  Bt879 Video Capture PAL BG
+		14f1 0244  Bt879a Video Capture NTSC
+		14f1 0322  Bt879 Video Capture NTSC
+		14f1 0422  Bt879 Video Capture NTSC
+		14f1 1122  Bt879 Video Capture PAL I
+		14f1 1222  Bt879 Video Capture PAL BG
+		14f1 1322  Bt879 Video Capture NTSC
+		14f1 1522  Bt879a Video Capture PAL I
+		14f1 1622  Bt879a Video Capture PAL BG
+		14f1 1722  Bt879a Video Capture NTSC
+		1851 1850  FlyVideo'98 - Video
+		1851 1851  FlyVideo II
+		1852 1852  FlyVideo'98 - Video (with FM Tuner)
+	0370  Bt880 Video Capture
+		1851 1850  FlyVideo'98
+		1851 1851  FlyVideo'98 EZ - video
+		1852 1852  FlyVideo'98 (with FM Tuner)
+	0878  Bt878 Audio Capture
+		0070 13eb  WinTV Series
+		0070 ff01  Viewcast Osprey 200
+		0071 0101  DigiTV PCI
+		1002 0001  TV-Wonder
+		1002 0003  TV-Wonder/VE
+		11bd 0012  PCTV pro (TV + FM stereo receiver, audio section)
+		11bd 001c  PCTV Sat (DBC receiver)
+		127a 0001  Bt878 Video Capture (Audio Section)
+		127a 0002  Bt878 Video Capture (Audio Section)
+		127a 0003  Bt878 Video Capture (Audio Section)
+		127a 0048  Bt878 Video Capture (Audio Section)
+		13e9 0070  Win/TV (Audio Section)
+		144f 3000  MagicTView CPH060 - Audio
+		1461 0004  AVerTV WDM Audio Capture
+		1461 0761  AVerTV DVB-T
+		14f1 0001  Bt878 Video Capture (Audio Section)
+		14f1 0002  Bt878 Video Capture (Audio Section)
+		14f1 0003  Bt878 Video Capture (Audio Section)
+		14f1 0048  Bt878 Video Capture (Audio Section)
+		1822 0001  VisionPlus DVB Card
+		270f fc00  Digitop DTT-1000
+		bd11 1200  PCTV pro (TV + FM stereo receiver, audio section)
+	0879  Bt879 Audio Capture
+		127a 0044  Bt879 Video Capture (Audio Section)
+		127a 0122  Bt879 Video Capture (Audio Section)
+		127a 0144  Bt879 Video Capture (Audio Section)
+		127a 0222  Bt879 Video Capture (Audio Section)
+		127a 0244  Bt879 Video Capture (Audio Section)
+		127a 0322  Bt879 Video Capture (Audio Section)
+		127a 0422  Bt879 Video Capture (Audio Section)
+		127a 1122  Bt879 Video Capture (Audio Section)
+		127a 1222  Bt879 Video Capture (Audio Section)
+		127a 1322  Bt879 Video Capture (Audio Section)
+		127a 1522  Bt879 Video Capture (Audio Section)
+		127a 1622  Bt879 Video Capture (Audio Section)
+		127a 1722  Bt879 Video Capture (Audio Section)
+		14f1 0044  Bt879 Video Capture (Audio Section)
+		14f1 0122  Bt879 Video Capture (Audio Section)
+		14f1 0144  Bt879 Video Capture (Audio Section)
+		14f1 0222  Bt879 Video Capture (Audio Section)
+		14f1 0244  Bt879 Video Capture (Audio Section)
+		14f1 0322  Bt879 Video Capture (Audio Section)
+		14f1 0422  Bt879 Video Capture (Audio Section)
+		14f1 1122  Bt879 Video Capture (Audio Section)
+		14f1 1222  Bt879 Video Capture (Audio Section)
+		14f1 1322  Bt879 Video Capture (Audio Section)
+		14f1 1522  Bt879 Video Capture (Audio Section)
+		14f1 1622  Bt879 Video Capture (Audio Section)
+		14f1 1722  Bt879 Video Capture (Audio Section)
+	0880  Bt880 Audio Capture
+	2115  BtV 2115 Mediastream controller
+	2125  BtV 2125 Mediastream controller
+	2164  BtV 2164
+	2165  BtV 2165
+	8230  Bt8230 ATM Segment/Reassembly Ctrlr (SRC)
+	8472  Bt8472
+	8474  Bt8474
+109f  Trigem Computer Inc.
+10a0  Meidensha Corporation
+10a1  Juko Electronics Ind. Co. Ltd
+10a2  Quantum Corporation
+10a3  Everex Systems Inc
+10a4  Globe Manufacturing Sales
+10a5  Smart Link Ltd.
+	3052  SmartPCI562 56K Modem
+	5449  SmartPCI561 modem
+10a6  Informtech Industrial Ltd.
+10a7  Benchmarq Microelectronics
+10a8  Sierra Semiconductor
+	0000  STB Horizon 64
+10a9  Silicon Graphics, Inc.
+	0001  Crosstalk to PCI Bridge
+	0002  Linc I/O controller
+	0003  IOC3 I/O controller
+	0004  O2 MACE
+	0005  RAD Audio
+	0006  HPCEX
+	0007  RPCEX
+	0008  DiVO VIP
+	0009  AceNIC Gigabit Ethernet
+		10a9 8002  AceNIC Gigabit Ethernet
+	0010  AMP Video I/O
+	0011  GRIP
+	0012  SGH PSHAC GSN
+	1001  Magic Carpet
+	1002  Lithium
+	1003  Dual JPEG 1
+	1004  Dual JPEG 2
+	1005  Dual JPEG 3
+	1006  Dual JPEG 4
+	1007  Dual JPEG 5
+	1008  Cesium
+	100a  IOC4 I/O controller
+	2001  Fibre Channel
+	2002  ASDE
+	8001  O2 1394
+	8002  G-net NT
+10aa  ACC Microelectronics
+	0000  ACCM 2188
+10ab  Digicom
+10ac  Honeywell IAC
+10ad  Symphony Labs
+	0001  W83769F
+	0003  SL82C103
+	0005  SL82C105
+	0103  SL82c103
+	0105  SL82c105
+	0565  W83C553
+10ae  Cornerstone Technology
+10af  Micro Computer Systems Inc
+10b0  CardExpert Technology
+10b1  Cabletron Systems Inc
+10b2  Raytheon Company
+10b3  Databook Inc
+	3106  DB87144
+	b106  DB87144
+10b4  STB Systems Inc
+	1b1d  Velocity 128 3D
+		10b4 237e  Velocity 4400
+10b5  PLX Technology, Inc.
+	0001  i960 PCI bus interface
+	1076  VScom 800 8 port serial adaptor
+	1077  VScom 400 4 port serial adaptor
+	1078  VScom 210 2 port serial and 1 port parallel adaptor
+	1103  VScom 200 2 port serial adaptor
+	1146  VScom 010 1 port parallel adaptor
+	1147  VScom 020 2 port parallel adaptor
+	2724  Thales PCSM Security Card
+	8516  PEX 8516  Versatile PCI Express Switch
+	8532  PEX 8532  Versatile PCI Express Switch
+	9030  PCI <-> IOBus Bridge Hot Swap
+		10b5 2862  Alpermann+Velte PCL PCI LV (3V/5V): Timecode Reader Board
+		10b5 2906  Alpermann+Velte PCI TS (3V/5V): Time Synchronisation Board
+		10b5 2940  Alpermann+Velte PCL PCI D (3V/5V): Timecode Reader Board
+		10b5 3025  Alpermann+Velte PCL PCI L (3V/5V): Timecode Reader Board
+		10b5 3068  Alpermann+Velte PCL PCI HD (3V/5V): Timecode Reader Board
+		15ed 1002  MCCS 8-port Serial Hot Swap
+		15ed 1003  MCCS 16-port Serial Hot Swap
+	9036  9036
+	9050  PCI <-> IOBus Bridge
+		10b5 1067  IXXAT CAN i165
+		10b5 1172  IK220 (Heidenhain)
+		10b5 2036  SatPak GPS
+		10b5 2221  Alpermann+Velte PCL PCI LV: Timecode Reader Board
+		10b5 2273  SH-ARC SoHard ARCnet card
+		10b5 2431  Alpermann+Velte PCL PCI D: Timecode Reader Board
+		10b5 2905  Alpermann+Velte PCI TS: Time Synchronisation Board
+		10b5 9050  MP9050
+		1498 0362  TPMC866 8 Channel Serial Card
+		1522 0001  RockForce 4 Port V.90 Data/Fax/Voice Modem
+		1522 0002  RockForce 2 Port V.90 Data/Fax/Voice Modem
+		1522 0003  RockForce 6 Port V.90 Data/Fax/Voice Modem
+		1522 0004  RockForce 8 Port V.90 Data/Fax/Voice Modem
+		1522 0010  RockForce2000 4 Port V.90 Data/Fax/Voice Modem
+		1522 0020  RockForce2000 2 Port V.90 Data/Fax/Voice Modem
+		15ed 1000  Macrolink MCCS 8-port Serial
+		15ed 1001  Macrolink MCCS 16-port Serial
+		15ed 1002  Macrolink MCCS 8-port Serial Hot Swap
+		15ed 1003  Macrolink MCCS 16-port Serial Hot Swap
+# Sorry, there was a typo
+		5654 2036  OpenSwitch 6 Telephony card
+# Sorry, there was a typo
+		5654 3132  OpenSwitch 12 Telephony card
+		5654 5634  OpenLine4 Telephony Card
+		d531 c002  PCIntelliCAN 2xSJA1000 CAN bus
+		d84d 4006  EX-4006 1P
+		d84d 4008  EX-4008 1P EPP/ECP
+		d84d 4014  EX-4014 2P
+		d84d 4018  EX-4018 3P EPP/ECP
+		d84d 4025  EX-4025 1S(16C550) RS-232
+		d84d 4027  EX-4027 1S(16C650) RS-232
+		d84d 4028  EX-4028 1S(16C850) RS-232
+		d84d 4036  EX-4036 2S(16C650) RS-232
+		d84d 4037  EX-4037 2S(16C650) RS-232
+		d84d 4038  EX-4038 2S(16C850) RS-232
+		d84d 4052  EX-4052 1S(16C550) RS-422/485
+		d84d 4053  EX-4053 2S(16C550) RS-422/485
+		d84d 4055  EX-4055 4S(16C550) RS-232
+		d84d 4058  EX-4055 4S(16C650) RS-232
+		d84d 4065  EX-4065 8S(16C550) RS-232
+		d84d 4068  EX-4068 8S(16C650) RS-232
+		d84d 4078  EX-4078 2S(16C552) RS-232+1P
+	9054  PCI <-> IOBus Bridge
+		10b5 2455  Wessex Techology PHIL-PCI
+		10b5 2696  Innes Corp AM Radcap card
+		10b5 2717  Innes Corp Auricon card
+		10b5 2844  Innes Corp TVS Encoder card
+		12d9 0002  PCI Prosody Card rev 1.5
+		16df 0011  PIKA PrimeNet MM PCI
+		16df 0012  PIKA PrimeNet MM cPCI 8
+		16df 0013  PIKA PrimeNet MM cPCI 8 (without CAS Signaling Option)
+		16df 0014  PIKA PrimeNet MM cPCI 4
+		16df 0015  PIKA Daytona MM
+		16df 0016  PIKA InLine MM
+	9056  Francois
+		10b5 2979  CellinkBlade 11 - CPCI board VoATM AAL1
+	9060  9060
+	906d  9060SD
+		125c 0640  Aries 16000P
+	906e  9060ES
+	9080  9080
+		103c 10eb  (Agilent) E2777B 83K Series PCI based Optical Communication Interface
+		103c 10ec  (Agilent) E6978-66442 PCI CIC
+		10b5 9080  9080 [real subsystem ID not set]
+		129d 0002  Aculab PCI Prosidy card
+		12d9 0002  PCI Prosody Card
+		12df 4422  4422PCI ["Do-All" Telemetry Data Aquisition System]
+	bb04  B&B 3PCIOSD1A Isolated PCI Serial
+10b6  Madge Networks
+	0001  Smart 16/4 PCI Ringnode
+	0002  Smart 16/4 PCI Ringnode Mk2
+		10b6 0002  Smart 16/4 PCI Ringnode Mk2
+		10b6 0006  16/4 CardBus Adapter
+	0003  Smart 16/4 PCI Ringnode Mk3
+		0e11 b0fd  Compaq NC4621 PCI, 4/16, WOL
+		10b6 0003  Smart 16/4 PCI Ringnode Mk3
+		10b6 0007  Presto PCI Plus Adapter
+	0004  Smart 16/4 PCI Ringnode Mk1
+	0006  16/4 Cardbus Adapter
+		10b6 0006  16/4 CardBus Adapter
+	0007  Presto PCI Adapter
+		10b6 0007  Presto PCI
+	0009  Smart 100/16/4 PCI-HS Ringnode
+		10b6 0009  Smart 100/16/4 PCI-HS Ringnode
+	000a  Smart 100/16/4 PCI Ringnode
+		10b6 000a  Smart 100/16/4 PCI Ringnode
+	000b  16/4 CardBus Adapter Mk2
+		10b6 0008  16/4 CardBus Adapter Mk2
+		10b6 000b  16/4 Cardbus Adapter Mk2
+	000c  RapidFire 3140V2 16/4 TR Adapter
+		10b6 000c  RapidFire 3140V2 16/4 TR Adapter
+	1000  Collage 25/155 ATM Client Adapter
+	1001  Collage 155 ATM Server Adapter
+10b7  3Com Corporation
+	0001  3c985 1000BaseSX (SX/TX)
+	0013  AR5212 802.11abg NIC (3CRDAG675)
+		10b7 2031  3CRDAG675 11a/b/g Wireless PCI Adapter
+	0910  3C910-A01
+	1006  MINI PCI type 3B Data Fax Modem
+	1007  Mini PCI 56k Winmodem
+		10b7 615c  Mini PCI 56K Modem
+	1201  3c982-TXM 10/100baseTX Dual Port A [Hydra]
+	1202  3c982-TXM 10/100baseTX Dual Port B [Hydra]
+	1700  3c940 10/100/1000Base-T [Marvell]
+		1043 80eb  P4P800/K8V Deluxe motherboard
+		10b7 0010  3C940 Gigabit LOM Ethernet Adapter
+		10b7 0020  3C941 Gigabit LOM Ethernet Adapter
+		147b 1407  KV8-MAX3 motherboard
+	3390  3c339 TokenLink Velocity
+	3590  3c359 TokenLink Velocity XL
+		10b7 3590  TokenLink Velocity XL Adapter (3C359/359B)
+	4500  3c450 HomePNA [Tornado]
+	5055  3c555 Laptop Hurricane
+	5057  3c575 Megahertz 10/100 LAN CardBus [Boomerang]
+		10b7 5a57  3C575 Megahertz 10/100 LAN Cardbus PC Card
+	5157  3cCFE575BT Megahertz 10/100 LAN CardBus [Cyclone]
+		10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card
+	5257  3cCFE575CT CardBus [Cyclone]
+		10b7 5c57  FE575C-3Com 10/100 LAN CardBus-Fast Ethernet
+	5900  3c590 10BaseT [Vortex]
+	5920  3c592 EISA 10mbps Demon/Vortex
+	5950  3c595 100BaseTX [Vortex]
+	5951  3c595 100BaseT4 [Vortex]
+	5952  3c595 100Base-MII [Vortex]
+	5970  3c597 EISA Fast Demon/Vortex
+	5b57  3c595 Megahertz 10/100 LAN CardBus [Boomerang]
+		10b7 5b57  3C575 Megahertz 10/100 LAN Cardbus PC Card
+	6000  3CRSHPW796 [OfficeConnect Wireless CardBus]
+	6001  3com 3CRWE154G72 [Office Connect Wireless LAN Adapter]
+	6055  3c556 Hurricane CardBus [Cyclone]
+	6056  3c556B CardBus [Tornado]
+		10b7 6556  10/100 Mini PCI Ethernet Adapter
+	6560  3cCFE656 CardBus [Cyclone]
+		10b7 656a  3CCFEM656 10/100 LAN+56K Modem CardBus
+	6561  3cCFEM656 10/100 LAN+56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus
+	6562  3cCFEM656B 10/100 LAN+Winmodem CardBus [Cyclone]
+		10b7 656b  3CCFEM656B 10/100 LAN+56K Modem CardBus
+	6563  3cCFEM656B 10/100 LAN+56K Modem CardBus
+		10b7 656b  3CCFEM656 10/100 LAN+56K Modem CardBus
+	6564  3cXFEM656C 10/100 LAN+Winmodem CardBus [Tornado]
+	7646  3cSOHO100-TX Hurricane
+	7770  3CRWE777 PCI(PLX) Wireless Adaptor [Airconnect]
+	7940  3c803 FDDILink UTP Controller
+	7980  3c804 FDDILink SAS Controller
+	7990  3c805 FDDILink DAS Controller
+	80eb  3c940B 10/100/1000Base-T
+	8811  Token ring
+	9000  3c900 10BaseT [Boomerang]
+	9001  3c900 10Mbps Combo [Boomerang]
+	9004  3c900B-TPO Etherlink XL [Cyclone]
+		10b7 9004  3C900B-TPO Etherlink XL TPO 10Mb
+	9005  3c900B-Combo Etherlink XL [Cyclone]
+		10b7 9005  3C900B-Combo Etherlink XL Combo
+	9006  3c900B-TPC Etherlink XL [Cyclone]
+	900a  3c900B-FL 10base-FL [Cyclone]
+	9050  3c905 100BaseTX [Boomerang]
+	9051  3c905 100BaseT4 [Boomerang]
+	9055  3c905B 100BaseTX [Cyclone]
+		1028 0080  3C905B Fast Etherlink XL 10/100
+		1028 0081  3C905B Fast Etherlink XL 10/100
+		1028 0082  3C905B Fast Etherlink XL 10/100
+		1028 0083  3C905B Fast Etherlink XL 10/100
+		1028 0084  3C905B Fast Etherlink XL 10/100
+		1028 0085  3C905B Fast Etherlink XL 10/100
+		1028 0086  3C905B Fast Etherlink XL 10/100
+		1028 0087  3C905B Fast Etherlink XL 10/100
+		1028 0088  3C905B Fast Etherlink XL 10/100
+		1028 0089  3C905B Fast Etherlink XL 10/100
+		1028 0090  3C905B Fast Etherlink XL 10/100
+		1028 0091  3C905B Fast Etherlink XL 10/100
+		1028 0092  3C905B Fast Etherlink XL 10/100
+		1028 0093  3C905B Fast Etherlink XL 10/100
+		1028 0094  3C905B Fast Etherlink XL 10/100
+		1028 0095  3C905B Fast Etherlink XL 10/100
+		1028 0096  3C905B Fast Etherlink XL 10/100
+		1028 0097  3C905B Fast Etherlink XL 10/100
+		1028 0098  3C905B Fast Etherlink XL 10/100
+		1028 0099  3C905B Fast Etherlink XL 10/100
+		10b7 9055  3C905B Fast Etherlink XL 10/100
+	9056  3c905B-T4 Fast EtherLink XL [Cyclone]
+	9058  3c905B Deluxe Etherlink 10/100/BNC [Cyclone]
+	905a  3c905B-FX Fast Etherlink XL FX 100baseFx [Cyclone]
+	9200  3c905C-TX/TX-M [Tornado]
+		1028 0095  3C920 Integrated Fast Ethernet Controller
+		1028 0097  3C920 Integrated Fast Ethernet Controller
+		1028 00fe  Optiplex GX240
+		1028 012a  3C920 Integrated Fast Ethernet Controller [Latitude C640]
+		10b7 1000  3C905C-TX Fast Etherlink for PC Management NIC
+		10b7 7000  10/100 Mini PCI Ethernet Adapter
+		10f1 2466  Tiger MPX S2466 (3C920 Integrated Fast Ethernet Controller)
+	9201  3C920B-EMB Integrated Fast Ethernet Controller [Tornado]
+		1043 80ab  A7N8X Deluxe onboard 3C920B-EMB Integrated Fast Ethernet Controller
+	9202  3Com 3C920B-EMB-WNM Integrated Fast Ethernet Controller
+	9210  3C920B-EMB-WNM Integrated Fast Ethernet Controller
+	9300  3CSOHO100B-TX 910-A01 [tulip]
+	9800  3c980-TX Fast Etherlink XL Server Adapter [Cyclone]
+		10b7 9800  3c980-TX Fast Etherlink XL Server Adapter
+	9805  3c980-C 10/100baseTX NIC [Python-T]
+		10b7 1201  EtherLink Server 10/100 Dual Port A
+		10b7 1202  EtherLink Server 10/100 Dual Port B
+		10b7 9805  3c980 10/100baseTX NIC [Python-T]
+		10f1 2462  Thunder K7 S2462
+	9900  3C990-TX [Typhoon]
+	9902  3CR990-TX-95 [Typhoon 56-bit]
+	9903  3CR990-TX-97 [Typhoon 168-bit]
+	9904  3C990B-TX-M/3C990BSVR [Typhoon2]
+		10b7 1000  3CR990B-TX-M [Typhoon2]
+		10b7 2000  3CR990BSVR [Typhoon2 Server]
+	9905  3CR990-FX-95/97/95 [Typhon Fiber]
+		10b7 1101  3CR990-FX-95 [Typhoon Fiber 56-bit]
+		10b7 1102  3CR990-FX-97 [Typhoon Fiber 168-bit]
+		10b7 2101  3CR990-FX-95 Server [Typhoon Fiber 56-bit]
+		10b7 2102  3CR990-FX-97 Server [Typhoon Fiber 168-bit]
+	9908  3CR990SVR95 [Typhoon Server 56-bit]
+	9909  3CR990SVR97 [Typhoon Server 168-bit]
+	990a  3C990SVR [Typhoon Server]
+	990b  3C990SVR [Typhoon Server]
+10b8  Standard Microsystems Corp [SMC]
+	0005  83c170 EPIC/100 Fast Ethernet Adapter
+		1055 e000  LANEPIC 10/100 [EVB171Q-PCI]
+		1055 e002  LANEPIC 10/100 [EVB171G-PCI]
+		10b8 a011  EtherPower II 10/100
+		10b8 a014  EtherPower II 10/100
+		10b8 a015  EtherPower II 10/100
+		10b8 a016  EtherPower II 10/100
+		10b8 a017  EtherPower II 10/100
+	0006  83c175 EPIC/100 Fast Ethernet Adapter
+		1055 e100  LANEPIC Cardbus Fast Ethernet Adapter
+		1055 e102  LANEPIC Cardbus Fast Ethernet Adapter
+		1055 e300  LANEPIC Cardbus Fast Ethernet Adapter
+		1055 e302  LANEPIC Cardbus Fast Ethernet Adapter
+		10b8 a012  LANEPIC Cardbus Fast Ethernet Adapter
+		13a2 8002  LANEPIC Cardbus Fast Ethernet Adapter
+		13a2 8006  LANEPIC Cardbus Fast Ethernet Adapter
+	1000  FDC 37c665
+	1001  FDC 37C922
+# 802.11g card
+	2802  SMC2802W [EZ Connect g]
+	a011  83C170QF
+	b106  SMC34C90
+10b9  ALi Corporation
+	0101  CMI8338/C3DX PCI Audio Device
+	0111  C-Media CMI8738/C3DX Audio Device (OEM)
+		10b9 0111  C-Media CMI8738/C3DX Audio Device (OEM)
+	0780  Multi-IO Card
+	0782  Multi-IO Card
+	1435  M1435
+	1445  M1445
+	1449  M1449
+	1451  M1451
+	1461  M1461
+	1489  M1489
+	1511  M1511 [Aladdin]
+	1512  M1512 [Aladdin]
+	1513  M1513 [Aladdin]
+	1521  M1521 [Aladdin III]
+		10b9 1521  ALI M1521 Aladdin III CPU Bridge
+	1523  M1523
+		10b9 1523  ALI M1523 ISA Bridge
+	1531  M1531 [Aladdin IV]
+	1533  M1533 PCI to ISA Bridge [Aladdin IV]
+		1014 053b  ThinkPad R40e (2684-HVG) PCI to ISA Bridge
+		10b9 1533  ALI M1533 Aladdin IV ISA Bridge
+	1541  M1541
+		10b9 1541  ALI M1541 Aladdin V/V+ AGP System Controller
+	1543  M1543
+	1563  M1563 HyperTransport South Bridge
+	1621  M1621
+	1631  ALI M1631 PCI North Bridge Aladdin Pro III
+	1632  M1632M Northbridge+Trident
+	1641  ALI M1641 PCI North Bridge Aladdin Pro IV
+	1644  M1644/M1644T Northbridge+Trident
+	1646  M1646 Northbridge+Trident
+	1647  M1647 Northbridge [MAGiK 1 / MobileMAGiK 1]
+	1651  M1651/M1651T Northbridge [Aladdin-Pro 5/5M,Aladdin-Pro 5T/5TM]
+	1671  M1671 Super P4 Northbridge [AGP4X,PCI and SDR/DDR]
+	1672  M1672 Northbridge [CyberALADDiN-P4]
+	1681  M1681 P4 Northbridge [AGP8X,HyperTransport and SDR/DDR]
+	1687  M1687 K8 Northbridge [AGP8X and HyperTransport]
+	1689  M1689 K8 Northbridge [Super K8 Single Chip]
+	3141  M3141
+	3143  M3143
+	3145  M3145
+	3147  M3147
+	3149  M3149
+	3151  M3151
+	3307  M3307
+	3309  M3309
+	3323  M3325 Video/Audio Decoder
+	5212  M4803
+	5215  MS4803
+	5217  M5217H
+	5219  M5219
+	5225  M5225
+	5228  M5228 ALi ATA/RAID Controller
+	5229  M5229 IDE
+		1014 050f  ThinkPad R30
+		1014 053d  ThinkPad R40e (2684-HVG) builtin IDE
+		103c 0024  Pavilion ze4400 builtin IDE
+		1043 8053  A7A266 Motherboard IDE
+	5235  M5225
+	5237  USB 1.1 Controller
+		1014 0540  ThinkPad R40e (2684-HVG) builtin USB
+		103c 0024  Pavilion ze4400 builtin USB
+	5239  USB 2.0 Controller
+	5243  M1541 PCI to AGP Controller
+	5246  AGP8X Controller
+	5247  PCI to AGP Controller
+	5249  M5249 HTT to PCI Bridge
+	5251  M5251 P1394 OHCI 1.0 Controller
+	5253  M5253 P1394 OHCI 1.1 Controller
+	5261  M5261 Ethernet Controller
+	5263  M5263 Ethernet Controller
+	5281  ALi M5281 Serial ATA / RAID Host Controller
+	5287  ULi 5287 SATA
+	5289  ULi 5289 SATA
+	5450  Lucent Technologies Soft Modem AMR
+	5451  M5451 PCI AC-Link Controller Audio Device
+		1014 0506  ThinkPad R30
+		1014 053e  ThinkPad R40e (2684-HVG) builtin Audio
+		103c 0024  Pavilion ze4400 builtin Audio
+		10b9 5451  HP Compaq nc4010 (DY885AA#ABN)
+	5453  M5453 PCI AC-Link Controller Modem Device
+	5455  M5455 PCI AC-Link Controller Audio Device
+	5457  M5457 AC'97 Modem Controller
+		1014 0535  ThinkPad R40e (2684-HVG) builtin modem
+		103c 0024  Pavilion ze4400 builtin Modem Device
+# Same but more usefull for driver's lookup
+	5459  SmartLink SmartPCI561 56K Modem
+# SmartLink PCI SoftModem
+	545a  SmartLink SmartPCI563 56K Modem
+	5471  M5471 Memory Stick Controller
+	5473  M5473 SD-MMC Controller
+	7101  M7101 Power Management Controller [PMU]
+		1014 0510  ThinkPad R30
+		1014 053c  ThinkPad R40e (2684-HVG) Power Management Controller
+		103c 0024  Pavilion ze4400
+10ba  Mitsubishi Electric Corp.
+	0301  AccelGraphics AccelECLIPSE
+	0304  AccelGALAXY A2100 [OEM Evans & Sutherland]
+	0308  Tornado 3000 [OEM Evans & Sutherland]
+	1002  VG500 [VolumePro Volume Rendering Accelerator]
+10bb  Dapha Electronics Corporation
+10bc  Advanced Logic Research
+10bd  Surecom Technology
+	0e34  NE-34
+10be  Tseng Labs International Co.
+10bf  Most Inc
+10c0  Boca Research Inc.
+10c1  ICM Co., Ltd.
+10c2  Auspex Systems Inc.
+10c3  Samsung Semiconductors, Inc.
+	1100  Smartether100 SC1100 LAN Adapter (i82557B)
+10c4  Award Software International Inc.
+10c5  Xerox Corporation
+10c6  Rambus Inc.
+10c7  Media Vision
+10c8  Neomagic Corporation
+	0001  NM2070 [MagicGraph 128]
+	0002  NM2090 [MagicGraph 128V]
+	0003  NM2093 [MagicGraph 128ZV]
+	0004  NM2160 [MagicGraph 128XD]
+		1014 00ba  MagicGraph 128XD
+		1025 1007  MagicGraph 128XD
+		1028 0074  MagicGraph 128XD
+		1028 0075  MagicGraph 128XD
+		1028 007d  MagicGraph 128XD
+		1028 007e  MagicGraph 128XD
+		1033 802f  MagicGraph 128XD
+		104d 801b  MagicGraph 128XD
+		104d 802f  MagicGraph 128XD
+		104d 830b  MagicGraph 128XD
+		10ba 0e00  MagicGraph 128XD
+		10c8 0004  MagicGraph 128XD
+		10cf 1029  MagicGraph 128XD
+		10f7 8308  MagicGraph 128XD
+		10f7 8309  MagicGraph 128XD
+		10f7 830b  MagicGraph 128XD
+		10f7 830d  MagicGraph 128XD
+		10f7 8312  MagicGraph 128XD
+	0005  NM2200 [MagicGraph 256AV]
+		1014 00dd  ThinkPad 570
+		1028 0088  Latitude CPi A
+	0006  NM2360 [MagicMedia 256ZX]
+	0016  NM2380 [MagicMedia 256XL+]
+		10c8 0016  MagicMedia 256XL+
+	0025  NM2230 [MagicGraph 256AV+]
+	0083  NM2093 [MagicGraph 128ZV+]
+	8005  NM2200 [MagicMedia 256AV Audio]
+		0e11 b0d1  MagicMedia 256AV Audio Device on Discovery
+		0e11 b126  MagicMedia 256AV Audio Device on Durango
+		1014 00dd  MagicMedia 256AV Audio Device on BlackTip Thinkpad
+		1025 1003  MagicMedia 256AV Audio Device on TravelMate 720
+		1028 0088  Latitude CPi A
+		1028 008f  MagicMedia 256AV Audio Device on Colorado Inspiron
+		103c 0007  MagicMedia 256AV Audio Device on Voyager II
+		103c 0008  MagicMedia 256AV Audio Device on Voyager III
+		103c 000d  MagicMedia 256AV Audio Device on Omnibook 900
+		10c8 8005  MagicMedia 256AV Audio Device on FireAnt
+		110a 8005  MagicMedia 256AV Audio Device
+		14c0 0004  MagicMedia 256AV Audio Device
+	8006  NM2360 [MagicMedia 256ZX Audio]
+	8016  NM2380 [MagicMedia 256XL+ Audio]
+10c9  Dataexpert Corporation
+10ca  Fujitsu Microelectr., Inc.
+10cb  Omron Corporation
+# nee Mentor ARC Inc
+10cc  Mai Logic Incorporated
+	0660  Articia S Host Bridge
+	0661  Articia S PCI Bridge
+10cd  Advanced System Products, Inc
+	1100  ASC1100
+	1200  ASC1200 [(abp940) Fast SCSI-II]
+	1300  ABP940-U / ABP960-U
+		10cd 1310  ASC1300 SCSI Adapter
+	2300  ABP940-UW
+	2500  ABP940-U2W
+10ce  Radius
+# nee Citicorp TTI
+10cf  Fujitsu Limited.
+	2001  mb86605
+10d1  FuturePlus Systems Corp.
+10d2  Molex Incorporated
+10d3  Jabil Circuit Inc
+10d4  Hualon Microelectronics
+10d5  Autologic Inc.
+10d6  Cetia
+10d7  BCM Advanced Research
+10d8  Advanced Peripherals Labs
+10d9  Macronix, Inc. [MXIC]
+	0431  MX98715
+	0512  MX98713
+	0531  MX987x5
+		1186 1200  DFE-540TX ProFAST 10/100 Adapter
+	8625  MX86250
+	8888  MX86200
+10da  Compaq IPG-Austin
+	0508  TC4048 Token Ring 4/16
+	3390  Tl3c3x9
+10db  Rohm LSI Systems, Inc.
+10dc  CERN/ECP/EDU
+	0001  STAR/RD24 SCI-PCI (PMC)
+	0002  TAR/RD24 SCI-PCI (PMC)
+	0021  HIPPI destination
+	0022  HIPPI source
+	10dc  ATT2C15-3 FPGA
+10dd  Evans & Sutherland
+10de  nVidia Corporation
+	0008  NV1 [EDGE 3D]
+	0009  NV1 [EDGE 3D]
+	0010  NV2 [Mutara V08]
+	0020  NV4 [RIVA TNT]
+		1043 0200  V3400 TNT
+		1048 0c18  Erazor II SGRAM
+		1048 0c1b  Erazor II
+		1092 0550  Viper V550
+		1092 0552  Viper V550
+		1092 4804  Viper V550
+		1092 4808  Viper V550
+		1092 4810  Viper V550
+		1092 4812  Viper V550
+		1092 4815  Viper V550
+		1092 4820  Viper V550 with TV out
+		1092 4822  Viper V550
+		1092 4904  Viper V550
+		1092 4914  Viper V550
+		1092 8225  Viper V550
+		10b4 273d  Velocity 4400
+		10b4 273e  Velocity 4400
+		10b4 2740  Velocity 4400
+		10de 0020  Riva TNT
+		1102 1015  Graphics Blaster CT6710
+		1102 1016  Graphics Blaster RIVA TNT
+	0028  NV5 [RIVA TNT2/TNT2 Pro]
+		1043 0200  AGP-V3800 SGRAM
+		1043 0201  AGP-V3800 SDRAM
+		1043 0205  PCI-V3800
+		1043 4000  AGP-V3800PRO
+		1048 0c21  Synergy II
+		1048 0c31  Erazor III
+		107d 2134  WinFast 3D S320 II + TV-Out
+		1092 4804  Viper V770
+		1092 4a00  Viper V770
+		1092 4a02  Viper V770 Ultra
+		1092 5a00  RIVA TNT2/TNT2 Pro
+		1092 6a02  Viper V770 Ultra
+		1092 7a02  Viper V770 Ultra
+		10de 0005  RIVA TNT2 Pro
+		10de 000f  Compaq NVIDIA TNT2 Pro
+		1102 1020  3D Blaster RIVA TNT2
+		1102 1026  3D Blaster RIVA TNT2 Digital
+		14af 5810  Maxi Gamer Xentor
+	0029  NV5 [RIVA TNT2 Ultra]
+		1043 0200  AGP-V3800 Deluxe
+		1043 0201  AGP-V3800 Ultra SDRAM
+		1043 0205  PCI-V3800 Ultra
+		1102 1021  3D Blaster RIVA TNT2 Ultra
+		1102 1029  3D Blaster RIVA TNT2 Ultra
+		1102 102f  3D Blaster RIVA TNT2 Ultra
+		14af 5820  Maxi Gamer Xentor 32
+	002a  NV5 [Riva TnT2]
+	002b  NV5 [Riva TnT2]
+	002c  NV6 [Vanta/Vanta LT]
+		1043 0200  AGP-V3800 Combat SDRAM
+		1043 0201  AGP-V3800 Combat
+		1092 6820  Viper V730
+		1102 1031  CT6938 VANTA 8MB
+		1102 1034  CT6894 VANTA 16MB
+		14af 5008  Maxi Gamer Phoenix 2
+	002d  NV5M64 [RIVA TNT2 Model 64/Model 64 Pro]
+		1043 0200  AGP-V3800M
+		1043 0201  AGP-V3800M
+		1048 0c3a  Erazor III LT
+		10de 001e  M64 AGP4x
+		1102 1023  CT6892 RIVA TNT2 Value
+		1102 1024  CT6932 RIVA TNT2 Value 32Mb
+		1102 102c  CT6931 RIVA TNT2 Value [Jumper]
+		1462 8808  MSI-8808
+		1554 1041  Pixelview RIVA TNT2 M64
+		1569 002d  Palit Microsystems Daytona TNT2 M64
+	002e  NV6 [Vanta]
+	002f  NV6 [Vanta]
+	0034  MCP04 SMBus
+	0035  MCP04 IDE
+	0036  MCP04 Serial ATA Controller
+	0037  MCP04 Ethernet Controller
+	0038  MCP04 Ethernet Controller
+	003a  MCP04 AC'97 Audio Controller
+	003b  MCP04 USB Controller
+	003c  MCP04 USB Controller
+	003d  MCP04 PCI Bridge
+	003e  MCP04 Serial ATA Controller
+	0040  nv40 [GeForce 6800 Ultra]
+	0041  NV40 [GeForce 6800]
+	0042  NV40.2
+	0043  NV40.3
+	0045  NV40 [GeForce 6800 GT]
+	0049  NV40GL
+	004e  NV40GL [Quadro FX 4000]
+	0051  CK804 ISA Bridge
+	0052  CK804 SMBus
+	0053  CK804 IDE
+	0054  CK804 Serial ATA Controller
+	0055  CK804 Serial ATA Controller
+	0056  CK804 Ethernet Controller
+	0057  CK804 Ethernet Controller
+	0059  CK804 AC'97 Audio Controller
+	005a  CK804 USB Controller
+	005b  CK804 USB Controller
+	005c  CK804 PCI Bridge
+	005d  CK804 PCIE Bridge
+	005e  CK804 Memory Controller
+	0060  nForce2 ISA Bridge
+		1043 80ad  A7N8X Mainboard
+	0064  nForce2 SMBus (MCP)
+	0065  nForce2 IDE
+	0066  nForce2 Ethernet Controller
+		1043 80a7  A7N8X Mainboard onboard nForce2 Ethernet
+	0067  nForce2 USB Controller
+		1043 0c11  A7N8X Mainboard
+	0068  nForce2 USB Controller
+		1043 0c11  A7N8X Mainboard
+	006a  nForce2 AC97 Audio Controler (MCP)
+	006b  nForce Audio Processing Unit
+		10de 006b  nForce2 MCP Audio Processing Unit
+	006c  nForce2 External PCI Bridge
+	006d  nForce2 PCI Bridge
+	006e  nForce2 FireWire (IEEE 1394) Controller
+	0084  MCP2A SMBus
+	0085  MCP2A IDE
+	0086  MCP2A Ethernet Controller
+	0087  MCP2A USB Controller
+	0088  MCP2A USB Controller
+	008a  MCP2S AC'97 Audio Controller
+	008b  MCP2A PCI Bridge
+	008c  MCP2A Ethernet Controller
+	008e  nForce2 Serial ATA Controller
+	00a0  NV5 [Aladdin TNT2]
+		14af 5810  Maxi Gamer Xentor
+	00c0  NV41.0
+	00c1  NV41.1
+	00c2  NV41.2
+	00c8  NV41.8
+	00ce  NV41GL
+	00d0  nForce3 LPC Bridge
+	00d1  nForce3 Host Bridge
+	00d2  nForce3 AGP Bridge
+	00d3  CK804 Memory Controller
+	00d4  nForce3 SMBus
+	00d5  nForce3 IDE
+	00d6  nForce3 Ethernet
+	00d7  nForce3 USB 1.1
+	00d8  nForce3 USB 2.0
+	00da  nForce3 Audio
+	00dd  nForce3 PCI Bridge
+	00df  CK8S Ethernet Controller
+	00e0  nForce3 250Gb LPC Bridge
+	00e1  nForce3 250Gb Host Bridge
+	00e2  nForce3 250Gb AGP Host to PCI Bridge
+	00e3  CK8S Serial ATA Controller (v2.5)
+	00e4  nForce 250Gb PCI System Management
+	00e5  CK8S Parallel ATA Controller (v2.5)
+	00e6  CK8S Ethernet Controller
+	00e7  CK8S USB Controller
+	00e8  nForce3 EHCI USB 2.0 Controller
+	00ea  nForce3 250Gb AC'97 Audio Controller
+	00ed  nForce3 250Gb PCI-to-PCI Bridge
+	00ee  CK8S Serial ATA Controller (v2.5)
+	00f0  NV40 [GeForce 6800/GeForce 6800 Ultra]
+	00f1  NV43 [GeForce 6600/GeForce 6600 GT]
+	00f2  NV43 [GeForce 6600 GT]
+	00f8  NV45GL [Quadro FX 3400]
+	00f9  NV40 [GeForce 6800 Ultra/GeForce 6800 GT]
+		1682 2120  GEFORCE 6800 GT PCI-E
+	00fa  NV36 [GeForce PCX 5750]
+	00fb  NV35 [GeForce PCX 5900]
+	00fc  NV37GL [Quadro FX 330/GeForce PCX 5300]
+	00fd  NV37GL [Quadro FX 330]
+	00fe  NV38GL [Quadro FX 1300]
+	00ff  NV18 [GeForce PCX 4300]
+	0100  NV10 [GeForce 256 SDR]
+		1043 0200  AGP-V6600 SGRAM
+		1043 0201  AGP-V6600 SDRAM
+		1043 4008  AGP-V6600 SGRAM
+		1043 4009  AGP-V6600 SDRAM
+		1102 102d  CT6941 GeForce 256
+		14af 5022  3D Prophet SE
+	0101  NV10DDR [GeForce 256 DDR]
+		1043 0202  AGP-V6800 DDR
+		1043 400a  AGP-V6800 DDR SGRAM
+		1043 400b  AGP-V6800 DDR SDRAM
+		107d 2822  WinFast GeForce 256
+		1102 102e  CT6971 GeForce 256 DDR
+		14af 5021  3D Prophet DDR-DVI
+	0103  NV10GL [Quadro]
+	0110  NV11 [GeForce2 MX/MX 400]
+		1043 4015  AGP-V7100 Pro
+		1043 4031  V7100 Pro with TV output
+		10de 0091  Dell OEM GeForce 2 MX 400
+		1462 8817  MSI GeForce2 MX400 Pro32S [MS-8817]
+		14af 7102  3D Prophet II MX
+		14af 7103  3D Prophet II MX Dual-Display
+	0111  NV11DDR [GeForce2 MX 100 DDR/200 DDR]
+	0112  NV11 [GeForce2 Go]
+	0113  NV11GL [Quadro2 MXR/EX]
+	0140  NV43 [MSI NX6600GT-TD128E]
+	014f  NV43 [GeForce 6200]
+	0150  NV15 [GeForce2 GTS/Pro]
+		1043 4016  V7700 AGP Video Card
+		107d 2840  WinFast GeForce2 GTS with TV output
+		107d 2842  WinFast GeForce 2 Pro
+		1462 8831  Creative GeForce2 Pro
+	0151  NV15DDR [GeForce2 Ti]
+		1043 405f  V7700Ti
+		1462 5506  Creative 3D Blaster Geforce2 Titanium
+	0152  NV15BR [GeForce2 Ultra, Bladerunner]
+		1048 0c56  GLADIAC Ultra
+	0153  NV15GL [Quadro2 Pro]
+	0170  NV17 [GeForce4 MX 460]
+	0171  NV17 [GeForce4 MX 440]
+		10b0 0002  Gainward Pro/600 TV
+		1462 8661  G4MX440-VTP
+		1462 8730  MX440SES-T (MS-8873)
+		147b 8f00  Abit Siluro GeForce4MX440
+	0172  NV17 [GeForce4 MX 420]
+	0173  NV17 [GeForce4 MX 440-SE]
+	0174  NV17 [GeForce4 440 Go]
+	0175  NV17 [GeForce4 420 Go]
+	0176  NV17 [GeForce4 420 Go 32M]
+		4c53 1090  Cx9 / Vx9 mainboard
+	0177  NV17 [GeForce4 460 Go]
+	0178  NV17GL [Quadro4 550 XGL]
+	0179  NV17 [GeForce4 440 Go 64M]
+		10de 0179  GeForce4 MX (Mac)
+	017a  NV17GL [Quadro4 200/400 NVS]
+	017b  NV17GL [Quadro4 550 XGL]
+	017c  NV17GL [Quadro4 550 GoGL]
+	017d  NV17 [GeForce4 410 Go 16M]
+	0181  NV18 [GeForce4 MX 440 AGP 8x]
+		1043 806f  V9180 Magic
+		1462 8880  MS-StarForce GeForce4 MX 440 with AGP8X
+		1462 8900  MS-8890 GeForce 4 MX440 AGP8X
+		1462 9350  MSI Geforce4 MX T8X with AGP8X
+		147b 8f0d  Siluro GF4 MX-8X
+	0182  NV18 [GeForce4 MX 440SE AGP 8x]
+	0183  NV18 [GeForce4 MX 420 AGP 8x]
+	0185  NV18 [GeForce4 MX 4000 AGP 8x]
+	0186  NV18M [GeForce4 448 Go]
+	0187  NV18M [GeForce4 488 Go]
+	0188  NV18GL [Quadro4 580 XGL]
+	018a  NV18GL [Quadro4 NVS AGP 8x]
+	018b  NV18GL [Quadro4 380 XGL]
+	018d  NV18M [GeForce4 448 Go]
+	01a0  NVCrush11 [GeForce2 MX Integrated Graphics]
+	01a4  nForce CPU bridge
+	01ab  nForce 420 Memory Controller (DDR)
+	01ac  nForce 220/420 Memory Controller
+	01ad  nForce 220/420 Memory Controller
+	01b0  nForce Audio
+	01b1  nForce Audio
+	01b2  nForce ISA Bridge
+	01b4  nForce PCI System Management
+	01b7  nForce AGP to PCI Bridge
+	01b8  nForce PCI-to-PCI bridge
+	01bc  nForce IDE
+	01c1  nForce AC'97 Modem Controller
+	01c2  nForce USB Controller
+	01c3  nForce Ethernet Controller
+	01e0  nForce2 AGP (different version?)
+	01e8  nForce2 AGP
+	01ea  nForce2 Memory Controller 0
+	01eb  nForce2 Memory Controller 1
+	01ec  nForce2 Memory Controller 2
+	01ed  nForce2 Memory Controller 3
+	01ee  nForce2 Memory Controller 4
+	01ef  nForce2 Memory Controller 5
+	01f0  NV18 [GeForce4 MX - nForce GPU]
+	0200  NV20 [GeForce3]
+		1043 402f  AGP-V8200 DDR
+	0201  NV20 [GeForce3 Ti 200]
+	0202  NV20 [GeForce3 Ti 500]
+		1043 405b  V8200 T5
+		1545 002f  Xtasy 6964
+	0203  NV20DCC [Quadro DCC]
+	0240  C51 PCI Express Bridge
+	0241  C51 PCI Express Bridge
+	0242  C51 PCI Express Bridge
+	0243  C51 PCI Express Bridge
+	0244  C51 PCI Express Bridge
+	0245  C51 PCI Express Bridge
+	0246  C51 PCI Express Bridge
+	0247  C51 PCI Express Bridge
+	0248  C51 PCI Express Bridge
+	0249  C51 PCI Express Bridge
+	024a  C51 PCI Express Bridge
+	024b  C51 PCI Express Bridge
+	024c  C51 PCI Express Bridge
+	024d  C51 PCI Express Bridge
+	024e  C51 PCI Express Bridge
+	024f  C51 PCI Express Bridge
+	0250  NV25 [GeForce4 Ti 4600]
+	0251  NV25 [GeForce4 Ti 4400]
+		1043 8023  v8440 GeForce 4 Ti4400
+	0252  NV25 [GeForce4 Ti]
+	0253  NV25 [GeForce4 Ti 4200]
+		107d 2896  WinFast A250 LE TD (Dual VGA/TV-out/DVI)
+		147b 8f09  Siluro (Dual VGA/TV-out/DVI)
+	0258  NV25GL [Quadro4 900 XGL]
+	0259  NV25GL [Quadro4 750 XGL]
+	025b  NV25GL [Quadro4 700 XGL]
+	0260  MCP51 LPC Bridge
+	0261  MCP51 LPC Bridge
+	0262  MCP51 LPC Bridge
+	0263  MCP51 LPC Bridge
+	0264  MCP51 SMBus
+	0265  MCP51 IDE
+	0266  MCP51 Serial ATA Controller
+	0267  MCP51 Serial ATA Controller
+	0268  MCP51 Ethernet Controller
+	0269  MCP51 Ethernet Controller
+	026a  MCP51 MCI
+	026b  MCP51 AC97 Audio Controller
+	026c  MCP51 High Definition Audio
+	026d  MCP51 USB Controller
+	026e  MCP51 USB Controller
+	026f  MCP51 PCI Bridge
+	0270  MCP51 Host Bridge
+	0271  MCP51 PMU
+	0272  MCP51 Memory Controller 0
+	027e  C51 Memory Controller 2
+	027f  C51 Memory Controller 3
+	0280  NV28 [GeForce4 Ti 4800]
+	0281  NV28 [GeForce4 Ti 4200 AGP 8x]
+	0282  NV28 [GeForce4 Ti 4800 SE]
+	0286  NV28 [GeForce4 Ti 4200 Go AGP 8x]
+	0288  NV28GL [Quadro4 980 XGL]
+	0289  NV28GL [Quadro4 780 XGL]
+	028c  NV28GLM [Quadro4 700 GoGL]
+	02f0  C51 Host Bridge
+	02f1  C51 Host Bridge
+	02f2  C51 Host Bridge
+	02f3  C51 Host Bridge
+	02f4  C51 Host Bridge
+	02f5  C51 Host Bridge
+	02f6  C51 Host Bridge
+	02f7  C51 Host Bridge
+	02f8  C51 Memory Controller 5
+	02f9  C51 Memory Controller 4
+	02fa  C51 Memory Controller 0
+	02fb  C51 PCI Express Bridge
+	02fc  C51 PCI Express Bridge
+	02fd  C51 PCI Express Bridge
+	02fe  C51 Memory Controller 1
+	02ff  C51 Host Bridge
+	0300  NV30 [GeForce FX]
+	0301  NV30 [GeForce FX 5800 Ultra]
+	0302  NV30 [GeForce FX 5800]
+	0308  NV30GL [Quadro FX 2000]
+	0309  NV30GL [Quadro FX 1000]
+	0311  NV31 [GeForce FX 5600 Ultra]
+	0312  NV31 [GeForce FX 5600]
+	0313  NV31
+	0314  NV31 [GeForce FX 5600XT]
+		1043 814a  V9560XT/TD
+	0316  NV31
+	0317  NV31
+	031a  NV31M [GeForce FX Go 5600]
+	031b  NV31M [GeForce FX Go5650]
+	031c  NVIDIA Quadro FX 700 Go
+	031d  NV31
+	031e  NV31
+	031f  NV31
+	0320  NV34 [GeForce FX 5200]
+	0321  NV34 [GeForce FX 5200 Ultra]
+	0322  NV34 [GeForce FX 5200]
+		1462 9171  MS-8917 (FX5200-T128)
+	0323  NV34 [GeForce FX 5200LE]
+	0324  NV34M [GeForce FX Go 5200]
+		1071 8160  MIM2000
+	0325  NV34M [GeForce FX Go5250]
+	0326  NV34 [GeForce FX 5500]
+	0327  NV34 [GeForce FX 5100]
+	0328  NV34M [GeForce FX Go 5200]
+	0329  NV34M [GeForce FX Go5200]
+	032a  NV34GL [Quadro NVS 280 PCI]
+	032b  NV34GL [Quadro FX 500/600 PCI]
+	032c  NV34GLM [GeForce FX Go 5300]
+	032d  NV34 [GeForce FX Go5100]
+	032f  NV34
+	0330  NV35 [GeForce FX 5900 Ultra]
+	0331  NV35 [GeForce FX 5900]
+		1043 8145  V9950GE
+	0332  NV35 [GeForce FX 5900XT]
+	0333  NV38 [GeForce FX 5950 Ultra]
+	0334  NV35 [GeForce FX 5900ZT]
+	0338  NV35GL [Quadro FX 3000]
+	033f  NV35GL [Quadro FX 700]
+	0341  NV36.1 [GeForce FX 5700 Ultra]
+	0342  NV36.2 [GeForce FX 5700]
+	0343  NV36 [GeForce FX 5700LE]
+	0344  NV36.4 [GeForce FX 5700VE]
+	0345  NV36.5
+	0347  NV36 [GeForce FX Go5700]
+	0348  NV36 [GeForce FX Go5700]
+	0349  NV36
+	034b  NV36
+	034c  NV36 [Quadro FX Go1000]
+	034e  NV36GL [Quadro FX 1100]
+	034f  NV36GL
+10df  Emulex Corporation
+	1ae5  LP6000 Fibre Channel Host Adapter
+	1ae6  LP 8000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)
+	1ae7  LP 8000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:2-3)
+	f005  LP1150e Fibre Channel Host Adapter
+	f085  LP850 Fibre Channel Host Adapter
+	f095  LP952 Fibre Channel Host Adapter
+	f098  LP982 Fibre Channel Host Adapter
+	f0a5  LP1050 Fibre Channel Host Adapter
+	f0d5  LP1150 Fibre Channel Host Adapter
+	f100  LP11000e Fibre Channel Host Adapter
+	f700  LP7000 Fibre Channel Host Adapter
+	f701  LP 7000EFibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)
+	f800  LP8000 Fibre Channel Host Adapter
+	f801  LP 8000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)
+	f900  LP9000 Fibre Channel Host Adapter
+	f901  LP 9000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2)
+	f980  LP9802 Fibre Channel Host Adapter
+	f981  LP 9802 Fibre Channel Host Adapter Alternate ID
+	f982  LP 9802 Fibre Channel Host Adapter Alternate ID
+	fa00  LP10000 Fibre Channel Host Adapter
+	fa01  LP101 Fibre Channel Host Adapter
+	fd00  LP11000 Fibre Channel Host Adapter
+10e0  Integrated Micro Solutions Inc.
+	5026  IMS5026/27/28
+	5027  IMS5027
+	5028  IMS5028
+	8849  IMS8849
+	8853  IMS8853
+	9128  IMS9128 [Twin turbo 128]
+10e1  Tekram Technology Co.,Ltd.
+	0391  TRM-S1040
+		10e1 0391  DC-315U SCSI-3 Host Adapter
+	690c  DC-690c
+	dc29  DC-290
+10e2  Aptix Corporation
+10e3  Tundra Semiconductor Corp.
+	0000  CA91C042 [Universe]
+	0860  CA91C860 [QSpan]
+	0862  CA91C862A [QSpan-II]
+	8260  CA91L8200B [Dual PCI PowerSpan II]
+	8261  CA91L8260B [Single PCI PowerSpan II]
+10e4  Tandem Computers
+10e5  Micro Industries Corporation
+10e6  Gainbery Computer Products Inc.
+10e7  Vadem
+10e8  Applied Micro Circuits Corp.
+	1072  INES GPIB-PCI (AMCC5920 based)
+	2011  Q-Motion Video Capture/Edit board
+	4750  S5930 [Matchmaker]
+	5920  S5920
+	8043  LANai4.x [Myrinet LANai interface chip]
+	8062  S5933_PARASTATION
+	807d  S5933 [Matchmaker]
+	8088  Kongsberg Spacetec Format Synchronizer
+	8089  Kongsberg Spacetec Serial Output Board
+	809c  S5933_HEPC3
+	80d7  PCI-9112
+	80d9  PCI-9118
+	80da  PCI-9812
+	811a  PCI-IEEE1355-DS-DE Interface
+	814c  Fastcom ESCC-PCI (Commtech, Inc.)
+	8170  S5933 [Matchmaker] (Chipset Development Tool)
+# sold with Roper Scientifc(Photometrics) CoolSnap HQ camera
+	81e6  Multimedia video controller
+	8291  Fastcom 232/8-PCI (Commtech, Inc.)
+	82c4  Fastcom 422/4-PCI (Commtech, Inc.)
+	82c5  Fastcom 422/2-PCI (Commtech, Inc.)
+	82c6  Fastcom IG422/1-PCI (Commtech, Inc.)
+	82c7  Fastcom IG232/2-PCI (Commtech, Inc.)
+	82ca  Fastcom 232/4-PCI (Commtech, Inc.)
+	82db  AJA HDNTV HD SDI Framestore
+	82e2  Fastcom DIO24H-PCI (Commtech, Inc.)
+	8851  S5933 on Innes Corp FM Radio Capture card
+10e9  Alps Electric Co., Ltd.
+10ea  Intergraphics Systems
+	1680  IGA-1680
+	1682  IGA-1682
+	1683  IGA-1683
+	2000  CyberPro 2000
+	2010  CyberPro 2000A
+	5000  CyberPro 5000
+	5050  CyberPro 5050
+	5202  CyberPro 5202
+# CyberPro5202 Audio Function
+	5252  CyberPro5252
+10eb  Artists Graphics
+	0101  3GA
+	8111  Twist3 Frame Grabber
+10ec  Realtek Semiconductor Co., Ltd.
+	8029  RTL-8029(AS)
+		10b8 2011  EZ-Card (SMC1208)
+		10ec 8029  RTL-8029(AS)
+		1113 1208  EN1208
+		1186 0300  DE-528
+		1259 2400  AT-2400
+	8129  RTL-8129
+		10ec 8129  RT8129 Fast Ethernet Adapter
+	8138  RT8139 (B/C) Cardbus Fast Ethernet Adapter
+		10ec 8138  RT8139 (B/C) Fast Ethernet Adapter
+	8139  RTL-8139/8139C/8139C+
+		0357 000a  TTP-Monitoring Card V2.0
+		1025 005a  TravelMate 290
+		1025 8920  ALN-325
+		1025 8921  ALN-325
+		1071 8160  MIM2000
+		10bd 0320  EP-320X-R
+		10ec 8139  RT8139
+		1113 ec01  FNC-0107TX
+		1186 1300  DFE-538TX
+		1186 1320  SN5200
+		1186 8139  DRN-32TX
+		11f6 8139  FN22-3(A) LinxPRO Ethernet Adapter
+		1259 2500  AT-2500TX
+		1259 2503  AT-2500TX/ACPI
+		1429 d010  ND010
+		1432 9130  EN-9130TX
+		1436 8139  RT8139
+		1458 e000  GA-7VM400M/7VT600 Motherboard
+		146c 1439  FE-1439TX
+		1489 6001  GF100TXRII
+		1489 6002  GF100TXRA
+		149c 139a  LFE-8139ATX
+		149c 8139  LFE-8139TX
+		14cb 0200  LNR-100 Family 10/100 Base-TX Ethernet
+		1799 5000  F5D5000 PCI Card/Desktop Network PCI Card
+		2646 0001  EtheRx
+		8e2e 7000  KF-230TX
+		8e2e 7100  KF-230TX/2
+		a0a0 0007  ALN-325C
+	8169  RTL-8169 Gigabit Ethernet
+		1259 c107  CG-LAPCIGT
+		1371 434e  ProG-2000L
+		1458 e000  GA-K8VT800 Pro Motherboard
+		1462 702c  K8T NEO 2 motherboard
+	8180  RTL8180L 802.11b MAC
+	8197  SmartLAN56 56K Modem
+10ed  Ascii Corporation
+	7310  V7310
+10ee  Xilinx Corporation
+	3fc0  RME Digi96
+	3fc1  RME Digi96/8
+	3fc2  RME Digi96/8 Pro
+	3fc3  RME Digi96/8 Pad
+	3fc4  RME Digi9652 (Hammerfall)
+	3fc5  RME Hammerfall DSP
+	3fc6  RME Hammerfall DSP MADI
+	8381  Ellips Santos Frame Grabber
+10ef  Racore Computer Products, Inc.
+	8154  M815x Token Ring Adapter
+10f0  Peritek Corporation
+10f1  Tyan Computer
+10f2  Achme Computer, Inc.
+10f3  Alaris, Inc.
+10f4  S-MOS Systems, Inc.
+10f5  NKK Corporation
+	a001  NDR4000 [NR4600 Bridge]
+10f6  Creative Electronic Systems SA
+10f7  Matsushita Electric Industrial Co., Ltd.
+10f8  Altos India Ltd
+10f9  PC Direct
+10fa  Truevision
+	000c  TARGA 1000
+10fb  Thesys Gesellschaft für Mikroelektronik mbH
+	186f  TH 6255
+10fc  I-O Data Device, Inc.
+# What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives
+	0003  Cardbus IDE Controller
+	0005  Cardbus SCSI CBSC II
+10fd  Soyo Computer, Inc
+10fe  Fast Multimedia AG
+10ff  NCube
+1100  Jazz Multimedia
+1101  Initio Corporation
+	1060  INI-A100U2W
+	9100  INI-9100/9100W
+	9400  INI-940
+	9401  INI-950
+	9500  360P
+	9502  Initio INI-9100UW Ultra Wide SCSI Controller INIC-950P chip
+1102  Creative Labs
+	0002  SB Live! EMU10k1
+		1102 0020  CT4850 SBLive! Value
+		1102 0021  CT4620 SBLive!
+		1102 002f  SBLive! mainboard implementation
+		1102 4001  E-mu APS
+		1102 8022  CT4780 SBLive! Value
+		1102 8023  CT4790 SoundBlaster PCI512
+		1102 8024  CT4760 SBLive!
+		1102 8025  SBLive! Mainboard Implementation
+		1102 8026  CT4830 SBLive! Value
+		1102 8027  CT4832 SBLive! Value
+		1102 8028  CT4760 SBLive! OEM version
+		1102 8031  CT4831 SBLive! Value
+		1102 8040  CT4760 SBLive!
+		1102 8051  CT4850 SBLive! Value
+		1102 8061  SBLive! Player 5.1
+		1102 8064  SB Live! 5.1 Model SB0100
+		1102 8065  SBLive! 5.1 Digital Model SB0220
+		1102 8067  SBLive! 5.1 eMicro 28028
+	0004  SB Audigy
+		1102 0051  SB0090 Audigy Player
+		1102 0053  SB0090 Audigy Player/OEM
+		1102 0058  SB0090 Audigy Player/OEM
+		1102 1007  SB0240 Audigy 2 Platinum 6.1
+		1102 2002  SB Audigy 2 ZS (SB0350)
+	0006  [SB Live! Value] EMU10k1X
+	0007  SB Audigy LS
+		1102 1001  SB0310 Audigy LS
+		1102 1002  SB0312 Audigy LS
+		1102 1006  SB0410 SBLive! 24-bit
+	0008  SB0400 Audigy2 Value
+	4001  SB Audigy FireWire Port
+		1102 0010  SB Audigy FireWire Port
+	7002  SB Live! MIDI/Game Port
+		1102 0020  Gameport Joystick
+	7003  SB Audigy MIDI/Game port
+		1102 0040  SB Audigy MIDI/Game Port
+	7004  [SB Live! Value] Input device controller
+	7005  SB Audigy LS MIDI/Game port
+		1102 1001  SB0310 Audigy LS MIDI/Game port
+		1102 1002  SB0312 Audigy LS MIDI/Game port
+	8064  SB0100 [SBLive! 5.1 OEM]
+	8938  Ectiva EV1938
+		1033 80e5  SlimTower-Jim (NEC)
+		1071 7150  Mitac 7150
+		110a 5938  Siemens Scenic Mobile 510PIII
+		13bd 100c  Ceres-C (Sharp, Intel BX)
+		13bd 100d  Sharp, Intel Banister
+		13bd 100e  TwinHead P09S/P09S3 (Sharp)
+		13bd f6f1  Marlin (Sharp)
+		14ff 0e70  P88TE (TWINHEAD INTERNATIONAL Corp)
+		14ff c401  Notebook 9100/9200/2000 (TWINHEAD INTERNATIONAL Corp)
+		156d b400  G400 - Geo (AlphaTop (Taiwan))
+		156d b550  G560  (AlphaTop (Taiwan))
+		156d b560  G560  (AlphaTop (Taiwan))
+		156d b700  G700/U700  (AlphaTop (Taiwan))
+		156d b795  G795  (AlphaTop (Taiwan))
+		156d b797  G797  (AlphaTop (Taiwan))
+1103  Triones Technologies, Inc.
+	0003  HPT343
+	0004  HPT366/368/370/370A/372/372N
+		1103 0001  HPT370A
+		1103 0003  HPT343 / HPT345 / HPT363 UDMA33
+		1103 0004  HPT366 UDMA66 (r1) / HPT368 UDMA66 (r2) / HPT370 UDMA100 (r3) / HPT370 UDMA100 RAID (r4)
+		1103 0005  HPT370 UDMA100
+		1103 0006  HPT302
+		1103 0007  HPT371 UDMA133
+		1103 0008  HPT374 UDMA/ATA133 RAID Controller
+	0005  HPT372A/372N
+	0006  HPT302
+	0007  HPT371/371N
+	0008  HPT374
+	0009  HPT372N
+1104  RasterOps Corp.
+1105  Sigma Designs, Inc.
+	1105  REALmagic Xcard MPEG 1/2/3/4 DVD Decoder
+	8300  REALmagic Hollywood Plus DVD Decoder
+	8400  EM840x REALmagic DVD/MPEG-2 Audio/Video Decoder
+	8401  EM8401 REALmagic DVD/MPEG-2 A/V Decoder
+	8470  EM8470 REALmagic DVD/MPEG-4 A/V Decoder
+	8471  EM8471 REALmagic DVD/MPEG-4 A/V Decoder
+	8475  EM8475 REALmagic DVD/MPEG-4 A/V Decoder
+	8476  EM8476 REALmagic DVD/MPEG-4 A/V Decoder
+	8485  EM8485 REALmagic DVD/MPEG-4 A/V Decoder
+	8486  EM8486 REALmagic DVD/MPEG-4 A/V Decoder
+1106  VIA Technologies, Inc.
+	0102  Embedded VIA Ethernet Controller
+	0130  VT6305 1394.A Controller
+	0305  VT8363/8365 [KT133/KM133]
+		1043 8033  A7V Mainboard
+		1043 803e  A7V-E Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
+		147b a401  KT7/KT7-RAID/KT7A/KT7A-RAID Mainboard
+	0391  VT8371 [KX133]
+	0501  VT8501 [Apollo MVP4]
+	0505  VT82C505
+# Shares chip with :0576. The VT82C576M has :1571 instead of :0561.
+	0561  VT82C576MV
+	0571  VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE
+		1019 0985  P6VXA Motherboard
+		1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)
+		1043 8052  VT8233A Bus Master ATA100/66/33 IDE
+		1043 808c  A7V8X motherboard
+		1043 80a1  A7V8X-X motherboard rev. 1.01
+		1043 80ed  A7V600 motherboard
+		1106 0571  VT82C586/B/VT82C686/A/B/VT8233/A/C/VT8235 PIPC Bus Master IDE
+		1179 0001  Magnia Z310
+		1297 f641  FX41 motherboard
+		1458 5002  GA-7VAX Mainboard
+		1462 7020  K8T NEO 2 motherboard
+		147b 1407  KV8-MAX3 motherboard
+		1849 0571  K7VT2 motherboard
+	0576  VT82C576 3V [Apollo Master]
+	0585  VT82C585VP [Apollo VP1/VPX]
+	0586  VT82C586/A/B PCI-to-ISA [Apollo VP]
+		1106 0000  MVP3 ISA Bridge
+	0595  VT82C595 [Apollo VP2]
+	0596  VT82C596 ISA [Mobile South]
+		1106 0000  VT82C596/A/B PCI to ISA Bridge
+		1458 0596  VT82C596/A/B PCI to ISA Bridge
+	0597  VT82C597 [Apollo VP3]
+	0598  VT82C598 [Apollo MVP3]
+	0601  VT8601 [Apollo ProMedia]
+	0605  VT8605 [ProSavage PM133]
+		1043 802c  CUV4X mainboard
+	0680  VT82C680 [Apollo P6]
+	0686  VT82C686 [Apollo Super South]
+		1019 0985  P6VXA Motherboard
+		1043 802c  CUV4X mainboard
+		1043 8033  A7V Mainboard
+		1043 803e  A7V-E Mainboard
+		1043 8040  A7M266 Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
+		1106 0000  VT82C686/A PCI to ISA Bridge
+		1106 0686  VT82C686/A PCI to ISA Bridge
+		1179 0001  Magnia Z310
+		147b a702  KG7-Lite Mainboard
+	0691  VT82C693A/694x [Apollo PRO133x]
+		1019 0985  P6VXA Motherboard
+		1179 0001  Magnia Z310
+		1458 0691  VT82C691 Apollo Pro System Controller
+	0693  VT82C693 [Apollo Pro Plus]
+	0698  VT82C693A [Apollo Pro133 AGP]
+	0926  VT82C926 [Amazon]
+	1000  VT82C570MV
+	1106  VT82C570MV
+	1571  VT82C576M/VT82C586
+	1595  VT82C595/97 [Apollo VP2/97]
+	3022  CLE266
+# This is *not* USB 2.0 as the existing entry suggests
+	3038  VT82xxxxx UHCI USB 1.1 Controller
+		0925 1234  USB Controller
+		1019 0985  P6VXA Motherboard
+		1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)
+		1043 808c  VT6202 USB2.0 4 port controller
+		1043 80a1  A7V8X-X motherboard
+		1043 80ed  A7V600 motherboard
+		1179 0001  Magnia Z310
+		1458 5004  GA-7VAX Mainboard
+		1462 7020  K8T NEO 2 motherboard
+		147b 1407  KV8-MAX3 motherboard
+		182d 201d  CN-029 USB2.0 4 port PCI Card
+	3040  VT82C586B ACPI
+	3043  VT86C100A [Rhine]
+		10bd 0000  VT86C100A Fast Ethernet Adapter
+		1106 0100  VT86C100A Fast Ethernet Adapter
+		1186 1400  DFE-530TX rev A
+	3044  IEEE 1394 Host Controller
+		1025 005a  TravelMate 290
+		1458 1000  GA-7VT600-1394 Motherboard
+		1462 702d  K8T NEO 2 motherboard
+	3050  VT82C596 Power Management
+	3051  VT82C596 Power Management
+	3053  VT6105M [Rhine-III]
+	3057  VT82C686 [Apollo Super ACPI]
+		1019 0985  P6VXA Motherboard
+		1043 8033  A7V Mainboard
+		1043 803e  A7V-E Mainboard
+		1043 8040  A7M266 Mainboard
+		1043 8042  A7V133/A7V133-C Mainboard
+		1179 0001  Magnia Z310
+	3058  VT82C686 AC97 Audio Controller
+		0e11 0097  SoundMax Digital Integrated Audio
+		0e11 b194  Soundmax integrated digital audio
+		1019 0985  P6VXA Motherboard
+		1043 1106  A7V133/A7V133-C Mainboard
+		1106 4511  Onboard Audio on EP7KXA
+		1458 7600  Onboard Audio
+		1462 3091  MS-6309 Onboard Audio
+		1462 3300  MS-6330 Onboard Audio
+		15dd 7609  Onboard Audio
+	3059  VT8233/A/8235/8237 AC97 Audio Controller
+		1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)
+		1043 8095  A7V8X Motherboard (Realtek ALC650 codec)
+		1043 80a1  A7V8X-X Motherboard
+		1043 80b0  A7V600/K8V Deluxe motherboard (ADI AD1980 codec [SoundMAX])
+		1106 3059  L7VMM2 Motherboard
+		1106 4161  K7VT2 motherboard
+		1297 c160  FX41 motherboard (Realtek ALC650 codec)
+		1458 a002  GA-7VAX Onboard Audio (Realtek ALC650)
+		1462 0080  K8T NEO 2 motherboard
+		1462 3800  KT266 onboard audio
+		147b 1407  KV8-MAX3 motherboard
+	3065  VT6102 [Rhine-II]
+		1043 80a1  A7V8X-X Motherboard
+		1106 0102  VT6102 [Rhine II] Embeded Ethernet Controller on VT8235
+		1186 1400  DFE-530TX rev A
+		1186 1401  DFE-530TX rev B
+		13b9 1421  LD-10/100AL PCI Fast Ethernet Adapter (rev.B)
+# This hosts more than just the Intel 537 codec, it also hosts PCtel (SIL33) and SmartLink (SIL34) codecs
+	3068  AC'97 Modem Controller
+		1462 309e  MS-6309 Saturn Motherboard
+	3074  VT8233 PCI to ISA Bridge
+		1043 8052  VT8233A
+	3091  VT8633 [Apollo Pro266]
+	3099  VT8366/A/7 [Apollo KT266/A/333]
+		1043 8064  A7V266-E Mainboard
+		1043 807f  A7V333 Mainboard
+		1849 3099  K7VT2 motherboard
+	3101  VT8653 Host Bridge
+	3102  VT8662 Host Bridge
+	3103  VT8615 Host Bridge
+	3104  USB 2.0
+		1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)
+		1043 808c  A7V8X motherboard
+		1043 80a1  A7V8X-X motherboard rev 1.01
+		1043 80ed  A7V600 motherboard
+		1297 f641  FX41 motherboard
+		1458 5004  GA-7VAX Mainboard
+		1462 7020  K8T NEO 2 motherboard
+		147b 1407  KV8-MAX3 motherboard
+		182d 201d  CN-029 USB 2.0 4 port PCI Card
+	3106  VT6105 [Rhine-III]
+		1186 1403  DFE-530TX rev C
+	3108  S3 Unichrome Pro VGA Adapter
+	3109  VT8233C PCI to ISA Bridge
+	3112  VT8361 [KLE133] Host Bridge
+	3116  VT8375 [KM266/KL266] Host Bridge
+		1297 f641  FX41 motherboard
+	3118  S3 Unichrome Pro VGA Adapter
+	3119  VT6120/VT6121/VT6122 Gigabit Ethernet Adapter
+# found on EPIA M6000/9000 mainboard
+	3122  VT8623 [Apollo CLE266] integrated CastleRock graphics
+# found on EPIA M6000/9000 mainboard
+	3123  VT8623 [Apollo CLE266]
+	3128  VT8753 [P4X266 AGP]
+	3133  VT3133 Host Bridge
+	3147  VT8233A ISA Bridge
+	3148  P4M266 Host Bridge
+	3149  VIA VT6420 SATA RAID Controller
+		1043 80ed  A7V600/K8V Deluxe motherboard
+		1458 b003  GA-7VM400AM(F) Motherboard
+		1462 7020  K8T Neo 2 Motherboard
+		147b 1407  KV8-MAX3 motherboard
+	3156  P/KN266 Host Bridge
+# on ASUS P4P800
+	3164  VT6410 ATA133 RAID controller
+	3168  VT8374 P4X400 Host Controller/AGP Bridge
+	3177  VT8235 ISA Bridge
+		1019 0a81  L7VTA v1.0 Motherboard (KT400-8235)
+		1043 808c  A7V8X motherboard
+		1043 80a1  A7V8X-X motherboard
+		1297 f641  FX41 motherboard
+		1458 5001  GA-7VAX Mainboard
+		1849 3177  K7VT2 motherboard
+	3178  ProSavageDDR P4N333 Host Bridge
+	3188  VT8385 [K8T800 AGP] Host Bridge
+		1043 80a3  K8V Deluxe motherboard
+		147b 1407  KV8-MAX3 motherboard
+	3189  VT8377 [KT400/KT600 AGP] Host Bridge
+		1043 807f  A7V8X motherboard
+		1458 5000  GA-7VAX Mainboard
+	3204  K8M800
+	3205  VT8378 [KM400/A] Chipset Host Bridge
+		1458 5000  GA-7VM400M Motherboard
+	3218  K8T800M Host Bridge
+	3227  VT8237 ISA bridge [KT600/K8T800 South]
+		1043 80ed  A7V600 motherboard
+		1106 3227  DFI KT600-AL Motherboard
+		1458 5001  GA-7VT600 Motherboard
+		147b 1407  KV8-MAX3 motherboard
+	3249  VT6421 IDE RAID Controller
+	4149  VIA VT6420 (ATA133) Controller
+	5030  VT82C596 ACPI [Apollo PRO]
+	6100  VT85C100A [Rhine II]
+	7204  K8M800
+# S3 Graphics UniChrome™ 2D/3D Graphics with motion compensation
+	7205  VT8378 [S3 UniChrome] Integrated Video
+		1458 d000  Gigabyte GA-7VM400(A)M(F) Motherboard
+	8231  VT8231 [PCI-to-ISA Bridge]
+	8235  VT8235 ACPI
+	8305  VT8363/8365 [KT133/KM133 AGP]
+	8391  VT8371 [KX133 AGP]
+	8501  VT8501 [Apollo MVP4 AGP]
+	8596  VT82C596 [Apollo PRO AGP]
+	8597  VT82C597 [Apollo VP3 AGP]
+	8598  VT82C598/694x [Apollo MVP3/Pro133x AGP]
+		1019 0985  P6VXA Motherboard
+	8601  VT8601 [Apollo ProMedia AGP]
+	8605  VT8605 [PM133 AGP]
+	8691  VT82C691 [Apollo Pro]
+	8693  VT82C693 [Apollo Pro Plus] PCI Bridge
+	b091  VT8633 [Apollo Pro266 AGP]
+	b099  VT8366/A/7 [Apollo KT266/A/333 AGP]
+	b101  VT8653 AGP Bridge
+	b102  VT8362 AGP Bridge
+	b103  VT8615 AGP Bridge
+	b112  VT8361 [KLE133] AGP Bridge
+	b168  VT8235 PCI Bridge
+	b188  VT8237 PCI bridge [K8T800 South]
+		147b 1407  KV8-MAX3 motherboard
+	b198  VT8237 PCI Bridge
+# 32-Bit PCI bus master Ethernet MAC with standard MII interface
+	d104  VT8237 Integrated Fast Ethernet Controller
+1107  Stratus Computers
+	0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)
+1108  Proteon, Inc.
+	0100  p1690plus_AA
+	0101  p1690plus_AB
+	0105  P1690Plus
+	0108  P1690Plus
+	0138  P1690Plus
+	0139  P1690Plus
+	013c  P1690Plus
+	013d  P1690Plus
+1109  Cogent Data Technologies, Inc.
+	1400  EM110TX [EX110TX]
+110a  Siemens Nixdorf AG
+	0002  Pirahna 2-port
+	0005  Tulip controller, power management, switch extender
+	0006  FSC PINC (I/O-APIC)
+	0015  FSC Multiprocessor Interrupt Controller
+	001d  FSC Copernicus Management Controller
+	007b  FSC Remote Service Controller, mailbox device
+	007c  FSC Remote Service Controller, shared memory device
+	007d  FSC Remote Service Controller, SMIC device
+# Superfastcom-PCI (Commtech, Inc.) or DSCC4 WAN Adapter
+	2102  DSCC4 PEB/PEF 20534 DMA Supported Serial Communication Controller with 4 Channels
+	2104  Eicon Diva 2.02 compatible passive ISDN card
+	3142  SIMATIC NET CP 5613A1 (Profibus Adapter)
+	4021  SIMATIC NET CP 5512 (Profibus and MPI Cardbus Adapter)
+	4029  SIMATIC NET CP 5613A2 (Profibus Adapter)
+	4942  FPGA I-Bus Tracer for MBD
+	6120  SZB6120
+110b  Chromatic Research Inc.
+	0001  Mpact Media Processor
+	0004  Mpact 2
+110c  Mini-Max Technology, Inc.
+110d  Znyx Advanced Systems
+110e  CPU Technology
+110f  Ross Technology
+1110  Powerhouse Systems
+	6037  Firepower Powerized SMP I/O ASIC
+	6073  Firepower Powerized SMP I/O ASIC
+1111  Santa Cruz Operation
+# Also claimed to be RNS or Rockwell International, current PCISIG records list Osicom
+1112  Osicom Technologies Inc
+	2200  FDDI Adapter
+	2300  Fast Ethernet Adapter
+	2340  4 Port Fast Ethernet Adapter
+	2400  ATM Adapter
+1113  Accton Technology Corporation
+	1211  SMC2-1211TX
+		103c 1207  EN-1207D Fast Ethernet Adapter
+		1113 1211  EN-1207D Fast Ethernet Adapter
+	1216  EN-1216 Ethernet Adapter
+		1113 2242  EN2242 10/100 Ethernet Mini-PCI Card
+		111a 1020  SpeedStream 1020 PCI 10/100 Ethernet Adaptor [EN-1207F-TX ?]
+	1217  EN-1217 Ethernet Adapter
+	5105  10Mbps Network card
+	9211  EN-1207D Fast Ethernet Adapter
+		1113 9211  EN-1207D Fast Ethernet Adapter
+	9511  21x4x DEC-Tulip compatible Fast Ethernet
+	d301  CPWNA100 (Philips wireless PCMCIA)
+	ec02  SMC 1244TX v3
+1114  Atmel Corporation
+	0506  802.11b Wireless Network Adaptor (at76c506)
+1115  3D Labs
+1116  Data Translation
+	0022  DT3001
+	0023  DT3002
+	0024  DT3003
+	0025  DT3004
+	0026  DT3005
+	0027  DT3001-PGL
+	0028  DT3003-PGL
+1117  Datacube, Inc
+	9500  Max-1C SVGA card
+	9501  Max-1C image processing
+1118  Berg Electronics
+1119  ICP Vortex Computersysteme GmbH
+	0000  GDT 6000/6020/6050
+	0001  GDT 6000B/6010
+	0002  GDT 6110/6510
+	0003  GDT 6120/6520
+	0004  GDT 6530
+	0005  GDT 6550
+	0006  GDT 6117/6517
+	0007  GDT 6127/6527
+	0008  GDT 6537
+	0009  GDT 6557/6557-ECC
+	000a  GDT 6115/6515
+	000b  GDT 6125/6525
+	000c  GDT 6535
+	000d  GDT 6555
+	0010  GDT 6115/6515
+	0011  GDT 6125/6525
+	0012  GDT 6535
+	0013  GDT 6555/6555-ECC
+	0100  GDT 6117RP/6517RP
+	0101  GDT 6127RP/6527RP
+	0102  GDT 6537RP
+	0103  GDT 6557RP
+	0104  GDT 6111RP/6511RP
+	0105  GDT 6121RP/6521RP
+	0110  GDT 6117RD/6517RD
+	0111  GDT 6127RD/6527RD
+	0112  GDT 6537RD
+	0113  GDT 6557RD
+	0114  GDT 6111RD/6511RD
+	0115  GDT 6121RD/6521RD
+	0118  GDT 6118RD/6518RD/6618RD
+	0119  GDT 6128RD/6528RD/6628RD
+	011a  GDT 6538RD/6638RD
+	011b  GDT 6558RD/6658RD
+	0120  GDT 6117RP2/6517RP2
+	0121  GDT 6127RP2/6527RP2
+	0122  GDT 6537RP2
+	0123  GDT 6557RP2
+	0124  GDT 6111RP2/6511RP2
+	0125  GDT 6121RP2/6521RP2
+	0136  GDT 6113RS/6513RS
+	0137  GDT 6123RS/6523RS
+	0138  GDT 6118RS/6518RS/6618RS
+	0139  GDT 6128RS/6528RS/6628RS
+	013a  GDT 6538RS/6638RS
+	013b  GDT 6558RS/6658RS
+	013c  GDT 6533RS/6633RS
+	013d  GDT 6543RS/6643RS
+	013e  GDT 6553RS/6653RS
+	013f  GDT 6563RS/6663RS
+	0166  GDT 7113RN/7513RN/7613RN
+	0167  GDT 7123RN/7523RN/7623RN
+	0168  GDT 7118RN/7518RN/7518RN
+	0169  GDT 7128RN/7528RN/7628RN
+	016a  GDT 7538RN/7638RN
+	016b  GDT 7558RN/7658RN
+	016c  GDT 7533RN/7633RN
+	016d  GDT 7543RN/7643RN
+	016e  GDT 7553RN/7653RN
+	016f  GDT 7563RN/7663RN
+	01d6  GDT 4x13RZ
+	01d7  GDT 4x23RZ
+	01f6  GDT 8x13RZ
+	01f7  GDT 8x23RZ
+	01fc  GDT 8x33RZ
+	01fd  GDT 8x43RZ
+	01fe  GDT 8x53RZ
+	01ff  GDT 8x63RZ
+	0210  GDT 6519RD/6619RD
+	0211  GDT 6529RD/6629RD
+	0260  GDT 7519RN/7619RN
+	0261  GDT 7529RN/7629RN
+	02ff  GDT MAXRP
+	0300  GDT NEWRX
+111a  Efficient Networks, Inc
+	0000  155P-MF1 (FPGA)
+	0002  155P-MF1 (ASIC)
+	0003  ENI-25P ATM
+		111a 0000  ENI-25p Miniport ATM Adapter
+	0005  SpeedStream (LANAI)
+		111a 0001  ENI-3010 ATM
+		111a 0009  ENI-3060 ADSL (VPI=0)
+		111a 0101  ENI-3010 ATM
+		111a 0109  ENI-3060CO ADSL (VPI=0)
+		111a 0809  ENI-3060 ADSL (VPI=0 or 8)
+		111a 0909  ENI-3060CO ADSL (VPI=0 or 8)
+		111a 0a09  ENI-3060 ADSL (VPI=<0..15>)
+	0007  SpeedStream ADSL
+		111a 1001  ENI-3061 ADSL [ASIC]
+	1203  SpeedStream 1023 Wireless PCI Adapter
+111b  Teledyne Electronic Systems
+111c  Tricord Systems Inc.
+	0001  Powerbis Bridge
+111d  Integrated Device Technology, Inc.
+	0001  IDT77201/77211 155Mbps ATM SAR Controller [NICStAR]
+	0003  IDT77222/77252 155Mbps ATM MICRO ABR SAR Controller
+	0004  IDT77V252 155Mbps ATM MICRO ABR SAR Controller
+	0005  IDT77V222 155Mbps ATM MICRO ABR SAR Controller
+111e  Eldec
+111f  Precision Digital Images
+	4a47  Precision MX Video engine interface
+	5243  Frame capture bus interface
+1120  EMC Corporation
+1121  Zilog
+1122  Multi-tech Systems, Inc.
+1123  Excellent Design, Inc.
+1124  Leutron Vision AG
+1125  Eurocore
+1126  Vigra
+1127  FORE Systems Inc
+	0200  ForeRunner PCA-200 ATM
+	0210  PCA-200PC
+	0250  ATM
+	0300  ForeRunner PCA-200EPC ATM
+	0310  ATM
+	0400  ForeRunnerHE ATM Adapter
+		1127 0400  ForeRunnerHE ATM
+1129  Firmworks
+112a  Hermes Electronics Company, Ltd.
+112b  Linotype - Hell AG
+112c  Zenith Data Systems
+112d  Ravicad
+112e  Infomedia Microelectronics Inc.
+112f  Imaging Technology Inc
+	0000  MVC IC-PCI
+	0001  MVC IM-PCI Video frame grabber/processor
+1130  Computervision
+1131  Philips Semiconductors
+	1561  USB 1.1 Host Controller
+	1562  USB 2.0 Host Controller
+	3400  SmartPCI56(UCB1500) 56K Modem
+	5400  TriMedia TM1000/1100
+	5402  TriMedia TM-1300
+		1244 0f00  Fritz!Card DSL
+	7130  SAA7130 Video Broadcast Decoder
+		5168 0138  LiveView FlyVideo 2000
+	7133  SAA713X Audio+video broadcast decoder
+		5168 0138  LifeView FlyVideo 3000
+		5168 0212  LifeView FlyTV Platinum mini
+		5168 0502  LifeView FlyDVB-T Duo CardBus
+# PCI audio and video broadcast decoder (http://www.semiconductors.philips.com/pip/saa7134hl)
+	7134  SAA7134
+		1043 4842  TV-FM Card 7134
+	7135  SAA7135 Audio+video broadcast decoder
+	7145  SAA7145
+	7146  SAA7146
+		110a 0000  Fujitsu/Siemens DVB-C card rev1.5
+		110a ffff  Fujitsu/Siemens DVB-C card rev1.5
+		1131 4f56  KNC1 DVB-S Budget
+		1131 4f61  Fujitsu-Siemens Activy DVB-S Budget
+		114b 2003  DVRaptor Video Edit/Capture Card
+		11bd 0006  DV500 Overlay
+		11bd 000a  DV500 Overlay
+		11bd 000f  DV500 Overlay
+		13c2 0000  Siemens/Technotrend/Hauppauge DVB card rev1.3 or rev1.5
+		13c2 0001  Technotrend/Hauppauge DVB card rev1.3 or rev1.6
+		13c2 0002  Technotrend/Hauppauge DVB card rev2.1
+		13c2 0003  Technotrend/Hauppauge DVB card rev2.1
+		13c2 0004  Technotrend/Hauppauge DVB card rev2.1
+		13c2 0006  Technotrend/Hauppauge DVB card rev1.3 or rev1.6
+		13c2 0008  Technotrend/Hauppauge DVB-T
+		13c2 000a  Octal/Technotrend DVB-C for iTV
+		13c2 1003  Technotrend-Budget / Hauppauge WinTV-NOVA-S DVB card
+		13c2 1004  Technotrend-Budget / Hauppauge WinTV-NOVA-C DVB card
+		13c2 1005  Technotrend-Budget / Hauppauge WinTV-NOVA-T DVB card
+		13c2 100c  Technotrend-Budget / Hauppauge WinTV-NOVA-CI DVB card
+		13c2 100f  Technotrend-Budget / Hauppauge WinTV-NOVA-CI DVB card
+		13c2 1011  Technotrend-Budget / Hauppauge WinTV-NOVA-T DVB card
+		13c2 1013  SATELCO Multimedia DVB
+		13c2 1102  Technotrend/Hauppauge DVB card rev2.1
+1132  Mitel Corp.
+# This is the new official company name. See disclaimer on www.eicon.com for details!
+1133  Eicon Networks Corporation
+	7901  EiconCard S90
+	7902  EiconCard S90
+	7911  EiconCard S91
+	7912  EiconCard S91
+	7941  EiconCard S94
+	7942  EiconCard S94
+	7943  EiconCard S94
+	7944  EiconCard S94
+	b921  EiconCard P92
+	b922  EiconCard P92
+	b923  EiconCard P92
+	e001  Diva Pro 2.0 S/T
+	e002  Diva 2.0 S/T PCI
+	e003  Diva Pro 2.0 U
+	e004  Diva 2.0 U PCI
+	e005  Diva 2.01 S/T PCI
+	e006  Diva CT S/T PCI
+	e007  Diva CT U PCI
+	e008  Diva CT Lite S/T PCI
+	e009  Diva CT Lite U PCI
+	e00a  Diva ISDN+V.90 PCI
+	e00b  Diva 2.02 PCI S/T
+	e00c  Diva 2.02 PCI U
+	e00d  Diva ISDN Pro 3.0 PCI
+	e00e  Diva ISDN+CT S/T PCI Rev 2
+	e010  Diva Server BRI-2M PCI
+		110a 0021  Fujitsu Siemens ISDN S0
+		8001 0014  Diva Server BRI-2M PCI Cornet NQ
+	e011  Diva Server BRI S/T Rev 2
+	e012  Diva Server 4BRI-8M PCI
+		8001 0014  Diva Server 4BRI-8M PCI Cornet NQ
+	e013  Diva Server 4BRI Rev 2
+		1133 1300  Diva Server V-4BRI-8
+		1133 e013  Diva Server 4BRI-8M 2.0 PCI
+		8001 0014  Diva Server 4BRI-8M 2.0 PCI Cornet NQ
+	e014  Diva Server PRI-30M PCI
+		0008 0100  Diva Server PRI-30M PCI
+		8001 0014  Diva Server PRI-30M PCI Cornet NQ
+	e015  DIVA Server PRI Rev 2
+		1133 e015  Diva Server PRI 2.0 PCI
+		8001 0014  Diva Server PRI 2.0 PCI Cornet NQ
+	e016  Diva Server Voice 4BRI PCI
+		8001 0014  Diva Server PRI Cornet NQ
+	e017  Diva Server Voice 4BRI Rev 2
+		1133 e017  Diva Server Voice 4BRI-8M 2.0 PCI
+		8001 0014  Diva Server Voice 4BRI-8M 2.0 PCI Cornet NQ
+	e018  Diva Server BRI-2M 2.0 PCI
+		1133 1800  Diva Server V-BRI-2
+		1133 e018  Diva Server BRI-2M 2.0 PCI
+		8001 0014  Diva Server BRI-2M 2.0 PCI Cornet NQ
+	e019  Diva Server Voice PRI Rev 2
+		1133 e019  Diva Server Voice PRI 2.0 PCI
+		8001 0014  Diva Server Voice PRI 2.0 PCI Cornet NQ
+	e01a  Diva Server 2FX
+	e01b  Diva Server Voice BRI-2M 2.0 PCI
+		1133 e01b  Diva Server Voice BRI-2M 2.0 PCI
+		8001 0014  Diva Server Voice BRI-2M 2.0 PCI Cornet NQ
+	e01c  Diva Server PRI Rev 3
+		1133 1c01  Diva Server PRI/E1/T1-8
+		1133 1c02  Diva Server PRI/T1-24
+		1133 1c03  Diva Server PRI/E1-30
+		1133 1c04  Diva Server PRI/E1/T1
+		1133 1c05  Diva Server V-PRI/T1-24
+		1133 1c06  Diva Server V-PRI/E1-30
+		1133 1c07  Diva Server PRI/E1/T1-8 Cornet NQ
+		1133 1c08  Diva Server PRI/T1-24 Cornet NQ
+		1133 1c09  Diva Server PRI/E1-30 Cornet NQ
+		1133 1c0a  Diva Server PRI/E1/T1 Cornet NQ
+		1133 1c0b  Diva Server V-PRI/T1-24 Cornet NQ
+		1133 1c0c  Diva Server V-PRI/E1-30 Cornet NQ
+	e01e  Diva Server 2PRI
+		1133 1e00  Diva Server V-2PRI/E1-60
+		1133 1e01  Diva Server V-2PRI/T1-48
+		1133 1e02  Diva Server 2PRI/E1-60
+		1133 1e03  Diva Server 2PRI/T1-48
+	e020  Diva Server 4PRI
+		1133 2000  Diva Server V-4PRI/E1-120
+		1133 2001  Diva Server V-4PRI/T1-96
+		1133 2002  Diva Server 4PRI/E1-120
+		1133 2003  Diva Server 4PRI/T1-96
+	e024  Diva Server Analog-4P
+		1133 2400  Diva Server V-Analog-4P
+		1133 e024  Diva Server Analog-4P
+	e028  Diva Server Analog-8P
+		1133 2800  Diva Server V-Analog-8P
+		1133 e028  Diva Server Analog-8P
+1134  Mercury Computer Systems
+	0001  Raceway Bridge
+	0002  Dual PCI to RapidIO Bridge
+1135  Fuji Xerox Co Ltd
+	0001  Printer controller
+1136  Momentum Data Systems
+1137  Cisco Systems Inc
+1138  Ziatech Corporation
+	8905  8905 [STD 32 Bridge]
+1139  Dynamic Pictures, Inc
+	0001  VGA Compatable 3D Graphics
+113a  FWB Inc
+113b  Network Computing Devices
+113c  Cyclone Microsystems, Inc.
+	0000  PCI-9060 i960 Bridge
+	0001  PCI-SDK [PCI i960 Evaluation Platform]
+	0911  PCI-911 [i960Jx-based Intelligent I/O Controller]
+	0912  PCI-912 [i960CF-based Intelligent I/O Controller]
+	0913  PCI-913
+	0914  PCI-914 [I/O Controller w/ secondary PCI bus]
+113d  Leading Edge Products Inc
+113e  Sanyo Electric Co - Computer Engineering Dept
+113f  Equinox Systems, Inc.
+	0808  SST-64P Adapter
+	1010  SST-128P Adapter
+	80c0  SST-16P DB Adapter
+	80c4  SST-16P RJ Adapter
+	80c8  SST-16P Adapter
+	8888  SST-4P Adapter
+	9090  SST-8P Adapter
+1140  Intervoice Inc
+1141  Crest Microsystem Inc
+1142  Alliance Semiconductor Corporation
+	3210  AP6410
+	6422  ProVideo 6422
+	6424  ProVideo 6424
+	6425  ProMotion AT25
+	643d  ProMotion AT3D
+1143  NetPower, Inc
+1144  Cincinnati Milacron
+	0001  Noservo controller
+1145  Workbit Corporation
+	8007  NinjaSCSI-32 Workbit
+	f007  NinjaSCSI-32 KME
+	f010  NinjaSCSI-32 Workbit
+	f012  NinjaSCSI-32 Logitec
+	f013  NinjaSCSI-32 Logitec
+	f015  NinjaSCSI-32 Melco
+1146  Force Computers
+1147  Interface Corp
+# Formerly (Schneider & Koch)
+1148  SysKonnect
+	4000  FDDI Adapter
+		0e11 b03b  Netelligent 100 FDDI DAS Fibre SC
+		0e11 b03c  Netelligent 100 FDDI SAS Fibre SC
+		0e11 b03d  Netelligent 100 FDDI DAS UTP
+		0e11 b03e  Netelligent 100 FDDI SAS UTP
+		0e11 b03f  Netelligent 100 FDDI SAS Fibre MIC
+		1148 5521  FDDI SK-5521 (SK-NET FDDI-UP)
+		1148 5522  FDDI SK-5522 (SK-NET FDDI-UP DAS)
+		1148 5541  FDDI SK-5541 (SK-NET FDDI-FP)
+		1148 5543  FDDI SK-5543 (SK-NET FDDI-LP)
+		1148 5544  FDDI SK-5544 (SK-NET FDDI-LP DAS)
+		1148 5821  FDDI SK-5821 (SK-NET FDDI-UP64)
+		1148 5822  FDDI SK-5822 (SK-NET FDDI-UP64 DAS)
+		1148 5841  FDDI SK-5841 (SK-NET FDDI-FP64)
+		1148 5843  FDDI SK-5843 (SK-NET FDDI-LP64)
+		1148 5844  FDDI SK-5844 (SK-NET FDDI-LP64 DAS)
+	4200  Token Ring adapter
+	4300  SK-98xx Gigabit Ethernet Server Adapter
+		1148 9821  SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T)
+		1148 9822  SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link)
+		1148 9841  SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX)
+		1148 9842  SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link)
+		1148 9843  SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX)
+		1148 9844  SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link)
+		1148 9861  SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition)
+		1148 9862  SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link)
+		1148 9871  SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX)
+		1148 9872  SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link)
+		1259 2970  AT-2970SX Gigabit Ethernet Adapter
+		1259 2971  AT-2970LX Gigabit Ethernet Adapter
+		1259 2972  AT-2970TX Gigabit Ethernet Adapter
+		1259 2973  AT-2971SX Gigabit Ethernet Adapter
+		1259 2974  AT-2971T Gigabit Ethernet Adapter
+		1259 2975  AT-2970SX/2SC Gigabit Ethernet Adapter
+		1259 2976  AT-2970LX/2SC Gigabit Ethernet Adapter
+		1259 2977  AT-2970TX/2TX Gigabit Ethernet Adapter
+	4320  SK-98xx V2.0 Gigabit Ethernet Adapter
+		1148 0121  Marvell RDK-8001 Adapter
+		1148 0221  Marvell RDK-8002 Adapter
+		1148 0321  Marvell RDK-8003 Adapter
+		1148 0421  Marvell RDK-8004 Adapter
+		1148 0621  Marvell RDK-8006 Adapter
+		1148 0721  Marvell RDK-8007 Adapter
+		1148 0821  Marvell RDK-8008 Adapter
+		1148 0921  Marvell RDK-8009 Adapter
+		1148 1121  Marvell RDK-8011 Adapter
+		1148 1221  Marvell RDK-8012 Adapter
+		1148 3221  SK-9521 V2.0 10/100/1000Base-T Adapter
+		1148 5021  SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter
+		1148 5041  SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter
+		1148 5043  SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+		1148 5051  SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+		1148 5061  SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+		1148 5071  SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter
+		1148 9521  SK-9521 10/100/1000Base-T Adapter
+	4400  SK-9Dxx Gigabit Ethernet Adapter
+	4500  SK-9Mxx Gigabit Ethernet Adapter
+	9000  SK-9Sxx Gigabit Ethernet Server Adapter PCI-X
+	9843  [Fujitsu] Gigabit Ethernet
+	9e00  SK-9Exx 10/100/1000Base-T Adapter
+		1148 2100  SK-9E21 Server Adapter
+		1148 21d0  SK-9E21D 10/100/1000Base-T Adapter
+		1148 2200  SK-9E22 Server Adapter
+		1148 8100  SK-9E81 Server Adapter
+		1148 8200  SK-9E82 Server Adapter
+		1148 9100  SK-9E91 Server Adapter
+		1148 9200  SK-9E92 Server Adapter
+1149  Win System Corporation
+114a  VMIC
+	5579  VMIPCI-5579 (Reflective Memory Card)
+	5587  VMIPCI-5587 (Reflective Memory Card)
+	6504  VMIC PCI 7755 FPGA
+	7587  VMIVME-7587
+114b  Canopus Co., Ltd
+114c  Annabooks
+114d  IC Corporation
+114e  Nikon Systems Inc
+114f  Digi International
+	0002  AccelePort EPC
+	0003  RightSwitch SE-6
+	0004  AccelePort Xem
+	0005  AccelePort Xr
+	0006  AccelePort Xr,C/X
+	0009  AccelePort Xr/J
+	000a  AccelePort EPC/J
+	000c  DataFirePRIme T1 (1-port)
+	000d  SyncPort 2-Port (x.25/FR)
+	0011  AccelePort 8r EIA-232 (IBM)
+	0012  AccelePort 8r EIA-422
+	0013  AccelePort Xr
+	0014  AccelePort 8r EIA-422
+	0015  AccelePort Xem
+	0016  AccelePort EPC/X
+	0017  AccelePort C/X
+	001a  DataFirePRIme E1 (1-port)
+	001b  AccelePort C/X (IBM)
+	001d  DataFire RAS T1/E1/PRI
+		114f 0050  DataFire RAS E1 Adapter
+		114f 0051  DataFire RAS Dual E1 Adapter
+		114f 0052  DataFire RAS T1 Adapter
+		114f 0053  DataFire RAS Dual T1 Adapter
+	0023  AccelePort RAS
+	0024  DataFire RAS B4 ST/U
+		114f 0030  DataFire RAS BRI U Adapter
+		114f 0031  DataFire RAS BRI S/T Adapter
+	0026  AccelePort 4r 920
+	0027  AccelePort Xr 920
+	0028  ClassicBoard 4
+	0029  ClassicBoard 8
+	0034  AccelePort 2r 920
+	0035  DataFire DSP T1/E1/PRI cPCI
+	0040  AccelePort Xp
+	0042  AccelePort 2p
+	0043  AccelePort 4p
+	0044  AccelePort 8p
+	0045  AccelePort 16p
+	004e  AccelePort 32p
+	0070  Datafire Micro V IOM2 (Europe)
+	0071  Datafire Micro V (Europe)
+	0072  Datafire Micro V IOM2 (North America)
+	0073  Datafire Micro V (North America)
+	00b0  Digi Neo 4
+	00b1  Digi Neo 8
+	00c8  Digi Neo 2 DB9
+	00c9  Digi Neo 2 DB9 PRI
+	00ca  Digi Neo 2 RJ45
+	00cb  Digi Neo 2 RJ45 PRI
+	00d0  ClassicBoard 4 422
+	00d1  ClassicBoard 8 422
+	6001  Avanstar
+1150  Thinking Machines Corp
+1151  JAE Electronics Inc.
+1152  Megatek
+1153  Land Win Electronic Corp
+1154  Melco Inc
+1155  Pine Technology Ltd
+1156  Periscope Engineering
+1157  Avsys Corporation
+1158  Voarx R & D Inc
+	3011  Tokenet/vg 1001/10m anylan
+	9050  Lanfleet/Truevalue
+	9051  Lanfleet/Truevalue
+1159  Mutech Corp
+	0001  MV-1000
+115a  Harlequin Ltd
+115b  Parallax Graphics
+115c  Photron Ltd.
+115d  Xircom
+	0003  Cardbus Ethernet 10/100
+		1014 0181  10/100 EtherJet Cardbus Adapter
+		1014 1181  10/100 EtherJet Cardbus Adapter
+		1014 8181  10/100 EtherJet Cardbus Adapter
+		1014 9181  10/100 EtherJet Cardbus Adapter
+		115d 0181  Cardbus Ethernet 10/100
+		115d 1181  Cardbus Ethernet 10/100
+		1179 0181  Cardbus Ethernet 10/100
+		8086 8181  EtherExpress PRO/100 Mobile CardBus 32 Adapter
+		8086 9181  EtherExpress PRO/100 Mobile CardBus 32 Adapter
+	0005  Cardbus Ethernet 10/100
+		1014 0182  10/100 EtherJet Cardbus Adapter
+		1014 1182  10/100 EtherJet Cardbus Adapter
+		115d 0182  Cardbus Ethernet 10/100
+		115d 1182  Cardbus Ethernet 10/100
+	0007  Cardbus Ethernet 10/100
+		1014 0182  10/100 EtherJet Cardbus Adapter
+		1014 1182  10/100 EtherJet Cardbus Adapter
+		115d 0182  Cardbus Ethernet 10/100
+		115d 1182  Cardbus Ethernet 10/100
+	000b  Cardbus Ethernet 10/100
+		1014 0183  10/100 EtherJet Cardbus Adapter
+		115d 0183  Cardbus Ethernet 10/100
+	000c  Mini-PCI V.90 56k Modem
+	000f  Cardbus Ethernet 10/100
+		1014 0183  10/100 EtherJet Cardbus Adapter
+		115d 0183  Cardbus Ethernet 10/100
+	00d4  Mini-PCI K56Flex Modem
+	0101  Cardbus 56k modem
+		115d 1081  Cardbus 56k Modem
+	0103  Cardbus Ethernet + 56k Modem
+		1014 9181  Cardbus 56k Modem
+		1115 1181  Cardbus Ethernet 100 + 56k Modem
+		115d 1181  CBEM56G-100 Ethernet + 56k Modem
+		8086 9181  PRO/100 LAN + Modem56 CardBus
+115e  Peer Protocols Inc
+115f  Maxtor Corporation
+1160  Megasoft Inc
+1161  PFU Limited
+1162  OA Laboratory Co Ltd
+1163  Rendition
+	0001  Verite 1000
+	2000  Verite V2000/V2100/V2200
+		1092 2000  Stealth II S220
+1164  Advanced Peripherals Technologies
+1165  Imagraph Corporation
+	0001  Motion TPEG Recorder/Player with audio
+1166  ServerWorks
+	0000  CMIC-LE
+	0005  CNB20-LE Host Bridge
+	0006  CNB20HE Host Bridge
+	0007  CNB20-LE Host Bridge
+	0008  CNB20HE Host Bridge
+	0009  CNB20LE Host Bridge
+	0010  CIOB30
+	0011  CMIC-HE
+	0012  CMIC-WS Host Bridge (GC-LE chipset)
+	0013  CNB20-HE Host Bridge
+	0014  CMIC-LE Host Bridge (GC-LE chipset)
+	0015  CMIC-GC Host Bridge
+	0016  CMIC-GC Host Bridge
+	0017  GCNB-LE Host Bridge
+	0101  CIOB-X2 PCI-X I/O Bridge
+	0110  CIOB-E I/O Bridge with Gigabit Ethernet
+	0200  OSB4 South Bridge
+	0201  CSB5 South Bridge
+		4c53 1080  CT8 mainboard
+	0203  CSB6 South Bridge
+	0211  OSB4 IDE Controller
+	0212  CSB5 IDE Controller
+		4c53 1080  CT8 mainboard
+	0213  CSB6 RAID/IDE Controller
+	0217  CSB6 IDE Controller
+	0220  OSB4/CSB5 OHCI USB Controller
+		4c53 1080  CT8 mainboard
+	0221  CSB6 OHCI USB Controller
+	0225  CSB5 LPC bridge
+# cancelled
+		4c53 1080  CT8 mainboard
+	0227  GCLE-2 Host Bridge
+	0230  CSB5 LPC bridge
+		4c53 1080  CT8 mainboard
+	0240  K2 SATA
+	0241  K2 SATA
+	0242  K2 SATA
+1167  Mutoh Industries Inc
+1168  Thine Electronics Inc
+1169  Centre for Development of Advanced Computing
+116a  Polaris Communications
+	6100  Bus/Tag Channel
+	6800  Escon Channel
+	7100  Bus/Tag Channel
+	7800  Escon Channel
+116b  Connectware Inc
+116c  Intelligent Resources Integrated Systems
+116d  Martin-Marietta
+116e  Electronics for Imaging
+116f  Workstation Technology
+1170  Inventec Corporation
+1171  Loughborough Sound Images Plc
+1172  Altera Corporation
+1173  Adobe Systems, Inc
+1174  Bridgeport Machines
+1175  Mitron Computer Inc.
+1176  SBE Incorporated
+1177  Silicon Engineering
+1178  Alfa, Inc.
+	afa1  Fast Ethernet Adapter
+1179  Toshiba America Info Systems
+	0103  EX-IDE Type-B
+	0404  DVD Decoder card
+	0406  Tecra Video Capture device
+	0407  DVD Decoder card (Version 2)
+	0601  CPU to PCI bridge
+	0603  ToPIC95 PCI to CardBus Bridge for Notebooks
+	060a  ToPIC95
+	060f  ToPIC97
+	0617  ToPIC100 PCI to Cardbus Bridge with ZV Support
+	0618  CPU to PCI and PCI to ISA bridge
+# Claimed to be Lucent DSP1645 [Mars], but that's apparently incorrect. Does anyone know the correct ID?
+	0701  FIR Port
+	0804  TC6371AF SmartMedia Controller
+	0805  SD TypA Controller
+	0d01  FIR Port Type-DO
+		1179 0001  FIR Port Type-DO
+117a  A-Trend Technology
+117b  L G Electronics, Inc.
+117c  Atto Technology
+117d  Becton & Dickinson
+117e  T/R Systems
+117f  Integrated Circuit Systems
+1180  Ricoh Co Ltd
+	0465  RL5c465
+	0466  RL5c466
+	0475  RL5c475
+		144d c006  vpr Matrix 170B4 CardBus bridge
+	0476  RL5c476 II
+		1014 0185  ThinkPad A/T/X Series
+		104d 80df  Vaio PCG-FX403
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		14ef 0220  PCD-RP-220S
+	0477  RL5c477
+	0478  RL5c478
+		1014 0184  ThinkPad A30p (2653-64G)
+	0522  R5C522 IEEE 1394 Controller
+		1014 01cf  ThinkPad A30p (2653-64G)
+	0551  R5C551 IEEE 1394 Controller
+		144d c006  vpr Matrix 170B4
+	0552  R5C552 IEEE 1394 Controller
+		1014 0511  ThinkPad A/T/X Series
+	0576  R5C576 SD Bus Host Adapter
+	0592  R5C592 Memory Stick Bus Host Adapter
+1181  Telmatics International
+1183  Fujikura Ltd
+1184  Forks Inc
+1185  Dataworld International Ltd
+1186  D-Link System Inc
+	0100  DC21041
+	1002  DL10050 Sundance Ethernet
+		1186 1002  DFE-550TX
+		1186 1012  DFE-580TX
+	1025  AirPlus Xtreme G DWL-G650 Adapter
+	1026  AirXpert DWL-AG650 Wireless Cardbus Adapter
+	1043  AirXpert DWL-AG650 Wireless Cardbus Adapter
+	1300  RTL8139 Ethernet
+		1186 1300  DFE-538TX 10/100 Ethernet Adapter
+		1186 1301  DFE-530TX+ 10/100 Ethernet Adapter
+	1340  DFE-690TXD CardBus PC Card
+	1541  DFE-680TXD CardBus PC Card
+	1561  DRP-32TXD Cardbus PC Card
+	2027  AirPlus Xtreme G DWL-G520 Adapter
+	3203  AirPlus Xtreme G DWL-G520 Adapter
+	3300  DWL-510 2.4GHz Wireless PCI Adapter
+	3a03  AirPro DWL-A650 Wireless Cardbus Adapter(rev.B)
+	3a04  AirPro DWL-AB650 Multimode Wireless Cardbus Adapter
+	3a05  AirPro DWL-AB520 Multimode Wireless PCI Adapter
+	3a07  AirXpert DWL-AG650 Wireless Cardbus Adapter
+	3a08  AirXpert DWL-AG520 Wireless PCI Adapter
+	3a10  AirXpert DWL-AG650 Wireless Cardbus Adapter(rev.B)
+	3a11  AirXpert DWL-AG520 Wireless PCI Adapter(rev.B)
+	3a12  AirPlus DWL-G650 Wireless Cardbus Adapter(rev.C)
+	3a13  AirPlus DWL-G520 Wireless PCI Adapter(rev.B)
+	3a14  AirPremier DWL-AG530 Wireless PCI Adapter
+	3a63  AirXpert DWL-AG660 Wireless Cardbus Adapter
+	3b05  DWL-G650+ CardBus PC Card
+	4000  DL2000-based Gigabit Ethernet
+	4300  DGE-528T Gigabit Ethernet Adapter
+	4c00  Gigabit Ethernet Adapter
+		1186 4c00  DGE-530T Gigabit Ethernet Adapter
+	8400  D-Link DWL-650+ CardBus PC Card
+1187  Advanced Technology Laboratories, Inc.
+1188  Shima Seiki Manufacturing Ltd.
+1189  Matsushita Electronics Co Ltd
+118a  Hilevel Technology
+118b  Hypertec Pty Limited
+118c  Corollary, Inc
+	0014  PCIB [C-bus II to PCI bus host bridge chip]
+	1117  Intel 8-way XEON Profusion Chipset [Cache Coherency Filter]
+118d  BitFlow Inc
+	0001  Raptor-PCI framegrabber
+	0012  Model 12 Road Runner Frame Grabber
+	0014  Model 14 Road Runner Frame Grabber
+	0024  Model 24 Road Runner Frame Grabber
+	0044  Model 44 Road Runner Frame Grabber
+	0112  Model 12 Road Runner Frame Grabber
+	0114  Model 14 Road Runner Frame Grabber
+	0124  Model 24 Road Runner Frame Grabber
+	0144  Model 44 Road Runner Frame Grabber
+	0212  Model 12 Road Runner Frame Grabber
+	0214  Model 14 Road Runner Frame Grabber
+	0224  Model 24 Road Runner Frame Grabber
+	0244  Model 44 Road Runner Frame Grabber
+	0312  Model 12 Road Runner Frame Grabber
+	0314  Model 14 Road Runner Frame Grabber
+	0324  Model 24 Road Runner Frame Grabber
+	0344  Model 44 Road Runner Frame Grabber
+118e  Hermstedt GmbH
+118f  Green Logic
+1190  Tripace
+	c731  TP-910/920/940 PCI Ultra(Wide) SCSI Adapter
+1191  Artop Electronic Corp
+	0003  SCSI Cache Host Adapter
+	0004  ATP8400
+	0005  ATP850UF
+	0006  ATP860 NO-BIOS
+	0007  ATP860
+	0008  ATP865 NO-ROM
+	0009  ATP865
+	8002  AEC6710 SCSI-2 Host Adapter
+	8010  AEC6712UW SCSI
+	8020  AEC6712U SCSI
+	8030  AEC6712S SCSI
+	8040  AEC6712D SCSI
+	8050  AEC6712SUW SCSI
+	8060  AEC6712 SCSI
+	8080  AEC67160 SCSI
+	8081  AEC67160S SCSI
+	808a  AEC67162 2-ch. LVD SCSI
+1192  Densan Company Ltd
+1193  Zeitnet Inc.
+	0001  1221
+	0002  1225
+1194  Toucan Technology
+1195  Ratoc System Inc
+1196  Hytec Electronics Ltd
+1197  Gage Applied Sciences, Inc.
+	010c  CompuScope 82G 8bit 2GS/s Analog Input Card
+1198  Lambda Systems Inc
+1199  Attachmate Corporation
+119a  Mind Share, Inc.
+119b  Omega Micro Inc.
+	1221  82C092G
+119c  Information Technology Inst.
+119d  Bug, Inc. Sapporo Japan
+119e  Fujitsu Microelectronics Ltd.
+	0001  FireStream 155
+	0003  FireStream 50
+119f  Bull HN Information Systems
+11a0  Convex Computer Corporation
+11a1  Hamamatsu Photonics K.K.
+11a2  Sierra Research and Technology
+11a3  Deuretzbacher GmbH & Co. Eng. KG
+11a4  Barco Graphics NV
+11a5  Microunity Systems Eng. Inc
+11a6  Pure Data Ltd.
+11a7  Power Computing Corp.
+11a8  Systech Corp.
+11a9  InnoSys Inc.
+	4240  AMCC S933Q Intelligent Serial Card
+11aa  Actel
+# Formerly Galileo Technology, Inc.
+11ab  Marvell Technology Group Ltd.
+	0146  GT-64010/64010A System Controller
+	138f  W8300 802.11 Adapter (rev 07)
+	1fa6  Marvell W8300 802.11 Adapter
+	1fa7  88W8310 and 88W8000G [Libertas] 802.11g client chipset
+	4320  Gigabit Ethernet Controller
+		1019 0f38  Marvell 88E8001 Gigabit Ethernet Controller (ECS)
+		1019 8001  Marvell 88E8001 Gigabit Ethernet Controller (ECS)
+		1043 173c  Marvell 88E8001 Gigabit Ethernet Controller (Asus)
+		1043 811a  Marvell 88E8001 Gigabit Ethernet Controller (Asus)
+		105b 0c19  Marvell 88E8001 Gigabit Ethernet Controller (Foxconn)
+		10b8 b452  SMC EZ Card 1000 (SMC9452TXV.2)
+		11ab 0121  Marvell RDK-8001
+		11ab 0321  Marvell RDK-8003
+		11ab 1021  Marvell RDK-8010
+		11ab 5021  Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Controller (64 bit)
+		11ab 9521  Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Controller (32 bit)
+		1458 e000  Marvell 88E8001 Gigabit Ethernet Controller (Gigabyte)
+		147b 1406  Marvell 88E8001 Gigabit Ethernet Controller (Abit)
+		15d4 0047  Marvell 88E8001 Gigabit Ethernet Controller (Iwill)
+		1695 9025  Marvell 88E8001 Gigabit Ethernet Controller (Epox)
+		17f2 1c03  Marvell 88E8001 Gigabit Ethernet Controller (Albatron)
+		270f 2803  Marvell 88E8001 Gigabit Ethernet Controller (Chaintech)
+	4350  Fast Ethernet Controller
+		1179 0001  Marvell 88E8035 Fast Ethernet Controller (Toshiba)
+		11ab 3521  Marvell RDK-8035
+		1854 000d  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 000e  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 000f  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0011  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0012  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0016  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0017  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0018  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0019  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 001c  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 001e  Marvell 88E8035 Fast Ethernet Controller (LGE)
+		1854 0020  Marvell 88E8035 Fast Ethernet Controller (LGE)
+	4351  Fast Ethernet Controller
+		107b 4009  Marvell 88E8036 Fast Ethernet Controller (Wistron)
+		10f7 8338  Marvell 88E8036 Fast Ethernet Controller (Panasonic)
+		1179 0001  Marvell 88E8036 Fast Ethernet Controller (Toshiba)
+		1179 ff00  Marvell 88E8036 Fast Ethernet Controller (Compal)
+		1179 ff10  Marvell 88E8036 Fast Ethernet Controller (Inventec)
+		11ab 3621  Marvell RDK-8036
+		13d1 ac12  Abocom EFE3K - 10/100 Ethernet Expresscard
+		161f 203d  Marvell 88E8036 Fast Ethernet Controller (Arima)
+		1854 000d  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 000e  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 000f  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0011  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0012  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0016  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0017  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0018  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0019  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 001c  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 001e  Marvell 88E8036 Fast Ethernet Controller (LGE)
+		1854 0020  Marvell 88E8036 Fast Ethernet Controller (LGE)
+	4360  Gigabit Ethernet Controller
+		1043 8134  Marvell 88E8052 Gigabit Ethernet Controller (Asus)
+		107b 4009  Marvell 88E8052 Gigabit Ethernet Controller (Wistron)
+		11ab 5221  Marvell RDK-8052
+		1458 e000  Marvell 88E8052 Gigabit Ethernet Controller (Gigabyte)
+		1462 052c  Marvell 88E8052 Gigabit Ethernet Controller (MSI)
+		1849 8052  Marvell 88E8052 Gigabit Ethernet Controller (ASRock)
+		1940 e000  Marvell 88E8052 Gigabit Ethernet Controller (Gigabyte)
+		a0a0 0509  Marvell 88E8052 Gigabit Ethernet Controller (Aopen)
+	4361  Gigabit Ethernet Controller
+		107b 3015  Marvell 88E8050 Gigabit Ethernet Controller (Gateway)
+		11ab 5021  Marvell 88E8050 Gigabit Ethernet Controller (Intel)
+		8086 3063  D925XCVLK mainboard
+	4362  Gigabit Ethernet Controller
+		103c 2a0d  Marvell 88E8053 Gigabit Ethernet Controller (Asus)
+		1043 8142  Marvell 88E8053 Gigabit Ethernet Controller (Asus)
+		109f 3197  Marvell 88E8053 Gigabit Ethernet Controller (Trigem)
+		10f7 8338  Marvell 88E8053 Gigabit Ethernet Controller (Panasonic)
+		10fd a430  Marvell 88E8053 Gigabit Ethernet Controller (SOYO)
+		1179 0001  Marvell 88E8053 Gigabit Ethernet Controller (Toshiba)
+		1179 ff00  Marvell 88E8053 Gigabit Ethernet Controller (Compal)
+		1179 ff10  Marvell 88E8053 Gigabit Ethernet Controller (Inventec)
+		11ab 5321  Marvell RDK-8053
+		1297 c240  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		1297 c241  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		1297 c242  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		1297 c243  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		1297 c244  Marvell 88E8053 Gigabit Ethernet Controller (Shuttle)
+		13d1 ac11  Abocom EGE5K - Giga Ethernet Expresscard
+		1458 e000  Marvell 88E8053 Gigabit Ethernet Controller (Gigabyte)
+		1462 058c  Marvell 88E8053 Gigabit Ethernet Controller (MSI)
+		14c0 0012  Marvell 88E8053 Gigabit Ethernet Controller (Compal)
+		1558 04a0  Marvell 88E8053 Gigabit Ethernet Controller (Clevo)
+		15bd 1003  Marvell 88E8053 Gigabit Ethernet Controller (DFI)
+		161f 203c  Marvell 88E8053 Gigabit Ethernet Controller (Arima)
+		161f 203d  Marvell 88E8053 Gigabit Ethernet Controller (Arima)
+		1695 9029  Marvell 88E8053 Gigabit Ethernet Controller (Epox)
+		17f2 2c08  Marvell 88E8053 Gigabit Ethernet Controller (Albatron)
+		17ff 0585  Marvell 88E8053 Gigabit Ethernet Controller (Quanta)
+		1849 8053  Marvell 88E8053 Gigabit Ethernet Controller (ASRock)
+		1854 000b  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 000c  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0010  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0013  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0014  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0015  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 001a  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 001b  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 001d  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 001f  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0021  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1854 0022  Marvell 88E8053 Gigabit Ethernet Controller (LGE)
+		1940 e000  Marvell 88E8053 Gigabit Ethernet Controller (Gigabyte)
+		270f 2801  Marvell 88E8053 Gigabit Ethernet Controller (Chaintech)
+		a0a0 0506  Marvell 88E8053 Gigabit Ethernet Controller (Aopen)
+	4611  GT-64115 System Controller
+	4620  GT-64120/64120A/64121A System Controller
+	4801  GT-48001
+	5005  Belkin F5D5005 Gigabit Desktop Network PCI Card
+	5040  MV88SX5040 4-port SATA I PCI-X Controller
+	5041  MV88SX5041 4-port SATA I PCI-X Controller
+	5080  MV88SX5080 8-port SATA I PCI-X Controller
+	5081  MV88SX5081 8-port SATA I PCI-X Controller
+	6041  MV88SX6041 4-port SATA II PCI-X Controller
+	6081  MV88SX6081 8-port SATA II PCI-X Controller
+	6460  MV64360/64361/64362 System Controller
+	f003  GT-64010 Primary Image Piranha Image Generator
+11ac  Canon Information Systems Research Aust.
+11ad  Lite-On Communications Inc
+	0002  LNE100TX
+		11ad 0002  LNE100TX
+		11ad 0003  LNE100TX
+		11ad f003  LNE100TX
+		11ad ffff  LNE100TX
+		1385 f004  FA310TX
+	c115  LNE100TX [Linksys EtherFast 10/100]
+		11ad c001  LNE100TX [ver 2.0]
+11ae  Aztech System Ltd
+11af  Avid Technology Inc.
+	0001  [Cinema]
+11b0  V3 Semiconductor Inc.
+	0002  V300PSC
+	0292  V292PBC [Am29030/40 Bridge]
+	0960  V96xPBC
+	c960  V96DPC
+11b1  Apricot Computers
+11b2  Eastman Kodak
+11b3  Barr Systems Inc.
+11b4  Leitch Technology International
+11b5  Radstone Technology Plc
+11b6  United Video Corp
+11b7  Motorola
+11b8  XPoint Technologies, Inc
+	0001  Quad PeerMaster
+11b9  Pathlight Technology Inc.
+	c0ed  SSA Controller
+11ba  Videotron Corp
+11bb  Pyramid Technology
+11bc  Network Peripherals Inc
+	0001  NP-PCI
+11bd  Pinnacle Systems Inc.
+11be  International Microcircuits Inc
+11bf  Astrodesign, Inc.
+11c0  Hewlett Packard
+11c1  Agere Systems (former Lucent Microelectronics)
+	0440  56k WinModem
+		1033 8015  LT WinModem 56k Data+Fax+Voice+Dsvd
+		1033 8047  LT WinModem 56k Data+Fax+Voice+Dsvd
+		1033 804f  LT WinModem 56k Data+Fax+Voice+Dsvd
+		10cf 102c  LB LT Modem V.90 56k
+		10cf 104a  BIBLO LT Modem 56k
+		10cf 105f  LB2 LT Modem V.90 56k
+		1179 0001  Internal V.90 Modem
+		11c1 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
+		122d 4101  MDP7800-U Modem
+		122d 4102  MDP7800SP-U Modem
+		13e0 0040  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 0441  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 0450  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 f100  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 f101  LT WinModem 56k Data+Fax+Voice+Dsvd
+		144d 2101  LT56PV Modem
+		149f 0440  LT WinModem 56k Data+Fax+Voice+Dsvd
+	0441  56k WinModem
+		1033 804d  LT WinModem 56k Data+Fax
+		1033 8065  LT WinModem 56k Data+Fax
+		1092 0440  Supra 56i
+		1179 0001  Internal V.90 Modem
+		11c1 0440  LT WinModem 56k Data+Fax
+		11c1 0441  LT WinModem 56k Data+Fax
+		122d 4100  MDP7800-U Modem
+		13e0 0040  LT WinModem 56k Data+Fax
+		13e0 0100  LT WinModem 56k Data+Fax
+		13e0 0410  LT WinModem 56k Data+Fax
+		13e0 0420  TelePath Internet 56k WinModem
+		13e0 0440  LT WinModem 56k Data+Fax
+		13e0 0443  LT WinModem 56k Data+Fax
+		13e0 f102  LT WinModem 56k Data+Fax
+		1416 9804  CommWave 56k Modem
+		141d 0440  LT WinModem 56k Data+Fax
+		144f 0441  Lucent 56k V.90 DF Modem
+		144f 0449  Lucent 56k V.90 DF Modem
+		144f 110d  Lucent Win Modem
+		1468 0441  Presario 56k V.90 DF Modem
+		1668 0440  Lucent Win Modem
+	0442  56k WinModem
+		11c1 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+		11c1 0442  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+		13e0 0412  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+		13e0 0442  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+		13fc 2471  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+		144d 2104  LT56PT Modem
+		144f 1104  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+		149f 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+		1668 0440  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+	0443  LT WinModem
+	0444  LT WinModem
+	0445  LT WinModem
+		8086 2203  PRO/100+ MiniPCI (probably an Ambit U98.003.C.00 combo card)
+		8086 2204  PRO/100+ MiniPCI on Armada E500
+	0446  LT WinModem
+	0447  LT WinModem
+	0448  WinModem 56k
+		1014 0131  Lucent Win Modem
+		1033 8066  LT WinModem 56k Data+Fax+Voice+Dsvd
+		13e0 0030  56k Voice Modem
+		13e0 0040  LT WinModem 56k Data+Fax+Voice+Dsvd
+# Actiontech eth+modem card as used by Dell &c.
+		1668 2400  LT WinModem 56k (MiniPCI Ethernet+Modem)
+	0449  WinModem 56k
+		0e11 b14d  56k V.90 Modem
+		13e0 0020  LT WinModem 56k Data+Fax
+		13e0 0041  TelePath Internet 56k WinModem
+		1436 0440  Lucent Win Modem
+		144f 0449  Lucent 56k V.90 DFi Modem
+		1468 0410  IBM ThinkPad T23 (2647-4MG)
+		1468 0440  Lucent Win Modem
+		1468 0449  Presario 56k V.90 DFi Modem
+	044a  F-1156IV WinModem (V90, 56KFlex)
+		10cf 1072  LB Global LT Modem
+		13e0 0012  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+		13e0 0042  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+		144f 1005  LT WinModem 56k Data+Fax+Voice+VoiceView+Dsvd
+	044b  LT WinModem
+	044c  LT WinModem
+	044d  LT WinModem
+	044e  LT WinModem
+	044f  V90 WildWire Modem
+	0450  LT WinModem
+		1033 80a8  Versa Note Vxi
+		144f 4005  Magnia SG20
+	0451  LT WinModem
+	0452  LT WinModem
+	0453  LT WinModem
+	0454  LT WinModem
+	0455  LT WinModem
+	0456  LT WinModem
+	0457  LT WinModem
+	0458  LT WinModem
+	0459  LT WinModem
+	045a  LT WinModem
+	045c  LT WinModem
+	0461  V90 WildWire Modem
+	0462  V90 WildWire Modem
+	0480  Venus Modem (V90, 56KFlex)
+	048c  V.92 56K WinModem
+# InPorte Home Internal 56k Modem/fax/answering machine/SMS Features
+	048f  V.92 56k WinModem
+	5801  USB
+	5802  USS-312 USB Controller
+# 4 port PCI USB Controller made by Agere (formely Lucent)
+	5803  USS-344S USB Controller
+	5811  FW323
+		8086 524c  D865PERL mainboard
+		dead 0800  FireWire Host Bus Adapter
+	ab10  WL60010 Wireless LAN MAC
+	ab11  WL60040 Multimode Wireles LAN MAC
+		11c1 ab12  WaveLAN 11abg Cardbus card (Model 1102)
+		11c1 ab13  WaveLAN 11abg MiniPCI card (Model 0512)
+		11c1 ab15  WaveLAN 11abg Cardbus card (Model 1106)
+		11c1 ab16  WaveLAN 11abg MiniPCI card (Model 0516)
+	ab20  ORiNOCO PCI Adapter
+	ab21  Agere Wireless PCI Adapter
+	ab30  Hermes2 Mini-PCI WaveLAN a/b/g
+		14cd 2012  Hermes2 Mini-PCI WaveLAN a/b/g
+11c2  Sand Microelectronics
+11c3  NEC Corporation
+11c4  Document Technologies, Inc
+11c5  Shiva Corporation
+11c6  Dainippon Screen Mfg. Co. Ltd
+11c7  D.C.M. Data Systems
+11c8  Dolphin Interconnect Solutions AS
+	0658  PSB32 SCI-Adapter D31x
+	d665  PSB64 SCI-Adapter D32x
+	d667  PSB66 SCI-Adapter D33x
+11c9  Magma
+	0010  16-line serial port w/- DMA
+	0011  4-line serial port w/- DMA
+11ca  LSI Systems, Inc
+11cb  Specialix Research Ltd.
+	2000  PCI_9050
+		11cb 0200  SX
+		11cb b008  I/O8+
+	4000  SUPI_1
+	8000  T225
+11cc  Michels & Kleberhoff Computer GmbH
+11cd  HAL Computer Systems, Inc.
+11ce  Netaccess
+11cf  Pioneer Electronic Corporation
+11d0  Lockheed Martin Federal Systems-Manassas
+11d1  Auravision
+	01f7  VxP524
+11d2  Intercom Inc.
+11d3  Trancell Systems Inc
+11d4  Analog Devices
+	1535  Blackfin BF535 processor
+	1805  SM56 PCI modem
+	1889  AD1889 sound chip
+11d5  Ikon Corporation
+	0115  10115
+	0117  10117
+11d6  Tekelec Telecom
+11d7  Trenton Technology, Inc.
+11d8  Image Technologies Development
+11d9  TEC Corporation
+11da  Novell
+11db  Sega Enterprises Ltd
+11dc  Questra Corporation
+11dd  Crosfield Electronics Limited
+11de  Zoran Corporation
+	6057  ZR36057PQC Video cutting chipset
+		1031 7efe  DC10 Plus
+		1031 fc00  MiroVIDEO DC50, Motion JPEG Capture/CODEC Board
+		13ca 4231  JPEG/TV Card
+	6120  ZR36120
+		1328 f001  Cinemaster C DVD Decoder
+11df  New Wave PDG
+11e0  Cray Communications A/S
+11e1  GEC Plessey Semi Inc.
+11e2  Samsung Information Systems America
+11e3  Quicklogic Corporation
+	5030  PC Watchdog
+11e4  Second Wave Inc
+11e5  IIX Consulting
+11e6  Mitsui-Zosen System Research
+11e7  Toshiba America, Elec. Company
+11e8  Digital Processing Systems Inc.
+11e9  Highwater Designs Ltd.
+11ea  Elsag Bailey
+11eb  Formation Inc.
+11ec  Coreco Inc
+11ed  Mediamatics
+11ee  Dome Imaging Systems Inc
+11ef  Nicolet Technologies B.V.
+11f0  Compu-Shack
+	4231  FDDI
+	4232  FASTline UTP Quattro
+	4233  FASTline FO
+	4234  FASTline UTP
+	4235  FASTline-II UTP
+	4236  FASTline-II FO
+	4731  GIGAline
+11f1  Symbios Logic Inc
+11f2  Picture Tel Japan K.K.
+11f3  Keithley Metrabyte
+11f4  Kinetic Systems Corporation
+	2915  CAMAC controller
+11f5  Computing Devices International
+11f6  Compex
+	0112  ENet100VG4
+	0113  FreedomLine 100
+	1401  ReadyLink 2000
+	2011  RL100-ATX 10/100
+		11f6 2011  RL100-ATX
+	2201  ReadyLink 100TX (Winbond W89C840)
+		11f6 2011  ReadyLink 100TX
+	9881  RL100TX Fast Ethernet
+11f7  Scientific Atlanta
+11f8  PMC-Sierra Inc.
+	7375  PM7375 [LASAR-155 ATM SAR]
+11f9  I-Cube Inc
+11fa  Kasan Electronics Company, Ltd.
+11fb  Datel Inc
+11fc  Silicon Magic
+11fd  High Street Consultants
+11fe  Comtrol Corporation
+	0001  RocketPort 32 port w/external I/F
+	0002  RocketPort 8 port w/external I/F
+	0003  RocketPort 16 port w/external I/F
+	0004  RocketPort 4 port w/quad cable
+	0005  RocketPort 8 port w/octa cable
+	0006  RocketPort 8 port w/RJ11 connectors
+	0007  RocketPort 4 port w/RJ11 connectors
+	0008  RocketPort 8 port w/ DB78 SNI (Siemens) connector
+	0009  RocketPort 16 port w/ DB78 SNI (Siemens) connector
+	000a  RocketPort Plus 4 port
+	000b  RocketPort Plus 8 port
+	000c  RocketModem 6 port
+	000d  RocketModem 4-port
+	000e  RocketPort Plus 2 port RS232
+	000f  RocketPort Plus 2 port RS422
+	0801  RocketPort UPCI 32 port w/external I/F
+	0802  RocketPort UPCI 8 port w/external I/F
+	0803  RocketPort UPCI 16 port w/external I/F
+	0805  RocketPort UPCI 8 port w/octa cable
+	080c  RocketModem III 8 port
+	080d  RocketModem III 4 port
+	0903  RocketPort Compact PCI 16 port w/external I/F
+	8015  RocketPort 4-port UART 16954
+11ff  Scion Corporation
+	0003  AG-5
+1200  CSS Corporation
+1201  Vista Controls Corp
+1202  Network General Corp.
+	4300  Gigabit Ethernet Adapter
+		1202 9841  SK-9841 LX
+		1202 9842  SK-9841 LX dual link
+		1202 9843  SK-9843 SX
+		1202 9844  SK-9843 SX dual link
+1203  Bayer Corporation, Agfa Division
+1204  Lattice Semiconductor Corporation
+1205  Array Corporation
+1206  Amdahl Corporation
+1208  Parsytec GmbH
+	4853  HS-Link Device
+1209  SCI Systems Inc
+120a  Synaptel
+120b  Adaptive Solutions
+120c  Technical Corp.
+120d  Compression Labs, Inc.
+120e  Cyclades Corporation
+	0100  Cyclom-Y below first megabyte
+	0101  Cyclom-Y above first megabyte
+	0102  Cyclom-4Y below first megabyte
+	0103  Cyclom-4Y above first megabyte
+	0104  Cyclom-8Y below first megabyte
+	0105  Cyclom-8Y above first megabyte
+	0200  Cyclades-Z below first megabyte
+	0201  Cyclades-Z above first megabyte
+	0300  PC300/RSV or /X21 (2 ports)
+	0301  PC300/RSV or /X21 (1 port)
+	0310  PC300/TE (2 ports)
+	0311  PC300/TE (1 port)
+	0320  PC300/TE-M (2 ports)
+	0321  PC300/TE-M (1 port)
+	0400  PC400
+120f  Essential Communications
+	0001  Roadrunner serial HIPPI
+1210  Hyperparallel Technologies
+1211  Braintech Inc
+1212  Kingston Technology Corp.
+1213  Applied Intelligent Systems, Inc.
+1214  Performance Technologies, Inc.
+1215  Interware Co., Ltd
+1216  Purup Prepress A/S
+1217  O2 Micro, Inc.
+	6729  OZ6729
+	673a  OZ6730
+	6832  OZ6832/6833 CardBus Controller
+	6836  OZ6836/6860 CardBus Controller
+	6872  OZ6812 CardBus Controller
+	6925  OZ6922 CardBus Controller
+	6933  OZ6933/711E1 CardBus/SmartCardBus Controller
+		1025 1016  Travelmate 612 TX
+	6972  OZ601/6912/711E0 CardBus/SmartCardBus Controller
+		1014 020c  ThinkPad R30
+		1179 0001  Magnia Z310
+	7110  OZ711Mx 4-in-1 MemoryCardBus Accelerator
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+	7112  OZ711EC1/M1 SmartCardBus/MemoryCardBus Controller
+	7113  OZ711EC1 SmartCardBus Controller
+	7114  OZ711M1/MC1 4-in-1 MemoryCardBus Controller
+	7134  OZ711MP1/MS1 MemoryCardBus Controller
+	71e2  OZ711E2 SmartCardBus Controller
+	7212  OZ711M2 4-in-1 MemoryCardBus Controller
+	7213  OZ6933E CardBus Controller
+	7223  OZ711M3/MC3 4-in-1 MemoryCardBus Controller
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+	7233  OZ711MP3/MS3 4-in-1 MemoryCardBus Controller
+1218  Hybricon Corp.
+1219  First Virtual Corporation
+121a  3Dfx Interactive, Inc.
+	0001  Voodoo
+	0002  Voodoo 2
+	0003  Voodoo Banshee
+		1092 0003  Monster Fusion
+		1092 4000  Monster Fusion
+		1092 4002  Monster Fusion
+		1092 4801  Monster Fusion AGP
+		1092 4803  Monster Fusion AGP
+		1092 8030  Monster Fusion
+		1092 8035  Monster Fusion AGP
+		10b0 0001  Dragon 4000
+		1102 1018  3D Blaster Banshee VE
+		121a 0001  Voodoo Banshee AGP
+		121a 0003  Voodoo Banshee AGP SGRAM
+		121a 0004  Voodoo Banshee
+		139c 0016  Raven
+		139c 0017  Raven
+		14af 0002  Maxi Gamer Phoenix
+	0004  Voodoo Banshee [Velocity 100]
+	0005  Voodoo 3
+		121a 0004  Voodoo3 AGP
+		121a 0030  Voodoo3 AGP
+		121a 0031  Voodoo3 AGP
+		121a 0034  Voodoo3 AGP
+		121a 0036  Voodoo3 2000 PCI
+		121a 0037  Voodoo3 AGP
+		121a 0038  Voodoo3 AGP
+		121a 003a  Voodoo3 AGP
+		121a 0044  Voodoo3
+		121a 004b  Velocity 100
+		121a 004c  Velocity 200
+		121a 004d  Voodoo3 AGP
+		121a 004e  Voodoo3 AGP
+		121a 0051  Voodoo3 AGP
+		121a 0052  Voodoo3 AGP
+		121a 0060  Voodoo3 3500 TV (NTSC)
+		121a 0061  Voodoo3 3500 TV (PAL)
+		121a 0062  Voodoo3 3500 TV (SECAM)
+	0009  Voodoo 4 / Voodoo 5
+		121a 0003  Voodoo5 PCI 5500
+		121a 0009  Voodoo5 AGP 5500/6000
+	0057  Voodoo 3/3000 [Avenger]
+121b  Advanced Telecommunications Modules
+121c  Nippon Texaco., Ltd
+121d  Lippert Automationstechnik GmbH
+121e  CSPI
+121f  Arcus Technology, Inc.
+1220  Ariel Corporation
+	1220  AMCC 5933 TMS320C80 DSP/Imaging board
+1221  Contec Co., Ltd
+1222  Ancor Communications, Inc.
+1223  Artesyn Communication Products
+	0003  PM/Link
+	0004  PM/T1
+	0005  PM/E1
+	0008  PM/SLS
+	0009  BajaSpan Resource Target
+	000a  BajaSpan Section 0
+	000b  BajaSpan Section 1
+	000c  BajaSpan Section 2
+	000d  BajaSpan Section 3
+	000e  PM/PPC
+1224  Interactive Images
+1225  Power I/O, Inc.
+1227  Tech-Source
+	0006  Raptor GFX 8P
+1228  Norsk Elektro Optikk A/S
+1229  Data Kinesis Inc.
+122a  Integrated Telecom
+122b  LG Industrial Systems Co., Ltd
+122c  Sican GmbH
+122d  Aztech System Ltd
+	1206  368DSP
+	1400  Trident PCI288-Q3DII (NX)
+	50dc  3328 Audio
+		122d 0001  3328 Audio
+	80da  3328 Audio
+		122d 0001  3328 Audio
+122e  Xyratex
+122f  Andrew Corporation
+1230  Fishcamp Engineering
+1231  Woodward McCoach, Inc.
+1232  GPT Limited
+1233  Bus-Tech, Inc.
+1234  Technical Corp.
+1235  Risq Modular Systems, Inc.
+1236  Sigma Designs Corporation
+	0000  RealMagic64/GX
+	6401  REALmagic 64/GX (SD 6425)
+1237  Alta Technology Corporation
+1238  Adtran
+1239  3DO Company
+123a  Visicom Laboratories, Inc.
+123b  Seeq Technology, Inc.
+123c  Century Systems, Inc.
+123d  Engineering Design Team, Inc.
+	0000  EasyConnect 8/32
+	0002  EasyConnect 8/64
+	0003  EasyIO
+123e  Simutech, Inc.
+123f  C-Cube Microsystems
+	00e4  MPEG
+	8120  E4?
+		11bd 0006  DV500 E4
+		11bd 000a  DV500 E4
+		11bd 000f  DV500 E4
+	8888  Cinemaster C 3.0 DVD Decoder
+		1002 0001  Cinemaster C 3.0 DVD Decoder
+		1002 0002  Cinemaster C 3.0 DVD Decoder
+		1328 0001  Cinemaster C 3.0 DVD Decoder
+1240  Marathon Technologies Corp.
+1241  DSC Communications
+# Formerly Jaycor Networks, Inc.
+1242  JNI Corporation
+	1560  JNIC-1560 PCI-X Fibre Channel Controller
+		1242 6562  FCX2-6562 Dual Channel PCI-X Fibre Channel Adapter
+		1242 656a  FCX-6562 PCI-X Fibre Channel Adapter
+	4643  FCI-1063 Fibre Channel Adapter
+	6562  FCX2-6562 Dual Channel PCI-X Fibre Channel Adapter
+	656a  FCX-6562 PCI-X Fibre Channel Adapter
+1243  Delphax
+1244  AVM Audiovisuelles MKTG & Computer System GmbH
+	0700  B1 ISDN
+	0800  C4 ISDN
+	0a00  A1 ISDN [Fritz]
+		1244 0a00  FRITZ!Card ISDN Controller
+	0e00  Fritz!PCI v2.0 ISDN
+	1100  C2 ISDN
+	1200  T1 ISDN
+	2700  Fritz!Card DSL SL
+	2900  Fritz!Card DSL v2.0
+1245  A.P.D., S.A.
+1246  Dipix Technologies, Inc.
+1247  Xylon Research, Inc.
+1248  Central Data Corporation
+1249  Samsung Electronics Co., Ltd.
+124a  AEG Electrocom GmbH
+124b  SBS/Greenspring Modular I/O
+	0040  PCI-40A or cPCI-200 Quad IndustryPack carrier
+		124b 9080  PCI9080 Bridge
+124c  Solitron Technologies, Inc.
+124d  Stallion Technologies, Inc.
+	0000  EasyConnection 8/32
+	0002  EasyConnection 8/64
+	0003  EasyIO
+	0004  EasyConnection/RA
+124e  Cylink
+124f  Infortrend Technology, Inc.
+	0041  IFT-2000 Series RAID Controller
+1250  Hitachi Microcomputer System Ltd
+1251  VLSI Solutions Oy
+1253  Guzik Technical Enterprises
+1254  Linear Systems Ltd.
+1255  Optibase Ltd
+	1110  MPEG Forge
+	1210  MPEG Fusion
+	2110  VideoPlex
+	2120  VideoPlex CC
+	2130  VideoQuest
+1256  Perceptive Solutions, Inc.
+	4201  PCI-2220I
+	4401  PCI-2240I
+	5201  PCI-2000
+1257  Vertex Networks, Inc.
+1258  Gilbarco, Inc.
+1259  Allied Telesyn International
+	2560  AT-2560 Fast Ethernet Adapter (i82557B)
+	a117  RTL81xx Fast Ethernet
+	a120  21x4x DEC-Tulip compatible 10/100 Ethernet
+125a  ABB Power Systems
+125b  Asix Electronics Corporation
+	1400  ALFA GFC2204 Fast Ethernet
+125c  Aurora Technologies, Inc.
+	0101  Saturn 4520P
+	0640  Aries 16000P
+125d  ESS Technology
+	0000  ES336H Fax Modem (Early Model)
+	1948  Solo?
+	1968  ES1968 Maestro 2
+		1028 0085  ES1968 Maestro-2 PCI
+		1033 8051  ES1968 Maestro-2 Audiodrive
+	1969  ES1969 Solo-1 Audiodrive
+		1014 0166  ES1969 SOLO-1 AudioDrive on IBM Aptiva Mainboard
+		125d 8888  Solo-1 Audio Adapter
+		153b 111b  Terratec 128i PCI
+	1978  ES1978 Maestro 2E
+		0e11 b112  Armada M700/E500
+		1033 803c  ES1978 Maestro-2E Audiodrive
+		1033 8058  ES1978 Maestro-2E Audiodrive
+		1092 4000  Monster Sound MX400
+		1179 0001  ES1978 Maestro-2E Audiodrive
+	1988  ES1988 Allegro-1
+		1092 4100  Sonic Impact S100
+		125d 1988  ESS Allegro-1 Audiodrive
+	1989  ESS Modem
+		125d 1989  ESS Modem
+	1998  ES1983S Maestro-3i PCI Audio Accelerator
+		1028 00b1  Latitude C600
+		1028 00e6  ES1983S Maestro-3i (Dell Inspiron 8100)
+	1999  ES1983S Maestro-3i PCI Modem Accelerator
+	199a  ES1983S Maestro-3i PCI Audio Accelerator
+	199b  ES1983S Maestro-3i PCI Modem Accelerator
+	2808  ES336H Fax Modem (Later Model)
+	2838  ES2838/2839 SuperLink Modem
+	2898  ES2898 Modem
+		125d 0424  ES56-PI Data Fax Modem
+		125d 0425  ES56T-PI Data Fax Modem
+		125d 0426  ES56V-PI Data Fax Modem
+		125d 0427  VW-PI Data Fax Modem
+		125d 0428  ES56ST-PI Data Fax Modem
+		125d 0429  ES56SV-PI Data Fax Modem
+		147a c001  ES56-PI Data Fax Modem
+		14fe 0428  ES56-PI Data Fax Modem
+		14fe 0429  ES56-PI Data Fax Modem
+125e  Specialvideo Engineering SRL
+125f  Concurrent Technologies, Inc.
+1260  Intersil Corporation
+	3872  Prism 2.5 Wavelan chipset
+		1468 0202  LAN-Express IEEE 802.11b Wireless LAN
+	3873  Prism 2.5 Wavelan chipset
+		1186 3501  DWL-520 Wireless PCI Adapter
+		1186 3700  DWL-520 Wireless PCI Adapter, Rev E1
+		1385 4105  MA311 802.11b wireless adapter
+		1668 0414  HWP01170-01 802.11b PCI Wireless Adapter
+		16a5 1601  AIR.mate PC-400 PCI Wireless LAN Adapter
+		1737 3874  WMP11 Wireless 802.11b PCI Adapter
+		8086 2513  Wireless 802.11b MiniPCI Adapter
+	3886  ISL3886 [Prism Javelin/Prism Xbow]
+		17cf 0037  Z-Com XG-901 and clones Wireless Adapter
+	3890  Intersil ISL3890 [Prism GT/Prism Duette]
+		10b8 2802  SMC2802W Wireless PCI Adapter
+		10b8 2835  SMC2835W Wireless Cardbus Adapter
+		10b8 a835  SMC2835W V2 Wireless Cardbus Adapter
+		1113 ee03  SMC2802W V2 Wireless PCI Adapter
+		1113 ee08  SMC2835W V3 EU Wireless Cardbus Adapter
+		1186 3202  DWL-G650 A1 Wireless Adapter
+		1259 c104  CG-WLCB54GT Wireless Adapter
+		1385 4800  WG511 Wireless Adapter
+		16a5 1605  ALLNET ALL0271 Wireless PCI Adapter
+		17cf 0014  Z-Com XG-600 and clones Wireless Adapter
+		17cf 0020  Z-Com XG-900 and clones Wireless Adapter
+	8130  HMP8130 NTSC/PAL Video Decoder
+	8131  HMP8131 NTSC/PAL Video Decoder
+1261  Matsushita-Kotobuki Electronics Industries, Ltd.
+1262  ES Computer Company, Ltd.
+1263  Sonic Solutions
+1264  Aval Nagasaki Corporation
+1265  Casio Computer Co., Ltd.
+1266  Microdyne Corporation
+	0001  NE10/100 Adapter (i82557B)
+	1910  NE2000Plus (RT8029) Ethernet Adapter
+		1266 1910  NE2000Plus Ethernet Adapter
+1267  S. A. Telecommunications
+	5352  PCR2101
+	5a4b  Telsat Turbo
+1268  Tektronix
+1269  Thomson-CSF/TTM
+126a  Lexmark International, Inc.
+126b  Adax, Inc.
+126c  Northern Telecom
+	1211  10/100BaseTX [RTL81xx]
+	126c  802.11b Wireless Ethernet Adapter
+126d  Splash Technology, Inc.
+126e  Sumitomo Metal Industries, Ltd.
+126f  Silicon Motion, Inc.
+	0501  SM501 VoyagerGX
+	0710  SM710 LynxEM
+	0712  SM712 LynxEM+
+	0720  SM720 Lynx3DM
+	0730  SM731 Cougar3DR
+	0810  SM810 LynxE
+	0811  SM811 LynxE
+	0820  SM820 Lynx3D
+	0910  SM910
+1270  Olympus Optical Co., Ltd.
+1271  GW Instruments
+1272  Telematics International
+1273  Hughes Network Systems
+	0002  DirecPC
+1274  Ensoniq
+	1171  ES1373 [AudioPCI] (also Creative Labs CT5803)
+	1371  ES1371 [AudioPCI-97]
+		0e11 0024  AudioPCI on Motherboard Compaq Deskpro
+		0e11 b1a7  ES1371, ES1373 AudioPCI
+		1033 80ac  ES1371, ES1373 AudioPCI
+		1042 1854  Tazer
+		107b 8054  Tabor2
+		1274 1371  Creative Sound Blaster AudioPCI64V, AudioPCI128
+		1462 6470  ES1371, ES1373 AudioPCI On Motherboard MS-6147 1.1A
+		1462 6560  ES1371, ES1373 AudioPCI On Motherboard MS-6156 1.10
+		1462 6630  ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 1.0A
+		1462 6631  ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 1.0A
+		1462 6632  ES1371, ES1373 AudioPCI On Motherboard MS-6163BX 2.0A
+		1462 6633  ES1371, ES1373 AudioPCI On Motherboard MS-6163VIA 2.0A
+		1462 6820  ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00
+		1462 6822  ES1371, ES1373 AudioPCI On Motherboard MS-6182 1.00A
+		1462 6830  ES1371, ES1373 AudioPCI On Motherboard MS-6183 1.00
+		1462 6880  ES1371, ES1373 AudioPCI On Motherboard MS-6188 1.00
+		1462 6900  ES1371, ES1373 AudioPCI On Motherboard MS-6190 1.00
+		1462 6910  ES1371, ES1373 AudioPCI On Motherboard MS-6191
+		1462 6930  ES1371, ES1373 AudioPCI On Motherboard MS-6193
+		1462 6990  ES1371, ES1373 AudioPCI On Motherboard MS-6199BX 2.0A
+		1462 6991  ES1371, ES1373 AudioPCI On Motherboard MS-6199VIA 2.0A
+		14a4 2077  ES1371, ES1373 AudioPCI On Motherboard KR639
+		14a4 2105  ES1371, ES1373 AudioPCI On Motherboard MR800
+		14a4 2107  ES1371, ES1373 AudioPCI On Motherboard MR801
+		14a4 2172  ES1371, ES1373 AudioPCI On Motherboard DR739
+		1509 9902  ES1371, ES1373 AudioPCI On Motherboard KW11
+		1509 9903  ES1371, ES1373 AudioPCI On Motherboard KW31
+		1509 9904  ES1371, ES1373 AudioPCI On Motherboard KA11
+		1509 9905  ES1371, ES1373 AudioPCI On Motherboard KC13
+		152d 8801  ES1371, ES1373 AudioPCI On Motherboard CP810E
+		152d 8802  ES1371, ES1373 AudioPCI On Motherboard CP810
+		152d 8803  ES1371, ES1373 AudioPCI On Motherboard P3810E
+		152d 8804  ES1371, ES1373 AudioPCI On Motherboard P3810-S
+		152d 8805  ES1371, ES1373 AudioPCI On Motherboard P3820-S
+		270f 2001  ES1371, ES1373 AudioPCI On Motherboard 6CTR
+		270f 2200  ES1371, ES1373 AudioPCI On Motherboard 6WTX
+		270f 3000  ES1371, ES1373 AudioPCI On Motherboard 6WSV
+		270f 3100  ES1371, ES1373 AudioPCI On Motherboard 6WIV2
+		270f 3102  ES1371, ES1373 AudioPCI On Motherboard 6WIV
+		270f 7060  ES1371, ES1373 AudioPCI On Motherboard 6ASA2
+		8086 4249  ES1371, ES1373 AudioPCI On Motherboard BI440ZX
+		8086 424c  ES1371, ES1373 AudioPCI On Motherboard BL440ZX
+		8086 425a  ES1371, ES1373 AudioPCI On Motherboard BZ440ZX
+		8086 4341  ES1371, ES1373 AudioPCI On Motherboard Cayman
+		8086 4343  ES1371, ES1373 AudioPCI On Motherboard Cape Cod
+		8086 4649  ES1371, ES1373 AudioPCI On Motherboard Fire Island
+		8086 464a  ES1371, ES1373 AudioPCI On Motherboard FJ440ZX
+		8086 4d4f  ES1371, ES1373 AudioPCI On Motherboard Montreal
+		8086 4f43  ES1371, ES1373 AudioPCI On Motherboard OC440LX
+		8086 5243  ES1371, ES1373 AudioPCI On Motherboard RC440BX
+		8086 5352  ES1371, ES1373 AudioPCI On Motherboard SunRiver
+		8086 5643  ES1371, ES1373 AudioPCI On Motherboard Vancouver
+		8086 5753  ES1371, ES1373 AudioPCI On Motherboard WS440BX
+	5000  ES1370 [AudioPCI]
+	5880  5880 AudioPCI
+		1274 2000  Creative Sound Blaster AudioPCI128
+		1274 2003  Creative SoundBlaster AudioPCI 128
+		1274 5880  Creative Sound Blaster AudioPCI128
+		1274 8001  Sound Blaster 16PCI 4.1ch
+		1458 a000  5880 AudioPCI On Motherboard 6OXET
+		1462 6880  5880 AudioPCI On Motherboard MS-6188 1.00
+		270f 2001  5880 AudioPCI On Motherboard 6CTR
+		270f 2200  5880 AudioPCI On Motherboard 6WTX
+		270f 7040  5880 AudioPCI On Motherboard 6ATA4
+1275  Network Appliance Corporation
+1276  Switched Network Technologies, Inc.
+1277  Comstream
+1278  Transtech Parallel Systems Ltd.
+	0701  TPE3/TM3 PowerPC Node
+	0710  TPE5 PowerPC PCI board
+1279  Transmeta Corporation
+	0295  Northbridge
+	0395  LongRun Northbridge
+	0396  SDRAM controller
+	0397  BIOS scratchpad
+127a  Rockwell International
+	1002  HCF 56k Data/Fax Modem
+		1092 094c  SupraExpress 56i PRO [Diamond SUP2380]
+		122d 4002  HPG / MDP3858-U
+		122d 4005  MDP3858-E
+		122d 4007  MDP3858-A/-NZ
+		122d 4012  MDP3858-SA
+		122d 4017  MDP3858-W
+		122d 4018  MDP3858-W
+		127a 1002  Rockwell 56K D/F HCF Modem
+	1003  HCF 56k Data/Fax Modem
+		0e11 b0bc  229-DF Zephyr
+		0e11 b114  229-DF Cheetah
+		1033 802b  229-DF
+		13df 1003  PCI56RX Modem
+		13e0 0117  IBM
+		13e0 0147  IBM F-1156IV+/R3 Spain V.90 Modem
+		13e0 0197  IBM
+		13e0 01c7  IBM F-1156IV+/R3 WW V.90 Modem
+		13e0 01f7  IBM
+		1436 1003  IBM
+		1436 1103  IBM 5614PM3G V.90 Modem
+		1436 1602  Compaq 229-DF Ducati
+	1004  HCF 56k Data/Fax/Voice Modem
+		1048 1500  MicroLink 56k Modem
+		10cf 1059  Fujitsu 229-DFRT
+	1005  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+		1005 127a  AOpen FM56-P
+		1033 8029  229-DFSV
+		1033 8054  Modem
+		10cf 103c  Fujitsu
+		10cf 1055  Fujitsu 229-DFSV
+		10cf 1056  Fujitsu 229-DFSV
+		122d 4003  MDP3858SP-U
+		122d 4006  Packard Bell MDP3858V-E
+		122d 4008  MDP3858SP-A/SP-NZ
+		122d 4009  MDP3858SP-E
+		122d 4010  MDP3858V-U
+		122d 4011  MDP3858SP-SA
+		122d 4013  MDP3858V-A/V-NZ
+		122d 4015  MDP3858SP-W
+		122d 4016  MDP3858V-W
+		122d 4019  MDP3858V-SA
+		13df 1005  PCI56RVP Modem
+		13e0 0187  IBM
+		13e0 01a7  IBM
+		13e0 01b7  IBM DF-1156IV+/R3 Spain V.90 Modem
+		13e0 01d7  IBM DF-1156IV+/R3 WW V.90 Modem
+		1436 1005  IBM
+		1436 1105  IBM
+		1437 1105  IBM 5614PS3G V.90 Modem
+	1022  HCF 56k Modem
+		1436 1303  M3-5614PM3G V.90 Modem
+	1023  HCF 56k Data/Fax Modem
+		122d 4020  Packard Bell MDP3858-WE
+		122d 4023  MDP3858-UE
+		13e0 0247  IBM F-1156IV+/R6 Spain V.90 Modem
+		13e0 0297  IBM
+		13e0 02c7  IBM F-1156IV+/R6 WW V.90 Modem
+		1436 1203  IBM
+		1436 1303  IBM
+	1024  HCF 56k Data/Fax/Voice Modem
+	1025  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+		10cf 106a  Fujitsu 235-DFSV
+		122d 4021  Packard Bell MDP3858V-WE
+		122d 4022  MDP3858SP-WE
+		122d 4024  MDP3858V-UE
+		122d 4025  MDP3858SP-UE
+	1026  HCF 56k PCI Speakerphone Modem
+	1032  HCF 56k Modem
+	1033  HCF 56k Modem
+	1034  HCF 56k Modem
+	1035  HCF 56k PCI Speakerphone Modem
+	1036  HCF 56k Modem
+	1085  HCF 56k Volcano PCI Modem
+	2005  HCF 56k Data/Fax Modem
+		104d 8044  229-DFSV
+		104d 8045  229-DFSV
+		104d 8055  PBE/Aztech 235W-DFSV
+		104d 8056  235-DFSV
+		104d 805a  Modem
+		104d 805f  Modem
+		104d 8074  Modem
+	2013  HSF 56k Data/Fax Modem
+		1179 0001  Modem
+		1179 ff00  Modem
+	2014  HSF 56k Data/Fax/Voice Modem
+		10cf 1057  Fujitsu Citicorp III
+		122d 4050  MSP3880-U
+		122d 4055  MSP3880-W
+	2015  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+		10cf 1063  Fujitsu
+		10cf 1064  Fujitsu
+		1468 2015  Fujitsu
+	2016  HSF 56k Data/Fax/Voice/Spkp Modem
+		122d 4051  MSP3880V-W
+		122d 4052  MSP3880SP-W
+		122d 4054  MSP3880V-U
+		122d 4056  MSP3880SP-U
+		122d 4057  MSP3880SP-A
+	4311  Riptide HSF 56k PCI Modem
+		127a 4311  Ring Modular? Riptide HSF RT HP Dom
+		13e0 0210  HP-GVC
+	4320  Riptide PCI Audio Controller
+		1235 4320  Riptide PCI Audio Controller
+	4321  Riptide HCF 56k PCI Modem
+		1235 4321  Hewlett Packard DF
+		1235 4324  Hewlett Packard DF
+		13e0 0210  Hewlett Packard DF
+		144d 2321  Riptide
+	4322  Riptide PCI Game Controller
+		1235 4322  Riptide PCI Game Controller
+	8234  RapidFire 616X ATM155 Adapter
+		108d 0022  RapidFire 616X ATM155 Adapter
+		108d 0027  RapidFire 616X ATM155 Adapter
+127b  Pixera Corporation
+127c  Crosspoint Solutions, Inc.
+127d  Vela Research
+127e  Winnov, L.P.
+127f  Fujifilm
+1280  Photoscript Group Ltd.
+1281  Yokogawa Electric Corporation
+1282  Davicom Semiconductor, Inc.
+	9009  Ethernet 100/10 MBit
+	9100  21x4x DEC-Tulip compatible 10/100 Ethernet
+	9102  21x4x DEC-Tulip compatible 10/100 Ethernet
+	9132  Ethernet 100/10 MBit
+1283  Integrated Technology Express, Inc.
+	673a  IT8330G
+	8212  IT/ITE8212 Dual channel ATA RAID controller (PCI version seems to be IT8212, embedded seems to be ITE8212)
+		1283 0001  IT/ITE8212 Dual channel ATA RAID controller
+	8330  IT8330G
+	8872  IT8874F PCI Dual Serial Port Controller
+	8888  IT8888F PCI to ISA Bridge with SMB
+	8889  IT8889F PCI to ISA Bridge
+	e886  IT8330G
+1284  Sahara Networks, Inc.
+1285  Platform Technologies, Inc.
+	0100  AGOGO sound chip (aka ESS Maestro 1)
+1286  Mazet GmbH
+1287  M-Pact, Inc.
+	001e  LS220D DVD Decoder
+	001f  LS220C DVD Decoder
+1288  Timestep Corporation
+1289  AVC Technology, Inc.
+128a  Asante Technologies, Inc.
+128b  Transwitch Corporation
+128c  Retix Corporation
+128d  G2 Networks, Inc.
+	0021  ATM155 Adapter
+128e  Hoontech Corporation/Samho Multi Tech Ltd.
+	0008  ST128 WSS/SB
+	0009  ST128 SAM9407
+	000a  ST128 Game Port
+	000b  ST128 MPU Port
+	000c  ST128 Ctrl Port
+128f  Tateno Dennou, Inc.
+1290  Sord Computer Corporation
+1291  NCS Computer Italia
+1292  Tritech Microelectronics Inc
+1293  Media Reality Technology
+1294  Rhetorex, Inc.
+1295  Imagenation Corporation
+1296  Kofax Image Products
+1297  Holco Enterprise Co, Ltd/Shuttle Computer
+1298  Spellcaster Telecommunications Inc.
+1299  Knowledge Technology Lab.
+129a  VMetro, inc.
+	0615  PBT-615 PCI-X Bus Analyzer
+129b  Image Access
+129c  Jaycor
+129d  Compcore Multimedia, Inc.
+129e  Victor Company of Japan, Ltd.
+129f  OEC Medical Systems, Inc.
+12a0  Allen-Bradley Company
+12a1  Simpact Associates, Inc.
+12a2  Newgen Systems Corporation
+12a3  Lucent Technologies
+	8105  T8105 H100 Digital Switch
+12a4  NTT Electronics Technology Company
+12a5  Vision Dynamics Ltd.
+12a6  Scalable Networks, Inc.
+12a7  AMO GmbH
+12a8  News Datacom
+12a9  Xiotech Corporation
+12aa  SDL Communications, Inc.
+12ab  Yuan Yuan Enterprise Co., Ltd.
+	0002  AU8830 [Vortex2] Based Sound Card With A3D Support
+	3000  MPG-200C PCI DVD Decoder Card
+12ac  Measurex Corporation
+12ad  Multidata GmbH
+12ae  Alteon Networks Inc.
+	0001  AceNIC Gigabit Ethernet
+		1014 0104  Gigabit Ethernet-SX PCI Adapter
+		12ae 0001  Gigabit Ethernet-SX (Universal)
+		1410 0104  Gigabit Ethernet-SX PCI Adapter
+	0002  AceNIC Gigabit Ethernet (Copper)
+		10a9 8002  Acenic Gigabit Ethernet
+		12ae 0002  Gigabit Ethernet-T (3C986-T)
+	00fa  Farallon PN9100-T Gigabit Ethernet
+12af  TDK USA Corp
+12b0  Jorge Scientific Corp
+12b1  GammaLink
+12b2  General Signal Networks
+12b3  Inter-Face Co Ltd
+12b4  FutureTel Inc
+12b5  Granite Systems Inc.
+12b6  Natural Microsystems
+12b7  Cognex Modular Vision Systems Div. - Acumen Inc.
+12b8  Korg
+12b9  3Com Corp, Modem Division (formerly US Robotics)
+	1006  WinModem
+		12b9 005c  USR 56k Internal Voice WinModem (Model 3472)
+		12b9 005e  USR 56k Internal WinModem (Models 662975)
+		12b9 0062  USR 56k Internal Voice WinModem (Model 662978)
+		12b9 0068  USR 56k Internal Voice WinModem (Model 5690)
+		12b9 007a  USR 56k Internal Voice WinModem (Model 662974)
+		12b9 007f  USR 56k Internal WinModem (Models 5698, 5699)
+		12b9 0080  USR 56k Internal WinModem (Models 2975, 3528)
+		12b9 0081  USR 56k Internal Voice WinModem (Models 2974, 3529)
+		12b9 0091  USR 56k Internal Voice WinModem (Model 2978)
+	1007  USR 56k Internal WinModem
+		12b9 00a3  USR 56k Internal WinModem (Model 3595)
+	1008  56K FaxModem Model 5610
+		12b9 00a2  USR 56k Internal FAX Modem (Model 2977)
+		12b9 00aa  USR 56k Internal Voice Modem (Model 2976)
+		12b9 00ab  USR 56k Internal Voice Modem (Model 5609)
+		12b9 00ac  USR 56k Internal Voice Modem (Model 3298)
+		12b9 00ad  USR 56k Internal FAX Modem (Model 5610)
+12ba  BittWare, Inc.
+12bb  Nippon Unisoft Corporation
+12bc  Array Microsystems
+12bd  Computerm Corp.
+12be  Anchor Chips Inc.
+	3041  AN3041Q CO-MEM
+	3042  AN3042Q CO-MEM Lite
+		12be 3042  Anchor Chips Lite Evaluation Board
+12bf  Fujifilm Microdevices
+12c0  Infimed
+12c1  GMM Research Corp
+12c2  Mentec Limited
+12c3  Holtek Microelectronics Inc
+	0058  PCI NE2K Ethernet
+	5598  PCI NE2K Ethernet
+12c4  Connect Tech Inc
+	0001  Blue HEAT/PCI 8 (RS232/CL/RJ11)
+	0002  Blue HEAT/PCI 4 (RS232)
+	0003  Blue HEAT/PCI 2 (RS232)
+	0004  Blue HEAT/PCI 8 (UNIV, RS485)
+	0005  Blue HEAT/PCI 4+4/6+2 (UNIV, RS232/485)
+	0006  Blue HEAT/PCI 4 (OPTO, RS485)
+	0007  Blue HEAT/PCI 2+2 (RS232/485)
+	0008  Blue HEAT/PCI 2 (OPTO, Tx, RS485)
+	0009  Blue HEAT/PCI 2+6 (RS232/485)
+	000a  Blue HEAT/PCI 8 (Tx, RS485)
+	000b  Blue HEAT/PCI 4 (Tx, RS485)
+	000c  Blue HEAT/PCI 2 (20 MHz, RS485)
+	000d  Blue HEAT/PCI 2 PTM
+	0100  NT960/PCI
+	0201  cPCI Titan - 2 Port
+	0202  cPCI Titan - 4 Port
+	0300  CTI PCI UART 2 (RS232)
+	0301  CTI PCI UART 4 (RS232)
+	0302  CTI PCI UART 8 (RS232)
+	0310  CTI PCI UART 1+1 (RS232/485)
+	0311  CTI PCI UART 2+2 (RS232/485)
+	0312  CTI PCI UART 4+4 (RS232/485)
+	0320  CTI PCI UART 2
+	0321  CTI PCI UART 4
+	0322  CTI PCI UART 8
+	0330  CTI PCI UART 2 (RS485)
+	0331  CTI PCI UART 4 (RS485)
+	0332  CTI PCI UART 8 (RS485)
+12c5  Picture Elements Incorporated
+	007e  Imaging/Scanning Subsystem Engine
+	007f  Imaging/Scanning Subsystem Engine
+	0081  PCIVST [Grayscale Thresholding Engine]
+	0085  Video Simulator/Sender
+	0086  THR2 Multi-scale Thresholder
+12c6  Mitani Corporation
+12c7  Dialogic Corp
+12c8  G Force Co, Ltd
+12c9  Gigi Operations
+12ca  Integrated Computing Engines
+12cb  Antex Electronics Corporation
+12cc  Pluto Technologies International
+12cd  Aims Lab
+12ce  Netspeed Inc.
+12cf  Prophet Systems, Inc.
+12d0  GDE Systems, Inc.
+12d1  PSITech
+12d2  NVidia / SGS Thomson (Joint Venture)
+	0008  NV1
+	0009  DAC64
+	0018  Riva128
+		1048 0c10  VICTORY Erazor
+		107b 8030  STB Velocity 128
+		1092 0350  Viper V330
+		1092 1092  Viper V330
+		10b4 1b1b  STB Velocity 128
+		10b4 1b1d  STB Velocity 128
+		10b4 1b1e  STB Velocity 128, PAL TV-Out
+		10b4 1b20  STB Velocity 128 Sapphire
+		10b4 1b21  STB Velocity 128
+		10b4 1b22  STB Velocity 128 AGP, NTSC TV-Out
+		10b4 1b23  STB Velocity 128 AGP, PAL TV-Out
+		10b4 1b27  STB Velocity 128 DVD
+		10b4 1b88  MVP Pro 128
+		10b4 222a  STB Velocity 128 AGP
+		10b4 2230  STB Velocity 128
+		10b4 2232  STB Velocity 128
+		10b4 2235  STB Velocity 128 AGP
+		2a15 54a3  3DVision-SAGP / 3DexPlorer 3000
+	0019  Riva128ZX
+	0020  TNT
+	0028  TNT2
+	0029  UTNT2
+	002c  VTNT2
+	00a0  ITNT2
+12d3  Vingmed Sound A/S
+12d4  Ulticom (Formerly DGM&S)
+	0200  T1 Card
+12d5  Equator Technologies Inc
+	0003  BSP16
+	1000  BSP15
+12d6  Analogic Corp
+12d7  Biotronic SRL
+12d8  Pericom Semiconductor
+12d9  Aculab PLC
+	0002  PCI Prosody
+	0004  cPCI Prosody
+	0005  Aculab E1/T1 PCI card
+12da  True Time Inc.
+12db  Annapolis Micro Systems, Inc
+12dc  Symicron Computer Communication Ltd.
+12dd  Management Graphics
+12de  Rainbow Technologies
+	0200  CryptoSwift CS200
+12df  SBS Technologies Inc
+12e0  Chase Research
+	0010  ST16C654 Quad UART
+	0020  ST16C654 Quad UART
+	0030  ST16C654 Quad UART
+12e1  Nintendo Co, Ltd
+12e2  Datum Inc. Bancomm-Timing Division
+12e3  Imation Corp - Medical Imaging Systems
+12e4  Brooktrout Technology Inc
+12e5  Apex Semiconductor Inc
+12e6  Cirel Systems
+12e7  Sunsgroup Corporation
+12e8  Crisc Corp
+12e9  GE Spacenet
+12ea  Zuken
+12eb  Aureal Semiconductor
+	0001  Vortex 1
+		104d 8036  AU8820 Vortex Digital Audio Processor
+		1092 2000  Sonic Impact A3D
+		1092 2100  Sonic Impact A3D
+		1092 2110  Sonic Impact A3D
+		1092 2200  Sonic Impact A3D
+		122d 1002  AU8820 Vortex Digital Audio Processor
+		12eb 0001  AU8820 Vortex Digital Audio Processor
+		5053 3355  Montego
+	0002  Vortex 2
+		104d 8049  AU8830 Vortex 3D Digital Audio Processor
+		104d 807b  AU8830 Vortex 3D Digital Audio Processor
+		1092 3000  Monster Sound II
+		1092 3001  Monster Sound II
+		1092 3002  Monster Sound II
+		1092 3003  Monster Sound II
+		1092 3004  Monster Sound II
+		12eb 0001  AU8830 Vortex 3D Digital Audio Processor
+		12eb 0002  AU8830 Vortex 3D Digital Audio Processor
+		12eb 0088  AU8830 Vortex 3D Digital Audio Processor
+		144d 3510  AU8830 Vortex 3D Digital Audio Processor
+		5053 3356  Montego II
+	0003  AU8810 Vortex Digital Audio Processor
+		104d 8049  AU8810 Vortex Digital Audio Processor
+		104d 8077  AU8810 Vortex Digital Audio Processor
+		109f 1000  AU8810 Vortex Digital Audio Processor
+		12eb 0003  AU8810 Vortex Digital Audio Processor
+		1462 6780  AU8810 Vortex Digital Audio Processor
+		14a4 2073  AU8810 Vortex Digital Audio Processor
+		14a4 2091  AU8810 Vortex Digital Audio Processor
+		14a4 2104  AU8810 Vortex Digital Audio Processor
+		14a4 2106  AU8810 Vortex Digital Audio Processor
+	8803  Vortex 56k Software Modem
+		12eb 8803  Vortex 56k Software Modem
+12ec  3A International, Inc.
+12ed  Optivision Inc.
+12ee  Orange Micro
+12ef  Vienna Systems
+12f0  Pentek
+12f1  Sorenson Vision Inc
+12f2  Gammagraphx, Inc.
+12f3  Radstone Technology
+12f4  Megatel
+12f5  Forks
+12f6  Dawson France
+12f7  Cognex
+12f8  Electronic Design GmbH
+	0002  VideoMaker
+12f9  Four Fold Ltd
+12fb  Spectrum Signal Processing
+12fc  Capital Equipment Corp
+12fd  I2S
+12fe  ESD Electronic System Design GmbH
+12ff  Lexicon
+1300  Harman International Industries Inc
+1302  Computer Sciences Corp
+1303  Innovative Integration
+1304  Juniper Networks
+1305  Netphone, Inc
+1306  Duet Technologies
+# Formerly ComputerBoards
+1307  Measurement Computing
+	0001  PCI-DAS1602/16
+	000b  PCI-DIO48H
+	000c  PCI-PDISO8
+	000d  PCI-PDISO16
+	000f  PCI-DAS1200
+	0010  PCI-DAS1602/12
+	0014  PCI-DIO24H
+	0015  PCI-DIO24H/CTR3
+	0016  PCI-DIO48H/CTR15
+	0017  PCI-DIO96H
+	0018  PCI-CTR05
+	0019  PCI-DAS1200/JR
+	001a  PCI-DAS1001
+	001b  PCI-DAS1002
+	001c  PCI-DAS1602JR/16
+	001d  PCI-DAS6402/16
+	001e  PCI-DAS6402/12
+	001f  PCI-DAS16/M1
+	0020  PCI-DDA02/12
+	0021  PCI-DDA04/12
+	0022  PCI-DDA08/12
+	0023  PCI-DDA02/16
+	0024  PCI-DDA04/16
+	0025  PCI-DDA08/16
+	0026  PCI-DAC04/12-HS
+	0027  PCI-DAC04/16-HS
+	0028  PCI-DIO24
+	0029  PCI-DAS08
+	002c  PCI-INT32
+	0033  PCI-DUAL-AC5
+	0034  PCI-DAS-TC
+	0035  PCI-DAS64/M1/16
+	0036  PCI-DAS64/M2/16
+	0037  PCI-DAS64/M3/16
+	004c  PCI-DAS1000
+	004d  PCI-QUAD04
+	0052  PCI-DAS4020/12
+	005e  PCI-DAS6025
+1308  Jato Technologies Inc.
+	0001  NetCelerator Adapter
+		1308 0001  NetCelerator Adapter
+1309  AB Semiconductor Ltd
+130a  Mitsubishi Electric Microcomputer
+130b  Colorgraphic Communications Corp
+130c  Ambex Technologies, Inc
+130d  Accelerix Inc
+130e  Yamatake-Honeywell Co. Ltd
+130f  Advanet Inc
+1310  Gespac
+1311  Videoserver, Inc
+1312  Acuity Imaging, Inc
+1313  Yaskawa Electric Co.
+1316  Teradyne Inc
+1317  Linksys
+	0981  21x4x DEC-Tulip compatible 10/100 Ethernet
+	0985  NC100 Network Everywhere Fast Ethernet 10/100
+	1985  21x4x DEC-Tulip compatible 10/100 Ethernet
+	2850  HSP MicroModem 56
+	8201  ADMtek ADM8211 802.11b Wireless Interface
+		10b8 2635  SMC2635W 802.11b (11Mbps) wireless lan pcmcia (cardbus) card
+		1317 8201  SMC2635W 802.11b (11mbps) wireless lan pcmcia (cardbus) card
+	8211  ADMtek ADM8211 802.11b Wireless Interface
+	9511  21x4x DEC-Tulip compatible 10/100 Ethernet
+1318  Packet Engines Inc.
+	0911  GNIC-II PCI Gigabit Ethernet [Hamachi]
+1319  Fortemedia, Inc
+	0801  Xwave QS3000A [FM801]
+	0802  Xwave QS3000A [FM801 game port]
+	1000  FM801 PCI Audio
+	1001  FM801 PCI Joystick
+131a  Finisar Corp.
+131c  Nippon Electro-Sensory Devices Corp
+131d  Sysmic, Inc.
+131e  Xinex Networks Inc
+131f  Siig Inc
+	1000  CyberSerial (1-port) 16550
+	1001  CyberSerial (1-port) 16650
+	1002  CyberSerial (1-port) 16850
+	1010  Duet 1S(16550)+1P
+	1011  Duet 1S(16650)+1P
+	1012  Duet 1S(16850)+1P
+	1020  CyberParallel (1-port)
+	1021  CyberParallel (2-port)
+	1030  CyberSerial (2-port) 16550
+	1031  CyberSerial (2-port) 16650
+	1032  CyberSerial (2-port) 16850
+	1034  Trio 2S(16550)+1P
+	1035  Trio 2S(16650)+1P
+	1036  Trio 2S(16850)+1P
+	1050  CyberSerial (4-port) 16550
+	1051  CyberSerial (4-port) 16650
+	1052  CyberSerial (4-port) 16850
+	2000  CyberSerial (1-port) 16550
+	2001  CyberSerial (1-port) 16650
+	2002  CyberSerial (1-port) 16850
+	2010  Duet 1S(16550)+1P
+	2011  Duet 1S(16650)+1P
+	2012  Duet 1S(16850)+1P
+	2020  CyberParallel (1-port)
+	2021  CyberParallel (2-port)
+	2030  CyberSerial (2-port) 16550
+		131f 2030  PCI Serial Card
+	2031  CyberSerial (2-port) 16650
+	2032  CyberSerial (2-port) 16850
+	2040  Trio 1S(16550)+2P
+	2041  Trio 1S(16650)+2P
+	2042  Trio 1S(16850)+2P
+	2050  CyberSerial (4-port) 16550
+	2051  CyberSerial (4-port) 16650
+	2052  CyberSerial (4-port) 16850
+	2060  Trio 2S(16550)+1P
+	2061  Trio 2S(16650)+1P
+	2062  Trio 2S(16850)+1P
+	2081  CyberSerial (8-port) ST16654
+1320  Crypto AG
+1321  Arcobel Graphics BV
+1322  MTT Co., Ltd
+1323  Dome Inc
+1324  Sphere Communications
+1325  Salix Technologies, Inc
+1326  Seachange international
+1327  Voss scientific
+1328  quadrant international
+1329  Productivity Enhancement
+132a  Microcom Inc.
+132b  Broadband Technologies
+132c  Micrel Inc
+132d  Integrated Silicon Solution, Inc.
+1330  MMC Networks
+1331  Radisys Corp.
+	0030  ENP-2611
+	8200  82600 Host Bridge
+	8201  82600 IDE
+	8202  82600 USB
+	8210  82600 PCI Bridge
+1332  Micro Memory
+	5415  MM-5415CN PCI Memory Module with Battery Backup
+	5425  MM-5425CN PCI 64/66 Memory Module with Battery Backup
+1334  Redcreek Communications, Inc
+1335  Videomail, Inc
+1337  Third Planet Publishing
+1338  BT Electronics
+133a  Vtel Corp
+133b  Softcom Microsystems
+133c  Holontech Corp
+133d  SS Technologies
+133e  Virtual Computer Corp
+133f  SCM Microsystems
+1340  Atalla Corp
+1341  Kyoto Microcomputer Co
+1342  Promax Systems Inc
+1343  Phylon Communications Inc
+1344  Crucial Technology
+1345  Arescom Inc
+1347  Odetics
+1349  Sumitomo Electric Industries, Ltd.
+134a  DTC Technology Corp.
+	0001  Domex 536
+	0002  Domex DMX3194UP SCSI Adapter
+134b  ARK Research Corp.
+134c  Chori Joho System Co. Ltd
+134d  PCTel Inc
+	2189  HSP56 MicroModem
+	2486  2304WT V.92 MDC Modem
+	7890  HSP MicroModem 56
+		134d 0001  PCT789 adapter
+	7891  HSP MicroModem 56
+		134d 0001  HSP MicroModem 56
+	7892  HSP MicroModem 56
+	7893  HSP MicroModem 56
+	7894  HSP MicroModem 56
+	7895  HSP MicroModem 56
+	7896  HSP MicroModem 56
+	7897  HSP MicroModem 56
+134e  CSTI
+134f  Algo System Co Ltd
+1350  Systec Co. Ltd
+1351  Sonix Inc
+1353  Thales Idatys
+	0002  Proserver
+	0003  PCI-FUT
+	0004  PCI-S0
+	0005  PCI-FUT-S0
+1354  Dwave System Inc
+1355  Kratos Analytical Ltd
+1356  The Logical Co
+1359  Prisa Networks
+135a  Brain Boxes
+135b  Giganet Inc
+135c  Quatech Inc
+	0010  QSC-100
+	0020  DSC-100
+	0030  DSC-200/300
+	0040  QSC-200/300
+	0050  ESC-100D
+	0060  ESC-100M
+	00f0  MPAC-100 Syncronous Serial Card (Zilog 85230)
+	0170  QSCLP-100
+	0180  DSCLP-100
+	0190  SSCLP-100
+	01a0  QSCLP-200/300
+	01b0  DSCLP-200/300
+	01c0  SSCLP-200/300
+135d  ABB Network Partner AB
+135e  Sealevel Systems Inc
+	5101  Route 56.PCI - Multi-Protocol Serial Interface (Zilog Z16C32)
+	7101  Single Port RS-232/422/485/530
+	7201  Dual Port RS-232/422/485 Interface
+	7202  Dual Port RS-232 Interface
+	7401  Four Port RS-232 Interface
+	7402  Four Port RS-422/485 Interface
+	7801  Eight Port RS-232 Interface
+	7804  Eight Port RS-232/422/485 Interface
+	8001  8001 Digital I/O Adapter
+135f  I-Data International A-S
+1360  Meinberg Funkuhren
+	0101  PCI32 DCF77 Radio Clock
+	0102  PCI509 DCF77 Radio Clock
+	0103  PCI510 DCF77 Radio Clock
+	0201  GPS167PCI GPS Receiver
+	0202  GPS168PCI GPS Receiver
+	0203  GPS169PCI GPS Receiver
+	0301  TCR510PCI IRIG Receiver
+1361  Soliton Systems K.K.
+1362  Fujifacom Corporation
+1363  Phoenix Technology Ltd
+1364  ATM Communications Inc
+1365  Hypercope GmbH
+1366  Teijin Seiki Co. Ltd
+1367  Hitachi Zosen Corporation
+1368  Skyware Corporation
+1369  Digigram
+136a  High Soft Tech
+136b  Kawasaki Steel Corporation
+	ff01  KL5A72002 Motion JPEG
+136c  Adtek System Science Co Ltd
+136d  Gigalabs Inc
+136f  Applied Magic Inc
+1370  ATL Products
+1371  CNet Technology Inc
+	434e  GigaCard Network Adapter
+		1371 434e  N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L)
+1373  Silicon Vision Inc
+1374  Silicom Ltd
+1375  Argosystems Inc
+1376  LMC
+1377  Electronic Equipment Production & Distribution GmbH
+1378  Telemann Co. Ltd
+1379  Asahi Kasei Microsystems Co Ltd
+137a  Mark of the Unicorn Inc
+	0001  PCI-324 Audiowire Interface
+137b  PPT Vision
+137c  Iwatsu Electric Co Ltd
+137d  Dynachip Corporation
+137e  Patriot Scientific Corporation
+137f  Japan Satellite Systems Inc
+1380  Sanritz Automation Co Ltd
+1381  Brains Co. Ltd
+1382  Marian - Electronic & Software
+	0001  ARC88 audio recording card
+	2008  Prodif 96 Pro sound system
+	2088  Marc 8 Midi sound system
+	20c8  Marc A sound system
+	4008  Marc 2 sound system
+	4010  Marc 2 Pro sound system
+	4048  Marc 4 MIDI sound system
+	4088  Marc 4 Digi sound system
+	4248  Marc X sound system
+1383  Controlnet Inc
+1384  Reality Simulation Systems Inc
+1385  Netgear
+# Note: This lists as Atheros Communications, Inc. AR5212 802.11abg NIC because of Madwifi
+	0013  WG311T
+	311a  GA511 Gigabit Ethernet
+	4100  802.11b Wireless Adapter (MA301)
+	4105  MA311 802.11b wireless adapter
+	4400  WAG511 802.11a/b/g Dual Band Wireless PC Card
+	4600  WAG511 802.11a/b/g Dual Band Wireless PC Card
+	4601  WAG511 802.11a/b/g Dual Band Wireless PC Card
+	4610  WAG511 802.11a/b/g Dual Band Wireless PC Card
+	4a00  WAG311 802.11a/g Wireless PCI Adapter
+	4c00  WG311v2 54 Mbps Wireless PCI Adapter
+	620a  GA620 Gigabit Ethernet
+	622a  GA622
+	630a  GA630 Gigabit Ethernet
+	f004  FA310TX
+1386  Video Domain Technologies
+1387  Systran Corp
+1388  Hitachi Information Technology Co Ltd
+1389  Applicom International
+	0001  PCI1500PFB [Intelligent fieldbus adaptor]
+138a  Fusion Micromedia Corp
+138b  Tokimec Inc
+138c  Silicon Reality
+138d  Future Techno Designs pte Ltd
+138e  Basler GmbH
+138f  Patapsco Designs Inc
+1390  Concept Development Inc
+1391  Development Concepts Inc
+1392  Medialight Inc
+1393  Moxa Technologies Co Ltd
+	1040  Smartio C104H/PCI
+	1141  Industrio CP-114
+	1680  Smartio C168H/PCI
+	2040  Intellio CP-204J
+	2180  Intellio C218 Turbo PCI
+	3200  Intellio C320 Turbo PCI
+1394  Level One Communications
+	0001  LXT1001 Gigabit Ethernet
+		1394 0001  NetCelerator Adapter
+1395  Ambicom Inc
+1396  Cipher Systems Inc
+1397  Cologne Chip Designs GmbH
+	2bd0  ISDN network controller [HFC-PCI]
+		1397 2bd0  ISDN Board
+		e4bf 1000  CI1-1-Harp
+1398  Clarion co. Ltd
+1399  Rios systems Co Ltd
+139a  Alacritech Inc
+	0001  Quad Port 10/100 Server Accelerator
+	0003  Single Port 10/100 Server Accelerator
+	0005  Single Port Gigabit Server Accelerator
+139b  Mediasonic Multimedia Systems Ltd
+139c  Quantum 3d Inc
+139d  EPL limited
+139e  Media4
+139f  Aethra s.r.l.
+13a0  Crystal Group Inc
+13a1  Kawasaki Heavy Industries Ltd
+13a2  Ositech Communications Inc
+13a3  Hifn Inc.
+	0005  7751 Security Processor
+	0006  6500 Public Key Processor
+	0007  7811 Security Processor
+	0012  7951 Security Processor
+	0014  78XX Security Processor
+	0016  8065 Security Processor
+	0017  8165 Security Processor
+	0018  8154 Security Processor
+	001d  7956 Security Processor
+	0020  7955 Security Processor
+13a4  Rascom Inc
+13a5  Audio Digital Imaging Inc
+13a6  Videonics Inc
+13a7  Teles AG
+13a8  Exar Corp.
+	0154  XR17C154 Quad UART
+	0158  XR17C158 Octal UART
+13a9  Siemens Medical Systems, Ultrasound Group
+13aa  Broadband Networks Inc
+13ab  Arcom Control Systems Ltd
+13ac  Motion Media Technology Ltd
+13ad  Nexus Inc
+13ae  ALD Technology Ltd
+13af  T.Sqware
+13b0  Maxspeed Corp
+13b1  Tamura corporation
+13b2  Techno Chips Co. Ltd
+13b3  Lanart Corporation
+13b4  Wellbean Co Inc
+13b5  ARM
+13b6  Dlog GmbH
+13b7  Logic Devices Inc
+13b8  Nokia Telecommunications oy
+13b9  Elecom Co Ltd
+13ba  Oxford Instruments
+13bb  Sanyo Technosound Co Ltd
+13bc  Bitran Corporation
+13bd  Sharp corporation
+13be  Miroku Jyoho Service Co. Ltd
+13bf  Sharewave Inc
+13c0  Microgate Corporation
+	0010  SyncLink Adapter v1
+	0020  SyncLink SCC Adapter
+	0030  SyncLink Multiport Adapter
+	0210  SyncLink Adapter v2
+13c1  3ware Inc
+	1000  3ware Inc 3ware 5xxx/6xxx-series PATA-RAID
+	1001  3ware Inc 3ware 7xxx/8xxx-series PATA/SATA-RAID
+		13c1 1001  3ware Inc 3ware 7xxx/8xxx-series PATA/SATA-RAID
+	1002  3ware Inc 3ware 9xxx-series SATA-RAID
+13c2  Technotrend Systemtechnik GmbH
+13c3  Janz Computer AG
+13c4  Phase Metrics
+13c5  Alphi Technology Corp
+13c6  Condor Engineering Inc
+	0520  CEI-520 A429 Card
+	0620  CEI-620 A429 Card
+	0820  CEI-820 A429 Card
+13c7  Blue Chip Technology Ltd
+13c8  Apptech Inc
+13c9  Eaton Corporation
+13ca  Iomega Corporation
+13cb  Yano Electric Co Ltd
+13cc  Metheus Corporation
+13cd  Compatible Systems Corporation
+13ce  Cocom A/S
+13cf  Studio Audio & Video Ltd
+13d0  Techsan Electronics Co Ltd
+	2103  B2C2 FlexCopII DVB chip / Technisat SkyStar2 DVB card
+	2200  B2C2 FlexCopIII DVB chip / Technisat SkyStar2 DVB card
+13d1  Abocom Systems Inc
+	ab02  ADMtek Centaur-C rev 17 [D-Link DFE-680TX] CardBus Fast Ethernet Adapter
+	ab03  21x4x DEC-Tulip compatible 10/100 Ethernet
+	ab06  RTL8139 [FE2000VX] CardBus Fast Ethernet Attached Port Adapter
+	ab08  21x4x DEC-Tulip compatible 10/100 Ethernet
+13d2  Shark Multimedia Inc
+13d3  IMC Networks
+13d4  Graphics Microsystems Inc
+13d5  Media 100 Inc
+13d6  K.I. Technology Co Ltd
+13d7  Toshiba Engineering Corporation
+13d8  Phobos corporation
+13d9  Apex PC Solutions Inc
+13da  Intresource Systems pte Ltd
+13db  Janich & Klass Computertechnik GmbH
+13dc  Netboost Corporation
+13dd  Multimedia Bundle Inc
+13de  ABB Robotics Products AB
+13df  E-Tech Inc
+	0001  PCI56RVP Modem
+		13df 0001  PCI56RVP Modem
+13e0  GVC Corporation
+13e1  Silicom Multimedia Systems Inc
+13e2  Dynamics Research Corporation
+13e3  Nest Inc
+13e4  Calculex Inc
+13e5  Telesoft Design Ltd
+13e6  Argosy research Inc
+13e7  NAC Incorporated
+13e8  Chip Express Corporation
+13e9  Intraserver Technology Inc
+13ea  Dallas Semiconductor
+13eb  Hauppauge Computer Works Inc
+13ec  Zydacron Inc
+13ed  Raytheion E-Systems
+13ee  Hayes Microcomputer Products Inc
+13ef  Coppercom Inc
+13f0  Sundance Technology Inc
+	0201  ST201 Sundance Ethernet
+13f1  Oce' - Technologies B.V.
+13f2  Ford Microelectronics Inc
+13f3  Mcdata Corporation
+13f4  Troika Networks, Inc.
+	1401  Zentai Fibre Channel Adapter
+13f5  Kansai Electric Co. Ltd
+13f6  C-Media Electronics Inc
+	0011  CMI8738
+	0100  CM8338A
+		13f6 ffff  CMI8338/C3DX PCI Audio Device
+	0101  CM8338B
+		13f6 0101  CMI8338-031 PCI Audio Device
+	0111  CM8738
+		1019 0970  P6STP-FL motherboard
+		1043 8035  CUSI-FX motherboard
+		1043 8077  CMI8738 6-channel audio controller
+		1043 80e2  CMI8738 6ch-MX
+		13f6 0111  CMI8738/C3DX PCI Audio Device
+		1681 a000  Gamesurround MUSE XL
+	0211  CM8738
+13f7  Wildfire Communications
+13f8  Ad Lib Multimedia Inc
+13f9  NTT Advanced Technology Corp.
+13fa  Pentland Systems Ltd
+13fb  Aydin Corp
+13fc  Computer Peripherals International
+13fd  Micro Science Inc
+13fe  Advantech Co. Ltd
+	1240  PCI-1240 4-channel stepper motor controller card w.  Nova Electronics MCX314
+	1600  PCI-1612 4-port RS-232/422/485 PCI Communication Card
+	1752  PCI-1752
+	1754  PCI-1754
+	1756  PCI-1756
+13ff  Silicon Spice Inc
+1400  Artx Inc
+	1401  9432 TX
+1401  CR-Systems A/S
+1402  Meilhaus Electronic GmbH
+1403  Ascor Inc
+1404  Fundamental Software Inc
+1405  Excalibur Systems Inc
+1406  Oce' Printing Systems GmbH
+1407  Lava Computer mfg Inc
+	0100  Lava Dual Serial
+	0101  Lava Quatro A
+	0102  Lava Quatro B
+	0110  Lava DSerial-PCI Port A
+	0111  Lava DSerial-PCI Port B
+	0120  Quattro-PCI A
+	0121  Quattro-PCI B
+	0180  Lava Octo A
+	0181  Lava Octo B
+	0200  Lava Port Plus
+	0201  Lava Quad A
+	0202  Lava Quad B
+	0220  Lava Quattro PCI Ports A/B
+	0221  Lava Quattro PCI Ports C/D
+	0500  Lava Single Serial
+	0600  Lava Port 650
+	8000  Lava Parallel
+	8001  Dual parallel port controller A
+	8002  Lava Dual Parallel port A
+	8003  Lava Dual Parallel port B
+	8800  BOCA Research IOPPAR
+1408  Aloka Co. Ltd
+1409  Timedia Technology Co Ltd
+	7168  PCI2S550 (Dual 16550 UART)
+140a  DSP Research Inc
+140b  Ramix Inc
+140c  Elmic Systems Inc
+140d  Matsushita Electric Works Ltd
+140e  Goepel Electronic GmbH
+140f  Salient Systems Corp
+1410  Midas lab Inc
+1411  Ikos Systems Inc
+# formerly IC Ensemble Inc.
+1412  VIA Technologies Inc.
+	1712  ICE1712 [Envy24] PCI Multi-Channel I/O Controller
+		1412 1712  Hoontech ST Audio DSP 24
+		1412 d630  M-Audio Delta 1010
+		1412 d631  M-Audio Delta DiO
+		1412 d632  M-Audio Delta 66
+		1412 d633  M-Audio Delta 44
+		1412 d634  M-Audio Delta Audiophile
+		1412 d635  M-Audio Delta TDIF
+		1412 d637  M-Audio Delta RBUS
+		1412 d638  M-Audio Delta 410
+		1412 d63b  M-Audio Delta 1010LT
+		1412 d63c  Digigram VX442
+		1416 1712  Hoontech ST Audio DSP 24 Media 7.1
+		153b 1115  EWS88 MT
+		153b 1125  EWS88 MT (Master)
+		153b 112b  EWS88 D
+		153b 112c  EWS88 D (Master)
+		153b 1130  EWX 24/96
+		153b 1138  DMX 6fire 24/96
+		153b 1151  PHASE88
+		16ce 1040  Edirol DA-2496
+	1724  VT1720/24 [Envy24PT/HT] PCI Multi-Channel Audio Controller
+		1412 1724  AMP Ltd AUDIO2000
+		1412 3630  M-Audio Revolution 7.1
+		153b 1145  Aureon 7.1 Space
+		153b 1147  Aureon 5.1 Sky
+		153b 1153  Aureon 7.1 Universe
+		270f f641  ZNF3-150
+		270f f645  ZNF3-250
+1413  Addonics
+1414  Microsoft Corporation
+1415  Oxford Semiconductor Ltd
+	8403  VScom 011H-EP1 1 port parallel adaptor
+	9501  OX16PCI954 (Quad 16950 UART) function 0
+		131f 2050  CyberPro (4-port)
+# Model IO1085, Part No: JJ-P46012
+		131f 2051  CyberSerial 4S Plus
+		15ed 2000  MCCR Serial p0-3 of 8
+		15ed 2001  MCCR Serial p0-3 of 16
+	950a  EXSYS EX-41092 Dual 16950 Serial adapter
+	950b  OXCB950 Cardbus 16950 UART
+	9510  OX16PCI954 (Quad 16950 UART) function 1 (Disabled)
+	9511  OX16PCI954 (Quad 16950 UART) function 1
+		15ed 2000  MCCR Serial p4-7 of 8
+		15ed 2001  MCCR Serial p4-15 of 16
+	9521  OX16PCI952 (Dual 16950 UART)
+1416  Multiwave Innovation pte Ltd
+1417  Convergenet Technologies Inc
+1418  Kyushu electronics systems Inc
+1419  Excel Switching Corp
+141a  Apache Micro Peripherals Inc
+141b  Zoom Telephonics Inc
+141d  Digitan Systems Inc
+141e  Fanuc Ltd
+141f  Visiontech Ltd
+1420  Psion Dacom plc
+	8002  Gold Card NetGlobal 56k+10/100Mb CardBus (Ethernet part)
+	8003  Gold Card NetGlobal 56k+10/100Mb CardBus (Modem part)
+1421  Ads Technologies Inc
+1422  Ygrec Systems Co Ltd
+1423  Custom Technology Corp.
+1424  Videoserver Connections
+1425  Chelsio Communications Inc
+1426  Storage Technology Corp.
+1427  Better On-Line Solutions
+1428  Edec Co Ltd
+1429  Unex Technology Corp.
+142a  Kingmax Technology Inc
+142b  Radiolan
+142c  Minton Optic Industry Co Ltd
+142d  Pix stream Inc
+142e  Vitec Multimedia
+	4020  VM2-2 [Video Maker 2] MPEG1/2 Encoder
+142f  Radicom Research Inc
+1430  ITT Aerospace/Communications Division
+1431  Gilat Satellite Networks
+1432  Edimax Computer Co.
+	9130  RTL81xx Fast Ethernet
+1433  Eltec Elektronik GmbH
+1435  Real Time Devices US Inc.
+1436  CIS Technology Inc
+1437  Nissin Inc Co
+1438  Atmel-dream
+1439  Outsource Engineering & Mfg. Inc
+143a  Stargate Solutions Inc
+143b  Canon Research Center, America
+143c  Amlogic Inc
+143d  Tamarack Microelectronics Inc
+143e  Jones Futurex Inc
+143f  Lightwell Co Ltd - Zax Division
+1440  ALGOL Corp.
+1441  AGIE Ltd
+1442  Phoenix Contact GmbH & Co.
+1443  Unibrain S.A.
+1444  TRW
+1445  Logical DO Ltd
+1446  Graphin Co Ltd
+1447  AIM GmBH
+1448  Alesis Studio Electronics
+1449  TUT Systems Inc
+144a  Adlink Technology
+	7296  PCI-7296
+	7432  PCI-7432
+	7433  PCI-7433
+	7434  PCI-7434
+	7841  PCI-7841
+	8133  PCI-8133
+	8164  PCI-8164
+	8554  PCI-8554
+	9111  PCI-9111
+	9113  PCI-9113
+	9114  PCI-9114
+144b  Loronix Information Systems Inc
+144c  Catalina Research Inc
+144d  Samsung Electronics Co Ltd
+144e  OLITEC
+144f  Askey Computer Corp.
+1450  Octave Communications Ind.
+1451  SP3D Chip Design GmBH
+1453  MYCOM Inc
+1454  Altiga Networks
+1455  Logic Plus Plus Inc
+1456  Advanced Hardware Architectures
+1457  Nuera Communications Inc
+1458  Giga-byte Technology
+	0c11  K8NS Pro Mainboard
+1459  DOOIN Electronics
+145a  Escalate Networks Inc
+145b  PRAIM SRL
+145c  Cryptek
+145d  Gallant Computer Inc
+145e  Aashima Technology B.V.
+145f  Baldor Electric Company
+	0001  NextMove PCI
+1460  DYNARC INC
+1461  Avermedia Technologies Inc
+1462  Micro-Star International Co., Ltd.
+# MSI CB54G Wireless PC Card that seems to use the Broadcom 4306 Chipset
+	6819  Broadcom Corporation BCM4306 802.11b/g Wireless LAN Controller [MSI CB54G]
+	6825  PCI Card wireless 11g [PC54G]
+	8725  NVIDIA NV25 [GeForce4 Ti 4600] VGA Adapter
+# MSI G4Ti4800, 128MB DDR SDRAM, TV-Out, DVI-I
+	9000  NVIDIA NV28 [GeForce4 Ti 4800] VGA Adapter
+	9110  GeFORCE FX5200
+	9119  NVIDIA NV31 [GeForce FX 5600XT] VGA Adapter
+	9591  nVidia Corporation NV36 [GeForce FX 5700LE]
+1463  Fast Corporation
+1464  Interactive Circuits & Systems Ltd
+1465  GN NETTEST Telecom DIV.
+1466  Designpro Inc.
+1467  DIGICOM SPA
+1468  AMBIT Microsystem Corp.
+1469  Cleveland Motion Controls
+146a  IFR
+146b  Parascan Technologies Ltd
+146c  Ruby Tech Corp.
+	1430  FE-1430TX Fast Ethernet PCI Adapter
+146d  Tachyon, INC.
+146e  Williams Electronics Games, Inc.
+146f  Multi Dimensional Consulting Inc
+1470  Bay Networks
+1471  Integrated Telecom Express Inc
+1472  DAIKIN Industries, Ltd
+1473  ZAPEX Technologies Inc
+1474  Doug Carson & Associates
+1475  PICAZO Communications
+1476  MORTARA Instrument Inc
+1477  Net Insight
+1478  DIATREND Corporation
+1479  TORAY Industries Inc
+147a  FORMOSA Industrial Computing
+147b  ABIT Computer Corp.
+147c  AWARE, Inc.
+147d  Interworks Computer Products
+147e  Matsushita Graphic Communication Systems, Inc.
+147f  NIHON UNISYS, Ltd.
+1480  SCII Telecom
+1481  BIOPAC Systems Inc
+1482  ISYTEC - Integrierte Systemtechnik GmBH
+1483  LABWAY Corporation
+1484  Logic Corporation
+1485  ERMA - Electronic GmBH
+1486  L3 Communications Telemetry & Instrumentation
+1487  MARQUETTE Medical Systems
+1488  KONTRON Electronik GmBH
+1489  KYE Systems Corporation
+148a  OPTO
+148b  INNOMEDIALOGIC Inc.
+148c  C.P. Technology Co. Ltd
+148d  DIGICOM Systems, Inc.
+	1003  HCF 56k Data/Fax Modem
+148e  OSI Plus Corporation
+148f  Plant Equipment, Inc.
+1490  Stone Microsystems PTY Ltd.
+1491  ZEAL Corporation
+1492  Time Logic Corporation
+1493  MAKER Communications
+1494  WINTOP Technology, Inc.
+1495  TOKAI Communications Industry Co. Ltd
+1496  JOYTECH Computer Co., Ltd.
+1497  SMA Regelsysteme GmBH
+1498  TEWS Datentechnik GmBH
+	30c8  TPCI200
+1499  EMTEC CO., Ltd
+149a  ANDOR Technology Ltd
+149b  SEIKO Instruments Inc
+149c  OVISLINK Corp.
+149d  NEWTEK Inc
+	0001  Video Toaster for PC
+149e  Mapletree Networks Inc.
+149f  LECTRON Co Ltd
+14a0  SOFTING GmBH
+14a1  Systembase Co Ltd
+14a2  Millennium Engineering Inc
+14a3  Maverick Networks
+14a4  GVC/BCM Advanced Research
+14a5  XIONICS Document Technologies Inc
+14a6  INOVA Computers GmBH & Co KG
+14a7  MYTHOS Systems Inc
+14a8  FEATRON Technologies Corporation
+14a9  HIVERTEC Inc
+14aa  Advanced MOS Technology Inc
+14ab  Mentor Graphics Corp.
+14ac  Novaweb Technologies Inc
+14ad  Time Space Radio AB
+14ae  CTI, Inc
+14af  Guillemot Corporation
+	7102  3D Prophet II MX
+14b0  BST Communication Technology Ltd
+14b1  Nextcom K.K.
+14b2  ENNOVATE Networks Inc
+14b3  XPEED Inc
+	0000  DSL NIC
+14b4  PHILIPS Business Electronics B.V.
+14b5  Creamware GmBH
+	0200  Scope
+	0300  Pulsar
+	0400  PulsarSRB
+	0600  Pulsar2
+	0800  DSP-Board
+	0900  DSP-Board
+	0a00  DSP-Board
+	0b00  DSP-Board
+14b6  Quantum Data Corp.
+14b7  PROXIM Inc
+	0001  Symphony 4110
+14b8  Techsoft Technology Co Ltd
+14b9  AIRONET Wireless Communications
+	0001  PC4800
+	0340  PC4800
+	0350  PC4800
+	4500  PC4500
+	4800  Cisco Aironet 340 802.11b Wireless LAN Adapter/Aironet PC4800
+	a504  Cisco Aironet Wireless 802.11b
+	a505  Cisco Aironet CB20a 802.11a Wireless LAN Adapter
+	a506  Cisco Aironet Mini PCI b/g
+14ba  INTERNIX Inc.
+14bb  SEMTECH Corporation
+14bc  Globespan Semiconductor Inc.
+14bd  CARDIO Control N.V.
+14be  L3 Communications
+14bf  SPIDER Communications Inc.
+14c0  COMPAL Electronics Inc
+14c1  MYRICOM Inc.
+	8043  Myrinet 2000 Scalable Cluster Interconnect
+14c2  DTK Computer
+14c3  MEDIATEK Corp.
+14c4  IWASAKI Information Systems Co Ltd
+14c5  Automation Products AB
+14c6  Data Race Inc
+14c7  Modular Technology Holdings Ltd
+14c8  Turbocomm Tech. Inc.
+14c9  ODIN Telesystems Inc
+14ca  PE Logic Corp.
+14cb  Billionton Systems Inc
+14cc  NAKAYO Telecommunications Inc
+14cd  Universal Scientific Ind.
+14ce  Whistle Communications
+14cf  TEK Microsystems Inc.
+14d0  Ericsson Axe R & D
+14d1  Computer Hi-Tech Co Ltd
+14d2  Titan Electronics Inc
+	8001  VScom 010L 1 port parallel adaptor
+	8002  VScom 020L 2 port parallel adaptor
+	8010  VScom 100L 1 port serial adaptor
+	8011  VScom 110L 1 port serial and 1 port parallel adaptor
+	8020  VScom 200L 1 port serial adaptor
+	8021  VScom 210L 2 port serial and 1 port parallel adaptor
+	8040  VScom 400L 4 port serial adaptor
+	8080  VScom 800L 8 port serial adaptor
+	a000  VScom 010H 1 port parallel adaptor
+	a001  VScom 100H 1 port serial adaptor
+	a003  VScom 400H 4 port serial adaptor
+	a004  VScom 400HF1 4 port serial adaptor
+	a005  VScom 200H 2 port serial adaptor
+	e001  VScom 010HV2 1 port parallel adaptor
+	e010  VScom 100HV2 1 port serial adaptor
+	e020  VScom 200HV2 2 port serial adaptor
+14d3  CIRTECH (UK) Ltd
+14d4  Panacom Technology Corp
+14d5  Nitsuko Corporation
+14d6  Accusys Inc
+14d7  Hirakawa Hewtech Corp
+14d8  HOPF Elektronik GmBH
+# Formerly SiPackets, Inc., formerly API NetWorks, Inc., formerly Alpha Processor, Inc.
+14d9  Alliance Semiconductor Corporation
+	0010  AP1011/SP1011 HyperTransport-PCI Bridge [Sturgeon]
+	9000  AS90L10204/10208 HyperTransport to PCI-X Bridge
+14da  National Aerospace Laboratories
+14db  AFAVLAB Technology Inc
+	2120  TK9902
+14dc  Amplicon Liveline Ltd
+	0000  PCI230
+	0001  PCI242
+	0002  PCI244
+	0003  PCI247
+	0004  PCI248
+	0005  PCI249
+	0006  PCI260
+	0007  PCI224
+	0008  PCI234
+	0009  PCI236
+	000a  PCI272
+	000b  PCI215
+14dd  Boulder Design Labs Inc
+14de  Applied Integration Corporation
+14df  ASIC Communications Corp
+14e1  INVERTEX
+14e2  INFOLIBRIA
+14e3  AMTELCO
+14e4  Broadcom Corporation
+	0800  Sentry5 Chipcommon I/O Controller
+	0804  Sentry5 PCI Bridge
+	0805  Sentry5 MIPS32 CPU
+	0806  Sentry5 Ethernet Controller
+	080b  Sentry5 Crypto Accelerator
+	080f  Sentry5 DDR/SDR RAM Controller
+	0811  Sentry5 External Interface Core
+	0816  BCM3302 Sentry5 MIPS32 CPU
+	1644  NetXtreme BCM5700 Gigabit Ethernet
+		1014 0277  Broadcom Vigil B5700 1000Base-T
+		1028 00d1  Broadcom BCM5700
+		1028 0106  Broadcom BCM5700
+		1028 0109  Broadcom BCM5700 1000Base-T
+		1028 010a  Broadcom BCM5700 1000BaseTX
+		10b7 1000  3C996-T 1000Base-T
+		10b7 1001  3C996B-T 1000Base-T
+		10b7 1002  3C996C-T 1000Base-T
+		10b7 1003  3C997-T 1000Base-T Dual Port
+		10b7 1004  3C996-SX 1000Base-SX
+		10b7 1005  3C997-SX 1000Base-SX Dual Port
+		10b7 1008  3C942 Gigabit LOM (31X31)
+		14e4 0002  NetXtreme 1000Base-SX
+		14e4 0003  NetXtreme 1000Base-SX
+		14e4 0004  NetXtreme 1000Base-T
+		14e4 1028  NetXtreme 1000BaseTX
+		14e4 1644  BCM5700 1000Base-T
+	1645  NetXtreme BCM5701 Gigabit Ethernet
+		0e11 007c  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
+		0e11 007d  NC6770 Gigabit Server Adapter (PCI-X, 1000-SX)
+		0e11 0085  NC7780 Gigabit Server Adapter (embedded, WOL)
+		0e11 0099  NC7780 Gigabit Server Adapter (embedded, WOL)
+		0e11 009a  NC7770 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
+		0e11 00c1  NC6770 Gigabit Server Adapter (PCI-X, 1000-SX)
+		1028 0121  Broadcom BCM5701 1000Base-T
+		103c 128a  HP 1000Base-T (PCI) [A7061A]
+		103c 128b  HP 1000Base-SX (PCI) [A7073A]
+		103c 12a4  HP Core Lan 1000Base-T
+		103c 12c1  HP IOX Core Lan 1000Base-T [A7109AX]
+		10a9 8010  SGI IO9 Gigabit Ethernet (Copper)
+		10a9 8011  SGI Gigabit Ethernet (Copper)
+		10a9 8012  SGI Gigabit Ethernet (Fiber)
+		10b7 1004  3C996-SX 1000Base-SX
+		10b7 1006  3C996B-T 1000Base-T
+		10b7 1007  3C1000-T 1000Base-T
+		10b7 1008  3C940-BR01 1000Base-T
+		14e4 0001  BCM5701 1000Base-T
+		14e4 0005  BCM5701 1000Base-T
+		14e4 0006  BCM5701 1000Base-T
+		14e4 0007  BCM5701 1000Base-SX
+		14e4 0008  BCM5701 1000Base-T
+		14e4 8008  BCM5701 1000Base-T
+	1646  NetXtreme BCM5702 Gigabit Ethernet
+		0e11 00bb  NC7760 1000BaseTX
+		1028 0126  Broadcom BCM5702 1000BaseTX
+		14e4 8009  BCM5702 1000BaseTX
+	1647  NetXtreme BCM5703 Gigabit Ethernet
+		0e11 0099  NC7780 1000BaseTX
+		0e11 009a  NC7770 1000BaseTX
+		10a9 8010  SGI IO9 Gigabit Ethernet (Copper)
+		14e4 0009  BCM5703 1000BaseTX
+		14e4 000a  BCM5703 1000BaseSX
+		14e4 000b  BCM5703 1000BaseTX
+		14e4 8009  BCM5703 1000BaseTX
+		14e4 800a  BCM5703 1000BaseTX
+	1648  NetXtreme BCM5704 Gigabit Ethernet
+		0e11 00cf  NC7772 Gigabit Server Adapter (PCI-X, 10,100,1000-T)
+		0e11 00d0  NC7782 Gigabit Server Adapter (PCI-X, 10,100,1000-T)
+		0e11 00d1  NC7783 Gigabit Server Adapter (PCI-X, 10,100,1000-T)
+		10b7 2000  3C998-T Dual Port 10/100/1000 PCI-X
+		10b7 3000  3C999-T Quad Port 10/100/1000 PCI-X
+		1166 1648  NetXtreme CIOB-E 1000Base-T
+	164a  NetXtreme II BCM5706 Gigabit Ethernet
+	164d  NetXtreme BCM5702FE Gigabit Ethernet
+	1653  NetXtreme BCM5705 Gigabit Ethernet
+		0e11 00e3  NC7761 Gigabit Server Adapter
+	1654  NetXtreme BCM5705_2 Gigabit Ethernet
+		0e11 00e3  NC7761 Gigabit Server Adapter
+		103c 3100  NC1020 HP ProLiant Gigabit Server Adapter 32 PCI
+	1659  NetXtreme BCM5721 Gigabit Ethernet PCI Express
+	165d  NetXtreme BCM5705M Gigabit Ethernet
+	165e  NetXtreme BCM5705M_2 Gigabit Ethernet
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+	166e  570x 10/100 Integrated Controller
+	1677  NetXtreme BCM5751 Gigabit Ethernet PCI Express
+		1028 0179  Optiplex GX280
+	167d  NetXtreme BCM5751M Gigabit Ethernet PCI Express
+	167e  NetXtreme BCM5751F Fast Ethernet PCI Express
+	1696  NetXtreme BCM5782 Gigabit Ethernet
+		103c 12bc  HP d530 CMT (DG746A)
+		14e4 000d  NetXtreme BCM5782 1000Base-T
+	169c  NetXtreme BCM5788 Gigabit Ethernet
+	169d  NetLink BCM5789 Gigabit Ethernet PCI Express
+	16a6  NetXtreme BCM5702X Gigabit Ethernet
+		0e11 00bb  NC7760 Gigabit Server Adapter (PCI-X, 10/100/1000-T)
+		1028 0126  BCM5702 1000Base-T
+		14e4 000c  BCM5702 1000Base-T
+		14e4 8009  BCM5702 1000Base-T
+	16a7  NetXtreme BCM5703X Gigabit Ethernet
+		0e11 00ca  NC7771 Gigabit Server Adapter (PCI-X, 10,100,1000-T)
+		0e11 00cb  NC7781 Gigabit Server Adapter (PCI-X, 10,100,1000-T)
+		14e4 0009  NetXtreme BCM5703 1000Base-T
+		14e4 000a  NetXtreme BCM5703 1000Base-SX
+		14e4 000b  NetXtreme BCM5703 1000Base-T
+		14e4 800a  NetXtreme BCM5703 1000Base-T
+	16a8  NetXtreme BCM5704S Gigabit Ethernet
+		10b7 2001  3C998-SX Dual Port 1000-SX PCI-X
+	16aa  NetXtreme II BCM5706S Gigabit Ethernet
+	16c6  NetXtreme BCM5702A3 Gigabit Ethernet
+		10b7 1100  3C1000B-T 10/100/1000 PCI
+		14e4 000c  BCM5702 1000Base-T
+		14e4 8009  BCM5702 1000Base-T
+	16c7  NetXtreme BCM5703 Gigabit Ethernet
+		0e11 00ca  NC7771 Gigabit Server Adapter (PCI-X, 10,100,1000-T)
+		0e11 00cb  NC7781 Gigabit Server Adapter (PCI-X, 10,100,1000-T)
+		103c 12c3  HP Combo FC/GigE-SX [A9782A]
+		103c 12ca  HP Combo FC/GigE-T [A9784A]
+		14e4 0009  NetXtreme BCM5703 1000Base-T
+		14e4 000a  NetXtreme BCM5703 1000Base-SX
+	16dd  NetLink BCM5781 Gigabit Ethernet PCI Express
+	16f7  NetXtreme BCM5753 Gigabit Ethernet PCI Express
+	16fd  NetXtreme BCM5753M Gigabit Ethernet PCI Express
+	16fe  NetXtreme BCM5753F Fast Ethernet PCI Express
+	170c  BCM4401-B0 100Base-TX
+	170d  NetXtreme BCM5901 100Base-TX
+		1014 0545  ThinkPad R40e (2684-HVG) builtin ethernet controller
+	170e  NetXtreme BCM5901 100Base-TX
+	3352  BCM3352
+	3360  BCM3360
+	4210  BCM4210 iLine10 HomePNA 2.0
+	4211  BCM4211 iLine10 HomePNA 2.0 + V.90 56k modem
+	4212  BCM4212 v.90 56k modem
+	4301  BCM4303 802.11b Wireless LAN Controller
+		1028 0407  TrueMobile 1180 Onboard WLAN
+		1043 0120  WL-103b Wireless LAN PC Card
+	4305  BCM4307 V.90 56k Modem
+	4306  BCM4307 Ethernet Controller
+	4307  BCM4307 802.11b Wireless LAN Controller
+	4310  BCM4310 Chipcommon I/OController
+	4312  BCM4310 UART
+	4313  BCM4310 Ethernet Controller
+	4315  BCM4310 USB Controller
+	4320  BCM4306 802.11b/g Wireless LAN Controller
+		1028 0001  TrueMobile 1300 WLAN Mini-PCI Card
+		1028 0003  Wireless 1350 WLAN Mini-PCI Card
+		1043 100f  WL-100G
+		14e4 4320  Linksys WMP54G PCI
+		1737 4320  WPC54G
+		1799 7010  Belkin F5D7010 54g Wireless Network card
+	4321  BCM4306 802.11a Wireless LAN Controller
+	4322  BCM4306 UART
+	4324  BCM4309 802.11a/b/g
+		1028 0001  Truemobile 1400
+		1028 0003  Truemobile 1450 MiniPCI
+	4325  BCM43xG 802.11b/g
+		1414 0003  Wireless Notebook Adapter MN-720
+		1414 0004  Wireless PCI Adapter MN-730
+# probably this is a correct ID...
+	4326  BCM4307 Chipcommon I/O Controller?
+	4401  BCM4401 100Base-T
+		1043 80a8  A7V8X motherboard
+	4402  BCM4402 Integrated 10/100BaseT
+	4403  BCM4402 V.90 56k Modem
+	4410  BCM4413 iLine32 HomePNA 2.0
+	4411  BCM4413 V.90 56k modem
+	4412  BCM4412 10/100BaseT
+	4430  BCM44xx CardBus iLine32 HomePNA 2.0
+	4432  BCM4432 CardBus 10/100BaseT
+	4610  BCM4610 Sentry5 PCI to SB Bridge
+	4611  BCM4610 Sentry5 iLine32 HomePNA 1.0
+	4612  BCM4610 Sentry5 V.90 56k Modem
+	4613  BCM4610 Sentry5 Ethernet Controller
+	4614  BCM4610 Sentry5 External Interface
+	4615  BCM4610 Sentry5 USB Controller
+	4704  BCM4704 PCI to SB Bridge
+	4705  BCM4704 Sentry5 802.11b Wireless LAN Controller
+	4706  BCM4704 Sentry5 Ethernet Controller
+	4707  BCM4704 Sentry5 USB Controller
+	4708  BCM4704 Crypto Accelerator
+	4710  BCM4710 Sentry5 PCI to SB Bridge
+	4711  BCM47xx Sentry5 iLine32 HomePNA 2.0
+	4712  BCM47xx V.92 56k modem
+	4713  Sentry5 Ethernet Controller
+	4714  BCM47xx Sentry5 External Interface
+	4715  Sentry5 USB Controller
+	4716  BCM47xx Sentry5 USB Host Controller
+	4717  BCM47xx Sentry5 USB Device Controller
+	4718  Sentry5 Crypto Accelerator
+	4720  BCM4712 MIPS CPU
+	5365  BCM5365P Sentry5 Host Bridge
+	5600  BCM5600 StrataSwitch 24+2 Ethernet Switch Controller
+	5605  BCM5605 StrataSwitch 24+2 Ethernet Switch Controller
+	5615  BCM5615 StrataSwitch 24+2 Ethernet Switch Controller
+	5625  BCM5625 StrataSwitch 24+2 Ethernet Switch Controller
+	5645  BCM5645 StrataSwitch 24+2 Ethernet Switch Controller
+	5670  BCM5670 8-Port 10GE Ethernet Switch Fabric
+	5680  BCM5680 G-Switch 8 Port Gigabit Ethernet Switch Controller
+	5690  BCM5690 12-port Multi-Layer Gigabit Ethernet Switch
+	5691  BCM5691 GE/10GE 8+2 Gigabit Ethernet Switch Controller
+	5820  BCM5820 Crypto Accelerator
+	5821  BCM5821 Crypto Accelerator
+	5822  BCM5822 Crypto Accelerator
+	5823  BCM5823 Crypto Accelerator
+	5824  BCM5824 Crypto Accelerator
+	5840  BCM5840 Crypto Accelerator
+	5841  BCM5841 Crypto Accelerator
+	5850  BCM5850 Crypto Accelerator
+14e5  Pixelfusion Ltd
+14e6  SHINING Technology Inc
+14e7  3CX
+14e8  RAYCER Inc
+14e9  GARNETS System CO Ltd
+14ea  Planex Communications, Inc
+	ab06  FNW-3603-TX CardBus Fast Ethernet
+	ab07  RTL81xx RealTek Ethernet
+14eb  SEIKO EPSON Corp
+14ec  ACQIRIS
+14ed  DATAKINETICS Ltd
+14ee  MASPRO KENKOH Corp
+14ef  CARRY Computer ENG. CO Ltd
+14f0  CANON RESEACH CENTRE FRANCE
+14f1  Conexant
+	1002  HCF 56k Modem
+	1003  HCF 56k Modem
+	1004  HCF 56k Modem
+	1005  HCF 56k Modem
+	1006  HCF 56k Modem
+	1022  HCF 56k Modem
+	1023  HCF 56k Modem
+	1024  HCF 56k Modem
+	1025  HCF 56k Modem
+	1026  HCF 56k Modem
+	1032  HCF 56k Modem
+	1033  HCF 56k Data/Fax Modem
+		1033 8077  NEC
+		122d 4027  Dell Zeus - MDP3880-W(B) Data Fax Modem
+		122d 4030  Dell Mercury - MDP3880-U(B) Data Fax Modem
+		122d 4034  Dell Thor - MDP3880-W(U) Data Fax Modem
+		13e0 020d  Dell Copper
+		13e0 020e  Dell Silver
+		13e0 0261  IBM
+		13e0 0290  Compaq Goldwing
+		13e0 02a0  IBM
+		13e0 02b0  IBM
+		13e0 02c0  Compaq Scooter
+		13e0 02d0  IBM
+		144f 1500  IBM P85-DF (1)
+		144f 1501  IBM P85-DF (2)
+		144f 150a  IBM P85-DF (3)
+		144f 150b  IBM P85-DF Low Profile (1)
+		144f 1510  IBM P85-DF Low Profile (2)
+	1034  HCF 56k Data/Fax/Voice Modem
+	1035  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+		10cf 1098  Fujitsu P85-DFSV
+	1036  HCF 56k Data/Fax/Voice/Spkp Modem
+		104d 8067  HCF 56k Modem
+		122d 4029  MDP3880SP-W
+		122d 4031  MDP3880SP-U
+		13e0 0209  Dell Titanium
+		13e0 020a  Dell Graphite
+		13e0 0260  Gateway Red Owl
+		13e0 0270  Gateway White Horse
+	1052  HCF 56k Data/Fax Modem (Worldwide)
+	1053  HCF 56k Data/Fax Modem (Worldwide)
+	1054  HCF 56k Data/Fax/Voice Modem (Worldwide)
+	1055  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (Worldwide)
+	1056  HCF 56k Data/Fax/Voice/Spkp Modem (Worldwide)
+	1057  HCF 56k Data/Fax/Voice/Spkp Modem (Worldwide)
+	1059  HCF 56k Data/Fax/Voice Modem (Worldwide)
+	1063  HCF 56k Data/Fax Modem
+	1064  HCF 56k Data/Fax/Voice Modem
+	1065  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	1066  HCF 56k Data/Fax/Voice/Spkp Modem
+		122d 4033  Dell Athena - MDP3900V-U
+	1433  HCF 56k Data/Fax Modem
+	1434  HCF 56k Data/Fax/Voice Modem
+	1435  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	1436  HCF 56k Data/Fax Modem
+	1453  HCF 56k Data/Fax Modem
+		13e0 0240  IBM
+		13e0 0250  IBM
+		144f 1502  IBM P95-DF (1)
+		144f 1503  IBM P95-DF (2)
+	1454  HCF 56k Data/Fax/Voice Modem
+	1455  HCF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	1456  HCF 56k Data/Fax/Voice/Spkp Modem
+		122d 4035  Dell Europa - MDP3900V-W
+		122d 4302  Dell MP3930V-W(C) MiniPCI
+	1610  ADSL AccessRunner PCI Arbitration Device
+	1611  AccessRunner PCI ADSL Interface Device
+	1620  ADSL AccessRunner V2 PCI Arbitration Device
+	1621  AccessRunner V2 PCI ADSL Interface Device
+	1622  AccessRunner V2 PCI ADSL Yukon WAN Adapter
+	1803  HCF 56k Modem
+		0e11 0023  623-LAN Grizzly
+		0e11 0043  623-LAN Yogi
+	1815  HCF 56k Modem
+		0e11 0022  Grizzly
+		0e11 0042  Yogi
+	2003  HSF 56k Data/Fax Modem
+	2004  HSF 56k Data/Fax/Voice Modem
+	2005  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	2006  HSF 56k Data/Fax/Voice/Spkp Modem
+	2013  HSF 56k Data/Fax Modem
+		0e11 b195  Bear
+		0e11 b196  Seminole 1
+		0e11 b1be  Seminole 2
+		1025 8013  Acer
+		1033 809d  NEC
+		1033 80bc  NEC
+		155d 6793  HP
+		155d 8850  E Machines
+	2014  HSF 56k Data/Fax/Voice Modem
+	2015  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem
+	2016  HSF 56k Data/Fax/Voice/Spkp Modem
+	2043  HSF 56k Data/Fax Modem (WorldW SmartDAA)
+	2044  HSF 56k Data/Fax/Voice Modem (WorldW SmartDAA)
+	2045  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (WorldW SmartDAA)
+	2046  HSF 56k Data/Fax/Voice/Spkp Modem (WorldW SmartDAA)
+	2063  HSF 56k Data/Fax Modem (SmartDAA)
+	2064  HSF 56k Data/Fax/Voice Modem (SmartDAA)
+	2065  HSF 56k Data/Fax/Voice/Spkp (w/Handset) Modem (SmartDAA)
+	2066  HSF 56k Data/Fax/Voice/Spkp Modem (SmartDAA)
+	2093  HSF 56k Modem
+		155d 2f07  Legend
+	2143  HSF 56k Data/Fax/Cell Modem (Mob WorldW SmartDAA)
+	2144  HSF 56k Data/Fax/Voice/Cell Modem (Mob WorldW SmartDAA)
+	2145  HSF 56k Data/Fax/Voice/Spkp (w/HS)/Cell Modem (Mob WorldW SmartDAA)
+	2146  HSF 56k Data/Fax/Voice/Spkp/Cell Modem (Mob WorldW SmartDAA)
+	2163  HSF 56k Data/Fax/Cell Modem (Mob SmartDAA)
+	2164  HSF 56k Data/Fax/Voice/Cell Modem (Mob SmartDAA)
+	2165  HSF 56k Data/Fax/Voice/Spkp (w/HS)/Cell Modem (Mob SmartDAA)
+	2166  HSF 56k Data/Fax/Voice/Spkp/Cell Modem (Mob SmartDAA)
+	2343  HSF 56k Data/Fax CardBus Modem (Mob WorldW SmartDAA)
+	2344  HSF 56k Data/Fax/Voice CardBus Modem (Mob WorldW SmartDAA)
+	2345  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob WorldW SmartDAA)
+	2346  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob WorldW SmartDAA)
+	2363  HSF 56k Data/Fax CardBus Modem (Mob SmartDAA)
+	2364  HSF 56k Data/Fax/Voice CardBus Modem (Mob SmartDAA)
+	2365  HSF 56k Data/Fax/Voice/Spkp (w/HS) CardBus Modem (Mob SmartDAA)
+	2366  HSF 56k Data/Fax/Voice/Spkp CardBus Modem (Mob SmartDAA)
+	2443  HSF 56k Data/Fax Modem (Mob WorldW SmartDAA)
+		104d 8075  Modem
+		104d 8083  Modem
+		104d 8097  Modem
+	2444  HSF 56k Data/Fax/Voice Modem (Mob WorldW SmartDAA)
+	2445  HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob WorldW SmartDAA)
+	2446  HSF 56k Data/Fax/Voice/Spkp Modem (Mob WorldW SmartDAA)
+	2463  HSF 56k Data/Fax Modem (Mob SmartDAA)
+	2464  HSF 56k Data/Fax/Voice Modem (Mob SmartDAA)
+	2465  HSF 56k Data/Fax/Voice/Spkp (w/HS) Modem (Mob SmartDAA)
+	2466  HSF 56k Data/Fax/Voice/Spkp Modem (Mob SmartDAA)
+	2f00  HSF 56k HSFi Modem
+		13e0 8d84  IBM HSFi V.90
+		13e0 8d85  Compaq Stinger
+		14f1 2004  Dynalink 56PMi
+	2f02  HSF 56k HSFi Data/Fax
+	2f11  HSF 56k HSFi Modem
+	8234  RS8234 ATM SAR Controller [ServiceSAR Plus]
+	8800  CX22702 DVB-T 2k/8k
+		17de 08a1  XPert DVB-T PCI BDA DVBT 23880 Video Capture
+	8802  CX23883 Broadcast Decoder
+		17de 08a1  Xpert DVB-T PCI 2388x Transport Stream Capture
+14f2  MOBILITY Electronics
+	0120  EV1000 bridge
+	0121  EV1000 Parallel port
+	0122  EV1000 Serial port
+	0123  EV1000 Keyboard controller
+	0124  EV1000 Mouse controller
+14f3  BroadLogic
+	2030  2030 DVB-S Satellite Reciever
+	2050  2050 DVB-T Terrestrial (Cable) Reciever
+	2060  2060 ATSC Terrestrial (Cable) Reciever
+14f4  TOKYO Electronic Industry CO Ltd
+14f5  SOPAC Ltd
+14f6  COYOTE Technologies LLC
+14f7  WOLF Technology Inc
+14f8  AUDIOCODES Inc
+	2077  TP-240 dual span E1 VoIP PCI card
+14f9  AG COMMUNICATIONS
+14fa  WANDEL & GOCHERMANN
+14fb  TRANSAS MARINE (UK) Ltd
+14fc  Quadrics Ltd
+	0000  QsNet Elan3 Network Adapter
+	0001  QsNetII Elan4 Network Adapter
+14fd  JAPAN Computer Industry Inc
+14fe  ARCHTEK TELECOM Corp
+14ff  TWINHEAD INTERNATIONAL Corp
+1500  DELTA Electronics, Inc
+	1360  RTL81xx RealTek Ethernet
+1501  BANKSOFT CANADA Ltd
+1502  MITSUBISHI ELECTRIC LOGISTICS SUPPORT Co Ltd
+1503  KAWASAKI LSI USA Inc
+1504  KAISER Electronics
+1505  ITA INGENIEURBURO FUR TESTAUFGABEN GmbH
+1506  CHAMELEON Systems Inc
+# Should be HTEC Ltd, but there are no known HTEC chips and 1507 is already used by mistake by Motorola (see vendor ID 1057).
+1507  Motorola ?? / HTEC
+	0001  MPC105 [Eagle]
+	0002  MPC106 [Grackle]
+	0003  MPC8240 [Kahlua]
+	0100  MC145575 [HFC-PCI]
+	0431  KTI829c 100VG
+	4801  Raven
+	4802  Falcon
+	4803  Hawk
+	4806  CPX8216
+1508  HONDA CONNECTORS/MHOTRONICS Inc
+1509  FIRST INTERNATIONAL Computer Inc
+150a  FORVUS RESEARCH Inc
+150b  YAMASHITA Systems Corp
+150c  KYOPAL CO Ltd
+150d  WARPSPPED Inc
+150e  C-PORT Corp
+150f  INTEC GmbH
+1510  BEHAVIOR TECH Computer Corp
+1511  CENTILLIUM Technology Corp
+1512  ROSUN Technologies Inc
+1513  Raychem
+1514  TFL LAN Inc
+1515  Advent design
+1516  MYSON Technology Inc
+	0800  MTD-8xx 100/10M Ethernet PCI Adapter
+	0803  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter
+		1320 10bd  SURECOM EP-320X-S 100/10M Ethernet PCI Adapter
+	0891  MTD-8xx 100/10M Ethernet PCI Adapter
+1517  ECHOTEK Corp
+1518  PEP MODULAR Computers GmbH
+1519  TELEFON AKTIEBOLAGET LM Ericsson
+151a  Globetek
+	1002  PCI-1002
+	1004  PCI-1004
+	1008  PCI-1008
+151b  COMBOX Ltd
+151c  DIGITAL AUDIO LABS Inc
+	0003  Prodif T 2496
+	4000  Prodif 88
+151d  Fujitsu Computer Products Of America
+151e  MATRIX Corp
+151f  TOPIC SEMICONDUCTOR Corp
+	0000  TP560 Data/Fax/Voice 56k modem
+1520  CHAPLET System Inc
+1521  BELL Corp
+1522  MainPine Ltd
+	0100  PCI <-> IOBus Bridge
+		1522 0200  RockForceDUO 2 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0300  RockForceQUATRO 4 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0400  RockForceDUO+ 2 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0500  RockForceQUATRO+ 4 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0600  RockForce+ 2 Port V.90 Data/Fax/Voice Modem
+		1522 0700  RockForce+ 4 Port V.90 Data/Fax/Voice Modem
+		1522 0800  RockForceOCTO+ 8 Port V.92/V.44 Data/Fax/Voice Modem
+		1522 0c00  RockForceDUO+ 2 Port V.92/V.44 Data, V.34 Super-G3 Fax, Voice Modem
+		1522 0d00  RockForceQUATRO+ 4 Port V.92/V.44 Data, V.34 Super-G3 Fax, Voice Modem
+# this is a correction to a recent entry. 1522:0E00 should be 1522:1D00
+		1522 1d00  RockForceOCTO+ 8 Port V.92/V.44 Data, V.34 Super-G3 Fax, Voice Modem
+1523  MUSIC Semiconductors
+1524  ENE Technology Inc
+	0510  CB710 Memory Card Reader Controller
+	0610  PCI Smart Card Reader Controller
+	1211  CB1211 Cardbus Controller
+	1225  CB1225 Cardbus Controller
+	1410  CB1410 Cardbus Controller
+		1025 005a  TravelMate 290
+	1411  CB-710/2/4 Cardbus Controller
+	1412  CB-712/4 Cardbus Controller
+	1420  CB1420 Cardbus Controller
+	1421  CB-720/2/4 Cardbus Controller
+	1422  CB-722/4 Cardbus Controller
+1525  IMPACT Technologies
+1526  ISS, Inc
+1527  SOLECTRON
+1528  ACKSYS
+1529  AMERICAN MICROSystems Inc
+152a  QUICKTURN DESIGN Systems
+152b  FLYTECH Technology CO Ltd
+152c  MACRAIGOR Systems LLC
+152d  QUANTA Computer Inc
+152e  MELEC Inc
+152f  PHILIPS - CRYPTO
+1530  ACQIS Technology Inc
+1531  CHRYON Corp
+1532  ECHELON Corp
+1533  BALTIMORE
+1534  ROAD Corp
+1535  EVERGREEN Technologies Inc
+1537  DATALEX COMMUNCATIONS
+1538  ARALION Inc
+	0303  ARS106S Ultra ATA 133/100/66 Host Controller
+1539  ATELIER INFORMATIQUES et ELECTRONIQUE ETUDES S.A.
+153a  ONO SOKKI
+153b  TERRATEC Electronic GmbH
+	1144  Aureon 5.1
+# Terratec seems to use several IDs for the same card.
+	1147  Aureon 5.1 Sky
+	1158  Philips Semiconductors SAA7134 (rev 01) [Terratec Cinergy 600 TV]
+153c  ANTAL Electronic
+153d  FILANET Corp
+153e  TECHWELL Inc
+153f  MIPS DENMARK
+1540  PROVIDEO MULTIMEDIA Co Ltd
+1541  MACHONE Communications
+1542  VIVID Technology Inc
+1543  SILICON Laboratories
+	3052  Intel 537 [Winmodem]
+	4c22  Si3036 MC'97 DAA
+1544  DCM DATA Systems
+1545  VISIONTEK
+1546  IOI Technology Corp
+1547  MITUTOYO Corp
+1548  JET PROPULSION Laboratory
+1549  INTERCONNECT Systems Solutions
+154a  MAX Technologies Inc
+154b  COMPUTEX Co Ltd
+154c  VISUAL Technology Inc
+154d  PAN INTERNATIONAL Industrial Corp
+154e  SERVOTEST Ltd
+154f  STRATABEAM Technology
+1550  OPEN NETWORK Co Ltd
+1551  SMART Electronic DEVELOPMENT GmBH
+1552  RACAL AIRTECH Ltd
+1553  CHICONY Electronics Co Ltd
+1554  PROLINK Microsystems Corp
+1555  GESYTEC GmBH
+1556  PLD APPLICATIONS
+1557  MEDIASTAR Co Ltd
+1558  CLEVO/KAPOK Computer
+1559  SI LOGIC Ltd
+155a  INNOMEDIA Inc
+155b  PROTAC INTERNATIONAL Corp
+155c  Cemax-Icon Inc
+155d  Mac System Co Ltd
+155e  LP Elektronik GmbH
+155f  Perle Systems Ltd
+1560  Terayon Communications Systems
+1561  Viewgraphics Inc
+1562  Symbol Technologies
+1563  A-Trend Technology Co Ltd
+1564  Yamakatsu Electronics Industry Co Ltd
+1565  Biostar Microtech Int'l Corp
+1566  Ardent Technologies Inc
+1567  Jungsoft
+1568  DDK Electronics Inc
+1569  Palit Microsystems Inc.
+156a  Avtec Systems
+156b  2wire Inc
+156c  Vidac Electronics GmbH
+156d  Alpha-Top Corp
+156e  Alfa Inc
+156f  M-Systems Flash Disk Pioneers Ltd
+1570  Lecroy Corp
+1571  Contemporary Controls
+	a001  CCSI PCI20-485 ARCnet
+	a002  CCSI PCI20-485D ARCnet
+	a003  CCSI PCI20-485X ARCnet
+	a004  CCSI PCI20-CXB ARCnet
+	a005  CCSI PCI20-CXS ARCnet
+	a006  CCSI PCI20-FOG-SMA ARCnet
+	a007  CCSI PCI20-FOG-ST ARCnet
+	a008  CCSI PCI20-TB5 ARCnet
+	a009  CCSI PCI20-5-485 5Mbit ARCnet
+	a00a  CCSI PCI20-5-485D 5Mbit ARCnet
+	a00b  CCSI PCI20-5-485X 5Mbit ARCnet
+	a00c  CCSI PCI20-5-FOG-ST 5Mbit ARCnet
+	a00d  CCSI PCI20-5-FOG-SMA 5Mbit ARCnet
+	a201  CCSI PCI22-485 10Mbit ARCnet
+	a202  CCSI PCI22-485D 10Mbit ARCnet
+	a203  CCSI PCI22-485X 10Mbit ARCnet
+	a204  CCSI PCI22-CHB 10Mbit ARCnet
+	a205  CCSI PCI22-FOG_ST 10Mbit ARCnet
+	a206  CCSI PCI22-THB 10Mbit ARCnet
+1572  Otis Elevator Company
+1573  Lattice - Vantis
+1574  Fairchild Semiconductor
+1575  Voltaire Advanced Data Security Ltd
+1576  Viewcast COM
+1578  HITT
+	5615  VPMK3 [Video Processor Mk III]
+1579  Dual Technology Corp
+157a  Japan Elecronics Ind Inc
+157b  Star Multimedia Corp
+157c  Eurosoft (UK)
+	8001  Fix2000 PCI Y2K Compliance Card
+157d  Gemflex Networks
+157e  Transition Networks
+157f  PX Instruments Technology Ltd
+1580  Primex Aerospace Co
+1581  SEH Computertechnik GmbH
+1582  Cytec Corp
+1583  Inet Technologies Inc
+1584  Uniwill Computer Corp
+1585  Logitron
+1586  Lancast Inc
+1587  Konica Corp
+1588  Solidum Systems Corp
+1589  Atlantek Microsystems Pty Ltd
+158a  Digalog Systems Inc
+158b  Allied Data Technologies
+158c  Hitachi Semiconductor & Devices Sales Co Ltd
+158d  Point Multimedia Systems
+158e  Lara Technology Inc
+158f  Ditect Coop
+1590  3pardata Inc
+1591  ARN
+1592  Syba Tech Ltd
+	0781  Multi-IO Card
+	0782  Parallel Port Card 2xEPP
+	0783  Multi-IO Card
+	0785  Multi-IO Card
+	0786  Multi-IO Card
+	0787  Multi-IO Card
+	0788  Multi-IO Card
+	078a  Multi-IO Card
+1593  Bops Inc
+1594  Netgame Ltd
+1595  Diva Systems Corp
+1596  Folsom Research Inc
+1597  Memec Design Services
+1598  Granite Microsystems
+1599  Delta Electronics Inc
+159a  General Instrument
+159b  Faraday Technology Corp
+159c  Stratus Computer Systems
+159d  Ningbo Harrison Electronics Co Ltd
+159e  A-Max Technology Co Ltd
+159f  Galea Network Security
+15a0  Compumaster SRL
+15a1  Geocast Network Systems
+15a2  Catalyst Enterprises Inc
+	0001  TA700 PCI Bus Analyzer/Exerciser
+15a3  Italtel
+15a4  X-Net OY
+15a5  Toyota Macs Inc
+15a6  Sunlight Ultrasound Technologies Ltd
+15a7  SSE Telecom Inc
+15a8  Shanghai Communications Technologies Center
+15aa  Moreton Bay
+15ab  Bluesteel Networks Inc
+15ac  North Atlantic Instruments
+15ad  VMware Inc
+	0405  [VMware SVGA II] PCI Display Adapter
+	0710  Virtual SVGA
+	0720  VMware High-Speed Virtual NIC [vmxnet]
+15ae  Amersham Pharmacia Biotech
+15b0  Zoltrix International Ltd
+15b1  Source Technology Inc
+15b2  Mosaid Technologies Inc
+15b3  Mellanox Technologies
+	5274  MT21108 InfiniBridge
+	5a44  MT23108 InfiniHost
+	5a45  MT23108 [Infinihost HCA Flash Recovery]
+	5a46  MT23108 PCI Bridge
+	5e8c  MT24204 [InfiniHost III Lx HCA]
+	5e8d  MT24204 [InfiniHost III Lx HCA Flash Recovery]
+	6278  MT25208 InfiniHost III Ex (Tavor compatibility mode)
+	6279  MT25208 [InfiniHost III Ex HCA Flash Recovery]
+	6282  MT25208 InfiniHost III Ex
+15b4  CCI/TRIAD
+15b5  Cimetrics Inc
+15b6  Texas Memory Systems Inc
+15b7  Sandisk Corp
+15b8  ADDI-DATA GmbH
+15b9  Maestro Digital Communications
+15ba  Impacct Technology Corp
+15bb  Portwell Inc
+15bc  Agilent Technologies
+	2922  64 Bit, 133MHz PCI-X Exerciser & Protocol Checker
+	2928  64 Bit, 66MHz PCI Exerciser & Analyzer
+	2929  64 Bit, 133MHz PCI-X Analyzer & Exerciser
+15bd  DFI Inc
+15be  Sola Electronics
+15bf  High Tech Computer Corp (HTC)
+15c0  BVM Ltd
+15c1  Quantel
+15c2  Newer Technology Inc
+15c3  Taiwan Mycomp Co Ltd
+15c4  EVSX Inc
+15c5  Procomp Informatics Ltd
+	8010  1394b - 1394 Firewire 3-Port Host Adapter Card
+15c6  Technical University of Budapest
+15c7  Tateyama System Laboratory Co Ltd
+	0349  Tateyama C-PCI PLC/NC card Rev.01A
+15c8  Penta Media Co Ltd
+15c9  Serome Technology Inc
+15ca  Bitboys OY
+15cb  AG Electronics Ltd
+15cc  Hotrail Inc
+15cd  Dreamtech Co Ltd
+15ce  Genrad Inc
+15cf  Hilscher GmbH
+15d1  Infineon Technologies AG
+15d2  FIC (First International Computer Inc)
+15d3  NDS Technologies Israel Ltd
+15d4  Iwill Corp
+15d5  Tatung Co
+15d6  Entridia Corp
+15d7  Rockwell-Collins Inc
+15d8  Cybernetics Technology Co Ltd
+15d9  Super Micro Computer Inc
+15da  Cyberfirm Inc
+15db  Applied Computing Systems Inc
+15dc  Litronic Inc
+	0001  Argus 300 PCI Cryptography Module
+15dd  Sigmatel Inc
+15de  Malleable Technologies Inc
+15df  Infinilink Corp
+15e0  Cacheflow Inc
+15e1  Voice Technologies Group Inc
+15e2  Quicknet Technologies Inc
+15e3  Networth Technologies Inc
+15e4  VSN Systemen BV
+15e5  Valley technologies Inc
+15e6  Agere Inc
+15e7  Get Engineering Corp
+15e8  National Datacomm Corp
+	0130  Wireless PCI Card
+15e9  Pacific Digital Corp
+	1841  ADMA-100 DiscStaQ ATA Controller
+15ea  Tokyo Denshi Sekei K.K.
+15eb  Drsearch GmbH
+15ec  Beckhoff GmbH
+	3101  FC3101 Profibus DP 1 Channel PCI
+	5102  FC5102
+15ed  Macrolink Inc
+15ee  In Win Development Inc
+15ef  Intelligent Paradigm Inc
+15f0  B-Tree Systems Inc
+15f1  Times N Systems Inc
+15f2  Diagnostic Instruments Inc
+15f3  Digitmedia Corp
+15f4  Valuesoft
+15f5  Power Micro Research
+15f6  Extreme Packet Device Inc
+15f7  Banctec
+15f8  Koga Electronics Co
+15f9  Zenith Electronics Corp
+15fa  J.P. Axzam Corp
+15fb  Zilog Inc
+15fc  Techsan Electronics Co Ltd
+15fd  N-CUBED.NET
+15fe  Kinpo Electronics Inc
+15ff  Fastpoint Technologies Inc
+1600  Northrop Grumman - Canada Ltd
+1601  Tenta Technology
+1602  Prosys-tec Inc
+1603  Nokia Wireless Communications
+1604  Central System Research Co Ltd
+1605  Pairgain Technologies
+1606  Europop AG
+1607  Lava Semiconductor Manufacturing Inc
+1608  Automated Wagering International
+1609  Scimetric Instruments Inc
+1612  Telesynergy Research Inc.
+1619  FarSite Communications Ltd
+	0400  FarSync T2P (2 port X.21/V.35/V.24)
+	0440  FarSync T4P (4 port X.21/V.35/V.24)
+# www.rioworks.com
+161f  Rioworks
+1626  TDK Semiconductor Corp.
+	8410  RTL81xx Fast Ethernet
+1629  Kongsberg Spacetec AS
+	1003  Format synchronizer v3.0
+	2002  Fast Universal Data Output
+# This seems to occur on their 802.11b Wireless card WMP-11
+1637  Linksys
+	3874  Linksys 802.11b WMP11 PCI Wireless card
+1638  Standard Microsystems Corp [SMC]
+	1100  SMC2602W EZConnect / Addtron AWA-100 / Eumitcom PCI WL11000
+163c  Smart Link Ltd.
+	3052  SmartLink SmartPCI562 56K Modem
+	5449  SmartPCI561 Modem
+1657  Brocade Communications Systems, Inc.
+165a  Epix Inc
+	c100  PIXCI(R) CL1 Camera Link Video Capture Board [custom QL5232]
+	d200  PIXCI(R) D2X Digital Video Capture Board [custom QL5232]
+	d300  PIXCI(R) D3X Digital Video Capture Board [custom QL5232]
+165d  Hsing Tech. Enterprise Co., Ltd.
+1661  Worldspace Corp.
+1668  Actiontec Electronics Inc
+	0100  Mini-PCI bridge
+# Formerly SiByte, Inc.
+166d  Broadcom Corporation
+	0001  SiByte BCM1125/1125H/1250 System-on-a-Chip PCI
+	0002  SiByte BCM1125H/1250 System-on-a-Chip HyperTransport
+1677  Bernecker + Rainer
+	104e  5LS172.6 B&R Dual CAN Interface Card
+	12d7  5LS172.61 B&R Dual CAN Interface Card
+167b  ZyDAS Technology Corp.
+	2102  ZyDAS ZD1202
+		187e 3406  ZyAIR B-122 CardBus 11Mbs Wireless LAN Card
+1681  Hercules
+# More specs, more accurate desc.
+	0010  Hercules 3d Prophet II Ultra 64MB [ 350 MHz NV15BR core, 128-bit DDR @ 460 MHz, 1.5v AGP4x  ]
+1682  XFX Pine Group Inc.
+1688  CastleNet Technology Inc.
+	1170  WLAN 802.11b card
+168c  Atheros Communications, Inc.
+	0007  AR5000 802.11a Wireless Adapter
+	0011  AR5210 802.11a NIC
+	0012  AR5211 802.11ab NIC
+	0013  AR5212 802.11abg NIC
+		1113 d301  Philips CPWNA100 Wireless CardBus adapter
+		1186 3202  D-link DWL-G650 B3 Wireless cardbus adapter
+		1186 3203  DWL-G520 Wireless PCI Adapter
+		1186 3a13  DWL-G520 Wireless PCI Adapter rev. B
+		1186 3a94  C54C Wireless 801.11g cardbus
+		1385 4d00  Netgear WG311T Wireless PCI Adapter
+		14b7 0a60  8482-WD ORiNOCO 11a/b/g Wireless PCI Adapter
+		168c 0013  WG511T Wireless CardBus Adapter
+		168c 1025  DWL-G650B2 Wireless CardBus Adapter
+		168c 1027  Netgate NL-3054CB ARIES b/g CardBus Adapter
+		168c 2026  Netgate 5354MP ARIES a(108Mb turbo)/b/g MiniPCI Adapter
+		168c 2041  Netgate 5354MP Plus ARIES2 b/g MiniPCI Adapter
+		168c 2042  Netgate 5354MP Plus ARIES2 a/b/g MiniPCI Adapter
+	1014  AR5212 802.11abg NIC
+169c  Netcell Corporation
+	0044  SyncRAID SR3000/5000 Series SATA RAID Controllers
+16a5  Tekram Technology Co.,Ltd.
+16ab  Global Sun Technology Inc
+	1100  GL24110P
+	1101  PLX9052 PCMCIA-to-PCI Wireless LAN
+	1102  PCMCIA-to-PCI Wireless Network Bridge
+	8501  WL-8305 Wireless LAN PCI Adapter
+16ae  Safenet Inc
+	1141  SafeXcel-1141
+16b4  Aspex Semiconductor Ltd
+16be  Creatix Polymedia GmbH
+16ca  CENATEK Inc
+	0001  Rocket Drive DL
+16cd  Densitron Technologies
+16ce  Roland Corp.
+# www.pikatechnologies.com
+16df  PIKA Technologies Inc.
+16e3  European Space Agency
+	1e0f  LEON2FT Processor
+16ec  U.S. Robotics
+	00ff  USR997900 10/100 Mbps PCI Network Card
+	0116  USR997902 10/100/1000 Mbps PCI Network Card
+	3685  Wireless Access PCI Adapter Model 022415
+16ed  Sycron N. V.
+	1001  UMIO communication card
+16f3  Jetway Information Co., Ltd.
+16f4  Vweb Corp
+	8000  VW2010
+16f6  VideoTele.com, Inc.
+# www.internetmachines.com
+1702  Internet Machines Corporation (IMC)
+1705  Digital First, Inc.
+170b  NetOctave
+	0100  NSP2000-SSL crypto accelerator
+170c  YottaYotta Inc.
+# Seems to be a 2nd ID for Vitesse Semiconductor
+1725  Vitesse Semiconductor
+	7174  VSC7174 PCI/PCI-X Serial ATA Host Bus Controller
+172a  Accelerated Encryption
+1734  Fujitsu Siemens Computer GmbH
+1737  Linksys
+	0013  WMP54G Wireless Pci Card
+	0015  WMP54GS Wireless Pci Card
+	1032  Gigabit Network Adapter
+		1737 0015  EG1032 v2 Instant Gigabit Network Adapter
+	1064  Gigabit Network Adapter
+		1737 0016  EG1064 v2 Instant Gigabit Network Adapter
+	ab08  21x4x DEC-Tulip compatible 10/100 Ethernet
+	ab09  21x4x DEC-Tulip compatible 10/100 Ethernet
+173b  Altima (nee Broadcom)
+	03e8  AC1000 Gigabit Ethernet
+	03e9  AC1001 Gigabit Ethernet
+	03ea  AC9100 Gigabit Ethernet
+		173b 0001  AC1002
+	03eb  AC1003 Gigabit Ethernet
+1743  Peppercon AG
+	8139  ROL/F-100 Fast Ethernet Adapter with ROL
+1749  RLX Technologies
+174b  PC Partner Limited
+174d  WellX Telecom SA
+175c  AudioScience Inc
+175e  Sanera Systems, Inc.
+1787  Hightech Information System Ltd.
+# also used by Struck Innovative Systeme for joint developments
+1796  Research Centre Juelich
+	0001  SIS1100 [Gigabit link]
+	0002  HOTlink
+	0003  Counter Timer
+	0004  CAMAC Controller
+	0005  PROFIBUS
+	0006  AMCC HOTlink
+1797  JumpTec h, GMBH
+1799  Belkin
+	6001  Wireless PCI Card - F5D6001
+	6020  Wireless PCMCIA Card - F5D6020
+	6060  Wireless PDA Card - F5D6060
+	7000  Wireless PCI Card - F5D7000
+17a0  Genesys Logic, Inc
+	8033  GL880S USB 1.1 controller
+	8034  GL880S USB 2.0 controller
+17af  Hightech Information System Ltd.
+17b3  Hawking Technologies
+	ab08  PN672TX 10/100 Ethernet
+17b4  Indra Networks, Inc.
+	0011  WebEnhance 100 GZIP Compression Card
+17c0  Wistron Corp.
+17c2  Newisys, Inc.
+17cc  NetChip Technology, Inc
+	2280  USB 2.0
+17d3  Areca Technology Corp.
+	1110  ARC-1110 4-Port PCI-X to SATA RAID Controller
+	1120  ARC-1120 8-Port PCI-X to SATA RAID Controller
+	1130  ARC-1130 12-Port PCI-X to SATA RAID Controller
+	1160  ARC-1160 16-Port PCI-X to SATA RAID Controller
+	1210  ARC-1210 4-Port PCI-Express to SATA RAID Controller
+	1220  ARC-1220 8-Port PCI-Express to SATA RAID Controller
+	1230  ARC-1230 12-Port PCI-Express to SATA RAID Controller
+	1260  ARC-1260 16-Port PCI-Express to SATA RAID Controller
+# S2io ships 10Gb PCI-X Ethernet adapters www.s2io.com
+17d5  S2io Inc.
+	5831  Xframe 10 Gigabit Ethernet PCI-X
+		103c 12d5  HP PCI-X 133MHz 10GbE SR Fiber [AB287A]
+17de  KWorld Computer Co. Ltd.
+# http://www.connect3d.com
+17ee  Connect Components Ltd
+17fe  Linksys, A Division of Cisco Systems
+	2120  WMP11v4 802.11b PCI card
+	2220  [AirConn] INPROCOMM IPN 2220 Wireless LAN Adapter (rev 01)
+1813  Ambient Technologies Inc
+	4000  HaM controllerless modem
+		16be 0001  V9x HAM Data Fax Modem
+	4100  HaM plus Data Fax Modem
+		16be 0002  V9x HAM 1394
+1814  RaLink
+	0101  Wireless PCI Adpator RT2400 / RT2460
+		3306 1113  Quidway WL100M
+	0201  Ralink RT2500 802.11 Cardbus Reference Card
+		1371 001e  CWC-854 Wireless-G CardBus Adapter
+		1371 001f  CWM-854 Wireless-G Mini PCI Adapter
+		1371 0020  CWP-854 Wireless-G PCI Adapter
+		1458 e381  GN-WMKG 802.11b/g Wireless CardBus Adapter
+1820  InfiniCon Systems Inc.
+1822  Twinhan Technology Co. Ltd
+182d  SiteCom Europe BV
+# HFC-based ISDN card
+	3069  ISDN PCI DC-105V2
+	9790  WL-121 Wireless Network Adapter 100g+ [Ver.3]
+1830  Credence Systems Corporation
+183b  MikroM GmbH
+	08a7  MVC100 DVI
+	08a8  MVC101 SDI
+	08a9  MVC102 DVI+Audio
+1849  ASRock Incorporation
+1851  Microtune, Inc.
+1852  Anritsu Corp.
+185f  Wistron NeWeb Corp.
+1867  Topspin Communications
+	5a44  MT23108 PCI-X HCA
+	5a45  MT23108 PCI-X HCA flash recovery
+	5a46  MT23108 PCI-X HCA bridge
+	6278  MT25208 InfiniHost III Ex (Tavor compatibility mode)
+	6282  MT25208 InfiniHost III Ex
+187e  ZyXEL Communication Corporation
+1888  Varisys Ltd
+	0301  VMFX1 FPGA PMC module
+	0601  VSM2 dual PMC carrier
+	0710  VS14x series PowerPC PCI board
+	0720  VS24x series PowerPC PCI board
+# found e.g. on KNC DVB-S card
+1894  KNC One
+1896  B&B Electronics Manufacturing Company, Inc.
+18a1  Astute Networks Inc.
+18ac  DViCO Corporation
+	d810  FusionHDTV 3 Gold
+18b8  Ammasso
+	b001  AMSO 1100 iWARP/RDMA Gigabit Ethernet Coprocessor
+18bc  Info-Tek Corp.
+# assigned to Octigabay System, which has been acquired by Cray
+18c8  Cray Inc
+18c9  ARVOO Engineering BV
+18ca  XGI - Xabre Graphics Inc
+	0040  Volari V8
+18e6  MPL AG
+	0001  OSCI [Octal Serial Communication Interface]
+18f7  Commtech, Inc.
+	0001  Fastcom ESCC-PCI-335
+	0002  Fastcom 422/4-PCI-335
+	0004  Fastcom 422/2-PCI-335
+	0005  Fastcom IGESCC-PCI-ISO/1
+	000a  Fastcom 232/4-PCI-335
+18fb  Resilience Corporation
+1924  Level 5 Networks Inc.
+1966  Orad Hi-Tec Systems
+	1975  DVG64 family
+1993  Innominate Security Technologies AG
+# http://www.progeny.net
+19ae  Progeny Systems Corporation
+1a08  Sierra semiconductor
+	0000  SC15064
+1b13  Jaton Corp
+1c1c  Symphony
+	0001  82C101
+1d44  DPT
+	a400  PM2x24/PM3224
+1de1  Tekram Technology Co.,Ltd.
+	0391  TRM-S1040
+	2020  DC-390
+	690c  690c
+	dc29  DC290
+1fc0  Tumsan Oy
+	0300  E2200 Dual E1/Rawpipe Card
+2000  Smart Link Ltd.
+2001  Temporal Research Ltd
+2003  Smart Link Ltd.
+2004  Smart Link Ltd.
+21c3  21st Century Computer Corp.
+2348  Racore
+	2010  8142 100VG/AnyLAN
+2646  Kingston Technologies
+270b  Xantel Corporation
+270f  Chaintech Computer Co. Ltd
+2711  AVID Technology Inc.
+2a15  3D Vision(???)
+3000  Hansol Electronics Inc.
+3142  Post Impression Systems.
+3388  Hint Corp
+	0013  HiNT HC4 PCI to ISDN bridge, Multimedia audio controller
+	0014  HiNT HC4 PCI to ISDN bridge, Network controller
+	0020  HB6 Universal PCI-PCI bridge (transparent mode)
+	0021  HB6 Universal PCI-PCI bridge (non-transparent mode)
+		4c53 1050  CT7 mainboard
+		4c53 1080  CT8 mainboard
+		4c53 10a0  CA3/CR3 mainboard
+		4c53 3010  PPCI mezzanine (32-bit PMC)
+		4c53 3011  PPCI mezzanine (64-bit PMC)
+	0022  HiNT HB4 PCI-PCI Bridge (PCI6150)
+	0026  HB2 PCI-PCI Bridge
+	101a  E.Band [AudioTrak Inca88]
+	101b  E.Band [AudioTrak Inca88]
+	8011  VXPro II Chipset
+		3388 8011  VXPro II Chipset CPU to PCI Bridge
+	8012  VXPro II Chipset
+		3388 8012  VXPro II Chipset PCI to ISA Bridge
+	8013  VXPro II IDE
+		3388 8013  VXPro II Chipset EIDE Controller
+3411  Quantum Designs (H.K.) Inc
+3513  ARCOM Control Systems Ltd
+3842  eVga.com. Corp.
+38ef  4Links
+3d3d  3DLabs
+	0001  GLINT 300SX
+	0002  GLINT 500TX
+	0003  GLINT Delta
+	0004  Permedia
+	0005  Permedia
+	0006  GLINT MX
+	0007  3D Extreme
+	0008  GLINT Gamma G1
+	0009  Permedia II 2D+3D
+		1040 0011  AccelStar II
+		13e9 1000  6221L-4U
+		3d3d 0100  AccelStar II 3D Accelerator
+		3d3d 0111  Permedia 3:16
+		3d3d 0114  Santa Ana
+		3d3d 0116  Oxygen GVX1
+		3d3d 0119  Scirocco
+		3d3d 0120  Santa Ana PCL
+		3d3d 0125  Oxygen VX1
+		3d3d 0127  Permedia3 Create!
+	000a  GLINT R3
+		3d3d 0121  Oxygen VX1
+	000c  GLINT R3 [Oxygen VX1]
+		3d3d 0144  Oxygen VX1-4X AGP [Permedia 4]
+	000d  GLint R4 rev A
+	0011  GLint R4 rev B
+	0012  GLint R5 rev A
+	0013  GLint R5 rev B
+	0020  VP10 visual processor
+# P10 generic II
+	0022  VP10 visual processor
+	0024  VP9 visual processor
+	0100  Permedia II 2D+3D
+	07a1  Wildcat III 6210
+	07a2  Sun XVR-500 Graphics Accelerator
+	07a3  Wildcat IV 7210
+	1004  Permedia
+	3d04  Permedia
+	ffff  Glint VGA
+4005  Avance Logic Inc.
+	0300  ALS300 PCI Audio Device
+	0308  ALS300+ PCI Audio Device
+	0309  PCI Input Controller
+	1064  ALG-2064
+	2064  ALG-2064i
+	2128  ALG-2364A GUI Accelerator
+	2301  ALG-2301
+	2302  ALG-2302
+	2303  AVG-2302 GUI Accelerator
+	2364  ALG-2364A
+	2464  ALG-2464
+	2501  ALG-2564A/25128A
+	4000  ALS4000 Audio Chipset
+		4005 4000  ALS4000 Audio Chipset
+	4710  ALC200/200P
+4033  Addtron Technology Co, Inc.
+	1360  RTL8139 Ethernet
+4143  Digital Equipment Corp
+4144  Alpha Data
+	0044  ADM-XRCIIPro
+416c  Aladdin Knowledge Systems
+	0100  AladdinCARD
+	0200  CPC
+4444  Internext Compression Inc
+	0016  iTVC16 (CX23416) MPEG-2 Encoder
+		0070 4009  WinTV PVR 250
+		0070 8003  WinTV PVR 150
+	0803  iTVC15 MPEG-2 Encoder
+		0070 4000  WinTV PVR-350
+		0070 4001  WinTV PVR-250
+# video capture card
+		1461 a3cf  M179
+4468  Bridgeport machines
+4594  Cogetec Informatique Inc
+45fb  Baldor Electric Company
+4680  Umax Computer Corp
+4843  Hercules Computer Technology Inc
+4916  RedCreek Communications Inc
+	1960  RedCreek PCI adapter
+4943  Growth Networks
+494f  ACCES I/O Products, Inc.
+	10e8  LPCI-COM-8SM
+4978  Axil Computer Inc
+4a14  NetVin
+	5000  NV5000SC
+		4a14 5000  RT8029-Based Ethernet Adapter
+4b10  Buslogic Inc.
+4c48  LUNG HWA Electronics
+4c53  SBS Technologies
+	0000  PLUSTEST device
+		4c53 3000  PLUSTEST card (PC104+)
+		4c53 3001  PLUSTEST card (PMC)
+	0001  PLUSTEST-MM device
+		4c53 3002  PLUSTEST-MM card (PMC)
+4ca1  Seanix Technology Inc
+4d51  MediaQ Inc.
+	0200  MQ-200
+4d54  Microtechnica Co Ltd
+4ddc  ILC Data Device Corp
+	0100  DD-42924I5-300 (ARINC 429 Data Bus)
+	0801  BU-65570I1 MIL-STD-1553 Test and Simulation
+	0802  BU-65570I2 MIL-STD-1553 Test and Simulation
+	0811  BU-65572I1 MIL-STD-1553 Test and Simulation
+	0812  BU-65572I2 MIL-STD-1553 Test and Simulation
+	0881  BU-65570T1 MIL-STD-1553 Test and Simulation
+	0882  BU-65570T2 MIL-STD-1553 Test and Simulation
+	0891  BU-65572T1 MIL-STD-1553 Test and Simulation
+	0892  BU-65572T2 MIL-STD-1553 Test and Simulation
+	0901  BU-65565C1 MIL-STD-1553 Data Bus
+	0902  BU-65565C2 MIL-STD-1553 Data Bus
+	0903  BU-65565C3 MIL-STD-1553 Data Bus
+	0904  BU-65565C4 MIL-STD-1553 Data Bus
+	0b01  BU-65569I1 MIL-STD-1553 Data Bus
+	0b02  BU-65569I2 MIL-STD-1553 Data Bus
+	0b03  BU-65569I3 MIL-STD-1553 Data Bus
+	0b04  BU-65569I4 MIL-STD-1553 Data Bus
+5046  GemTek Technology Corporation
+	1001  PCI Radio
+5053  Voyetra Technologies
+	2010  Daytona Audio Adapter
+5136  S S Technologies
+5143  Qualcomm Inc
+5145  Ensoniq (Old)
+	3031  Concert AudioPCI
+5168  Animation Technologies Inc.
+5301  Alliance Semiconductor Corp.
+	0001  ProMotion aT3D
+5333  S3 Inc.
+	0551  Plato/PX (system)
+	5631  86c325 [ViRGE]
+	8800  86c866 [Vision 866]
+	8801  86c964 [Vision 964]
+	8810  86c764_0 [Trio 32 vers 0]
+	8811  86c764/765 [Trio32/64/64V+]
+	8812  86cM65 [Aurora64V+]
+	8813  86c764_3 [Trio 32/64 vers 3]
+	8814  86c767 [Trio 64UV+]
+	8815  86cM65 [Aurora 128]
+	883d  86c988 [ViRGE/VX]
+	8870  FireGL
+	8880  86c868 [Vision 868 VRAM] vers 0
+	8881  86c868 [Vision 868 VRAM] vers 1
+	8882  86c868 [Vision 868 VRAM] vers 2
+	8883  86c868 [Vision 868 VRAM] vers 3
+	88b0  86c928 [Vision 928 VRAM] vers 0
+	88b1  86c928 [Vision 928 VRAM] vers 1
+	88b2  86c928 [Vision 928 VRAM] vers 2
+	88b3  86c928 [Vision 928 VRAM] vers 3
+	88c0  86c864 [Vision 864 DRAM] vers 0
+	88c1  86c864 [Vision 864 DRAM] vers 1
+	88c2  86c864 [Vision 864-P DRAM] vers 2
+	88c3  86c864 [Vision 864-P DRAM] vers 3
+	88d0  86c964 [Vision 964 VRAM] vers 0
+	88d1  86c964 [Vision 964 VRAM] vers 1
+	88d2  86c964 [Vision 964-P VRAM] vers 2
+	88d3  86c964 [Vision 964-P VRAM] vers 3
+	88f0  86c968 [Vision 968 VRAM] rev 0
+	88f1  86c968 [Vision 968 VRAM] rev 1
+	88f2  86c968 [Vision 968 VRAM] rev 2
+	88f3  86c968 [Vision 968 VRAM] rev 3
+	8900  86c755 [Trio 64V2/DX]
+		5333 8900  86C775 Trio64V2/DX
+	8901  86c775/86c785 [Trio 64V2/DX or /GX]
+		5333 8901  86C775 Trio64V2/DX, 86C785 Trio64V2/GX
+	8902  Plato/PX
+	8903  Trio 3D business multimedia
+	8904  Trio 64 3D
+		1014 00db  Integrated Trio3D
+		5333 8904  86C365 Trio3D AGP
+	8905  Trio 64V+ family
+	8906  Trio 64V+ family
+	8907  Trio 64V+ family
+	8908  Trio 64V+ family
+	8909  Trio 64V+ family
+	890a  Trio 64V+ family
+	890b  Trio 64V+ family
+	890c  Trio 64V+ family
+	890d  Trio 64V+ family
+	890e  Trio 64V+ family
+	890f  Trio 64V+ family
+	8a01  ViRGE/DX or /GX
+		0e11 b032  ViRGE/GX
+		10b4 1617  Nitro 3D
+		10b4 1717  Nitro 3D
+		5333 8a01  ViRGE/DX
+	8a10  ViRGE/GX2
+		1092 8a10  Stealth 3D 4000
+	8a13  86c368 [Trio 3D/2X]
+		5333 8a13  Trio3D/2X
+	8a20  86c794 [Savage 3D]
+		5333 8a20  86C391 Savage3D
+	8a21  86c390 [Savage 3D/MV]
+		5333 8a21  86C390 Savage3D/MV
+	8a22  Savage 4
+		1033 8068  Savage 4
+		1033 8069  Savage 4
+		1033 8110  Savage4 LT
+		105d 0018  SR9 8Mb SDRAM
+		105d 002a  SR9 Pro 16Mb SDRAM
+		105d 003a  SR9 Pro 32Mb SDRAM
+		105d 092f  SR9 Pro+ 16Mb SGRAM
+		1092 4207  Stealth III S540
+		1092 4800  Stealth III S540
+		1092 4807  SpeedStar A90
+		1092 4808  Stealth III S540
+		1092 4809  Stealth III S540
+		1092 480e  Stealth III S540
+		1092 4904  Stealth III S520
+		1092 4905  SpeedStar A200
+		1092 4a09  Stealth III S540
+		1092 4a0b  Stealth III S540 Xtreme
+		1092 4a0f  Stealth III S540
+		1092 4e01  Stealth III S540
+		1102 101d  3d Blaster Savage 4
+		1102 101e  3d Blaster Savage 4
+		5333 8100  86C394-397 Savage4 SDRAM 100
+		5333 8110  86C394-397 Savage4 SDRAM 110
+		5333 8125  86C394-397 Savage4 SDRAM 125
+		5333 8143  86C394-397 Savage4 SDRAM 143
+		5333 8a22  86C394-397 Savage4
+		5333 8a2e  86C394-397 Savage4 32bit
+		5333 9125  86C394-397 Savage4 SGRAM 125
+		5333 9143  86C394-397 Savage4 SGRAM 143
+	8a23  Savage 4
+	8a25  ProSavage PM133
+	8a26  ProSavage KM133
+	8c00  ViRGE/M3
+	8c01  ViRGE/MX
+		1179 0001  ViRGE/MX
+	8c02  ViRGE/MX+
+	8c03  ViRGE/MX+MV
+	8c10  86C270-294 Savage/MX-MV
+	8c11  82C270-294 Savage/MX
+	8c12  86C270-294 Savage/IX-MV
+		1014 017f  ThinkPad T20
+		1179 0001  86C584 SuperSavage/IXC Toshiba
+	8c13  86C270-294 Savage/IX
+		1179 0001  Magnia Z310
+	8c22  SuperSavage MX/128
+	8c24  SuperSavage MX/64
+	8c26  SuperSavage MX/64C
+	8c2a  SuperSavage IX/128 SDR
+	8c2b  SuperSavage IX/128 DDR
+	8c2c  SuperSavage IX/64 SDR
+	8c2d  SuperSavage IX/64 DDR
+	8c2e  SuperSavage IX/C SDR
+		1014 01fc  ThinkPad T23 (2647-4MG)
+	8c2f  SuperSavage IX/C DDR
+	8d01  86C380 [ProSavageDDR K4M266]
+	8d02  VT8636A [ProSavage KN133] AGP4X VGA Controller (TwisterK)
+	8d03  VT8751 [ProSavageDDR P4M266]
+	8d04  VT8375 [ProSavage8 KM266/KL266]
+	9102  86C410 Savage 2000
+		1092 5932  Viper II Z200
+		1092 5934  Viper II Z200
+		1092 5952  Viper II Z200
+		1092 5954  Viper II Z200
+		1092 5a35  Viper II Z200
+		1092 5a37  Viper II Z200
+		1092 5a55  Viper II Z200
+		1092 5a57  Viper II Z200
+	ca00  SonicVibes
+544c  Teralogic Inc
+	0350  TL880-based HDTV/ATSC tuner
+5455  Technische University Berlin
+	4458  S5933
+5519  Cnet Technologies, Inc.
+5544  Dunord Technologies
+	0001  I-30xx Scanner Interface
+5555  Genroco, Inc
+	0003  TURBOstor HFP-832 [HiPPI NIC]
+5654  VoiceTronix Pty Ltd
+	3132  OpenSwitch12
+5700  Netpower
+5851  Exacq Technologies
+6356  UltraStor
+6374  c't Magazin für Computertechnik
+	6773  GPPCI
+6409  Logitec Corp.
+6666  Decision Computer International Co.
+	0001  PCCOM4
+	0002  PCCOM8
+7604  O.N. Electronic Co Ltd.
+7bde  MIDAC Corporation
+7fed  PowerTV
+8008  Quancom Electronic GmbH
+	0010  WDOG1 [PCI-Watchdog 1]
+	0011  PWDOG2 [PCI-Watchdog 2]
+# Wrong ID used in subsystem ID of AsusTek PCI-USB2 PCI card.
+807d  Asustek Computer, Inc.
+8086  Intel Corporation
+	0007  82379AB
+	0008  Extended Express System Support Controller
+		0008 1000  WorldMark 4300 INCA ASIC
+	0039  21145 Fast Ethernet
+	0122  82437FX
+	0309  80303 I/O Processor PCI-to-PCI Bridge
+	030d  80312 I/O Companion Chip PCI-to-PCI Bridge
+	0326  6700/6702PXH I/OxAPIC Interrupt Controller A
+	0327  6700PXH I/OxAPIC Interrupt Controller B
+	0329  6700PXH PCI Express-to-PCI Bridge A
+	032a  6700PXH PCI Express-to-PCI Bridge B
+	032c  6702PXH PCI Express-to-PCI Bridge A
+# A-segment bridge
+	0330  80332 [Dobson] I/O processor
+# A-segment IOAPIC
+	0331  80332 [Dobson] I/O processor
+# B-segment bridge
+	0332  80332 [Dobson] I/O processor
+# B-segment IOAPIC
+	0333  80332 [Dobson] I/O processor
+# Address Translation Unit (ATU)
+	0334  80332 [Dobson] I/O processor
+# PCI-X bridge
+	0335  80331 [Lindsay] I/O processor
+# Address Translation Unit (ATU)
+	0336  80331 [Lindsay] I/O processor
+# A-segment bridge
+	0340  41210 [Lanai] Serial to Parallel PCI Bridge
+# B-segment bridge
+	0341  41210 [Lanai] Serial to Parallel PCI Bridge
+	0482  82375EB/SB PCI to EISA Bridge
+	0483  82424TX/ZX [Saturn] CPU to PCI bridge
+	0484  82378ZB/IB, 82379AB (SIO, SIO.A) PCI to ISA Bridge
+	0486  82425EX/ZX [Aries] PCIset with ISA bridge
+	04a3  82434LX/NX [Mercury/Neptune] Processor to PCI bridge
+	04d0  82437FX [Triton FX]
+	0500  E8870 Processor bus control
+	0501  E8870 Memory controller
+# and registers common to both SPs
+	0502  E8870 Scalability Port 0
+# and global performance monitoring
+	0503  E8870 Scalability Port 1
+	0510  E8870IO Hub Interface Port 0 registers (8-bit compatibility port)
+	0511  E8870IO Hub Interface Port 1 registers
+	0512  E8870IO Hub Interface Port 2 registers
+	0513  E8870IO Hub Interface Port 3 registers
+	0514  E8870IO Hub Interface Port 4 registers
+	0515  E8870IO General SIOH registers
+	0516  E8870IO RAS registers
+	0530  E8870SP Scalability Port 0 registers
+	0531  E8870SP Scalability Port 1 registers
+	0532  E8870SP Scalability Port 2 registers
+	0533  E8870SP Scalability Port 3 registers
+	0534  E8870SP Scalability Port 4 registers
+	0535  E8870SP Scalability Port 5 registers
+# (bi-interleave 0) and global registers that are neither per-port nor per-interleave
+	0536  E8870SP Interleave registers 0 and 1
+# (bi-interleave 1)
+	0537  E8870SP Interleave registers 2 and 3
+	0600  RAID Controller
+		8086 01c1  ICP Vortex GDT8546RZ
+		8086 01f7  SCRU32
+# uninitialized SRCU32 RAID Controller
+	061f  80303 I/O Processor
+	0960  80960RP [i960 RP Microprocessor/Bridge]
+	0962  80960RM [i960RM Bridge]
+	0964  80960RP [i960 RP Microprocessor/Bridge]
+	1000  82542 Gigabit Ethernet Controller
+		0e11 b0df  NC1632 Gigabit Ethernet Adapter (1000-SX)
+		0e11 b0e0  NC1633 Gigabit Ethernet Adapter (1000-LX)
+		0e11 b123  NC1634 Gigabit Ethernet Adapter (1000-SX)
+		1014 0119  Netfinity Gigabit Ethernet SX Adapter
+		8086 1000  PRO/1000 Gigabit Server Adapter
+	1001  82543GC Gigabit Ethernet Controller (Fiber)
+		0e11 004a  NC6136 Gigabit Server Adapter
+		1014 01ea  Netfinity Gigabit Ethernet SX Adapter
+		8086 1002  PRO/1000 F Server Adapter
+		8086 1003  PRO/1000 F Server Adapter
+	1002  Pro 100 LAN+Modem 56 Cardbus II
+		8086 200e  Pro 100 LAN+Modem 56 Cardbus II
+		8086 2013  Pro 100 SR Mobile Combo Adapter
+		8086 2017  Pro 100 S Combo Mobile Adapter
+	1004  82543GC Gigabit Ethernet Controller (Copper)
+		0e11 0049  NC7132 Gigabit Upgrade Module
+		0e11 b1a4  NC7131 Gigabit Server Adapter
+		1014 10f2  Gigabit Ethernet Server Adapter
+		8086 1004  PRO/1000 T Server Adapter
+		8086 2004  PRO/1000 T Server Adapter
+	1008  82544EI Gigabit Ethernet Controller (Copper)
+		1014 0269  iSeries 1000/100/10 Ethernet Adapter
+		1028 011c  PRO/1000 XT Network Connection
+		8086 1107  PRO/1000 XT Server Adapter
+		8086 2107  PRO/1000 XT Server Adapter
+		8086 2110  PRO/1000 XT Server Adapter
+		8086 3108  PRO/1000 XT Network Connection
+	1009  82544EI Gigabit Ethernet Controller (Fiber)
+		1014 0268  iSeries Gigabit Ethernet Adapter
+		8086 1109  PRO/1000 XF Server Adapter
+		8086 2109  PRO/1000 XF Server Adapter
+	100c  82544GC Gigabit Ethernet Controller (Copper)
+		8086 1112  PRO/1000 T Desktop Adapter
+		8086 2112  PRO/1000 T Desktop Adapter
+	100d  82544GC Gigabit Ethernet Controller (LOM)
+		1028 0123  PRO/1000 XT Network Connection
+		1079 891f  82544GC Based Network Connection
+		4c53 1080  CT8 mainboard
+		8086 110d  82544GC Based Network Connection
+	100e  82540EM Gigabit Ethernet Controller
+		1014 0265  PRO/1000 MT Network Connection
+		1014 0267  PRO/1000 MT Network Connection
+		1014 026a  PRO/1000 MT Network Connection
+		1028 002e  Optiplex GX260
+		1028 0151  PRO/1000 MT Network Connection
+		107b 8920  PRO/1000 MT Desktop Adapter
+		8086 001e  PRO/1000 MT Desktop Adapter
+		8086 002e  PRO/1000 MT Desktop Adapter
+	100f  82545EM Gigabit Ethernet Controller (Copper)
+		1014 0269  iSeries 1000/100/10 Ethernet Adapter
+		1014 028e  PRO/1000 MT Network Connection
+		8086 1000  PRO/1000 MT Network Connection
+		8086 1001  PRO/1000 MT Server Adapter
+	1010  82546EB Gigabit Ethernet Controller (Copper)
+		1014 027c  PRO/1000 MT Dual Port Network Adapter
+		18fb 7872  RESlink-X
+		4c53 1080  CT8 mainboard
+		4c53 10a0  CA3/CR3 mainboard
+		8086 1011  PRO/1000 MT Dual Port Server Adapter
+		8086 101a  PRO/1000 MT Dual Port Network Adapter
+		8086 3424  SE7501HG2 Mainboard
+	1011  82545EM Gigabit Ethernet Controller (Fiber)
+		1014 0268  iSeries Gigabit Ethernet Adapter
+		8086 1002  PRO/1000 MF Server Adapter
+		8086 1003  PRO/1000 MF Server Adapter (LX)
+	1012  82546EB Gigabit Ethernet Controller (Fiber)
+		8086 1012  PRO/1000 MF Dual Port Server Adapter
+	1013  82541EI Gigabit Ethernet Controller (Copper)
+		8086 0013  PRO/1000 MT Network Connection
+		8086 1013  IBM ThinkCentre Network Card
+		8086 1113  PRO/1000 MT Desktop Adapter
+	1014  82541ER Gigabit Ethernet Controller
+	1015  82540EM Gigabit Ethernet Controller (LOM)
+	1016  82540EP Gigabit Ethernet Controller (LOM)
+		1014 052c  PRO/1000 MT Mobile Connection
+		1179 0001  PRO/1000 MT Mobile Connection
+		8086 1016  PRO/1000 MT Mobile Connection
+	1017  82540EP Gigabit Ethernet Controller (LOM)
+		8086 1017  PR0/1000 MT Desktop Connection
+# Update controller name from 82541EP to 82541EI
+	1018  82541EI Gigabit Ethernet Controller
+		8086 1018  PRO/1000 MT Desktop Adapter
+	1019  82547EI Gigabit Ethernet Controller (LOM)
+		1458 1019  GA-8IPE1000 Pro2 motherboard (865PE)
+		1458 e000  Intel Gigabit Ethernet (Kenai II)
+		8086 1019  PRO/1000 CT Desktop Connection
+		8086 301f  D865PERL mainboard
+		8086 3427  S875WP1-E mainboard
+	101d  82546EB Gigabit Ethernet Controller
+		8086 1000  PRO/1000 MT Quad Port Server Adapter
+	101e  82540EP Gigabit Ethernet Controller (Mobile)
+		1014 0549  PRO/1000 MT Mobile Connection
+		1179 0001  PRO/1000 MT Mobile Connection
+		8086 101e  PRO/1000 MT Mobile Connection
+	1026  82545GM Gigabit Ethernet Controller
+		8086 1000  PRO/1000 MT Server Connection
+		8086 1001  PRO/1000 MT Server Adapter
+		8086 1002  PRO/1000 MT Server Adapter
+		8086 1026  PRO/1000 MT Server Connection
+	1027  82545GM Gigabit Ethernet Controller
+		8086 1001  PRO/1000 MF Server Adapter(LX)
+		8086 1002  PRO/1000 MF Server Adapter(LX)
+		8086 1003  PRO/1000 MF Server Adapter(LX)
+		8086 1027  PRO/1000 MF Server Adapter
+	1028  82545GM Gigabit Ethernet Controller
+		8086 1028  PRO/1000 MB Server Adapter
+	1029  82559 Ethernet Controller
+	1030  82559 InBusiness 10/100
+	1031  82801CAM (ICH3) PRO/100 VE (LOM) Ethernet Controller
+		1014 0209  ThinkPad A/T/X Series
+		104d 80e7  Vaio PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		107b 5350  EtherExpress PRO/100 VE
+		1179 0001  EtherExpress PRO/100 VE
+		144d c000  EtherExpress PRO/100 VE
+		144d c001  EtherExpress PRO/100 VE
+		144d c003  EtherExpress PRO/100 VE
+		144d c006  vpr Matrix 170B4
+	1032  82801CAM (ICH3) PRO/100 VE Ethernet Controller
+	1033  82801CAM (ICH3) PRO/100 VM (LOM) Ethernet Controller
+	1034  82801CAM (ICH3) PRO/100 VM Ethernet Controller
+	1035  82801CAM (ICH3)/82562EH (LOM)  Ethernet Controller
+	1036  82801CAM (ICH3) 82562EH Ethernet Controller
+	1037  82801CAM (ICH3) Chipset Ethernet Controller
+	1038  82801CAM (ICH3) PRO/100 VM (KM) Ethernet Controller
+	1039  82801DB PRO/100 VE (LOM) Ethernet Controller
+		1014 0267  NetVista A30p
+	103a  82801DB PRO/100 VE (CNR) Ethernet Controller
+	103b  82801DB PRO/100 VM (LOM) Ethernet Controller
+	103c  82801DB PRO/100 VM (CNR) Ethernet Controller
+	103d  82801DB PRO/100 VE (MOB) Ethernet Controller
+	103e  82801DB PRO/100 VM (MOB) Ethernet Controller
+	1040  536EP Data Fax Modem
+		16be 1040  V.9X DSP Data Fax Modem
+	1043  PRO/Wireless LAN 2100 3B Mini PCI Adapter
+		8086 2527  MIM2000/Centrino
+	1048  PRO/10GbE LR Server Adapter
+		8086 a01f  PRO/10GbE LR Server Adapter
+		8086 a11f  PRO/10GbE LR Server Adapter
+	1050  82562EZ 10/100 Ethernet Controller
+		1462 728c  865PE Neo2 (MS-6728)
+		1462 758c  MS-6758 (875P Neo)
+		8086 3020  D865PERL mainboard
+		8086 3427  S875WP1-E mainboard
+	1051  82801EB/ER (ICH5/ICH5R) integrated LAN Controller
+	1059  82551QM Ethernet Controller
+# ICH-6 Component
+	1064  82562ET/EZ/GT/GZ - PRO/100 VE (LOM) Ethernet Controller
+# ICH-6 Component
+	1065  82562ET/EZ/GT/GZ - PRO/100 VE Ethernet Controller
+# ICH-6 Component
+	1066  82562 EM/EX/GX - PRO/100 VM (LOM) Ethernet Controller
+# ICH-6 Component
+	1067  82562 EM/EX/GX - PRO/100 VM Ethernet Controller
+# ICH-6 Component
+	1068  82562ET/EZ/GT/GZ - PRO/100 VE (LOM) Ethernet Controller Mobile
+# ICH-6 Component
+	1069  82562 EM/EX/GX - PRO/100 VM (LOM) Ethernet Controller Mobile
+# ICH-6 Component
+	106a  82562G \t- PRO/100 VE (LOM) Ethernet Controller
+# ICH-6 Component
+	106b  82562G \t- PRO/100 VE Ethernet Controller Mobile
+	1075  82547GI Gigabit Ethernet Controller
+		1028 0165  PowerEdge 750
+		8086 0075  PRO/1000 CT Network Connection
+		8086 1075  PRO/1000 CT Network Connection
+	1076  82541GI/PI Gigabit Ethernet Controller
+		1028 0165  PowerEdge 750
+		8086 0076  PRO/1000 MT Network Connection
+		8086 1076  PRO/1000 MT Network Connection
+		8086 1176  PRO/1000 MT Desktop Adapter
+		8086 1276  PRO/1000 MT Desktop Adapter
+	1077  82541GI Gigabit Ethernet Controller
+		1179 0001  PRO/1000 MT Mobile Connection
+		8086 0077  PRO/1000 MT Mobile Connection
+		8086 1077  PRO/1000 MT Mobile Connection
+	1078  82541EI Gigabit Ethernet Controller
+		8086 1078  PRO/1000 MT Network Connection
+	1079  82546GB Gigabit Ethernet Controller
+		103c 12a6  HP Dual Port 1000Base-T [A9900A]
+		103c 12cf  HP Core Dual Port 1000Base-T [AB352A]
+		4c53 1090  Cx9 / Vx9 mainboard
+		4c53 10b0  CL9 mainboard
+		8086 0079  PRO/1000 MT Dual Port Network Connection
+		8086 1079  PRO/1000 MT Dual Port Network Connection
+		8086 1179  PRO/1000 MT Dual Port Network Connection
+		8086 117a  PRO/1000 MT Dual Port Server Adapter
+	107a  82546GB Gigabit Ethernet Controller
+		103c 12a8  HP Dual Port 1000base-SX [A9899A]
+		8086 107a  PRO/1000 MF Dual Port Server Adapter
+		8086 127a  PRO/1000 MF Dual Port Server Adapter
+	107b  82546GB Gigabit Ethernet Controller
+		8086 007b  PRO/1000 MB Dual Port Server Connection
+		8086 107b  PRO/1000 MB Dual Port Server Connection
+	1107  PRO/1000 MF Server Adapter (LX)
+	1130  82815 815 Chipset Host Bridge and Memory Controller Hub
+		1025 1016  Travelmate 612 TX
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
+		8086 4532  D815EEA2 mainboard
+		8086 4557  D815EGEW Mainboard
+	1131  82815 815 Chipset AGP Bridge
+	1132  82815 CGC [Chipset Graphics Controller]
+		1025 1016  Travelmate 612 TX
+		104d 80df  Vaio PCG-FX403
+		8086 4532  D815EEA2 Mainboard
+		8086 4557  D815EGEW Mainboard
+	1161  82806AA PCI64 Hub Advanced Programmable Interrupt Controller
+		8086 1161  82806AA PCI64 Hub APIC
+	1162  Xscale 80200 Big Endian Companion Chip
+	1200  Intel IXP1200 Network Processor
+		172a 0000  AEP SSL Accelerator
+	1209  8255xER/82551IT Fast Ethernet Controller
+		4c53 1050  CT7 mainboard
+		4c53 1051  CE7 mainboard
+		4c53 1070  PC6 mainboard
+	1221  82092AA PCI to PCMCIA Bridge
+	1222  82092AA IDE Controller
+	1223  SAA7116
+	1225  82452KX/GX [Orion]
+	1226  82596 PRO/10 PCI
+	1227  82865 EtherExpress PRO/100A
+	1228  82556 EtherExpress PRO/100 Smart
+# the revision field differentiates between them (1-3 is 82557, 4-5 is 82558, 6-8 is 82559, 9 is 82559ER)
+	1229  82557/8/9 [Ethernet Pro 100]
+		0e11 3001  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3002  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3003  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3004  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3005  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3006  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 3007  82559 Fast Ethernet LOM with Alert on LAN*
+		0e11 b01e  NC3120 Fast Ethernet NIC
+		0e11 b01f  NC3122 Fast Ethernet NIC (dual port)
+		0e11 b02f  NC1120 Ethernet NIC
+		0e11 b04a  Netelligent 10/100TX NIC with Wake on LAN
+		0e11 b0c6  NC3161 Fast Ethernet NIC (embedded, WOL)
+		0e11 b0c7  NC3160 Fast Ethernet NIC (embedded)
+		0e11 b0d7  NC3121 Fast Ethernet NIC (WOL)
+		0e11 b0dd  NC3131 Fast Ethernet NIC (dual port)
+		0e11 b0de  NC3132 Fast Ethernet Module (dual port)
+		0e11 b0e1  NC3133 Fast Ethernet Module (100-FX)
+		0e11 b134  NC3163 Fast Ethernet NIC (embedded, WOL)
+		0e11 b13c  NC3162 Fast Ethernet NIC (embedded)
+		0e11 b144  NC3123 Fast Ethernet NIC (WOL)
+		0e11 b163  NC3134 Fast Ethernet NIC (dual port)
+		0e11 b164  NC3135 Fast Ethernet Upgrade Module (dual port)
+		0e11 b1a4  NC7131 Gigabit Server Adapter
+		1014 005c  82558B Ethernet Pro 10/100
+		1014 01bc  82559 Fast Ethernet LAN On Motherboard
+		1014 01f1  10/100 Ethernet Server Adapter
+		1014 01f2  10/100 Ethernet Server Adapter
+		1014 0207  Ethernet Pro/100 S
+		1014 0232  10/100 Dual Port Server Adapter
+		1014 023a  ThinkPad R30
+		1014 105c  Netfinity 10/100
+		1014 2205  ThinkPad A22p
+		1014 305c  10/100 EtherJet Management Adapter
+		1014 405c  10/100 EtherJet Adapter with Alert on LAN
+		1014 505c  10/100 EtherJet Secure Management Adapter
+		1014 605c  10/100 EtherJet Secure Management Adapter
+		1014 705c  10/100 Netfinity 10/100 Ethernet Security Adapter
+		1014 805c  10/100 Netfinity 10/100 Ethernet Security Adapter
+		1028 009b  PowerEdge 2500/2550
+		1028 00ce  PowerEdge 1400
+		1033 8000  PC-9821X-B06
+		1033 8016  PK-UG-X006
+		1033 801f  PK-UG-X006
+		1033 8026  PK-UG-X006
+		1033 8063  82559-based Fast Ethernet Adapter
+		1033 8064  82559-based Fast Ethernet Adapter
+		103c 10c0  NetServer 10/100TX
+		103c 10c3  NetServer 10/100TX
+		103c 10ca  NetServer 10/100TX
+		103c 10cb  NetServer 10/100TX
+		103c 10e3  NetServer 10/100TX
+		103c 10e4  NetServer 10/100TX
+		103c 1200  NetServer 10/100TX
+		10c3 1100  SmartEther100 SC1100
+		10cf 1115  8255x-based Ethernet Adapter (10/100)
+		10cf 1143  8255x-based Ethernet Adapter (10/100)
+		1179 0001  8255x-based Ethernet Adapter (10/100)
+		1179 0002  PCI FastEther LAN on Docker
+		1179 0003  8255x-based Fast Ethernet
+		1259 2560  AT-2560 100
+		1259 2561  AT-2560 100 FX Ethernet Adapter
+		1266 0001  NE10/100 Adapter
+		13e9 1000  6221L-4U
+		144d 2501  SEM-2000 MiniPCI LAN Adapter
+		144d 2502  SEM-2100IL MiniPCI LAN Adapter
+		1668 1100  EtherExpress PRO/100B (TX) (MiniPCI Ethernet+Modem)
+		4c53 1080  CT8 mainboard
+		8086 0001  EtherExpress PRO/100B (TX)
+		8086 0002  EtherExpress PRO/100B (T4)
+		8086 0003  EtherExpress PRO/10+
+		8086 0004  EtherExpress PRO/100 WfM
+		8086 0005  82557 10/100
+		8086 0006  82557 10/100 with Wake on LAN
+		8086 0007  82558 10/100 Adapter
+		8086 0008  82558 10/100 with Wake on LAN
+		8086 0009  EtherExpress PRO/100+
+		8086 000a  EtherExpress PRO/100+ Management Adapter
+		8086 000b  EtherExpress PRO/100+
+		8086 000c  EtherExpress PRO/100+ Management Adapter
+		8086 000d  EtherExpress PRO/100+ Alert On LAN II* Adapter
+		8086 000e  EtherExpress PRO/100+ Management Adapter with Alert On LAN*
+		8086 000f  EtherExpress PRO/100 Desktop Adapter
+		8086 0010  EtherExpress PRO/100 S Management Adapter
+		8086 0011  EtherExpress PRO/100 S Management Adapter
+		8086 0012  EtherExpress PRO/100 S Advanced Management Adapter (D)
+		8086 0013  EtherExpress PRO/100 S Advanced Management Adapter (E)
+		8086 0030  EtherExpress PRO/100  Management Adapter with Alert On LAN* GC
+		8086 0031  EtherExpress PRO/100 Desktop Adapter
+		8086 0040  EtherExpress PRO/100 S Desktop Adapter
+		8086 0041  EtherExpress PRO/100 S Desktop Adapter
+		8086 0042  EtherExpress PRO/100 Desktop Adapter
+		8086 0050  EtherExpress PRO/100 S Desktop Adapter
+		8086 1009  EtherExpress PRO/100+ Server Adapter
+		8086 100c  EtherExpress PRO/100+ Server Adapter (PILA8470B)
+		8086 1012  EtherExpress PRO/100 S Server Adapter (D)
+		8086 1013  EtherExpress PRO/100 S Server Adapter (E)
+		8086 1015  EtherExpress PRO/100 S Dual Port Server Adapter
+		8086 1017  EtherExpress PRO/100+ Dual Port Server Adapter
+		8086 1030  EtherExpress PRO/100+ Management Adapter with Alert On LAN* G Server
+		8086 1040  EtherExpress PRO/100 S Server Adapter
+		8086 1041  EtherExpress PRO/100 S Server Adapter
+		8086 1042  EtherExpress PRO/100 Server Adapter
+		8086 1050  EtherExpress PRO/100 S Server Adapter
+		8086 1051  EtherExpress PRO/100 Server Adapter
+		8086 1052  EtherExpress PRO/100 Server Adapter
+		8086 10f0  EtherExpress PRO/100+ Dual Port Adapter
+		8086 2009  EtherExpress PRO/100 S Mobile Adapter
+		8086 200d  EtherExpress PRO/100 Cardbus
+		8086 200e  EtherExpress PRO/100 LAN+V90 Cardbus Modem
+		8086 200f  EtherExpress PRO/100 SR Mobile Adapter
+		8086 2010  EtherExpress PRO/100 S Mobile Combo Adapter
+		8086 2013  EtherExpress PRO/100 SR Mobile Combo Adapter
+		8086 2016  EtherExpress PRO/100 S Mobile Adapter
+		8086 2017  EtherExpress PRO/100 S Combo Mobile Adapter
+		8086 2018  EtherExpress PRO/100 SR Mobile Adapter
+		8086 2019  EtherExpress PRO/100 SR Combo Mobile Adapter
+		8086 2101  EtherExpress PRO/100 P Mobile Adapter
+		8086 2102  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2103  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2104  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2105  EtherExpress PRO/100 SP Mobile Adapter
+		8086 2106  EtherExpress PRO/100 P Mobile Adapter
+		8086 2107  EtherExpress PRO/100 Network Connection
+		8086 2108  EtherExpress PRO/100 Network Connection
+		8086 2200  EtherExpress PRO/100 P Mobile Combo Adapter
+		8086 2201  EtherExpress PRO/100 P Mobile Combo Adapter
+		8086 2202  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2203  EtherExpress PRO/100+ MiniPCI
+		8086 2204  EtherExpress PRO/100+ MiniPCI
+		8086 2205  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2206  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2207  EtherExpress PRO/100 SP Mobile Combo Adapter
+		8086 2208  EtherExpress PRO/100 P Mobile Combo Adapter
+		8086 2402  EtherExpress PRO/100+ MiniPCI
+		8086 2407  EtherExpress PRO/100+ MiniPCI
+		8086 2408  EtherExpress PRO/100+ MiniPCI
+		8086 2409  EtherExpress PRO/100+ MiniPCI
+		8086 240f  EtherExpress PRO/100+ MiniPCI
+		8086 2410  EtherExpress PRO/100+ MiniPCI
+		8086 2411  EtherExpress PRO/100+ MiniPCI
+		8086 2412  EtherExpress PRO/100+ MiniPCI
+		8086 2413  EtherExpress PRO/100+ MiniPCI
+		8086 3000  82559 Fast Ethernet LAN on Motherboard
+		8086 3001  82559 Fast Ethernet LOM with Basic Alert on LAN*
+		8086 3002  82559 Fast Ethernet LOM with Alert on LAN II*
+		8086 3006  EtherExpress PRO/100 S Network Connection
+		8086 3007  EtherExpress PRO/100 S Network Connection
+		8086 3008  EtherExpress PRO/100 Network Connection
+		8086 3010  EtherExpress PRO/100 S Network Connection
+		8086 3011  EtherExpress PRO/100 S Network Connection
+		8086 3012  EtherExpress PRO/100 Network Connection
+		8086 3411  SDS2 Mainboard
+	122d  430FX - 82437FX TSC [Triton I]
+	122e  82371FB PIIX ISA [Triton I]
+	1230  82371FB PIIX IDE [Triton I]
+	1231  DSVD Modem
+	1234  430MX - 82371MX Mobile PCI I/O IDE Xcelerator (MPIIX)
+	1235  430MX - 82437MX Mob. System Ctrlr (MTSC) & 82438MX Data Path (MTDP)
+	1237  440FX - 82441FX PMC [Natoma]
+	1239  82371FB PIIX IDE Interface
+	123b  82380PB PCI to PCI Docking Bridge
+	123c  82380AB (MISA) Mobile PCI-to-ISA Bridge
+	123d  683053 Programmable Interrupt Device
+# in" hidden" mode
+	123e  82466GX (IHPC) Integrated Hot-Plug Controller
+	123f  82466GX Integrated Hot-Plug Controller (IHPC)
+	1240  82752 (752) AGP Graphics Accelerator
+	124b  82380FB (MPCI2) Mobile Docking Controller
+	1250  430HX - 82439HX TXC [Triton II]
+	1360  82806AA PCI64 Hub PCI Bridge
+	1361  82806AA PCI64 Hub Controller (HRes)
+		8086 1361  82806AA PCI64 Hub Controller (HRes)
+		8086 8000  82806AA PCI64 Hub Controller (HRes)
+	1460  82870P2 P64H2 Hub PCI Bridge
+	1461  82870P2 P64H2 I/OxAPIC
+		15d9 3480  P4DP6
+		4c53 1090  Cx9 / Vx9 mainboard
+	1462  82870P2 P64H2 Hot Plug Controller
+	1960  80960RP [i960RP Microprocessor]
+		101e 0431  MegaRAID 431 RAID Controller
+		101e 0438  MegaRAID 438 Ultra2 LVD RAID Controller
+		101e 0466  MegaRAID 466 Express Plus RAID Controller
+		101e 0467  MegaRAID 467 Enterprise 1500 RAID Controller
+		101e 0490  MegaRAID 490 Express 300 RAID Controller
+		101e 0762  MegaRAID 762 Express RAID Controller
+		101e 09a0  PowerEdge Expandable RAID Controller 2/SC
+		1028 0467  PowerEdge Expandable RAID Controller 2/DC
+		1028 1111  PowerEdge Expandable RAID Controller 2/SC
+		103c 03a2  MegaRAID
+		103c 10c6  MegaRAID 438, HP NetRAID-3Si
+		103c 10c7  MegaRAID T5, Integrated HP NetRAID
+		103c 10cc  MegaRAID, Integrated HP NetRAID
+		103c 10cd  HP NetRAID-1Si
+		105a 0000  SuperTrak
+		105a 2168  SuperTrak Pro
+		105a 5168  SuperTrak66/100
+		1111 1111  MegaRAID 466, PowerEdge Expandable RAID Controller 2/SC
+		1111 1112  PowerEdge Expandable RAID Controller 2/SC
+		113c 03a2  MegaRAID
+		e4bf 1010  CG1-RADIO
+		e4bf 1020  CU2-QUARTET
+		e4bf 1040  CU1-CHORUS
+		e4bf 3100  CX1-BAND
+	1962  80960RM [i960RM Microprocessor]
+		105a 0000  SuperTrak SX6000 I2O CPU
+	1a21  82840 840 (Carmel) Chipset Host Bridge (Hub A)
+	1a23  82840 840 (Carmel) Chipset AGP Bridge
+	1a24  82840 840 (Carmel) Chipset PCI Bridge (Hub B)
+	1a30  82845 845 (Brookdale) Chipset Host Bridge
+		1028 010e  Optiplex GX240
+	1a31  82845 845 (Brookdale) Chipset AGP Bridge
+	2410  82801AA ISA Bridge (LPC)
+	2411  82801AA IDE
+	2412  82801AA USB
+	2413  82801AA SMBus
+	2415  82801AA AC'97 Audio
+		1028 0095  Precision Workstation 220 Integrated Digital Audio
+		11d4 0040  SoundMAX Integrated Digital Audio
+		11d4 0048  SoundMAX Integrated Digital Audio
+		11d4 5340  SoundMAX Integrated Digital Audio
+	2416  82801AA AC'97 Modem
+	2418  82801AA PCI Bridge
+	2420  82801AB ISA Bridge (LPC)
+	2421  82801AB IDE
+	2422  82801AB USB
+	2423  82801AB SMBus
+	2425  82801AB AC'97 Audio
+		11d4 0040  SoundMAX Integrated Digital Audio
+		11d4 0048  SoundMAX Integrated Digital Audio
+	2426  82801AB AC'97 Modem
+	2428  82801AB PCI Bridge
+	2440  82801BA ISA Bridge (LPC)
+	2442  82801BA/BAM USB (Hub #1)
+		1014 01c6  Netvista A40/A40p
+		1025 1016  Travelmate 612 TX
+		1028 010e  Optiplex GX240
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
+		8086 4532  D815EEA2 mainboard
+		8086 4557  D815EGEW Mainboard
+	2443  82801BA/BAM SMBus
+		1014 01c6  Netvista A40/A40p
+		1025 1016  Travelmate 612 TX
+		1028 010e  Optiplex GX240
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
+		8086 4532  D815EEA2 mainboard
+		8086 4557  D815EGEW Mainboard
+	2444  82801BA/BAM USB (Hub #2)
+		1025 1016  Travelmate 612 TX
+		1028 010e  Optiplex GX240
+		1043 8027  TUSL2-C Mainboard
+		104d 80df  Vaio PCG-FX403
+		147b 0507  TH7II-RAID
+		8086 4532  D815EEA2 mainboard
+	2445  82801BA/BAM AC'97 Audio
+		1014 01c6  Netvista A40/A40p
+		1025 1016  Travelmate 612 TX
+		104d 80df  Vaio PCG-FX403
+		1462 3370  STAC9721 AC
+		147b 0507  TH7II-RAID
+		8086 4557  D815EGEW Mainboard
+	2446  82801BA/BAM AC'97 Modem
+		1025 1016  Travelmate 612 TX
+		104d 80df  Vaio PCG-FX403
+	2448  82801 Mobile PCI Bridge
+	2449  82801BA/BAM/CA/CAM Ethernet Controller
+		0e11 0012  EtherExpress PRO/100 VM
+		0e11 0091  EtherExpress PRO/100 VE
+		1014 01ce  EtherExpress PRO/100 VE
+		1014 01dc  EtherExpress PRO/100 VE
+		1014 01eb  EtherExpress PRO/100 VE
+		1014 01ec  EtherExpress PRO/100 VE
+		1014 0202  EtherExpress PRO/100 VE
+		1014 0205  EtherExpress PRO/100 VE
+		1014 0217  EtherExpress PRO/100 VE
+		1014 0234  EtherExpress PRO/100 VE
+		1014 023d  EtherExpress PRO/100 VE
+		1014 0244  EtherExpress PRO/100 VE
+		1014 0245  EtherExpress PRO/100 VE
+		1014 0265  PRO/100 VE Desktop Connection
+		1014 0267  PRO/100 VE Desktop Connection
+		1014 026a  PRO/100 VE Desktop Connection
+		109f 315d  EtherExpress PRO/100 VE
+		109f 3181  EtherExpress PRO/100 VE
+		1179 ff01  PRO/100 VE Network Connection
+		1186 7801  EtherExpress PRO/100 VE
+		144d 2602  HomePNA 1M CNR
+		8086 3010  EtherExpress PRO/100 VE
+		8086 3011  EtherExpress PRO/100 VM
+		8086 3012  82562EH based Phoneline
+		8086 3013  EtherExpress PRO/100 VE
+		8086 3014  EtherExpress PRO/100 VM
+		8086 3015  82562EH based Phoneline
+		8086 3016  EtherExpress PRO/100 P Mobile Combo
+		8086 3017  EtherExpress PRO/100 P Mobile
+		8086 3018  EtherExpress PRO/100
+	244a  82801BAM IDE U100
+		1025 1016  Travelmate 612TX
+		104d 80df  Vaio PCG-FX403
+	244b  82801BA IDE U100
+		1014 01c6  Netvista A40/A40p
+		1028 010e  Optiplex GX240
+		1043 8027  TUSL2-C Mainboard
+		147b 0507  TH7II-RAID
+		8086 4532  D815EEA2 mainboard
+		8086 4557  D815EGEW Mainboard
+	244c  82801BAM ISA Bridge (LPC)
+	244e  82801 PCI Bridge
+		1014 0267  NetVista A30p
+	2450  82801E ISA Bridge (LPC)
+	2452  82801E USB
+	2453  82801E SMBus
+	2459  82801E Ethernet Controller 0
+	245b  82801E IDE U100
+	245d  82801E Ethernet Controller 1
+	245e  82801E PCI Bridge
+	2480  82801CA LPC Interface Controller
+	2482  82801CA/CAM USB (Hub #1)
+		1014 0220  ThinkPad A/T/X Series
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		15d9 3480  P4DP6
+		8086 1958  vpr Matrix 170B4
+		8086 3424  SE7501HG2 Mainboard
+		8086 4541  Latitude C640
+	2483  82801CA/CAM SMBus Controller
+		1014 0220  ThinkPad A/T/X Series
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		15d9 3480  P4DP6
+		8086 1958  vpr Matrix 170B4
+	2484  82801CA/CAM USB (Hub #2)
+		1014 0220  ThinkPad A/T/X Series
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		15d9 3480  P4DP6
+		8086 1958  vpr Matrix 170B4
+	2485  82801CA/CAM AC'97 Audio Controller
+		1013 5959  Crystal WMD Audio Codec
+		1014 0222  ThinkPad T23 (2647-4MG) or A30/A30p (2652/2653)
+		1014 0508  ThinkPad T30
+		1014 051c  ThinkPad A/T/X Series
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		144d c006  vpr Matrix 170B4
+	2486  82801CA/CAM AC'97 Modem Controller
+		1014 0223  ThinkPad A/T/X Series
+		1014 0503  ThinkPad R31 2656BBG
+		1014 051a  ThinkPad A/T/X Series
+		101f 1025  Acer 620 Series
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		1179 0001  Toshiba Satellite 1110 Z15 internal Modem
+		134d 4c21  Dell Inspiron 2100 internal modem
+		144d 2115  vpr Matrix 170B4 internal modem
+		14f1 5421  MD56ORD V.92 MDC Modem
+	2487  82801CA/CAM USB (Hub #3)
+		1014 0220  ThinkPad A/T/X Series
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		15d9 3480  P4DP6
+		8086 1958  vpr Matrix 170B4
+	248a  82801CAM IDE U100
+		1014 0220  ThinkPad A/T/X Series
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+		8086 1958  vpr Matrix 170B4
+		8086 4541  Latitude C640
+	248b  82801CA Ultra ATA Storage Controller
+		15d9 3480  P4DP6
+	248c  82801CAM ISA Bridge (LPC)
+	24c0  82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge
+		1014 0267  NetVista A30p
+		1462 5800  845PE Max (MS-6580)
+	24c1  82801DBL (ICH4-L) IDE Controller
+	24c2  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1
+		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1071 8160  MIM2000
+		1462 5800  845PE Max (MS-6580)
+		1509 2990  Averatec 5110H laptop
+		4c53 1090  Cx9 / Vx9 mainboard
+	24c3  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller
+		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1071 8160  MIM2000
+		1458 24c2  GA-8PE667 Ultra
+		1462 5800  845PE Max (MS-6580)
+		4c53 1090  Cx9 / Vx9 mainboard
+	24c4  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2
+		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1071 8160  MIM2000
+		1462 5800  845PE Max (MS-6580)
+		1509 2990  Averatec 5110H
+		4c53 1090  Cx9 / Vx9 mainboard
+	24c5  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller
+		0e11 00b8  Analog Devices Inc. codec [SoundMAX]
+		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1071 8160  MIM2000
+		1458 a002  GA-8PE667 Ultra
+		1462 5800  845PE Max (MS-6580)
+	24c6  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller
+		1025 005a  TravelMate 290
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1071 8160  MIM2000
+	24c7  82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3
+		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1071 8160  MIM2000
+		1462 5800  845PE Max (MS-6580)
+		1509 2990  Averatec 5110H
+		4c53 1090  Cx9 / Vx9 mainboard
+	24ca  82801DBM (ICH4-M) IDE Controller
+		1025 005a  TravelMate 290
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1071 8160  MIM2000
+	24cb  82801DB (ICH4) IDE Controller
+		1014 0267  NetVista A30p
+		1028 0126  Optiplex GX260
+		1458 24c2  GA-8PE667 Ultra
+		1462 5800  845PE Max (MS-6580)
+		4c53 1090  Cx9 / Vx9 mainboard
+	24cc  82801DBM (ICH4-M) LPC Interface Bridge
+	24cd  82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller
+		1014 0267  NetVista A30p
+		1025 005a  TravelMate 290
+		1028 0126  Optiplex GX260
+		1028 0163  Latitude D505
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+		1071 8160  MIM2000
+		1462 3981  845PE Max (MS-6580)
+		1509 1968  Averatec 5110H
+		4c53 1090  Cx9 / Vx9 mainboard
+	24d0  82801EB/ER (ICH5/ICH5R) LPC Interface Bridge
+	24d1  82801EB (ICH5) SATA Controller
+		103c 12bc  d530 CMT (DG746A)
+		1458 24d1  GA-8IPE1000 Pro2 motherboard (865PE)
+		1462 7280  865PE Neo2 (MS-6728)
+		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
+	24d2  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #1
+		1028 0183  PowerEdge 1800
+		103c 12bc  d530 CMT (DG746A)
+		1043 80a6  P4P800 Mainboard
+		1458 24d2  GA-8IPE1000/8KNXP motherboard
+		1462 7280  865PE Neo2 (MS-6728)
+		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
+	24d3  82801EB/ER (ICH5/ICH5R) SMBus Controller
+		1043 80a6  P4P800 Mainboard
+		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
+		1462 7280  865PE Neo2 (MS-6728)
+		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
+	24d4  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #2
+		1028 0183  PowerEdge 1800
+		103c 12bc  d530 CMT (DG746A)
+		1043 80a6  P4P800 Mainboard
+		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
+		1462 7280  865PE Neo2 (MS-6728)
+		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
+	24d5  82801EB/ER (ICH5/ICH5R) AC'97 Audio Controller
+		103c 12bc  Analog Devices codec [SoundMAX Integrated Digital Audio]
+		1043 80f3  P4P800 Mainboard
+# Again, I suppose they use the same in different subsystems
+		1458 a002  GA-8IPE1000/8KNXP motherboard
+		1462 7280  865PE Neo2 (MS-6728)
+		8086 a000  D865PERL mainboard
+		8086 e000  D865PERL mainboard
+	24d6  82801EB/ER (ICH5/ICH5R) AC'97 Modem Controller
+	24d7  82801EB/ER (ICH5/ICH5R) USB UHCI #3
+		1028 0183  PowerEdge 1800
+		103c 12bc  d530 CMT (DG746A)
+		1043 80a6  P4P800 Mainboard
+		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
+		1462 7280  865PE Neo2 (MS-6728)
+		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
+	24db  82801EB/ER (ICH5/ICH5R) IDE Controller
+		103c 12bc  d530 CMT (DG746A)
+		1043 80a6  P4P800 Mainboard
+		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
+		1462 7280  865PE Neo2 (MS-6728)
+		1462 7580  MSI 875P
+		8086 24db  P4C800 Mainboard
+		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
+	24dc  82801EB (ICH5) LPC Interface Bridge
+	24dd  82801EB/ER (ICH5/ICH5R) USB2 EHCI Controller
+		1028 0183  PowerEdge 1800
+		103c 12bc  d530 CMT (DG746A)
+		1043 80a6  P4P800 Mainboard
+		1458 5006  GA-8IPE1000 Pro2 motherboard (865PE)
+		1462 7280  865PE Neo2 (MS-6728)
+		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
+	24de  82801EB/ER (ICH5/ICH5R) USB UHCI Controller #4
+		1043 80a6  P4P800 Mainboard
+		1458 24d2  GA-8IPE1000 Pro2 motherboard (865PE)
+		1462 7280  865PE Neo2 (MS-6728)
+		8086 3427  S875WP1-E mainboard
+		8086 524c  D865PERL mainboard
+	24df  82801ER (ICH5R) SATA Controller
+	2500  82820 820 (Camino) Chipset Host Bridge (MCH)
+		1028 0095  Precision Workstation 220 Chipset
+		1043 801c  P3C-2000 system chipset
+	2501  82820 820 (Camino) Chipset Host Bridge (MCH)
+		1043 801c  P3C-2000 system chipset
+	250b  82820 820 (Camino) Chipset Host Bridge
+	250f  82820 820 (Camino) Chipset AGP Bridge
+	2520  82805AA MTH Memory Translator Hub
+	2521  82804AA MRH-S Memory Repeater Hub for SDRAM
+	2530  82850 850 (Tehama) Chipset Host Bridge (MCH)
+		147b 0507  TH7II-RAID
+	2531  82860 860 (Wombat) Chipset Host Bridge (MCH)
+	2532  82850 850 (Tehama) Chipset AGP Bridge
+	2533  82860 860 (Wombat) Chipset AGP Bridge
+	2534  82860 860 (Wombat) Chipset PCI Bridge
+	2540  E7500 Memory Controller Hub
+		15d9 3480  P4DP6
+	2541  E7500/E7501 Host RASUM Controller
+		15d9 3480  P4DP6
+		4c53 1090  Cx9 / Vx9 mainboard
+		8086 3424  SE7501HG2 Mainboard
+	2543  E7500/E7501 Hub Interface B PCI-to-PCI Bridge
+	2544  E7500/E7501 Hub Interface B RASUM Controller
+		4c53 1090  Cx9 / Vx9 mainboard
+	2545  E7500/E7501 Hub Interface C PCI-to-PCI Bridge
+	2546  E7500/E7501 Hub Interface C RASUM Controller
+	2547  E7500/E7501 Hub Interface D PCI-to-PCI Bridge
+	2548  E7500/E7501 Hub Interface D RASUM Controller
+	254c  E7501 Memory Controller Hub
+		4c53 1090  Cx9 / Vx9 mainboard
+		8086 3424  SE7501HG2 Mainboard
+	2550  E7505 Memory Controller Hub
+	2551  E7505/E7205 Series RAS Controller
+	2552  E7505/E7205 PCI-to-AGP Bridge
+	2553  E7505 Hub Interface B PCI-to-PCI Bridge
+	2554  E7505 Hub Interface B PCI-to-PCI Bridge RAS Controller
+	255d  E7205 Memory Controller Hub
+	2560  82845G/GL[Brookdale-G]/GE/PE DRAM Controller/Host-Hub Interface
+		1028 0126  Optiplex GX260
+		1458 2560  GA-8PE667 Ultra
+		1462 5800  845PE Max (MS-6580)
+	2561  82845G/GL[Brookdale-G]/GE/PE Host-to-AGP Bridge
+	2562  82845G/GL[Brookdale-G]/GE Chipset Integrated Graphics Device
+		1014 0267  NetVista A30p
+	2570  82865G/PE/P DRAM Controller/Host-Hub Interface
+		1043 80f2  P4P800 Mainboard
+		1458 2570  GA-8IPE1000 Pro2 motherboard (865PE)
+	2571  82865G/PE/P PCI to AGP Controller
+	2572  82865G Integrated Graphics Controller
+	2573  82865G/PE/P PCI to CSA Bridge
+	2576  82865G/PE/P Processor to I/O Memory Interface
+	2578  82875P/E7210 Memory Controller Hub
+		1458 2578  GA-8KNXP motherboard (875P)
+		1462 7580  MS-6758 (875P Neo)
+# Motherboard P4SCE
+		15d9 4580  Super Micro Computer Inc. P4SCE
+	2579  82875P Processor to AGP Controller
+	257b  82875P/E7210 Processor to PCI to CSA Bridge
+	257e  82875P/E7210 Processor to I/O Memory Interface
+	2580  915G/P/GV/GL/PL/910GL Processor to I/O Controller
+	2581  915G/P/GV/GL/PL/910GL PCI Express Root Port
+	2582  82915G/GV/910GL Express Chipset Family Graphics Controller
+		1028 1079  Optiplex GX280
+	2584  925X/XE Memory Controller Hub
+	2585  925X/XE PCI Express Root Port
+	2588  E7220/E7221 Memory Controller Hub
+	2589  E7220/E7221 PCI Express Root Port
+	258a  E7221 Integrated Graphics Controller
+	2590  Mobile 915GM/PM/GMS/910GML Express Processor to DRAM Controller
+	2591  Mobile 915GM/PM Express PCI Express Root Port
+	2592  Mobile 915GM/GMS/910GML Express Graphics Controller
+	25a1  6300ESB LPC Interface Controller
+	25a2  6300ESB PATA Storage Controller
+		4c53 10b0  CL9 mainboard
+	25a3  6300ESB SATA Storage Controller
+		4c53 10b0  CL9 mainboard
+	25a4  6300ESB SMBus Controller
+		4c53 10b0  CL9 mainboard
+	25a6  6300ESB AC'97 Audio Controller
+		4c53 10b0  CL9 mainboard
+	25a7  6300ESB AC'97 Modem Controller
+	25a9  6300ESB USB Universal Host Controller
+		4c53 10b0  CL9 mainboard
+	25aa  6300ESB USB Universal Host Controller
+		4c53 10b0  CL9 mainboard
+	25ab  6300ESB Watchdog Timer
+		4c53 10b0  CL9 mainboard
+	25ac  6300ESB I/O Advanced Programmable Interrupt Controller
+		4c53 10b0  CL9 mainboard
+	25ad  6300ESB USB2 Enhanced Host Controller
+	25ae  6300ESB 64-bit PCI-X Bridge
+	25b0  6300ESB SATA RAID Controller
+	2600  E8500 Hub Interface
+	2601  E8500 PCI Express x4 Port D
+	2602  E8500 PCI Express x4 Port C0
+	2603  E8500 PCI Express x4 Port C1
+	2604  E8500 PCI Express x4 Port B0
+	2605  E8500 PCI Express x4 Port B1
+	2606  E8500 PCI Express x4 Port A0
+	2607  E8500 PCI Express x4 Port A1
+	2608  E8500 PCI Express x8 Port C
+	2609  E8500 PCI Express x8 Port B
+	260a  E8500 PCI Express x8 Port A
+	260c  E8500 IMI Registers
+	2610  E8500 System Bus, Boot, and Interrupt Registers
+	2611  E8500 Address Mapping Registers
+	2612  E8500 RAS Registers
+	2613  E8500 Reserved Registers
+	2614  E8500 Reserved Registers
+	2615  E8500 Miscellaneous Registers
+	2617  E8500 Reserved Registers
+	2618  E8500 Reserved Registers
+	2619  E8500 Reserved Registers
+	261a  E8500 Reserved Registers
+	261b  E8500 Reserved Registers
+	261c  E8500 Reserved Registers
+	261d  E8500 Reserved Registers
+	261e  E8500 Reserved Registers
+	2620  E8500 eXternal Memory Bridge
+	2621  E8500 XMB Miscellaneous Registers
+	2622  E8500 XMB Memory Interleaving Registers
+	2623  E8500 XMB DDR Initialization and Calibration
+	2624  E8500 XMB Reserved Registers
+	2625  E8500 XMB Reserved Registers
+	2626  E8500 XMB Reserved Registers
+	2627  E8500 XMB Reserved Registers
+	2640  82801FB/FR (ICH6/ICH6R) LPC Interface Bridge
+	2641  82801FBM (ICH6M) LPC Interface Bridge
+	2642  82801FW/FRW (ICH6W/ICH6RW) LPC Interface Bridge
+	2651  82801FB/FW (ICH6/ICH6W) SATA Controller
+		1028 0179  Optiplex GX280
+	2652  82801FR/FRW (ICH6R/ICH6RW) SATA Controller
+	2653  82801FBM (ICH6M) SATA Controller
+	2658  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #1
+		1028 0179  Optiplex GX280
+	2659  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #2
+		1028 0179  Optiplex GX280
+	265a  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #3
+		1028 0179  Optiplex GX280
+	265b  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB UHCI #4
+		1028 0179  Optiplex GX280
+	265c  82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller
+		1028 0179  Optiplex GX280
+	2660  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 1
+	2662  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 2
+	2664  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 3
+	2666  82801FB/FBM/FR/FW/FRW (ICH6 Family) PCI Express Port 4
+	2668  82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller
+	266a  82801FB/FBM/FR/FW/FRW (ICH6 Family) SMBus Controller
+		1028 0179  Optiplex GX280
+	266c  82801FB/FBM/FR/FW/FRW (ICH6 Family) LAN Controller
+	266d  82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Modem Controller
+	266e  82801FB/FBM/FR/FW/FRW (ICH6 Family) AC'97 Audio Controller
+		1028 0179  Optiplex GX280
+	266f  82801FB/FBM/FR/FW/FRW (ICH6 Family) IDE Controller
+	2770  Memory Controller Hub
+	2771  PCI Express Graphics Port
+	2772  Integrated Graphics Controller
+	2774  Workstation Memory Controller Hub
+	2775  PCI Express Graphics Port
+	2776  Integrated Graphics Controller
+	2778  Server Memory Controller Hub
+	2779  PCI Express Root Port
+	2782  82915G Express Chipset Family Graphics Controller
+	2792  Mobile 915GM/GMS/910GML Express Graphics Controller
+	27b8  I/O Controller Hub LPC
+	27b9  Mobile I/O Controller Hub LPC
+	27c0  I/O Controller Hub SATA cc=IDE
+	27c1  I/O Controller Hub SATA cc=AHCI
+	27c3  I/O Controller Hub SATA cc=RAID
+	27c4  Mobile I/O Controller Hub SATA cc=IDE
+	27c5  Mobile I/O Controller Hub SATA cc=AHCI
+	27c8  I/O Controller Hub UHCI USB #1
+	27c9  I/O Controller Hub UHCI USB #2
+	27ca  I/O Controller Hub UHCI USB #3
+	27cb  I/O Controller Hub UHCI USB #4
+	27cc  I/O Controller Hub EHCI USB
+	27d0  I/O Controller Hub PCI Express Port 1
+	27d2  I/O Controller Hub PCI Express Port 2
+	27d4  I/O Controller Hub PCI Express Port 3
+	27d6  I/O Controller Hub PCI Express Port 4
+	27d8  I/O Controller Hub High Definition Audio
+	27da  I/O Controller Hub SMBus
+	27dc  I/O Controller Hub LAN
+	27dd  I/O Controller Hub AC'97 Modem
+	27de  I/O Controller Hub AC'97 Audio
+	27df  I/O Controller Hub PATA
+	27e0  I/O Controller Hub PCI Express Port 5
+	27e2  I/O Controller Hub PCI Express Port 6
+	3092  Integrated RAID
+	3200  GD31244 PCI-X SATA HBA
+	3340  82855PM Processor to I/O Controller
+		1025 005a  TravelMate 290
+		103c 088c  nc8000 laptop
+		103c 0890  nc6000 laptop
+	3341  82855PM Processor to AGP Controller
+	3575  82830 830 Chipset Host Bridge
+		1014 021d  ThinkPad A/T/X Series
+		104d 80e7  VAIO PCG-GR214EP/GR214MP/GR215MP/GR314MP/GR315MP
+	3576  82830 830 Chipset AGP Bridge
+	3577  82830 CGC [Chipset Graphics Controller]
+		1014 0513  ThinkPad A/T/X Series
+	3578  82830 830 Chipset Host Bridge
+	3580  82852/82855 GM/GME/PM/GMV Processor to I/O Controller
+		1028 0163  Latitude D505
+		4c53 10b0  CL9 mainboard
+	3581  82852/82855 GM/GME/PM/GMV Processor to AGP Controller
+	3582  82852/855GM Integrated Graphics Device
+		1028 0163  Latitude D505
+		4c53 10b0  CL9 mainboard
+	3584  82852/82855 GM/GME/PM/GMV Processor to I/O Controller
+		1028 0163  Latitude D505
+		4c53 10b0  CL9 mainboard
+	3585  82852/82855 GM/GME/PM/GMV Processor to I/O Controller
+		1028 0163  Latitude D505
+		4c53 10b0  CL9 mainboard
+	3590  E7520 Memory Controller Hub
+	3591  E7525/E7520 Error Reporting Registers
+	3592  E7320 Memory Controller Hub
+	3593  E7320 Error Reporting Registers
+	3594  E7520 DMA Controller
+	3595  E7525/E7520/E7320 PCI Express Port A
+	3596  E7525/E7520/E7320 PCI Express Port A1
+	3597  E7525/E7520 PCI Express Port B
+	3598  E7520 PCI Express Port B1
+	3599  E7520 PCI Express Port C
+	359a  E7520 PCI Express Port C1
+	359b  E7525/E7520/E7320 Extended Configuration Registers
+	359e  E7525 Memory Controller Hub
+	4220  PRO/Wireless 2200BG
+	4223  PRO/Wireless 2915ABG MiniPCI Adapter
+	5200  EtherExpress PRO/100 Intelligent Server
+	5201  EtherExpress PRO/100 Intelligent Server
+		8086 0001  EtherExpress PRO/100 Server Ethernet Adapter
+	530d  80310 IOP [IO Processor]
+	7000  82371SB PIIX3 ISA [Natoma/Triton II]
+	7010  82371SB PIIX3 IDE [Natoma/Triton II]
+	7020  82371SB PIIX3 USB [Natoma/Triton II]
+	7030  430VX - 82437VX TVX [Triton VX]
+	7050  Intel Intercast Video Capture Card
+	7100  430TX - 82439TX MTXC
+	7110  82371AB/EB/MB PIIX4 ISA
+		15ad 1976  virtualHW v3
+	7111  82371AB/EB/MB PIIX4 IDE
+		15ad 1976  virtualHW v3
+	7112  82371AB/EB/MB PIIX4 USB
+		15ad 1976  virtualHW v3
+	7113  82371AB/EB/MB PIIX4 ACPI
+		15ad 1976  virtualHW v3
+	7120  82810 GMCH [Graphics Memory Controller Hub]
+		4c53 1040  CL7 mainboard
+		4c53 1060  PC7 mainboard
+	7121  82810 CGC [Chipset Graphics Controller]
+		4c53 1040  CL7 mainboard
+		4c53 1060  PC7 mainboard
+		8086 4341  Cayman (CA810) Mainboard
+	7122  82810 DC-100 GMCH [Graphics Memory Controller Hub]
+	7123  82810 DC-100 CGC [Chipset Graphics Controller]
+	7124  82810E DC-133 GMCH [Graphics Memory Controller Hub]
+	7125  82810E DC-133 CGC [Chipset Graphics Controller]
+	7126  82810 DC-133 System and Graphics Controller
+	7128  82810-M DC-100 System and Graphics Controller
+	712a  82810-M DC-133 System and Graphics Controller
+	7180  440LX/EX - 82443LX/EX Host bridge
+	7181  440LX/EX - 82443LX/EX AGP bridge
+	7190  440BX/ZX/DX - 82443BX/ZX/DX Host bridge
+		0e11 0500  Armada 1750 Laptop System Chipset
+		0e11 b110  Armada M700/E500
+		1179 0001  Toshiba Tecra 8100 Laptop System Chipset
+		15ad 1976  virtualHW v3
+		4c53 1050  CT7 mainboard
+		4c53 1051  CE7 mainboard
+	7191  440BX/ZX/DX - 82443BX/ZX/DX AGP bridge
+	7192  440BX/ZX/DX - 82443BX/ZX/DX Host bridge (AGP disabled)
+		0e11 0460  Armada 1700 Laptop System Chipset
+		4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard
+	7194  82440MX Host Bridge
+		1033 0000  Versa Note Vxi
+		4c53 10a0  CA3/CR3 mainboard
+	7195  82440MX AC'97 Audio Controller
+		1033 80cc  Versa Note VXi
+		10cf 1099  QSound_SigmaTel Stac97 PCI Audio
+		11d4 0040  SoundMAX Integrated Digital Audio
+		11d4 0048  SoundMAX Integrated Digital Audio
+	7196  82440MX AC'97 Modem Controller
+	7198  82440MX ISA Bridge
+	7199  82440MX EIDE Controller
+	719a  82440MX USB Universal Host Controller
+	719b  82440MX Power Management Controller
+	71a0  440GX - 82443GX Host bridge
+		4c53 1050  CT7 mainboard
+		4c53 1051  CE7 mainboard
+	71a1  440GX - 82443GX AGP bridge
+	71a2  440GX - 82443GX Host bridge (AGP disabled)
+		4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard
+	7600  82372FB PIIX5 ISA
+	7601  82372FB PIIX5 IDE
+	7602  82372FB PIIX5 USB
+	7603  82372FB PIIX5 SMBus
+	7800  82740 (i740) AGP Graphics Accelerator
+		003d 0008  Starfighter AGP
+		003d 000b  Starfighter AGP
+		1092 0100  Stealth II G460
+		10b4 201a  Lightspeed 740
+		10b4 202f  Lightspeed 740
+		8086 0000  Terminator 2x/i
+		8086 0100  Intel740 Graphics Accelerator
+	84c4  450KX/GX [Orion] - 82454KX/GX PCI bridge
+	84c5  450KX/GX [Orion] - 82453KX/GX Memory controller
+	84ca  450NX - 82451NX Memory & I/O Controller
+	84cb  450NX - 82454NX/84460GX PCI Expander Bridge
+	84e0  460GX - 84460GX System Address Controller (SAC)
+	84e1  460GX - 84460GX System Data Controller (SDC)
+	84e2  460GX - 84460GX AGP Bridge (GXB function 2)
+	84e3  460GX - 84460GX Memory Address Controller (MAC)
+	84e4  460GX - 84460GX Memory Data Controller (MDC)
+	84e6  460GX - 82466GX Wide and fast PCI eXpander Bridge (WXB)
+	84ea  460GX - 84460GX AGP Bridge (GXB function 1)
+	8500  IXP4XX - Intel Network Processor family. IXP420, IXP421, IXP422, IXP425 and IXC1100
+		1993 0dee  mGuard-PCI AV#1
+		1993 0def  mGuard-PCI AV#0
+	9000  IXP2000 Family Network Processor
+	9001  IXP2400 Network Processor
+	9004  IXP2800 Network Processor
+	9621  Integrated RAID
+	9622  Integrated RAID
+	9641  Integrated RAID
+	96a1  Integrated RAID
+# retail verson
+	a01f  PRO/10GbE LR Server Adapter
+# OEM version
+	a11f  PRO/10GbE LR Server Adapter
+	b152  21152 PCI-to-PCI Bridge
+# observed, and documented in Intel revision note; new mask of 1011:0026
+	b154  21154 PCI-to-PCI Bridge
+	b555  21555 Non transparent PCI-to-PCI Bridge
+		12d9 000a  PCI VoIP Gateway
+		4c53 1050  CT7 mainboard
+		4c53 1051  CE7 mainboard
+		e4bf 1000  CC8-1-BLUES
+	ffff  450NX/GX [Orion] - 82453KX/GX Memory controller [BUG]
+8401  TRENDware International Inc.
+8800  Trigem Computer Inc.
+	2008  Video assistent component
+8866  T-Square Design Inc.
+8888  Silicon Magic
+# 8c4a is not Winbond but there is a board misprogrammed
+8c4a  Winbond
+	1980  W89C940 misprogrammed [ne2k]
+8e0e  Computone Corporation
+8e2e  KTI
+	3000  ET32P2
+9004  Adaptec
+	0078  AHA-2940U_CN
+	1078  AIC-7810
+	1160  AIC-1160 [Family Fibre Channel Adapter]
+	2178  AIC-7821
+	3860  AHA-2930CU
+	3b78  AHA-4844W/4844UW
+	5075  AIC-755x
+	5078  AHA-7850
+		9004 7850  AHA-2904/Integrated AIC-7850
+	5175  AIC-755x
+	5178  AIC-7851
+	5275  AIC-755x
+	5278  AIC-7852
+	5375  AIC-755x
+	5378  AIC-7850
+	5475  AIC-755x
+	5478  AIC-7850
+	5575  AVA-2930
+	5578  AIC-7855
+	5647  ANA-7711 TCP Offload Engine
+		9004 7710  ANA-7711F TCP Offload Engine - Optical
+		9004 7711  ANA-7711LP TCP Offload Engine - Copper
+	5675  AIC-755x
+	5678  AIC-7856
+	5775  AIC-755x
+	5778  AIC-7850
+	5800  AIC-5800
+	5900  ANA-5910/5930/5940 ATM155 & 25 LAN Adapter
+	5905  ANA-5910A/5930A/5940A ATM Adapter
+	6038  AIC-3860
+	6075  AIC-1480 / APA-1480
+		9004 7560  AIC-1480 / APA-1480 Cardbus
+	6078  AIC-7860
+	6178  AIC-7861
+		9004 7861  AHA-2940AU Single
+	6278  AIC-7860
+	6378  AIC-7860
+	6478  AIC-786x
+	6578  AIC-786x
+	6678  AIC-786x
+	6778  AIC-786x
+	6915  ANA620xx/ANA69011A
+		9004 0008  ANA69011A/TX 10/100
+		9004 0009  ANA69011A/TX 10/100
+		9004 0010  ANA62022 2-port 10/100
+		9004 0018  ANA62044 4-port 10/100
+		9004 0019  ANA62044 4-port 10/100
+		9004 0020  ANA62022 2-port 10/100
+		9004 0028  ANA69011A/TX 10/100
+		9004 8008  ANA69011A/TX 64 bit 10/100
+		9004 8009  ANA69011A/TX 64 bit 10/100
+		9004 8010  ANA62022 2-port 64 bit 10/100
+		9004 8018  ANA62044 4-port 64 bit 10/100
+		9004 8019  ANA62044 4-port 64 bit 10/100
+		9004 8020  ANA62022 2-port 64 bit 10/100
+		9004 8028  ANA69011A/TX 64 bit 10/100
+	7078  AHA-294x / AIC-7870
+	7178  AHA-2940/2940W / AIC-7871
+	7278  AHA-3940/3940W / AIC-7872
+	7378  AHA-3985 / AIC-7873
+	7478  AHA-2944/2944W / AIC-7874
+	7578  AHA-3944/3944W / AIC-7875
+	7678  AHA-4944W/UW / AIC-7876
+	7710  ANA-7711F Network Accelerator Card (NAC) - Optical
+	7711  ANA-7711C Network Accelerator Card (NAC) - Copper
+	7778  AIC-787x
+	7810  AIC-7810
+	7815  AIC-7815 RAID+Memory Controller IC
+		9004 7815  ARO-1130U2 RAID Controller
+		9004 7840  AIC-7815 RAID+Memory Controller IC
+	7850  AIC-7850
+	7855  AHA-2930
+	7860  AIC-7860
+	7870  AIC-7870
+	7871  AHA-2940
+	7872  AHA-3940
+	7873  AHA-3980
+	7874  AHA-2944
+	7880  AIC-7880P
+	7890  AIC-7890
+	7891  AIC-789x
+	7892  AIC-789x
+	7893  AIC-789x
+	7894  AIC-789x
+	7895  AHA-2940U/UW / AHA-39xx / AIC-7895
+		9004 7890  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+		9004 7891  AHA-2940U/2940UW Dual
+		9004 7892  AHA-3940AU/AUW/AUWD/UWD
+		9004 7894  AHA-3944AUWD
+		9004 7895  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+		9004 7896  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+		9004 7897  AHA-2940U/2940UW Dual AHA-394xAU/AUW/AUWD AIC-7895B
+	7896  AIC-789x
+	7897  AIC-789x
+	8078  AIC-7880U
+		9004 7880  AIC-7880P Ultra/Ultra Wide SCSI Chipset
+	8178  AHA-2940U/UW/D / AIC-7881U
+		9004 7881  AHA-2940UW SCSI Host Adapter
+	8278  AHA-3940U/UW/UWD / AIC-7882U
+	8378  AHA-3940U/UW / AIC-7883U
+	8478  AHA-2944UW / AIC-7884U
+	8578  AHA-3944U/UWD / AIC-7885
+	8678  AHA-4944UW / AIC-7886
+	8778  AHA-2940UW Pro / AIC-788x
+		9004 7887  2940UW Pro Ultra-Wide SCSI Controller
+	8878  AHA-2930UW / AIC-7888
+		9004 7888  AHA-2930UW SCSI Controller
+	8b78  ABA-1030
+	ec78  AHA-4944W/UW
+9005  Adaptec
+	0010  AHA-2940U2/U2W
+		9005 2180  AHA-2940U2 SCSI Controller
+		9005 8100  AHA-2940U2B SCSI Controller
+		9005 a100  AHA-2940U2B SCSI Controller
+		9005 a180  AHA-2940U2W SCSI Controller
+		9005 e100  AHA-2950U2B SCSI Controller
+	0011  AHA-2930U2
+	0013  78902
+		9005 0003  AAA-131U2 Array1000 1 Channel RAID Controller
+		9005 000f  AIC7890_ARO
+	001f  AHA-2940U2/U2W / 7890/7891
+		9005 000f  2940U2W SCSI Controller
+		9005 a180  2940U2W SCSI Controller
+	0020  AIC-7890
+	002f  AIC-7890
+	0030  AIC-7890
+	003f  AIC-7890
+	0050  AHA-3940U2x/395U2x
+		9005 f500  AHA-3950U2B
+		9005 ffff  AHA-3950U2B
+	0051  AHA-3950U2D
+		9005 b500  AHA-3950U2D
+	0053  AIC-7896 SCSI Controller
+		9005 ffff  AIC-7896 SCSI Controller mainboard implementation
+	005f  AIC-7896U2/7897U2
+	0080  AIC-7892A U160/m
+		0e11 e2a0  Compaq 64-Bit/66MHz Wide Ultra3 SCSI Adapter
+		9005 6220  AHA-29160C
+		9005 62a0  29160N Ultra160 SCSI Controller
+		9005 e220  29160LP Low Profile Ultra160 SCSI Controller
+		9005 e2a0  29160 Ultra160 SCSI Controller
+	0081  AIC-7892B U160/m
+		9005 62a1  19160 Ultra160 SCSI Controller
+	0083  AIC-7892D U160/m
+	008f  AIC-7892P U160/m
+		1179 0001  Magnia Z310
+		15d9 9005  Onboard SCSI Host Adapter
+	00c0  AHA-3960D / AIC-7899A U160/m
+		0e11 f620  Compaq 64-Bit/66MHz Dual Channel Wide Ultra3 SCSI Adapter
+		9005 f620  AHA-3960D U160/m
+	00c1  AIC-7899B U160/m
+	00c3  AIC-7899D U160/m
+	00c5  RAID subsystem HBA
+		1028 00c5  PowerEdge 2400,2500,2550,4400
+	00cf  AIC-7899P U160/m
+		1028 00ce  PowerEdge 1400
+		1028 00d1  PowerEdge 2550
+		1028 00d9  PowerEdge 2500
+		10f1 2462  Thunder K7 S2462
+		15d9 9005  Onboard SCSI Host Adapter
+		8086 3411  SDS2 Mainboard
+	0250  ServeRAID Controller
+		1014 0279  ServeRAID-xx
+		1014 028c  ServeRAID-xx
+# from kernel sources
+	0279  ServeRAID 6M
+	0283  AAC-RAID
+		9005 0283  Catapult
+	0284  AAC-RAID
+		9005 0284  Tomcat
+	0285  AAC-RAID
+		0e11 0295  SATA 6Ch (Bearcat)
+		1014 02f2  ServeRAID 8i
+		1028 0287  PowerEdge Expandable RAID Controller 320/DC
+		1028 0291  CERC SATA RAID 2 PCI SATA 6ch (DellCorsair)
+		103c 3227  AAR-2610SA
+		17aa 0286  Legend S220 (Legend Crusader)
+		17aa 0287  Legend S230 (Legend Vulcan)
+		9005 0285  2200S (Vulcan)
+		9005 0286  2120S (Crusader)
+		9005 0287  2200S (Vulcan-2m)
+		9005 0288  3230S (Harrier)
+		9005 0289  3240S (Tornado)
+		9005 028a  ASR-2020S PCI-X ZCR (Skyhawk)
+		9005 028b  ASR-2020S SO-DIMM PCI-X ZCR (Terminator)
+		9005 0290  AAR-2410SA PCI SATA 4ch (Jaguar II)
+		9005 0292  AAR-2810SA PCI SATA 8ch (Corsair-8)
+		9005 0293  AAR-21610SA PCI SATA 16ch (Corsair-16)
+		9005 0294  ESD SO-DIMM PCI-X SATA ZCR (Prowler)
+	0286  AAC-RAID (Rocket)
+		9005 028c  ASR-2230S + ASR-2230SLP PCI-X (Lancer)
+	0503  Scamp chipset SCSI controller
+		1014 02BF  Quad Channel PCI-X DDR U320 SCSI RAID Adapter (571E)
+	8000  ASC-29320A U320
+	800f  AIC-7901 U320
+	8010  ASC-39320 U320
+	8011  ASC-32320D U320
+		0e11 00ac  ASC-39320D U320
+		9005 0041  ASC-39320D U320
+	8012  ASC-29320 U320
+	8013  ASC-29320B U320
+	8014  ASC-29320LP U320
+	8015  ASC-39320B U320
+	8016  ASC-39320A U320
+	8017  ASC-29320ALP U320
+	801c  ASC-39320D U320
+	801d  AIC-7902B U320
+	801e  AIC-7901A U320
+	801f  AIC-7902 U320
+	8080  ASC-29320A U320 w/HostRAID
+	808f  AIC-7901 U320 w/HostRAID
+	8090  ASC-39320 U320 w/HostRAID
+	8091  ASC-39320D U320 w/HostRAID
+	8092  ASC-29320 U320 w/HostRAID
+	8093  ASC-29320B U320 w/HostRAID
+	8094  ASC-29320LP U320 w/HostRAID
+	8095  ASC-39320(B) U320 w/HostRAID
+	8096  ASC-39320A U320 w/HostRAID
+	8097  ASC-29320ALP U320 w/HostRAID
+	809c  ASC-39320D(B) U320 w/HostRAID
+	809d  AIC-7902(B) U320 w/HostRAID
+	809e  AIC-7901A U320 w/HostRAID
+	809f  AIC-7902 U320 w/HostRAID
+907f  Atronics
+	2015  IDE-2015PL
+919a  Gigapixel Corp
+9412  Holtek
+	6565  6565
+9699  Omni Media Technology Inc
+	6565  6565
+9710  NetMos Technology
+	7780  USB IRDA-port
+	9705  PCI 9705 Parallel Port
+	9715  PCI 9715 Dual Parallel Port
+	9735  PCI 9735 Multi-I/O Controller
+		1000 0002  0P2S (2 serial)
+		1000 0012  1P2S (1 parallel + 2 serial)
+	9745  PCI 9745 Multi-I/O Controller
+		1000 0002  0P2S (2 serial)
+		1000 0012  1P2S (1 parallel + 2 serial)
+	9755  PCI 9755 Parallel Port and ISA Bridge
+	9805  PCI 9805 Parallel Port
+	9815  PCI 9815 Dual Parallel Port
+		1000 0020  2P0S (2 port parallel adaptor)
+	9835  PCI 9835 Multi-I/O Controller
+		1000 0002  0P2S (16C550 UART)
+		1000 0012  1P2S
+	9845  PCI 9845 Multi-I/O Controller
+		1000 0004  0P4S (4 port 16550A serial card)
+		1000 0006  0P6S (6 port 16550A serial card)
+		1000 0014  1P4S (4 port 16550A serial card + parallel)
+	9855  PCI 9855 Multi-I/O Controller
+		1000 0014  1P4S
+9902  Stargen Inc.
+	0001  SG2010 PCI over Starfabric Bridge
+	0002  SG2010 PCI to Starfabric Gateway
+	0003  SG1010 Starfabric Switch and PCI Bridge
+a0a0  AOPEN Inc.
+a0f1  UNISYS Corporation
+a200  NEC Corporation
+a259  Hewlett Packard
+a25b  Hewlett Packard GmbH PL24-MKT
+a304  Sony
+a727  3Com Corporation
+	0013  3CRPAG175 Wireless PC Card
+aa42  Scitex Digital Video
+ac1e  Digital Receiver Technology Inc
+ac3d  Actuality Systems
+aecb  Adrienne Electronics Corporation
+b1b3  Shiva Europe Limited
+# Pinnacle should be 11bd, but they got it wrong several times --mj
+bd11  Pinnacle Systems, Inc. (Wrong ID)
+c001  TSI Telsys
+c0a9  Micron/Crucial Technology
+c0de  Motorola
+c0fe  Motion Engineering, Inc.
+ca50  Varian Australia Pty Ltd
+cafe  Chrysalis-ITS
+cccc  Catapult Communications
+cddd  Tyzx, Inc.
+	0101  DeepSea 1 High Speed Stereo Vision Frame Grabber
+	0200  DeepSea 2 High Speed Stereo Vision Frame Grabber
+d4d4  Dy4 Systems Inc
+	0601  PCI Mezzanine Card
+d531  I+ME ACTIA GmbH
+d84d  Exsys
+dead  Indigita Corporation
+deaf  Middle Digital Inc.
+	9050  PC Weasel Virtual VGA
+	9051  PC Weasel Serial Port
+	9052  PC Weasel Watchdog Timer
+e000  Winbond
+	e000  W89C940
+# see also : http://www.schoenfeld.de/inside/Inside_CWMK3.txt maybe a misuse of TJN id or it use the TJN 3XX chip for other applic
+e159  Tiger Jet Network Inc.
+	0001  Tiger3XX Modem/ISDN interface
+		0059 0001  128k ISDN-S/T Adapter
+		0059 0003  128k ISDN-U Adapter
+	0002  Tiger100APC ISDN chipset
+e4bf  EKF Elektronik GmbH
+# Innovative and scalable network IC vendor
+e55e  Essence Technology, Inc.
+ea01  Eagle Technology
+# The main chip of all these devices is by Xilinx -> It could also be a Xilinx ID.
+ea60  RME
+	9896  Digi32
+	9897  Digi32 Pro
+	9898  Digi32/8
+eabb  Aashima Technology B.V.
+eace  Endace Measurement Systems, Ltd
+	3100  DAG 3.10 OC-3/OC-12
+	3200  DAG 3.2x OC-3/OC-12
+	320e  DAG 3.2E Fast Ethernet
+	340e  DAG 3.4E Fast Ethernet
+	341e  DAG 3.41E Fast Ethernet
+	3500  DAG 3.5 OC-3/OC-12
+	351c  DAG 3.5ECM Fast Ethernet
+	4100  DAG 4.10 OC-48
+	4110  DAG 4.11 OC-48
+	4220  DAG 4.2 OC-48
+	422e  DAG 4.2E Dual Gigabit Ethernet
+ec80  Belkin Corporation
+	ec00  F5D6000
+ecc0  Echo Digital Audio Corporation
+edd8  ARK Logic Inc
+	a091  1000PV [Stingray]
+	a099  2000PV [Stingray]
+	a0a1  2000MT
+	a0a9  2000MI
+f1d0  AJA Video
+# All boards I have seen have this ID not efac, though all docs say efac...
+	cafe  KONA SD SMPTE 259M I/O
+	efac  KONA SD SMPTE 259M I/O
+	facd  KONA HD SMPTE 292M I/O
+fa57  Interagon AS
+	0001  PMC [Pattern Matching Chip]
+febd  Ultraview Corp.
+feda  Broadcom Inc (nee Epigram)
+	a0fa  BCM4210 iLine10 HomePNA 2.0
+	a10e  BCM4230 iLine10 HomePNA 2.0
+# IT & Telecom company, develops PCI Trunk cards <www.fedetec.es>
+fede  Fedetec Inc.
+	0003  TABIC PCI v3
+fffe  VMWare Inc
+	0405  Virtual SVGA 4.0
+	0710  Virtual SVGA
+ffff  Illegal Vendor ID
+
+
+# List of known device classes, subclasses and programming interfaces
+
+# Syntax:
+# C class	class_name
+#	subclass	subclass_name  		<-- single tab
+#		prog-if  prog-if_name  	<-- two tabs
+
+C 00  Unclassified device
+	00  Non-VGA unclassified device
+	01  VGA compatible unclassified device
+C 01  Mass storage controller
+	00  SCSI storage controller
+	01  IDE interface
+	02  Floppy disk controller
+	03  IPI bus controller
+	04  RAID bus controller
+	80  Unknown mass storage controller
+C 02  Network controller
+	00  Ethernet controller
+	01  Token ring network controller
+	02  FDDI network controller
+	03  ATM network controller
+	04  ISDN controller
+	80  Network controller
+C 03  Display controller
+	00  VGA compatible controller
+		00  VGA
+		01  8514
+	01  XGA compatible controller
+	02  3D controller
+	80  Display controller
+C 04  Multimedia controller
+	00  Multimedia video controller
+	01  Multimedia audio controller
+	02  Computer telephony device
+	80  Multimedia controller
+C 05  Memory controller
+	00  RAM memory
+	01  FLASH memory
+	80  Memory controller
+C 06  Bridge
+	00  Host bridge
+	01  ISA bridge
+	02  EISA bridge
+	03  MicroChannel bridge
+	04  PCI bridge
+		00  Normal decode
+		01  Subtractive decode
+	05  PCMCIA bridge
+	06  NuBus bridge
+	07  CardBus bridge
+	08  RACEway bridge
+		00  Transparent mode
+		01  Endpoint mode
+	09  Semi-transparent PCI-to-PCI bridge
+		40  Primary bus towards host CPU
+		80  Secondary bus towards host CPU
+	0a  InfiniBand to PCI host bridge
+	80  Bridge
+C 07  Communication controller
+	00  Serial controller
+		00  8250
+		01  16450
+		02  16550
+		03  16650
+		04  16750
+		05  16850
+		06  16950
+	01  Parallel controller
+		00  SPP
+		01  BiDir
+		02  ECP
+		03  IEEE1284
+		fe  IEEE1284 Target
+	02  Multiport serial controller
+	03  Modem
+		00  Generic
+		01  Hayes/16450
+		02  Hayes/16550
+		03  Hayes/16650
+		04  Hayes/16750
+	80  Communication controller
+C 08  Generic system peripheral
+	00  PIC
+		00  8259
+		01  ISA PIC
+		02  EISA PIC
+		10  IO-APIC
+		20  IO(X)-APIC
+	01  DMA controller
+		00  8237
+		01  ISA DMA
+		02  EISA DMA
+	02  Timer
+		00  8254
+		01  ISA Timer
+		02  EISA Timers
+	03  RTC
+		00  Generic
+		01  ISA RTC
+	04  PCI Hot-plug controller
+	80  System peripheral
+C 09  Input device controller
+	00  Keyboard controller
+	01  Digitizer Pen
+	02  Mouse controller
+	03  Scanner controller
+	04  Gameport controller
+		00  Generic
+		10  Extended
+	80  Input device controller
+C 0a  Docking station
+	00  Generic Docking Station
+	80  Docking Station
+C 0b  Processor
+	00  386
+	01  486
+	02  Pentium
+	10  Alpha
+	20  Power PC
+	30  MIPS
+	40  Co-processor
+C 0c  Serial bus controller
+	00  FireWire (IEEE 1394)
+		00  Generic
+		10  OHCI
+	01  ACCESS Bus
+	02  SSA
+	03  USB Controller
+		00  UHCI
+		10  OHCI
+		20  EHCI
+		80  Unspecified
+		fe  USB Device
+	04  Fibre Channel
+	05  SMBus
+	06  InfiniBand
+C 0d  Wireless controller
+	00  IRDA controller
+	01  Consumer IR controller
+	10  RF controller
+	80  Wireless controller
+C 0e  Intelligent controller
+	00  I2O
+C 0f  Satellite communications controller
+	00  Satellite TV controller
+	01  Satellite audio communication controller
+	03  Satellite voice communication controller
+	04  Satellite data communication controller
+C 10  Encryption controller
+	00  Network and computing encryption device
+	10  Entertainment encryption device
+	80  Encryption controller
+C 11  Signal processing controller
+	00  DPIO module
+	01  Performance counters
+	10  Communication synchronizer
+	80  Signal processing controller
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
new file mode 100644
index 0000000..1012db8
--- /dev/null
+++ b/drivers/pci/pcie/Kconfig
@@ -0,0 +1,36 @@
+#
+# PCI Express Port Bus Configuration
+#
+config PCIEPORTBUS
+	bool "PCI Express support"
+	depends on PCI
+	help
+	  This automatically enables PCI Express Port Bus support. Users can
+	  choose Native Hot-Plug support, Advanced Error Reporting support,
+	  Power Management Event support and Virtual Channel support to run
+	  on PCI Express Ports (Root or Switch).
+
+#
+# Include service Kconfig here
+#
+config HOTPLUG_PCI_PCIE
+	tristate "PCI Express Hotplug driver"
+	depends on HOTPLUG_PCI && PCIEPORTBUS
+	help
+	  Say Y here if you have a motherboard that supports PCI Express Native
+	  Hotplug
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pciehp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
+	bool "Use polling mechanism for hot-plug events (for testing purpose)"
+	depends on HOTPLUG_PCI_PCIE
+	help
+	  Say Y here if you want to use the polling mechanism for hot-plug 
+	  events for early platform testing.
+	   
+	  When in doubt, say N.
+
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
new file mode 100644
index 0000000..984fa87
--- /dev/null
+++ b/drivers/pci/pcie/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for PCI-Express PORT Driver
+#
+
+pcieportdrv-y			:= portdrv_core.o portdrv_pci.o portdrv_bus.o
+
+obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
new file mode 100644
index 0000000..6c3ad89
--- /dev/null
+++ b/drivers/pci/pcie/portdrv.h
@@ -0,0 +1,41 @@
+/*
+ * File:	portdrv.h
+ * Purpose:	PCI Express Port Bus Driver's Internal Data Structures
+ *
+ * Copyright (C) 2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#ifndef _PORTDRV_H_
+#define _PORTDRV_H_
+
+#if !defined(PCI_CAP_ID_PME)
+#define PCI_CAP_ID_PME			1
+#endif
+
+#if !defined(PCI_CAP_ID_EXP)
+#define PCI_CAP_ID_EXP			0x10
+#endif
+
+#define PORT_TYPE_MASK			0xf
+#define PORT_TO_SLOT_MASK		0x100
+#define SLOT_HP_CAPABLE_MASK		0x40
+#define PCIE_CAPABILITIES_REG		0x2
+#define PCIE_SLOT_CAPABILITIES_REG	0x14
+#define PCIE_PORT_DEVICE_MAXSERVICES	4
+#define PCI_CFG_SPACE_SIZE		256
+
+#define get_descriptor_id(type, service) (((type - 4) << 4) | service)
+
+extern struct bus_type pcie_port_bus_type;
+extern int pcie_port_device_probe(struct pci_dev *dev);
+extern int pcie_port_device_register(struct pci_dev *dev);
+#ifdef CONFIG_PM
+extern int pcie_port_device_suspend(struct pci_dev *dev, u32 state);
+extern int pcie_port_device_resume(struct pci_dev *dev);
+#endif
+extern void pcie_port_device_remove(struct pci_dev *dev);
+extern void pcie_port_bus_register(void);
+extern void pcie_port_bus_unregister(void);
+
+#endif /* _PORTDRV_H_ */
diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c
new file mode 100644
index 0000000..9a02f28
--- /dev/null
+++ b/drivers/pci/pcie/portdrv_bus.c
@@ -0,0 +1,77 @@
+/*
+ * File:	portdrv_bus.c
+ * Purpose:	PCI Express Port Bus Driver's Bus Overloading Functions
+ *
+ * Copyright (C) 2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+
+#include <linux/pcieport_if.h>
+
+static int pcie_port_bus_match(struct device *dev, struct device_driver *drv);
+static int pcie_port_bus_suspend(struct device *dev, u32 state);
+static int pcie_port_bus_resume(struct device *dev);
+
+struct bus_type pcie_port_bus_type = {
+	.name 		= "pci_express",
+	.match 		= pcie_port_bus_match,
+	.suspend	= pcie_port_bus_suspend,
+	.resume		= pcie_port_bus_resume, 
+};
+
+static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct pcie_device *pciedev;
+	struct pcie_port_service_driver *driver;
+
+	if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type)
+		return 0;
+	
+	pciedev = to_pcie_device(dev);
+	driver = to_service_driver(drv);
+	if (   (driver->id_table->vendor != PCI_ANY_ID && 
+		driver->id_table->vendor != pciedev->id.vendor) ||
+	       (driver->id_table->device != PCI_ANY_ID &&
+		driver->id_table->device != pciedev->id.device) ||	
+		driver->id_table->port_type != pciedev->id.port_type ||
+		driver->id_table->service_type != pciedev->id.service_type )
+		return 0;
+
+	return 1;
+}
+
+static int pcie_port_bus_suspend(struct device *dev, u32 state)
+{
+	struct pcie_device *pciedev;
+	struct pcie_port_service_driver *driver;
+
+	if (!dev || !dev->driver)
+		return 0;
+
+	pciedev = to_pcie_device(dev);
+ 	driver = to_service_driver(dev->driver);
+	if (driver && driver->suspend)
+		driver->suspend(pciedev, state);
+	return 0;
+}
+
+static int pcie_port_bus_resume(struct device *dev)
+{
+	struct pcie_device *pciedev;
+	struct pcie_port_service_driver *driver;
+
+	if (!dev || !dev->driver)
+		return 0;
+
+	pciedev = to_pcie_device(dev);
+ 	driver = to_service_driver(dev->driver);
+	if (driver && driver->resume)
+		driver->resume(pciedev);
+	return 0;
+}
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
new file mode 100644
index 0000000..127f64f
--- /dev/null
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -0,0 +1,434 @@
+/*
+ * File:	portdrv_core.c
+ * Purpose:	PCI Express Port Bus Driver's Core Functions
+ *
+ * Copyright (C) 2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/pcieport_if.h>
+
+#include "portdrv.h"
+
+extern int pcie_mch_quirk;	/* MSI-quirk Indicator */
+
+static int pcie_port_probe_service(struct device *dev)
+{
+	struct pcie_device *pciedev;
+	struct pcie_port_service_driver *driver;
+	int status = -ENODEV;
+
+	if (!dev || !dev->driver)
+		return status;
+
+ 	driver = to_service_driver(dev->driver);
+	if (!driver || !driver->probe)
+		return status;
+
+	pciedev = to_pcie_device(dev);
+	status = driver->probe(pciedev, driver->id_table);
+	if (!status) {
+		printk(KERN_DEBUG "Load service driver %s on pcie device %s\n",
+			driver->name, dev->bus_id);
+		get_device(dev);
+	}
+	return status;
+}
+
+static int pcie_port_remove_service(struct device *dev)
+{
+	struct pcie_device *pciedev;
+	struct pcie_port_service_driver *driver;
+
+	if (!dev || !dev->driver)
+		return 0;
+
+	pciedev = to_pcie_device(dev);
+ 	driver = to_service_driver(dev->driver);
+	if (driver && driver->remove) { 
+		printk(KERN_DEBUG "Unload service driver %s on pcie device %s\n",
+			driver->name, dev->bus_id);
+		driver->remove(pciedev);
+		put_device(dev);
+	}
+	return 0;
+}
+
+static void pcie_port_shutdown_service(struct device *dev) {}
+
+static int pcie_port_suspend_service(struct device *dev, u32 state, u32 level)
+{
+	struct pcie_device *pciedev;
+	struct pcie_port_service_driver *driver;
+
+	if (!dev || !dev->driver)
+		return 0;
+
+	pciedev = to_pcie_device(dev);
+ 	driver = to_service_driver(dev->driver);
+	if (driver && driver->suspend)
+		driver->suspend(pciedev, state);
+	return 0;
+}
+
+static int pcie_port_resume_service(struct device *dev, u32 state)
+{
+	struct pcie_device *pciedev;
+	struct pcie_port_service_driver *driver;
+
+	if (!dev || !dev->driver)
+		return 0;
+
+	pciedev = to_pcie_device(dev);
+ 	driver = to_service_driver(dev->driver);
+
+	if (driver && driver->resume)
+		driver->resume(pciedev);
+	return 0;
+}
+
+/*
+ * release_pcie_device
+ *	
+ *	Being invoked automatically when device is being removed 
+ *	in response to device_unregister(dev) call.
+ *	Release all resources being claimed.
+ */
+static void release_pcie_device(struct device *dev)
+{
+	printk(KERN_DEBUG "Free Port Service[%s]\n", dev->bus_id);
+	kfree(to_pcie_device(dev));			
+}
+
+static int is_msi_quirked(struct pci_dev *dev)
+{
+	int port_type, quirk = 0;
+	u16 reg16;
+
+	pci_read_config_word(dev, 
+		pci_find_capability(dev, PCI_CAP_ID_EXP) + 
+		PCIE_CAPABILITIES_REG, &reg16);
+	port_type = (reg16 >> 4) & PORT_TYPE_MASK;
+	switch(port_type) {
+	case PCIE_RC_PORT:
+		if (pcie_mch_quirk == 1)
+			quirk = 1;
+		break;
+	case PCIE_SW_UPSTREAM_PORT:
+	case PCIE_SW_DOWNSTREAM_PORT:
+	default:
+		break;	
+	}
+	return quirk;
+}
+	
+static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
+{
+	int i, pos, nvec, status = -EINVAL;
+	int interrupt_mode = PCIE_PORT_INTx_MODE;
+
+	/* Set INTx as default */
+	for (i = 0, nvec = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
+		if (mask & (1 << i)) 
+			nvec++;
+		vectors[i] = dev->irq;
+	}
+	
+	/* Check MSI quirk */
+	if (is_msi_quirked(dev))
+		return interrupt_mode;
+
+	/* Select MSI-X over MSI if supported */		
+	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+	if (pos) {
+		struct msix_entry msix_entries[PCIE_PORT_DEVICE_MAXSERVICES] = 
+			{{0, 0}, {0, 1}, {0, 2}, {0, 3}};
+		printk("%s Found MSIX capability\n", __FUNCTION__);
+		status = pci_enable_msix(dev, msix_entries, nvec);
+		if (!status) {
+			int j = 0;
+
+			interrupt_mode = PCIE_PORT_MSIX_MODE;
+			for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
+				if (mask & (1 << i)) 
+					vectors[i] = msix_entries[j++].vector;
+			}
+		}
+	} 
+	if (status) {
+		pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+		if (pos) {
+			printk("%s Found MSI capability\n", __FUNCTION__);
+			status = pci_enable_msi(dev);
+			if (!status) {
+				interrupt_mode = PCIE_PORT_MSI_MODE;
+				for (i = 0;i < PCIE_PORT_DEVICE_MAXSERVICES;i++)
+					vectors[i] = dev->irq;
+			}
+		}
+	} 
+	return interrupt_mode;
+}
+
+static int get_port_device_capability(struct pci_dev *dev)
+{
+	int services = 0, pos;
+	u16 reg16;
+	u32 reg32;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+	pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg16);
+	/* Hot-Plug Capable */
+	if (reg16 & PORT_TO_SLOT_MASK) {
+		pci_read_config_dword(dev, 
+			pos + PCIE_SLOT_CAPABILITIES_REG, &reg32);
+		if (reg32 & SLOT_HP_CAPABLE_MASK)
+			services |= PCIE_PORT_SERVICE_HP;
+	} 
+	/* PME Capable */
+	pos = pci_find_capability(dev, PCI_CAP_ID_PME);
+	if (pos) 
+		services |= PCIE_PORT_SERVICE_PME;
+	
+	pos = PCI_CFG_SPACE_SIZE;
+	while (pos) {
+		pci_read_config_dword(dev, pos, &reg32);
+		switch (reg32 & 0xffff) {
+		case PCI_EXT_CAP_ID_ERR:
+			services |= PCIE_PORT_SERVICE_AER;
+			pos = reg32 >> 20;
+			break;
+		case PCI_EXT_CAP_ID_VC:
+			services |= PCIE_PORT_SERVICE_VC;
+			pos = reg32 >> 20;
+			break;
+		default:
+			pos = 0;
+			break;
+		}
+	}
+
+	return services;
+}
+
+static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, 
+	int port_type, int service_type, int irq, int irq_mode)
+{
+	struct device *device;
+
+	dev->port = parent;
+	dev->interrupt_mode = irq_mode;
+	dev->irq = irq;
+	dev->id.vendor = parent->vendor;
+	dev->id.device = parent->device;
+	dev->id.port_type = port_type;
+	dev->id.service_type = (1 << service_type);
+
+	/* Initialize generic device interface */
+	device = &dev->device;
+	memset(device, 0, sizeof(struct device));
+	INIT_LIST_HEAD(&device->node);
+	INIT_LIST_HEAD(&device->children);
+	INIT_LIST_HEAD(&device->bus_list);
+	device->bus = &pcie_port_bus_type;
+	device->driver = NULL;
+	device->driver_data = NULL; 
+	device->release = release_pcie_device;	/* callback to free pcie dev */
+	sprintf(&device->bus_id[0], "pcie%02x", 
+		get_descriptor_id(port_type, service_type));
+	device->parent = &parent->dev;
+}
+
+static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, 
+	int port_type, int service_type, int irq, int irq_mode)
+{
+	struct pcie_device *device;
+
+	device = kmalloc(sizeof(struct pcie_device), GFP_KERNEL);
+	if (!device)
+		return NULL;
+
+	memset(device, 0, sizeof(struct pcie_device));
+	pcie_device_init(parent, device, port_type, service_type, irq,irq_mode);
+	printk(KERN_DEBUG "Allocate Port Service[%s]\n", device->device.bus_id);
+	return device;
+}
+
+int pcie_port_device_probe(struct pci_dev *dev)
+{
+	int pos, type;
+	u16 reg;
+
+	if (!(pos = pci_find_capability(dev, PCI_CAP_ID_EXP)))
+		return -ENODEV;
+
+	pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg);
+	type = (reg >> 4) & PORT_TYPE_MASK;
+	if (	type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT ||
+		type == PCIE_SW_DOWNSTREAM_PORT )  
+		return 0;
+ 
+	return -ENODEV;
+}
+
+int pcie_port_device_register(struct pci_dev *dev)
+{
+	int status, type, capabilities, irq_mode, i;
+	int vectors[PCIE_PORT_DEVICE_MAXSERVICES];
+	u16 reg16;
+
+	/* Get port type */
+	pci_read_config_word(dev, 
+		pci_find_capability(dev, PCI_CAP_ID_EXP) + 
+		PCIE_CAPABILITIES_REG, &reg16);
+	type = (reg16 >> 4) & PORT_TYPE_MASK;
+
+	/* Now get port services */
+	capabilities = get_port_device_capability(dev);
+	irq_mode = assign_interrupt_mode(dev, vectors, capabilities);
+
+	/* Allocate child services if any */
+	for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
+		struct pcie_device *child;
+
+		if (capabilities & (1 << i)) {
+			child = alloc_pcie_device(
+				dev, 		/* parent */
+				type,		/* port type */ 
+				i,		/* service type */
+				vectors[i],	/* irq */
+				irq_mode	/* interrupt mode */);
+			if (child) { 
+				status = device_register(&child->device);
+				if (status) {
+					kfree(child);
+					continue;
+				}
+				get_device(&child->device);
+			}
+		}
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+int pcie_port_device_suspend(struct pci_dev *dev, u32 state)
+{
+	struct list_head 		*head, *tmp;
+	struct device 			*parent, *child;
+	struct device_driver 		*driver;
+	struct pcie_port_service_driver *service_driver;
+
+	parent = &dev->dev;
+	head = &parent->children;
+	tmp = head->next;
+	while (head != tmp) {
+		child = container_of(tmp, struct device, node);
+		tmp = tmp->next;
+		if (child->bus != &pcie_port_bus_type)
+			continue;
+		driver = child->driver;
+		if (!driver)
+			continue;
+		service_driver = to_service_driver(driver);
+		if (service_driver->suspend)  
+			service_driver->suspend(to_pcie_device(child), state);
+	}
+	return 0; 
+}
+
+int pcie_port_device_resume(struct pci_dev *dev) 
+{ 
+	struct list_head 		*head, *tmp;
+	struct device 			*parent, *child;
+	struct device_driver 		*driver;
+	struct pcie_port_service_driver *service_driver;
+
+	parent = &dev->dev;
+	head = &parent->children;
+	tmp = head->next;
+	while (head != tmp) {
+		child = container_of(tmp, struct device, node);
+		tmp = tmp->next;
+		if (child->bus != &pcie_port_bus_type)
+			continue;
+		driver = child->driver;
+		if (!driver)
+			continue;
+		service_driver = to_service_driver(driver);
+		if (service_driver->resume)  
+			service_driver->resume(to_pcie_device(child));
+	}
+	return 0; 
+
+}
+#endif
+
+void pcie_port_device_remove(struct pci_dev *dev)
+{
+	struct list_head 		*head, *tmp;
+	struct device 			*parent, *child;
+	struct device_driver 		*driver;
+	struct pcie_port_service_driver *service_driver;
+	int interrupt_mode = PCIE_PORT_INTx_MODE;
+
+	parent = &dev->dev;
+	head = &parent->children;
+	tmp = head->next;
+	while (head != tmp) {
+		child = container_of(tmp, struct device, node);
+		tmp = tmp->next;
+		if (child->bus != &pcie_port_bus_type)
+			continue;
+		driver = child->driver;
+		if (driver) { 
+			service_driver = to_service_driver(driver);
+			if (service_driver->remove)  
+				service_driver->remove(to_pcie_device(child));
+		}
+		interrupt_mode = (to_pcie_device(child))->interrupt_mode;
+		put_device(child);
+		device_unregister(child);
+	}
+	/* Switch to INTx by default if MSI enabled */
+	if (interrupt_mode == PCIE_PORT_MSIX_MODE)
+		pci_disable_msix(dev);
+	else if (interrupt_mode == PCIE_PORT_MSI_MODE)
+		pci_disable_msi(dev);
+}
+
+void pcie_port_bus_register(void)
+{
+	bus_register(&pcie_port_bus_type);
+}
+
+void pcie_port_bus_unregister(void)
+{
+	bus_unregister(&pcie_port_bus_type);
+}
+
+int pcie_port_service_register(struct pcie_port_service_driver *new)
+{
+	new->driver.name = (char *)new->name;
+	new->driver.bus = &pcie_port_bus_type;
+	new->driver.probe = pcie_port_probe_service;
+	new->driver.remove = pcie_port_remove_service;
+	new->driver.shutdown = pcie_port_shutdown_service;
+	new->driver.suspend = pcie_port_suspend_service;
+	new->driver.resume = pcie_port_resume_service;
+
+	return driver_register(&new->driver);
+} 
+
+void pcie_port_service_unregister(struct pcie_port_service_driver *new)
+{
+	driver_unregister(&new->driver);
+}
+
+EXPORT_SYMBOL(pcie_port_service_register);
+EXPORT_SYMBOL(pcie_port_service_unregister);
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
new file mode 100644
index 0000000..3184843
--- /dev/null
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -0,0 +1,122 @@
+/*
+ * File:	portdrv_pci.c
+ * Purpose:	PCI Express Port Bus Driver
+ *
+ * Copyright (C) 2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/pcieport_if.h>
+
+#include "portdrv.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
+#define DRIVER_DESC "PCIE Port Bus Driver"
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/* global data */
+static const char device_name[] = "pcieport-driver";
+
+/*
+ * pcie_portdrv_probe - Probe PCI-Express port devices
+ * @dev: PCI-Express port device being probed
+ *
+ * If detected invokes the pcie_port_device_register() method for 
+ * this port device.
+ *
+ */
+static int __devinit pcie_portdrv_probe (struct pci_dev *dev, 
+				const struct pci_device_id *id )
+{
+	int			status;
+
+	status = pcie_port_device_probe(dev);
+	if (status)
+		return status;
+
+	if (pci_enable_device(dev) < 0) 
+		return -ENODEV;
+	
+	pci_set_master(dev);
+        if (!dev->irq) {
+		printk(KERN_WARNING 
+		"%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n", 
+		__FUNCTION__, dev->device, dev->vendor);
+	}
+	if (pcie_port_device_register(dev)) 
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void pcie_portdrv_remove (struct pci_dev *dev)
+{
+	pcie_port_device_remove(dev);
+}
+
+#ifdef CONFIG_PM
+static int pcie_portdrv_suspend (struct pci_dev *dev, u32 state)
+{
+	return pcie_port_device_suspend(dev, state);
+}
+
+static int pcie_portdrv_resume (struct pci_dev *dev)
+{
+	return pcie_port_device_resume(dev);
+}
+#endif
+
+/*
+ * LINUX Device Driver Model
+ */
+static const struct pci_device_id port_pci_ids[] = { {
+	/* handle any PCI-Express port */
+	PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0),
+	}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, port_pci_ids);
+
+static struct pci_driver pcie_portdrv = {
+	.name		= (char *)device_name,
+	.id_table	= &port_pci_ids[0],
+
+	.probe		= pcie_portdrv_probe,
+	.remove		= pcie_portdrv_remove,
+
+#ifdef	CONFIG_PM
+	.suspend	= pcie_portdrv_suspend,
+	.resume		= pcie_portdrv_resume,
+#endif	/* PM */
+};
+
+static int __init pcie_portdrv_init(void)
+{
+	int retval = 0;
+
+	pcie_port_bus_register();
+	retval = pci_register_driver(&pcie_portdrv);
+	if (retval)
+		pcie_port_bus_unregister();
+	return retval;
+}
+
+static void __exit pcie_portdrv_exit(void) 
+{
+	pci_unregister_driver(&pcie_portdrv);
+	pcie_port_bus_unregister();
+}
+
+module_init(pcie_portdrv_init);
+module_exit(pcie_portdrv_exit);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
new file mode 100644
index 0000000..6f0edad
--- /dev/null
+++ b/drivers/pci/probe.c
@@ -0,0 +1,939 @@
+/*
+ * probe.c - PCI detection and setup code
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/cpumask.h>
+
+#define CARDBUS_LATENCY_TIMER	176	/* secondary latency timer */
+#define CARDBUS_RESERVE_BUSNR	3
+#define PCI_CFG_SPACE_SIZE	256
+#define PCI_CFG_SPACE_EXP_SIZE	4096
+
+/* Ugh.  Need to stop exporting this to modules. */
+LIST_HEAD(pci_root_buses);
+EXPORT_SYMBOL(pci_root_buses);
+
+LIST_HEAD(pci_devices);
+
+#ifdef HAVE_PCI_LEGACY
+/**
+ * pci_create_legacy_files - create legacy I/O port and memory files
+ * @b: bus to create files under
+ *
+ * Some platforms allow access to legacy I/O port and ISA memory space on
+ * a per-bus basis.  This routine creates the files and ties them into
+ * their associated read, write and mmap files from pci-sysfs.c
+ */
+static void pci_create_legacy_files(struct pci_bus *b)
+{
+	b->legacy_io = kmalloc(sizeof(struct bin_attribute) * 2,
+			       GFP_ATOMIC);
+	if (b->legacy_io) {
+		memset(b->legacy_io, 0, sizeof(struct bin_attribute) * 2);
+		b->legacy_io->attr.name = "legacy_io";
+		b->legacy_io->size = 0xffff;
+		b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
+		b->legacy_io->attr.owner = THIS_MODULE;
+		b->legacy_io->read = pci_read_legacy_io;
+		b->legacy_io->write = pci_write_legacy_io;
+		class_device_create_bin_file(&b->class_dev, b->legacy_io);
+
+		/* Allocated above after the legacy_io struct */
+		b->legacy_mem = b->legacy_io + 1;
+		b->legacy_mem->attr.name = "legacy_mem";
+		b->legacy_mem->size = 1024*1024;
+		b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
+		b->legacy_mem->attr.owner = THIS_MODULE;
+		b->legacy_mem->mmap = pci_mmap_legacy_mem;
+		class_device_create_bin_file(&b->class_dev, b->legacy_mem);
+	}
+}
+
+void pci_remove_legacy_files(struct pci_bus *b)
+{
+	if (b->legacy_io) {
+		class_device_remove_bin_file(&b->class_dev, b->legacy_io);
+		class_device_remove_bin_file(&b->class_dev, b->legacy_mem);
+		kfree(b->legacy_io); /* both are allocated here */
+	}
+}
+#else /* !HAVE_PCI_LEGACY */
+static inline void pci_create_legacy_files(struct pci_bus *bus) { return; }
+void pci_remove_legacy_files(struct pci_bus *bus) { return; }
+#endif /* HAVE_PCI_LEGACY */
+
+/*
+ * PCI Bus Class Devices
+ */
+static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, char *buf)
+{
+	cpumask_t cpumask = pcibus_to_cpumask(to_pci_bus(class_dev));
+	int ret;
+
+	ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
+	if (ret < PAGE_SIZE)
+		buf[ret++] = '\n';
+	return ret;
+}
+CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
+
+/*
+ * PCI Bus Class
+ */
+static void release_pcibus_dev(struct class_device *class_dev)
+{
+	struct pci_bus *pci_bus = to_pci_bus(class_dev);
+
+	if (pci_bus->bridge)
+		put_device(pci_bus->bridge);
+	kfree(pci_bus);
+}
+
+static struct class pcibus_class = {
+	.name		= "pci_bus",
+	.release	= &release_pcibus_dev,
+};
+
+static int __init pcibus_class_init(void)
+{
+	return class_register(&pcibus_class);
+}
+postcore_initcall(pcibus_class_init);
+
+/*
+ * Translate the low bits of the PCI base
+ * to the resource type
+ */
+static inline unsigned int pci_calc_resource_flags(unsigned int flags)
+{
+	if (flags & PCI_BASE_ADDRESS_SPACE_IO)
+		return IORESOURCE_IO;
+
+	if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
+		return IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+	return IORESOURCE_MEM;
+}
+
+/*
+ * Find the extent of a PCI decode..
+ */
+static u32 pci_size(u32 base, u32 maxbase, unsigned long mask)
+{
+	u32 size = mask & maxbase;	/* Find the significant bits */
+	if (!size)
+		return 0;
+
+	/* Get the lowest of them to find the decode size, and
+	   from that the extent.  */
+	size = (size & ~(size-1)) - 1;
+
+	/* base == maxbase can be valid only if the BAR has
+	   already been programmed with all 1s.  */
+	if (base == maxbase && ((base | size) & mask) != mask)
+		return 0;
+
+	return size;
+}
+
+static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
+{
+	unsigned int pos, reg, next;
+	u32 l, sz;
+	struct resource *res;
+
+	for(pos=0; pos<howmany; pos = next) {
+		next = pos+1;
+		res = &dev->resource[pos];
+		res->name = pci_name(dev);
+		reg = PCI_BASE_ADDRESS_0 + (pos << 2);
+		pci_read_config_dword(dev, reg, &l);
+		pci_write_config_dword(dev, reg, ~0);
+		pci_read_config_dword(dev, reg, &sz);
+		pci_write_config_dword(dev, reg, l);
+		if (!sz || sz == 0xffffffff)
+			continue;
+		if (l == 0xffffffff)
+			l = 0;
+		if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+			sz = pci_size(l, sz, PCI_BASE_ADDRESS_MEM_MASK);
+			if (!sz)
+				continue;
+			res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
+			res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
+		} else {
+			sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
+			if (!sz)
+				continue;
+			res->start = l & PCI_BASE_ADDRESS_IO_MASK;
+			res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
+		}
+		res->end = res->start + (unsigned long) sz;
+		res->flags |= pci_calc_resource_flags(l);
+		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+			pci_read_config_dword(dev, reg+4, &l);
+			next++;
+#if BITS_PER_LONG == 64
+			res->start |= ((unsigned long) l) << 32;
+			res->end = res->start + sz;
+			pci_write_config_dword(dev, reg+4, ~0);
+			pci_read_config_dword(dev, reg+4, &sz);
+			pci_write_config_dword(dev, reg+4, l);
+			sz = pci_size(l, sz, 0xffffffff);
+			if (sz) {
+				/* This BAR needs > 4GB?  Wow. */
+				res->end |= (unsigned long)sz<<32;
+			}
+#else
+			if (l) {
+				printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev));
+				res->start = 0;
+				res->flags = 0;
+				continue;
+			}
+#endif
+		}
+	}
+	if (rom) {
+		dev->rom_base_reg = rom;
+		res = &dev->resource[PCI_ROM_RESOURCE];
+		res->name = pci_name(dev);
+		pci_read_config_dword(dev, rom, &l);
+		pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
+		pci_read_config_dword(dev, rom, &sz);
+		pci_write_config_dword(dev, rom, l);
+		if (l == 0xffffffff)
+			l = 0;
+		if (sz && sz != 0xffffffff) {
+			sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK);
+			if (sz) {
+				res->flags = (l & IORESOURCE_ROM_ENABLE) |
+				  IORESOURCE_MEM | IORESOURCE_PREFETCH |
+				  IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+				res->start = l & PCI_ROM_ADDRESS_MASK;
+				res->end = res->start + (unsigned long) sz;
+			}
+		}
+	}
+}
+
+void __devinit pci_read_bridge_bases(struct pci_bus *child)
+{
+	struct pci_dev *dev = child->self;
+	u8 io_base_lo, io_limit_lo;
+	u16 mem_base_lo, mem_limit_lo;
+	unsigned long base, limit;
+	struct resource *res;
+	int i;
+
+	if (!dev)		/* It's a host bus, nothing to read */
+		return;
+
+	if (dev->transparent) {
+		printk(KERN_INFO "PCI: Transparent bridge - %s\n", pci_name(dev));
+		for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++)
+			child->resource[i] = child->parent->resource[i];
+		return;
+	}
+
+	for(i=0; i<3; i++)
+		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
+	res = child->resource[0];
+	pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
+	pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
+	base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
+	limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
+
+	if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
+		u16 io_base_hi, io_limit_hi;
+		pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
+		pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
+		base |= (io_base_hi << 16);
+		limit |= (io_limit_hi << 16);
+	}
+
+	if (base <= limit) {
+		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+		res->start = base;
+		res->end = limit + 0xfff;
+	}
+
+	res = child->resource[1];
+	pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
+	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
+	base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
+	limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
+	if (base <= limit) {
+		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
+		res->start = base;
+		res->end = limit + 0xfffff;
+	}
+
+	res = child->resource[2];
+	pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
+	pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
+	base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
+	limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
+
+	if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
+		u32 mem_base_hi, mem_limit_hi;
+		pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
+		pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
+
+		/*
+		 * Some bridges set the base > limit by default, and some
+		 * (broken) BIOSes do not initialize them.  If we find
+		 * this, just assume they are not being used.
+		 */
+		if (mem_base_hi <= mem_limit_hi) {
+#if BITS_PER_LONG == 64
+			base |= ((long) mem_base_hi) << 32;
+			limit |= ((long) mem_limit_hi) << 32;
+#else
+			if (mem_base_hi || mem_limit_hi) {
+				printk(KERN_ERR "PCI: Unable to handle 64-bit address space for bridge %s\n", pci_name(dev));
+				return;
+			}
+#endif
+		}
+	}
+	if (base <= limit) {
+		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
+		res->start = base;
+		res->end = limit + 0xfffff;
+	}
+}
+
+static struct pci_bus * __devinit pci_alloc_bus(void)
+{
+	struct pci_bus *b;
+
+	b = kmalloc(sizeof(*b), GFP_KERNEL);
+	if (b) {
+		memset(b, 0, sizeof(*b));
+		INIT_LIST_HEAD(&b->node);
+		INIT_LIST_HEAD(&b->children);
+		INIT_LIST_HEAD(&b->devices);
+	}
+	return b;
+}
+
+static struct pci_bus * __devinit
+pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
+{
+	struct pci_bus *child;
+	int i;
+
+	/*
+	 * Allocate a new bus, and inherit stuff from the parent..
+	 */
+	child = pci_alloc_bus();
+	if (!child)
+		return NULL;
+
+	child->self = bridge;
+	child->parent = parent;
+	child->ops = parent->ops;
+	child->sysdata = parent->sysdata;
+	child->bridge = get_device(&bridge->dev);
+
+	child->class_dev.class = &pcibus_class;
+	sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr);
+	class_device_register(&child->class_dev);
+	class_device_create_file(&child->class_dev, &class_device_attr_cpuaffinity);
+
+	/*
+	 * Set up the primary, secondary and subordinate
+	 * bus numbers.
+	 */
+	child->number = child->secondary = busnr;
+	child->primary = parent->secondary;
+	child->subordinate = 0xff;
+
+	/* Set up default resource pointers and names.. */
+	for (i = 0; i < 4; i++) {
+		child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];
+		child->resource[i]->name = child->name;
+	}
+	bridge->subordinate = child;
+
+	return child;
+}
+
+struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+{
+	struct pci_bus *child;
+
+	child = pci_alloc_child_bus(parent, dev, busnr);
+	if (child)
+		list_add_tail(&child->node, &parent->children);
+	return child;
+}
+
+static void pci_enable_crs(struct pci_dev *dev)
+{
+	u16 cap, rpctl;
+	int rpcap = pci_find_capability(dev, PCI_CAP_ID_EXP);
+	if (!rpcap)
+		return;
+
+	pci_read_config_word(dev, rpcap + PCI_CAP_FLAGS, &cap);
+	if (((cap & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_ROOT_PORT)
+		return;
+
+	pci_read_config_word(dev, rpcap + PCI_EXP_RTCTL, &rpctl);
+	rpctl |= PCI_EXP_RTCTL_CRSSVE;
+	pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl);
+}
+
+unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus);
+
+/*
+ * If it's a bridge, configure it and scan the bus behind it.
+ * For CardBus bridges, we don't scan behind as the devices will
+ * be handled by the bridge driver itself.
+ *
+ * We need to process bridges in two passes -- first we scan those
+ * already configured by the BIOS and after we are done with all of
+ * them, we proceed to assigning numbers to the remaining buses in
+ * order to avoid overlaps between old and new bus numbers.
+ */
+int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
+{
+	struct pci_bus *child;
+	int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+	u32 buses;
+	u16 bctl;
+
+	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+
+	pr_debug("PCI: Scanning behind PCI bridge %s, config %06x, pass %d\n",
+		 pci_name(dev), buses & 0xffffff, pass);
+
+	/* Disable MasterAbortMode during probing to avoid reporting
+	   of bus errors (in some architectures) */ 
+	pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl);
+	pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
+			      bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
+
+	pci_enable_crs(dev);
+
+	if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) {
+		unsigned int cmax, busnr;
+		/*
+		 * Bus already configured by firmware, process it in the first
+		 * pass and just note the configuration.
+		 */
+		if (pass)
+			return max;
+		busnr = (buses >> 8) & 0xFF;
+
+		/*
+		 * If we already got to this bus through a different bridge,
+		 * ignore it.  This can happen with the i450NX chipset.
+		 */
+		if (pci_find_bus(pci_domain_nr(bus), busnr)) {
+			printk(KERN_INFO "PCI: Bus %04x:%02x already known\n",
+					pci_domain_nr(bus), busnr);
+			return max;
+		}
+
+		child = pci_alloc_child_bus(bus, dev, busnr);
+		if (!child)
+			return max;
+		child->primary = buses & 0xFF;
+		child->subordinate = (buses >> 16) & 0xFF;
+		child->bridge_ctl = bctl;
+
+		cmax = pci_scan_child_bus(child);
+		if (cmax > max)
+			max = cmax;
+		if (child->subordinate > max)
+			max = child->subordinate;
+	} else {
+		/*
+		 * We need to assign a number to this bus which we always
+		 * do in the second pass.
+		 */
+		if (!pass)
+			return max;
+
+		/* Clear errors */
+		pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
+		child = pci_alloc_child_bus(bus, dev, ++max);
+		buses = (buses & 0xff000000)
+		      | ((unsigned int)(child->primary)     <<  0)
+		      | ((unsigned int)(child->secondary)   <<  8)
+		      | ((unsigned int)(child->subordinate) << 16);
+
+		/*
+		 * yenta.c forces a secondary latency timer of 176.
+		 * Copy that behaviour here.
+		 */
+		if (is_cardbus) {
+			buses &= ~0xff000000;
+			buses |= CARDBUS_LATENCY_TIMER << 24;
+		}
+			
+		/*
+		 * We need to blast all three values with a single write.
+		 */
+		pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
+
+		if (!is_cardbus) {
+			child->bridge_ctl = PCI_BRIDGE_CTL_NO_ISA;
+
+			/* Now we can scan all subordinate buses... */
+			max = pci_scan_child_bus(child);
+		} else {
+			/*
+			 * For CardBus bridges, we leave 4 bus numbers
+			 * as cards with a PCI-to-PCI bridge can be
+			 * inserted later.
+			 */
+			max += CARDBUS_RESERVE_BUSNR;
+		}
+		/*
+		 * Set the subordinate bus number to its real value.
+		 */
+		child->subordinate = max;
+		pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+	}
+
+	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
+
+	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+
+	return max;
+}
+
+/*
+ * Read interrupt line and base address registers.
+ * The architecture-dependent code can tweak these, of course.
+ */
+static void pci_read_irq(struct pci_dev *dev)
+{
+	unsigned char irq;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
+	if (irq)
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+}
+
+/**
+ * pci_setup_device - fill in class and map information of a device
+ * @dev: the device structure to fill
+ *
+ * Initialize the device structure with information about the device's 
+ * vendor,class,memory and IO-space addresses,IRQ lines etc.
+ * Called at initialisation of the PCI subsystem and by CardBus services.
+ * Returns 0 on success and -1 if unknown type of device (not normal, bridge
+ * or CardBus).
+ */
+static int pci_setup_device(struct pci_dev * dev)
+{
+	u32 class;
+
+	sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
+		dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+	class >>= 8;				    /* upper 3 bytes */
+	dev->class = class;
+	class >>= 8;
+
+	pr_debug("PCI: Found %s [%04x/%04x] %06x %02x\n", pci_name(dev),
+		 dev->vendor, dev->device, class, dev->hdr_type);
+
+	/* "Unknown power state" */
+	dev->current_state = 4;
+
+	/* Early fixups, before probing the BARs */
+	pci_fixup_device(pci_fixup_early, dev);
+	class = dev->class >> 8;
+
+	switch (dev->hdr_type) {		    /* header type */
+	case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
+		if (class == PCI_CLASS_BRIDGE_PCI)
+			goto bad;
+		pci_read_irq(dev);
+		pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
+		pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
+		pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
+		break;
+
+	case PCI_HEADER_TYPE_BRIDGE:		    /* bridge header */
+		if (class != PCI_CLASS_BRIDGE_PCI)
+			goto bad;
+		/* The PCI-to-PCI bridge spec requires that subtractive
+		   decoding (i.e. transparent) bridge must have programming
+		   interface code of 0x01. */ 
+		dev->transparent = ((dev->class & 0xff) == 1);
+		pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
+		break;
+
+	case PCI_HEADER_TYPE_CARDBUS:		    /* CardBus bridge header */
+		if (class != PCI_CLASS_BRIDGE_CARDBUS)
+			goto bad;
+		pci_read_irq(dev);
+		pci_read_bases(dev, 1, 0);
+		pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
+		pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
+		break;
+
+	default:				    /* unknown header */
+		printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
+			pci_name(dev), dev->hdr_type);
+		return -1;
+
+	bad:
+		printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
+		       pci_name(dev), class, dev->hdr_type);
+		dev->class = PCI_CLASS_NOT_DEFINED;
+	}
+
+	/* We found a fine healthy device, go go go... */
+	return 0;
+}
+
+/**
+ * pci_release_dev - free a pci device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this pci device are
+ * done.
+ */
+static void pci_release_dev(struct device *dev)
+{
+	struct pci_dev *pci_dev;
+
+	pci_dev = to_pci_dev(dev);
+	kfree(pci_dev);
+}
+
+/**
+ * pci_cfg_space_size - get the configuration space size of the PCI device.
+ *
+ * Regular PCI devices have 256 bytes, but PCI-X 2 and PCI Express devices
+ * have 4096 bytes.  Even if the device is capable, that doesn't mean we can
+ * access it.  Maybe we don't have a way to generate extended config space
+ * accesses, or the device is behind a reverse Express bridge.  So we try
+ * reading the dword at 0x100 which must either be 0 or a valid extended
+ * capability header.
+ */
+static int pci_cfg_space_size(struct pci_dev *dev)
+{
+	int pos;
+	u32 status;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+	if (!pos) {
+		pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+		if (!pos)
+			goto fail;
+
+		pci_read_config_dword(dev, pos + PCI_X_STATUS, &status);
+		if (!(status & (PCI_X_STATUS_266MHZ | PCI_X_STATUS_533MHZ)))
+			goto fail;
+	}
+
+	if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL)
+		goto fail;
+	if (status == 0xffffffff)
+		goto fail;
+
+	return PCI_CFG_SPACE_EXP_SIZE;
+
+ fail:
+	return PCI_CFG_SPACE_SIZE;
+}
+
+static void pci_release_bus_bridge_dev(struct device *dev)
+{
+	kfree(dev);
+}
+
+/*
+ * Read the config data for a PCI device, sanity-check it
+ * and fill in the dev structure...
+ */
+static struct pci_dev * __devinit
+pci_scan_device(struct pci_bus *bus, int devfn)
+{
+	struct pci_dev *dev;
+	u32 l;
+	u8 hdr_type;
+	int delay = 1;
+
+	if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
+		return NULL;
+
+	/* some broken boards return 0 or ~0 if a slot is empty: */
+	if (l == 0xffffffff || l == 0x00000000 ||
+	    l == 0x0000ffff || l == 0xffff0000)
+		return NULL;
+
+	/* Configuration request Retry Status */
+	while (l == 0xffff0001) {
+		msleep(delay);
+		delay *= 2;
+		if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
+			return NULL;
+		/* Card hasn't responded in 60 seconds?  Must be stuck. */
+		if (delay > 60 * 1000) {
+			printk(KERN_WARNING "Device %04x:%02x:%02x.%d not "
+					"responding\n", pci_domain_nr(bus),
+					bus->number, PCI_SLOT(devfn),
+					PCI_FUNC(devfn));
+			return NULL;
+		}
+	}
+
+	if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
+		return NULL;
+
+	dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	memset(dev, 0, sizeof(struct pci_dev));
+	dev->bus = bus;
+	dev->sysdata = bus->sysdata;
+	dev->dev.parent = bus->bridge;
+	dev->dev.bus = &pci_bus_type;
+	dev->devfn = devfn;
+	dev->hdr_type = hdr_type & 0x7f;
+	dev->multifunction = !!(hdr_type & 0x80);
+	dev->vendor = l & 0xffff;
+	dev->device = (l >> 16) & 0xffff;
+	dev->cfg_size = pci_cfg_space_size(dev);
+
+	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
+	   set this higher, assuming the system even supports it.  */
+	dev->dma_mask = 0xffffffff;
+	if (pci_setup_device(dev) < 0) {
+		kfree(dev);
+		return NULL;
+	}
+	device_initialize(&dev->dev);
+	dev->dev.release = pci_release_dev;
+	pci_dev_get(dev);
+
+	pci_name_device(dev);
+
+	dev->dev.dma_mask = &dev->dma_mask;
+	dev->dev.coherent_dma_mask = 0xffffffffull;
+
+	return dev;
+}
+
+struct pci_dev * __devinit
+pci_scan_single_device(struct pci_bus *bus, int devfn)
+{
+	struct pci_dev *dev;
+
+	dev = pci_scan_device(bus, devfn);
+	pci_scan_msi_device(dev);
+
+	if (!dev)
+		return NULL;
+	
+	/* Fix up broken headers */
+	pci_fixup_device(pci_fixup_header, dev);
+
+	/*
+	 * Add the device to our list of discovered devices
+	 * and the bus list for fixup functions, etc.
+	 */
+	INIT_LIST_HEAD(&dev->global_list);
+	list_add_tail(&dev->bus_list, &bus->devices);
+
+	return dev;
+}
+
+/**
+ * pci_scan_slot - scan a PCI slot on a bus for devices.
+ * @bus: PCI bus to scan
+ * @devfn: slot number to scan (must have zero function.)
+ *
+ * Scan a PCI slot on the specified PCI bus for devices, adding
+ * discovered devices to the @bus->devices list.  New devices
+ * will have an empty dev->global_list head.
+ */
+int __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
+{
+	int func, nr = 0;
+	int scan_all_fns;
+
+	scan_all_fns = pcibios_scan_all_fns(bus, devfn);
+
+	for (func = 0; func < 8; func++, devfn++) {
+		struct pci_dev *dev;
+
+		dev = pci_scan_single_device(bus, devfn);
+		if (dev) {
+			nr++;
+
+			/*
+		 	 * If this is a single function device,
+		 	 * don't scan past the first function.
+		 	 */
+			if (!dev->multifunction) {
+				if (func > 0) {
+					dev->multifunction = 1;
+				} else {
+ 					break;
+				}
+			}
+		} else {
+			if (func == 0 && !scan_all_fns)
+				break;
+		}
+	}
+	return nr;
+}
+
+unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
+{
+	unsigned int devfn, pass, max = bus->secondary;
+	struct pci_dev *dev;
+
+	pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(bus), bus->number);
+
+	/* Go find them, Rover! */
+	for (devfn = 0; devfn < 0x100; devfn += 8)
+		pci_scan_slot(bus, devfn);
+
+	/*
+	 * After performing arch-dependent fixup of the bus, look behind
+	 * all PCI-to-PCI bridges on this bus.
+	 */
+	pr_debug("PCI: Fixups for bus %04x:%02x\n", pci_domain_nr(bus), bus->number);
+	pcibios_fixup_bus(bus);
+	for (pass=0; pass < 2; pass++)
+		list_for_each_entry(dev, &bus->devices, bus_list) {
+			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+				max = pci_scan_bridge(bus, dev, max, pass);
+		}
+
+	/*
+	 * We've scanned the bus and so we know all about what's on
+	 * the other side of any bridges that may be on this bus plus
+	 * any devices.
+	 *
+	 * Return how far we've got finding sub-buses.
+	 */
+	pr_debug("PCI: Bus scan for %04x:%02x returning with max=%02x\n",
+		pci_domain_nr(bus), bus->number, max);
+	return max;
+}
+
+unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
+{
+	unsigned int max;
+
+	max = pci_scan_child_bus(bus);
+
+	/*
+	 * Make the discovered devices available.
+	 */
+	pci_bus_add_devices(bus);
+
+	return max;
+}
+
+struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata)
+{
+	int error;
+	struct pci_bus *b;
+	struct device *dev;
+
+	b = pci_alloc_bus();
+	if (!b)
+		return NULL;
+
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev){
+		kfree(b);
+		return NULL;
+	}
+
+	b->sysdata = sysdata;
+	b->ops = ops;
+
+	if (pci_find_bus(pci_domain_nr(b), bus)) {
+		/* If we already got to this bus through a different bridge, ignore it */
+		pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus);
+		goto err_out;
+	}
+	list_add_tail(&b->node, &pci_root_buses);
+
+	memset(dev, 0, sizeof(*dev));
+	dev->parent = parent;
+	dev->release = pci_release_bus_bridge_dev;
+	sprintf(dev->bus_id, "pci%04x:%02x", pci_domain_nr(b), bus);
+	error = device_register(dev);
+	if (error)
+		goto dev_reg_err;
+	b->bridge = get_device(dev);
+
+	b->class_dev.class = &pcibus_class;
+	sprintf(b->class_dev.class_id, "%04x:%02x", pci_domain_nr(b), bus);
+	error = class_device_register(&b->class_dev);
+	if (error)
+		goto class_dev_reg_err;
+	error = class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity);
+	if (error)
+		goto class_dev_create_file_err;
+
+	/* Create legacy_io and legacy_mem files for this bus */
+	pci_create_legacy_files(b);
+
+	error = sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge");
+	if (error)
+		goto sys_create_link_err;
+
+	b->number = b->secondary = bus;
+	b->resource[0] = &ioport_resource;
+	b->resource[1] = &iomem_resource;
+
+	b->subordinate = pci_scan_child_bus(b);
+
+	pci_bus_add_devices(b);
+
+	return b;
+
+sys_create_link_err:
+	class_device_remove_file(&b->class_dev, &class_device_attr_cpuaffinity);
+class_dev_create_file_err:
+	class_device_unregister(&b->class_dev);
+class_dev_reg_err:
+	device_unregister(dev);
+dev_reg_err:
+	list_del(&b->node);
+err_out:
+	kfree(dev);
+	kfree(b);
+	return NULL;
+}
+EXPORT_SYMBOL(pci_scan_bus_parented);
+
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_add_new_bus);
+EXPORT_SYMBOL(pci_do_scan_bus);
+EXPORT_SYMBOL(pci_scan_slot);
+EXPORT_SYMBOL(pci_scan_bridge);
+EXPORT_SYMBOL(pci_scan_single_device);
+EXPORT_SYMBOL_GPL(pci_scan_child_bus);
+#endif
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
new file mode 100644
index 0000000..84cc4f6
--- /dev/null
+++ b/drivers/pci/proc.c
@@ -0,0 +1,619 @@
+/*
+ *	$Id: proc.c,v 1.13 1998/05/12 07:36:07 mj Exp $
+ *
+ *	Procfs interface for the PCI bus.
+ *
+ *	Copyright (c) 1997--1999 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+static int proc_initialized;	/* = 0 */
+
+static loff_t
+proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
+{
+	loff_t new = -1;
+	struct inode *inode = file->f_dentry->d_inode;
+
+	down(&inode->i_sem);
+	switch (whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	case 2:
+		new = inode->i_size + off;
+		break;
+	}
+	if (new < 0 || new > inode->i_size)
+		new = -EINVAL;
+	else
+		file->f_pos = new;
+	up(&inode->i_sem);
+	return new;
+}
+
+static ssize_t
+proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+{
+	const struct inode *ino = file->f_dentry->d_inode;
+	const struct proc_dir_entry *dp = PDE(ino);
+	struct pci_dev *dev = dp->data;
+	unsigned int pos = *ppos;
+	unsigned int cnt, size;
+
+	/*
+	 * Normal users can read only the standardized portion of the
+	 * configuration space as several chips lock up when trying to read
+	 * undefined locations (think of Intel PIIX4 as a typical example).
+	 */
+
+	if (capable(CAP_SYS_ADMIN))
+		size = dev->cfg_size;
+	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+		size = 128;
+	else
+		size = 64;
+
+	if (pos >= size)
+		return 0;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
+	cnt = nbytes;
+
+	if (!access_ok(VERIFY_WRITE, buf, cnt))
+		return -EINVAL;
+
+	if ((pos & 1) && cnt) {
+		unsigned char val;
+		pci_read_config_byte(dev, pos, &val);
+		__put_user(val, buf);
+		buf++;
+		pos++;
+		cnt--;
+	}
+
+	if ((pos & 3) && cnt > 2) {
+		unsigned short val;
+		pci_read_config_word(dev, pos, &val);
+		__put_user(cpu_to_le16(val), (unsigned short __user *) buf);
+		buf += 2;
+		pos += 2;
+		cnt -= 2;
+	}
+
+	while (cnt >= 4) {
+		unsigned int val;
+		pci_read_config_dword(dev, pos, &val);
+		__put_user(cpu_to_le32(val), (unsigned int __user *) buf);
+		buf += 4;
+		pos += 4;
+		cnt -= 4;
+	}
+
+	if (cnt >= 2) {
+		unsigned short val;
+		pci_read_config_word(dev, pos, &val);
+		__put_user(cpu_to_le16(val), (unsigned short __user *) buf);
+		buf += 2;
+		pos += 2;
+		cnt -= 2;
+	}
+
+	if (cnt) {
+		unsigned char val;
+		pci_read_config_byte(dev, pos, &val);
+		__put_user(val, buf);
+		buf++;
+		pos++;
+		cnt--;
+	}
+
+	*ppos = pos;
+	return nbytes;
+}
+
+static ssize_t
+proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
+{
+	const struct inode *ino = file->f_dentry->d_inode;
+	const struct proc_dir_entry *dp = PDE(ino);
+	struct pci_dev *dev = dp->data;
+	int pos = *ppos;
+	int size = dev->cfg_size;
+	int cnt;
+
+	if (pos >= size)
+		return 0;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
+	cnt = nbytes;
+
+	if (!access_ok(VERIFY_READ, buf, cnt))
+		return -EINVAL;
+
+	if ((pos & 1) && cnt) {
+		unsigned char val;
+		__get_user(val, buf);
+		pci_write_config_byte(dev, pos, val);
+		buf++;
+		pos++;
+		cnt--;
+	}
+
+	if ((pos & 3) && cnt > 2) {
+		unsigned short val;
+		__get_user(val, (unsigned short __user *) buf);
+		pci_write_config_word(dev, pos, le16_to_cpu(val));
+		buf += 2;
+		pos += 2;
+		cnt -= 2;
+	}
+
+	while (cnt >= 4) {
+		unsigned int val;
+		__get_user(val, (unsigned int __user *) buf);
+		pci_write_config_dword(dev, pos, le32_to_cpu(val));
+		buf += 4;
+		pos += 4;
+		cnt -= 4;
+	}
+
+	if (cnt >= 2) {
+		unsigned short val;
+		__get_user(val, (unsigned short __user *) buf);
+		pci_write_config_word(dev, pos, le16_to_cpu(val));
+		buf += 2;
+		pos += 2;
+		cnt -= 2;
+	}
+
+	if (cnt) {
+		unsigned char val;
+		__get_user(val, buf);
+		pci_write_config_byte(dev, pos, val);
+		buf++;
+		pos++;
+		cnt--;
+	}
+
+	*ppos = pos;
+	return nbytes;
+}
+
+struct pci_filp_private {
+	enum pci_mmap_state mmap_state;
+	int write_combine;
+};
+
+static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	const struct proc_dir_entry *dp = PDE(inode);
+	struct pci_dev *dev = dp->data;
+#ifdef HAVE_PCI_MMAP
+	struct pci_filp_private *fpriv = file->private_data;
+#endif /* HAVE_PCI_MMAP */
+	int ret = 0;
+
+	switch (cmd) {
+	case PCIIOC_CONTROLLER:
+		ret = pci_domain_nr(dev->bus);
+		break;
+
+#ifdef HAVE_PCI_MMAP
+	case PCIIOC_MMAP_IS_IO:
+		fpriv->mmap_state = pci_mmap_io;
+		break;
+
+	case PCIIOC_MMAP_IS_MEM:
+		fpriv->mmap_state = pci_mmap_mem;
+		break;
+
+	case PCIIOC_WRITE_COMBINE:
+		if (arg)
+			fpriv->write_combine = 1;
+		else
+			fpriv->write_combine = 0;
+		break;
+
+#endif /* HAVE_PCI_MMAP */
+
+	default:
+		ret = -EINVAL;
+		break;
+	};
+
+	return ret;
+}
+
+#ifdef HAVE_PCI_MMAP
+static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	const struct proc_dir_entry *dp = PDE(inode);
+	struct pci_dev *dev = dp->data;
+	struct pci_filp_private *fpriv = file->private_data;
+	int ret;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	ret = pci_mmap_page_range(dev, vma,
+				  fpriv->mmap_state,
+				  fpriv->write_combine);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int proc_bus_pci_open(struct inode *inode, struct file *file)
+{
+	struct pci_filp_private *fpriv = kmalloc(sizeof(*fpriv), GFP_KERNEL);
+
+	if (!fpriv)
+		return -ENOMEM;
+
+	fpriv->mmap_state = pci_mmap_io;
+	fpriv->write_combine = 0;
+
+	file->private_data = fpriv;
+
+	return 0;
+}
+
+static int proc_bus_pci_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	file->private_data = NULL;
+
+	return 0;
+}
+#endif /* HAVE_PCI_MMAP */
+
+static struct file_operations proc_bus_pci_operations = {
+	.llseek		= proc_bus_pci_lseek,
+	.read		= proc_bus_pci_read,
+	.write		= proc_bus_pci_write,
+	.ioctl		= proc_bus_pci_ioctl,
+#ifdef HAVE_PCI_MMAP
+	.open		= proc_bus_pci_open,
+	.release	= proc_bus_pci_release,
+	.mmap		= proc_bus_pci_mmap,
+#ifdef HAVE_ARCH_PCI_GET_UNMAPPED_AREA
+	.get_unmapped_area = get_pci_unmapped_area,
+#endif /* HAVE_ARCH_PCI_GET_UNMAPPED_AREA */
+#endif /* HAVE_PCI_MMAP */
+};
+
+#if BITS_PER_LONG == 32
+#define LONG_FORMAT "\t%08lx"
+#else
+#define LONG_FORMAT "\t%16lx"
+#endif
+
+/* iterator */
+static void *pci_seq_start(struct seq_file *m, loff_t *pos)
+{
+	struct pci_dev *dev = NULL;
+	loff_t n = *pos;
+
+	for_each_pci_dev(dev) {
+		if (!n--)
+			break;
+	}
+	return dev;
+}
+
+static void *pci_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct pci_dev *dev = v;
+
+	(*pos)++;
+	dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+	return dev;
+}
+
+static void pci_seq_stop(struct seq_file *m, void *v)
+{
+	if (v) {
+		struct pci_dev *dev = v;
+		pci_dev_put(dev);
+	}
+}
+
+static int show_device(struct seq_file *m, void *v)
+{
+	const struct pci_dev *dev = v;
+	const struct pci_driver *drv;
+	int i;
+
+	if (dev == NULL)
+		return 0;
+
+	drv = pci_dev_driver(dev);
+	seq_printf(m, "%02x%02x\t%04x%04x\t%x",
+			dev->bus->number,
+			dev->devfn,
+			dev->vendor,
+			dev->device,
+			dev->irq);
+	/* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
+	for(i=0; i<7; i++)
+		seq_printf(m, LONG_FORMAT,
+			dev->resource[i].start |
+			(dev->resource[i].flags & PCI_REGION_FLAG_MASK));
+	for(i=0; i<7; i++)
+		seq_printf(m, LONG_FORMAT,
+			dev->resource[i].start < dev->resource[i].end ?
+			dev->resource[i].end - dev->resource[i].start + 1 : 0);
+	seq_putc(m, '\t');
+	if (drv)
+		seq_printf(m, "%s", drv->name);
+	seq_putc(m, '\n');
+	return 0;
+}
+
+static struct seq_operations proc_bus_pci_devices_op = {
+	.start	= pci_seq_start,
+	.next	= pci_seq_next,
+	.stop	= pci_seq_stop,
+	.show	= show_device
+};
+
+static struct proc_dir_entry *proc_bus_pci_dir;
+
+int pci_proc_attach_device(struct pci_dev *dev)
+{
+	struct pci_bus *bus = dev->bus;
+	struct proc_dir_entry *e;
+	char name[16];
+
+	if (!proc_initialized)
+		return -EACCES;
+
+	if (!bus->procdir) {
+		if (pci_proc_domain(bus)) {
+			sprintf(name, "%04x:%02x", pci_domain_nr(bus),
+					bus->number);
+		} else {
+			sprintf(name, "%02x", bus->number);
+		}
+		bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
+		if (!bus->procdir)
+			return -ENOMEM;
+	}
+
+	sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir);
+	if (!e)
+		return -ENOMEM;
+	e->proc_fops = &proc_bus_pci_operations;
+	e->data = dev;
+	e->size = dev->cfg_size;
+	dev->procent = e;
+
+	return 0;
+}
+
+int pci_proc_detach_device(struct pci_dev *dev)
+{
+	struct proc_dir_entry *e;
+
+	if ((e = dev->procent)) {
+		if (atomic_read(&e->count))
+			return -EBUSY;
+		remove_proc_entry(e->name, dev->bus->procdir);
+		dev->procent = NULL;
+	}
+	return 0;
+}
+
+int pci_proc_attach_bus(struct pci_bus* bus)
+{
+	struct proc_dir_entry *de = bus->procdir;
+
+	if (!proc_initialized)
+		return -EACCES;
+
+	if (!de) {
+		char name[16];
+		sprintf(name, "%02x", bus->number);
+		de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
+		if (!de)
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+int pci_proc_detach_bus(struct pci_bus* bus)
+{
+	struct proc_dir_entry *de = bus->procdir;
+	if (de)
+		remove_proc_entry(de->name, proc_bus_pci_dir);
+	return 0;
+}
+
+#ifdef CONFIG_PCI_LEGACY_PROC
+
+/*
+ *  Backward compatible /proc/pci interface.
+ */
+
+/*
+ * Convert some of the configuration space registers of the device at
+ * address (bus,devfn) into a string (possibly several lines each).
+ * The configuration string is stored starting at buf[len].  If the
+ * string would exceed the size of the buffer (SIZE), 0 is returned.
+ */
+static int show_dev_config(struct seq_file *m, void *v)
+{
+	struct pci_dev *dev = v;
+	struct pci_dev *first_dev;
+	struct pci_driver *drv;
+	u32 class_rev;
+	unsigned char latency, min_gnt, max_lat, *class;
+	int reg;
+
+	first_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
+	if (dev == first_dev)
+		seq_puts(m, "PCI devices found:\n");
+	pci_dev_put(first_dev);
+
+	drv = pci_dev_driver(dev);
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+	pci_read_config_byte (dev, PCI_MIN_GNT, &min_gnt);
+	pci_read_config_byte (dev, PCI_MAX_LAT, &max_lat);
+	seq_printf(m, "  Bus %2d, device %3d, function %2d:\n",
+	       dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	class = pci_class_name(class_rev >> 16);
+	if (class)
+		seq_printf(m, "    %s", class);
+	else
+		seq_printf(m, "    Class %04x", class_rev >> 16);
+#ifdef CONFIG_PCI_NAMES
+	seq_printf(m, ": %s", dev->pretty_name);
+#else
+	seq_printf(m, ": PCI device %04x:%04x", dev->vendor, dev->device);
+#endif
+	seq_printf(m, " (rev %d).\n", class_rev & 0xff);
+
+	if (dev->irq)
+		seq_printf(m, "      IRQ %d.\n", dev->irq);
+
+	if (latency || min_gnt || max_lat) {
+		seq_printf(m, "      Master Capable.  ");
+		if (latency)
+			seq_printf(m, "Latency=%d.  ", latency);
+		else
+			seq_puts(m, "No bursts.  ");
+		if (min_gnt)
+			seq_printf(m, "Min Gnt=%d.", min_gnt);
+		if (max_lat)
+			seq_printf(m, "Max Lat=%d.", max_lat);
+		seq_putc(m, '\n');
+	}
+
+	for (reg = 0; reg < 6; reg++) {
+		struct resource *res = dev->resource + reg;
+		unsigned long base, end, flags;
+
+		base = res->start;
+		end = res->end;
+		flags = res->flags;
+		if (!end)
+			continue;
+
+		if (flags & PCI_BASE_ADDRESS_SPACE_IO) {
+			seq_printf(m, "      I/O at 0x%lx [0x%lx].\n",
+				base, end);
+		} else {
+			const char *pref, *type = "unknown";
+
+			if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
+				pref = "P";
+			else
+				pref = "Non-p";
+			switch (flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+			      case PCI_BASE_ADDRESS_MEM_TYPE_32:
+				type = "32 bit"; break;
+			      case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+				type = "20 bit"; break;
+			      case PCI_BASE_ADDRESS_MEM_TYPE_64:
+				type = "64 bit"; break;
+			}
+			seq_printf(m, "      %srefetchable %s memory at "
+				       "0x%lx [0x%lx].\n", pref, type,
+				       base,
+				       end);
+		}
+	}
+	return 0;
+}
+
+static struct seq_operations proc_pci_op = {
+	.start	= pci_seq_start,
+	.next	= pci_seq_next,
+	.stop	= pci_seq_stop,
+	.show	= show_dev_config
+};
+
+static int proc_pci_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &proc_pci_op);
+}
+static struct file_operations proc_pci_operations = {
+	.open		= proc_pci_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static void legacy_proc_init(void)
+{
+	struct proc_dir_entry * entry = create_proc_entry("pci", 0, NULL);
+	if (entry)
+		entry->proc_fops = &proc_pci_operations;
+}
+
+#else
+
+static void legacy_proc_init(void)
+{
+
+}
+
+#endif /* CONFIG_PCI_LEGACY_PROC */
+
+static int proc_bus_pci_dev_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &proc_bus_pci_devices_op);
+}
+static struct file_operations proc_bus_pci_dev_operations = {
+	.open		= proc_bus_pci_dev_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int __init pci_proc_init(void)
+{
+	struct proc_dir_entry *entry;
+	struct pci_dev *dev = NULL;
+	proc_bus_pci_dir = proc_mkdir("pci", proc_bus);
+	entry = create_proc_entry("devices", 0, proc_bus_pci_dir);
+	if (entry)
+		entry->proc_fops = &proc_bus_pci_dev_operations;
+	proc_initialized = 1;
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		pci_proc_attach_device(dev);
+	}
+	legacy_proc_init();
+	return 0;
+}
+
+__initcall(pci_proc_init);
+
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_proc_attach_device);
+EXPORT_SYMBOL(pci_proc_attach_bus);
+EXPORT_SYMBOL(pci_proc_detach_bus);
+#endif
+
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
new file mode 100644
index 0000000..1cfe953
--- /dev/null
+++ b/drivers/pci/quirks.c
@@ -0,0 +1,1352 @@
+/*
+ *  This file contains work-arounds for many known PCI hardware
+ *  bugs.  Devices present only on certain architectures (host
+ *  bridges et cetera) should be handled in arch-specific code.
+ *
+ *  Note: any quirks for hotpluggable devices must _NOT_ be declared __init.
+ *
+ *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
+ *
+ *  The bridge optimization stuff has been removed. If you really
+ *  have a silly BIOS which is unable to set your host bridge right,
+ *  use the PowerTweak utility (see http://powertweak.sourceforge.net).
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+/* Deal with broken BIOS'es that neglect to enable passive release,
+   which can cause problems in combination with the 82441FX/PPro MTRRs */
+static void __devinit quirk_passive_release(struct pci_dev *dev)
+{
+	struct pci_dev *d = NULL;
+	unsigned char dlc;
+
+	/* We have to make sure a particular bit is set in the PIIX3
+	   ISA bridge, so we have to go out and find it. */
+	while ((d = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
+		pci_read_config_byte(d, 0x82, &dlc);
+		if (!(dlc & 1<<1)) {
+			printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", pci_name(d));
+			dlc |= 1<<1;
+			pci_write_config_byte(d, 0x82, dlc);
+		}
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82441,	quirk_passive_release );
+
+/*  The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround
+    but VIA don't answer queries. If you happen to have good contacts at VIA
+    ask them for me please -- Alan 
+    
+    This appears to be BIOS not version dependent. So presumably there is a 
+    chipset level fix */
+int isa_dma_bridge_buggy;		/* Exported */
+    
+static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
+{
+	if (!isa_dma_bridge_buggy) {
+		isa_dma_bridge_buggy=1;
+		printk(KERN_INFO "Activating ISA DMA hang workarounds.\n");
+	}
+}
+	/*
+	 * Its not totally clear which chipsets are the problematic ones
+	 * We know 82C586 and 82C596 variants are affected.
+	 */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_0,	quirk_isa_dma_hangs );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C596,	quirk_isa_dma_hangs );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371SB_0,  quirk_isa_dma_hangs );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M1533, 	quirk_isa_dma_hangs );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_1,	quirk_isa_dma_hangs );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_2,	quirk_isa_dma_hangs );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,	PCI_DEVICE_ID_NEC_CBUS_3,	quirk_isa_dma_hangs );
+
+int pci_pci_problems;
+
+/*
+ *	Chipsets where PCI->PCI transfers vanish or hang
+ */
+static void __devinit quirk_nopcipci(struct pci_dev *dev)
+{
+	if ((pci_pci_problems & PCIPCI_FAIL)==0) {
+		printk(KERN_INFO "Disabling direct PCI/PCI transfers.\n");
+		pci_pci_problems |= PCIPCI_FAIL;
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci );
+
+/*
+ *	Triton requires workarounds to be used by the drivers
+ */
+static void __devinit quirk_triton(struct pci_dev *dev)
+{
+	if ((pci_pci_problems&PCIPCI_TRITON)==0) {
+		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+		pci_pci_problems |= PCIPCI_TRITON;
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82437, 	quirk_triton ); 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82437VX, 	quirk_triton ); 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82439, 	quirk_triton ); 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82439TX, 	quirk_triton ); 
+
+/*
+ *	VIA Apollo KT133 needs PCI latency patch
+ *	Made according to a windows driver based patch by George E. Breese
+ *	see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm
+ *      Also see http://www.au-ja.org/review-kt133a-1-en.phtml for
+ *      the info on which Mr Breese based his work.
+ *
+ *	Updated based on further information from the site and also on
+ *	information provided by VIA 
+ */
+static void __devinit quirk_vialatency(struct pci_dev *dev)
+{
+	struct pci_dev *p;
+	u8 rev;
+	u8 busarb;
+	/* Ok we have a potential problem chipset here. Now see if we have
+	   a buggy southbridge */
+	   
+	p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
+	if (p!=NULL) {
+		pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
+		/* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
+		/* Check for buggy part revisions */
+		if (rev < 0x40 || rev > 0x42)
+			goto exit;
+	} else {
+		p = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL);
+		if (p==NULL)	/* No problem parts */
+			goto exit;
+		pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
+		/* Check for buggy part revisions */
+		if (rev < 0x10 || rev > 0x12) 
+			goto exit;
+	}
+	
+	/*
+	 *	Ok we have the problem. Now set the PCI master grant to 
+	 *	occur every master grant. The apparent bug is that under high
+	 *	PCI load (quite common in Linux of course) you can get data
+	 *	loss when the CPU is held off the bus for 3 bus master requests
+	 *	This happens to include the IDE controllers....
+	 *
+	 *	VIA only apply this fix when an SB Live! is present but under
+	 *	both Linux and Windows this isnt enough, and we have seen
+	 *	corruption without SB Live! but with things like 3 UDMA IDE
+	 *	controllers. So we ignore that bit of the VIA recommendation..
+	 */
+
+	pci_read_config_byte(dev, 0x76, &busarb);
+	/* Set bit 4 and bi 5 of byte 76 to 0x01 
+	   "Master priority rotation on every PCI master grant */
+	busarb &= ~(1<<5);
+	busarb |= (1<<4);
+	pci_write_config_byte(dev, 0x76, busarb);
+	printk(KERN_INFO "Applying VIA southbridge workaround.\n");
+exit:
+	pci_dev_put(p);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8371_1,	quirk_vialatency );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,		quirk_vialatency );
+
+/*
+ *	VIA Apollo VP3 needs ETBF on BT848/878
+ */
+static void __devinit quirk_viaetbf(struct pci_dev *dev)
+{
+	if ((pci_pci_problems&PCIPCI_VIAETBF)==0) {
+		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+		pci_pci_problems |= PCIPCI_VIAETBF;
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_viaetbf );
+
+static void __devinit quirk_vsfx(struct pci_dev *dev)
+{
+	if ((pci_pci_problems&PCIPCI_VSFX)==0) {
+		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+		pci_pci_problems |= PCIPCI_VSFX;
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C576,	quirk_vsfx );
+
+/*
+ *	Ali Magik requires workarounds to be used by the drivers
+ *	that DMA to AGP space. Latency must be set to 0xA and triton
+ *	workaround applied too
+ *	[Info kindly provided by ALi]
+ */	
+static void __init quirk_alimagik(struct pci_dev *dev)
+{
+	if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) {
+		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+		pci_pci_problems |= PCIPCI_ALIMAGIK|PCIPCI_TRITON;
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1647, 	quirk_alimagik );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1651, 	quirk_alimagik );
+
+/*
+ *	Natoma has some interesting boundary conditions with Zoran stuff
+ *	at least
+ */
+static void __devinit quirk_natoma(struct pci_dev *dev)
+{
+	if ((pci_pci_problems&PCIPCI_NATOMA)==0) {
+		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+		pci_pci_problems |= PCIPCI_NATOMA;
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82441, 	quirk_natoma ); 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443LX_0, 	quirk_natoma ); 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443LX_1, 	quirk_natoma ); 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_0, 	quirk_natoma ); 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_1, 	quirk_natoma ); 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_2, 	quirk_natoma );
+
+/*
+ *  This chip can cause PCI parity errors if config register 0xA0 is read
+ *  while DMAs are occurring.
+ */
+static void __devinit quirk_citrine(struct pci_dev *dev)
+{
+	dev->cfg_size = 0xA0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,	PCI_DEVICE_ID_IBM_CITRINE,	quirk_citrine );
+
+/*
+ *  S3 868 and 968 chips report region size equal to 32M, but they decode 64M.
+ *  If it's needed, re-allocate the region.
+ */
+static void __devinit quirk_s3_64M(struct pci_dev *dev)
+{
+	struct resource *r = &dev->resource[0];
+
+	if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) {
+		r->start = 0;
+		r->end = 0x3ffffff;
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_868,		quirk_s3_64M );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_968,		quirk_s3_64M );
+
+static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr)
+{
+	region &= ~(size-1);
+	if (region) {
+		struct resource *res = dev->resource + nr;
+
+		res->name = pci_name(dev);
+		res->start = region;
+		res->end = region + size - 1;
+		res->flags = IORESOURCE_IO;
+		pci_claim_resource(dev, nr);
+	}
+}	
+
+/*
+ *	ATI Northbridge setups MCE the processor if you even
+ *	read somewhere between 0x3b0->0x3bb or read 0x3d3
+ */
+static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev)
+{
+	printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n");
+	/* Mae rhaid i ni beidio ag edrych ar y lleoliadiau I/O hyn */
+	request_region(0x3b0, 0x0C, "RadeonIGP");
+	request_region(0x3d3, 0x01, "RadeonIGP");
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI,	PCI_DEVICE_ID_ATI_RS100,   quirk_ati_exploding_mce );
+
+/*
+ * Let's make the southbridge information explicit instead
+ * of having to worry about people probing the ACPI areas,
+ * for example.. (Yes, it happens, and if you read the wrong
+ * ACPI register it will put the machine to sleep with no
+ * way of waking it up again. Bummer).
+ *
+ * ALI M7101: Two IO regions pointed to by words at
+ *	0xE0 (64 bytes of ACPI registers)
+ *	0xE2 (32 bytes of SMB registers)
+ */
+static void __devinit quirk_ali7101_acpi(struct pci_dev *dev)
+{
+	u16 region;
+
+	pci_read_config_word(dev, 0xE0, &region);
+	quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES);
+	pci_read_config_word(dev, 0xE2, &region);
+	quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M7101,		quirk_ali7101_acpi );
+
+/*
+ * PIIX4 ACPI: Two IO regions pointed to by longwords at
+ *	0x40 (64 bytes of ACPI registers)
+ *	0x90 (32 bytes of SMB registers)
+ */
+static void __devinit quirk_piix4_acpi(struct pci_dev *dev)
+{
+	u32 region;
+
+	pci_read_config_dword(dev, 0x40, &region);
+	quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES);
+	pci_read_config_dword(dev, 0x90, &region);
+	quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	quirk_piix4_acpi );
+
+/*
+ * ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at
+ *	0x40 (128 bytes of ACPI, GPIO & TCO registers)
+ *	0x58 (64 bytes of GPIO I/O space)
+ */
+static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev)
+{
+	u32 region;
+
+	pci_read_config_dword(dev, 0x40, &region);
+	quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES);
+
+	pci_read_config_dword(dev, 0x58, &region);
+	quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AA_0,		quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801AB_0,		quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_0,		quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801BA_10,	quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_0,		quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801CA_12,	quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_0,		quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801DB_12,	quirk_ich4_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82801EB_0,		quirk_ich4_lpc_acpi );
+
+/*
+ * VIA ACPI: One IO region pointed to by longword at
+ *	0x48 or 0x20 (256 bytes of ACPI registers)
+ */
+static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
+{
+	u8 rev;
+	u32 region;
+
+	pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
+	if (rev & 0x10) {
+		pci_read_config_dword(dev, 0x48, &region);
+		region &= PCI_BASE_ADDRESS_IO_MASK;
+		quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES);
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_vt82c586_acpi );
+
+/*
+ * VIA VT82C686 ACPI: Three IO region pointed to by (long)words at
+ *	0x48 (256 bytes of ACPI registers)
+ *	0x70 (128 bytes of hardware monitoring register)
+ *	0x90 (16 bytes of SMB registers)
+ */
+static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev)
+{
+	u16 hm;
+	u32 smb;
+
+	quirk_vt82c586_acpi(dev);
+
+	pci_read_config_word(dev, 0x70, &hm);
+	hm &= PCI_BASE_ADDRESS_IO_MASK;
+	quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1);
+
+	pci_read_config_dword(dev, 0x90, &smb);
+	smb &= PCI_BASE_ADDRESS_IO_MASK;
+	quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_vt82c686_acpi );
+
+
+#ifdef CONFIG_X86_IO_APIC 
+
+#include <asm/io_apic.h>
+
+/*
+ * VIA 686A/B: If an IO-APIC is active, we need to route all on-chip
+ * devices to the external APIC.
+ *
+ * TODO: When we have device-specific interrupt routers,
+ * this code will go away from quirks.
+ */
+static void __devinit quirk_via_ioapic(struct pci_dev *dev)
+{
+	u8 tmp;
+	
+	if (nr_ioapics < 1)
+		tmp = 0;    /* nothing routed to external APIC */
+	else
+		tmp = 0x1f; /* all known bits (4-0) routed to external APIC */
+		
+	printk(KERN_INFO "PCI: %sbling Via external APIC routing\n",
+	       tmp == 0 ? "Disa" : "Ena");
+
+	/* Offset 0x58: External APIC IRQ output control */
+	pci_write_config_byte (dev, 0x58, tmp);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686,	quirk_via_ioapic );
+
+/*
+ * The AMD io apic can hang the box when an apic irq is masked.
+ * We check all revs >= B0 (yet not in the pre production!) as the bug
+ * is currently marked NoFix
+ *
+ * We have multiple reports of hangs with this chipset that went away with
+ * noapic specified. For the moment we assume its the errata. We may be wrong
+ * of course. However the advice is demonstrably good even if so..
+ */
+static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
+{
+	u8 rev;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+	if (rev >= 0x02) {
+		printk(KERN_WARNING "I/O APIC: AMD Errata #22 may be present. In the event of instability try\n");
+		printk(KERN_WARNING "        : booting with the \"noapic\" option.\n");
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7410,	quirk_amd_ioapic );
+
+static void __init quirk_ioapic_rmw(struct pci_dev *dev)
+{
+	if (dev->devfn == 0 && dev->bus->number == 0)
+		sis_apic_bug = 1;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,	PCI_ANY_ID,			quirk_ioapic_rmw );
+
+int pci_msi_quirk;
+
+#define AMD8131_revA0        0x01
+#define AMD8131_revB0        0x11
+#define AMD8131_MISC         0x40
+#define AMD8131_NIOAMODE_BIT 0
+static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) 
+{ 
+        unsigned char revid, tmp;
+        
+	pci_msi_quirk = 1;
+	printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+
+        if (nr_ioapics == 0) 
+                return;
+
+        pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
+        if (revid == AMD8131_revA0 || revid == AMD8131_revB0) {
+                printk(KERN_INFO "Fixing up AMD8131 IOAPIC mode\n"); 
+                pci_read_config_byte( dev, AMD8131_MISC, &tmp);
+                tmp &= ~(1 << AMD8131_NIOAMODE_BIT);
+                pci_write_config_byte( dev, AMD8131_MISC, tmp);
+        }
+} 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC,         quirk_amd_8131_ioapic ); 
+
+#endif /* CONFIG_X86_IO_APIC */
+
+
+/*
+ * Via 686A/B:  The PCI_INTERRUPT_LINE register for the on-chip
+ * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
+ * when written, it makes an internal connection to the PIC.
+ * For these devices, this register is defined to be 4 bits wide.
+ * Normally this is fine.  However for IO-APIC motherboards, or
+ * non-x86 architectures (yes Via exists on PPC among other places),
+ * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
+ * interrupts delivered properly.
+ *
+ * TODO: When we have device-specific interrupt routers,
+ * quirk_via_irqpic will go away from quirks.
+ */
+
+/*
+ * FIXME: it is questionable that quirk_via_acpi
+ * is needed.  It shows up as an ISA bridge, and does not
+ * support the PCI_INTERRUPT_LINE register at all.  Therefore
+ * it seems like setting the pci_dev's 'irq' to the
+ * value of the ACPI SCI interrupt is only done for convenience.
+ *	-jgarzik
+ */
+static void __devinit quirk_via_acpi(struct pci_dev *d)
+{
+	/*
+	 * VIA ACPI device: SCI IRQ line in PCI config byte 0x42
+	 */
+	u8 irq;
+	pci_read_config_byte(d, 0x42, &irq);
+	irq &= 0xf;
+	if (irq && (irq != 2))
+		d->irq = irq;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_via_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	quirk_via_acpi );
+
+/*
+ * PIIX3 USB: We have to disable USB interrupts that are
+ * hardwired to PIRQD# and may be shared with an
+ * external device.
+ *
+ * Legacy Support Register (LEGSUP):
+ *     bit13:  USB PIRQ Enable (USBPIRQDEN),
+ *     bit4:   Trap/SMI On IRQ Enable (USBSMIEN).
+ *
+ * We mask out all r/wc bits, too.
+ */
+static void __devinit quirk_piix3_usb(struct pci_dev *dev)
+{
+	u16 legsup;
+
+	pci_read_config_word(dev, 0xc0, &legsup);
+	legsup &= 0x50ef;
+	pci_write_config_word(dev, 0xc0, legsup);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371SB_2,	quirk_piix3_usb );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_2,	quirk_piix3_usb );
+
+/*
+ * VIA VT82C598 has its device ID settable and many BIOSes
+ * set it to the ID of VT82C597 for backward compatibility.
+ * We need to switch it off to be able to recognize the real
+ * type of the chip.
+ */
+static void __devinit quirk_vt82c598_id(struct pci_dev *dev)
+{
+	pci_write_config_byte(dev, 0xfc, 0);
+	pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_vt82c598_id );
+
+/*
+ * CardBus controllers have a legacy base address that enables them
+ * to respond as i82365 pcmcia controllers.  We don't want them to
+ * do this even if the Linux CardBus driver is not loaded, because
+ * the Linux i82365 driver does not (and should not) handle CardBus.
+ */
+static void __devinit quirk_cardbus_legacy(struct pci_dev *dev)
+{
+	if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
+		return;
+	pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
+
+/*
+ * Following the PCI ordering rules is optional on the AMD762. I'm not
+ * sure what the designers were smoking but let's not inhale...
+ *
+ * To be fair to AMD, it follows the spec by default, its BIOS people
+ * who turn it off!
+ */
+static void __devinit quirk_amd_ordering(struct pci_dev *dev)
+{
+	u32 pcic;
+	pci_read_config_dword(dev, 0x4C, &pcic);
+	if ((pcic&6)!=6) {
+		pcic |= 6;
+		printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n");
+		pci_write_config_dword(dev, 0x4C, pcic);
+		pci_read_config_dword(dev, 0x84, &pcic);
+		pcic |= (1<<23);	/* Required in this mode */
+		pci_write_config_dword(dev, 0x84, pcic);
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
+
+/*
+ *	DreamWorks provided workaround for Dunord I-3000 problem
+ *
+ *	This card decodes and responds to addresses not apparently
+ *	assigned to it. We force a larger allocation to ensure that
+ *	nothing gets put too close to it.
+ */
+static void __devinit quirk_dunord ( struct pci_dev * dev )
+{
+	struct resource *r = &dev->resource [1];
+	r->start = 0;
+	r->end = 0xffffff;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD,	PCI_DEVICE_ID_DUNORD_I3000,	quirk_dunord );
+
+/*
+ * i82380FB mobile docking controller: its PCI-to-PCI bridge
+ * is subtractive decoding (transparent), and does indicate this
+ * in the ProgIf. Unfortunately, the ProgIf value is wrong - 0x80
+ * instead of 0x01.
+ */
+static void __devinit quirk_transparent_bridge(struct pci_dev *dev)
+{
+	dev->transparent = 1;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82380FB,	quirk_transparent_bridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA,	0x605,	quirk_transparent_bridge );
+
+/*
+ * Common misconfiguration of the MediaGX/Geode PCI master that will
+ * reduce PCI bandwidth from 70MB/s to 25MB/s.  See the GXM/GXLV/GX1
+ * datasheets found at http://www.national.com/ds/GX for info on what
+ * these bits do.  <christer@weinigel.se>
+ */
+static void __init quirk_mediagx_master(struct pci_dev *dev)
+{
+	u8 reg;
+	pci_read_config_byte(dev, 0x41, &reg);
+	if (reg & 2) {
+		reg &= ~2;
+		printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
+                pci_write_config_byte(dev, 0x41, reg);
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX,	PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
+
+/*
+ * As per PCI spec, ignore base address registers 0-3 of the IDE controllers
+ * running in Compatible mode (bits 0 and 2 in the ProgIf for primary and
+ * secondary channels respectively). If the device reports Compatible mode
+ * but does use BAR0-3 for address decoding, we assume that firmware has
+ * programmed these BARs with standard values (0x1f0,0x3f4 and 0x170,0x374).
+ * Exceptions (if they exist) must be handled in chip/architecture specific
+ * fixups.
+ *
+ * Note: for non x86 people. You may need an arch specific quirk to handle
+ * moving IDE devices to native mode as well. Some plug in card devices power
+ * up in compatible mode and assume the BIOS will adjust them.
+ *
+ * Q: should we load the 0x1f0,0x3f4 into the registers or zap them as
+ * we do now ? We don't want is pci_enable_device to come along
+ * and assign new resources. Both approaches work for that.
+ */ 
+static void __devinit quirk_ide_bases(struct pci_dev *dev)
+{
+       struct resource *res;
+       int first_bar = 2, last_bar = 0;
+
+       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+               return;
+
+       res = &dev->resource[0];
+
+       /* primary channel: ProgIf bit 0, BAR0, BAR1 */
+       if (!(dev->class & 1) && (res[0].flags || res[1].flags)) { 
+               res[0].start = res[0].end = res[0].flags = 0;
+               res[1].start = res[1].end = res[1].flags = 0;
+               first_bar = 0;
+               last_bar = 1;
+       }
+
+       /* secondary channel: ProgIf bit 2, BAR2, BAR3 */
+       if (!(dev->class & 4) && (res[2].flags || res[3].flags)) { 
+               res[2].start = res[2].end = res[2].flags = 0;
+               res[3].start = res[3].end = res[3].flags = 0;
+               last_bar = 3;
+       }
+
+       if (!last_bar)
+               return;
+
+       printk(KERN_INFO "PCI: Ignoring BAR%d-%d of IDE controller %s\n",
+              first_bar, last_bar, pci_name(dev));
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_ide_bases);
+
+/*
+ *	Ensure C0 rev restreaming is off. This is normally done by
+ *	the BIOS but in the odd case it is not the results are corruption
+ *	hence the presence of a Linux check
+ */
+static void __init quirk_disable_pxb(struct pci_dev *pdev)
+{
+	u16 config;
+	u8 rev;
+	
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+	if (rev != 0x04)		/* Only C0 requires this */
+		return;
+	pci_read_config_word(pdev, 0x40, &config);
+	if (config & (1<<6)) {
+		config &= ~(1<<6);
+		pci_write_config_word(pdev, 0x40, config);
+		printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n");
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454NX,	quirk_disable_pxb );
+
+/*
+ *	VIA northbridges care about PCI_INTERRUPT_LINE
+ */
+int via_interrupt_line_quirk;
+
+static void __devinit quirk_via_bridge(struct pci_dev *pdev)
+{
+	if(pdev->devfn == 0) {
+		printk(KERN_INFO "PCI: Via IRQ fixup\n");
+		via_interrupt_line_quirk = 1;
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,	PCI_ANY_ID,                     quirk_via_bridge );
+
+/*
+ *	Serverworks CSB5 IDE does not fully support native mode
+ */
+static void __devinit quirk_svwks_csb5ide(struct pci_dev *pdev)
+{
+	u8 prog;
+	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
+	if (prog & 5) {
+		prog &= ~5;
+		pdev->class &= ~5;
+		pci_write_config_byte(pdev, PCI_CLASS_PROG, prog);
+		/* need to re-assign BARs for compat mode */
+		quirk_ide_bases(pdev);
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, quirk_svwks_csb5ide );
+
+/*
+ *	Intel 82801CAM ICH3-M datasheet says IDE modes must be the same
+ */
+static void __init quirk_ide_samemode(struct pci_dev *pdev)
+{
+	u8 prog;
+
+	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
+
+	if (((prog & 1) && !(prog & 4)) || ((prog & 4) && !(prog & 1))) {
+		printk(KERN_INFO "PCI: IDE mode mismatch; forcing legacy mode\n");
+		prog &= ~5;
+		pdev->class &= ~5;
+		pci_write_config_byte(pdev, PCI_CLASS_PROG, prog);
+		/* need to re-assign BARs for compat mode */
+		quirk_ide_bases(pdev);
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, quirk_ide_samemode);
+
+/* This was originally an Alpha specific thing, but it really fits here.
+ * The i82375 PCI/EISA bridge appears as non-classified. Fix that.
+ */
+static void __init quirk_eisa_bridge(struct pci_dev *dev)
+{
+	dev->class = PCI_CLASS_BRIDGE_EISA << 8;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82375,	quirk_eisa_bridge );
+
+/*
+ * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
+ * is not activated. The myth is that Asus said that they do not want the
+ * users to be irritated by just another PCI Device in the Win98 device
+ * manager. (see the file prog/hotplug/README.p4b in the lm_sensors 
+ * package 2.7.0 for details)
+ *
+ * The SMBus PCI Device can be activated by setting a bit in the ICH LPC 
+ * bridge. Unfortunately, this device has no subvendor/subdevice ID. So it 
+ * becomes necessary to do this tweak in two steps -- I've chosen the Host
+ * bridge as trigger.
+ */
+static int __initdata asus_hides_smbus = 0;
+
+static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
+{
+	if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) {
+		if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB)
+			switch(dev->subsystem_device) {
+			case 0x8070: /* P4B */
+			case 0x8088: /* P4B533 */
+			case 0x1626: /* L3C notebook */
+				asus_hides_smbus = 1;
+			}
+		if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
+			switch(dev->subsystem_device) {
+			case 0x80b1: /* P4GE-V */
+			case 0x80b2: /* P4PE */
+			case 0x8093: /* P4B533-V */
+				asus_hides_smbus = 1;
+			}
+		if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
+			switch(dev->subsystem_device) {
+			case 0x8030: /* P4T533 */
+				asus_hides_smbus = 1;
+			}
+		if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
+			switch (dev->subsystem_device) {
+			case 0x8070: /* P4G8X Deluxe */
+				asus_hides_smbus = 1;
+			}
+		if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
+			switch (dev->subsystem_device) {
+			case 0x1751: /* M2N notebook */
+			case 0x1821: /* M5N notebook */
+				asus_hides_smbus = 1;
+			}
+		if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+			switch (dev->subsystem_device) {
+			case 0x184b: /* W1N notebook */
+			case 0x186a: /* M6Ne notebook */
+				asus_hides_smbus = 1;
+			}
+	} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) {
+		if (dev->device ==  PCI_DEVICE_ID_INTEL_82855PM_HB)
+			switch(dev->subsystem_device) {
+			case 0x088C: /* HP Compaq nc8000 */
+			case 0x0890: /* HP Compaq nc6000 */
+				asus_hides_smbus = 1;
+			}
+		if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+			switch (dev->subsystem_device) {
+			case 0x12bc: /* HP D330L */
+				asus_hides_smbus = 1;
+			}
+	} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
+		if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
+			switch(dev->subsystem_device) {
+			case 0x0001: /* Toshiba Satellite A40 */
+				asus_hides_smbus = 1;
+			}
+       } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) {
+               if (dev->device ==  PCI_DEVICE_ID_INTEL_82855PM_HB)
+                       switch(dev->subsystem_device) {
+                       case 0xC00C: /* Samsung P35 notebook */
+                               asus_hides_smbus = 1;
+                       }
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845_HB,	asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845G_HB,	asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82850_HB,	asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82865_HB,	asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_7205_0,	asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82855PM_HB,	asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82855GM_HB,	asus_hides_smbus_hostbridge );
+
+static void __init asus_hides_smbus_lpc(struct pci_dev *dev)
+{
+	u16 val;
+	
+	if (likely(!asus_hides_smbus))
+		return;
+
+	pci_read_config_word(dev, 0xF2, &val);
+	if (val & 0x8) {
+		pci_write_config_word(dev, 0xF2, val & (~0x8));
+		pci_read_config_word(dev, 0xF2, &val);
+		if (val & 0x8)
+			printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val);
+		else
+			printk(KERN_INFO "PCI: Enabled i801 SMBus device\n");
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_0,	asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801BA_0,	asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_12,	asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_12,	asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801EB_0,	asus_hides_smbus_lpc );
+
+/*
+ * SiS 96x south bridge: BIOS typically hides SMBus device...
+ */
+static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
+{
+	u8 val = 0;
+	printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
+	pci_read_config_byte(dev, 0x77, &val);
+	pci_write_config_byte(dev, 0x77, val & ~0x10);
+	pci_read_config_byte(dev, 0x77, &val);
+}
+
+
+#define UHCI_USBLEGSUP		0xc0		/* legacy support */
+#define UHCI_USBCMD		0		/* command register */
+#define UHCI_USBSTS		2		/* status register */
+#define UHCI_USBINTR		4		/* interrupt register */
+#define UHCI_USBLEGSUP_DEFAULT	0x2000		/* only PIRQ enable set */
+#define UHCI_USBCMD_RUN		(1 << 0)	/* RUN/STOP bit */
+#define UHCI_USBCMD_GRESET	(1 << 2)	/* Global reset */
+#define UHCI_USBCMD_CONFIGURE	(1 << 6)	/* config semaphore */
+#define UHCI_USBSTS_HALTED	(1 << 5)	/* HCHalted bit */
+
+#define OHCI_CONTROL		0x04
+#define OHCI_CMDSTATUS		0x08
+#define OHCI_INTRSTATUS		0x0c
+#define OHCI_INTRENABLE		0x10
+#define OHCI_INTRDISABLE	0x14
+#define OHCI_OCR		(1 << 3)	/* ownership change request */
+#define OHCI_CTRL_IR		(1 << 8)	/* interrupt routing */
+#define OHCI_INTR_OC		(1 << 30)	/* ownership change */
+
+#define EHCI_HCC_PARAMS		0x08		/* extended capabilities */
+#define EHCI_USBCMD		0		/* command register */
+#define EHCI_USBCMD_RUN		(1 << 0)	/* RUN/STOP bit */
+#define EHCI_USBSTS		4		/* status register */
+#define EHCI_USBSTS_HALTED	(1 << 12)	/* HCHalted bit */
+#define EHCI_USBINTR		8		/* interrupt register */
+#define EHCI_USBLEGSUP		0		/* legacy support register */
+#define EHCI_USBLEGSUP_BIOS	(1 << 16)	/* BIOS semaphore */
+#define EHCI_USBLEGSUP_OS	(1 << 24)	/* OS semaphore */
+#define EHCI_USBLEGCTLSTS	4		/* legacy control/status */
+#define EHCI_USBLEGCTLSTS_SOOE	(1 << 13)	/* SMI on ownership change */
+
+int usb_early_handoff __devinitdata = 0;
+static int __init usb_handoff_early(char *str)
+{
+	usb_early_handoff = 1;
+	return 0;
+}
+__setup("usb-handoff", usb_handoff_early);
+
+static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
+{
+	unsigned long base = 0;
+	int wait_time, delta;
+	u16 val, sts;
+	int i;
+
+	for (i = 0; i < PCI_ROM_RESOURCE; i++)
+		if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
+			base = pci_resource_start(pdev, i);
+			break;
+		}
+
+	if (!base)
+		return;
+
+	/*
+	 * stop controller
+	 */
+	sts = inw(base + UHCI_USBSTS);
+	val = inw(base + UHCI_USBCMD);
+	val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
+	outw(val, base + UHCI_USBCMD);
+
+	/*
+	 * wait while it stops if it was running
+	 */
+	if ((sts & UHCI_USBSTS_HALTED) == 0)
+	{
+		wait_time = 1000;
+		delta = 100;
+
+		do {
+			outw(0x1f, base + UHCI_USBSTS);
+			udelay(delta);
+			wait_time -= delta;
+			val = inw(base + UHCI_USBSTS);
+			if (val & UHCI_USBSTS_HALTED)
+				break;
+		} while (wait_time > 0);
+	}
+
+	/*
+	 * disable interrupts & legacy support
+	 */
+	outw(0, base + UHCI_USBINTR);
+	outw(0x1f, base + UHCI_USBSTS);
+	pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
+	if (val & 0xbf) 
+		pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
+		
+}
+
+static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
+{
+	void __iomem *base;
+	int wait_time;
+
+	base = ioremap_nocache(pci_resource_start(pdev, 0),
+				     pci_resource_len(pdev, 0));
+	if (base == NULL) return;
+
+	if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
+		wait_time = 500; /* 0.5 seconds */
+		writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
+		writel(OHCI_OCR, base + OHCI_CMDSTATUS);
+		while (wait_time > 0 && 
+				readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
+			wait_time -= 10;
+			msleep(10);
+		}
+	}
+
+	/*
+	 * disable interrupts
+	 */
+	writel(~(u32)0, base + OHCI_INTRDISABLE);
+	writel(~(u32)0, base + OHCI_INTRSTATUS);
+
+	iounmap(base);
+}
+
+static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
+{
+	int wait_time, delta;
+	void __iomem *base, *op_reg_base;
+	u32 hcc_params, val, temp;
+	u8 cap_length;
+
+	base = ioremap_nocache(pci_resource_start(pdev, 0),
+				pci_resource_len(pdev, 0));
+	if (base == NULL) return;
+
+	cap_length = readb(base);
+	op_reg_base = base + cap_length;
+	hcc_params = readl(base + EHCI_HCC_PARAMS);
+	hcc_params = (hcc_params >> 8) & 0xff;
+	if (hcc_params) {
+		pci_read_config_dword(pdev, 
+					hcc_params + EHCI_USBLEGSUP,
+					&val);
+		if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
+			/*
+			 * Ok, BIOS is in smm mode, try to hand off...
+			 */
+			pci_read_config_dword(pdev,
+						hcc_params + EHCI_USBLEGCTLSTS,
+						&temp);
+			pci_write_config_dword(pdev,
+						hcc_params + EHCI_USBLEGCTLSTS,
+						temp | EHCI_USBLEGCTLSTS_SOOE);
+			val |= EHCI_USBLEGSUP_OS;
+			pci_write_config_dword(pdev, 
+						hcc_params + EHCI_USBLEGSUP, 
+						val);
+
+			wait_time = 500;
+			do {
+				msleep(10);
+				wait_time -= 10;
+				pci_read_config_dword(pdev,
+						hcc_params + EHCI_USBLEGSUP,
+						&val);
+			} while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
+			if (!wait_time) {
+				/*
+				 * well, possibly buggy BIOS...
+				 */
+				printk(KERN_WARNING "EHCI early BIOS handoff "
+						"failed (BIOS bug ?)\n");
+				pci_write_config_dword(pdev,
+						hcc_params + EHCI_USBLEGSUP,
+						EHCI_USBLEGSUP_OS);
+				pci_write_config_dword(pdev,
+						hcc_params + EHCI_USBLEGCTLSTS,
+						0);
+			}
+		}
+	}
+
+	/*
+	 * halt EHCI & disable its interrupts in any case
+	 */
+	val = readl(op_reg_base + EHCI_USBSTS);
+	if ((val & EHCI_USBSTS_HALTED) == 0) {
+		val = readl(op_reg_base + EHCI_USBCMD);
+		val &= ~EHCI_USBCMD_RUN;
+		writel(val, op_reg_base + EHCI_USBCMD);
+
+		wait_time = 2000;
+		delta = 100;
+		do {
+			writel(0x3f, op_reg_base + EHCI_USBSTS);
+			udelay(delta);
+			wait_time -= delta;
+			val = readl(op_reg_base + EHCI_USBSTS);
+			if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
+				break;
+			}
+		} while (wait_time > 0);
+	}
+	writel(0, op_reg_base + EHCI_USBINTR);
+	writel(0x3f, op_reg_base + EHCI_USBSTS);
+
+	iounmap(base);
+
+	return;
+}
+
+
+
+static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
+{
+	if (!usb_early_handoff)
+		return;
+
+	if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
+		quirk_usb_handoff_uhci(pdev);
+	} else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
+		quirk_usb_handoff_ohci(pdev);
+	} else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
+		quirk_usb_disable_ehci(pdev);
+	}
+
+	return;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+
+/*
+ * ... This is further complicated by the fact that some SiS96x south
+ * bridges pretend to be 85C503/5513 instead.  In that case see if we
+ * spotted a compatible north bridge to make sure.
+ * (pci_find_device doesn't work yet)
+ *
+ * We can also enable the sis96x bit in the discovery register..
+ */
+static int __devinitdata sis_96x_compatible = 0;
+
+#define SIS_DETECT_REGISTER 0x40
+
+static void __init quirk_sis_503(struct pci_dev *dev)
+{
+	u8 reg;
+	u16 devid;
+
+	pci_read_config_byte(dev, SIS_DETECT_REGISTER, &reg);
+	pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg | (1 << 6));
+	pci_read_config_word(dev, PCI_DEVICE_ID, &devid);
+	if (((devid & 0xfff0) != 0x0960) && (devid != 0x0018)) {
+		pci_write_config_byte(dev, SIS_DETECT_REGISTER, reg);
+		return;
+	}
+
+	/* Make people aware that we changed the config.. */
+	printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible);
+
+	/*
+	 * Ok, it now shows up as a 96x.. The 96x quirks are after
+	 * the 503 quirk in the quirk table, so they'll automatically
+	 * run and enable things like the SMBus device
+	 */
+	dev->device = devid;
+}
+
+static void __init quirk_sis_96x_compatible(struct pci_dev *dev)
+{
+	sis_96x_compatible = 1;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_645,		quirk_sis_96x_compatible );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_646,		quirk_sis_96x_compatible );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_648,		quirk_sis_96x_compatible );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_650,		quirk_sis_96x_compatible );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_651,		quirk_sis_96x_compatible );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_735,		quirk_sis_96x_compatible );
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503 );
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_LPC,		quirk_sis_96x_smbus );
+
+#ifdef CONFIG_X86_IO_APIC
+static void __init quirk_alder_ioapic(struct pci_dev *pdev)
+{
+	int i;
+
+	if ((pdev->class >> 8) != 0xff00)
+		return;
+
+	/* the first BAR is the location of the IO APIC...we must
+	 * not touch this (and it's already covered by the fixmap), so
+	 * forcibly insert it into the resource tree */
+	if (pci_resource_start(pdev, 0) && pci_resource_len(pdev, 0))
+		insert_resource(&iomem_resource, &pdev->resource[0]);
+
+	/* The next five BARs all seem to be rubbish, so just clean
+	 * them out */
+	for (i=1; i < 6; i++) {
+		memset(&pdev->resource[i], 0, sizeof(pdev->resource[i]));
+	}
+
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_EESSC,	quirk_alder_ioapic );
+#endif
+
+#ifdef CONFIG_SCSI_SATA
+static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
+{
+	u8 prog, comb, tmp;
+	int ich = 0;
+
+	/*
+	 * Narrow down to Intel SATA PCI devices.
+	 */
+	switch (pdev->device) {
+	/* PCI ids taken from drivers/scsi/ata_piix.c */
+	case 0x24d1:
+	case 0x24df:
+	case 0x25a3:
+	case 0x25b0:
+		ich = 5;
+		break;
+	case 0x2651:
+	case 0x2652:
+	case 0x2653:
+		ich = 6;
+		break;
+	case 0x27c0:
+	case 0x27c4:
+		ich = 7;
+		break;
+	default:
+		/* we do not handle this PCI device */
+		return;
+	}
+
+	/*
+	 * Read combined mode register.
+	 */
+	pci_read_config_byte(pdev, 0x90, &tmp);	/* combined mode reg */
+
+	if (ich == 5) {
+		tmp &= 0x6;  /* interesting bits 2:1, PATA primary/secondary */
+		if (tmp == 0x4)		/* bits 10x */
+			comb = (1 << 0);	/* SATA port 0, PATA port 1 */
+		else if (tmp == 0x6)	/* bits 11x */
+			comb = (1 << 2);	/* PATA port 0, SATA port 1 */
+		else
+			return;			/* not in combined mode */
+	} else {
+		WARN_ON((ich != 6) && (ich != 7));
+		tmp &= 0x3;  /* interesting bits 1:0 */
+		if (tmp & (1 << 0))
+			comb = (1 << 2);	/* PATA port 0, SATA port 1 */
+		else if (tmp & (1 << 1))
+			comb = (1 << 0);	/* SATA port 0, PATA port 1 */
+		else
+			return;			/* not in combined mode */
+	}
+
+	/*
+	 * Read programming interface register.
+	 * (Tells us if it's legacy or native mode)
+	 */
+	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
+
+	/* if SATA port is in native mode, we're ok. */
+	if (prog & comb)
+		return;
+
+	/* SATA port is in legacy mode.  Reserve port so that
+	 * IDE driver does not attempt to use it.  If request_region
+	 * fails, it will be obvious at boot time, so we don't bother
+	 * checking return values.
+	 */
+	if (comb == (1 << 0))
+		request_region(0x1f0, 8, "libata");	/* port 0 */
+	else
+		request_region(0x170, 8, "libata");	/* port 1 */
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_ANY_ID,	  quirk_intel_ide_combined );
+#endif /* CONFIG_SCSI_SATA */
+
+
+int pcie_mch_quirk;
+
+static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
+{
+	pcie_mch_quirk = 1;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7520_MCH,	quirk_pcie_mch );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7320_MCH,	quirk_pcie_mch );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7525_MCH,	quirk_pcie_mch );
+
+static void __devinit quirk_netmos(struct pci_dev *dev)
+{
+	unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
+	unsigned int num_serial = dev->subsystem_device & 0xf;
+
+	/*
+	 * These Netmos parts are multiport serial devices with optional
+	 * parallel ports.  Even when parallel ports are present, they
+	 * are identified as class SERIAL, which means the serial driver
+	 * will claim them.  To prevent this, mark them as class OTHER.
+	 * These combo devices should be claimed by parport_serial.
+	 *
+	 * The subdevice ID is of the form 0x00PS, where <P> is the number
+	 * of parallel ports and <S> is the number of serial ports.
+	 */
+	switch (dev->device) {
+	case PCI_DEVICE_ID_NETMOS_9735:
+	case PCI_DEVICE_ID_NETMOS_9745:
+	case PCI_DEVICE_ID_NETMOS_9835:
+	case PCI_DEVICE_ID_NETMOS_9845:
+	case PCI_DEVICE_ID_NETMOS_9855:
+		if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL &&
+		    num_parallel) {
+			printk(KERN_INFO "PCI: Netmos %04x (%u parallel, "
+				"%u serial); changing class SERIAL to OTHER "
+				"(use parport_serial)\n",
+				dev->device, num_parallel, num_serial);
+			dev->class = (PCI_CLASS_COMMUNICATION_OTHER << 8) |
+			    (dev->class & 0xff);
+		}
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+
+static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
+{
+	while (f < end) {
+		if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
+ 		    (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
+			pr_debug("PCI: Calling quirk %p for %s\n", f->hook, pci_name(dev));
+			f->hook(dev);
+		}
+		f++;
+	}
+}
+
+extern struct pci_fixup __start_pci_fixups_early[];
+extern struct pci_fixup __end_pci_fixups_early[];
+extern struct pci_fixup __start_pci_fixups_header[];
+extern struct pci_fixup __end_pci_fixups_header[];
+extern struct pci_fixup __start_pci_fixups_final[];
+extern struct pci_fixup __end_pci_fixups_final[];
+extern struct pci_fixup __start_pci_fixups_enable[];
+extern struct pci_fixup __end_pci_fixups_enable[];
+
+
+void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
+{
+	struct pci_fixup *start, *end;
+
+	switch(pass) {
+	case pci_fixup_early:
+		start = __start_pci_fixups_early;
+		end = __end_pci_fixups_early;
+		break;
+
+	case pci_fixup_header:
+		start = __start_pci_fixups_header;
+		end = __end_pci_fixups_header;
+		break;
+
+	case pci_fixup_final:
+		start = __start_pci_fixups_final;
+		end = __end_pci_fixups_final;
+		break;
+
+	case pci_fixup_enable:
+		start = __start_pci_fixups_enable;
+		end = __end_pci_fixups_enable;
+		break;
+
+	default:
+		/* stupid compiler warning, you would think with an enum... */
+		return;
+	}
+	pci_do_fixups(dev, start, end);
+}
+
+EXPORT_SYMBOL(pcie_mch_quirk);
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_fixup_device);
+#endif
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
new file mode 100644
index 0000000..96f077f
--- /dev/null
+++ b/drivers/pci/remove.c
@@ -0,0 +1,118 @@
+#include <linux/pci.h>
+#include <linux/module.h>
+#include "pci.h"
+
+static void pci_free_resources(struct pci_dev *dev)
+{
+	int i;
+
+ 	msi_remove_pci_irq_vectors(dev);
+
+	pci_cleanup_rom(dev);
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *res = dev->resource + i;
+		if (res->parent)
+			release_resource(res);
+	}
+}
+
+static void pci_destroy_dev(struct pci_dev *dev)
+{
+	pci_proc_detach_device(dev);
+	pci_remove_sysfs_dev_files(dev);
+	device_unregister(&dev->dev);
+
+	/* Remove the device from the device lists, and prevent any further
+	 * list accesses from this device */
+	spin_lock(&pci_bus_lock);
+	list_del(&dev->bus_list);
+	list_del(&dev->global_list);
+	dev->bus_list.next = dev->bus_list.prev = NULL;
+	dev->global_list.next = dev->global_list.prev = NULL;
+	spin_unlock(&pci_bus_lock);
+
+	pci_free_resources(dev);
+	pci_dev_put(dev);
+}
+
+/**
+ * pci_remove_device_safe - remove an unused hotplug device
+ * @dev: the device to remove
+ *
+ * Delete the device structure from the device lists and 
+ * notify userspace (/sbin/hotplug), but only if the device
+ * in question is not being used by a driver.
+ * Returns 0 on success.
+ */
+int pci_remove_device_safe(struct pci_dev *dev)
+{
+	if (pci_dev_driver(dev))
+		return -EBUSY;
+	pci_destroy_dev(dev);
+	return 0;
+}
+EXPORT_SYMBOL(pci_remove_device_safe);
+
+void pci_remove_bus(struct pci_bus *pci_bus)
+{
+	pci_proc_detach_bus(pci_bus);
+
+	spin_lock(&pci_bus_lock);
+	list_del(&pci_bus->node);
+	spin_unlock(&pci_bus_lock);
+	pci_remove_legacy_files(pci_bus);
+	class_device_remove_file(&pci_bus->class_dev,
+		&class_device_attr_cpuaffinity);
+	sysfs_remove_link(&pci_bus->class_dev.kobj, "bridge");
+	class_device_unregister(&pci_bus->class_dev);
+}
+EXPORT_SYMBOL(pci_remove_bus);
+
+/**
+ * pci_remove_bus_device - remove a PCI device and any children
+ * @dev: the device to remove
+ *
+ * Remove a PCI device from the device lists, informing the drivers
+ * that the device has been removed.  We also remove any subordinate
+ * buses and children in a depth-first manner.
+ *
+ * For each device we remove, delete the device structure from the
+ * device lists, remove the /proc entry, and notify userspace
+ * (/sbin/hotplug).
+ */
+void pci_remove_bus_device(struct pci_dev *dev)
+{
+	if (dev->subordinate) {
+		struct pci_bus *b = dev->subordinate;
+
+		pci_remove_behind_bridge(dev);
+		pci_remove_bus(b);
+		dev->subordinate = NULL;
+	}
+
+	pci_destroy_dev(dev);
+}
+
+/**
+ * pci_remove_behind_bridge - remove all devices behind a PCI bridge
+ * @dev: PCI bridge device
+ *
+ * Remove all devices on the bus, except for the parent bridge.
+ * This also removes any child buses, and any devices they may
+ * contain in a depth-first manner.
+ */
+void pci_remove_behind_bridge(struct pci_dev *dev)
+{
+	struct list_head *l, *n;
+
+	if (dev->subordinate) {
+		list_for_each_safe(l, n, &dev->subordinate->devices) {
+			struct pci_dev *dev = pci_dev_b(l);
+
+			pci_remove_bus_device(dev);
+		}
+	}
+}
+
+EXPORT_SYMBOL(pci_remove_bus_device);
+EXPORT_SYMBOL(pci_remove_behind_bridge);
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
new file mode 100644
index 0000000..3e64ff6
--- /dev/null
+++ b/drivers/pci/rom.c
@@ -0,0 +1,227 @@
+/*
+ * drivers/pci/rom.c
+ *
+ * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
+ * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
+ *
+ * PCI ROM access routines
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include "pci.h"
+
+/**
+ * pci_enable_rom - enable ROM decoding for a PCI device
+ * @dev: PCI device to enable
+ *
+ * Enable ROM decoding on @dev.  This involves simply turning on the last
+ * bit of the PCI ROM BAR.  Note that some cards may share address decoders
+ * between the ROM and other resources, so enabling it may disable access
+ * to MMIO registers or other card memory.
+ */
+static void pci_enable_rom(struct pci_dev *pdev)
+{
+	u32 rom_addr;
+
+	pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
+	rom_addr |= PCI_ROM_ADDRESS_ENABLE;
+	pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
+}
+
+/**
+ * pci_disable_rom - disable ROM decoding for a PCI device
+ * @dev: PCI device to disable
+ *
+ * Disable ROM decoding on a PCI device by turning off the last bit in the
+ * ROM BAR.
+ */
+static void pci_disable_rom(struct pci_dev *pdev)
+{
+	u32 rom_addr;
+	pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
+	rom_addr &= ~PCI_ROM_ADDRESS_ENABLE;
+	pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr);
+}
+
+/**
+ * pci_map_rom - map a PCI ROM to kernel space
+ * @dev: pointer to pci device struct
+ * @size: pointer to receive size of pci window over ROM
+ * @return: kernel virtual pointer to image of ROM
+ *
+ * Map a PCI ROM into kernel space. If ROM is boot video ROM,
+ * the shadow BIOS copy will be returned instead of the
+ * actual ROM.
+ */
+void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
+{
+	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+	loff_t start;
+	void __iomem *rom;
+	void __iomem *image;
+	int last_image;
+
+	/* IORESOURCE_ROM_SHADOW only set on x86 */
+	if (res->flags & IORESOURCE_ROM_SHADOW) {
+		/* primary video rom always starts here */
+		start = (loff_t)0xC0000;
+		*size = 0x20000; /* cover C000:0 through E000:0 */
+	} else {
+		if (res->flags & IORESOURCE_ROM_COPY) {
+			*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+			return (void __iomem *)pci_resource_start(pdev, PCI_ROM_RESOURCE);
+		} else {
+			/* assign the ROM an address if it doesn't have one */
+			if (res->parent == NULL)
+				pci_assign_resource(pdev, PCI_ROM_RESOURCE);
+
+			start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
+			*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+			if (*size == 0)
+				return NULL;
+
+			/* Enable ROM space decodes */
+			pci_enable_rom(pdev);
+		}
+	}
+
+	rom = ioremap(start, *size);
+	if (!rom) {
+		/* restore enable if ioremap fails */
+		if (!(res->flags & (IORESOURCE_ROM_ENABLE |
+				    IORESOURCE_ROM_SHADOW |
+				    IORESOURCE_ROM_COPY)))
+			pci_disable_rom(pdev);
+		return NULL;
+	}
+
+	/*
+	 * Try to find the true size of the ROM since sometimes the PCI window
+	 * size is much larger than the actual size of the ROM.
+	 * True size is important if the ROM is going to be copied.
+	 */
+	image = rom;
+	do {
+		void __iomem *pds;
+		/* Standard PCI ROMs start out with these bytes 55 AA */
+		if (readb(image) != 0x55)
+			break;
+		if (readb(image + 1) != 0xAA)
+			break;
+		/* get the PCI data structure and check its signature */
+		pds = image + readw(image + 24);
+		if (readb(pds) != 'P')
+			break;
+		if (readb(pds + 1) != 'C')
+			break;
+		if (readb(pds + 2) != 'I')
+			break;
+		if (readb(pds + 3) != 'R')
+			break;
+		last_image = readb(pds + 21) & 0x80;
+		/* this length is reliable */
+		image += readw(pds + 16) * 512;
+	} while (!last_image);
+
+	*size = image - rom;
+
+	return rom;
+}
+
+/**
+ * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy
+ * @dev: pointer to pci device struct
+ * @size: pointer to receive size of pci window over ROM
+ * @return: kernel virtual pointer to image of ROM
+ *
+ * Map a PCI ROM into kernel space. If ROM is boot video ROM,
+ * the shadow BIOS copy will be returned instead of the
+ * actual ROM.
+ */
+void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
+{
+	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+	void __iomem *rom;
+
+	rom = pci_map_rom(pdev, size);
+	if (!rom)
+		return NULL;
+
+	if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW))
+		return rom;
+
+	res->start = (unsigned long)kmalloc(*size, GFP_KERNEL);
+	if (!res->start)
+		return rom;
+
+	res->end = res->start + *size;
+	memcpy_fromio((void*)res->start, rom, *size);
+	pci_unmap_rom(pdev, rom);
+	res->flags |= IORESOURCE_ROM_COPY;
+
+	return (void __iomem *)res->start;
+}
+
+/**
+ * pci_unmap_rom - unmap the ROM from kernel space
+ * @dev: pointer to pci device struct
+ * @rom: virtual address of the previous mapping
+ *
+ * Remove a mapping of a previously mapped ROM
+ */
+void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
+{
+	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+
+	if (res->flags & IORESOURCE_ROM_COPY)
+		return;
+
+	iounmap(rom);
+
+	/* Disable again before continuing, leave enabled if pci=rom */
+	if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
+		pci_disable_rom(pdev);
+}
+
+/**
+ * pci_remove_rom - disable the ROM and remove its sysfs attribute
+ * @dev: pointer to pci device struct
+ *
+ * Remove the rom file in sysfs and disable ROM decoding.
+ */
+void pci_remove_rom(struct pci_dev *pdev)
+{
+	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+
+	if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
+		sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
+	if (!(res->flags & (IORESOURCE_ROM_ENABLE |
+			    IORESOURCE_ROM_SHADOW |
+			    IORESOURCE_ROM_COPY)))
+		pci_disable_rom(pdev);
+}
+
+/**
+ * pci_cleanup_rom - internal routine for freeing the ROM copy created
+ * by pci_map_rom_copy called from remove.c
+ * @dev: pointer to pci device struct
+ *
+ * Free the copied ROM if we allocated one.
+ */
+void pci_cleanup_rom(struct pci_dev *pdev)
+{
+	struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
+	if (res->flags & IORESOURCE_ROM_COPY) {
+		kfree((void*)res->start);
+		res->flags &= ~IORESOURCE_ROM_COPY;
+		res->start = 0;
+		res->end = 0;
+	}
+}
+
+EXPORT_SYMBOL(pci_map_rom);
+EXPORT_SYMBOL(pci_map_rom_copy);
+EXPORT_SYMBOL(pci_unmap_rom);
+EXPORT_SYMBOL(pci_remove_rom);
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
new file mode 100644
index 0000000..a90a533
--- /dev/null
+++ b/drivers/pci/search.c
@@ -0,0 +1,388 @@
+/*
+ * 	PCI searching functions.
+ *
+ *	Copyright (C) 1993 -- 1997 Drew Eckhardt, Frederic Potter,
+ *					David Mosberger-Tang
+ *	Copyright (C) 1997 -- 2000 Martin Mares <mj@ucw.cz>
+ *	Copyright (C) 2003 -- 2004 Greg Kroah-Hartman <greg@kroah.com>
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include "pci.h"
+
+DEFINE_SPINLOCK(pci_bus_lock);
+
+static struct pci_bus * __devinit
+pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
+{
+	struct pci_bus* child;
+	struct list_head *tmp;
+
+	if(bus->number == busnr)
+		return bus;
+
+	list_for_each(tmp, &bus->children) {
+		child = pci_do_find_bus(pci_bus_b(tmp), busnr);
+		if(child)
+			return child;
+	}
+	return NULL;
+}
+
+/**
+ * pci_find_bus - locate PCI bus from a given domain and bus number
+ * @domain: number of PCI domain to search
+ * @busnr: number of desired PCI bus
+ *
+ * Given a PCI bus number and domain number, the desired PCI bus is located
+ * in the global list of PCI buses.  If the bus is found, a pointer to its
+ * data structure is returned.  If no bus is found, %NULL is returned.
+ */
+struct pci_bus * __devinit pci_find_bus(int domain, int busnr)
+{
+	struct pci_bus *bus = NULL;
+	struct pci_bus *tmp_bus;
+
+	while ((bus = pci_find_next_bus(bus)) != NULL)  {
+		if (pci_domain_nr(bus) != domain)
+			continue;
+		tmp_bus = pci_do_find_bus(bus, busnr);
+		if (tmp_bus)
+			return tmp_bus;
+	}
+	return NULL;
+}
+
+/**
+ * pci_find_next_bus - begin or continue searching for a PCI bus
+ * @from: Previous PCI bus found, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI busses.  A new search is
+ * initiated by passing %NULL to the @from argument.  Otherwise if
+ * @from is not %NULL, searches continue from next device on the
+ * global list.
+ */
+struct pci_bus * 
+pci_find_next_bus(const struct pci_bus *from)
+{
+	struct list_head *n;
+	struct pci_bus *b = NULL;
+
+	WARN_ON(in_interrupt());
+	spin_lock(&pci_bus_lock);
+	n = from ? from->node.next : pci_root_buses.next;
+	if (n != &pci_root_buses)
+		b = pci_bus_b(n);
+	spin_unlock(&pci_bus_lock);
+	return b;
+}
+
+/**
+ * pci_find_slot - locate PCI device from a given PCI slot
+ * @bus: number of PCI bus on which desired PCI device resides
+ * @devfn: encodes number of PCI slot in which the desired PCI 
+ * device resides and the logical device number within that slot 
+ * in case of multi-function devices.
+ *
+ * Given a PCI bus and slot/function number, the desired PCI device 
+ * is located in system global list of PCI devices.  If the device
+ * is found, a pointer to its data structure is returned.  If no 
+ * device is found, %NULL is returned.
+ */
+struct pci_dev *
+pci_find_slot(unsigned int bus, unsigned int devfn)
+{
+	struct pci_dev *dev = NULL;
+
+	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		if (dev->bus->number == bus && dev->devfn == devfn)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
+ * pci_get_slot - locate PCI device for a given PCI slot
+ * @bus: PCI bus on which desired PCI device resides
+ * @devfn: encodes number of PCI slot in which the desired PCI 
+ * device resides and the logical device number within that slot 
+ * in case of multi-function devices.
+ *
+ * Given a PCI bus and slot/function number, the desired PCI device 
+ * is located in the list of PCI devices.
+ * If the device is found, its reference count is increased and this
+ * function returns a pointer to its data structure.  The caller must
+ * decrement the reference count by calling pci_dev_put().
+ * If no device is found, %NULL is returned.
+ */
+struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
+{
+	struct list_head *tmp;
+	struct pci_dev *dev;
+
+	WARN_ON(in_interrupt());
+	spin_lock(&pci_bus_lock);
+
+	list_for_each(tmp, &bus->devices) {
+		dev = pci_dev_b(tmp);
+		if (dev->devfn == devfn)
+			goto out;
+	}
+
+	dev = NULL;
+ out:
+	pci_dev_get(dev);
+	spin_unlock(&pci_bus_lock);
+	return dev;
+}
+
+/**
+ * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
+ * device structure is returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ *
+ * NOTE: Do not use this function anymore, use pci_get_subsys() instead, as
+ * the pci device returned by this function can disappear at any moment in
+ * time.
+ */
+static struct pci_dev * pci_find_subsys(unsigned int vendor,
+				        unsigned int device,
+					unsigned int ss_vendor,
+					unsigned int ss_device,
+					const struct pci_dev *from)
+{
+	struct list_head *n;
+	struct pci_dev *dev;
+
+	WARN_ON(in_interrupt());
+	spin_lock(&pci_bus_lock);
+	n = from ? from->global_list.next : pci_devices.next;
+
+	while (n && (n != &pci_devices)) {
+		dev = pci_dev_g(n);
+		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
+		    (device == PCI_ANY_ID || dev->device == device) &&
+		    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
+		    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
+			goto exit;
+		n = n->next;
+	}
+	dev = NULL;
+exit:
+	spin_unlock(&pci_bus_lock);
+	return dev;
+}
+
+/**
+ * pci_find_device - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @vendor and @device, a pointer to its device structure is
+ * returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ * 
+ * NOTE: Do not use this function anymore, use pci_get_device() instead, as
+ * the pci device returned by this function can disappear at any moment in
+ * time.
+ */
+struct pci_dev *
+pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
+{
+	return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
+}
+
+/**
+ * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
+ * device structure is returned, and the reference count to the device is
+ * incremented.  Otherwise, %NULL is returned.  A new search is initiated by
+ * passing %NULL to the @from argument.  Otherwise if @from is not %NULL,
+ * searches continue from next device on the global list.
+ * The reference count for @from is always decremented if it is not %NULL.
+ */
+struct pci_dev * 
+pci_get_subsys(unsigned int vendor, unsigned int device,
+	       unsigned int ss_vendor, unsigned int ss_device,
+	       struct pci_dev *from)
+{
+	struct list_head *n;
+	struct pci_dev *dev;
+
+	WARN_ON(in_interrupt());
+	spin_lock(&pci_bus_lock);
+	n = from ? from->global_list.next : pci_devices.next;
+
+	while (n && (n != &pci_devices)) {
+		dev = pci_dev_g(n);
+		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
+		    (device == PCI_ANY_ID || dev->device == device) &&
+		    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
+		    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
+			goto exit;
+		n = n->next;
+	}
+	dev = NULL;
+exit:
+	pci_dev_put(from);
+	dev = pci_dev_get(dev);
+	spin_unlock(&pci_bus_lock);
+	return dev;
+}
+
+/**
+ * pci_get_device - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @vendor and @device, the reference count to the
+ * device is incremented and a pointer to its device structure is returned.
+ * Otherwise, %NULL is returned.  A new search is initiated by passing %NULL
+ * to the @from argument.  Otherwise if @from is not %NULL, searches continue
+ * from next device on the global list.  The reference count for @from is
+ * always decremented if it is not %NULL.
+ */
+struct pci_dev *
+pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
+{
+	return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
+}
+
+
+/**
+ * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices in the reverse order of pci_find_device().
+ * If a PCI device is found with a matching @vendor and @device, a pointer to
+ * its device structure is returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from previous device on the global list.
+ */
+struct pci_dev *
+pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
+{
+	struct list_head *n;
+	struct pci_dev *dev;
+
+	WARN_ON(in_interrupt());
+	spin_lock(&pci_bus_lock);
+	n = from ? from->global_list.prev : pci_devices.prev;
+
+	while (n && (n != &pci_devices)) {
+		dev = pci_dev_g(n);
+		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
+		    (device == PCI_ANY_ID || dev->device == device))
+			goto exit;
+		n = n->prev;
+	}
+	dev = NULL;
+exit:
+	spin_unlock(&pci_bus_lock);
+	return dev;
+}
+
+/**
+ * pci_get_class - begin or continue searching for a PCI device by class
+ * @class: search for a PCI device with this class designation
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @class, the reference count to the device is
+ * incremented and a pointer to its device structure is returned.
+ * Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.  The reference count for @from is always decremented
+ * if it is not %NULL.
+ */
+struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
+{
+	struct list_head *n;
+	struct pci_dev *dev;
+
+	WARN_ON(in_interrupt());
+	spin_lock(&pci_bus_lock);
+	n = from ? from->global_list.next : pci_devices.next;
+
+	while (n && (n != &pci_devices)) {
+		dev = pci_dev_g(n);
+		if (dev->class == class)
+			goto exit;
+		n = n->next;
+	}
+	dev = NULL;
+exit:
+	pci_dev_put(from);
+	dev = pci_dev_get(dev);
+	spin_unlock(&pci_bus_lock);
+	return dev;
+}
+
+/**
+ * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
+ * @ids: A pointer to a null terminated list of struct pci_device_id structures
+ * that describe the type of PCI device the caller is trying to find.
+ *
+ * Obvious fact: You do not have a reference to any device that might be found
+ * by this function, so if that device is removed from the system right after
+ * this function is finished, the value will be stale.  Use this function to
+ * find devices that are usually built into a system, or for a general hint as
+ * to if another device happens to be present at this specific moment in time.
+ */
+int pci_dev_present(const struct pci_device_id *ids)
+{
+	struct pci_dev *dev;
+	int found = 0;
+
+	WARN_ON(in_interrupt());
+	spin_lock(&pci_bus_lock);
+	while (ids->vendor || ids->subvendor || ids->class_mask) {
+		list_for_each_entry(dev, &pci_devices, global_list) {
+			if (pci_match_one_device(ids, dev)) {
+				found = 1;
+				goto exit;
+			}
+		}
+		ids++;
+	}
+exit:				
+	spin_unlock(&pci_bus_lock);
+	return found;
+}
+EXPORT_SYMBOL(pci_dev_present);
+
+EXPORT_SYMBOL(pci_find_bus);
+EXPORT_SYMBOL(pci_find_device);
+EXPORT_SYMBOL(pci_find_device_reverse);
+EXPORT_SYMBOL(pci_find_slot);
+EXPORT_SYMBOL(pci_get_device);
+EXPORT_SYMBOL(pci_get_subsys);
+EXPORT_SYMBOL(pci_get_slot);
+EXPORT_SYMBOL(pci_get_class);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
new file mode 100644
index 0000000..1ba84be
--- /dev/null
+++ b/drivers/pci/setup-bus.c
@@ -0,0 +1,552 @@
+/*
+ *	drivers/pci/setup-bus.c
+ *
+ * Extruded from code written by
+ *      Dave Rusling (david.rusling@reo.mts.dec.com)
+ *      David Mosberger (davidm@cs.arizona.edu)
+ *	David Miller (davem@redhat.com)
+ *
+ * Support routines for initializing a PCI subsystem.
+ */
+
+/*
+ * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+ *	     PCI-PCI bridges cleanup, sorted resource allocation.
+ * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+ *	     Converted to allocation in 3 passes, which gives
+ *	     tighter packing. Prefetchable range support.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/cache.h>
+#include <linux/slab.h>
+
+
+#define DEBUG_CONFIG 1
+#if DEBUG_CONFIG
+#define DBG(x...)     printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
+
+/*
+ * FIXME: IO should be max 256 bytes.  However, since we may
+ * have a P2P bridge below a cardbus bridge, we need 4K.
+ */
+#define CARDBUS_IO_SIZE		(4096)
+#define CARDBUS_MEM_SIZE	(32*1024*1024)
+
+static void __devinit
+pbus_assign_resources_sorted(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+	struct resource *res;
+	struct resource_list head, *list, *tmp;
+	int idx;
+
+	bus->bridge_ctl &= ~PCI_BRIDGE_CTL_VGA;
+
+	head.next = NULL;
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		u16 class = dev->class >> 8;
+
+		/* Don't touch classless devices and host bridges.  */
+		if (class == PCI_CLASS_NOT_DEFINED ||
+		    class == PCI_CLASS_BRIDGE_HOST)
+			continue;
+
+		if (class == PCI_CLASS_DISPLAY_VGA ||
+		    class == PCI_CLASS_NOT_DEFINED_VGA)
+			bus->bridge_ctl |= PCI_BRIDGE_CTL_VGA;
+
+		pdev_sort_resources(dev, &head);
+	}
+
+	for (list = head.next; list;) {
+		res = list->res;
+		idx = res - &list->dev->resource[0];
+		pci_assign_resource(list->dev, idx);
+		tmp = list;
+		list = list->next;
+		kfree(tmp);
+	}
+}
+
+static void __devinit
+pci_setup_cardbus(struct pci_bus *bus)
+{
+	struct pci_dev *bridge = bus->self;
+	struct pci_bus_region region;
+
+	printk("PCI: Bus %d, cardbus bridge: %s\n",
+		bus->number, pci_name(bridge));
+
+	pcibios_resource_to_bus(bridge, &region, bus->resource[0]);
+	if (bus->resource[0]->flags & IORESOURCE_IO) {
+		/*
+		 * The IO resource is allocated a range twice as large as it
+		 * would normally need.  This allows us to set both IO regs.
+		 */
+		printk("  IO window: %08lx-%08lx\n",
+			region.start, region.end);
+		pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
+					region.start);
+		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
+					region.end);
+	}
+
+	pcibios_resource_to_bus(bridge, &region, bus->resource[1]);
+	if (bus->resource[1]->flags & IORESOURCE_IO) {
+		printk("  IO window: %08lx-%08lx\n",
+			region.start, region.end);
+		pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
+					region.start);
+		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
+					region.end);
+	}
+
+	pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
+	if (bus->resource[2]->flags & IORESOURCE_MEM) {
+		printk("  PREFETCH window: %08lx-%08lx\n",
+			region.start, region.end);
+		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
+					region.start);
+		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
+					region.end);
+	}
+
+	pcibios_resource_to_bus(bridge, &region, bus->resource[3]);
+	if (bus->resource[3]->flags & IORESOURCE_MEM) {
+		printk("  MEM window: %08lx-%08lx\n",
+			region.start, region.end);
+		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
+					region.start);
+		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
+					region.end);
+	}
+}
+
+/* Initialize bridges with base/limit values we have collected.
+   PCI-to-PCI Bridge Architecture Specification rev. 1.1 (1998)
+   requires that if there is no I/O ports or memory behind the
+   bridge, corresponding range must be turned off by writing base
+   value greater than limit to the bridge's base/limit registers.
+
+   Note: care must be taken when updating I/O base/limit registers
+   of bridges which support 32-bit I/O. This update requires two
+   config space writes, so it's quite possible that an I/O window of
+   the bridge will have some undesirable address (e.g. 0) after the
+   first write. Ditto 64-bit prefetchable MMIO.  */
+static void __devinit
+pci_setup_bridge(struct pci_bus *bus)
+{
+	struct pci_dev *bridge = bus->self;
+	struct pci_bus_region region;
+	u32 l, io_upper16;
+
+	DBG(KERN_INFO "PCI: Bridge: %s\n", pci_name(bridge));
+
+	/* Set up the top and bottom of the PCI I/O segment for this bus. */
+	pcibios_resource_to_bus(bridge, &region, bus->resource[0]);
+	if (bus->resource[0]->flags & IORESOURCE_IO) {
+		pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+		l &= 0xffff0000;
+		l |= (region.start >> 8) & 0x00f0;
+		l |= region.end & 0xf000;
+		/* Set up upper 16 bits of I/O base/limit. */
+		io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
+		DBG(KERN_INFO "  IO window: %04lx-%04lx\n",
+				region.start, region.end);
+	}
+	else {
+		/* Clear upper 16 bits of I/O base/limit. */
+		io_upper16 = 0;
+		l = 0x00f0;
+		DBG(KERN_INFO "  IO window: disabled.\n");
+	}
+	/* Temporarily disable the I/O range before updating PCI_IO_BASE. */
+	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
+	/* Update lower 16 bits of I/O base/limit. */
+	pci_write_config_dword(bridge, PCI_IO_BASE, l);
+	/* Update upper 16 bits of I/O base/limit. */
+	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
+
+	/* Set up the top and bottom of the PCI Memory segment
+	   for this bus. */
+	pcibios_resource_to_bus(bridge, &region, bus->resource[1]);
+	if (bus->resource[1]->flags & IORESOURCE_MEM) {
+		l = (region.start >> 16) & 0xfff0;
+		l |= region.end & 0xfff00000;
+		DBG(KERN_INFO "  MEM window: %08lx-%08lx\n",
+				region.start, region.end);
+	}
+	else {
+		l = 0x0000fff0;
+		DBG(KERN_INFO "  MEM window: disabled.\n");
+	}
+	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+
+	/* Clear out the upper 32 bits of PREF limit.
+	   If PCI_PREF_BASE_UPPER32 was non-zero, this temporarily
+	   disables PREF range, which is ok. */
+	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
+
+	/* Set up PREF base/limit. */
+	pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
+	if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
+		l = (region.start >> 16) & 0xfff0;
+		l |= region.end & 0xfff00000;
+		DBG(KERN_INFO "  PREFETCH window: %08lx-%08lx\n",
+				region.start, region.end);
+	}
+	else {
+		l = 0x0000fff0;
+		DBG(KERN_INFO "  PREFETCH window: disabled.\n");
+	}
+	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+	/* Clear out the upper 32 bits of PREF base. */
+	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+
+	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
+}
+
+/* Check whether the bridge supports optional I/O and
+   prefetchable memory ranges. If not, the respective
+   base/limit registers must be read-only and read as 0. */
+static void __devinit
+pci_bridge_check_ranges(struct pci_bus *bus)
+{
+	u16 io;
+	u32 pmem;
+	struct pci_dev *bridge = bus->self;
+	struct resource *b_res;
+
+	b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
+	b_res[1].flags |= IORESOURCE_MEM;
+
+	pci_read_config_word(bridge, PCI_IO_BASE, &io);
+	if (!io) {
+		pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
+		pci_read_config_word(bridge, PCI_IO_BASE, &io);
+ 		pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
+ 	}
+ 	if (io)
+		b_res[0].flags |= IORESOURCE_IO;
+	/*  DECchip 21050 pass 2 errata: the bridge may miss an address
+	    disconnect boundary by one PCI data phase.
+	    Workaround: do not use prefetching on this device. */
+	if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
+		return;
+	pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
+	if (!pmem) {
+		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
+					       0xfff0fff0);
+		pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
+		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
+	}
+	if (pmem)
+		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+}
+
+/* Helper function for sizing routines: find first available
+   bus resource of a given type. Note: we intentionally skip
+   the bus resources which have already been assigned (that is,
+   have non-NULL parent resource). */
+static struct resource * __devinit
+find_free_bus_resource(struct pci_bus *bus, unsigned long type)
+{
+	int i;
+	struct resource *r;
+	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+				  IORESOURCE_PREFETCH;
+
+	for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+		r = bus->resource[i];
+		if (r && (r->flags & type_mask) == type && !r->parent)
+			return r;
+	}
+	return NULL;
+}
+
+/* Sizing the IO windows of the PCI-PCI bridge is trivial,
+   since these windows have 4K granularity and the IO ranges
+   of non-bridge PCI devices are limited to 256 bytes.
+   We must be careful with the ISA aliasing though. */
+static void __devinit
+pbus_size_io(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
+	unsigned long size = 0, size1 = 0;
+
+	if (!b_res)
+ 		return;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		int i;
+
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &dev->resource[i];
+			unsigned long r_size;
+
+			if (r->parent || !(r->flags & IORESOURCE_IO))
+				continue;
+			r_size = r->end - r->start + 1;
+
+			if (r_size < 0x400)
+				/* Might be re-aligned for ISA */
+				size += r_size;
+			else
+				size1 += r_size;
+		}
+	}
+/* To be fixed in 2.5: we should have sort of HAVE_ISA
+   flag in the struct pci_bus. */
+#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
+	size = (size & 0xff) + ((size & ~0xffUL) << 2);
+#endif
+	size = ROUND_UP(size + size1, 4096);
+	if (!size) {
+		b_res->flags = 0;
+		return;
+	}
+	/* Alignment of the IO window is always 4K */
+	b_res->start = 4096;
+	b_res->end = b_res->start + size - 1;
+}
+
+/* Calculate the size of the bus and minimal alignment which
+   guarantees that all child resources fit in this size. */
+static int __devinit
+pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
+{
+	struct pci_dev *dev;
+	unsigned long min_align, align, size;
+	unsigned long aligns[12];	/* Alignments from 1Mb to 2Gb */
+	int order, max_order;
+	struct resource *b_res = find_free_bus_resource(bus, type);
+
+	if (!b_res)
+		return 0;
+
+	memset(aligns, 0, sizeof(aligns));
+	max_order = 0;
+	size = 0;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		int i;
+		
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &dev->resource[i];
+			unsigned long r_size;
+
+			if (r->parent || (r->flags & mask) != type)
+				continue;
+			r_size = r->end - r->start + 1;
+			/* For bridges size != alignment */
+			align = (i < PCI_BRIDGE_RESOURCES) ? r_size : r->start;
+			order = __ffs(align) - 20;
+			if (order > 11) {
+				printk(KERN_WARNING "PCI: region %s/%d "
+				       "too large: %lx-%lx\n",
+				       pci_name(dev), i, r->start, r->end);
+				r->flags = 0;
+				continue;
+			}
+			size += r_size;
+			if (order < 0)
+				order = 0;
+			/* Exclude ranges with size > align from
+			   calculation of the alignment. */
+			if (r_size == align)
+				aligns[order] += align;
+			if (order > max_order)
+				max_order = order;
+		}
+	}
+
+	align = 0;
+	min_align = 0;
+	for (order = 0; order <= max_order; order++) {
+		unsigned long align1 = 1UL << (order + 20);
+
+		if (!align)
+			min_align = align1;
+		else if (ROUND_UP(align + min_align, min_align) < align1)
+			min_align = align1 >> 1;
+		align += aligns[order];
+	}
+	size = ROUND_UP(size, min_align);
+	if (!size) {
+		b_res->flags = 0;
+		return 1;
+	}
+	b_res->start = min_align;
+	b_res->end = size + min_align - 1;
+	return 1;
+}
+
+static void __devinit
+pci_bus_size_cardbus(struct pci_bus *bus)
+{
+	struct pci_dev *bridge = bus->self;
+	struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
+	u16 ctrl;
+
+	/*
+	 * Reserve some resources for CardBus.  We reserve
+	 * a fixed amount of bus space for CardBus bridges.
+	 */
+	b_res[0].start = CARDBUS_IO_SIZE;
+	b_res[0].end = b_res[0].start + CARDBUS_IO_SIZE - 1;
+	b_res[0].flags |= IORESOURCE_IO;
+
+	b_res[1].start = CARDBUS_IO_SIZE;
+	b_res[1].end = b_res[1].start + CARDBUS_IO_SIZE - 1;
+	b_res[1].flags |= IORESOURCE_IO;
+
+	/*
+	 * Check whether prefetchable memory is supported
+	 * by this bridge.
+	 */
+	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+	if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
+		ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
+		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
+		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
+	}
+
+	/*
+	 * If we have prefetchable memory support, allocate
+	 * two regions.  Otherwise, allocate one region of
+	 * twice the size.
+	 */
+	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
+		b_res[2].start = CARDBUS_MEM_SIZE;
+		b_res[2].end = b_res[2].start + CARDBUS_MEM_SIZE - 1;
+		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+		b_res[3].start = CARDBUS_MEM_SIZE;
+		b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE - 1;
+		b_res[3].flags |= IORESOURCE_MEM;
+	} else {
+		b_res[3].start = CARDBUS_MEM_SIZE * 2;
+		b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE * 2 - 1;
+		b_res[3].flags |= IORESOURCE_MEM;
+	}
+}
+
+void __devinit
+pci_bus_size_bridges(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+	unsigned long mask, prefmask;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		struct pci_bus *b = dev->subordinate;
+		if (!b)
+			continue;
+
+		switch (dev->class >> 8) {
+		case PCI_CLASS_BRIDGE_CARDBUS:
+			pci_bus_size_cardbus(b);
+			break;
+
+		case PCI_CLASS_BRIDGE_PCI:
+		default:
+			pci_bus_size_bridges(b);
+			break;
+		}
+	}
+
+	/* The root bus? */
+	if (!bus->self)
+		return;
+
+	switch (bus->self->class >> 8) {
+	case PCI_CLASS_BRIDGE_CARDBUS:
+		/* don't size cardbuses yet. */
+		break;
+
+	case PCI_CLASS_BRIDGE_PCI:
+		pci_bridge_check_ranges(bus);
+	default:
+		pbus_size_io(bus);
+		/* If the bridge supports prefetchable range, size it
+		   separately. If it doesn't, or its prefetchable window
+		   has already been allocated by arch code, try
+		   non-prefetchable range for both types of PCI memory
+		   resources. */
+		mask = IORESOURCE_MEM;
+		prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+		if (pbus_size_mem(bus, prefmask, prefmask))
+			mask = prefmask; /* Success, size non-prefetch only. */
+		pbus_size_mem(bus, mask, IORESOURCE_MEM);
+		break;
+	}
+}
+EXPORT_SYMBOL(pci_bus_size_bridges);
+
+void __devinit
+pci_bus_assign_resources(struct pci_bus *bus)
+{
+	struct pci_bus *b;
+	struct pci_dev *dev;
+
+	pbus_assign_resources_sorted(bus);
+
+	if (bus->bridge_ctl & PCI_BRIDGE_CTL_VGA) {
+		/* Propagate presence of the VGA to upstream bridges */
+		for (b = bus; b->parent; b = b->parent) {
+			b->bridge_ctl |= PCI_BRIDGE_CTL_VGA;
+		}
+	}
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		b = dev->subordinate;
+		if (!b)
+			continue;
+
+		pci_bus_assign_resources(b);
+
+		switch (dev->class >> 8) {
+		case PCI_CLASS_BRIDGE_PCI:
+			pci_setup_bridge(b);
+			break;
+
+		case PCI_CLASS_BRIDGE_CARDBUS:
+			pci_setup_cardbus(b);
+			break;
+
+		default:
+			printk(KERN_INFO "PCI: not setting up bridge %s "
+			       "for bus %d\n", pci_name(dev), b->number);
+			break;
+		}
+	}
+}
+EXPORT_SYMBOL(pci_bus_assign_resources);
+
+void __init
+pci_assign_unassigned_resources(void)
+{
+	struct pci_bus *bus;
+
+	/* Depth first, calculate sizes and alignments of all
+	   subordinate buses. */
+	list_for_each_entry(bus, &pci_root_buses, node) {
+		pci_bus_size_bridges(bus);
+	}
+	/* Depth last, allocate resources and update the hardware. */
+	list_for_each_entry(bus, &pci_root_buses, node) {
+		pci_bus_assign_resources(bus);
+		pci_enable_bridges(bus);
+	}
+}
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
new file mode 100644
index 0000000..a251289
--- /dev/null
+++ b/drivers/pci/setup-irq.c
@@ -0,0 +1,64 @@
+/*
+ *	drivers/pci/setup-irq.c
+ *
+ * Extruded from code written by
+ *      Dave Rusling (david.rusling@reo.mts.dec.com)
+ *      David Mosberger (davidm@cs.arizona.edu)
+ *	David Miller (davem@redhat.com)
+ *
+ * Support routines for initializing a PCI subsystem.
+ */
+
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/cache.h>
+
+
+static void __init
+pdev_fixup_irq(struct pci_dev *dev,
+	       u8 (*swizzle)(struct pci_dev *, u8 *),
+	       int (*map_irq)(struct pci_dev *, u8, u8))
+{
+	u8 pin, slot;
+	int irq;
+
+	/* If this device is not on the primary bus, we need to figure out
+	   which interrupt pin it will come in on.   We know which slot it
+	   will come in on 'cos that slot is where the bridge is.   Each
+	   time the interrupt line passes through a PCI-PCI bridge we must
+	   apply the swizzle function.  */
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	/* Cope with 0 and illegal. */
+	if (pin == 0 || pin > 4)
+		pin = 1;
+
+	/* Follow the chain of bridges, swizzling as we go.  */
+	slot = (*swizzle)(dev, &pin);
+
+	irq = (*map_irq)(dev, slot, pin);
+	if (irq == -1)
+		irq = 0;
+	dev->irq = irq;
+
+	pr_debug("PCI: fixup irq: (%s) got %d\n",
+		dev->dev.kobj.name, dev->irq);
+
+	/* Always tell the device, so the driver knows what is
+	   the real IRQ to use; the device does not use it. */
+	pcibios_update_irq(dev, irq);
+}
+
+void __init
+pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
+	       int (*map_irq)(struct pci_dev *, u8, u8))
+{
+	struct pci_dev *dev = NULL;
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		pdev_fixup_irq(dev, swizzle, map_irq);
+	}
+}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
new file mode 100644
index 0000000..1ca21d2
--- /dev/null
+++ b/drivers/pci/setup-res.c
@@ -0,0 +1,200 @@
+/*
+ *	drivers/pci/setup-res.c
+ *
+ * Extruded from code written by
+ *      Dave Rusling (david.rusling@reo.mts.dec.com)
+ *      David Mosberger (davidm@cs.arizona.edu)
+ *	David Miller (davem@redhat.com)
+ *
+ * Support routines for initializing a PCI subsystem.
+ */
+
+/* fixed for multiple pci buses, 1999 Andrea Arcangeli <andrea@suse.de> */
+
+/*
+ * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+ *	     Resource sorting
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/cache.h>
+#include <linux/slab.h>
+#include "pci.h"
+
+
+static void
+pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
+{
+	struct pci_bus_region region;
+	u32 new, check, mask;
+	int reg;
+
+	pcibios_resource_to_bus(dev, &region, res);
+
+	pr_debug("  got res [%lx:%lx] bus [%lx:%lx] flags %lx for "
+		 "BAR %d of %s\n", res->start, res->end,
+		 region.start, region.end, res->flags, resno, pci_name(dev));
+
+	new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
+	if (res->flags & IORESOURCE_IO)
+		mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
+	else
+		mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
+
+	if (resno < 6) {
+		reg = PCI_BASE_ADDRESS_0 + 4 * resno;
+	} else if (resno == PCI_ROM_RESOURCE) {
+		new |= res->flags & IORESOURCE_ROM_ENABLE;
+		reg = dev->rom_base_reg;
+	} else {
+		/* Hmm, non-standard resource. */
+	
+		return;		/* kill uninitialised var warning */
+	}
+
+	pci_write_config_dword(dev, reg, new);
+	pci_read_config_dword(dev, reg, &check);
+
+	if ((new ^ check) & mask) {
+		printk(KERN_ERR "PCI: Error while updating region "
+		       "%s/%d (%08x != %08x)\n", pci_name(dev), resno,
+		       new, check);
+	}
+
+	if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
+	    (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+		new = 0; /* currently everyone zeros the high address */
+		pci_write_config_dword(dev, reg + 4, new);
+		pci_read_config_dword(dev, reg + 4, &check);
+		if (check != new) {
+			printk(KERN_ERR "PCI: Error updating region "
+			       "%s/%d (high %08x != %08x)\n",
+			       pci_name(dev), resno, new, check);
+		}
+	}
+	res->flags &= ~IORESOURCE_UNSET;
+	pr_debug("PCI: moved device %s resource %d (%lx) to %x\n",
+		pci_name(dev), resno, res->flags,
+		new & ~PCI_REGION_FLAG_MASK);
+}
+
+int __devinit
+pci_claim_resource(struct pci_dev *dev, int resource)
+{
+	struct resource *res = &dev->resource[resource];
+	struct resource *root = NULL;
+	char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
+	int err;
+
+	if (res->flags & IORESOURCE_IO)
+		root = &ioport_resource;
+	if (res->flags & IORESOURCE_MEM)
+		root = &iomem_resource;
+
+	err = -EINVAL;
+	if (root != NULL)
+		err = insert_resource(root, res);
+
+	if (err) {
+		printk(KERN_ERR "PCI: %s region %d of %s %s [%lx:%lx]\n",
+		       root ? "Address space collision on" :
+			      "No parent found for",
+		       resource, dtype, pci_name(dev), res->start, res->end);
+	}
+
+	return err;
+}
+
+int pci_assign_resource(struct pci_dev *dev, int resno)
+{
+	struct pci_bus *bus = dev->bus;
+	struct resource *res = dev->resource + resno;
+	unsigned long size, min, align;
+	int ret;
+
+	size = res->end - res->start + 1;
+	min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
+	/* The bridge resources are special, as their
+	   size != alignment. Sizing routines return
+	   required alignment in the "start" field. */
+	align = (resno < PCI_BRIDGE_RESOURCES) ? size : res->start;
+
+	/* First, try exact prefetching match.. */
+	ret = pci_bus_alloc_resource(bus, res, size, align, min,
+				     IORESOURCE_PREFETCH,
+				     pcibios_align_resource, dev);
+
+	if (ret < 0 && (res->flags & IORESOURCE_PREFETCH)) {
+		/*
+		 * That failed.
+		 *
+		 * But a prefetching area can handle a non-prefetching
+		 * window (it will just not perform as well).
+		 */
+		ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,
+					     pcibios_align_resource, dev);
+	}
+
+	if (ret) {
+		printk(KERN_ERR "PCI: Failed to allocate %s resource #%d:%lx@%lx for %s\n",
+		       res->flags & IORESOURCE_IO ? "I/O" : "mem",
+		       resno, size, res->start, pci_name(dev));
+	} else if (resno < PCI_BRIDGE_RESOURCES) {
+		pci_update_resource(dev, res, resno);
+	}
+
+	return ret;
+}
+
+/* Sort resources by alignment */
+void __devinit
+pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
+{
+	int i;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *r;
+		struct resource_list *list, *tmp;
+		unsigned long r_align;
+
+		r = &dev->resource[i];
+		r_align = r->end - r->start;
+		
+		if (!(r->flags) || r->parent)
+			continue;
+		if (!r_align) {
+			printk(KERN_WARNING "PCI: Ignore bogus resource %d "
+					    "[%lx:%lx] of %s\n",
+					    i, r->start, r->end, pci_name(dev));
+			continue;
+		}
+		r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
+		for (list = head; ; list = list->next) {
+			unsigned long align = 0;
+			struct resource_list *ln = list->next;
+			int idx;
+
+			if (ln) {
+				idx = ln->res - &ln->dev->resource[0];
+				align = (idx < PCI_BRIDGE_RESOURCES) ?
+					ln->res->end - ln->res->start + 1 :
+					ln->res->start;
+			}
+			if (r_align > align) {
+				tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+				if (!tmp)
+					panic("pdev_sort_resources(): "
+					      "kmalloc() failed!\n");
+				tmp->next = ln;
+				tmp->res = r;
+				tmp->dev = dev;
+				list->next = tmp;
+				break;
+			}
+		}
+	}
+}
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
new file mode 100644
index 0000000..c071790
--- /dev/null
+++ b/drivers/pci/syscall.c
@@ -0,0 +1,145 @@
+/*
+ *	pci_syscall.c
+ *
+ * For architectures where we want to allow direct access
+ * to the PCI config stuff - it would probably be preferable
+ * on PCs too, but there people just do it by hand with the
+ * magic northbridge registers..
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/syscalls.h>
+#include <asm/uaccess.h>
+
+
+asmlinkage long
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+		   unsigned long off, unsigned long len,
+		   void __user *buf)
+{
+	struct pci_dev *dev;
+	u8 byte;
+	u16 word;
+	u32 dword;
+	long err, cfg_ret;
+
+	err = -EPERM;
+	if (!capable(CAP_SYS_ADMIN))
+		goto error;
+
+	err = -ENODEV;
+	dev = pci_find_slot(bus, dfn);
+	if (!dev)
+		goto error;
+
+	lock_kernel();
+	switch (len) {
+	case 1:
+		cfg_ret = pci_read_config_byte(dev, off, &byte);
+		break;
+	case 2:
+		cfg_ret = pci_read_config_word(dev, off, &word);
+		break;
+	case 4:
+		cfg_ret = pci_read_config_dword(dev, off, &dword);
+		break;
+	default:
+		err = -EINVAL;
+		unlock_kernel();
+		goto error;
+	};
+	unlock_kernel();
+
+	err = -EIO;
+	if (cfg_ret != PCIBIOS_SUCCESSFUL)
+		goto error;
+
+	switch (len) {
+	case 1:
+		err = put_user(byte, (unsigned char __user *)buf);
+		break;
+	case 2:
+		err = put_user(word, (unsigned short __user *)buf);
+		break;
+	case 4:
+		err = put_user(dword, (unsigned int __user *)buf);
+		break;
+	};
+	return err;
+
+error:
+	/* ??? XFree86 doesn't even check the return value.  They
+	   just look for 0xffffffff in the output, since that's what
+	   they get instead of a machine check on x86.  */
+	switch (len) {
+	case 1:
+		put_user(-1, (unsigned char __user *)buf);
+		break;
+	case 2:
+		put_user(-1, (unsigned short __user *)buf);
+		break;
+	case 4:
+		put_user(-1, (unsigned int __user *)buf);
+		break;
+	};
+	return err;
+}
+
+asmlinkage long
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+		    unsigned long off, unsigned long len,
+		    void __user *buf)
+{
+	struct pci_dev *dev;
+	u8 byte;
+	u16 word;
+	u32 dword;
+	int err = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	dev = pci_find_slot(bus, dfn);
+	if (!dev)
+		return -ENODEV;
+
+	lock_kernel();
+	switch(len) {
+	case 1:
+		err = get_user(byte, (u8 __user *)buf);
+		if (err)
+			break;
+		err = pci_write_config_byte(dev, off, byte);
+		if (err != PCIBIOS_SUCCESSFUL)
+			err = -EIO;
+		break;
+
+	case 2:
+		err = get_user(word, (u16 __user *)buf);
+		if (err)
+			break;
+		err = pci_write_config_word(dev, off, word);
+		if (err != PCIBIOS_SUCCESSFUL)
+			err = -EIO;
+		break;
+
+	case 4:
+		err = get_user(dword, (u32 __user *)buf);
+		if (err)
+			break;
+		err = pci_write_config_dword(dev, off, dword);
+		if (err != PCIBIOS_SUCCESSFUL)
+			err = -EIO;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	};
+	unlock_kernel();
+
+	return err;
+}