#include <linux/errno.h>
#include <linux/init.h>
#include <linux/pm.h>
-
+#include <linux/console.h>
+#include <linux/cpu.h>
+#include <linux/resume-trace.h>
#include "power.h"
DECLARE_MUTEX(pm_sem);
-struct pm_ops * pm_ops = NULL;
-suspend_disk_method_t pm_disk_mode = PM_DISK_SHUTDOWN;
+struct pm_ops *pm_ops;
+suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM;
/**
* pm_set_ops - Set the global power method table.
static int suspend_prepare(suspend_state_t state)
{
- int error = 0;
+ int error;
unsigned int free_pages;
if (!pm_ops || !pm_ops->enter)
pm_prepare_console();
- disable_nonboot_cpus();
-
- if (num_online_cpus() != 1) {
- error = -EPERM;
+ error = disable_nonboot_cpus();
+ if (error)
goto Enable_cpu;
- }
if (freeze_processes()) {
error = -EAGAIN;
goto Thaw;
}
+ suspend_console();
if ((error = device_suspend(PMSG_SUSPEND))) {
printk(KERN_ERR "Some devices failed to suspend\n");
goto Finish;
}
-static int suspend_enter(suspend_state_t state)
+int suspend_enter(suspend_state_t state)
{
int error = 0;
unsigned long flags;
static void suspend_finish(suspend_state_t state)
{
device_resume();
- if (pm_ops && pm_ops->finish)
- pm_ops->finish(state);
+ resume_console();
thaw_processes();
enable_nonboot_cpus();
+ if (pm_ops && pm_ops->finish)
+ pm_ops->finish(state);
pm_restore_console();
}
-static char *pm_states[PM_SUSPEND_MAX] = {
+static const char * const pm_states[PM_SUSPEND_MAX] = {
[PM_SUSPEND_STANDBY] = "standby",
[PM_SUSPEND_MEM] = "mem",
#ifdef CONFIG_SOFTWARE_SUSPEND
#endif
};
+static inline int valid_state(suspend_state_t state)
+{
+ /* Suspend-to-disk does not really need low-level support.
+ * It can work with reboot if needed. */
+ if (state == PM_SUSPEND_DISK)
+ return 1;
+
+ if (pm_ops && pm_ops->valid && !pm_ops->valid(state))
+ return 0;
+ return 1;
+}
+
/**
* enter_state - Do common work of entering low-power state.
{
int error;
- if (pm_ops->valid && !pm_ops->valid(state))
+ if (!valid_state(state))
return -ENODEV;
if (down_trylock(&pm_sem))
return -EBUSY;
char * s = buf;
for (i = 0; i < PM_SUSPEND_MAX; i++) {
- if (pm_states[i] && pm_ops && (!pm_ops->valid
- ||(pm_ops->valid && pm_ops->valid(i))))
- s += sprintf(s,"%s ",pm_states[i]);
+ if (pm_states[i] && valid_state(i))
+ s += sprintf(s,"%s ", pm_states[i]);
}
s += sprintf(s,"\n");
return (s - buf);
static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
{
suspend_state_t state = PM_SUSPEND_STANDBY;
- char ** s;
+ const char * const *s;
char *p;
int error;
int len;
if (*s && !strncmp(buf, *s, len))
break;
}
- if (*s)
+ if (state < PM_SUSPEND_MAX && *s)
error = enter_state(state);
else
error = -EINVAL;
power_attr(state);
+#ifdef CONFIG_PM_TRACE
+int pm_trace_enabled;
+
+static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
+{
+ return sprintf(buf, "%d\n", pm_trace_enabled);
+}
+
+static ssize_t
+pm_trace_store(struct subsystem * subsys, const char * buf, size_t n)
+{
+ int val;
+
+ if (sscanf(buf, "%d", &val) == 1) {
+ pm_trace_enabled = !!val;
+ return n;
+ }
+ return -EINVAL;
+}
+
+power_attr(pm_trace);
+
+static struct attribute * g[] = {
+ &state_attr.attr,
+ &pm_trace_attr.attr,
+ NULL,
+};
+#else
static struct attribute * g[] = {
&state_attr.attr,
NULL,
};
+#endif /* CONFIG_PM_TRACE */
static struct attribute_group attr_group = {
.attrs = g,