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/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);
+}