From: Pavel Machek <pavel@ucw.cz>

This almost changes no code (constant is still "3"), but at least it uses
right constants for device_suspend() and fixes types at few points.  Also
puts explanation of constants to the Documentation.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/Documentation/power/devices.txt |   88 ++++++++++++++++++++++++++++++++
 25-akpm/arch/i386/kernel/apm.c          |    6 +-
 25-akpm/drivers/acpi/sleep/main.c       |    2 
 25-akpm/kernel/power/disk.c             |    6 +-
 25-akpm/kernel/power/main.c             |    7 +-
 25-akpm/kernel/power/swsusp.c           |    4 -
 6 files changed, 102 insertions(+), 11 deletions(-)

diff -puN arch/i386/kernel/apm.c~swsusp-dm-use-right-levels-for-device_suspend arch/i386/kernel/apm.c
--- 25/arch/i386/kernel/apm.c~swsusp-dm-use-right-levels-for-device_suspend	Wed Jan 12 16:08:40 2005
+++ 25-akpm/arch/i386/kernel/apm.c	Wed Jan 12 16:08:40 2005
@@ -1201,8 +1201,8 @@ static int suspend(int vetoable)
 		printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n");
 	}
 
-	device_suspend(3);
-	device_power_down(3);
+	device_suspend(PMSG_SUSPEND);
+	device_power_down(PMSG_SUSPEND);
 
 	/* serialize with the timer interrupt */
 	write_seqlock_irq(&xtime_lock);
