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. 6 * 7 * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> 8 * 9 * This file is released under the GPLv2. 10 */ 11 12#include <linux/pm.h> 13#include <linux/init.h> 14#include <acpi/acpi_bus.h> 15#include <linux/sysdev.h> 16#include <asm/io.h> 17#include "sleep.h" 18 19int acpi_sleep_prepare(u32 acpi_state) 20{ 21#ifdef CONFIG_ACPI_SLEEP 22 /* do we have a wakeup address for S2 and S3? */ 23 if (acpi_state == ACPI_STATE_S3) { 24 if (!acpi_wakeup_address) { 25 return -EFAULT; 26 } 27 acpi_set_firmware_waking_vector((acpi_physical_address) 28 virt_to_phys((void *) 29 acpi_wakeup_address)); 30 31 } 32 ACPI_FLUSH_CPU_CACHE(); 33 acpi_enable_wakeup_device_prep(acpi_state); 34#endif 35 acpi_gpe_sleep_prepare(acpi_state); 36 acpi_enter_sleep_state_prep(acpi_state); 37 return 0; 38} 39 40#ifdef CONFIG_PM 41 42void acpi_power_off(void) 43{ 44 /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ 45 printk("%s called\n", __FUNCTION__); 46 local_irq_disable(); 47 /* Some SMP machines only can poweroff in boot CPU */ 48 acpi_enter_sleep_state(ACPI_STATE_S5); 49} 50 51static int acpi_shutdown(struct sys_device *x) 52{ 53 switch (system_state) { 54 case SYSTEM_POWER_OFF: 55 /* Prepare to power off the system */ 56 return acpi_sleep_prepare(ACPI_STATE_S5); 57 case SYSTEM_SUSPEND_DISK: 58 /* Prepare to suspend the system to disk */ 59 return acpi_sleep_prepare(ACPI_STATE_S4); 60 default: 61 return 0; 62 } 63} 64 65static struct sysdev_class acpi_sysclass = { 66 set_kset_name("acpi"), 67 .shutdown = acpi_shutdown 68}; 69 70static struct sys_device device_acpi = { 71 .id = 0, 72 .cls = &acpi_sysclass, 73}; 74 75static int acpi_poweroff_init(void) 76{ 77 if (!acpi_disabled) { 78 u8 type_a, type_b; 79 acpi_status status; 80 81 status = 82 acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); 83 if (ACPI_SUCCESS(status)) { 84 int error; 85 error = sysdev_class_register(&acpi_sysclass); 86 if (!error) 87 error = sysdev_register(&device_acpi); 88 if (!error) 89 pm_power_off = acpi_power_off; 90 return error; 91 } 92 } 93 return 0; 94} 95 96late_initcall(acpi_poweroff_init); 97 98#endif /* CONFIG_PM */ 99