[PATCH 4/5] ACPI / button: Add SW_ACPI_LID for new usage model

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



There are many AML tables reporting wrong initial lid state, and some of
them never reports lid state. As a proxy layer acting between, ACPI button
driver is not able to handle all such cases, but need to re-define the
usage model of the ACPI lid. That is:
1. It's initial state is not reliable;
2. There may not be open event;
3. Userspace should only take action against the close event which is
   reliable, always sent after a real lid close.

Link: https://lkml.org/2016/3/7/460
Link: https://github.com/systemd/systemd/issues/2087
Signed-off-by: Lv Zheng <lv.zheng@xxxxxxxxx>
Cc: Bastien Nocera: <hadess@xxxxxxxxxx>
Cc: Benjamin Tissoires <benjamin.tissoires@xxxxxxxxx>
Cc: linux-input@xxxxxxxxxxxxxxx
---
 Documentation/acpi/acpi-lid.txt        |   42 ++++++++++++++++++++++++++++++++
 drivers/acpi/button.c                  |   20 ++++++++++-----
 include/linux/mod_devicetable.h        |    2 +-
 include/uapi/linux/input-event-codes.h |    3 ++-
 4 files changed, 59 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/acpi/acpi-lid.txt

diff --git a/Documentation/acpi/acpi-lid.txt b/Documentation/acpi/acpi-lid.txt
new file mode 100644
index 0000000..cba200d
--- /dev/null
+++ b/Documentation/acpi/acpi-lid.txt
@@ -0,0 +1,42 @@
+Restrictions of ACPI Control Method LID Device
+
+1. Expections of _LID control method's returning value
+
+The _LID control method is described to return the "current" lid state.
+However the word of "current" has ambiguity, many BIOSen return the lid
+state upon the last lid notification instead of returning the lid state
+upon the last _LID evaluation. There won't be difference when the _LID
+control method is evaluated during the runtime, the problem is its initial
+returning value. When the BIOSen implement this control method with cached
+value, the initial returning value is likely not reliable. There are simply
+so many examples always retuning "close" as initial lid state.
+
+2. Expections on lid events
+
+There are many BIOSen tables never notifying the lid open event. But it is
+ensured that there is always lid close events reported when the lid is
+closed. This is normally used to trigger system power saving operations on
+Windows, thus it is fully tested and functions correctly.
+
+3. Linux ACPI Control Method LID Device Users
+
+The userspace should stop relying on /proc/acpi/button/lid/LID0/state to
+obtain the lid state. This file is only used for the testing purpose.
+
+New userspace should rely on the lid close event to trigger power saving
+operations and may stop taking actions according to the lid open event. A
+new input event SW_ACPI_LID is prepared for the new userspace to implement
+the ACPI control method lid device specific logics.
+
+During the period the userspace hasn't been switched to use the new
+SW_ACPI_LID event, Linux users can use the following boot parameter to
+handle possible issues:
+  button.lid_init_state=method:
+   This is the default behavior, Linux kernel reports initial lid state
+   using _LID control method's returning value.
+   This may fixes some platforms if the _LID control method's returning
+   value is reliable.
+  button.lid_init_state=open:
+   Linux kernel always reports an initial lid state as "open".
+   This may fixes some platforms if the _LID control method's returning
+   value is not reliable.
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 148f4e5..4ef94d2 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -130,7 +130,8 @@ static int acpi_lid_evaluate_state(struct acpi_device *device)
 	return lid_state ? 1 : 0;
 }
 
-static int acpi_lid_notify_state(struct acpi_device *device, int state)
+static int acpi_lid_notify_state(struct acpi_device *device,
+				 int state, bool notify_acpi)
 {
 	struct acpi_button *button = acpi_driver_data(device);
 	int ret;
@@ -138,6 +139,11 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state)
 	/* input layer checks if event is redundant */
 	input_report_switch(button->input, SW_LID, !state);
 	input_sync(button->input);
+	if (notify_acpi) {
+		input_report_switch(button->input,
+				    SW_ACPI_LID, !state);
+		input_sync(button->input);
+	}
 
 	if (state)
 		pm_wakeup_event(&device->dev, 0);
@@ -279,7 +285,8 @@ int acpi_lid_open(void)
 }
 EXPORT_SYMBOL(acpi_lid_open);
 
-static int acpi_lid_update_state(struct acpi_device *device)
+static int acpi_lid_update_state(struct acpi_device *device,
+				 bool notify_acpi)
 {
 	int state;
 
@@ -287,17 +294,17 @@ static int acpi_lid_update_state(struct acpi_device *device)
 	if (state < 0)
 		return state;
 
-	return acpi_lid_notify_state(device, state);
+	return acpi_lid_notify_state(device, state, notify_acpi);
 }
 
 static void acpi_lid_initialize_state(struct acpi_device *device)
 {
 	switch (lid_init_state) {
 	case ACPI_BUTTON_LID_INIT_OPEN:
-		(void)acpi_lid_notify_state(device, 1);
+		(void)acpi_lid_notify_state(device, 1, false);
 		break;
 	case ACPI_BUTTON_LID_INIT_METHOD:
-		(void)acpi_lid_update_state(device);
+		(void)acpi_lid_update_state(device, false);
 		break;
 	case ACPI_BUTTON_LID_INIT_IGNORE:
 	default:
@@ -317,7 +324,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
 	case ACPI_BUTTON_NOTIFY_STATUS:
 		input = button->input;
 		if (button->type == ACPI_BUTTON_TYPE_LID) {
-			acpi_lid_update_state(device);
+			acpi_lid_update_state(device, true);
 		} else {
 			int keycode;
 
@@ -436,6 +443,7 @@ static int acpi_button_add(struct acpi_device *device)
 
 	case ACPI_BUTTON_TYPE_LID:
 		input_set_capability(input, EV_SW, SW_LID);
+		input_set_capability(input, EV_SW, SW_ACPI_LID);
 		break;
 	}
 
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 6e4c645..1014968 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -291,7 +291,7 @@ struct pcmcia_device_id {
 #define INPUT_DEVICE_ID_LED_MAX		0x0f
 #define INPUT_DEVICE_ID_SND_MAX		0x07
 #define INPUT_DEVICE_ID_FF_MAX		0x7f
-#define INPUT_DEVICE_ID_SW_MAX		0x0f
+#define INPUT_DEVICE_ID_SW_MAX		0x10
 
 #define INPUT_DEVICE_ID_MATCH_BUS	1
 #define INPUT_DEVICE_ID_MATCH_VENDOR	2
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index 737fa32..81c344c 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -780,7 +780,8 @@
 #define SW_ROTATE_LOCK		0x0c  /* set = rotate locked/disabled */
 #define SW_LINEIN_INSERT	0x0d  /* set = inserted */
 #define SW_MUTE_DEVICE		0x0e  /* set = device disabled */
-#define SW_MAX			0x0f
+#define SW_ACPI_LID		0x0f  /* set = lid shut */
+#define SW_MAX			0x10
 #define SW_CNT			(SW_MAX+1)
 
 /*
-- 
1.7.10

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux