Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[linux-2.6] / drivers / base / power / resume.c
1 /*
2  * resume.c - Functions for waking devices up.
3  *
4  * Copyright (c) 2003 Patrick Mochel
5  * Copyright (c) 2003 Open Source Development Labs
6  *
7  * This file is released under the GPLv2
8  *
9  */
10
11 #include <linux/device.h>
12 #include <linux/resume-trace.h>
13 #include "../base.h"
14 #include "power.h"
15
16
17 /**
18  *      resume_device - Restore state for one device.
19  *      @dev:   Device.
20  *
21  */
22
23 int resume_device(struct device * dev)
24 {
25         int error = 0;
26
27         TRACE_DEVICE(dev);
28         TRACE_RESUME(0);
29         down(&dev->sem);
30         if (dev->power.pm_parent
31                         && dev->power.pm_parent->power.power_state.event) {
32                 dev_err(dev, "PM: resume from %d, parent %s still %d\n",
33                         dev->power.power_state.event,
34                         dev->power.pm_parent->bus_id,
35                         dev->power.pm_parent->power.power_state.event);
36         }
37         if (dev->bus && dev->bus->resume) {
38                 dev_dbg(dev,"resuming\n");
39                 error = dev->bus->resume(dev);
40         }
41         if (dev->class && dev->class->resume) {
42                 dev_dbg(dev,"class resume\n");
43                 error = dev->class->resume(dev);
44         }
45         up(&dev->sem);
46         TRACE_RESUME(error);
47         return error;
48 }
49
50
51 static int resume_device_early(struct device * dev)
52 {
53         int error = 0;
54
55         TRACE_DEVICE(dev);
56         TRACE_RESUME(0);
57         if (dev->bus && dev->bus->resume_early) {
58                 dev_dbg(dev,"EARLY resume\n");
59                 error = dev->bus->resume_early(dev);
60         }
61         TRACE_RESUME(error);
62         return error;
63 }
64
65 /*
66  * Resume the devices that have either not gone through
67  * the late suspend, or that did go through it but also
68  * went through the early resume
69  */
70 void dpm_resume(void)
71 {
72         down(&dpm_list_sem);
73         while(!list_empty(&dpm_off)) {
74                 struct list_head * entry = dpm_off.next;
75                 struct device * dev = to_device(entry);
76
77                 get_device(dev);
78                 list_move_tail(entry, &dpm_active);
79
80                 up(&dpm_list_sem);
81                 if (!dev->power.prev_state.event)
82                         resume_device(dev);
83                 down(&dpm_list_sem);
84                 put_device(dev);
85         }
86         up(&dpm_list_sem);
87 }
88
89
90 /**
91  *      device_resume - Restore state of each device in system.
92  *
93  *      Walk the dpm_off list, remove each entry, resume the device,
94  *      then add it to the dpm_active list.
95  */
96
97 void device_resume(void)
98 {
99         might_sleep();
100         down(&dpm_sem);
101         dpm_resume();
102         up(&dpm_sem);
103 }
104
105 EXPORT_SYMBOL_GPL(device_resume);
106
107
108 /**
109  *      dpm_power_up - Power on some devices.
110  *
111  *      Walk the dpm_off_irq list and power each device up. This
112  *      is used for devices that required they be powered down with
113  *      interrupts disabled. As devices are powered on, they are moved
114  *      to the dpm_active list.
115  *
116  *      Interrupts must be disabled when calling this.
117  */
118
119 void dpm_power_up(void)
120 {
121         while(!list_empty(&dpm_off_irq)) {
122                 struct list_head * entry = dpm_off_irq.next;
123                 struct device * dev = to_device(entry);
124
125                 list_move_tail(entry, &dpm_off);
126                 resume_device_early(dev);
127         }
128 }
129
130
131 /**
132  *      device_power_up - Turn on all devices that need special attention.
133  *
134  *      Power on system devices then devices that required we shut them down
135  *      with interrupts disabled.
136  *      Called with interrupts disabled.
137  */
138
139 void device_power_up(void)
140 {
141         sysdev_resume();
142         dpm_power_up();
143 }
144
145 EXPORT_SYMBOL_GPL(device_power_up);
146
147