Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | /*
* 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 <linux/resume-trace.h>
#include "../base.h"
#include "power.h"
/**
* resume_device - Restore state for one device.
* @dev: Device.
*
*/
int resume_device(struct device * dev)
{
int error = 0;
TRACE_DEVICE(dev);
TRACE_RESUME(0);
down(&dev->sem);
if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state.event) {
dev_err(dev, "PM: resume from %d, parent %s still %d\n",
dev->power.power_state.event,
dev->power.pm_parent->bus_id,
dev->power.pm_parent->power.power_state.event);
}
if (dev->bus && dev->bus->resume) {
dev_dbg(dev,"resuming\n");
error = dev->bus->resume(dev);
}
if (dev->class && dev->class->resume) {
dev_dbg(dev,"class resume\n");
error = dev->class->resume(dev);
}
up(&dev->sem);
TRACE_RESUME(error);
return error;
}
static int resume_device_early(struct device * dev)
{
int error = 0;
TRACE_DEVICE(dev);
TRACE_RESUME(0);
if (dev->bus && dev->bus->resume_early) {
dev_dbg(dev,"EARLY resume\n");
error = dev->bus->resume_early(dev);
}
TRACE_RESUME(error);
return error;
}
/*
* Resume the devices that have either not gone through
* the late suspend, or that did go through it but also
* went through the early resume
*/
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_move_tail(entry, &dpm_active);
up(&dpm_list_sem);
if (!dev->power.prev_state.event)
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)
{
might_sleep();
down(&dpm_sem);
dpm_resume();
up(&dpm_sem);
}
EXPORT_SYMBOL_GPL(device_resume);
/**
* dpm_power_up - 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_active 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);
list_move_tail(entry, &dpm_off);
resume_device_early(dev);
}
}
/**
* device_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);
|