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>>