diff options
author | Lv Zheng <lv.zheng@intel.com> | 2016-06-01 06:10:48 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-06-21 20:10:17 -0400 |
commit | 3540c32a9ae4cb23ab70f7798f45affc02762fa7 (patch) | |
tree | 77bb6a7d07af7a2afa75ca4c86e5f1b35499f150 /drivers/acpi/button.c | |
parent | ee7e22653f5077169ec706b5a140a3be9db381e7 (diff) |
ACPI / button: Add quirks for initial lid state notification
Linux userspace (systemd-logind) keeps on rechecking lid state when the
lid state is closed. If it failed to update the lid state to open after
boot/resume, the system suspending right after the boot/resume could be
resulted.
Graphics drivers also use the lid notifications to implment
MODESET_ON_LID_OPEN option.
Before the situation is improved from the userspace and from the graphics
driver, users can simply configure ACPI button driver to send initial
"open" lid state using button.lid_init_state=open to avoid such kind of
issues.
And our ultimate target should be making button.lid_init_state=ignore
the default behavior. This patch implements the 2 options and keep the
old behavior (button.lid_init_state=method).
Link: https://lkml.org/2016/3/7/460
Link: https://github.com/systemd/systemd/issues/2087
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/button.c')
-rw-r--r-- | drivers/acpi/button.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 6e291c17e43a..148f4e5ca104 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c | |||
@@ -53,6 +53,10 @@ | |||
53 | #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" | 53 | #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" |
54 | #define ACPI_BUTTON_TYPE_LID 0x05 | 54 | #define ACPI_BUTTON_TYPE_LID 0x05 |
55 | 55 | ||
56 | #define ACPI_BUTTON_LID_INIT_IGNORE 0x00 | ||
57 | #define ACPI_BUTTON_LID_INIT_OPEN 0x01 | ||
58 | #define ACPI_BUTTON_LID_INIT_METHOD 0x02 | ||
59 | |||
56 | #define _COMPONENT ACPI_BUTTON_COMPONENT | 60 | #define _COMPONENT ACPI_BUTTON_COMPONENT |
57 | ACPI_MODULE_NAME("button"); | 61 | ACPI_MODULE_NAME("button"); |
58 | 62 | ||
@@ -105,6 +109,7 @@ struct acpi_button { | |||
105 | 109 | ||
106 | static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); | 110 | static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); |
107 | static struct acpi_device *lid_device; | 111 | static struct acpi_device *lid_device; |
112 | static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; | ||
108 | 113 | ||
109 | /* -------------------------------------------------------------------------- | 114 | /* -------------------------------------------------------------------------- |
110 | FS Interface (/proc) | 115 | FS Interface (/proc) |
@@ -285,6 +290,21 @@ static int acpi_lid_update_state(struct acpi_device *device) | |||
285 | return acpi_lid_notify_state(device, state); | 290 | return acpi_lid_notify_state(device, state); |
286 | } | 291 | } |
287 | 292 | ||
293 | static void acpi_lid_initialize_state(struct acpi_device *device) | ||
294 | { | ||
295 | switch (lid_init_state) { | ||
296 | case ACPI_BUTTON_LID_INIT_OPEN: | ||
297 | (void)acpi_lid_notify_state(device, 1); | ||
298 | break; | ||
299 | case ACPI_BUTTON_LID_INIT_METHOD: | ||
300 | (void)acpi_lid_update_state(device); | ||
301 | break; | ||
302 | case ACPI_BUTTON_LID_INIT_IGNORE: | ||
303 | default: | ||
304 | break; | ||
305 | } | ||
306 | } | ||
307 | |||
288 | static void acpi_button_notify(struct acpi_device *device, u32 event) | 308 | static void acpi_button_notify(struct acpi_device *device, u32 event) |
289 | { | 309 | { |
290 | struct acpi_button *button = acpi_driver_data(device); | 310 | struct acpi_button *button = acpi_driver_data(device); |
@@ -341,6 +361,8 @@ static int acpi_button_resume(struct device *dev) | |||
341 | struct acpi_button *button = acpi_driver_data(device); | 361 | struct acpi_button *button = acpi_driver_data(device); |
342 | 362 | ||
343 | button->suspended = false; | 363 | button->suspended = false; |
364 | if (button->type == ACPI_BUTTON_TYPE_LID) | ||
365 | acpi_lid_initialize_state(device); | ||
344 | return 0; | 366 | return 0; |
345 | } | 367 | } |
346 | #endif | 368 | #endif |
@@ -421,6 +443,7 @@ static int acpi_button_add(struct acpi_device *device) | |||
421 | if (error) | 443 | if (error) |
422 | goto err_remove_fs; | 444 | goto err_remove_fs; |
423 | if (button->type == ACPI_BUTTON_TYPE_LID) { | 445 | if (button->type == ACPI_BUTTON_TYPE_LID) { |
446 | acpi_lid_initialize_state(device); | ||
424 | /* | 447 | /* |
425 | * This assumes there's only one lid device, or if there are | 448 | * This assumes there's only one lid device, or if there are |
426 | * more we only care about the last one... | 449 | * more we only care about the last one... |
@@ -450,4 +473,42 @@ static int acpi_button_remove(struct acpi_device *device) | |||
450 | return 0; | 473 | return 0; |
451 | } | 474 | } |
452 | 475 | ||
476 | static int param_set_lid_init_state(const char *val, struct kernel_param *kp) | ||
477 | { | ||
478 | int result = 0; | ||
479 | |||
480 | if (!strncmp(val, "open", sizeof("open") - 1)) { | ||
481 | lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; | ||
482 | pr_info("Notify initial lid state as open\n"); | ||
483 | } else if (!strncmp(val, "method", sizeof("method") - 1)) { | ||
484 | lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; | ||
485 | pr_info("Notify initial lid state with _LID return value\n"); | ||
486 | } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) { | ||
487 | lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE; | ||
488 | pr_info("Do not notify initial lid state\n"); | ||
489 | } else | ||
490 | result = -EINVAL; | ||
491 | return result; | ||
492 | } | ||
493 | |||
494 | static int param_get_lid_init_state(char *buffer, struct kernel_param *kp) | ||
495 | { | ||
496 | switch (lid_init_state) { | ||
497 | case ACPI_BUTTON_LID_INIT_OPEN: | ||
498 | return sprintf(buffer, "open"); | ||
499 | case ACPI_BUTTON_LID_INIT_METHOD: | ||
500 | return sprintf(buffer, "method"); | ||
501 | case ACPI_BUTTON_LID_INIT_IGNORE: | ||
502 | return sprintf(buffer, "ignore"); | ||
503 | default: | ||
504 | return sprintf(buffer, "invalid"); | ||
505 | } | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | module_param_call(lid_init_state, | ||
510 | param_set_lid_init_state, param_get_lid_init_state, | ||
511 | NULL, 0644); | ||
512 | MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state"); | ||
513 | |||
453 | module_acpi_driver(acpi_button_driver); | 514 | module_acpi_driver(acpi_button_driver); |