diff options
author | Hans de Goede <hdegoede@redhat.com> | 2017-09-11 10:07:06 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-11-08 18:30:44 -0500 |
commit | 84d3f6b76447896919c63b28ad71f71238cefcce (patch) | |
tree | 0ee00fa0c6532ba48342e55011e38b972774a79c /drivers/acpi/button.c | |
parent | 39dae59d66acd86d1de24294bd2f343fd5e7a625 (diff) |
ACPI / button: Delay acpi_lid_initialize_state() until first user space open
ACPI _LID methods may depend on OpRegions and do not always handle
handlers for those OpRegions not being present properly e.g. :
Method (_LID, 0, NotSerialized) // _LID: Lid Status
{
If ((^^I2C5.PMI1.AVBL == One) && (^^GPO2.AVBL == One))
{
Return (^^GPO2.LPOL) /* \_SB_.GPO2.LPOL */
}
}
Note the missing Return (1) when either of the OpRegions is not available,
this causes (in this case) a report of the lid-switch being closed,
which causes userspace to do an immediate suspend at boot.
This commit delays getting the initial state and thus calling _LID for
the first time until userspace opens the /dev/input/event# node. This
ensures that all drivers will have had a chance to load and registerer
their OpRegions before the first _LID call, fixing this issue.
Signed-off-by: Hans de Goede <hdegoede@redhat.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 | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index ef1856b15488..c391898b483c 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c | |||
@@ -390,6 +390,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) | |||
390 | { | 390 | { |
391 | struct acpi_button *button = acpi_driver_data(device); | 391 | struct acpi_button *button = acpi_driver_data(device); |
392 | struct input_dev *input; | 392 | struct input_dev *input; |
393 | int users; | ||
393 | 394 | ||
394 | switch (event) { | 395 | switch (event) { |
395 | case ACPI_FIXED_HARDWARE_EVENT: | 396 | case ACPI_FIXED_HARDWARE_EVENT: |
@@ -398,7 +399,11 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) | |||
398 | case ACPI_BUTTON_NOTIFY_STATUS: | 399 | case ACPI_BUTTON_NOTIFY_STATUS: |
399 | input = button->input; | 400 | input = button->input; |
400 | if (button->type == ACPI_BUTTON_TYPE_LID) { | 401 | if (button->type == ACPI_BUTTON_TYPE_LID) { |
401 | acpi_lid_update_state(device); | 402 | mutex_lock(&button->input->mutex); |
403 | users = button->input->users; | ||
404 | mutex_unlock(&button->input->mutex); | ||
405 | if (users) | ||
406 | acpi_lid_update_state(device); | ||
402 | } else { | 407 | } else { |
403 | int keycode; | 408 | int keycode; |
404 | 409 | ||
@@ -442,12 +447,24 @@ static int acpi_button_resume(struct device *dev) | |||
442 | struct acpi_button *button = acpi_driver_data(device); | 447 | struct acpi_button *button = acpi_driver_data(device); |
443 | 448 | ||
444 | button->suspended = false; | 449 | button->suspended = false; |
445 | if (button->type == ACPI_BUTTON_TYPE_LID) | 450 | if (button->type == ACPI_BUTTON_TYPE_LID && button->input->users) |
446 | acpi_lid_initialize_state(device); | 451 | acpi_lid_initialize_state(device); |
447 | return 0; | 452 | return 0; |
448 | } | 453 | } |
449 | #endif | 454 | #endif |
450 | 455 | ||
456 | static int acpi_lid_input_open(struct input_dev *input) | ||
457 | { | ||
458 | struct acpi_device *device = input_get_drvdata(input); | ||
459 | struct acpi_button *button = acpi_driver_data(device); | ||
460 | |||
461 | button->last_state = !!acpi_lid_evaluate_state(device); | ||
462 | button->last_time = ktime_get(); | ||
463 | acpi_lid_initialize_state(device); | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
451 | static int acpi_button_add(struct acpi_device *device) | 468 | static int acpi_button_add(struct acpi_device *device) |
452 | { | 469 | { |
453 | struct acpi_button *button; | 470 | struct acpi_button *button; |
@@ -488,8 +505,7 @@ static int acpi_button_add(struct acpi_device *device) | |||
488 | strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID); | 505 | strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID); |
489 | sprintf(class, "%s/%s", | 506 | sprintf(class, "%s/%s", |
490 | ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); | 507 | ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); |
491 | button->last_state = !!acpi_lid_evaluate_state(device); | 508 | input->open = acpi_lid_input_open; |
492 | button->last_time = ktime_get(); | ||
493 | } else { | 509 | } else { |
494 | printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid); | 510 | printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid); |
495 | error = -ENODEV; | 511 | error = -ENODEV; |
@@ -522,11 +538,11 @@ static int acpi_button_add(struct acpi_device *device) | |||
522 | break; | 538 | break; |
523 | } | 539 | } |
524 | 540 | ||
541 | input_set_drvdata(input, device); | ||
525 | error = input_register_device(input); | 542 | error = input_register_device(input); |
526 | if (error) | 543 | if (error) |
527 | goto err_remove_fs; | 544 | goto err_remove_fs; |
528 | if (button->type == ACPI_BUTTON_TYPE_LID) { | 545 | if (button->type == ACPI_BUTTON_TYPE_LID) { |
529 | acpi_lid_initialize_state(device); | ||
530 | /* | 546 | /* |
531 | * This assumes there's only one lid device, or if there are | 547 | * This assumes there's only one lid device, or if there are |
532 | * more we only care about the last one... | 548 | * more we only care about the last one... |