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!
This commit is contained in:
144
drivers/base/power/suspend.c
Normal file
144
drivers/base/power/suspend.c
Normal file
@@ -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);
|
||||
|
Reference in New Issue
Block a user