#include <linux/device.h>
#include <linux/delay.h>
#include <linux/fs.h>
-#include <linux/device.h>
#include "power.h"
extern int swsusp_suspend(void);
extern int swsusp_write(void);
+extern int swsusp_check(void);
extern int swsusp_read(void);
+extern void swsusp_close(void);
extern int swsusp_resume(void);
extern int swsusp_free(void);
static int noresume = 0;
char resume_file[256] = CONFIG_PM_STD_PARTITION;
+dev_t swsusp_resume_device;
/**
* power_down - Shut machine down for hibernate.
local_irq_save(flags);
switch(mode) {
case PM_DISK_PLATFORM:
- device_power_down(PMSG_SUSPEND);
+ device_shutdown();
error = pm_ops->enter(PM_SUSPEND_DISK);
break;
case PM_DISK_SHUTDOWN:
}
-static int prepare(void)
+static int prepare_processes(void)
{
int error;
pm_prepare_console();
sys_sync();
+
if (freeze_processes()) {
error = -EBUSY;
- goto Thaw;
+ return error;
}
if (pm_disk_mode == PM_DISK_PLATFORM) {
if (pm_ops && pm_ops->prepare) {
if ((error = pm_ops->prepare(PM_SUSPEND_DISK)))
- goto Thaw;
+ return error;
}
}
/* Free memory before shutting down devices. */
free_some_memory();
+ return 0;
+}
+
+static void unprepare_processes(void)
+{
+ enable_nonboot_cpus();
+ thaw_processes();
+ pm_restore_console();
+}
+
+static int prepare_devices(void)
+{
+ int error;
+
disable_nonboot_cpus();
if ((error = device_suspend(PMSG_FREEZE))) {
printk("Some devices failed to suspend\n");
- goto Finish;
+ platform_finish();
+ enable_nonboot_cpus();
+ return error;
}
return 0;
- Finish:
- platform_finish();
- Thaw:
- enable_nonboot_cpus();
- thaw_processes();
- pm_restore_console();
- return error;
}
-
/**
* pm_suspend_disk - The granpappy of power management.
*
{
int error;
- if ((error = prepare()))
+ error = prepare_processes();
+ if (!error) {
+ error = prepare_devices();
+ }
+
+ if (error) {
+ unprepare_processes();
return error;
+ }
pr_debug("PM: Attempting to suspend to disk.\n");
if (pm_disk_mode == PM_DISK_FIRMWARE)
return 0;
}
+ pr_debug("PM: Checking swsusp image.\n");
+
+ if ((error = swsusp_check()))
+ goto Done;
+
+ pr_debug("PM: Preparing processes for restore.\n");
+
+ if ((error = prepare_processes())) {
+ swsusp_close();
+ goto Cleanup;
+ }
+
pr_debug("PM: Reading swsusp image.\n");
if ((error = swsusp_read()))
- goto Done;
+ goto Cleanup;
- pr_debug("PM: Preparing system for restore.\n");
+ pr_debug("PM: Preparing devices for restore.\n");
- if ((error = prepare()))
+ if ((error = prepare_devices()))
goto Free;
- barrier();
mb();
pr_debug("PM: Restoring saved image.\n");
finish();
Free:
swsusp_free();
+ Cleanup:
+ unprepare_processes();
Done:
pr_debug("PM: Resume from disk failed.\n");
return 0;
power_attr(disk);
+static ssize_t resume_show(struct subsystem * subsys, char *buf)
+{
+ return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
+ MINOR(swsusp_resume_device));
+}
+
+static ssize_t resume_store(struct subsystem * subsys, const char * buf, size_t n)
+{
+ int len;
+ char *p;
+ unsigned int maj, min;
+ int error = -EINVAL;
+ dev_t res;
+
+ p = memchr(buf, '\n', n);
+ len = p ? p - buf : n;
+
+ if (sscanf(buf, "%u:%u", &maj, &min) == 2) {
+ res = MKDEV(maj,min);
+ if (maj == MAJOR(res) && min == MINOR(res)) {
+ swsusp_resume_device = res;
+ printk("Attempting manual resume\n");
+ noresume = 0;
+ software_resume();
+ }
+ }
+
+ return error >= 0 ? n : error;
+}
+
+power_attr(resume);
+
static struct attribute * g[] = {
&disk_attr.attr,
+ &resume_attr.attr,
NULL,
};