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/base/Kconfig b/drivers/base/Kconfig
new file mode 100644
index 0000000..934149c
--- /dev/null
+++ b/drivers/base/Kconfig
@@ -0,0 +1,40 @@
+menu "Generic Driver Options"
+
+config STANDALONE
+	bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
+	default y
+	help
+	  Select this option if you don't have magic firmware for drivers that
+	  need it.
+
+	  If unsure, say Y.
+
+config PREVENT_FIRMWARE_BUILD
+	bool "Prevent firmware from being built"
+	default y
+	help
+	  Say yes to avoid building firmware. Firmware is usually shipped
+	  with the driver, and only when updating the firmware a rebuild
+	  should be made.
+	  If unsure say Y here.
+
+config FW_LOADER
+	tristate "Hotplug firmware loading support"
+	select HOTPLUG
+	---help---
+	  This option is provided for the case where no in-kernel-tree modules
+	  require hotplug firmware loading support, but a module built outside
+	  the kernel tree does.
+
+config DEBUG_DRIVER
+	bool "Driver Core verbose debug messages"
+	depends on DEBUG_KERNEL
+	help
+	  Say Y here if you want the Driver core to produce a bunch of
+	  debug messages to the system log. Select this if you are having a
+	  problem with the driver core and want to see more of what is
+	  going on.
+
+	  If you are unsure about this, say N here.
+
+endmenu
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
new file mode 100644
index 0000000..6662b54
--- /dev/null
+++ b/drivers/base/Makefile
@@ -0,0 +1,14 @@
+# Makefile for the Linux device tree
+
+obj-y			:= core.o sys.o interface.o bus.o \
+			   driver.o class.o class_simple.o platform.o \
+			   cpu.o firmware.o init.o map.o dmapool.o \
+			   attribute_container.o transport_class.o
+obj-y			+= power/
+obj-$(CONFIG_FW_LOADER)	+= firmware_class.o
+obj-$(CONFIG_NUMA)	+= node.o
+
+ifeq ($(CONFIG_DEBUG_DRIVER),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
new file mode 100644
index 0000000..ec615d8
--- /dev/null
+++ b/drivers/base/attribute_container.c
@@ -0,0 +1,376 @@
+/*
+ * attribute_container.c - implementation of a simple container for classes
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com>
+ *
+ * This file is licensed under GPLv2
+ *
+ * The basic idea here is to enable a device to be attached to an
+ * aritrary numer of classes without having to allocate storage for them.
+ * Instead, the contained classes select the devices they need to attach
+ * to via a matching function.
+ */
+
+#include <linux/attribute_container.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
+/* This is a private structure used to tie the classdev and the
+ * container .. it should never be visible outside this file */
+struct internal_container {
+	struct list_head node;
+	struct attribute_container *cont;
+	struct class_device classdev;
+};
+
+/**
+ * attribute_container_classdev_to_container - given a classdev, return the container
+ *
+ * @classdev: the class device created by attribute_container_add_device.
+ *
+ * Returns the container associated with this classdev.
+ */
+struct attribute_container *
+attribute_container_classdev_to_container(struct class_device *classdev)
+{
+	struct internal_container *ic =
+		container_of(classdev, struct internal_container, classdev);
+	return ic->cont;
+}
+EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
+
+static struct list_head attribute_container_list;
+
+static DECLARE_MUTEX(attribute_container_mutex);
+
+/**
+ * attribute_container_register - register an attribute container
+ *
+ * @cont: The container to register.  This must be allocated by the
+ *        callee and should also be zeroed by it.
+ */
+int
+attribute_container_register(struct attribute_container *cont)
+{
+	INIT_LIST_HEAD(&cont->node);
+	INIT_LIST_HEAD(&cont->containers);
+		
+	down(&attribute_container_mutex);
+	list_add_tail(&cont->node, &attribute_container_list);
+	up(&attribute_container_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(attribute_container_register);
+
+/**
+ * attribute_container_unregister - remove a container registration
+ *
+ * @cont: previously registered container to remove
+ */
+int
+attribute_container_unregister(struct attribute_container *cont)
+{
+	int retval = -EBUSY;
+	down(&attribute_container_mutex);
+	if (!list_empty(&cont->containers))
+		goto out;
+	retval = 0;
+	list_del(&cont->node);
+ out:
+	up(&attribute_container_mutex);
+	return retval;
+		
+}
+EXPORT_SYMBOL_GPL(attribute_container_unregister);
+
+/* private function used as class release */
+static void attribute_container_release(struct class_device *classdev)
+{
+	struct internal_container *ic 
+		= container_of(classdev, struct internal_container, classdev);
+	struct device *dev = classdev->dev;
+
+	kfree(ic);
+	put_device(dev);
+}
+
+/**
+ * attribute_container_add_device - see if any container is interested in dev
+ *
+ * @dev: device to add attributes to
+ * @fn:	 function to trigger addition of class device.
+ *
+ * This function allocates storage for the class device(s) to be
+ * attached to dev (one for each matching attribute_container).  If no
+ * fn is provided, the code will simply register the class device via
+ * class_device_add.  If a function is provided, it is expected to add
+ * the class device at the appropriate time.  One of the things that
+ * might be necessary is to allocate and initialise the classdev and
+ * then add it a later time.  To do this, call this routine for
+ * allocation and initialisation and then use
+ * attribute_container_device_trigger() to call class_device_add() on
+ * it.  Note: after this, the class device contains a reference to dev
+ * which is not relinquished until the release of the classdev.
+ */
+void
+attribute_container_add_device(struct device *dev,
+			       int (*fn)(struct attribute_container *,
+					 struct device *,
+					 struct class_device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		struct internal_container *ic;
+
+		if (attribute_container_no_classdevs(cont))
+			continue;
+
+		if (!cont->match(cont, dev))
+			continue;
+		ic = kmalloc(sizeof(struct internal_container), GFP_KERNEL);
+		if (!ic) {
+			dev_printk(KERN_ERR, dev, "failed to allocate class container\n");
+			continue;
+		}
+		memset(ic, 0, sizeof(struct internal_container));
+		INIT_LIST_HEAD(&ic->node);
+		ic->cont = cont;
+		class_device_initialize(&ic->classdev);
+		ic->classdev.dev = get_device(dev);
+		ic->classdev.class = cont->class;
+		cont->class->release = attribute_container_release;
+		strcpy(ic->classdev.class_id, dev->bus_id);
+		if (fn)
+			fn(cont, dev, &ic->classdev);
+		else
+			attribute_container_add_class_device(&ic->classdev);
+		list_add_tail(&ic->node, &cont->containers);
+	}
+	up(&attribute_container_mutex);
+}
+
+/**
+ * attribute_container_remove_device - make device eligible for removal.
+ *
+ * @dev:  The generic device
+ * @fn:	  A function to call to remove the device
+ *
+ * This routine triggers device removal.  If fn is NULL, then it is
+ * simply done via class_device_unregister (note that if something
+ * still has a reference to the classdev, then the memory occupied
+ * will not be freed until the classdev is released).  If you want a
+ * two phase release: remove from visibility and then delete the
+ * device, then you should use this routine with a fn that calls
+ * class_device_del() and then use
+ * attribute_container_device_trigger() to do the final put on the
+ * classdev.
+ */
+void
+attribute_container_remove_device(struct device *dev,
+				  void (*fn)(struct attribute_container *,
+					     struct device *,
+					     struct class_device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		struct internal_container *ic, *tmp;
+
+		if (attribute_container_no_classdevs(cont))
+			continue;
+
+		if (!cont->match(cont, dev))
+			continue;
+		list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
+			if (dev != ic->classdev.dev)
+				continue;
+			list_del(&ic->node);
+			if (fn)
+				fn(cont, dev, &ic->classdev);
+			else {
+				attribute_container_remove_attrs(&ic->classdev);
+				class_device_unregister(&ic->classdev);
+			}
+		}
+	}
+	up(&attribute_container_mutex);
+}
+EXPORT_SYMBOL_GPL(attribute_container_remove_device);
+
+/**
+ * attribute_container_device_trigger - execute a trigger for each matching classdev
+ *
+ * @dev:  The generic device to run the trigger for
+ * @fn	  the function to execute for each classdev.
+ *
+ * This funcion is for executing a trigger when you need to know both
+ * the container and the classdev.  If you only care about the
+ * container, then use attribute_container_trigger() instead.
+ */
+void
+attribute_container_device_trigger(struct device *dev, 
+				   int (*fn)(struct attribute_container *,
+					     struct device *,
+					     struct class_device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		struct internal_container *ic, *tmp;
+
+		if (!cont->match(cont, dev))
+			continue;
+
+		list_for_each_entry_safe(ic, tmp, &cont->containers, node) {
+			if (dev == ic->classdev.dev)
+				fn(cont, dev, &ic->classdev);
+		}
+	}
+	up(&attribute_container_mutex);
+}
+EXPORT_SYMBOL_GPL(attribute_container_device_trigger);
+
+/**
+ * attribute_container_trigger - trigger a function for each matching container
+ *
+ * @dev:  The generic device to activate the trigger for
+ * @fn:	  the function to trigger
+ *
+ * This routine triggers a function that only needs to know the
+ * matching containers (not the classdev) associated with a device.
+ * It is more lightweight than attribute_container_device_trigger, so
+ * should be used in preference unless the triggering function
+ * actually needs to know the classdev.
+ */
+void
+attribute_container_trigger(struct device *dev,
+			    int (*fn)(struct attribute_container *,
+				      struct device *))
+{
+	struct attribute_container *cont;
+
+	down(&attribute_container_mutex);
+	list_for_each_entry(cont, &attribute_container_list, node) {
+		if (cont->match(cont, dev))
+			fn(cont, dev);
+	}
+	up(&attribute_container_mutex);
+}
+EXPORT_SYMBOL_GPL(attribute_container_trigger);
+
+/**
+ * attribute_container_add_attrs - add attributes
+ *
+ * @classdev: The class device
+ *
+ * This simply creates all the class device sysfs files from the
+ * attributes listed in the container
+ */
+int
+attribute_container_add_attrs(struct class_device *classdev)
+{
+	struct attribute_container *cont =
+		attribute_container_classdev_to_container(classdev);
+	struct class_device_attribute **attrs =	cont->attrs;
+	int i, error;
+
+	if (!attrs)
+		return 0;
+
+	for (i = 0; attrs[i]; i++) {
+		error = class_device_create_file(classdev, attrs[i]);
+		if (error)
+			return error;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(attribute_container_add_attrs);
+
+/**
+ * attribute_container_add_class_device - same function as class_device_add
+ *
+ * @classdev:	the class device to add
+ *
+ * This performs essentially the same function as class_device_add except for
+ * attribute containers, namely add the classdev to the system and then
+ * create the attribute files
+ */
+int
+attribute_container_add_class_device(struct class_device *classdev)
+{
+	int error = class_device_add(classdev);
+	if (error)
+		return error;
+	return attribute_container_add_attrs(classdev);
+}
+EXPORT_SYMBOL_GPL(attribute_container_add_class_device);
+
+/**
+ * attribute_container_add_class_device_adapter - simple adapter for triggers
+ *
+ * This function is identical to attribute_container_add_class_device except
+ * that it is designed to be called from the triggers
+ */
+int
+attribute_container_add_class_device_adapter(struct attribute_container *cont,
+					     struct device *dev,
+					     struct class_device *classdev)
+{
+	return attribute_container_add_class_device(classdev);
+}
+EXPORT_SYMBOL_GPL(attribute_container_add_class_device_adapter);
+
+/**
+ * attribute_container_remove_attrs - remove any attribute files
+ *
+ * @classdev: The class device to remove the files from
+ *
+ */
+void
+attribute_container_remove_attrs(struct class_device *classdev)
+{
+	struct attribute_container *cont =
+		attribute_container_classdev_to_container(classdev);
+	struct class_device_attribute **attrs =	cont->attrs;
+	int i;
+
+	if (!attrs)
+		return;
+
+	for (i = 0; attrs[i]; i++)
+		class_device_remove_file(classdev, attrs[i]);
+}
+EXPORT_SYMBOL_GPL(attribute_container_remove_attrs);
+
+/**
+ * attribute_container_class_device_del - equivalent of class_device_del
+ *
+ * @classdev: the class device
+ *
+ * This function simply removes all the attribute files and then calls
+ * class_device_del.
+ */
+void
+attribute_container_class_device_del(struct class_device *classdev)
+{
+	attribute_container_remove_attrs(classdev);
+	class_device_del(classdev);
+}
+EXPORT_SYMBOL_GPL(attribute_container_class_device_del);
+
+int __init
+attribute_container_init(void)
+{
+	INIT_LIST_HEAD(&attribute_container_list);
+	return 0;
+}
diff --git a/drivers/base/base.h b/drivers/base/base.h
new file mode 100644
index 0000000..8d1e8bd
--- /dev/null
+++ b/drivers/base/base.h
@@ -0,0 +1,18 @@
+extern int bus_add_device(struct device * dev);
+extern void bus_remove_device(struct device * dev);
+
+extern int bus_add_driver(struct device_driver *);
+extern void bus_remove_driver(struct device_driver *);
+
+static inline struct class_device *to_class_dev(struct kobject *obj)
+{
+	return container_of(obj, struct class_device, kobj);
+}
+
+static inline
+struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
+{
+	return container_of(_attr, struct class_device_attribute, attr);
+}
+
+
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
new file mode 100644
index 0000000..f4fa273
--- /dev/null
+++ b/drivers/base/bus.c
@@ -0,0 +1,770 @@
+/*
+ * bus.c - bus driver management
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include "base.h"
+#include "power/power.h"
+
+#define to_dev(node) container_of(node, struct device, bus_list)
+#define to_drv(node) container_of(node, struct device_driver, kobj.entry)
+
+#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
+#define to_bus(obj) container_of(obj, struct bus_type, subsys.kset.kobj)
+
+/*
+ * sysfs bindings for drivers
+ */
+
+#define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr)
+#define to_driver(obj) container_of(obj, struct device_driver, kobj)
+
+
+static ssize_t
+drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+{
+	struct driver_attribute * drv_attr = to_drv_attr(attr);
+	struct device_driver * drv = to_driver(kobj);
+	ssize_t ret = 0;
+
+	if (drv_attr->show)
+		ret = drv_attr->show(drv, buf);
+	return ret;
+}
+
+static ssize_t
+drv_attr_store(struct kobject * kobj, struct attribute * attr,
+	       const char * buf, size_t count)
+{
+	struct driver_attribute * drv_attr = to_drv_attr(attr);
+	struct device_driver * drv = to_driver(kobj);
+	ssize_t ret = 0;
+
+	if (drv_attr->store)
+		ret = drv_attr->store(drv, buf, count);
+	return ret;
+}
+
+static struct sysfs_ops driver_sysfs_ops = {
+	.show	= drv_attr_show,
+	.store	= drv_attr_store,
+};
+
+
+static void driver_release(struct kobject * kobj)
+{
+	struct device_driver * drv = to_driver(kobj);
+	complete(&drv->unloaded);
+}
+
+static struct kobj_type ktype_driver = {
+	.sysfs_ops	= &driver_sysfs_ops,
+	.release	= driver_release,
+};
+
+
+/*
+ * sysfs bindings for buses
+ */
+
+
+static ssize_t
+bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+{
+	struct bus_attribute * bus_attr = to_bus_attr(attr);
+	struct bus_type * bus = to_bus(kobj);
+	ssize_t ret = 0;
+
+	if (bus_attr->show)
+		ret = bus_attr->show(bus, buf);
+	return ret;
+}
+
+static ssize_t
+bus_attr_store(struct kobject * kobj, struct attribute * attr,
+	       const char * buf, size_t count)
+{
+	struct bus_attribute * bus_attr = to_bus_attr(attr);
+	struct bus_type * bus = to_bus(kobj);
+	ssize_t ret = 0;
+
+	if (bus_attr->store)
+		ret = bus_attr->store(bus, buf, count);
+	return ret;
+}
+
+static struct sysfs_ops bus_sysfs_ops = {
+	.show	= bus_attr_show,
+	.store	= bus_attr_store,
+};
+
+int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
+{
+	int error;
+	if (get_bus(bus)) {
+		error = sysfs_create_file(&bus->subsys.kset.kobj, &attr->attr);
+		put_bus(bus);
+	} else
+		error = -EINVAL;
+	return error;
+}
+
+void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
+{
+	if (get_bus(bus)) {
+		sysfs_remove_file(&bus->subsys.kset.kobj, &attr->attr);
+		put_bus(bus);
+	}
+}
+
+static struct kobj_type ktype_bus = {
+	.sysfs_ops	= &bus_sysfs_ops,
+
+};
+
+decl_subsys(bus, &ktype_bus, NULL);
+
+static int __bus_for_each_dev(struct bus_type *bus, struct device *start,
+			      void *data, int (*fn)(struct device *, void *))
+{
+	struct list_head *head;
+	struct device *dev;
+	int error = 0;
+
+	if (!(bus = get_bus(bus)))
+		return -EINVAL;
+
+	head = &bus->devices.list;
+	dev = list_prepare_entry(start, head, bus_list);
+	list_for_each_entry_continue(dev, head, bus_list) {
+		get_device(dev);
+		error = fn(dev, data);
+		put_device(dev);
+		if (error)
+			break;
+	}
+	put_bus(bus);
+	return error;
+}
+
+static int __bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
+			      void * data, int (*fn)(struct device_driver *, void *))
+{
+	struct list_head *head;
+	struct device_driver *drv;
+	int error = 0;
+
+	if (!(bus = get_bus(bus)))
+		return -EINVAL;
+
+	head = &bus->drivers.list;
+	drv = list_prepare_entry(start, head, kobj.entry);
+	list_for_each_entry_continue(drv, head, kobj.entry) {
+		get_driver(drv);
+		error = fn(drv, data);
+		put_driver(drv);
+		if (error)
+			break;
+	}
+	put_bus(bus);
+	return error;
+}
+
+/**
+ *	bus_for_each_dev - device iterator.
+ *	@bus:	bus type.
+ *	@start:	device to start iterating from.
+ *	@data:	data for the callback.
+ *	@fn:	function to be called for each device.
+ *
+ *	Iterate over @bus's list of devices, and call @fn for each,
+ *	passing it @data. If @start is not NULL, we use that device to
+ *	begin iterating from.
+ *
+ *	We check the return of @fn each time. If it returns anything
+ *	other than 0, we break out and return that value.
+ *
+ *	NOTE: The device that returns a non-zero value is not retained
+ *	in any way, nor is its refcount incremented. If the caller needs
+ *	to retain this data, it should do, and increment the reference
+ *	count in the supplied callback.
+ */
+
+int bus_for_each_dev(struct bus_type * bus, struct device * start,
+		     void * data, int (*fn)(struct device *, void *))
+{
+	int ret;
+
+	down_read(&bus->subsys.rwsem);
+	ret = __bus_for_each_dev(bus, start, data, fn);
+	up_read(&bus->subsys.rwsem);
+	return ret;
+}
+
+/**
+ *	bus_for_each_drv - driver iterator
+ *	@bus:	bus we're dealing with.
+ *	@start:	driver to start iterating on.
+ *	@data:	data to pass to the callback.
+ *	@fn:	function to call for each driver.
+ *
+ *	This is nearly identical to the device iterator above.
+ *	We iterate over each driver that belongs to @bus, and call
+ *	@fn for each. If @fn returns anything but 0, we break out
+ *	and return it. If @start is not NULL, we use it as the head
+ *	of the list.
+ *
+ *	NOTE: we don't return the driver that returns a non-zero
+ *	value, nor do we leave the reference count incremented for that
+ *	driver. If the caller needs to know that info, it must set it
+ *	in the callback. It must also be sure to increment the refcount
+ *	so it doesn't disappear before returning to the caller.
+ */
+
+int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
+		     void * data, int (*fn)(struct device_driver *, void *))
+{
+	int ret;
+
+	down_read(&bus->subsys.rwsem);
+	ret = __bus_for_each_drv(bus, start, data, fn);
+	up_read(&bus->subsys.rwsem);
+	return ret;
+}
+
+/**
+ *	device_bind_driver - bind a driver to one device.
+ *	@dev:	device.
+ *
+ *	Allow manual attachment of a driver to a device.
+ *	Caller must have already set @dev->driver.
+ *
+ *	Note that this does not modify the bus reference count
+ *	nor take the bus's rwsem. Please verify those are accounted
+ *	for before calling this. (It is ok to call with no other effort
+ *	from a driver's probe() method.)
+ */
+
+void device_bind_driver(struct device * dev)
+{
+	pr_debug("bound device '%s' to driver '%s'\n",
+		 dev->bus_id, dev->driver->name);
+	list_add_tail(&dev->driver_list, &dev->driver->devices);
+	sysfs_create_link(&dev->driver->kobj, &dev->kobj,
+			  kobject_name(&dev->kobj));
+	sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
+}
+
+
+/**
+ *	driver_probe_device - attempt to bind device & driver.
+ *	@drv:	driver.
+ *	@dev:	device.
+ *
+ *	First, we call the bus's match function, if one present, which
+ *	should compare the device IDs the driver supports with the
+ *	device IDs of the device. Note we don't do this ourselves
+ *	because we don't know the format of the ID structures, nor what
+ *	is to be considered a match and what is not.
+ *
+ *	If we find a match, we call @drv->probe(@dev) if it exists, and
+ *	call device_bind_driver() above.
+ */
+int driver_probe_device(struct device_driver * drv, struct device * dev)
+{
+	if (drv->bus->match && !drv->bus->match(dev, drv))
+		return -ENODEV;
+
+	dev->driver = drv;
+	if (drv->probe) {
+		int error = drv->probe(dev);
+		if (error) {
+			dev->driver = NULL;
+			return error;
+		}
+	}
+
+	device_bind_driver(dev);
+	return 0;
+}
+
+
+/**
+ *	device_attach - try to attach device to a driver.
+ *	@dev:	device.
+ *
+ *	Walk the list of drivers that the bus has and call
+ *	driver_probe_device() for each pair. If a compatible
+ *	pair is found, break out and return.
+ */
+int device_attach(struct device * dev)
+{
+ 	struct bus_type * bus = dev->bus;
+	struct list_head * entry;
+	int error;
+
+	if (dev->driver) {
+		device_bind_driver(dev);
+		return 1;
+	}
+
+	if (bus->match) {
+		list_for_each(entry, &bus->drivers.list) {
+			struct device_driver * drv = to_drv(entry);
+			error = driver_probe_device(drv, dev);
+			if (!error)
+				/* success, driver matched */
+				return 1;
+			if (error != -ENODEV && error != -ENXIO)
+				/* driver matched but the probe failed */
+				printk(KERN_WARNING
+				    "%s: probe of %s failed with error %d\n",
+				    drv->name, dev->bus_id, error);
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ *	driver_attach - try to bind driver to devices.
+ *	@drv:	driver.
+ *
+ *	Walk the list of devices that the bus has on it and try to
+ *	match the driver with each one.  If driver_probe_device()
+ *	returns 0 and the @dev->driver is set, we've found a
+ *	compatible pair.
+ *
+ *	Note that we ignore the -ENODEV error from driver_probe_device(),
+ *	since it's perfectly valid for a driver not to bind to any devices.
+ */
+void driver_attach(struct device_driver * drv)
+{
+	struct bus_type * bus = drv->bus;
+	struct list_head * entry;
+	int error;
+
+	if (!bus->match)
+		return;
+
+	list_for_each(entry, &bus->devices.list) {
+		struct device * dev = container_of(entry, struct device, bus_list);
+		if (!dev->driver) {
+			error = driver_probe_device(drv, dev);
+			if (error && (error != -ENODEV))
+				/* driver matched but the probe failed */
+				printk(KERN_WARNING
+				    "%s: probe of %s failed with error %d\n",
+				    drv->name, dev->bus_id, error);
+		}
+	}
+}
+
+
+/**
+ *	device_release_driver - manually detach device from driver.
+ *	@dev:	device.
+ *
+ *	Manually detach device from driver.
+ *	Note that this is called without incrementing the bus
+ *	reference count nor taking the bus's rwsem. Be sure that
+ *	those are accounted for before calling this function.
+ */
+
+void device_release_driver(struct device * dev)
+{
+	struct device_driver * drv = dev->driver;
+	if (drv) {
+		sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
+		sysfs_remove_link(&dev->kobj, "driver");
+		list_del_init(&dev->driver_list);
+		device_detach_shutdown(dev);
+		if (drv->remove)
+			drv->remove(dev);
+		dev->driver = NULL;
+	}
+}
+
+
+/**
+ *	driver_detach - detach driver from all devices it controls.
+ *	@drv:	driver.
+ */
+
+static void driver_detach(struct device_driver * drv)
+{
+	struct list_head * entry, * next;
+	list_for_each_safe(entry, next, &drv->devices) {
+		struct device * dev = container_of(entry, struct device, driver_list);
+		device_release_driver(dev);
+	}
+}
+
+static int device_add_attrs(struct bus_type * bus, struct device * dev)
+{
+	int error = 0;
+	int i;
+
+	if (bus->dev_attrs) {
+		for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
+			error = device_create_file(dev,&bus->dev_attrs[i]);
+			if (error)
+				goto Err;
+		}
+	}
+ Done:
+	return error;
+ Err:
+	while (--i >= 0)
+		device_remove_file(dev,&bus->dev_attrs[i]);
+	goto Done;
+}
+
+
+static void device_remove_attrs(struct bus_type * bus, struct device * dev)
+{
+	int i;
+
+	if (bus->dev_attrs) {
+		for (i = 0; attr_name(bus->dev_attrs[i]); i++)
+			device_remove_file(dev,&bus->dev_attrs[i]);
+	}
+}
+
+
+/**
+ *	bus_add_device - add device to bus
+ *	@dev:	device being added
+ *
+ *	- Add the device to its bus's list of devices.
+ *	- Try to attach to driver.
+ *	- Create link to device's physical location.
+ */
+int bus_add_device(struct device * dev)
+{
+	struct bus_type * bus = get_bus(dev->bus);
+	int error = 0;
+
+	if (bus) {
+		down_write(&dev->bus->subsys.rwsem);
+		pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
+		list_add_tail(&dev->bus_list, &dev->bus->devices.list);
+		device_attach(dev);
+		up_write(&dev->bus->subsys.rwsem);
+		device_add_attrs(bus, dev);
+		sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
+		sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
+	}
+	return error;
+}
+
+/**
+ *	bus_remove_device - remove device from bus
+ *	@dev:	device to be removed
+ *
+ *	- Remove symlink from bus's directory.
+ *	- Delete device from bus's list.
+ *	- Detach from its driver.
+ *	- Drop reference taken in bus_add_device().
+ */
+void bus_remove_device(struct device * dev)
+{
+	if (dev->bus) {
+		sysfs_remove_link(&dev->kobj, "bus");
+		sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
+		device_remove_attrs(dev->bus, dev);
+		down_write(&dev->bus->subsys.rwsem);
+		pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
+		device_release_driver(dev);
+		list_del_init(&dev->bus_list);
+		up_write(&dev->bus->subsys.rwsem);
+		put_bus(dev->bus);
+	}
+}
+
+static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv)
+{
+	int error = 0;
+	int i;
+
+	if (bus->drv_attrs) {
+		for (i = 0; attr_name(bus->drv_attrs[i]); i++) {
+			error = driver_create_file(drv, &bus->drv_attrs[i]);
+			if (error)
+				goto Err;
+		}
+	}
+ Done:
+	return error;
+ Err:
+	while (--i >= 0)
+		driver_remove_file(drv, &bus->drv_attrs[i]);
+	goto Done;
+}
+
+
+static void driver_remove_attrs(struct bus_type * bus, struct device_driver * drv)
+{
+	int i;
+
+	if (bus->drv_attrs) {
+		for (i = 0; attr_name(bus->drv_attrs[i]); i++)
+			driver_remove_file(drv, &bus->drv_attrs[i]);
+	}
+}
+
+
+/**
+ *	bus_add_driver - Add a driver to the bus.
+ *	@drv:	driver.
+ *
+ */
+int bus_add_driver(struct device_driver * drv)
+{
+	struct bus_type * bus = get_bus(drv->bus);
+	int error = 0;
+
+	if (bus) {
+		pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
+		error = kobject_set_name(&drv->kobj, "%s", drv->name);
+		if (error) {
+			put_bus(bus);
+			return error;
+		}
+		drv->kobj.kset = &bus->drivers;
+		if ((error = kobject_register(&drv->kobj))) {
+			put_bus(bus);
+			return error;
+		}
+
+		down_write(&bus->subsys.rwsem);
+		driver_attach(drv);
+		up_write(&bus->subsys.rwsem);
+		module_add_driver(drv->owner, drv);
+
+		driver_add_attrs(bus, drv);
+	}
+	return error;
+}
+
+
+/**
+ *	bus_remove_driver - delete driver from bus's knowledge.
+ *	@drv:	driver.
+ *
+ *	Detach the driver from the devices it controls, and remove
+ *	it from its bus's list of drivers. Finally, we drop the reference
+ *	to the bus we took in bus_add_driver().
+ */
+
+void bus_remove_driver(struct device_driver * drv)
+{
+	if (drv->bus) {
+		driver_remove_attrs(drv->bus, drv);
+		down_write(&drv->bus->subsys.rwsem);
+		pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
+		driver_detach(drv);
+		up_write(&drv->bus->subsys.rwsem);
+		module_remove_driver(drv);
+		kobject_unregister(&drv->kobj);
+		put_bus(drv->bus);
+	}
+}
+
+
+/* Helper for bus_rescan_devices's iter */
+static int bus_rescan_devices_helper(struct device *dev, void *data)
+{
+	int *count = data;
+
+	if (!dev->driver && device_attach(dev))
+		(*count)++;
+
+	return 0;
+}
+
+
+/**
+ *	bus_rescan_devices - rescan devices on the bus for possible drivers
+ *	@bus:	the bus to scan.
+ *
+ *	This function will look for devices on the bus with no driver
+ *	attached and rescan it against existing drivers to see if it
+ *	matches any. Calls device_attach(). Returns the number of devices
+ *	that were sucessfully bound to a driver.
+ */
+int bus_rescan_devices(struct bus_type * bus)
+{
+	int count = 0;
+
+	down_write(&bus->subsys.rwsem);
+	__bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper);
+	up_write(&bus->subsys.rwsem);
+
+	return count;
+}
+
+
+struct bus_type * get_bus(struct bus_type * bus)
+{
+	return bus ? container_of(subsys_get(&bus->subsys), struct bus_type, subsys) : NULL;
+}
+
+void put_bus(struct bus_type * bus)
+{
+	subsys_put(&bus->subsys);
+}
+
+
+/**
+ *	find_bus - locate bus by name.
+ *	@name:	name of bus.
+ *
+ *	Call kset_find_obj() to iterate over list of buses to
+ *	find a bus by name. Return bus if found.
+ *
+ *	Note that kset_find_obj increments bus' reference count.
+ */
+
+struct bus_type * find_bus(char * name)
+{
+	struct kobject * k = kset_find_obj(&bus_subsys.kset, name);
+	return k ? to_bus(k) : NULL;
+}
+
+
+/**
+ *	bus_add_attrs - Add default attributes for this bus.
+ *	@bus:	Bus that has just been registered.
+ */
+
+static int bus_add_attrs(struct bus_type * bus)
+{
+	int error = 0;
+	int i;
+
+	if (bus->bus_attrs) {
+		for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
+			if ((error = bus_create_file(bus,&bus->bus_attrs[i])))
+				goto Err;
+		}
+	}
+ Done:
+	return error;
+ Err:
+	while (--i >= 0)
+		bus_remove_file(bus,&bus->bus_attrs[i]);
+	goto Done;
+}
+
+static void bus_remove_attrs(struct bus_type * bus)
+{
+	int i;
+
+	if (bus->bus_attrs) {
+		for (i = 0; attr_name(bus->bus_attrs[i]); i++)
+			bus_remove_file(bus,&bus->bus_attrs[i]);
+	}
+}
+
+/**
+ *	bus_register - register a bus with the system.
+ *	@bus:	bus.
+ *
+ *	Once we have that, we registered the bus with the kobject
+ *	infrastructure, then register the children subsystems it has:
+ *	the devices and drivers that belong to the bus.
+ */
+int bus_register(struct bus_type * bus)
+{
+	int retval;
+
+	retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);
+	if (retval)
+		goto out;
+
+	subsys_set_kset(bus, bus_subsys);
+	retval = subsystem_register(&bus->subsys);
+	if (retval)
+		goto out;
+
+	kobject_set_name(&bus->devices.kobj, "devices");
+	bus->devices.subsys = &bus->subsys;
+	retval = kset_register(&bus->devices);
+	if (retval)
+		goto bus_devices_fail;
+
+	kobject_set_name(&bus->drivers.kobj, "drivers");
+	bus->drivers.subsys = &bus->subsys;
+	bus->drivers.ktype = &ktype_driver;
+	retval = kset_register(&bus->drivers);
+	if (retval)
+		goto bus_drivers_fail;
+	bus_add_attrs(bus);
+
+	pr_debug("bus type '%s' registered\n", bus->name);
+	return 0;
+
+bus_drivers_fail:
+	kset_unregister(&bus->devices);
+bus_devices_fail:
+	subsystem_unregister(&bus->subsys);
+out:
+	return retval;
+}
+
+
+/**
+ *	bus_unregister - remove a bus from the system
+ *	@bus:	bus.
+ *
+ *	Unregister the child subsystems and the bus itself.
+ *	Finally, we call put_bus() to release the refcount
+ */
+void bus_unregister(struct bus_type * bus)
+{
+	pr_debug("bus %s: unregistering\n", bus->name);
+	bus_remove_attrs(bus);
+	kset_unregister(&bus->drivers);
+	kset_unregister(&bus->devices);
+	subsystem_unregister(&bus->subsys);
+}
+
+int __init buses_init(void)
+{
+	return subsystem_register(&bus_subsys);
+}
+
+
+EXPORT_SYMBOL_GPL(bus_for_each_dev);
+EXPORT_SYMBOL_GPL(bus_for_each_drv);
+
+EXPORT_SYMBOL_GPL(driver_probe_device);
+EXPORT_SYMBOL_GPL(device_bind_driver);
+EXPORT_SYMBOL_GPL(device_release_driver);
+EXPORT_SYMBOL_GPL(device_attach);
+EXPORT_SYMBOL_GPL(driver_attach);
+
+EXPORT_SYMBOL_GPL(bus_add_device);
+EXPORT_SYMBOL_GPL(bus_remove_device);
+EXPORT_SYMBOL_GPL(bus_register);
+EXPORT_SYMBOL_GPL(bus_unregister);
+EXPORT_SYMBOL_GPL(bus_rescan_devices);
+EXPORT_SYMBOL_GPL(get_bus);
+EXPORT_SYMBOL_GPL(put_bus);
+EXPORT_SYMBOL_GPL(find_bus);
+
+EXPORT_SYMBOL_GPL(bus_create_file);
+EXPORT_SYMBOL_GPL(bus_remove_file);
diff --git a/drivers/base/class.c b/drivers/base/class.c
new file mode 100644
index 0000000..6bf650f
--- /dev/null
+++ b/drivers/base/class.c
@@ -0,0 +1,591 @@
+/*
+ * class.c - basic device class management
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2003-2004 Greg Kroah-Hartman
+ * Copyright (c) 2003-2004 IBM Corp.
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kdev_t.h>
+#include "base.h"
+
+#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
+#define to_class(obj) container_of(obj, struct class, subsys.kset.kobj)
+
+static ssize_t
+class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+{
+	struct class_attribute * class_attr = to_class_attr(attr);
+	struct class * dc = to_class(kobj);
+	ssize_t ret = 0;
+
+	if (class_attr->show)
+		ret = class_attr->show(dc, buf);
+	return ret;
+}
+
+static ssize_t
+class_attr_store(struct kobject * kobj, struct attribute * attr,
+		 const char * buf, size_t count)
+{
+	struct class_attribute * class_attr = to_class_attr(attr);
+	struct class * dc = to_class(kobj);
+	ssize_t ret = 0;
+
+	if (class_attr->store)
+		ret = class_attr->store(dc, buf, count);
+	return ret;
+}
+
+static void class_release(struct kobject * kobj)
+{
+	struct class *class = to_class(kobj);
+
+	pr_debug("class '%s': release.\n", class->name);
+
+	if (class->class_release)
+		class->class_release(class);
+	else
+		pr_debug("class '%s' does not have a release() function, "
+			 "be careful\n", class->name);
+}
+
+static struct sysfs_ops class_sysfs_ops = {
+	.show	= class_attr_show,
+	.store	= class_attr_store,
+};
+
+static struct kobj_type ktype_class = {
+	.sysfs_ops	= &class_sysfs_ops,
+	.release	= class_release,
+};
+
+/* Hotplug events for classes go to the class_obj subsys */
+static decl_subsys(class, &ktype_class, NULL);
+
+
+int class_create_file(struct class * cls, const struct class_attribute * attr)
+{
+	int error;
+	if (cls) {
+		error = sysfs_create_file(&cls->subsys.kset.kobj, &attr->attr);
+	} else
+		error = -EINVAL;
+	return error;
+}
+
+void class_remove_file(struct class * cls, const struct class_attribute * attr)
+{
+	if (cls)
+		sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr);
+}
+
+struct class * class_get(struct class * cls)
+{
+	if (cls)
+		return container_of(subsys_get(&cls->subsys), struct class, subsys);
+	return NULL;
+}
+
+void class_put(struct class * cls)
+{
+	subsys_put(&cls->subsys);
+}
+
+
+static int add_class_attrs(struct class * cls)
+{
+	int i;
+	int error = 0;
+
+	if (cls->class_attrs) {
+		for (i = 0; attr_name(cls->class_attrs[i]); i++) {
+			error = class_create_file(cls,&cls->class_attrs[i]);
+			if (error)
+				goto Err;
+		}
+	}
+ Done:
+	return error;
+ Err:
+	while (--i >= 0)
+		class_remove_file(cls,&cls->class_attrs[i]);
+	goto Done;
+}
+
+static void remove_class_attrs(struct class * cls)
+{
+	int i;
+
+	if (cls->class_attrs) {
+		for (i = 0; attr_name(cls->class_attrs[i]); i++)
+			class_remove_file(cls,&cls->class_attrs[i]);
+	}
+}
+
+int class_register(struct class * cls)
+{
+	int error;
+
+	pr_debug("device class '%s': registering\n", cls->name);
+
+	INIT_LIST_HEAD(&cls->children);
+	INIT_LIST_HEAD(&cls->interfaces);
+	init_MUTEX(&cls->sem);
+	error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
+	if (error)
+		return error;
+
+	subsys_set_kset(cls, class_subsys);
+
+	error = subsystem_register(&cls->subsys);
+	if (!error) {
+		error = add_class_attrs(class_get(cls));
+		class_put(cls);
+	}
+	return error;
+}
+
+void class_unregister(struct class * cls)
+{
+	pr_debug("device class '%s': unregistering\n", cls->name);
+	remove_class_attrs(cls);
+	subsystem_unregister(&cls->subsys);
+}
+
+
+/* Class Device Stuff */
+
+int class_device_create_file(struct class_device * class_dev,
+			     const struct class_device_attribute * attr)
+{
+	int error = -EINVAL;
+	if (class_dev)
+		error = sysfs_create_file(&class_dev->kobj, &attr->attr);
+	return error;
+}
+
+void class_device_remove_file(struct class_device * class_dev,
+			      const struct class_device_attribute * attr)
+{
+	if (class_dev)
+		sysfs_remove_file(&class_dev->kobj, &attr->attr);
+}
+
+int class_device_create_bin_file(struct class_device *class_dev,
+				 struct bin_attribute *attr)
+{
+	int error = -EINVAL;
+	if (class_dev)
+		error = sysfs_create_bin_file(&class_dev->kobj, attr);
+	return error;
+}
+
+void class_device_remove_bin_file(struct class_device *class_dev,
+				  struct bin_attribute *attr)
+{
+	if (class_dev)
+		sysfs_remove_bin_file(&class_dev->kobj, attr);
+}
+
+static ssize_t
+class_device_attr_show(struct kobject * kobj, struct attribute * attr,
+		       char * buf)
+{
+	struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
+	struct class_device * cd = to_class_dev(kobj);
+	ssize_t ret = 0;
+
+	if (class_dev_attr->show)
+		ret = class_dev_attr->show(cd, buf);
+	return ret;
+}
+
+static ssize_t
+class_device_attr_store(struct kobject * kobj, struct attribute * attr,
+			const char * buf, size_t count)
+{
+	struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
+	struct class_device * cd = to_class_dev(kobj);
+	ssize_t ret = 0;
+
+	if (class_dev_attr->store)
+		ret = class_dev_attr->store(cd, buf, count);
+	return ret;
+}
+
+static struct sysfs_ops class_dev_sysfs_ops = {
+	.show	= class_device_attr_show,
+	.store	= class_device_attr_store,
+};
+
+static void class_dev_release(struct kobject * kobj)
+{
+	struct class_device *cd = to_class_dev(kobj);
+	struct class * cls = cd->class;
+
+	pr_debug("device class '%s': release.\n", cd->class_id);
+
+	if (cls->release)
+		cls->release(cd);
+	else {
+		printk(KERN_ERR "Device class '%s' does not have a release() function, "
+			"it is broken and must be fixed.\n",
+			cd->class_id);
+		WARN_ON(1);
+	}
+}
+
+static struct kobj_type ktype_class_device = {
+	.sysfs_ops	= &class_dev_sysfs_ops,
+	.release	= class_dev_release,
+};
+
+static int class_hotplug_filter(struct kset *kset, struct kobject *kobj)
+{
+	struct kobj_type *ktype = get_ktype(kobj);
+
+	if (ktype == &ktype_class_device) {
+		struct class_device *class_dev = to_class_dev(kobj);
+		if (class_dev->class)
+			return 1;
+	}
+	return 0;
+}
+
+static char *class_hotplug_name(struct kset *kset, struct kobject *kobj)
+{
+	struct class_device *class_dev = to_class_dev(kobj);
+
+	return class_dev->class->name;
+}
+
+static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
+			 int num_envp, char *buffer, int buffer_size)
+{
+	struct class_device *class_dev = to_class_dev(kobj);
+	int i = 0;
+	int length = 0;
+	int retval = 0;
+
+	pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
+
+	if (class_dev->dev) {
+		/* add physical device, backing this device  */
+		struct device *dev = class_dev->dev;
+		char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
+
+		add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
+				    &length, "PHYSDEVPATH=%s", path);
+		kfree(path);
+
+		if (dev->bus)
+			add_hotplug_env_var(envp, num_envp, &i,
+					    buffer, buffer_size, &length,
+					    "PHYSDEVBUS=%s", dev->bus->name);
+
+		if (dev->driver)
+			add_hotplug_env_var(envp, num_envp, &i,
+					    buffer, buffer_size, &length,
+					    "PHYSDEVDRIVER=%s", dev->driver->name);
+	}
+
+	if (MAJOR(class_dev->devt)) {
+		add_hotplug_env_var(envp, num_envp, &i,
+				    buffer, buffer_size, &length,
+				    "MAJOR=%u", MAJOR(class_dev->devt));
+
+		add_hotplug_env_var(envp, num_envp, &i,
+				    buffer, buffer_size, &length,
+				    "MINOR=%u", MINOR(class_dev->devt));
+	}
+
+	/* terminate, set to next free slot, shrink available space */
+	envp[i] = NULL;
+	envp = &envp[i];
+	num_envp -= i;
+	buffer = &buffer[length];
+	buffer_size -= length;
+
+	if (class_dev->class->hotplug) {
+		/* have the bus specific function add its stuff */
+		retval = class_dev->class->hotplug (class_dev, envp, num_envp,
+						    buffer, buffer_size);
+			if (retval) {
+			pr_debug ("%s - hotplug() returned %d\n",
+				  __FUNCTION__, retval);
+		}
+	}
+
+	return retval;
+}
+
+static struct kset_hotplug_ops class_hotplug_ops = {
+	.filter =	class_hotplug_filter,
+	.name =		class_hotplug_name,
+	.hotplug =	class_hotplug,
+};
+
+static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops);
+
+
+static int class_device_add_attrs(struct class_device * cd)
+{
+	int i;
+	int error = 0;
+	struct class * cls = cd->class;
+
+	if (cls->class_dev_attrs) {
+		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
+			error = class_device_create_file(cd,
+							 &cls->class_dev_attrs[i]);
+			if (error)
+				goto Err;
+		}
+	}
+ Done:
+	return error;
+ Err:
+	while (--i >= 0)
+		class_device_remove_file(cd,&cls->class_dev_attrs[i]);
+	goto Done;
+}
+
+static void class_device_remove_attrs(struct class_device * cd)
+{
+	int i;
+	struct class * cls = cd->class;
+
+	if (cls->class_dev_attrs) {
+		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
+			class_device_remove_file(cd,&cls->class_dev_attrs[i]);
+	}
+}
+
+static ssize_t show_dev(struct class_device *class_dev, char *buf)
+{
+	return print_dev_t(buf, class_dev->devt);
+}
+static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
+
+void class_device_initialize(struct class_device *class_dev)
+{
+	kobj_set_kset_s(class_dev, class_obj_subsys);
+	kobject_init(&class_dev->kobj);
+	INIT_LIST_HEAD(&class_dev->node);
+}
+
+int class_device_add(struct class_device *class_dev)
+{
+	struct class * parent = NULL;
+	struct class_interface * class_intf;
+	int error;
+
+	class_dev = class_device_get(class_dev);
+	if (!class_dev)
+		return -EINVAL;
+
+	if (!strlen(class_dev->class_id)) {
+		error = -EINVAL;
+		goto register_done;
+	}
+
+	parent = class_get(class_dev->class);
+
+	pr_debug("CLASS: registering class device: ID = '%s'\n",
+		 class_dev->class_id);
+
+	/* first, register with generic layer. */
+	kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
+	if (parent)
+		class_dev->kobj.parent = &parent->subsys.kset.kobj;
+
+	if ((error = kobject_add(&class_dev->kobj)))
+		goto register_done;
+
+	/* now take care of our own registration */
+	if (parent) {
+		down(&parent->sem);
+		list_add_tail(&class_dev->node, &parent->children);
+		list_for_each_entry(class_intf, &parent->interfaces, node)
+			if (class_intf->add)
+				class_intf->add(class_dev);
+		up(&parent->sem);
+	}
+
+	if (MAJOR(class_dev->devt))
+		class_device_create_file(class_dev, &class_device_attr_dev);
+
+	class_device_add_attrs(class_dev);
+	if (class_dev->dev)
+		sysfs_create_link(&class_dev->kobj,
+				  &class_dev->dev->kobj, "device");
+
+ register_done:
+	if (error && parent)
+		class_put(parent);
+	class_device_put(class_dev);
+	return error;
+}
+
+int class_device_register(struct class_device *class_dev)
+{
+	class_device_initialize(class_dev);
+	return class_device_add(class_dev);
+}
+
+void class_device_del(struct class_device *class_dev)
+{
+	struct class * parent = class_dev->class;
+	struct class_interface * class_intf;
+
+	if (parent) {
+		down(&parent->sem);
+		list_del_init(&class_dev->node);
+		list_for_each_entry(class_intf, &parent->interfaces, node)
+			if (class_intf->remove)
+				class_intf->remove(class_dev);
+		up(&parent->sem);
+	}
+
+	if (class_dev->dev)
+		sysfs_remove_link(&class_dev->kobj, "device");
+	class_device_remove_attrs(class_dev);
+
+	kobject_del(&class_dev->kobj);
+
+	if (parent)
+		class_put(parent);
+}
+
+void class_device_unregister(struct class_device *class_dev)
+{
+	pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
+		 class_dev->class_id);
+	class_device_del(class_dev);
+	class_device_put(class_dev);
+}
+
+int class_device_rename(struct class_device *class_dev, char *new_name)
+{
+	int error = 0;
+
+	class_dev = class_device_get(class_dev);
+	if (!class_dev)
+		return -EINVAL;
+
+	pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id,
+		 new_name);
+
+	strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
+
+	error = kobject_rename(&class_dev->kobj, new_name);
+
+	class_device_put(class_dev);
+
+	return error;
+}
+
+struct class_device * class_device_get(struct class_device *class_dev)
+{
+	if (class_dev)
+		return to_class_dev(kobject_get(&class_dev->kobj));
+	return NULL;
+}
+
+void class_device_put(struct class_device *class_dev)
+{
+	kobject_put(&class_dev->kobj);
+}
+
+
+int class_interface_register(struct class_interface *class_intf)
+{
+	struct class *parent;
+	struct class_device *class_dev;
+
+	if (!class_intf || !class_intf->class)
+		return -ENODEV;
+
+	parent = class_get(class_intf->class);
+	if (!parent)
+		return -EINVAL;
+
+	down(&parent->sem);
+	list_add_tail(&class_intf->node, &parent->interfaces);
+	if (class_intf->add) {
+		list_for_each_entry(class_dev, &parent->children, node)
+			class_intf->add(class_dev);
+	}
+	up(&parent->sem);
+
+	return 0;
+}
+
+void class_interface_unregister(struct class_interface *class_intf)
+{
+	struct class * parent = class_intf->class;
+	struct class_device *class_dev;
+
+	if (!parent)
+		return;
+
+	down(&parent->sem);
+	list_del_init(&class_intf->node);
+	if (class_intf->remove) {
+		list_for_each_entry(class_dev, &parent->children, node)
+			class_intf->remove(class_dev);
+	}
+	up(&parent->sem);
+
+	class_put(parent);
+}
+
+
+
+int __init classes_init(void)
+{
+	int retval;
+
+	retval = subsystem_register(&class_subsys);
+	if (retval)
+		return retval;
+
+	/* ick, this is ugly, the things we go through to keep from showing up
+	 * in sysfs... */
+	subsystem_init(&class_obj_subsys);
+	if (!class_obj_subsys.kset.subsys)
+			class_obj_subsys.kset.subsys = &class_obj_subsys;
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(class_create_file);
+EXPORT_SYMBOL_GPL(class_remove_file);
+EXPORT_SYMBOL_GPL(class_register);
+EXPORT_SYMBOL_GPL(class_unregister);
+EXPORT_SYMBOL_GPL(class_get);
+EXPORT_SYMBOL_GPL(class_put);
+
+EXPORT_SYMBOL_GPL(class_device_register);
+EXPORT_SYMBOL_GPL(class_device_unregister);
+EXPORT_SYMBOL_GPL(class_device_initialize);
+EXPORT_SYMBOL_GPL(class_device_add);
+EXPORT_SYMBOL_GPL(class_device_del);
+EXPORT_SYMBOL_GPL(class_device_get);
+EXPORT_SYMBOL_GPL(class_device_put);
+EXPORT_SYMBOL_GPL(class_device_create_file);
+EXPORT_SYMBOL_GPL(class_device_remove_file);
+EXPORT_SYMBOL_GPL(class_device_create_bin_file);
+EXPORT_SYMBOL_GPL(class_device_remove_bin_file);
+
+EXPORT_SYMBOL_GPL(class_interface_register);
+EXPORT_SYMBOL_GPL(class_interface_unregister);
diff --git a/drivers/base/class_simple.c b/drivers/base/class_simple.c
new file mode 100644
index 0000000..27699eb
--- /dev/null
+++ b/drivers/base/class_simple.c
@@ -0,0 +1,199 @@
+/*
+ * class_simple.c - a "simple" interface for classes for simple char devices.
+ *
+ * Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2003-2004 IBM Corp.
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/device.h>
+#include <linux/err.h>
+
+struct class_simple {
+	struct class class;
+};
+#define to_class_simple(d) container_of(d, struct class_simple, class)
+
+struct simple_dev {
+	struct list_head node;
+	struct class_device class_dev;
+};
+#define to_simple_dev(d) container_of(d, struct simple_dev, class_dev)
+
+static LIST_HEAD(simple_dev_list);
+static DEFINE_SPINLOCK(simple_dev_list_lock);
+
+static void release_simple_dev(struct class_device *class_dev)
+{
+	struct simple_dev *s_dev = to_simple_dev(class_dev);
+	kfree(s_dev);
+}
+
+static void class_simple_release(struct class *class)
+{
+	struct class_simple *cs = to_class_simple(class);
+	kfree(cs);
+}
+
+/**
+ * class_simple_create - create a struct class_simple structure
+ * @owner: pointer to the module that is to "own" this struct class_simple
+ * @name: pointer to a string for the name of this class.
+ *
+ * This is used to create a struct class_simple pointer that can then be used
+ * in calls to class_simple_device_add().  This is used when you do not wish to
+ * create a full blown class support for a type of char devices.
+ *
+ * Note, the pointer created here is to be destroyed when finished by making a
+ * call to class_simple_destroy().
+ */
+struct class_simple *class_simple_create(struct module *owner, char *name)
+{
+	struct class_simple *cs;
+	int retval;
+
+	cs = kmalloc(sizeof(*cs), GFP_KERNEL);
+	if (!cs) {
+		retval = -ENOMEM;
+		goto error;
+	}
+	memset(cs, 0x00, sizeof(*cs));
+
+	cs->class.name = name;
+	cs->class.class_release = class_simple_release;
+	cs->class.release = release_simple_dev;
+
+	retval = class_register(&cs->class);
+	if (retval)
+		goto error;
+
+	return cs;
+
+error:
+	kfree(cs);
+	return ERR_PTR(retval);
+}
+EXPORT_SYMBOL(class_simple_create);
+
+/**
+ * class_simple_destroy - destroys a struct class_simple structure
+ * @cs: pointer to the struct class_simple that is to be destroyed
+ *
+ * Note, the pointer to be destroyed must have been created with a call to
+ * class_simple_create().
+ */
+void class_simple_destroy(struct class_simple *cs)
+{
+	if ((cs == NULL) || (IS_ERR(cs)))
+		return;
+
+	class_unregister(&cs->class);
+}
+EXPORT_SYMBOL(class_simple_destroy);
+
+/**
+ * class_simple_device_add - adds a class device to sysfs for a character driver
+ * @cs: pointer to the struct class_simple that this device should be registered to.
+ * @dev: the dev_t for the device to be added.
+ * @device: a pointer to a struct device that is assiociated with this class device.
+ * @fmt: string for the class device's name
+ *
+ * This function can be used by simple char device classes that do not
+ * implement their own class device registration.  A struct class_device will
+ * be created in sysfs, registered to the specified class.  A "dev" file will
+ * be created, showing the dev_t for the device.  The pointer to the struct
+ * class_device will be returned from the call.  Any further sysfs files that
+ * might be required can be created using this pointer.
+ * Note: the struct class_simple passed to this function must have previously been
+ * created with a call to class_simple_create().
+ */
+struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, struct device *device, const char *fmt, ...)
+{
+	va_list args;
+	struct simple_dev *s_dev = NULL;
+	int retval;
+
+	if ((cs == NULL) || (IS_ERR(cs))) {
+		retval = -ENODEV;
+		goto error;
+	}
+
+	s_dev = kmalloc(sizeof(*s_dev), GFP_KERNEL);
+	if (!s_dev) {
+		retval = -ENOMEM;
+		goto error;
+	}
+	memset(s_dev, 0x00, sizeof(*s_dev));
+
+	s_dev->class_dev.devt = dev;
+	s_dev->class_dev.dev = device;
+	s_dev->class_dev.class = &cs->class;
+
+	va_start(args, fmt);
+	vsnprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, fmt, args);
+	va_end(args);
+	retval = class_device_register(&s_dev->class_dev);
+	if (retval)
+		goto error;
+
+	spin_lock(&simple_dev_list_lock);
+	list_add(&s_dev->node, &simple_dev_list);
+	spin_unlock(&simple_dev_list_lock);
+
+	return &s_dev->class_dev;
+
+error:
+	kfree(s_dev);
+	return ERR_PTR(retval);
+}
+EXPORT_SYMBOL(class_simple_device_add);
+
+/**
+ * class_simple_set_hotplug - set the hotplug callback in the embedded struct class
+ * @cs: pointer to the struct class_simple to hold the pointer
+ * @hotplug: function pointer to the hotplug function
+ *
+ * Implement and set a hotplug function to add environment variables specific to this
+ * class on the hotplug event.
+ */
+int class_simple_set_hotplug(struct class_simple *cs,
+	int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size))
+{
+	if ((cs == NULL) || (IS_ERR(cs)))
+		return -ENODEV;
+	cs->class.hotplug = hotplug;
+	return 0;
+}
+EXPORT_SYMBOL(class_simple_set_hotplug);
+
+/**
+ * class_simple_device_remove - removes a class device that was created with class_simple_device_add()
+ * @dev: the dev_t of the device that was previously registered.
+ *
+ * This call unregisters and cleans up a class device that was created with a
+ * call to class_device_simple_add()
+ */
+void class_simple_device_remove(dev_t dev)
+{
+	struct simple_dev *s_dev = NULL;
+	int found = 0;
+
+	spin_lock(&simple_dev_list_lock);
+	list_for_each_entry(s_dev, &simple_dev_list, node) {
+		if (s_dev->class_dev.devt == dev) {
+			found = 1;
+			break;
+		}
+	}
+	if (found) {
+		list_del(&s_dev->node);
+		spin_unlock(&simple_dev_list_lock);
+		class_device_unregister(&s_dev->class_dev);
+	} else {
+		spin_unlock(&simple_dev_list_lock);
+	}
+}
+EXPORT_SYMBOL(class_simple_device_remove);
diff --git a/drivers/base/core.c b/drivers/base/core.c
new file mode 100644
index 0000000..4e6cce8
--- /dev/null
+++ b/drivers/base/core.c
@@ -0,0 +1,439 @@
+/*
+ * drivers/base/core.c - core driver model code (device registration, etc)
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <asm/semaphore.h>
+
+#include "base.h"
+#include "power/power.h"
+
+int (*platform_notify)(struct device * dev) = NULL;
+int (*platform_notify_remove)(struct device * dev) = NULL;
+
+/*
+ * sysfs bindings for devices.
+ */
+
+#define to_dev(obj) container_of(obj, struct device, kobj)
+#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
+
+extern struct attribute * dev_default_attrs[];
+
+static ssize_t
+dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+{
+	struct device_attribute * dev_attr = to_dev_attr(attr);
+	struct device * dev = to_dev(kobj);
+	ssize_t ret = 0;
+
+	if (dev_attr->show)
+		ret = dev_attr->show(dev, buf);
+	return ret;
+}
+
+static ssize_t
+dev_attr_store(struct kobject * kobj, struct attribute * attr,
+	       const char * buf, size_t count)
+{
+	struct device_attribute * dev_attr = to_dev_attr(attr);
+	struct device * dev = to_dev(kobj);
+	ssize_t ret = 0;
+
+	if (dev_attr->store)
+		ret = dev_attr->store(dev, buf, count);
+	return ret;
+}
+
+static struct sysfs_ops dev_sysfs_ops = {
+	.show	= dev_attr_show,
+	.store	= dev_attr_store,
+};
+
+
+/**
+ *	device_release - free device structure.
+ *	@kobj:	device's kobject.
+ *
+ *	This is called once the reference count for the object
+ *	reaches 0. We forward the call to the device's release
+ *	method, which should handle actually freeing the structure.
+ */
+static void device_release(struct kobject * kobj)
+{
+	struct device * dev = to_dev(kobj);
+
+	if (dev->release)
+		dev->release(dev);
+	else {
+		printk(KERN_ERR "Device '%s' does not have a release() function, "
+			"it is broken and must be fixed.\n",
+			dev->bus_id);
+		WARN_ON(1);
+	}
+}
+
+static struct kobj_type ktype_device = {
+	.release	= device_release,
+	.sysfs_ops	= &dev_sysfs_ops,
+	.default_attrs	= dev_default_attrs,
+};
+
+
+static int dev_hotplug_filter(struct kset *kset, struct kobject *kobj)
+{
+	struct kobj_type *ktype = get_ktype(kobj);
+
+	if (ktype == &ktype_device) {
+		struct device *dev = to_dev(kobj);
+		if (dev->bus)
+			return 1;
+	}
+	return 0;
+}
+
+static char *dev_hotplug_name(struct kset *kset, struct kobject *kobj)
+{
+	struct device *dev = to_dev(kobj);
+
+	return dev->bus->name;
+}
+
+static int dev_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
+			int num_envp, char *buffer, int buffer_size)
+{
+	struct device *dev = to_dev(kobj);
+	int i = 0;
+	int length = 0;
+	int retval = 0;
+
+	/* add bus name of physical device */
+	if (dev->bus)
+		add_hotplug_env_var(envp, num_envp, &i,
+				    buffer, buffer_size, &length,
+				    "PHYSDEVBUS=%s", dev->bus->name);
+
+	/* add driver name of physical device */
+	if (dev->driver)
+		add_hotplug_env_var(envp, num_envp, &i,
+				    buffer, buffer_size, &length,
+				    "PHYSDEVDRIVER=%s", dev->driver->name);
+
+	/* terminate, set to next free slot, shrink available space */
+	envp[i] = NULL;
+	envp = &envp[i];
+	num_envp -= i;
+	buffer = &buffer[length];
+	buffer_size -= length;
+
+	if (dev->bus->hotplug) {
+		/* have the bus specific function add its stuff */
+		retval = dev->bus->hotplug (dev, envp, num_envp, buffer, buffer_size);
+			if (retval) {
+			pr_debug ("%s - hotplug() returned %d\n",
+				  __FUNCTION__, retval);
+		}
+	}
+
+	return retval;
+}
+
+static struct kset_hotplug_ops device_hotplug_ops = {
+	.filter =	dev_hotplug_filter,
+	.name =		dev_hotplug_name,
+	.hotplug =	dev_hotplug,
+};
+
+/**
+ *	device_subsys - structure to be registered with kobject core.
+ */
+
+decl_subsys(devices, &ktype_device, &device_hotplug_ops);
+
+
+/**
+ *	device_create_file - create sysfs attribute file for device.
+ *	@dev:	device.
+ *	@attr:	device attribute descriptor.
+ */
+
+int device_create_file(struct device * dev, struct device_attribute * attr)
+{
+	int error = 0;
+	if (get_device(dev)) {
+		error = sysfs_create_file(&dev->kobj, &attr->attr);
+		put_device(dev);
+	}
+	return error;
+}
+
+/**
+ *	device_remove_file - remove sysfs attribute file.
+ *	@dev:	device.
+ *	@attr:	device attribute descriptor.
+ */
+
+void device_remove_file(struct device * dev, struct device_attribute * attr)
+{
+	if (get_device(dev)) {
+		sysfs_remove_file(&dev->kobj, &attr->attr);
+		put_device(dev);
+	}
+}
+
+
+/**
+ *	device_initialize - init device structure.
+ *	@dev:	device.
+ *
+ *	This prepares the device for use by other layers,
+ *	including adding it to the device hierarchy.
+ *	It is the first half of device_register(), if called by
+ *	that, though it can also be called separately, so one
+ *	may use @dev's fields (e.g. the refcount).
+ */
+
+void device_initialize(struct device *dev)
+{
+	kobj_set_kset_s(dev, devices_subsys);
+	kobject_init(&dev->kobj);
+	INIT_LIST_HEAD(&dev->node);
+	INIT_LIST_HEAD(&dev->children);
+	INIT_LIST_HEAD(&dev->driver_list);
+	INIT_LIST_HEAD(&dev->bus_list);
+	INIT_LIST_HEAD(&dev->dma_pools);
+}
+
+/**
+ *	device_add - add device to device hierarchy.
+ *	@dev:	device.
+ *
+ *	This is part 2 of device_register(), though may be called
+ *	separately _iff_ device_initialize() has been called separately.
+ *
+ *	This adds it to the kobject hierarchy via kobject_add(), adds it
+ *	to the global and sibling lists for the device, then
+ *	adds it to the other relevant subsystems of the driver model.
+ */
+int device_add(struct device *dev)
+{
+	struct device *parent = NULL;
+	int error = -EINVAL;
+
+	dev = get_device(dev);
+	if (!dev || !strlen(dev->bus_id))
+		goto Error;
+
+	parent = get_device(dev->parent);
+
+	pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
+
+	/* first, register with generic layer. */
+	kobject_set_name(&dev->kobj, "%s", dev->bus_id);
+	if (parent)
+		dev->kobj.parent = &parent->kobj;
+
+	if ((error = kobject_add(&dev->kobj)))
+		goto Error;
+	if ((error = device_pm_add(dev)))
+		goto PMError;
+	if ((error = bus_add_device(dev)))
+		goto BusError;
+	down_write(&devices_subsys.rwsem);
+	if (parent)
+		list_add_tail(&dev->node, &parent->children);
+	up_write(&devices_subsys.rwsem);
+
+	/* notify platform of device entry */
+	if (platform_notify)
+		platform_notify(dev);
+ Done:
+	put_device(dev);
+	return error;
+ BusError:
+	device_pm_remove(dev);
+ PMError:
+	kobject_del(&dev->kobj);
+ Error:
+	if (parent)
+		put_device(parent);
+	goto Done;
+}
+
+
+/**
+ *	device_register - register a device with the system.
+ *	@dev:	pointer to the device structure
+ *
+ *	This happens in two clean steps - initialize the device
+ *	and add it to the system. The two steps can be called
+ *	separately, but this is the easiest and most common.
+ *	I.e. you should only call the two helpers separately if
+ *	have a clearly defined need to use and refcount the device
+ *	before it is added to the hierarchy.
+ */
+
+int device_register(struct device *dev)
+{
+	device_initialize(dev);
+	return device_add(dev);
+}
+
+
+/**
+ *	get_device - increment reference count for device.
+ *	@dev:	device.
+ *
+ *	This simply forwards the call to kobject_get(), though
+ *	we do take care to provide for the case that we get a NULL
+ *	pointer passed in.
+ */
+
+struct device * get_device(struct device * dev)
+{
+	return dev ? to_dev(kobject_get(&dev->kobj)) : NULL;
+}
+
+
+/**
+ *	put_device - decrement reference count.
+ *	@dev:	device in question.
+ */
+void put_device(struct device * dev)
+{
+	if (dev)
+		kobject_put(&dev->kobj);
+}
+
+
+/**
+ *	device_del - delete device from system.
+ *	@dev:	device.
+ *
+ *	This is the first part of the device unregistration
+ *	sequence. This removes the device from the lists we control
+ *	from here, has it removed from the other driver model
+ *	subsystems it was added to in device_add(), and removes it
+ *	from the kobject hierarchy.
+ *
+ *	NOTE: this should be called manually _iff_ device_add() was
+ *	also called manually.
+ */
+
+void device_del(struct device * dev)
+{
+	struct device * parent = dev->parent;
+
+	down_write(&devices_subsys.rwsem);
+	if (parent)
+		list_del_init(&dev->node);
+	up_write(&devices_subsys.rwsem);
+
+	/* Notify the platform of the removal, in case they
+	 * need to do anything...
+	 */
+	if (platform_notify_remove)
+		platform_notify_remove(dev);
+	bus_remove_device(dev);
+	device_pm_remove(dev);
+	kobject_del(&dev->kobj);
+	if (parent)
+		put_device(parent);
+}
+
+/**
+ *	device_unregister - unregister device from system.
+ *	@dev:	device going away.
+ *
+ *	We do this in two parts, like we do device_register(). First,
+ *	we remove it from all the subsystems with device_del(), then
+ *	we decrement the reference count via put_device(). If that
+ *	is the final reference count, the device will be cleaned up
+ *	via device_release() above. Otherwise, the structure will
+ *	stick around until the final reference to the device is dropped.
+ */
+void device_unregister(struct device * dev)
+{
+	pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id);
+	device_del(dev);
+	put_device(dev);
+}
+
+
+/**
+ *	device_for_each_child - device child iterator.
+ *	@dev:	parent struct device.
+ *	@data:	data for the callback.
+ *	@fn:	function to be called for each device.
+ *
+ *	Iterate over @dev's child devices, and call @fn for each,
+ *	passing it @data.
+ *
+ *	We check the return of @fn each time. If it returns anything
+ *	other than 0, we break out and return that value.
+ */
+int device_for_each_child(struct device * dev, void * data,
+		     int (*fn)(struct device *, void *))
+{
+	struct device * child;
+	int error = 0;
+
+	down_read(&devices_subsys.rwsem);
+	list_for_each_entry(child, &dev->children, node) {
+		if((error = fn(child, data)))
+			break;
+	}
+	up_read(&devices_subsys.rwsem);
+	return error;
+}
+
+/**
+ *	device_find - locate device on a bus by name.
+ *	@name:	name of the device.
+ *	@bus:	bus to scan for the device.
+ *
+ *	Call kset_find_obj() to iterate over list of devices on
+ *	a bus to find device by name. Return device if found.
+ *
+ *	Note that kset_find_obj increments device's reference count.
+ */
+struct device *device_find(const char *name, struct bus_type *bus)
+{
+	struct kobject *k = kset_find_obj(&bus->devices, name);
+	if (k)
+		return to_dev(k);
+	return NULL;
+}
+
+int __init devices_init(void)
+{
+	return subsystem_register(&devices_subsys);
+}
+
+EXPORT_SYMBOL_GPL(device_for_each_child);
+
+EXPORT_SYMBOL_GPL(device_initialize);
+EXPORT_SYMBOL_GPL(device_add);
+EXPORT_SYMBOL_GPL(device_register);
+
+EXPORT_SYMBOL_GPL(device_del);
+EXPORT_SYMBOL_GPL(device_unregister);
+EXPORT_SYMBOL_GPL(get_device);
+EXPORT_SYMBOL_GPL(put_device);
+EXPORT_SYMBOL_GPL(device_find);
+
+EXPORT_SYMBOL_GPL(device_create_file);
+EXPORT_SYMBOL_GPL(device_remove_file);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
new file mode 100644
index 0000000..6ef3069
--- /dev/null
+++ b/drivers/base/cpu.c
@@ -0,0 +1,104 @@
+/*
+ * drivers/base/cpu.c - basic CPU class support
+ */
+
+#include <linux/sysdev.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/topology.h>
+#include <linux/device.h>
+
+
+struct sysdev_class cpu_sysdev_class = {
+	set_kset_name("cpu"),
+};
+EXPORT_SYMBOL(cpu_sysdev_class);
+
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t show_online(struct sys_device *dev, char *buf)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+
+	return sprintf(buf, "%u\n", !!cpu_online(cpu->sysdev.id));
+}
+
+static ssize_t store_online(struct sys_device *dev, const char *buf,
+			    size_t count)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+	ssize_t ret;
+
+	switch (buf[0]) {
+	case '0':
+		ret = cpu_down(cpu->sysdev.id);
+		if (!ret)
+			kobject_hotplug(&dev->kobj, KOBJ_OFFLINE);
+		break;
+	case '1':
+		ret = cpu_up(cpu->sysdev.id);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret >= 0)
+		ret = count;
+	return ret;
+}
+static SYSDEV_ATTR(online, 0600, show_online, store_online);
+
+static void __devinit register_cpu_control(struct cpu *cpu)
+{
+	sysdev_create_file(&cpu->sysdev, &attr_online);
+}
+void unregister_cpu(struct cpu *cpu, struct node *root)
+{
+
+	if (root)
+		sysfs_remove_link(&root->sysdev.kobj,
+				  kobject_name(&cpu->sysdev.kobj));
+	sysdev_remove_file(&cpu->sysdev, &attr_online);
+
+	sysdev_unregister(&cpu->sysdev);
+
+	return;
+}
+#else /* ... !CONFIG_HOTPLUG_CPU */
+static inline void register_cpu_control(struct cpu *cpu)
+{
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/*
+ * register_cpu - Setup a driverfs device for a CPU.
+ * @cpu - Callers can set the cpu->no_control field to 1, to indicate not to
+ *		  generate a control file in sysfs for this CPU.
+ * @num - CPU number to use when creating the device.
+ *
+ * Initialize and register the CPU device.
+ */
+int __devinit register_cpu(struct cpu *cpu, int num, struct node *root)
+{
+	int error;
+
+	cpu->node_id = cpu_to_node(num);
+	cpu->sysdev.id = num;
+	cpu->sysdev.cls = &cpu_sysdev_class;
+
+	error = sysdev_register(&cpu->sysdev);
+	if (!error && root)
+		error = sysfs_create_link(&root->sysdev.kobj,
+					  &cpu->sysdev.kobj,
+					  kobject_name(&cpu->sysdev.kobj));
+	if (!error && !cpu->no_control)
+		register_cpu_control(cpu);
+	return error;
+}
+
+
+
+int __init cpu_dev_init(void)
+{
+	return sysdev_class_register(&cpu_sysdev_class);
+}
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
new file mode 100644
index 0000000..f48833d
--- /dev/null
+++ b/drivers/base/dmapool.c
@@ -0,0 +1,414 @@
+
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <asm/io.h>		/* Needed for i386 to build */
+#include <asm/scatterlist.h>	/* Needed for i386 to build */
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+/*
+ * Pool allocator ... wraps the dma_alloc_coherent page allocator, so
+ * small blocks are easily used by drivers for bus mastering controllers.
+ * This should probably be sharing the guts of the slab allocator.
+ */
+
+struct dma_pool {	/* the pool */
+	struct list_head	page_list;
+	spinlock_t		lock;
+	size_t			blocks_per_page;
+	size_t			size;
+	struct device		*dev;
+	size_t			allocation;
+	char			name [32];
+	wait_queue_head_t	waitq;
+	struct list_head	pools;
+};
+
+struct dma_page {	/* cacheable header for 'allocation' bytes */
+	struct list_head	page_list;
+	void			*vaddr;
+	dma_addr_t		dma;
+	unsigned		in_use;
+	unsigned long		bitmap [0];
+};
+
+#define	POOL_TIMEOUT_JIFFIES	((100 /* msec */ * HZ) / 1000)
+#define	POOL_POISON_FREED	0xa7	/* !inuse */
+#define	POOL_POISON_ALLOCATED	0xa9	/* !initted */
+
+static DECLARE_MUTEX (pools_lock);
+
+static ssize_t
+show_pools (struct device *dev, char *buf)
+{
+	unsigned temp;
+	unsigned size;
+	char *next;
+	struct dma_page *page;
+	struct dma_pool *pool;
+
+	next = buf;
+	size = PAGE_SIZE;
+
+	temp = scnprintf(next, size, "poolinfo - 0.1\n");
+	size -= temp;
+	next += temp;
+
+	down (&pools_lock);
+	list_for_each_entry(pool, &dev->dma_pools, pools) {
+		unsigned pages = 0;
+		unsigned blocks = 0;
+
+		list_for_each_entry(page, &pool->page_list, page_list) {
+			pages++;
+			blocks += page->in_use;
+		}
+
+		/* per-pool info, no real statistics yet */
+		temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n",
+				pool->name,
+				blocks, pages * pool->blocks_per_page,
+				pool->size, pages);
+		size -= temp;
+		next += temp;
+	}
+	up (&pools_lock);
+
+	return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (pools, S_IRUGO, show_pools, NULL);
+
+/**
+ * dma_pool_create - Creates a pool of consistent memory blocks, for dma.
+ * @name: name of pool, for diagnostics
+ * @dev: device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @allocation: returned blocks won't cross this boundary (or zero)
+ * Context: !in_interrupt()
+ *
+ * Returns a dma allocation pool with the requested characteristics, or
+ * null if one can't be created.  Given one of these pools, dma_pool_alloc()
+ * may be used to allocate memory.  Such memory will all have "consistent"
+ * DMA mappings, accessible by the device and its driver without using
+ * cache flushing primitives.  The actual size of blocks allocated may be
+ * larger than requested because of alignment.
+ *
+ * If allocation is nonzero, objects returned from dma_pool_alloc() won't
+ * cross that size boundary.  This is useful for devices which have
+ * addressing restrictions on individual DMA transfers, such as not crossing
+ * boundaries of 4KBytes.
+ */
+struct dma_pool *
+dma_pool_create (const char *name, struct device *dev,
+	size_t size, size_t align, size_t allocation)
+{
+	struct dma_pool		*retval;
+
+	if (align == 0)
+		align = 1;
+	if (size == 0)
+		return NULL;
+	else if (size < align)
+		size = align;
+	else if ((size % align) != 0) {
+		size += align + 1;
+		size &= ~(align - 1);
+	}
+
+	if (allocation == 0) {
+		if (PAGE_SIZE < size)
+			allocation = size;
+		else
+			allocation = PAGE_SIZE;
+		// FIXME: round up for less fragmentation
+	} else if (allocation < size)
+		return NULL;
+
+	if (!(retval = kmalloc (sizeof *retval, SLAB_KERNEL)))
+		return retval;
+
+	strlcpy (retval->name, name, sizeof retval->name);
+
+	retval->dev = dev;
+
+	INIT_LIST_HEAD (&retval->page_list);
+	spin_lock_init (&retval->lock);
+	retval->size = size;
+	retval->allocation = allocation;
+	retval->blocks_per_page = allocation / size;
+	init_waitqueue_head (&retval->waitq);
+
+	if (dev) {
+		down (&pools_lock);
+		if (list_empty (&dev->dma_pools))
+			device_create_file (dev, &dev_attr_pools);
+		/* note:  not currently insisting "name" be unique */
+		list_add (&retval->pools, &dev->dma_pools);
+		up (&pools_lock);
+	} else
+		INIT_LIST_HEAD (&retval->pools);
+
+	return retval;
+}
+
+
+static struct dma_page *
+pool_alloc_page (struct dma_pool *pool, unsigned int __nocast mem_flags)
+{
+	struct dma_page	*page;
+	int		mapsize;
+
+	mapsize = pool->blocks_per_page;
+	mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
+	mapsize *= sizeof (long);
+
+	page = (struct dma_page *) kmalloc (mapsize + sizeof *page, mem_flags);
+	if (!page)
+		return NULL;
+	page->vaddr = dma_alloc_coherent (pool->dev,
+					    pool->allocation,
+					    &page->dma,
+					    mem_flags);
+	if (page->vaddr) {
+		memset (page->bitmap, 0xff, mapsize);	// bit set == free
+#ifdef	CONFIG_DEBUG_SLAB
+		memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
+#endif
+		list_add (&page->page_list, &pool->page_list);
+		page->in_use = 0;
+	} else {
+		kfree (page);
+		page = NULL;
+	}
+	return page;
+}
+
+
+static inline int
+is_page_busy (int blocks, unsigned long *bitmap)
+{
+	while (blocks > 0) {
+		if (*bitmap++ != ~0UL)
+			return 1;
+		blocks -= BITS_PER_LONG;
+	}
+	return 0;
+}
+
+static void
+pool_free_page (struct dma_pool *pool, struct dma_page *page)
+{
+	dma_addr_t	dma = page->dma;
+
+#ifdef	CONFIG_DEBUG_SLAB
+	memset (page->vaddr, POOL_POISON_FREED, pool->allocation);
+#endif
+	dma_free_coherent (pool->dev, pool->allocation, page->vaddr, dma);
+	list_del (&page->page_list);
+	kfree (page);
+}
+
+
+/**
+ * dma_pool_destroy - destroys a pool of dma memory blocks.
+ * @pool: dma pool that will be destroyed
+ * Context: !in_interrupt()
+ *
+ * Caller guarantees that no more memory from the pool is in use,
+ * and that nothing will try to use the pool after this call.
+ */
+void
+dma_pool_destroy (struct dma_pool *pool)
+{
+	down (&pools_lock);
+	list_del (&pool->pools);
+	if (pool->dev && list_empty (&pool->dev->dma_pools))
+		device_remove_file (pool->dev, &dev_attr_pools);
+	up (&pools_lock);
+
+	while (!list_empty (&pool->page_list)) {
+		struct dma_page		*page;
+		page = list_entry (pool->page_list.next,
+				struct dma_page, page_list);
+		if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
+			if (pool->dev)
+				dev_err(pool->dev, "dma_pool_destroy %s, %p busy\n",
+					pool->name, page->vaddr);
+			else
+				printk (KERN_ERR "dma_pool_destroy %s, %p busy\n",
+					pool->name, page->vaddr);
+			/* leak the still-in-use consistent memory */
+			list_del (&page->page_list);
+			kfree (page);
+		} else
+			pool_free_page (pool, page);
+	}
+
+	kfree (pool);
+}
+
+
+/**
+ * dma_pool_alloc - get a block of consistent memory
+ * @pool: dma pool that will produce the block
+ * @mem_flags: GFP_* bitmask
+ * @handle: pointer to dma address of block
+ *
+ * This returns the kernel virtual address of a currently unused block,
+ * and reports its dma address through the handle.
+ * If such a memory block can't be allocated, null is returned.
+ */
+void *
+dma_pool_alloc (struct dma_pool *pool, int mem_flags, dma_addr_t *handle)
+{
+	unsigned long		flags;
+	struct dma_page		*page;
+	int			map, block;
+	size_t			offset;
+	void			*retval;
+
+restart:
+	spin_lock_irqsave (&pool->lock, flags);
+	list_for_each_entry(page, &pool->page_list, page_list) {
+		int		i;
+		/* only cachable accesses here ... */
+		for (map = 0, i = 0;
+				i < pool->blocks_per_page;
+				i += BITS_PER_LONG, map++) {
+			if (page->bitmap [map] == 0)
+				continue;
+			block = ffz (~ page->bitmap [map]);
+			if ((i + block) < pool->blocks_per_page) {
+				clear_bit (block, &page->bitmap [map]);
+				offset = (BITS_PER_LONG * map) + block;
+				offset *= pool->size;
+				goto ready;
+			}
+		}
+	}
+	if (!(page = pool_alloc_page (pool, SLAB_ATOMIC))) {
+		if (mem_flags & __GFP_WAIT) {
+			DECLARE_WAITQUEUE (wait, current);
+
+			current->state = TASK_INTERRUPTIBLE;
+			add_wait_queue (&pool->waitq, &wait);
+			spin_unlock_irqrestore (&pool->lock, flags);
+
+			schedule_timeout (POOL_TIMEOUT_JIFFIES);
+
+			remove_wait_queue (&pool->waitq, &wait);
+			goto restart;
+		}
+		retval = NULL;
+		goto done;
+	}
+
+	clear_bit (0, &page->bitmap [0]);
+	offset = 0;
+ready:
+	page->in_use++;
+	retval = offset + page->vaddr;
+	*handle = offset + page->dma;
+#ifdef	CONFIG_DEBUG_SLAB
+	memset (retval, POOL_POISON_ALLOCATED, pool->size);
+#endif
+done:
+	spin_unlock_irqrestore (&pool->lock, flags);
+	return retval;
+}
+
+
+static struct dma_page *
+pool_find_page (struct dma_pool *pool, dma_addr_t dma)
+{
+	unsigned long		flags;
+	struct dma_page		*page;
+
+	spin_lock_irqsave (&pool->lock, flags);
+	list_for_each_entry(page, &pool->page_list, page_list) {
+		if (dma < page->dma)
+			continue;
+		if (dma < (page->dma + pool->allocation))
+			goto done;
+	}
+	page = NULL;
+done:
+	spin_unlock_irqrestore (&pool->lock, flags);
+	return page;
+}
+
+
+/**
+ * dma_pool_free - put block back into dma pool
+ * @pool: the dma pool holding the block
+ * @vaddr: virtual address of block
+ * @dma: dma address of block
+ *
+ * Caller promises neither device nor driver will again touch this block
+ * unless it is first re-allocated.
+ */
+void
+dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t dma)
+{
+	struct dma_page		*page;
+	unsigned long		flags;
+	int			map, block;
+
+	if ((page = pool_find_page (pool, dma)) == 0) {
+		if (pool->dev)
+			dev_err(pool->dev, "dma_pool_free %s, %p/%lx (bad dma)\n",
+				pool->name, vaddr, (unsigned long) dma);
+		else
+			printk (KERN_ERR "dma_pool_free %s, %p/%lx (bad dma)\n",
+				pool->name, vaddr, (unsigned long) dma);
+		return;
+	}
+
+	block = dma - page->dma;
+	block /= pool->size;
+	map = block / BITS_PER_LONG;
+	block %= BITS_PER_LONG;
+
+#ifdef	CONFIG_DEBUG_SLAB
+	if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
+		if (pool->dev)
+			dev_err(pool->dev, "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
+				pool->name, vaddr, (unsigned long long) dma);
+		else
+			printk (KERN_ERR "dma_pool_free %s, %p (bad vaddr)/%Lx\n",
+				pool->name, vaddr, (unsigned long long) dma);
+		return;
+	}
+	if (page->bitmap [map] & (1UL << block)) {
+		if (pool->dev)
+			dev_err(pool->dev, "dma_pool_free %s, dma %Lx already free\n",
+				pool->name, (unsigned long long)dma);
+		else
+			printk (KERN_ERR "dma_pool_free %s, dma %Lx already free\n",
+				pool->name, (unsigned long long)dma);
+		return;
+	}
+	memset (vaddr, POOL_POISON_FREED, pool->size);
+#endif
+
+	spin_lock_irqsave (&pool->lock, flags);
+	page->in_use--;
+	set_bit (block, &page->bitmap [map]);
+	if (waitqueue_active (&pool->waitq))
+		wake_up (&pool->waitq);
+	/*
+	 * Resist a temptation to do
+	 *    if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
+	 * Better have a few empty pages hang around.
+	 */
+	spin_unlock_irqrestore (&pool->lock, flags);
+}
+
+
+EXPORT_SYMBOL (dma_pool_create);
+EXPORT_SYMBOL (dma_pool_destroy);
+EXPORT_SYMBOL (dma_pool_alloc);
+EXPORT_SYMBOL (dma_pool_free);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
new file mode 100644
index 0000000..3b269f7
--- /dev/null
+++ b/drivers/base/driver.c
@@ -0,0 +1,138 @@
+/*
+ * driver.c - centralized device driver management
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include "base.h"
+
+#define to_dev(node) container_of(node, struct device, driver_list)
+#define to_drv(obj) container_of(obj, struct device_driver, kobj)
+
+/**
+ *	driver_create_file - create sysfs file for driver.
+ *	@drv:	driver.
+ *	@attr:	driver attribute descriptor.
+ */
+
+int driver_create_file(struct device_driver * drv, struct driver_attribute * attr)
+{
+	int error;
+	if (get_driver(drv)) {
+		error = sysfs_create_file(&drv->kobj, &attr->attr);
+		put_driver(drv);
+	} else
+		error = -EINVAL;
+	return error;
+}
+
+
+/**
+ *	driver_remove_file - remove sysfs file for driver.
+ *	@drv:	driver.
+ *	@attr:	driver attribute descriptor.
+ */
+
+void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr)
+{
+	if (get_driver(drv)) {
+		sysfs_remove_file(&drv->kobj, &attr->attr);
+		put_driver(drv);
+	}
+}
+
+
+/**
+ *	get_driver - increment driver reference count.
+ *	@drv:	driver.
+ */
+struct device_driver * get_driver(struct device_driver * drv)
+{
+	return drv ? to_drv(kobject_get(&drv->kobj)) : NULL;
+}
+
+
+/**
+ *	put_driver - decrement driver's refcount.
+ *	@drv:	driver.
+ */
+void put_driver(struct device_driver * drv)
+{
+	kobject_put(&drv->kobj);
+}
+
+
+/**
+ *	driver_register - register driver with bus
+ *	@drv:	driver to register
+ *
+ *	We pass off most of the work to the bus_add_driver() call,
+ *	since most of the things we have to do deal with the bus
+ *	structures.
+ *
+ *	The one interesting aspect is that we setup @drv->unloaded
+ *	as a completion that gets complete when the driver reference
+ *	count reaches 0.
+ */
+int driver_register(struct device_driver * drv)
+{
+	INIT_LIST_HEAD(&drv->devices);
+	init_completion(&drv->unloaded);
+	return bus_add_driver(drv);
+}
+
+
+/**
+ *	driver_unregister - remove driver from system.
+ *	@drv:	driver.
+ *
+ *	Again, we pass off most of the work to the bus-level call.
+ *
+ *	Though, once that is done, we wait until @drv->unloaded is completed.
+ *	This will block until the driver refcount reaches 0, and it is
+ *	released. Only modular drivers will call this function, and we
+ *	have to guarantee that it won't complete, letting the driver
+ *	unload until all references are gone.
+ */
+
+void driver_unregister(struct device_driver * drv)
+{
+	bus_remove_driver(drv);
+	wait_for_completion(&drv->unloaded);
+}
+
+/**
+ *	driver_find - locate driver on a bus by its name.
+ *	@name:	name of the driver.
+ *	@bus:	bus to scan for the driver.
+ *
+ *	Call kset_find_obj() to iterate over list of drivers on
+ *	a bus to find driver by name. Return driver if found.
+ *
+ *	Note that kset_find_obj increments driver's reference count.
+ */
+struct device_driver *driver_find(const char *name, struct bus_type *bus)
+{
+	struct kobject *k = kset_find_obj(&bus->drivers, name);
+	if (k)
+		return to_drv(k);
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(driver_register);
+EXPORT_SYMBOL_GPL(driver_unregister);
+EXPORT_SYMBOL_GPL(get_driver);
+EXPORT_SYMBOL_GPL(put_driver);
+EXPORT_SYMBOL_GPL(driver_find);
+
+EXPORT_SYMBOL_GPL(driver_create_file);
+EXPORT_SYMBOL_GPL(driver_remove_file);
diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c
new file mode 100644
index 0000000..88ab044
--- /dev/null
+++ b/drivers/base/firmware.c
@@ -0,0 +1,34 @@
+/*
+ * firmware.c - firmware subsystem hoohaw.
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+static decl_subsys(firmware, NULL, NULL);
+
+int firmware_register(struct subsystem * s)
+{
+	kset_set_kset_s(s, firmware_subsys);
+	return subsystem_register(s);
+}
+
+void firmware_unregister(struct subsystem * s)
+{
+	subsystem_unregister(s);
+}
+
+int __init firmware_init(void)
+{
+	return subsystem_register(&firmware_subsys);
+}
+
+EXPORT_SYMBOL_GPL(firmware_register);
+EXPORT_SYMBOL_GPL(firmware_unregister);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
new file mode 100644
index 0000000..26c9464
--- /dev/null
+++ b/drivers/base/firmware_class.c
@@ -0,0 +1,583 @@
+/*
+ * firmware_class.c - Multi purpose firmware loading support
+ *
+ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
+ *
+ * Please see Documentation/firmware_class/ for more information.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <asm/semaphore.h>
+
+#include <linux/firmware.h>
+#include "base.h"
+
+MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
+MODULE_DESCRIPTION("Multi purpose firmware loading support");
+MODULE_LICENSE("GPL");
+
+enum {
+	FW_STATUS_LOADING,
+	FW_STATUS_DONE,
+	FW_STATUS_ABORT,
+	FW_STATUS_READY,
+};
+
+static int loading_timeout = 10;	/* In seconds */
+
+/* fw_lock could be moved to 'struct firmware_priv' but since it is just
+ * guarding for corner cases a global lock should be OK */
+static DECLARE_MUTEX(fw_lock);
+
+struct firmware_priv {
+	char fw_id[FIRMWARE_NAME_MAX];
+	struct completion completion;
+	struct bin_attribute attr_data;
+	struct firmware *fw;
+	unsigned long status;
+	int alloc_size;
+	struct timer_list timeout;
+};
+
+static inline void
+fw_load_abort(struct firmware_priv *fw_priv)
+{
+	set_bit(FW_STATUS_ABORT, &fw_priv->status);
+	wmb();
+	complete(&fw_priv->completion);
+}
+
+static ssize_t
+firmware_timeout_show(struct class *class, char *buf)
+{
+	return sprintf(buf, "%d\n", loading_timeout);
+}
+
+/**
+ * firmware_timeout_store:
+ * Description:
+ *	Sets the number of seconds to wait for the firmware.  Once
+ *	this expires an error will be return to the driver and no
+ *	firmware will be provided.
+ *
+ *	Note: zero means 'wait for ever'
+ *
+ **/
+static ssize_t
+firmware_timeout_store(struct class *class, const char *buf, size_t count)
+{
+	loading_timeout = simple_strtol(buf, NULL, 10);
+	return count;
+}
+
+static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
+
+static void  fw_class_dev_release(struct class_device *class_dev);
+int firmware_class_hotplug(struct class_device *dev, char **envp,
+			   int num_envp, char *buffer, int buffer_size);
+
+static struct class firmware_class = {
+	.name		= "firmware",
+	.hotplug	= firmware_class_hotplug,
+	.release	= fw_class_dev_release,
+};
+
+int
+firmware_class_hotplug(struct class_device *class_dev, char **envp,
+		       int num_envp, char *buffer, int buffer_size)
+{
+	struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+	int i = 0, len = 0;
+
+	if (!test_bit(FW_STATUS_READY, &fw_priv->status))
+		return -ENODEV;
+
+	if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
+			"FIRMWARE=%s", fw_priv->fw_id))
+		return -ENOMEM;
+
+	envp[i] = NULL;
+
+	return 0;
+}
+
+static ssize_t
+firmware_loading_show(struct class_device *class_dev, char *buf)
+{
+	struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+	int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
+	return sprintf(buf, "%d\n", loading);
+}
+
+/**
+ * firmware_loading_store: - loading control file
+ * Description:
+ *	The relevant values are:
+ *
+ *	 1: Start a load, discarding any previous partial load.
+ *	 0: Conclude the load and handle the data to the driver code.
+ *	-1: Conclude the load with an error and discard any written data.
+ **/
+static ssize_t
+firmware_loading_store(struct class_device *class_dev,
+		       const char *buf, size_t count)
+{
+	struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+	int loading = simple_strtol(buf, NULL, 10);
+
+	switch (loading) {
+	case 1:
+		down(&fw_lock);
+		vfree(fw_priv->fw->data);
+		fw_priv->fw->data = NULL;
+		fw_priv->fw->size = 0;
+		fw_priv->alloc_size = 0;
+		set_bit(FW_STATUS_LOADING, &fw_priv->status);
+		up(&fw_lock);
+		break;
+	case 0:
+		if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
+			complete(&fw_priv->completion);
+			clear_bit(FW_STATUS_LOADING, &fw_priv->status);
+			break;
+		}
+		/* fallthrough */
+	default:
+		printk(KERN_ERR "%s: unexpected value (%d)\n", __FUNCTION__,
+		       loading);
+		/* fallthrough */
+	case -1:
+		fw_load_abort(fw_priv);
+		break;
+	}
+
+	return count;
+}
+
+static CLASS_DEVICE_ATTR(loading, 0644,
+			firmware_loading_show, firmware_loading_store);
+
+static ssize_t
+firmware_data_read(struct kobject *kobj,
+		   char *buffer, loff_t offset, size_t count)
+{
+	struct class_device *class_dev = to_class_dev(kobj);
+	struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+	struct firmware *fw;
+	ssize_t ret_count = count;
+
+	down(&fw_lock);
+	fw = fw_priv->fw;
+	if (test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+		ret_count = -ENODEV;
+		goto out;
+	}
+	if (offset > fw->size) {
+		ret_count = 0;
+		goto out;
+	}
+	if (offset + ret_count > fw->size)
+		ret_count = fw->size - offset;
+
+	memcpy(buffer, fw->data + offset, ret_count);
+out:
+	up(&fw_lock);
+	return ret_count;
+}
+static int
+fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
+{
+	u8 *new_data;
+
+	if (min_size <= fw_priv->alloc_size)
+		return 0;
+
+	new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE);
+	if (!new_data) {
+		printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
+		/* Make sure that we don't keep incomplete data */
+		fw_load_abort(fw_priv);
+		return -ENOMEM;
+	}
+	fw_priv->alloc_size += PAGE_SIZE;
+	if (fw_priv->fw->data) {
+		memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
+		vfree(fw_priv->fw->data);
+	}
+	fw_priv->fw->data = new_data;
+	BUG_ON(min_size > fw_priv->alloc_size);
+	return 0;
+}
+
+/**
+ * firmware_data_write:
+ *
+ * Description:
+ *
+ *	Data written to the 'data' attribute will be later handled to
+ *	the driver as a firmware image.
+ **/
+static ssize_t
+firmware_data_write(struct kobject *kobj,
+		    char *buffer, loff_t offset, size_t count)
+{
+	struct class_device *class_dev = to_class_dev(kobj);
+	struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+	struct firmware *fw;
+	ssize_t retval;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	down(&fw_lock);
+	fw = fw_priv->fw;
+	if (test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+		retval = -ENODEV;
+		goto out;
+	}
+	retval = fw_realloc_buffer(fw_priv, offset + count);
+	if (retval)
+		goto out;
+
+	memcpy(fw->data + offset, buffer, count);
+
+	fw->size = max_t(size_t, offset + count, fw->size);
+	retval = count;
+out:
+	up(&fw_lock);
+	return retval;
+}
+static struct bin_attribute firmware_attr_data_tmpl = {
+	.attr = {.name = "data", .mode = 0644, .owner = THIS_MODULE},
+	.size = 0,
+	.read = firmware_data_read,
+	.write = firmware_data_write,
+};
+
+static void
+fw_class_dev_release(struct class_device *class_dev)
+{
+	struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+
+	kfree(fw_priv);
+	kfree(class_dev);
+
+	module_put(THIS_MODULE);
+}
+
+static void
+firmware_class_timeout(u_long data)
+{
+	struct firmware_priv *fw_priv = (struct firmware_priv *) data;
+	fw_load_abort(fw_priv);
+}
+
+static inline void
+fw_setup_class_device_id(struct class_device *class_dev, struct device *dev)
+{
+	/* XXX warning we should watch out for name collisions */
+	strlcpy(class_dev->class_id, dev->bus_id, BUS_ID_SIZE);
+}
+
+static int
+fw_register_class_device(struct class_device **class_dev_p,
+			 const char *fw_name, struct device *device)
+{
+	int retval;
+	struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
+						GFP_KERNEL);
+	struct class_device *class_dev = kmalloc(sizeof (struct class_device),
+						 GFP_KERNEL);
+
+	*class_dev_p = NULL;
+
+	if (!fw_priv || !class_dev) {
+		printk(KERN_ERR "%s: kmalloc failed\n", __FUNCTION__);
+		retval = -ENOMEM;
+		goto error_kfree;
+	}
+	memset(fw_priv, 0, sizeof (*fw_priv));
+	memset(class_dev, 0, sizeof (*class_dev));
+
+	init_completion(&fw_priv->completion);
+	fw_priv->attr_data = firmware_attr_data_tmpl;
+	strlcpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX);
+
+	fw_priv->timeout.function = firmware_class_timeout;
+	fw_priv->timeout.data = (u_long) fw_priv;
+	init_timer(&fw_priv->timeout);
+
+	fw_setup_class_device_id(class_dev, device);
+	class_dev->dev = device;
+	class_dev->class = &firmware_class;
+	class_set_devdata(class_dev, fw_priv);
+	retval = class_device_register(class_dev);
+	if (retval) {
+		printk(KERN_ERR "%s: class_device_register failed\n",
+		       __FUNCTION__);
+		goto error_kfree;
+	}
+	*class_dev_p = class_dev;
+	return 0;
+
+error_kfree:
+	kfree(fw_priv);
+	kfree(class_dev);
+	return retval;
+}
+
+static int
+fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
+		      const char *fw_name, struct device *device)
+{
+	struct class_device *class_dev;
+	struct firmware_priv *fw_priv;
+	int retval;
+
+	*class_dev_p = NULL;
+	retval = fw_register_class_device(&class_dev, fw_name, device);
+	if (retval)
+		goto out;
+
+	/* Need to pin this module until class device is destroyed */
+	__module_get(THIS_MODULE);
+
+	fw_priv = class_get_devdata(class_dev);
+
+	fw_priv->fw = fw;
+	retval = sysfs_create_bin_file(&class_dev->kobj, &fw_priv->attr_data);
+	if (retval) {
+		printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
+		       __FUNCTION__);
+		goto error_unreg;
+	}
+
+	retval = class_device_create_file(class_dev,
+					  &class_device_attr_loading);
+	if (retval) {
+		printk(KERN_ERR "%s: class_device_create_file failed\n",
+		       __FUNCTION__);
+		goto error_unreg;
+	}
+
+	set_bit(FW_STATUS_READY, &fw_priv->status);
+	*class_dev_p = class_dev;
+	goto out;
+
+error_unreg:
+	class_device_unregister(class_dev);
+out:
+	return retval;
+}
+
+/**
+ * request_firmware: - request firmware to hotplug and wait for it
+ * Description:
+ *	@firmware will be used to return a firmware image by the name
+ *	of @name for device @device.
+ *
+ *	Should be called from user context where sleeping is allowed.
+ *
+ *	@name will be use as $FIRMWARE in the hotplug environment and
+ *	should be distinctive enough not to be confused with any other
+ *	firmware image for this or any other device.
+ **/
+int
+request_firmware(const struct firmware **firmware_p, const char *name,
+		 struct device *device)
+{
+	struct class_device *class_dev;
+	struct firmware_priv *fw_priv;
+	struct firmware *firmware;
+	int retval;
+
+	if (!firmware_p)
+		return -EINVAL;
+
+	*firmware_p = firmware = kmalloc(sizeof (struct firmware), GFP_KERNEL);
+	if (!firmware) {
+		printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
+		       __FUNCTION__);
+		retval = -ENOMEM;
+		goto out;
+	}
+	memset(firmware, 0, sizeof (*firmware));
+
+	retval = fw_setup_class_device(firmware, &class_dev, name, device);
+	if (retval)
+		goto error_kfree_fw;
+
+	fw_priv = class_get_devdata(class_dev);
+
+	if (loading_timeout) {
+		fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
+		add_timer(&fw_priv->timeout);
+	}
+
+	kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
+	wait_for_completion(&fw_priv->completion);
+	set_bit(FW_STATUS_DONE, &fw_priv->status);
+
+	del_timer_sync(&fw_priv->timeout);
+
+	down(&fw_lock);
+	if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
+		retval = -ENOENT;
+		release_firmware(fw_priv->fw);
+		*firmware_p = NULL;
+	}
+	fw_priv->fw = NULL;
+	up(&fw_lock);
+	class_device_unregister(class_dev);
+	goto out;
+
+error_kfree_fw:
+	kfree(firmware);
+	*firmware_p = NULL;
+out:
+	return retval;
+}
+
+/**
+ * release_firmware: - release the resource associated with a firmware image
+ **/
+void
+release_firmware(const struct firmware *fw)
+{
+	if (fw) {
+		vfree(fw->data);
+		kfree(fw);
+	}
+}
+
+/**
+ * register_firmware: - provide a firmware image for later usage
+ *
+ * Description:
+ *	Make sure that @data will be available by requesting firmware @name.
+ *
+ *	Note: This will not be possible until some kind of persistence
+ *	is available.
+ **/
+void
+register_firmware(const char *name, const u8 *data, size_t size)
+{
+	/* This is meaningless without firmware caching, so until we
+	 * decide if firmware caching is reasonable just leave it as a
+	 * noop */
+}
+
+/* Async support */
+struct firmware_work {
+	struct work_struct work;
+	struct module *module;
+	const char *name;
+	struct device *device;
+	void *context;
+	void (*cont)(const struct firmware *fw, void *context);
+};
+
+static int
+request_firmware_work_func(void *arg)
+{
+	struct firmware_work *fw_work = arg;
+	const struct firmware *fw;
+	if (!arg) {
+		WARN_ON(1);
+		return 0;
+	}
+	daemonize("%s/%s", "firmware", fw_work->name);
+	request_firmware(&fw, fw_work->name, fw_work->device);
+	fw_work->cont(fw, fw_work->context);
+	release_firmware(fw);
+	module_put(fw_work->module);
+	kfree(fw_work);
+	return 0;
+}
+
+/**
+ * request_firmware_nowait:
+ *
+ * Description:
+ *	Asynchronous variant of request_firmware() for contexts where
+ *	it is not possible to sleep.
+ *
+ *	@cont will be called asynchronously when the firmware request is over.
+ *
+ *	@context will be passed over to @cont.
+ *
+ *	@fw may be %NULL if firmware request fails.
+ *
+ **/
+int
+request_firmware_nowait(
+	struct module *module,
+	const char *name, struct device *device, void *context,
+	void (*cont)(const struct firmware *fw, void *context))
+{
+	struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
+						GFP_ATOMIC);
+	int ret;
+
+	if (!fw_work)
+		return -ENOMEM;
+	if (!try_module_get(module)) {
+		kfree(fw_work);
+		return -EFAULT;
+	}
+
+	*fw_work = (struct firmware_work) {
+		.module = module,
+		.name = name,
+		.device = device,
+		.context = context,
+		.cont = cont,
+	};
+
+	ret = kernel_thread(request_firmware_work_func, fw_work,
+			    CLONE_FS | CLONE_FILES);
+
+	if (ret < 0) {
+		fw_work->cont(NULL, fw_work->context);
+		return ret;
+	}
+	return 0;
+}
+
+static int __init
+firmware_class_init(void)
+{
+	int error;
+	error = class_register(&firmware_class);
+	if (error) {
+		printk(KERN_ERR "%s: class_register failed\n", __FUNCTION__);
+		return error;
+	}
+	error = class_create_file(&firmware_class, &class_attr_timeout);
+	if (error) {
+		printk(KERN_ERR "%s: class_create_file failed\n",
+		       __FUNCTION__);
+		class_unregister(&firmware_class);
+	}
+	return error;
+
+}
+static void __exit
+firmware_class_exit(void)
+{
+	class_unregister(&firmware_class);
+}
+
+module_init(firmware_class_init);
+module_exit(firmware_class_exit);
+
+EXPORT_SYMBOL(release_firmware);
+EXPORT_SYMBOL(request_firmware);
+EXPORT_SYMBOL(request_firmware_nowait);
+EXPORT_SYMBOL(register_firmware);
diff --git a/drivers/base/init.c b/drivers/base/init.c
new file mode 100644
index 0000000..a76ae5a
--- /dev/null
+++ b/drivers/base/init.c
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+
+extern int devices_init(void);
+extern int buses_init(void);
+extern int classes_init(void);
+extern int firmware_init(void);
+extern int platform_bus_init(void);
+extern int system_bus_init(void);
+extern int cpu_dev_init(void);
+extern int attribute_container_init(void);
+/**
+ *	driver_init - initialize driver model.
+ *
+ *	Call the driver model init functions to initialize their
+ *	subsystems. Called early from init/main.c.
+ */
+
+void __init driver_init(void)
+{
+	/* These are the core pieces */
+	devices_init();
+	buses_init();
+	classes_init();
+	firmware_init();
+
+	/* These are also core pieces, but must come after the
+	 * core core pieces.
+	 */
+	platform_bus_init();
+	system_bus_init();
+	cpu_dev_init();
+	attribute_container_init();
+}
diff --git a/drivers/base/interface.c b/drivers/base/interface.c
new file mode 100644
index 0000000..bd51584
--- /dev/null
+++ b/drivers/base/interface.c
@@ -0,0 +1,51 @@
+/*
+ * drivers/base/interface.c - common driverfs interface that's exported to
+ * 	the world for all devices.
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+
+/**
+ *	detach_state - control the default power state for the device.
+ *
+ *	This is the state the device enters when it's driver module is
+ *	unloaded. The value is an unsigned integer, in the range of 0-4.
+ *	'0' indicates 'On', so no action will be taken when the driver is
+ *	unloaded. This is the default behavior.
+ *	'4' indicates 'Off', meaning the driver core will call the driver's
+ *	shutdown method to quiesce the device.
+ *	1-3 indicate a low-power state for the device to enter via the
+ *	driver's suspend method.
+ */
+
+static ssize_t detach_show(struct device * dev, char * buf)
+{
+	return sprintf(buf, "%u\n", dev->detach_state);
+}
+
+static ssize_t detach_store(struct device * dev, const char * buf, size_t n)
+{
+	u32 state;
+	state = simple_strtoul(buf, NULL, 10);
+	if (state > 4)
+		return -EINVAL;
+	dev->detach_state = state;
+	return n;
+}
+
+static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store);
+
+
+struct attribute * dev_default_attrs[] = {
+	&dev_attr_detach_state.attr,
+	NULL,
+};
diff --git a/drivers/base/map.c b/drivers/base/map.c
new file mode 100644
index 0000000..2f455d8
--- /dev/null
+++ b/drivers/base/map.c
@@ -0,0 +1,155 @@
+/*
+ *  linux/drivers/base/map.c
+ *
+ * (C) Copyright Al Viro 2002,2003
+ *	Released under GPL v2.
+ *
+ * NOTE: data structure needs to be changed.  It works, but for large dev_t
+ * it will be too slow.  It is isolated, though, so these changes will be
+ * local to that file.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kdev_t.h>
+#include <linux/kobject.h>
+#include <linux/kobj_map.h>
+
+struct kobj_map {
+	struct probe {
+		struct probe *next;
+		dev_t dev;
+		unsigned long range;
+		struct module *owner;
+		kobj_probe_t *get;
+		int (*lock)(dev_t, void *);
+		void *data;
+	} *probes[255];
+	struct semaphore *sem;
+};
+
+int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
+	     struct module *module, kobj_probe_t *probe,
+	     int (*lock)(dev_t, void *), void *data)
+{
+	unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
+	unsigned index = MAJOR(dev);
+	unsigned i;
+	struct probe *p;
+
+	if (n > 255)
+		n = 255;
+
+	p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);
+
+	if (p == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < n; i++, p++) {
+		p->owner = module;
+		p->get = probe;
+		p->lock = lock;
+		p->dev = dev;
+		p->range = range;
+		p->data = data;
+	}
+	down(domain->sem);
+	for (i = 0, p -= n; i < n; i++, p++, index++) {
+		struct probe **s = &domain->probes[index % 255];
+		while (*s && (*s)->range < range)
+			s = &(*s)->next;
+		p->next = *s;
+		*s = p;
+	}
+	up(domain->sem);
+	return 0;
+}
+
+void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
+{
+	unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
+	unsigned index = MAJOR(dev);
+	unsigned i;
+	struct probe *found = NULL;
+
+	if (n > 255)
+		n = 255;
+
+	down(domain->sem);
+	for (i = 0; i < n; i++, index++) {
+		struct probe **s;
+		for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
+			struct probe *p = *s;
+			if (p->dev == dev && p->range == range) {
+				*s = p->next;
+				if (!found)
+					found = p;
+				break;
+			}
+		}
+	}
+	up(domain->sem);
+	kfree(found);
+}
+
+struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
+{
+	struct kobject *kobj;
+	struct probe *p;
+	unsigned long best = ~0UL;
+
+retry:
+	down(domain->sem);
+	for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
+		struct kobject *(*probe)(dev_t, int *, void *);
+		struct module *owner;
+		void *data;
+
+		if (p->dev > dev || p->dev + p->range - 1 < dev)
+			continue;
+		if (p->range - 1 >= best)
+			break;
+		if (!try_module_get(p->owner))
+			continue;
+		owner = p->owner;
+		data = p->data;
+		probe = p->get;
+		best = p->range - 1;
+		*index = dev - p->dev;
+		if (p->lock && p->lock(dev, data) < 0) {
+			module_put(owner);
+			continue;
+		}
+		up(domain->sem);
+		kobj = probe(dev, index, data);
+		/* Currently ->owner protects _only_ ->probe() itself. */
+		module_put(owner);
+		if (kobj)
+			return kobj;
+		goto retry;
+	}
+	up(domain->sem);
+	return NULL;
+}
+
+struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
+{
+	struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
+	struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL);
+	int i;
+
+	if ((p == NULL) || (base == NULL)) {
+		kfree(p);
+		kfree(base);
+		return NULL;
+	}
+
+	memset(base, 0, sizeof(struct probe));
+	base->dev = 1;
+	base->range = ~0;
+	base->get = base_probe;
+	for (i = 0; i < 255; i++)
+		p->probes[i] = base;
+	p->sem = sem;
+	return p;
+}
diff --git a/drivers/base/node.c b/drivers/base/node.c
new file mode 100644
index 0000000..583d57e
--- /dev/null
+++ b/drivers/base/node.c
@@ -0,0 +1,161 @@
+/*
+ * drivers/base/node.c - basic Node class support
+ */
+
+#include <linux/sysdev.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/node.h>
+#include <linux/hugetlb.h>
+#include <linux/cpumask.h>
+#include <linux/topology.h>
+#include <linux/nodemask.h>
+
+static struct sysdev_class node_class = {
+	set_kset_name("node"),
+};
+
+
+static ssize_t node_read_cpumap(struct sys_device * dev, char * buf)
+{
+	struct node *node_dev = to_node(dev);
+	cpumask_t mask = node_to_cpumask(node_dev->sysdev.id);
+	int len;
+
+	/* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */
+	BUILD_BUG_ON(MAX_NUMNODES/4 > PAGE_SIZE/2);
+
+	len = cpumask_scnprintf(buf, PAGE_SIZE-1, mask);
+	len += sprintf(buf + len, "\n");
+	return len;
+}
+
+static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumap, NULL);
+
+#define K(x) ((x) << (PAGE_SHIFT - 10))
+static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
+{
+	int n;
+	int nid = dev->id;
+	struct sysinfo i;
+	unsigned long inactive;
+	unsigned long active;
+	unsigned long free;
+
+	si_meminfo_node(&i, nid);
+	__get_zone_counts(&active, &inactive, &free, NODE_DATA(nid));
+
+	n = sprintf(buf, "\n"
+		       "Node %d MemTotal:     %8lu kB\n"
+		       "Node %d MemFree:      %8lu kB\n"
+		       "Node %d MemUsed:      %8lu kB\n"
+		       "Node %d Active:       %8lu kB\n"
+		       "Node %d Inactive:     %8lu kB\n"
+		       "Node %d HighTotal:    %8lu kB\n"
+		       "Node %d HighFree:     %8lu kB\n"
+		       "Node %d LowTotal:     %8lu kB\n"
+		       "Node %d LowFree:      %8lu kB\n",
+		       nid, K(i.totalram),
+		       nid, K(i.freeram),
+		       nid, K(i.totalram - i.freeram),
+		       nid, K(active),
+		       nid, K(inactive),
+		       nid, K(i.totalhigh),
+		       nid, K(i.freehigh),
+		       nid, K(i.totalram - i.totalhigh),
+		       nid, K(i.freeram - i.freehigh));
+	n += hugetlb_report_node_meminfo(nid, buf + n);
+	return n;
+}
+
+#undef K
+static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);
+
+static ssize_t node_read_numastat(struct sys_device * dev, char * buf)
+{
+	unsigned long numa_hit, numa_miss, interleave_hit, numa_foreign;
+	unsigned long local_node, other_node;
+	int i, cpu;
+	pg_data_t *pg = NODE_DATA(dev->id);
+	numa_hit = 0;
+	numa_miss = 0;
+	interleave_hit = 0;
+	numa_foreign = 0;
+	local_node = 0;
+	other_node = 0;
+	for (i = 0; i < MAX_NR_ZONES; i++) {
+		struct zone *z = &pg->node_zones[i];
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			struct per_cpu_pageset *ps = &z->pageset[cpu];
+			numa_hit += ps->numa_hit;
+			numa_miss += ps->numa_miss;
+			numa_foreign += ps->numa_foreign;
+			interleave_hit += ps->interleave_hit;
+			local_node += ps->local_node;
+			other_node += ps->other_node;
+		}
+	}
+	return sprintf(buf,
+		       "numa_hit %lu\n"
+		       "numa_miss %lu\n"
+		       "numa_foreign %lu\n"
+		       "interleave_hit %lu\n"
+		       "local_node %lu\n"
+		       "other_node %lu\n",
+		       numa_hit,
+		       numa_miss,
+		       numa_foreign,
+		       interleave_hit,
+		       local_node,
+		       other_node);
+}
+static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
+
+static ssize_t node_read_distance(struct sys_device * dev, char * buf)
+{
+	int nid = dev->id;
+	int len = 0;
+	int i;
+
+	/* buf currently PAGE_SIZE, need ~4 chars per node */
+	BUILD_BUG_ON(MAX_NUMNODES*4 > PAGE_SIZE/2);
+
+	for_each_online_node(i)
+		len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i));
+
+	len += sprintf(buf + len, "\n");
+	return len;
+}
+static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
+
+
+/*
+ * register_node - Setup a driverfs device for a node.
+ * @num - Node number to use when creating the device.
+ *
+ * Initialize and register the node device.
+ */
+int __init register_node(struct node *node, int num, struct node *parent)
+{
+	int error;
+
+	node->sysdev.id = num;
+	node->sysdev.cls = &node_class;
+	error = sysdev_register(&node->sysdev);
+
+	if (!error){
+		sysdev_create_file(&node->sysdev, &attr_cpumap);
+		sysdev_create_file(&node->sysdev, &attr_meminfo);
+		sysdev_create_file(&node->sysdev, &attr_numastat);
+		sysdev_create_file(&node->sysdev, &attr_distance);
+	}
+	return error;
+}
+
+
+int __init register_node_type(void)
+{
+	return sysdev_class_register(&node_class);
+}
+postcore_initcall(register_node_type);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
new file mode 100644
index 0000000..996cbb4
--- /dev/null
+++ b/drivers/base/platform.c
@@ -0,0 +1,350 @@
+/*
+ * platform.c - platform 'pseudo' bus for legacy devices
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ * Please see Documentation/driver-model/platform.txt for more
+ * information.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/bootmem.h>
+#include <linux/err.h>
+
+struct device platform_bus = {
+	.bus_id		= "platform",
+};
+
+/**
+ *	platform_get_resource - get a resource for a device
+ *	@dev: platform device
+ *	@type: resource type
+ *	@num: resource index
+ */
+struct resource *
+platform_get_resource(struct platform_device *dev, unsigned int type,
+		      unsigned int num)
+{
+	int i;
+
+	for (i = 0; i < dev->num_resources; i++) {
+		struct resource *r = &dev->resource[i];
+
+		if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
+				 IORESOURCE_IRQ|IORESOURCE_DMA))
+		    == type)
+			if (num-- == 0)
+				return r;
+	}
+	return NULL;
+}
+
+/**
+ *	platform_get_irq - get an IRQ for a device
+ *	@dev: platform device
+ *	@num: IRQ number index
+ */
+int platform_get_irq(struct platform_device *dev, unsigned int num)
+{
+	struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
+
+	return r ? r->start : 0;
+}
+
+/**
+ *	platform_get_resource_byname - get a resource for a device by name
+ *	@dev: platform device
+ *	@type: resource type
+ *	@name: resource name
+ */
+struct resource *
+platform_get_resource_byname(struct platform_device *dev, unsigned int type,
+		      char *name)
+{
+	int i;
+
+	for (i = 0; i < dev->num_resources; i++) {
+		struct resource *r = &dev->resource[i];
+
+		if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
+				 IORESOURCE_IRQ|IORESOURCE_DMA)) == type)
+			if (!strcmp(r->name, name))
+				return r;
+	}
+	return NULL;
+}
+
+/**
+ *	platform_get_irq - get an IRQ for a device
+ *	@dev: platform device
+ *	@name: IRQ name
+ */
+int platform_get_irq_byname(struct platform_device *dev, char *name)
+{
+	struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
+
+	return r ? r->start : 0;
+}
+
+/**
+ *	platform_add_devices - add a numbers of platform devices
+ *	@devs: array of platform devices to add
+ *	@num: number of platform devices in array
+ */
+int platform_add_devices(struct platform_device **devs, int num)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < num; i++) {
+		ret = platform_device_register(devs[i]);
+		if (ret) {
+			while (--i >= 0)
+				platform_device_unregister(devs[i]);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ *	platform_device_register - add a platform-level device
+ *	@dev:	platform device we're adding
+ *
+ */
+int platform_device_register(struct platform_device * pdev)
+{
+	int i, ret = 0;
+
+	if (!pdev)
+		return -EINVAL;
+
+	if (!pdev->dev.parent)
+		pdev->dev.parent = &platform_bus;
+
+	pdev->dev.bus = &platform_bus_type;
+
+	if (pdev->id != -1)
+		snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
+	else
+		strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
+
+	for (i = 0; i < pdev->num_resources; i++) {
+		struct resource *p, *r = &pdev->resource[i];
+
+		if (r->name == NULL)
+			r->name = pdev->dev.bus_id;
+
+		p = r->parent;
+		if (!p) {
+			if (r->flags & IORESOURCE_MEM)
+				p = &iomem_resource;
+			else if (r->flags & IORESOURCE_IO)
+				p = &ioport_resource;
+		}
+
+		if (p && request_resource(p, r)) {
+			printk(KERN_ERR
+			       "%s: failed to claim resource %d\n",
+			       pdev->dev.bus_id, i);
+			ret = -EBUSY;
+			goto failed;
+		}
+	}
+
+	pr_debug("Registering platform device '%s'. Parent at %s\n",
+		 pdev->dev.bus_id, pdev->dev.parent->bus_id);
+
+	ret = device_register(&pdev->dev);
+	if (ret == 0)
+		return ret;
+
+ failed:
+	while (--i >= 0)
+		if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
+			release_resource(&pdev->resource[i]);
+	return ret;
+}
+
+/**
+ *	platform_device_unregister - remove a platform-level device
+ *	@dev:	platform device we're removing
+ *
+ *	Note that this function will also release all memory- and port-based
+ *	resources owned by the device (@dev->resource).
+ */
+void platform_device_unregister(struct platform_device * pdev)
+{
+	int i;
+
+	if (pdev) {
+		for (i = 0; i < pdev->num_resources; i++) {
+			struct resource *r = &pdev->resource[i];
+			if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO))
+				release_resource(r);
+		}
+
+		device_unregister(&pdev->dev);
+	}
+}
+
+struct platform_object {
+        struct platform_device pdev;
+        struct resource resources[0];
+};
+
+static void platform_device_release_simple(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	kfree(container_of(pdev, struct platform_object, pdev));
+}
+
+/**
+ *	platform_device_register_simple
+ *	@name:  base name of the device we're adding
+ *	@id:    instance id
+ *	@res:   set of resources that needs to be allocated for the device
+ *	@num:	number of resources
+ *
+ *	This function creates a simple platform device that requires minimal
+ *	resource and memory management. Canned release function freeing
+ *	memory allocated for the device allows drivers using such devices
+ *	to be unloaded iwithout waiting for the last reference to the device
+ *	to be dropped.
+ */
+struct platform_device *platform_device_register_simple(char *name, unsigned int id,
+							struct resource *res, unsigned int num)
+{
+	struct platform_object *pobj;
+	int retval;
+
+	pobj = kmalloc(sizeof(struct platform_object) + sizeof(struct resource) * num, GFP_KERNEL);
+	if (!pobj) {
+		retval = -ENOMEM;
+		goto error;
+	}
+
+	memset(pobj, 0, sizeof(*pobj));
+	pobj->pdev.name = name;
+	pobj->pdev.id = id;
+	pobj->pdev.dev.release = platform_device_release_simple;
+
+	if (num) {
+		memcpy(pobj->resources, res, sizeof(struct resource) * num);
+		pobj->pdev.resource = pobj->resources;
+		pobj->pdev.num_resources = num;
+	}
+
+	retval = platform_device_register(&pobj->pdev);
+	if (retval)
+		goto error;
+
+	return &pobj->pdev;
+
+error:
+	kfree(pobj);
+	return ERR_PTR(retval);
+}
+
+
+/**
+ *	platform_match - bind platform device to platform driver.
+ *	@dev:	device.
+ *	@drv:	driver.
+ *
+ *	Platform device IDs are assumed to be encoded like this:
+ *	"<name><instance>", where <name> is a short description of the
+ *	type of device, like "pci" or "floppy", and <instance> is the
+ *	enumerated instance of the device, like '0' or '42'.
+ *	Driver IDs are simply "<name>".
+ *	So, extract the <name> from the platform_device structure,
+ *	and compare it against the name of the driver. Return whether
+ *	they match or not.
+ */
+
+static int platform_match(struct device * dev, struct device_driver * drv)
+{
+	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+
+	return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
+}
+
+static int platform_suspend(struct device * dev, pm_message_t state)
+{
+	int ret = 0;
+
+	if (dev->driver && dev->driver->suspend) {
+		ret = dev->driver->suspend(dev, state, SUSPEND_DISABLE);
+		if (ret == 0)
+			ret = dev->driver->suspend(dev, state, SUSPEND_SAVE_STATE);
+		if (ret == 0)
+			ret = dev->driver->suspend(dev, state, SUSPEND_POWER_DOWN);
+	}
+	return ret;
+}
+
+static int platform_resume(struct device * dev)
+{
+	int ret = 0;
+
+	if (dev->driver && dev->driver->resume) {
+		ret = dev->driver->resume(dev, RESUME_POWER_ON);
+		if (ret == 0)
+			ret = dev->driver->resume(dev, RESUME_RESTORE_STATE);
+		if (ret == 0)
+			ret = dev->driver->resume(dev, RESUME_ENABLE);
+	}
+	return ret;
+}
+
+struct bus_type platform_bus_type = {
+	.name		= "platform",
+	.match		= platform_match,
+	.suspend	= platform_suspend,
+	.resume		= platform_resume,
+};
+
+int __init platform_bus_init(void)
+{
+	device_register(&platform_bus);
+	return bus_register(&platform_bus_type);
+}
+
+#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
+u64 dma_get_required_mask(struct device *dev)
+{
+	u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
+	u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
+	u64 mask;
+
+	if (!high_totalram) {
+		/* convert to mask just covering totalram */
+		low_totalram = (1 << (fls(low_totalram) - 1));
+		low_totalram += low_totalram - 1;
+		mask = low_totalram;
+	} else {
+		high_totalram = (1 << (fls(high_totalram) - 1));
+		high_totalram += high_totalram - 1;
+		mask = (((u64)high_totalram) << 32) + 0xffffffff;
+	}
+	return mask & *dev->dma_mask;
+}
+EXPORT_SYMBOL_GPL(dma_get_required_mask);
+#endif
+
+EXPORT_SYMBOL_GPL(platform_bus);
+EXPORT_SYMBOL_GPL(platform_bus_type);
+EXPORT_SYMBOL_GPL(platform_device_register);
+EXPORT_SYMBOL_GPL(platform_device_register_simple);
+EXPORT_SYMBOL_GPL(platform_device_unregister);
+EXPORT_SYMBOL_GPL(platform_get_irq);
+EXPORT_SYMBOL_GPL(platform_get_resource);
+EXPORT_SYMBOL_GPL(platform_get_irq_byname);
+EXPORT_SYMBOL_GPL(platform_get_resource_byname);
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
new file mode 100644
index 0000000..c0219ad
--- /dev/null
+++ b/drivers/base/power/Makefile
@@ -0,0 +1,6 @@
+obj-y			:= shutdown.o
+obj-$(CONFIG_PM)	+= main.o suspend.o resume.o runtime.o sysfs.o
+
+ifeq ($(CONFIG_DEBUG_DRIVER),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
new file mode 100644
index 0000000..15e6a8f
--- /dev/null
+++ b/drivers/base/power/main.c
@@ -0,0 +1,99 @@
+/*
+ * drivers/base/power/main.c - Where the driver meets power management.
+ *
+ * Copyright (c) 2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Lab
+ *
+ * This file is released under the GPLv2
+ *
+ *
+ * The driver model core calls device_pm_add() when a device is registered.
+ * This will intialize the embedded device_pm_info object in the device
+ * and add it to the list of power-controlled devices. sysfs entries for
+ * controlling device power management will also be added.
+ *
+ * A different set of lists than the global subsystem list are used to
+ * keep track of power info because we use different lists to hold
+ * devices based on what stage of the power management process they
+ * are in. The power domain dependencies may also differ from the
+ * ancestral dependencies that the subsystem list maintains.
+ */
+
+#include <linux/config.h>
+#include <linux/device.h>
+#include "power.h"
+
+LIST_HEAD(dpm_active);
+LIST_HEAD(dpm_off);
+LIST_HEAD(dpm_off_irq);
+
+DECLARE_MUTEX(dpm_sem);
+DECLARE_MUTEX(dpm_list_sem);
+
+/*
+ * PM Reference Counting.
+ */
+
+static inline void device_pm_hold(struct device * dev)
+{
+	if (dev)
+		atomic_inc(&dev->power.pm_users);
+}
+
+static inline void device_pm_release(struct device * dev)
+{
+	if (dev)
+		atomic_dec(&dev->power.pm_users);
+}
+
+
+/**
+ *	device_pm_set_parent - Specify power dependency.
+ *	@dev:		Device who needs power.
+ *	@parent:	Device that supplies power.
+ *
+ *	This function is used to manually describe a power-dependency
+ *	relationship. It may be used to specify a transversal relationship
+ *	(where the power supplier is not the physical (or electrical)
+ *	ancestor of a specific device.
+ *	The effect of this is that the supplier will not be powered down
+ *	before the power dependent.
+ */
+
+void device_pm_set_parent(struct device * dev, struct device * parent)
+{
+	struct device * old_parent = dev->power.pm_parent;
+	device_pm_release(old_parent);
+	dev->power.pm_parent = parent;
+	device_pm_hold(parent);
+}
+EXPORT_SYMBOL_GPL(device_pm_set_parent);
+
+int device_pm_add(struct device * dev)
+{
+	int error;
+
+	pr_debug("PM: Adding info for %s:%s\n",
+		 dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
+	atomic_set(&dev->power.pm_users, 0);
+	down(&dpm_list_sem);
+	list_add_tail(&dev->power.entry, &dpm_active);
+	device_pm_set_parent(dev, dev->parent);
+	if ((error = dpm_sysfs_add(dev)))
+		list_del(&dev->power.entry);
+	up(&dpm_list_sem);
+	return error;
+}
+
+void device_pm_remove(struct device * dev)
+{
+	pr_debug("PM: Removing info for %s:%s\n",
+		 dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
+	down(&dpm_list_sem);
+	dpm_sysfs_remove(dev);
+	device_pm_release(dev->power.pm_parent);
+	list_del_init(&dev->power.entry);
+	up(&dpm_list_sem);
+}
+
+
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
new file mode 100644
index 0000000..e5eda74
--- /dev/null
+++ b/drivers/base/power/power.h
@@ -0,0 +1,106 @@
+
+
+enum {
+	DEVICE_PM_ON,
+	DEVICE_PM1,
+	DEVICE_PM2,
+	DEVICE_PM3,
+	DEVICE_PM_OFF,
+};
+
+/*
+ * shutdown.c
+ */
+
+extern int device_detach_shutdown(struct device *);
+extern void device_shutdown(void);
+
+
+#ifdef CONFIG_PM
+
+/*
+ * main.c
+ */
+
+/*
+ * Used to synchronize global power management operations.
+ */
+extern struct semaphore dpm_sem;
+
+/*
+ * Used to serialize changes to the dpm_* lists.
+ */
+extern struct semaphore dpm_list_sem;
+
+/*
+ * The PM lists.
+ */
+extern struct list_head dpm_active;
+extern struct list_head dpm_off;
+extern struct list_head dpm_off_irq;
+
+
+static inline struct dev_pm_info * to_pm_info(struct list_head * entry)
+{
+	return container_of(entry, struct dev_pm_info, entry);
+}
+
+static inline struct device * to_device(struct list_head * entry)
+{
+	return container_of(to_pm_info(entry), struct device, power);
+}
+
+extern int device_pm_add(struct device *);
+extern void device_pm_remove(struct device *);
+
+/*
+ * sysfs.c
+ */
+
+extern int dpm_sysfs_add(struct device *);
+extern void dpm_sysfs_remove(struct device *);
+
+/*
+ * resume.c
+ */
+
+extern void dpm_resume(void);
+extern void dpm_power_up(void);
+extern int resume_device(struct device *);
+
+/*
+ * suspend.c
+ */
+extern int suspend_device(struct device *, pm_message_t);
+
+
+/*
+ * runtime.c
+ */
+
+extern int dpm_runtime_suspend(struct device *, pm_message_t);
+extern void dpm_runtime_resume(struct device *);
+
+#else /* CONFIG_PM */
+
+
+static inline int device_pm_add(struct device * dev)
+{
+	return 0;
+}
+static inline void device_pm_remove(struct device * dev)
+{
+
+}
+
+static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state)
+{
+	return 0;
+}
+
+static inline void dpm_runtime_resume(struct device * dev)
+{
+
+}
+
+#endif
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
new file mode 100644
index 0000000..f8f5055
--- /dev/null
+++ b/drivers/base/power/resume.c
@@ -0,0 +1,112 @@
+/*
+ * resume.c - Functions for waking devices up.
+ *
+ * Copyright (c) 2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/device.h>
+#include "power.h"
+
+extern int sysdev_resume(void);
+
+
+/**
+ *	resume_device - Restore state for one device.
+ *	@dev:	Device.
+ *
+ */
+
+int resume_device(struct device * dev)
+{
+	if (dev->bus && dev->bus->resume)
+		return dev->bus->resume(dev);
+	return 0;
+}
+
+
+
+void dpm_resume(void)
+{
+	down(&dpm_list_sem);
+	while(!list_empty(&dpm_off)) {
+		struct list_head * entry = dpm_off.next;
+		struct device * dev = to_device(entry);
+
+		get_device(dev);
+		list_del_init(entry);
+		list_add_tail(entry, &dpm_active);
+
+		up(&dpm_list_sem);
+		if (!dev->power.prev_state)
+			resume_device(dev);
+		down(&dpm_list_sem);
+		put_device(dev);
+	}
+	up(&dpm_list_sem);
+}
+
+
+/**
+ *	device_resume - Restore state of each device in system.
+ *
+ *	Walk the dpm_off list, remove each entry, resume the device,
+ *	then add it to the dpm_active list.
+ */
+
+void device_resume(void)
+{
+	down(&dpm_sem);
+	dpm_resume();
+	up(&dpm_sem);
+}
+
+EXPORT_SYMBOL_GPL(device_resume);
+
+
+/**
+ *	device_power_up_irq - Power on some devices.
+ *
+ *	Walk the dpm_off_irq list and power each device up. This
+ *	is used for devices that required they be powered down with
+ *	interrupts disabled. As devices are powered on, they are moved to
+ *	the dpm_suspended list.
+ *
+ *	Interrupts must be disabled when calling this.
+ */
+
+void dpm_power_up(void)
+{
+	while(!list_empty(&dpm_off_irq)) {
+		struct list_head * entry = dpm_off_irq.next;
+		struct device * dev = to_device(entry);
+
+		get_device(dev);
+		list_del_init(entry);
+		list_add_tail(entry, &dpm_active);
+		resume_device(dev);
+		put_device(dev);
+	}
+}
+
+
+/**
+ *	device_pm_power_up - Turn on all devices that need special attention.
+ *
+ *	Power on system devices then devices that required we shut them down
+ *	with interrupts disabled.
+ *	Called with interrupts disabled.
+ */
+
+void device_power_up(void)
+{
+	sysdev_resume();
+	dpm_power_up();
+}
+
+EXPORT_SYMBOL_GPL(device_power_up);
+
+
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
new file mode 100644
index 0000000..325962d
--- /dev/null
+++ b/drivers/base/power/runtime.c
@@ -0,0 +1,81 @@
+/*
+ * drivers/base/power/runtime.c - Handling dynamic device power management.
+ *
+ * Copyright (c) 2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Lab
+ *
+ */
+
+#include <linux/device.h>
+#include "power.h"
+
+
+static void runtime_resume(struct device * dev)
+{
+	dev_dbg(dev, "resuming\n");
+	if (!dev->power.power_state)
+		return;
+	if (!resume_device(dev))
+		dev->power.power_state = 0;
+}
+
+
+/**
+ *	dpm_runtime_resume - Power one device back on.
+ *	@dev:	Device.
+ *
+ *	Bring one device back to the on state by first powering it
+ *	on, then restoring state. We only operate on devices that aren't
+ *	already on.
+ *	FIXME: We need to handle devices that are in an unknown state.
+ */
+
+void dpm_runtime_resume(struct device * dev)
+{
+	down(&dpm_sem);
+	runtime_resume(dev);
+	up(&dpm_sem);
+}
+
+
+/**
+ *	dpm_runtime_suspend - Put one device in low-power state.
+ *	@dev:	Device.
+ *	@state:	State to enter.
+ */
+
+int dpm_runtime_suspend(struct device * dev, pm_message_t state)
+{
+	int error = 0;
+
+	down(&dpm_sem);
+	if (dev->power.power_state == state)
+		goto Done;
+
+	if (dev->power.power_state)
+		runtime_resume(dev);
+
+	if (!(error = suspend_device(dev, state)))
+		dev->power.power_state = state;
+ Done:
+	up(&dpm_sem);
+	return error;
+}
+
+
+/**
+ *	dpm_set_power_state - Update power_state field.
+ *	@dev:	Device.
+ *	@state:	Power state device is in.
+ *
+ *	This is an update mechanism for drivers to notify the core
+ *	what power state a device is in. Device probing code may not
+ *	always be able to tell, but we need accurate information to
+ *	work reliably.
+ */
+void dpm_set_power_state(struct device * dev, pm_message_t state)
+{
+	down(&dpm_sem);
+	dev->power.power_state = state;
+	up(&dpm_sem);
+}
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
new file mode 100644
index 0000000..d1e023f
--- /dev/null
+++ b/drivers/base/power/shutdown.c
@@ -0,0 +1,67 @@
+/*
+ * shutdown.c - power management functions for the device tree.
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ *		 2002-3 Open Source Development Lab
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/device.h>
+#include <asm/semaphore.h>
+
+#include "power.h"
+
+#define to_dev(node) container_of(node, struct device, kobj.entry)
+
+extern struct subsystem devices_subsys;
+
+
+int device_detach_shutdown(struct device * dev)
+{
+	if (!dev->detach_state)
+		return 0;
+
+	if (dev->detach_state == DEVICE_PM_OFF) {
+		if (dev->driver && dev->driver->shutdown)
+			dev->driver->shutdown(dev);
+		return 0;
+	}
+	return dpm_runtime_suspend(dev, dev->detach_state);
+}
+
+
+/**
+ * We handle system devices differently - we suspend and shut them
+ * down last and resume them first. That way, we don't do anything stupid like
+ * shutting down the interrupt controller before any devices..
+ *
+ * Note that there are not different stages for power management calls -
+ * they only get one called once when interrupts are disabled.
+ */
+
+extern int sysdev_shutdown(void);
+
+/**
+ * device_shutdown - call ->shutdown() on each device to shutdown.
+ */
+void device_shutdown(void)
+{
+	struct device * dev;
+
+	down_write(&devices_subsys.rwsem);
+	list_for_each_entry_reverse(dev, &devices_subsys.kset.list, kobj.entry) {
+		pr_debug("shutting down %s: ", dev->bus_id);
+		if (dev->driver && dev->driver->shutdown) {
+			pr_debug("Ok\n");
+			dev->driver->shutdown(dev);
+		} else
+			pr_debug("Ignored.\n");
+	}
+	up_write(&devices_subsys.rwsem);
+
+	sysdev_shutdown();
+}
+
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
new file mode 100644
index 0000000..a0b5cf6
--- /dev/null
+++ b/drivers/base/power/suspend.c
@@ -0,0 +1,144 @@
+/*
+ * suspend.c - Functions for putting devices to sleep.
+ *
+ * Copyright (c) 2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Labs
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/device.h>
+#include "power.h"
+
+extern int sysdev_suspend(pm_message_t state);
+
+/*
+ * The entries in the dpm_active list are in a depth first order, simply
+ * because children are guaranteed to be discovered after parents, and
+ * are inserted at the back of the list on discovery.
+ *
+ * All list on the suspend path are done in reverse order, so we operate
+ * on the leaves of the device tree (or forests, depending on how you want
+ * to look at it ;) first. As nodes are removed from the back of the list,
+ * they are inserted into the front of their destintation lists.
+ *
+ * Things are the reverse on the resume path - iterations are done in
+ * forward order, and nodes are inserted at the back of their destination
+ * lists. This way, the ancestors will be accessed before their descendents.
+ */
+
+
+/**
+ *	suspend_device - Save state of one device.
+ *	@dev:	Device.
+ *	@state:	Power state device is entering.
+ */
+
+int suspend_device(struct device * dev, pm_message_t state)
+{
+	int error = 0;
+
+	dev_dbg(dev, "suspending\n");
+
+	dev->power.prev_state = dev->power.power_state;
+
+	if (dev->bus && dev->bus->suspend && !dev->power.power_state)
+		error = dev->bus->suspend(dev, state);
+
+	return error;
+}
+
+
+/**
+ *	device_suspend - Save state and stop all devices in system.
+ *	@state:		Power state to put each device in.
+ *
+ *	Walk the dpm_active list, call ->suspend() for each device, and move
+ *	it to dpm_off.
+ *	Check the return value for each. If it returns 0, then we move the
+ *	the device to the dpm_off list. If it returns -EAGAIN, we move it to
+ *	the dpm_off_irq list. If we get a different error, try and back out.
+ *
+ *	If we hit a failure with any of the devices, call device_resume()
+ *	above to bring the suspended devices back to life.
+ *
+ */
+
+int device_suspend(pm_message_t state)
+{
+	int error = 0;
+
+	down(&dpm_sem);
+	down(&dpm_list_sem);
+	while (!list_empty(&dpm_active) && error == 0) {
+		struct list_head * entry = dpm_active.prev;
+		struct device * dev = to_device(entry);
+
+		get_device(dev);
+		up(&dpm_list_sem);
+
+		error = suspend_device(dev, state);
+
+		down(&dpm_list_sem);
+
+		/* Check if the device got removed */
+		if (!list_empty(&dev->power.entry)) {
+			/* Move it to the dpm_off or dpm_off_irq list */
+			if (!error) {
+				list_del(&dev->power.entry);
+				list_add(&dev->power.entry, &dpm_off);
+			} else if (error == -EAGAIN) {
+				list_del(&dev->power.entry);
+				list_add(&dev->power.entry, &dpm_off_irq);
+				error = 0;
+			}
+		}
+		if (error)
+			printk(KERN_ERR "Could not suspend device %s: "
+				"error %d\n", kobject_name(&dev->kobj), error);
+		put_device(dev);
+	}
+	up(&dpm_list_sem);
+	if (error)
+		dpm_resume();
+	up(&dpm_sem);
+	return error;
+}
+
+EXPORT_SYMBOL_GPL(device_suspend);
+
+
+/**
+ *	device_power_down - Shut down special devices.
+ *	@state:		Power state to enter.
+ *
+ *	Walk the dpm_off_irq list, calling ->power_down() for each device that
+ *	couldn't power down the device with interrupts enabled. When we're
+ *	done, power down system devices.
+ */
+
+int device_power_down(pm_message_t state)
+{
+	int error = 0;
+	struct device * dev;
+
+	list_for_each_entry_reverse(dev, &dpm_off_irq, power.entry) {
+		if ((error = suspend_device(dev, state)))
+			break;
+	}
+	if (error)
+		goto Error;
+	if ((error = sysdev_suspend(state)))
+		goto Error;
+ Done:
+	return error;
+ Error:
+	printk(KERN_ERR "Could not power down device %s: "
+		"error %d\n", kobject_name(&dev->kobj), error);
+	dpm_power_up();
+	goto Done;
+}
+
+EXPORT_SYMBOL_GPL(device_power_down);
+
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
new file mode 100644
index 0000000..6ac9634
--- /dev/null
+++ b/drivers/base/power/sysfs.c
@@ -0,0 +1,68 @@
+/*
+ * drivers/base/power/sysfs.c - sysfs entries for device PM
+ */
+
+#include <linux/device.h>
+#include "power.h"
+
+
+/**
+ *	state - Control current power state of device
+ *
+ *	show() returns the current power state of the device. '0' indicates
+ *	the device is on. Other values (1-3) indicate the device is in a low
+ *	power state.
+ *
+ *	store() sets the current power state, which is an integer value
+ *	between 0-3. If the device is on ('0'), and the value written is
+ *	greater than 0, then the device is placed directly into the low-power
+ *	state (via its driver's ->suspend() method).
+ *	If the device is currently in a low-power state, and the value is 0,
+ *	the device is powered back on (via the ->resume() method).
+ *	If the device is in a low-power state, and a different low-power state
+ *	is requested, the device is first resumed, then suspended into the new
+ *	low-power state.
+ */
+
+static ssize_t state_show(struct device * dev, char * buf)
+{
+	return sprintf(buf, "%u\n", dev->power.power_state);
+}
+
+static ssize_t state_store(struct device * dev, const char * buf, size_t n)
+{
+	u32 state;
+	char * rest;
+	int error = 0;
+
+	state = simple_strtoul(buf, &rest, 10);
+	if (*rest)
+		return -EINVAL;
+	if (state)
+		error = dpm_runtime_suspend(dev, state);
+	else
+		dpm_runtime_resume(dev);
+	return error ? error : n;
+}
+
+static DEVICE_ATTR(state, 0644, state_show, state_store);
+
+
+static struct attribute * power_attrs[] = {
+	&dev_attr_state.attr,
+	NULL,
+};
+static struct attribute_group pm_attr_group = {
+	.name	= "power",
+	.attrs	= power_attrs,
+};
+
+int dpm_sysfs_add(struct device * dev)
+{
+	return sysfs_create_group(&dev->kobj, &pm_attr_group);
+}
+
+void dpm_sysfs_remove(struct device * dev)
+{
+	sysfs_remove_group(&dev->kobj, &pm_attr_group);
+}
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
new file mode 100644
index 0000000..cff5a6a
--- /dev/null
+++ b/drivers/base/sys.c
@@ -0,0 +1,397 @@
+/*
+ * sys.c - pseudo-bus for system 'devices' (cpus, PICs, timers, etc)
+ *
+ * Copyright (c) 2002-3 Patrick Mochel
+ *               2002-3 Open Source Development Lab
+ *
+ * This file is released under the GPLv2
+ *
+ * This exports a 'system' bus type.
+ * By default, a 'sys' bus gets added to the root of the system. There will
+ * always be core system devices. Devices can use sysdev_register() to
+ * add themselves as children of the system bus.
+ */
+
+#include <linux/config.h>
+#include <linux/sysdev.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+
+extern struct subsystem devices_subsys;
+
+#define to_sysdev(k) container_of(k, struct sys_device, kobj)
+#define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr)
+
+
+static ssize_t
+sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
+{
+	struct sys_device * sysdev = to_sysdev(kobj);
+	struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
+
+	if (sysdev_attr->show)
+		return sysdev_attr->show(sysdev, buffer);
+	return 0;
+}
+
+
+static ssize_t
+sysdev_store(struct kobject * kobj, struct attribute * attr,
+	     const char * buffer, size_t count)
+{
+	struct sys_device * sysdev = to_sysdev(kobj);
+	struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
+
+	if (sysdev_attr->store)
+		return sysdev_attr->store(sysdev, buffer, count);
+	return 0;
+}
+
+static struct sysfs_ops sysfs_ops = {
+	.show	= sysdev_show,
+	.store	= sysdev_store,
+};
+
+static struct kobj_type ktype_sysdev = {
+	.sysfs_ops	= &sysfs_ops,
+};
+
+
+int sysdev_create_file(struct sys_device * s, struct sysdev_attribute * a)
+{
+	return sysfs_create_file(&s->kobj, &a->attr);
+}
+
+
+void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a)
+{
+	sysfs_remove_file(&s->kobj, &a->attr);
+}
+
+EXPORT_SYMBOL_GPL(sysdev_create_file);
+EXPORT_SYMBOL_GPL(sysdev_remove_file);
+
+/*
+ * declare system_subsys
+ */
+static decl_subsys(system, &ktype_sysdev, NULL);
+
+int sysdev_class_register(struct sysdev_class * cls)
+{
+	pr_debug("Registering sysdev class '%s'\n",
+		 kobject_name(&cls->kset.kobj));
+	INIT_LIST_HEAD(&cls->drivers);
+	cls->kset.subsys = &system_subsys;
+	kset_set_kset_s(cls, system_subsys);
+	return kset_register(&cls->kset);
+}
+
+void sysdev_class_unregister(struct sysdev_class * cls)
+{
+	pr_debug("Unregistering sysdev class '%s'\n",
+		 kobject_name(&cls->kset.kobj));
+	kset_unregister(&cls->kset);
+}
+
+EXPORT_SYMBOL_GPL(sysdev_class_register);
+EXPORT_SYMBOL_GPL(sysdev_class_unregister);
+
+
+static LIST_HEAD(sysdev_drivers);
+static DECLARE_MUTEX(sysdev_drivers_lock);
+
+/**
+ *	sysdev_driver_register - Register auxillary driver
+ * 	@cls:	Device class driver belongs to.
+ *	@drv:	Driver.
+ *
+ *	If @cls is valid, then @drv is inserted into @cls->drivers to be
+ *	called on each operation on devices of that class. The refcount
+ *	of @cls is incremented.
+ *	Otherwise, @drv is inserted into sysdev_drivers, and called for
+ *	each device.
+ */
+
+int sysdev_driver_register(struct sysdev_class * cls,
+			   struct sysdev_driver * drv)
+{
+	down(&sysdev_drivers_lock);
+	if (cls && kset_get(&cls->kset)) {
+		list_add_tail(&drv->entry, &cls->drivers);
+
+		/* If devices of this class already exist, tell the driver */
+		if (drv->add) {
+			struct sys_device *dev;
+			list_for_each_entry(dev, &cls->kset.list, kobj.entry)
+				drv->add(dev);
+		}
+	} else
+		list_add_tail(&drv->entry, &sysdev_drivers);
+	up(&sysdev_drivers_lock);
+	return 0;
+}
+
+
+/**
+ *	sysdev_driver_unregister - Remove an auxillary driver.
+ *	@cls:	Class driver belongs to.
+ *	@drv:	Driver.
+ */
+void sysdev_driver_unregister(struct sysdev_class * cls,
+			      struct sysdev_driver * drv)
+{
+	down(&sysdev_drivers_lock);
+	list_del_init(&drv->entry);
+	if (cls) {
+		if (drv->remove) {
+			struct sys_device *dev;
+			list_for_each_entry(dev, &cls->kset.list, kobj.entry)
+				drv->remove(dev);
+		}
+		kset_put(&cls->kset);
+	}
+	up(&sysdev_drivers_lock);
+}
+
+EXPORT_SYMBOL_GPL(sysdev_driver_register);
+EXPORT_SYMBOL_GPL(sysdev_driver_unregister);
+
+
+
+/**
+ *	sysdev_register - add a system device to the tree
+ *	@sysdev:	device in question
+ *
+ */
+int sysdev_register(struct sys_device * sysdev)
+{
+	int error;
+	struct sysdev_class * cls = sysdev->cls;
+
+	if (!cls)
+		return -EINVAL;
+
+	/* Make sure the kset is set */
+	sysdev->kobj.kset = &cls->kset;
+
+	/* But make sure we point to the right type for sysfs translation */
+	sysdev->kobj.ktype = &ktype_sysdev;
+	error = kobject_set_name(&sysdev->kobj, "%s%d",
+			 kobject_name(&cls->kset.kobj), sysdev->id);
+	if (error)
+		return error;
+
+	pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
+
+	/* Register the object */
+	error = kobject_register(&sysdev->kobj);
+
+	if (!error) {
+		struct sysdev_driver * drv;
+
+		down(&sysdev_drivers_lock);
+		/* Generic notification is implicit, because it's that
+		 * code that should have called us.
+		 */
+
+		/* Notify global drivers */
+		list_for_each_entry(drv, &sysdev_drivers, entry) {
+			if (drv->add)
+				drv->add(sysdev);
+		}
+
+		/* Notify class auxillary drivers */
+		list_for_each_entry(drv, &cls->drivers, entry) {
+			if (drv->add)
+				drv->add(sysdev);
+		}
+		up(&sysdev_drivers_lock);
+	}
+	return error;
+}
+
+void sysdev_unregister(struct sys_device * sysdev)
+{
+	struct sysdev_driver * drv;
+
+	down(&sysdev_drivers_lock);
+	list_for_each_entry(drv, &sysdev_drivers, entry) {
+		if (drv->remove)
+			drv->remove(sysdev);
+	}
+
+	list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
+		if (drv->remove)
+			drv->remove(sysdev);
+	}
+	up(&sysdev_drivers_lock);
+
+	kobject_unregister(&sysdev->kobj);
+}
+
+
+
+/**
+ *	sysdev_shutdown - Shut down all system devices.
+ *
+ *	Loop over each class of system devices, and the devices in each
+ *	of those classes. For each device, we call the shutdown method for
+ *	each driver registered for the device - the globals, the auxillaries,
+ *	and the class driver.
+ *
+ *	Note: The list is iterated in reverse order, so that we shut down
+ *	child devices before we shut down thier parents. The list ordering
+ *	is guaranteed by virtue of the fact that child devices are registered
+ *	after their parents.
+ */
+
+void sysdev_shutdown(void)
+{
+	struct sysdev_class * cls;
+
+	pr_debug("Shutting Down System Devices\n");
+
+	down(&sysdev_drivers_lock);
+	list_for_each_entry_reverse(cls, &system_subsys.kset.list,
+				    kset.kobj.entry) {
+		struct sys_device * sysdev;
+
+		pr_debug("Shutting down type '%s':\n",
+			 kobject_name(&cls->kset.kobj));
+
+		list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
+			struct sysdev_driver * drv;
+			pr_debug(" %s\n", kobject_name(&sysdev->kobj));
+
+			/* Call global drivers first. */
+			list_for_each_entry(drv, &sysdev_drivers, entry) {
+				if (drv->shutdown)
+					drv->shutdown(sysdev);
+			}
+
+			/* Call auxillary drivers next. */
+			list_for_each_entry(drv, &cls->drivers, entry) {
+				if (drv->shutdown)
+					drv->shutdown(sysdev);
+			}
+
+			/* Now call the generic one */
+			if (cls->shutdown)
+				cls->shutdown(sysdev);
+		}
+	}
+	up(&sysdev_drivers_lock);
+}
+
+
+/**
+ *	sysdev_suspend - Suspend all system devices.
+ *	@state:		Power state to enter.
+ *
+ *	We perform an almost identical operation as sys_device_shutdown()
+ *	above, though calling ->suspend() instead. Interrupts are disabled
+ *	when this called. Devices are responsible for both saving state and
+ *	quiescing or powering down the device.
+ *
+ *	This is only called by the device PM core, so we let them handle
+ *	all synchronization.
+ */
+
+int sysdev_suspend(u32 state)
+{
+	struct sysdev_class * cls;
+
+	pr_debug("Suspending System Devices\n");
+
+	list_for_each_entry_reverse(cls, &system_subsys.kset.list,
+				    kset.kobj.entry) {
+		struct sys_device * sysdev;
+
+		pr_debug("Suspending type '%s':\n",
+			 kobject_name(&cls->kset.kobj));
+
+		list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
+			struct sysdev_driver * drv;
+			pr_debug(" %s\n", kobject_name(&sysdev->kobj));
+
+			/* Call global drivers first. */
+			list_for_each_entry(drv, &sysdev_drivers, entry) {
+				if (drv->suspend)
+					drv->suspend(sysdev, state);
+			}
+
+			/* Call auxillary drivers next. */
+			list_for_each_entry(drv, &cls->drivers, entry) {
+				if (drv->suspend)
+					drv->suspend(sysdev, state);
+			}
+
+			/* Now call the generic one */
+			if (cls->suspend)
+				cls->suspend(sysdev, state);
+		}
+	}
+	return 0;
+}
+
+
+/**
+ *	sysdev_resume - Bring system devices back to life.
+ *
+ *	Similar to sys_device_suspend(), but we iterate the list forwards
+ *	to guarantee that parent devices are resumed before their children.
+ *
+ *	Note: Interrupts are disabled when called.
+ */
+
+int sysdev_resume(void)
+{
+	struct sysdev_class * cls;
+
+	pr_debug("Resuming System Devices\n");
+
+	list_for_each_entry(cls, &system_subsys.kset.list, kset.kobj.entry) {
+		struct sys_device * sysdev;
+
+		pr_debug("Resuming type '%s':\n",
+			 kobject_name(&cls->kset.kobj));
+
+		list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
+			struct sysdev_driver * drv;
+			pr_debug(" %s\n", kobject_name(&sysdev->kobj));
+
+			/* First, call the class-specific one */
+			if (cls->resume)
+				cls->resume(sysdev);
+
+			/* Call auxillary drivers next. */
+			list_for_each_entry(drv, &cls->drivers, entry) {
+				if (drv->resume)
+					drv->resume(sysdev);
+			}
+
+			/* Call global drivers. */
+			list_for_each_entry(drv, &sysdev_drivers, entry) {
+				if (drv->resume)
+					drv->resume(sysdev);
+			}
+
+		}
+	}
+	return 0;
+}
+
+
+int __init system_bus_init(void)
+{
+	system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj;
+	return subsystem_register(&system_subsys);
+}
+
+EXPORT_SYMBOL_GPL(sysdev_register);
+EXPORT_SYMBOL_GPL(sysdev_unregister);
diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c
new file mode 100644
index 0000000..6c2b447
--- /dev/null
+++ b/drivers/base/transport_class.c
@@ -0,0 +1,275 @@
+/*
+ * transport_class.c - implementation of generic transport classes
+ *                     using attribute_containers
+ *
+ * Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com>
+ *
+ * This file is licensed under GPLv2
+ *
+ * The basic idea here is to allow any "device controller" (which
+ * would most often be a Host Bus Adapter" to use the services of one
+ * or more tranport classes for performing transport specific
+ * services.  Transport specific services are things that the generic
+ * command layer doesn't want to know about (speed settings, line
+ * condidtioning, etc), but which the user might be interested in.
+ * Thus, the HBA's use the routines exported by the transport classes
+ * to perform these functions.  The transport classes export certain
+ * values to the user via sysfs using attribute containers.
+ *
+ * Note: because not every HBA will care about every transport
+ * attribute, there's a many to one relationship that goes like this:
+ *
+ * transport class<-----attribute container<----class device
+ *
+ * Usually the attribute container is per-HBA, but the design doesn't
+ * mandate that.  Although most of the services will be specific to
+ * the actual external storage connection used by the HBA, the generic
+ * transport class is framed entirely in terms of generic devices to
+ * allow it to be used by any physical HBA in the system.
+ */
+#include <linux/attribute_container.h>
+#include <linux/transport_class.h>
+
+/**
+ * transport_class_register - register an initial transport class
+ *
+ * @tclass:	a pointer to the transport class structure to be initialised
+ *
+ * The transport class contains an embedded class which is used to
+ * identify it.  The caller should initialise this structure with
+ * zeros and then generic class must have been initialised with the
+ * actual transport class unique name.  There's a macro
+ * DECLARE_TRANSPORT_CLASS() to do this (declared classes still must
+ * be registered).
+ *
+ * Returns 0 on success or error on failure.
+ */
+int transport_class_register(struct transport_class *tclass)
+{
+	return class_register(&tclass->class);
+}
+EXPORT_SYMBOL_GPL(transport_class_register);
+
+/**
+ * transport_class_unregister - unregister a previously registered class
+ *
+ * @tclass: The transport class to unregister
+ *
+ * Must be called prior to deallocating the memory for the transport
+ * class.
+ */
+void transport_class_unregister(struct transport_class *tclass)
+{
+	class_unregister(&tclass->class);
+}
+EXPORT_SYMBOL_GPL(transport_class_unregister);
+
+static int anon_transport_dummy_function(struct device *dev)
+{
+	/* do nothing */
+	return 0;
+}
+
+/**
+ * anon_transport_class_register - register an anonymous class
+ *
+ * @atc: The anon transport class to register
+ *
+ * The anonymous transport class contains both a transport class and a
+ * container.  The idea of an anonymous class is that it never
+ * actually has any device attributes associated with it (and thus
+ * saves on container storage).  So it can only be used for triggering
+ * events.  Use prezero and then use DECLARE_ANON_TRANSPORT_CLASS() to
+ * initialise the anon transport class storage.
+ */
+int anon_transport_class_register(struct anon_transport_class *atc)
+{
+	int error;
+	atc->container.class = &atc->tclass.class;
+	attribute_container_set_no_classdevs(&atc->container);
+	error = attribute_container_register(&atc->container);
+	if (error)
+		return error;
+	atc->tclass.setup = anon_transport_dummy_function;
+	atc->tclass.remove = anon_transport_dummy_function;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(anon_transport_class_register);
+
+/**
+ * anon_transport_class_unregister - unregister an anon class
+ *
+ * @atc: Pointer to the anon transport class to unregister
+ *
+ * Must be called prior to deallocating the memory for the anon
+ * transport class.
+ */
+void anon_transport_class_unregister(struct anon_transport_class *atc)
+{
+	attribute_container_unregister(&atc->container);
+}
+EXPORT_SYMBOL_GPL(anon_transport_class_unregister);
+
+static int transport_setup_classdev(struct attribute_container *cont,
+				    struct device *dev,
+				    struct class_device *classdev)
+{
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+
+	if (tclass->setup)
+		tclass->setup(dev);
+
+	return 0;
+}
+
+/**
+ * transport_setup_device - declare a new dev for transport class association
+ *			    but don't make it visible yet.
+ *
+ * @dev: the generic device representing the entity being added
+ *
+ * Usually, dev represents some component in the HBA system (either
+ * the HBA itself or a device remote across the HBA bus).  This
+ * routine is simply a trigger point to see if any set of transport
+ * classes wishes to associate with the added device.  This allocates
+ * storage for the class device and initialises it, but does not yet
+ * add it to the system or add attributes to it (you do this with
+ * transport_add_device).  If you have no need for a separate setup
+ * and add operations, use transport_register_device (see
+ * transport_class.h).
+ */
+
+void transport_setup_device(struct device *dev)
+{
+	attribute_container_add_device(dev, transport_setup_classdev);
+}
+EXPORT_SYMBOL_GPL(transport_setup_device);
+
+static int transport_add_class_device(struct attribute_container *cont,
+				      struct device *dev,
+				      struct class_device *classdev)
+{
+	int error = attribute_container_add_class_device(classdev);
+	struct transport_container *tcont = 
+		attribute_container_to_transport_container(cont);
+
+	if (!error && tcont->statistics)
+		error = sysfs_create_group(&classdev->kobj, tcont->statistics);
+
+	return error;
+}
+
+
+/**
+ * transport_add_device - declare a new dev for transport class association
+ *
+ * @dev: the generic device representing the entity being added
+ *
+ * Usually, dev represents some component in the HBA system (either
+ * the HBA itself or a device remote across the HBA bus).  This
+ * routine is simply a trigger point used to add the device to the
+ * system and register attributes for it.
+ */
+
+void transport_add_device(struct device *dev)
+{
+	attribute_container_device_trigger(dev, transport_add_class_device);
+}
+EXPORT_SYMBOL_GPL(transport_add_device);
+
+static int transport_configure(struct attribute_container *cont,
+			       struct device *dev)
+{
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+
+	if (tclass->configure)
+		tclass->configure(dev);
+
+	return 0;
+}
+
+/**
+ * transport_configure_device - configure an already set up device
+ *
+ * @dev: generic device representing device to be configured
+ *
+ * The idea of configure is simply to provide a point within the setup
+ * process to allow the transport class to extract information from a
+ * device after it has been setup.  This is used in SCSI because we
+ * have to have a setup device to begin using the HBA, but after we
+ * send the initial inquiry, we use configure to extract the device
+ * parameters.  The device need not have been added to be configured.
+ */
+void transport_configure_device(struct device *dev)
+{
+	attribute_container_trigger(dev, transport_configure);
+}
+EXPORT_SYMBOL_GPL(transport_configure_device);
+
+static int transport_remove_classdev(struct attribute_container *cont,
+				     struct device *dev,
+				     struct class_device *classdev)
+{
+	struct transport_container *tcont = 
+		attribute_container_to_transport_container(cont);
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+
+	if (tclass->remove)
+		tclass->remove(dev);
+
+	if (tclass->remove != anon_transport_dummy_function) {
+		if (tcont->statistics)
+			sysfs_remove_group(&classdev->kobj, tcont->statistics);
+		attribute_container_class_device_del(classdev);
+	}
+
+	return 0;
+}
+
+
+/**
+ * transport_remove_device - remove the visibility of a device
+ *
+ * @dev: generic device to remove
+ *
+ * This call removes the visibility of the device (to the user from
+ * sysfs), but does not destroy it.  To eliminate a device entirely
+ * you must also call transport_destroy_device.  If you don't need to
+ * do remove and destroy as separate operations, use
+ * transport_unregister_device() (see transport_class.h) which will
+ * perform both calls for you.
+ */
+void transport_remove_device(struct device *dev)
+{
+	attribute_container_device_trigger(dev, transport_remove_classdev);
+}
+EXPORT_SYMBOL_GPL(transport_remove_device);
+
+static void transport_destroy_classdev(struct attribute_container *cont,
+				      struct device *dev,
+				      struct class_device *classdev)
+{
+	struct transport_class *tclass = class_to_transport_class(cont->class);
+
+	if (tclass->remove != anon_transport_dummy_function)
+		class_device_put(classdev);
+}
+
+
+/**
+ * transport_destroy_device - destroy a removed device
+ *
+ * @dev: device to eliminate from the transport class.
+ *
+ * This call triggers the elimination of storage associated with the
+ * transport classdev.  Note: all it really does is relinquish a
+ * reference to the classdev.  The memory will not be freed until the
+ * last reference goes to zero.  Note also that the classdev retains a
+ * reference count on dev, so dev too will remain for as long as the
+ * transport class device remains around.
+ */
+void transport_destroy_device(struct device *dev)
+{
+	attribute_container_remove_device(dev, transport_destroy_classdev);
+}
+EXPORT_SYMBOL_GPL(transport_destroy_device);