diff options
author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-13 15:25:59 +0100 |
---|---|---|
committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-13 15:25:59 +0100 |
commit | 30beab1491f0b96b2f23d3fb68af01fd921a16d8 (patch) | |
tree | c580bdc0846269fbb10feeda901ecec1a48ee2ef /drivers/acpi/sleep/poweroff.c | |
parent | 21af6c4f2aa5f63138871b4ddd77d7ebf2588c9d (diff) | |
parent | c32511e2718618f0b53479eb36e07439aa363a74 (diff) |
Merge with /shiny/git/linux-2.6/.git
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 da237754ded..1fc86e6b5ab 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -3,35 +3,100 @@ * * AKA S5, but it is independent of whether or not the kernel supports * any other sleep support in the system. + * + * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> + * + * This file is released under the GPLv2. */ #include <linux/pm.h> #include <linux/init.h> #include <acpi/acpi_bus.h> #include <linux/sched.h> +#include <linux/sysdev.h> +#include <asm/io.h> #include "sleep.h" -static void -acpi_power_off (void) +int acpi_sleep_prepare(u32 acpi_state) +{ + /* Flag to do not allow second time invocation for S5 state */ + static int shutdown_prepared = 0; +#ifdef CONFIG_ACPI_SLEEP + /* do we have a wakeup address for S2 and S3? */ + /* Here, we support only S4BIOS, those we set the wakeup address */ + /* S4OS is only supported for now via swsusp.. */ + if (acpi_state == ACPI_STATE_S3 || acpi_state == ACPI_STATE_S4) { + if (!acpi_wakeup_address) { + return -EFAULT; + } + acpi_set_firmware_waking_vector((acpi_physical_address) + virt_to_phys((void *) + acpi_wakeup_address)); + + } + ACPI_FLUSH_CPU_CACHE(); + acpi_enable_wakeup_device_prep(acpi_state); +#endif + if (acpi_state == ACPI_STATE_S5) { + /* Check if we were already called */ + if (shutdown_prepared) + return 0; + acpi_wakeup_gpe_poweroff_prepare(); + shutdown_prepared = 1; + } + acpi_enter_sleep_state_prep(acpi_state); + return 0; +} + +void acpi_power_off(void) { - printk("%s called\n",__FUNCTION__); + printk("%s called\n", __FUNCTION__); + acpi_sleep_prepare(ACPI_STATE_S5); + local_irq_disable(); /* Some SMP machines only can poweroff in boot CPU */ set_cpus_allowed(current, cpumask_of_cpu(0)); - acpi_wakeup_gpe_poweroff_prepare(); - acpi_enter_sleep_state_prep(ACPI_STATE_S5); - ACPI_DISABLE_IRQS(); acpi_enter_sleep_state(ACPI_STATE_S5); } +#ifdef CONFIG_PM + +static int acpi_shutdown(struct sys_device *x) +{ + return acpi_sleep_prepare(ACPI_STATE_S5); +} + +static struct sysdev_class acpi_sysclass = { + set_kset_name("acpi"), + .shutdown = acpi_shutdown +}; + +static struct sys_device device_acpi = { + .id = 0, + .cls = &acpi_sysclass, +}; + +#endif + static int acpi_poweroff_init(void) { if (!acpi_disabled) { u8 type_a, type_b; acpi_status status; - status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); - if (ACPI_SUCCESS(status)) + status = + acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); + if (ACPI_SUCCESS(status)) { pm_power_off = acpi_power_off; +#ifdef CONFIG_PM + { + int error; + error = sysdev_class_register(&acpi_sysclass); + if (!error) + error = sysdev_register(&device_acpi); + return error; + } +#endif + } } return 0; } |