]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * poweroff.c - ACPI handler for powering off the system. | |
3 | * | |
4 | * AKA S5, but it is independent of whether or not the kernel supports | |
5 | * any other sleep support in the system. | |
e2a5b420 AS |
6 | * |
7 | * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> | |
8 | * | |
9 | * This file is released under the GPLv2. | |
1da177e4 LT |
10 | */ |
11 | ||
12 | #include <linux/pm.h> | |
13 | #include <linux/init.h> | |
14 | #include <acpi/acpi_bus.h> | |
15 | #include <linux/sched.h> | |
e2a5b420 AS |
16 | #include <linux/sysdev.h> |
17 | #include <asm/io.h> | |
1da177e4 LT |
18 | #include "sleep.h" |
19 | ||
e2a5b420 AS |
20 | int acpi_sleep_prepare(u32 acpi_state) |
21 | { | |
e2a5b420 AS |
22 | #ifdef CONFIG_ACPI_SLEEP |
23 | /* do we have a wakeup address for S2 and S3? */ | |
24 | /* Here, we support only S4BIOS, those we set the wakeup address */ | |
25 | /* S4OS is only supported for now via swsusp.. */ | |
26 | if (acpi_state == ACPI_STATE_S3 || acpi_state == ACPI_STATE_S4) { | |
27 | if (!acpi_wakeup_address) { | |
28 | return -EFAULT; | |
29 | } | |
30 | acpi_set_firmware_waking_vector((acpi_physical_address) | |
31 | virt_to_phys((void *) | |
32 | acpi_wakeup_address)); | |
33 | ||
34 | } | |
35 | ACPI_FLUSH_CPU_CACHE(); | |
36 | acpi_enable_wakeup_device_prep(acpi_state); | |
37 | #endif | |
38 | if (acpi_state == ACPI_STATE_S5) { | |
e2a5b420 | 39 | acpi_wakeup_gpe_poweroff_prepare(); |
e2a5b420 AS |
40 | } |
41 | acpi_enter_sleep_state_prep(acpi_state); | |
42 | return 0; | |
43 | } | |
44 | ||
b35c67a4 EB |
45 | #ifdef CONFIG_PM |
46 | ||
e2a5b420 | 47 | void acpi_power_off(void) |
1da177e4 | 48 | { |
b35c67a4 | 49 | /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ |
e2a5b420 | 50 | printk("%s called\n", __FUNCTION__); |
e2a5b420 | 51 | local_irq_disable(); |
1da177e4 | 52 | /* Some SMP machines only can poweroff in boot CPU */ |
1da177e4 LT |
53 | acpi_enter_sleep_state(ACPI_STATE_S5); |
54 | } | |
55 | ||
e2a5b420 AS |
56 | static int acpi_shutdown(struct sys_device *x) |
57 | { | |
58 | return acpi_sleep_prepare(ACPI_STATE_S5); | |
59 | } | |
60 | ||
61 | static struct sysdev_class acpi_sysclass = { | |
62 | set_kset_name("acpi"), | |
63 | .shutdown = acpi_shutdown | |
64 | }; | |
65 | ||
66 | static struct sys_device device_acpi = { | |
67 | .id = 0, | |
68 | .cls = &acpi_sysclass, | |
69 | }; | |
70 | ||
1da177e4 LT |
71 | static int acpi_poweroff_init(void) |
72 | { | |
73 | if (!acpi_disabled) { | |
74 | u8 type_a, type_b; | |
75 | acpi_status status; | |
76 | ||
e2a5b420 AS |
77 | status = |
78 | acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); | |
79 | if (ACPI_SUCCESS(status)) { | |
b35c67a4 EB |
80 | int error; |
81 | error = sysdev_class_register(&acpi_sysclass); | |
82 | if (!error) | |
83 | error = sysdev_register(&device_acpi); | |
84 | if (!error) | |
85 | pm_power_off = acpi_power_off; | |
86 | return error; | |
e2a5b420 | 87 | } |
1da177e4 LT |
88 | } |
89 | return 0; | |
90 | } | |
91 | ||
92 | late_initcall(acpi_poweroff_init); | |
b35c67a4 | 93 | |
4be44fcd | 94 | #endif /* CONFIG_PM */ |