@@ -1255,7 +1255,7 @@ static void standby(void)
 {
 	int	err;
 
-	device_power_down(3);
+	device_power_down(PMSG_SUSPEND);
 	/* serialize with the timer interrupt */
 	write_seqlock_irq(&xtime_lock);
 	/* If needed, notify drivers here */
diff -puN Documentation/power/devices.txt~swsusp-dm-use-right-levels-for-device_suspend Documentation/power/devices.txt
--- 25/Documentation/power/devices.txt~swsusp-dm-use-right-levels-for-device_suspend	Wed Jan 12 16:08:40 2005
+++ 25-akpm/Documentation/power/devices.txt	Wed Jan 12 16:08:40 2005
@@ -229,3 +229,91 @@ module is re-inserted during it's ->prob
 The driver core will not call any extra functions when binding the
 device to the driver. 
 
+pm_message_t meaning
+
+pm_message_t has two fields. event ("major"), and flags.  If driver
+does not know event code, it aborts the request, returning error. Some
+drivers may need to deal with special cases based on the actual type
+of suspend operation being done at the system level. This is why
+there are flags.
+
+Event codes are:
+
+ON -- no need to do anything except special cases like broken
+HW.
+
+# NOTIFICATION -- pretty much same as ON?
+
+FREEZE -- stop DMA and interrupts, and be prepared to reinit HW from
+scratch. That probably means stop accepting upstream requests, the
+actual policy of what to do with them being specific to a given
+driver. It's acceptable for a network driver to just drop packets
+while a block driver is expected to block the queue so no request is
+lost. (Use IDE as an example on how to do that). FREEZE requires no
+power state change, and it's expected for drivers to be able to
+quickly transition back to operating state.
+
+SUSPEND -- like FREEZE, but also put hardware into low-power state. If
+there's need to distinguish several levels of sleep, additional flag
+is probably best way to do that.
+
+Transitions are only from a resumed state to a suspended state, never
+between 2 suspended states. (ON -> FREEZE or ON -> SUSPEND can happen,
+FREEZE -> SUSPEND or SUSPEND -> FREEZE can not).
+
+All events are:
+
+[NOTE NOTE NOTE: If you are driver author, you should not care; you
+should only look at event, and ignore flags.]
+
+#Prepare for suspend -- userland is still running but we are going to
+#enter suspend state. This gives drivers chance to load firmware from
+#disk and store it in memory, or do other activities taht require
+#operating userland, ability to kmalloc GFP_KERNEL, etc... All of these
+#are forbiden once the suspend dance is started.. event = ON, flags =
+#PREPARE_TO_SUSPEND
+
+Apm standby -- prepare for APM event. Quiesce devices to make life
+easier for APM BIOS. event = FREEZE, flags = APM_STANDBY
+
+Apm suspend -- same as APM_STANDBY, but it we should probably avoid
+spinning down disks. event = FREEZE, flags = APM_SUSPEND
+
+System halt, reboot -- quiesce devices to make life easier for BIOS. event
+= FREEZE, flags = SYSTEM_HALT or SYSTEM_REBOOT
+
+System shutdown -- at least disks need to be spun down, or data may be
+lost. Quiesce devices, just to make life easier for BIOS. event =
+FREEZE, flags = SYSTEM_SHUTDOWN
+
+Kexec    -- turn off DMAs and put hardware into some state where new
+kernel can take over. event = FREEZE, flags = KEXEC
+
+Powerdown at end of swsusp -- very similar to SYSTEM_SHUTDOWN, except wake
+may need to be enabled on some devices. This actually has at least 3
+subtypes, system can reboot, enter S4 and enter S5 at the end of
+swsusp. event = FREEZE, flags = SWSUSP and one of SYSTEM_REBOOT,
+SYSTEM_SHUTDOWN, SYSTEM_S4
+
+Suspend to ram  -- put devices into low power state. event = SUSPEND,
+flags = SUSPEND_TO_RAM
+
+Freeze for swsusp snapshot -- stop DMA and interrupts. No need to put
+devices into low power mode, but you must be able to reinitialize
+device from scratch in resume method. This has two flavors, its done
+once on suspending kernel, once on resuming kernel. event = FREEZE,
+flags = DURING_SUSPEND or DURING_RESUME
+
+Device detach requested from /sys -- deinitialize device; proably same as
+SYSTEM_SHUTDOWN, I do not understand this one too much. probably event
+= FREEZE, flags = DEV_DETACH.
+
+#These are not really events sent:
+#
+#System fully on -- device is working normally; this is probably never
+#passed to suspend() method... event = ON, flags = 0
+#
+#Ready after resume -- userland is now running, again. Time to free any
+#memory you ate during prepare to suspend... event = ON, flags =
+#READY_AFTER_RESUME
+#
diff -puN drivers/acpi/sleep/main.c~swsusp-dm-use-right-levels-for-device_suspend drivers/acpi/sleep/main.c
--- 25/drivers/acpi/sleep/main.c~swsusp-dm-use-right-levels-for-device_suspend	Wed Jan 12 16:08:40 2005
+++ 25-akpm/drivers/acpi/sleep/main.c	Wed Jan 12 16:08:40 2005
@@ -159,7 +159,7 @@ static int acpi_pm_finish(suspend_state_
 
 int acpi_suspend(u32 acpi_state)
 {
-	u32 states[] = {
+	suspend_state_t states[] = {
 		[1]	= PM_SUSPEND_STANDBY,
 		[3]	= PM_SUSPEND_MEM,
 		[4]	= PM_SUSPEND_DISK,
diff -puN kernel/power/disk.c~swsusp-dm-use-right-levels-for-device_suspend kernel/power/disk.c
--- 25/kernel/power/disk.c~swsusp-dm-use-right-levels-for-device_suspend	Wed Jan 12 16:08:40 2005
+++ 25-akpm/kernel/power/disk.c	Wed Jan 12 16:08:40 2005
@@ -51,7 +51,7 @@ static void power_down(suspend_disk_meth
 	local_irq_save(flags);
 	switch(mode) {
 	case PM_DISK_PLATFORM:
-		device_power_down(PM_SUSPEND_DISK);
+ 		device_power_down(PMSG_SUSPEND);
 		error = pm_ops->enter(PM_SUSPEND_DISK);
 		break;
 	case PM_DISK_SHUTDOWN:
@@ -144,8 +144,10 @@ static int prepare(void)
 	free_some_memory();
 
 	disable_nonboot_cpus();
-	if ((error = device_suspend(PM_SUSPEND_DISK)))
+	if ((error = device_suspend(PMSG_FREEZE))) {
+		printk("Some devices failed to suspend\n");
 		goto Finish;
+	}
 
 	return 0;
  Finish:
diff -puN kernel/power/main.c~swsusp-dm-use-right-levels-for-device_suspend kernel/power/main.c
--- 25/kernel/power/main.c~swsusp-dm-use-right-levels-for-device_suspend	Wed Jan 12 16:08:40 2005
+++ 25-akpm/kernel/power/main.c	Wed Jan 12 16:08:40 2005
@@ -65,7 +65,7 @@ static int suspend_prepare(suspend_state
 			goto Thaw;
 	}
 
-	if ((error = device_suspend(state)))
+	if ((error = device_suspend(PMSG_SUSPEND)))
 		goto Finish;
 	return 0;
  Finish:
@@ -78,13 +78,14 @@ static int suspend_prepare(suspend_state
 }
 
 
-static int suspend_enter(u32 state)
+static int suspend_enter(suspend_state_t state)
 {
 	int error = 0;
 	unsigned long flags;
 
 	local_irq_save(flags);
-	if ((error = device_power_down(state)))
+
+	if ((error = device_power_down(PMSG_SUSPEND)))
 		goto Done;
 	error = pm_ops->enter(state);
 	device_power_up();
diff -puN kernel/power/swsusp.c~swsusp-dm-use-right-levels-for-device_suspend kernel/power/swsusp.c
--- 25/kernel/power/swsusp.c~swsusp-dm-use-right-levels-for-device_suspend	Wed Jan 12 16:08:40 2005
+++ 25-akpm/kernel/power/swsusp.c	Wed Jan 12 16:08:40 2005
@@ -849,7 +849,7 @@ int swsusp_suspend(void)
 	 * become desynchronized with the actual state of the hardware
 	 * at resume time, and evil weirdness ensues.
 	 */
-	if ((error = device_power_down(PM_SUSPEND_DISK))) {
+	if ((error = device_power_down(PMSG_FREEZE))) {
 		local_irq_enable();
 		return error;
 	}
@@ -878,7 +878,7 @@ int swsusp_resume(void)
 {
 	int error;
 	local_irq_disable();
-	device_power_down(PM_SUSPEND_DISK);
+	device_power_down(PMSG_FREEZE);
 	/* We'll ignore saved state, but this gets preempt count (etc) right */
 	save_processor_state();
 	error = swsusp_arch_resume();
_