diff options
| author | Patrick Mochel <mochel@segfault.osdl.org> | 2002-03-25 22:26:46 -0800 |
|---|---|---|
| committer | Patrick Mochel <mochel@segfault.osdl.org> | 2002-03-25 22:26:46 -0800 |
| commit | a0df92a42472b636998d39ce0255d5efaf56b61b (patch) | |
| tree | 153a2105c7abed262bb59400f91314982d349a28 | |
| parent | fba46407ee71baf4f4d0ebc3156920bc0318cd1d (diff) | |
Add device_{suspend,resume,shutdown} calls.
| -rw-r--r-- | drivers/base/Makefile | 4 | ||||
| -rw-r--r-- | drivers/base/power.c | 122 | ||||
| -rw-r--r-- | include/linux/device.h | 5 |
3 files changed, 129 insertions, 2 deletions
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index a6885490ffe0..1995637fa63f 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -1,7 +1,7 @@ O_TARGET := base.o -obj-y := core.o sys.o interface.o fs.o +obj-y := core.o sys.o interface.o fs.o power.o -export-objs := core.o sys.o interface.o fs.o +export-objs := $(obj-y) include $(TOPDIR)/Rules.make diff --git a/drivers/base/power.c b/drivers/base/power.c index e69de29bb2d1..92633070f254 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -0,0 +1,122 @@ +/* + * power.c - power management functions for the device tree. + * + * Copyright (c) 2002 Patrick Mochel + * 2002 Open Source Development Lab + * + * Kai Germaschewski contributed to the list walking routines. + * + * FIXME: The suspend and shutdown walks are identical. The resume walk + * is simply walking the list backward. Anyway we can combine these (cleanly)? + */ + +#include <linux/device.h> +#include <linux/module.h> +#include "base.h" + +/** + * device_suspend - suspend all devices on the device tree + * @state: state we're entering + * @level: what stage of the suspend process we're at + * + * The entries in the global device list are inserted such that they're in a + * depth-first ordering. So, simply iterate over the list, and call the driver's + * suspend callback for each device. + */ +int device_suspend(u32 state, u32 level) +{ + struct device * dev; + struct device * prev = &device_root; + int error = 0; + + get_device(prev); + + spin_lock(&device_lock); + dev = g_list_to_dev(prev->g_list.next); + while(dev != &device_root && !error) { + get_device(dev); + spin_unlock(&device_lock); + put_device(prev); + + if (dev->driver && dev->driver->suspend) + error = dev->driver->suspend(dev,state,level); + + spin_lock(&device_lock); + prev = dev; + dev = g_list_to_dev(prev->g_list.next); + } + spin_unlock(&device_root); + put_device(prev); + + return error; +} + +/** + * device_resume - resume all the devices in the system + * @level: stage of resume process we're at + * + * Similar to device_suspend above, though we want to do a breadth-first + * walk of the tree to make sure we wake up parents before children. + * So, we iterate over the list backward. + */ +void device_resume(u32 level) +{ + struct device * dev; + struct device * prev = &device_root; + + get_device(prev); + + spin_lock(&device_lock); + dev = g_list_to_dev(prev->g_list.prev); + while(dev != &device_root) { + get_device(dev); + spin_unlock(&device_lock); + put_device(prev); + + if (dev->driver && dev->driver->resume) + dev->driver->resume(dev,level); + + spin_lock(&device_lock); + prev = dev; + dev = g_list_to_dev(prev->g_list.prev); + } + spin_unlock(&device_root); + put_device(prev); +} + +/** + * device_shutdown - queisce all the devices before reboot/shutdown + * + * Do depth first iteration over device tree, calling ->remove() for each + * device. This should ensure the devices are put into a sane state before + * we reboot the system. + * + */ +void device_shutdown(void) +{ + struct device * dev; + struct device * prev = &device_root; + + get_device(prev); + + spin_lock(&device_lock); + dev = g_list_to_dev(prev->g_list.next); + while(dev != &device_root) { + get_device(dev); + spin_unlock(&device_lock); + put_device(prev); + + if (dev->driver && dev->driver->remove) + dev->driver->remove(dev,REMOVE_FREE_RESOURCES); + + spin_lock(&device_lock); + prev = dev; + dev = g_list_to_dev(prev->g_list.next); + } + spin_unlock(&device_root); + put_device(prev); +} + +EXPORT_SYMBOL(device_suspend); +EXPORT_SYMBOL(device_resume); +EXPORT_SYMBOL(device_shutdown); diff --git a/include/linux/device.h b/include/linux/device.h index 69797acdc546..b1858aa6a4ed 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -154,4 +154,9 @@ extern void put_device(struct device * dev); extern int register_sys_device(struct device * dev); extern void unregister_sys_device(struct device * dev); +/* drivers/base/power.c */ +extern int device_suspend(u32 state, u32 level); +extern void device_resume(u32 level); +extern void device_shutdown(void); + #endif /* _DEVICE_H_ */ |
