From: Wei-Ning Huang <wnhu...@chromium.org>

ACPI PNP device HID 'PNP0C60' is a device that indicates tablet mode
status. Add support for mapping this device to the SW_TABLET_MODE input
event.

Signed-off-by: Wei-Ning Huang <wnhu...@chromium.org>
---
 drivers/acpi/button.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 148f4e5..50e9de6 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -53,6 +53,11 @@
 #define ACPI_BUTTON_DEVICE_NAME_LID    "Lid Switch"
 #define ACPI_BUTTON_TYPE_LID           0x05
 
+#define ACPI_BUTTON_SUBCLASS_TABLET    "tablet"
+#define ACPI_BUTTON_HID_TABLET         "PNP0C60"
+#define ACPI_BUTTON_DEVICE_NAME_TABLET "Tablet Mode Switch"
+#define ACPI_BUTTON_TYPE_TABLET                0x07
+
 #define ACPI_BUTTON_LID_INIT_IGNORE    0x00
 #define ACPI_BUTTON_LID_INIT_OPEN      0x01
 #define ACPI_BUTTON_LID_INIT_METHOD    0x02
@@ -70,6 +75,7 @@ static const struct acpi_device_id button_device_ids[] = {
        {ACPI_BUTTON_HID_SLEEPF, 0},
        {ACPI_BUTTON_HID_POWER,  0},
        {ACPI_BUTTON_HID_POWERF, 0},
+       {ACPI_BUTTON_HID_TABLET, 0},
        {"", 0},
 };
 MODULE_DEVICE_TABLE(acpi, button_device_ids);
@@ -305,6 +311,23 @@ static void acpi_lid_initialize_state(struct acpi_device 
*device)
        }
 }
 
+static int acpi_tablet_send_state(struct acpi_device *device)
+{
+       struct acpi_button *button = acpi_driver_data(device);
+       unsigned long long state;
+       acpi_status status;
+
+       status = acpi_evaluate_integer(device->handle, "_TBL", NULL, &state);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       /* input layer checks if event is redundant */
+       input_report_switch(button->input, SW_TABLET_MODE, state);
+       input_sync(button->input);
+
+       return 0;
+}
+
 static void acpi_button_notify(struct acpi_device *device, u32 event)
 {
        struct acpi_button *button = acpi_driver_data(device);
@@ -318,6 +341,8 @@ static void acpi_button_notify(struct acpi_device *device, 
u32 event)
                input = button->input;
                if (button->type == ACPI_BUTTON_TYPE_LID) {
                        acpi_lid_update_state(device);
+               } else if (button->type == ACPI_BUTTON_TYPE_TABLET) {
+                       acpi_tablet_send_state(device);
                } else {
                        int keycode;
 
@@ -407,6 +432,11 @@ static int acpi_button_add(struct acpi_device *device)
                strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID);
                sprintf(class, "%s/%s",
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
+       } else if (!strcmp(hid, ACPI_BUTTON_HID_TABLET)) {
+               button->type = ACPI_BUTTON_TYPE_TABLET;
+               strcpy(name, ACPI_BUTTON_DEVICE_NAME_TABLET);
+               sprintf(class, "%s/%s",
+                       ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_TABLET);
        } else {
                printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid);
                error = -ENODEV;
@@ -437,6 +467,10 @@ static int acpi_button_add(struct acpi_device *device)
        case ACPI_BUTTON_TYPE_LID:
                input_set_capability(input, EV_SW, SW_LID);
                break;
+
+       case ACPI_BUTTON_TYPE_TABLET:
+               input_set_capability(input, EV_SW, SW_TABLET_MODE);
+               break;
        }
 
        error = input_register_device(input);
@@ -450,6 +484,8 @@ static int acpi_button_add(struct acpi_device *device)
                 */
                lid_device = device;
        }
+       if (button->type == ACPI_BUTTON_TYPE_TABLET)
+               acpi_tablet_send_state(device);
 
        printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
        return 0;
-- 
2.8.0.rc3.226.g39d4020

Reply via email to