[PATCH 4/6] input: cyapa: enable/disable trackpad device based on LID state

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

 



Rely on EV_SW and SW_LID bits to identify a LID device, and hook
up our filter to listen for SW_LID events to enable/disable touchpad when
LID is open/closed.
TEST=test on Chomebooks.

Signed-off-by: Du, Dudley <dudl@xxxxxxxxxxx>
---
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index 6820b3f..da03427 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -523,6 +523,9 @@ struct cyapa {
        int physical_size_x;
        int physical_size_y;

+       bool lid_handler_registered;
+       struct input_handler lid_handler;
+
        /* used in ttsp and truetouch based trackpad devices. */
        u8 x_origin;  /* X Axis Origin: 0 = left side; 1 = rigth side. */
        u8 y_origin;  /* Y Axis Origin: 0 = top; 1 = bottom. */
@@ -3107,6 +3110,125 @@ static void cyapa_start_runtime(struct cyapa *cyapa)
 static void cyapa_start_runtime(struct cyapa *cyapa) {}
 #endif /* CONFIG_PM_RUNTIME */

+
+/*
+ * We rely on EV_SW and SW_LID bits to identify a LID device, and hook
+ * up our filter to listen for SW_LID events to enable/disable touchpad when
+ * LID is open/closed.
+ */
+static const struct input_device_id lid_device_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+                        INPUT_DEVICE_ID_MATCH_SWBIT,
+               .evbit = { BIT_MASK(EV_SW) },
+               .swbit = { BIT_MASK(SW_LID) },
+       },
+       { },
+};
+
+static int lid_device_connect(struct input_handler *handler,
+                             struct input_dev *dev,
+                             const struct input_device_id *id)
+{
+       struct input_handle *lid_handle;
+       int error;
+
+       lid_handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!lid_handle)
+               return -ENOMEM;
+
+       lid_handle->dev = dev;
+       lid_handle->handler = handler;
+       lid_handle->name = "lid_event_handler";
+       lid_handle->private = handler->private;
+
+       error = input_register_handle(lid_handle);
+       if (error)
+               goto err_free;
+
+       error = input_open_device(lid_handle);
+       if (error)
+               goto err_unregister;
+
+       return 0;
+err_unregister:
+       input_unregister_handle(lid_handle);
+err_free:
+       kfree(lid_handle);
+       return error;
+}
+
+static void lid_device_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       input_unregister_handle(handle);
+       kfree(handle);
+}
+
+static bool lid_event_filter(struct input_handle *handle,
+                            unsigned int type, unsigned int code, int value)
+{
+       struct cyapa *cyapa = handle->private;
+       struct device *dev = &cyapa->client->dev;
+
+       if (type == EV_SW && code == SW_LID) {
+               if (cyapa->suspended) {
+                       /*
+                        * If the lid event filter is called while suspended,
+                        * there is no guarantee that the underlying i2cs are
+                        * resumed at this point, so it is not safe to issue
+                        * the command to change power modes.
+                        * Instead, rely on cyapa_resume to set us back to
+                        * PWR_MODE_FULL_ACTIVE.
+                        */
+                       return false;
+               }
+               if (value == 0) {
+                       if (cyapa->cyapa_set_power_mode)
+                               cyapa->cyapa_set_power_mode(cyapa,
+                                               PWR_MODE_FULL_ACTIVE, 0);
+                       pm_runtime_set_active(dev);
+                       pm_runtime_enable(dev);
+               } else {
+                       pm_runtime_disable(dev);
+                       if (cyapa->cyapa_set_power_mode)
+                               cyapa->cyapa_set_power_mode(cyapa,
+                                               PWR_MODE_OFF, 0);
+               }
+       }
+
+       return false;
+}
+
+static void lid_event_register_handler(struct cyapa *cyapa)
+{
+       int error;
+       struct input_handler *lid_handler = &cyapa->lid_handler;
+
+       if (cyapa->lid_handler_registered)
+               return;
+
+       lid_handler->filter     = lid_event_filter;
+       lid_handler->connect    = lid_device_connect;
+       lid_handler->disconnect = lid_device_disconnect;
+       lid_handler->name       = "cyapa_lid_event_handler";
+       lid_handler->id_table   = lid_device_ids;
+       lid_handler->private    = cyapa;
+
+       error = input_register_handler(lid_handler);
+       if (error)
+               return;
+       cyapa->lid_handler_registered = true;
+}
+
+static void lid_event_unregister_handler(struct cyapa *cyapa)
+{
+       if (cyapa->lid_handler_registered) {
+               input_unregister_handler(&cyapa->lid_handler);
+               cyapa->lid_handler_registered = false;
+       }
+}
+
 static void cyapa_detect_async(void *data, async_cookie_t cookie)
 {
        struct cyapa *cyapa = (struct cyapa *)data;
@@ -3126,6 +3248,7 @@ static void cyapa_detect_and_start(void *data, async_cookie_t cookie)
        cyapa_detect_async(data, cookie);

        cyapa_start_runtime(cyapa);
+       lid_event_register_handler(cyapa);
 }

 static int cyapa_probe(struct i2c_client *client,
@@ -3221,7 +3344,7 @@ static int cyapa_remove(struct i2c_client *client)

        free_irq(cyapa->irq, cyapa);
        input_unregister_device(cyapa->input);
-
+       lid_event_unregister_handler(cyapa);
        if (cyapa->cyapa_set_power_mode)
                cyapa->cyapa_set_power_mode(cyapa, PWR_MODE_OFF, 0);
        i2c_set_clientdata(client, NULL);
This message and any attachments may contain Cypress (or its subsidiaries) confidential information. If it has been received in error, please advise the sender and immediately delete this message.

<<attachment: winmail.dat>>


[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