aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2012-05-09 19:08:43 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-29 15:20:23 -0400
commitc10d7a13846bffa5c77f1122500b687ab902e2d2 (patch)
tree0ccc77e7931cb6bda11cc4d24caaebf5aea28246 /drivers/acpi
parent76e10d158efb6d4516018846f60c2ab5501900bc (diff)
ACPI / PM: Generate wakeup events on fixed power button
When the system is woken up by the ACPI fixed power button, currently there is no way of userspace becoming aware that the power button was pressed. OLPC would like to know this, so that we can respond appropriately. For example, if the system was woken up by a network packet, we know we can go back to sleep very quickly. But if the user explicitly woke the system with the power button, we're going to want to stay awake for a while. The wakeup count mechanism seems like a good fit for communicating this. Mark the fixed power button as wakeup-enabled, and increment its wakeup counter when the system is woken with the power button. (The wakeup counter is also incremented when the power button is pressed during system operation; this is already handled by an existing acpi-button codepath). Signed-off-by: Daniel Drake <dsd@laptop.org> Acked-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/scan.c1
-rw-r--r--drivers/acpi/sleep.c45
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.");
57MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".); 57MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);
58 58
59static u8 sleep_states[ACPI_S_STATE_COUNT]; 59static u8 sleep_states[ACPI_S_STATE_COUNT];
60static bool pwr_btn_event_pending;
60 61
61static void acpi_sleep_tts_switch(u32 acpi_state) 62static 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
190static 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 */
195static void acpi_pm_finish(void) 204static 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