diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/scan.c | 1 | ||||
-rw-r--r-- | drivers/acpi/sleep.c | 45 |
2 files changed, 44 insertions, 2 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 85cbfdccc97c..c8a1f3b68110 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -1567,6 +1567,7 @@ static int acpi_bus_scan_fixed(void) | |||
1567 | ACPI_BUS_TYPE_POWER_BUTTON, | 1567 | ACPI_BUS_TYPE_POWER_BUTTON, |
1568 | ACPI_STA_DEFAULT, | 1568 | ACPI_STA_DEFAULT, |
1569 | &ops); | 1569 | &ops); |
1570 | device_init_wakeup(&device->dev, true); | ||
1570 | } | 1571 | } |
1571 | 1572 | ||
1572 | if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { | 1573 | if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { |
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index eb6fd233764b..a564fc3ffa1c 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -57,6 +57,7 @@ MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend."); | |||
57 | MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); | 57 | MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); |
58 | 58 | ||
59 | static u8 sleep_states[ACPI_S_STATE_COUNT]; | 59 | static u8 sleep_states[ACPI_S_STATE_COUNT]; |
60 | static bool pwr_btn_event_pending; | ||
60 | 61 | ||
61 | static void acpi_sleep_tts_switch(u32 acpi_state) | 62 | static void acpi_sleep_tts_switch(u32 acpi_state) |
62 | { | 63 | { |
@@ -186,6 +187,14 @@ static int acpi_pm_prepare(void) | |||
186 | return error; | 187 | return error; |
187 | } | 188 | } |
188 | 189 | ||
190 | static int find_powerf_dev(struct device *dev, void *data) | ||
191 | { | ||
192 | struct acpi_device *device = to_acpi_device(dev); | ||
193 | const char *hid = acpi_device_hid(device); | ||
194 | |||
195 | return !strcmp(hid, ACPI_BUTTON_HID_POWERF); | ||
196 | } | ||
197 | |||
189 | /** | 198 | /** |
190 | * acpi_pm_finish - Instruct the platform to leave a sleep state. | 199 | * acpi_pm_finish - Instruct the platform to leave a sleep state. |
191 | * | 200 | * |
@@ -194,6 +203,7 @@ static int acpi_pm_prepare(void) | |||
194 | */ | 203 | */ |
195 | static void acpi_pm_finish(void) | 204 | static void acpi_pm_finish(void) |
196 | { | 205 | { |
206 | struct device *pwr_btn_dev; | ||
197 | u32 acpi_state = acpi_target_sleep_state; | 207 | u32 acpi_state = acpi_target_sleep_state; |
198 | 208 | ||
199 | acpi_ec_unblock_transactions(); | 209 | acpi_ec_unblock_transactions(); |
@@ -211,6 +221,23 @@ static void acpi_pm_finish(void) | |||
211 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | 221 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); |
212 | 222 | ||
213 | acpi_target_sleep_state = ACPI_STATE_S0; | 223 | acpi_target_sleep_state = ACPI_STATE_S0; |
224 | |||
225 | /* If we were woken with the fixed power button, provide a small | ||
226 | * hint to userspace in the form of a wakeup event on the fixed power | ||
227 | * button device (if it can be found). | ||
228 | * | ||
229 | * We delay the event generation til now, as the PM layer requires | ||
230 | * timekeeping to be running before we generate events. */ | ||
231 | if (!pwr_btn_event_pending) | ||
232 | return; | ||
233 | |||
234 | pwr_btn_event_pending = false; | ||
235 | pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL, | ||
236 | find_powerf_dev); | ||
237 | if (pwr_btn_dev) { | ||
238 | pm_wakeup_event(pwr_btn_dev, 0); | ||
239 | put_device(pwr_btn_dev); | ||
240 | } | ||
214 | } | 241 | } |
215 | 242 | ||
216 | /** | 243 | /** |
@@ -300,9 +327,23 @@ static int acpi_suspend_enter(suspend_state_t pm_state) | |||
300 | /* ACPI 3.0 specs (P62) says that it's the responsibility | 327 | /* ACPI 3.0 specs (P62) says that it's the responsibility |
301 | * of the OSPM to clear the status bit [ implying that the | 328 | * of the OSPM to clear the status bit [ implying that the |
302 | * POWER_BUTTON event should not reach userspace ] | 329 | * POWER_BUTTON event should not reach userspace ] |
330 | * | ||
331 | * However, we do generate a small hint for userspace in the form of | ||
332 | * a wakeup event. We flag this condition for now and generate the | ||
333 | * event later, as we're currently too early in resume to be able to | ||
334 | * generate wakeup events. | ||
303 | */ | 335 | */ |
304 | if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) | 336 | if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) { |
305 | acpi_clear_event(ACPI_EVENT_POWER_BUTTON); | 337 | acpi_event_status pwr_btn_status; |
338 | |||
339 | acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status); | ||
340 | |||
341 | if (pwr_btn_status & ACPI_EVENT_FLAG_SET) { | ||
342 | acpi_clear_event(ACPI_EVENT_POWER_BUTTON); | ||
343 | /* Flag for later */ | ||
344 | pwr_btn_event_pending = true; | ||
345 | } | ||
346 | } | ||
306 | 347 | ||
307 | /* | 348 | /* |
308 | * Disable and clear GPE status before interrupt is enabled. Some GPEs | 349 | * Disable and clear GPE status before interrupt is enabled. Some GPEs |