diff options
author | Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> | 2005-03-18 16:20:46 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2005-07-11 23:20:49 -0400 |
commit | e2a5b420f716cd1a46674b1a90389612eced916f (patch) | |
tree | 96f363f2e402d53428c046269514a82856b0cb34 /drivers/acpi/sleep/poweroff.c | |
parent | be91492ca871e58f61b517cfba541095bb60001c (diff) |
[ACPI] ACPI poweroff fix
Register an "acpi" system device to be notified of shutdown preparation.
This depends on CONFIG_PM
http://bugzilla.kernel.org/show_bug.cgi?id=4041
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/sleep/poweroff.c')
-rw-r--r-- | drivers/acpi/sleep/poweroff.c | 81 |
1 files changed, 73 insertions, 8 deletions
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index da237754ded9..1fc86e6b5ab9 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c | |||
@@ -3,35 +3,100 @@ | |||
3 | * | 3 | * |
4 | * AKA S5, but it is independent of whether or not the kernel supports | 4 | * AKA S5, but it is independent of whether or not the kernel supports |
5 | * any other sleep support in the system. | 5 | * any other sleep support in the system. |
6 | * | ||
7 | * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> | ||
8 | * | ||
9 | * This file is released under the GPLv2. | ||
6 | */ | 10 | */ |
7 | 11 | ||
8 | #include <linux/pm.h> | 12 | #include <linux/pm.h> |
9 | #include <linux/init.h> | 13 | #include <linux/init.h> |
10 | #include <acpi/acpi_bus.h> | 14 | #include <acpi/acpi_bus.h> |
11 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/sysdev.h> | ||
17 | #include <asm/io.h> | ||
12 | #include "sleep.h" | 18 | #include "sleep.h" |
13 | 19 | ||
14 | static void | 20 | int acpi_sleep_prepare(u32 acpi_state) |
15 | acpi_power_off (void) | 21 | { |
22 | /* Flag to do not allow second time invocation for S5 state */ | ||
23 | static int shutdown_prepared = 0; | ||
24 | #ifdef CONFIG_ACPI_SLEEP | ||
25 | /* do we have a wakeup address for S2 and S3? */ | ||
26 | /* Here, we support only S4BIOS, those we set the wakeup address */ | ||
27 | /* S4OS is only supported for now via swsusp.. */ | ||
28 | if (acpi_state == ACPI_STATE_S3 || acpi_state == ACPI_STATE_S4) { | ||
29 | if (!acpi_wakeup_address) { | ||
30 | return -EFAULT; | ||
31 | } | ||
32 | acpi_set_firmware_waking_vector((acpi_physical_address) | ||
33 | virt_to_phys((void *) | ||
34 | acpi_wakeup_address)); | ||
35 | |||
36 | } | ||
37 | ACPI_FLUSH_CPU_CACHE(); | ||
38 | acpi_enable_wakeup_device_prep(acpi_state); | ||
39 | #endif | ||
40 | if (acpi_state == ACPI_STATE_S5) { | ||
41 | /* Check if we were already called */ | ||
42 | if (shutdown_prepared) | ||
43 | return 0; | ||
44 | acpi_wakeup_gpe_poweroff_prepare(); | ||
45 | shutdown_prepared = 1; | ||
46 | } | ||
47 | acpi_enter_sleep_state_prep(acpi_state); | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | void acpi_power_off(void) | ||
16 | { | 52 | { |
17 | printk("%s called\n",__FUNCTION__); | 53 | printk("%s called\n", __FUNCTION__); |
54 | acpi_sleep_prepare(ACPI_STATE_S5); | ||
55 | local_irq_disable(); | ||
18 | /* Some SMP machines only can poweroff in boot CPU */ | 56 | /* Some SMP machines only can poweroff in boot CPU */ |
19 | set_cpus_allowed(current, cpumask_of_cpu(0)); | 57 | set_cpus_allowed(current, cpumask_of_cpu(0)); |
20 | acpi_wakeup_gpe_poweroff_prepare(); | ||
21 | acpi_enter_sleep_state_prep(ACPI_STATE_S5); | ||
22 | ACPI_DISABLE_IRQS(); | ||
23 | acpi_enter_sleep_state(ACPI_STATE_S5); | 58 | acpi_enter_sleep_state(ACPI_STATE_S5); |
24 | } | 59 | } |
25 | 60 | ||
61 | #ifdef CONFIG_PM | ||
62 | |||
63 | static int acpi_shutdown(struct sys_device *x) | ||
64 | { | ||
65 | return acpi_sleep_prepare(ACPI_STATE_S5); | ||
66 | } | ||
67 | |||
68 | static struct sysdev_class acpi_sysclass = { | ||
69 | set_kset_name("acpi"), | ||
70 | .shutdown = acpi_shutdown | ||
71 | }; | ||
72 | |||
73 | static struct sys_device device_acpi = { | ||
74 | .id = 0, | ||
75 | .cls = &acpi_sysclass, | ||
76 | }; | ||
77 | |||
78 | #endif | ||
79 | |||
26 | static int acpi_poweroff_init(void) | 80 | static int acpi_poweroff_init(void) |
27 | { | 81 | { |
28 | if (!acpi_disabled) { | 82 | if (!acpi_disabled) { |
29 | u8 type_a, type_b; | 83 | u8 type_a, type_b; |
30 | acpi_status status; | 84 | acpi_status status; |
31 | 85 | ||
32 | status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); | 86 | status = |
33 | if (ACPI_SUCCESS(status)) | 87 | acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); |
88 | if (ACPI_SUCCESS(status)) { | ||
34 | pm_power_off = acpi_power_off; | 89 | pm_power_off = acpi_power_off; |
90 | #ifdef CONFIG_PM | ||
91 | { | ||
92 | int error; | ||
93 | error = sysdev_class_register(&acpi_sysclass); | ||
94 | if (!error) | ||
95 | error = sysdev_register(&device_acpi); | ||
96 | return error; | ||
97 | } | ||
98 | #endif | ||
99 | } | ||
35 | } | 100 | } |
36 | return 0; | 101 | return 0; |
37 | } | 102 | } |