Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751591AbdFASrQ (ORCPT ); Thu, 1 Jun 2017 14:47:16 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58054 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751460AbdFASrN (ORCPT ); Thu, 1 Jun 2017 14:47:13 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 7086E7E9C3 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=benjamin.tissoires@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 7086E7E9C3 From: Benjamin Tissoires To: Lv Zheng , "Rafael J . Wysocki" , "Rafael J . Wysocki" , Len Brown , Lv Zheng , Peter Hutterer Cc: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, systemd-devel@lists.freedesktop.org, linux-input@vger.kernel.org, Benjamin Tissoires Subject: [WIP PATCH 3/4] ACPI: button: Let input filter out the LID events Date: Thu, 1 Jun 2017 20:46:31 +0200 Message-Id: <20170601184632.2980-4-benjamin.tissoires@redhat.com> In-Reply-To: <20170601184632.2980-1-benjamin.tissoires@redhat.com> References: <20170601184632.2980-1-benjamin.tissoires@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Thu, 01 Jun 2017 18:47:12 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5540 Lines: 211 The input stack already filters out the LID events. So instead of filtering them out at the source, we can hook up after the input processing and propagate the lid switch events when the input stack tells us to. An other benefit is that if userspace (think libinput) "fixes" the lid switch state by some heuristics, this new state is forwarded to the listeners in the kernel. Signed-off-by: Benjamin Tissoires --- drivers/acpi/button.c | 156 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 9ad7604..03e5981 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -109,8 +109,6 @@ struct acpi_button { struct input_dev *input; char phys[32]; /* for input device */ unsigned long pushed; - int last_state; - ktime_t last_time; bool suspended; }; @@ -184,7 +182,6 @@ static int acpi_lid_evaluate_state(struct acpi_device *device) static int acpi_lid_notify_state(struct acpi_device *device, int state) { struct acpi_button *button = acpi_driver_data(device); - int ret; /* button_input_lock must be held */ @@ -205,20 +202,129 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) if (state) pm_wakeup_hard_event(&device->dev); - ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); - if (ret == NOTIFY_DONE) - ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, - device); - if (ret == NOTIFY_DONE || ret == NOTIFY_OK) { - /* - * It is also regarded as success if the notifier_chain - * returns NOTIFY_OK or NOTIFY_DONE. - */ - ret = 0; + return 0; +} + +/* + * Pass incoming event to all connected clients. + */ +static void acpi_button_lid_events(struct input_handle *handle, + const struct input_value *vals, + unsigned int count) +{ + const struct input_value *v; + int state = -1; + int ret; + + for (v = vals; v != vals + count; v++) { + switch (v->type) { + case EV_SYN: + if (v->code == SYN_REPORT && state >= 0) { + ret = blocking_notifier_call_chain(&acpi_lid_notifier, + state, + lid_device); + if (ret == NOTIFY_DONE) + ret = blocking_notifier_call_chain(&acpi_lid_notifier, + state, + lid_device); + if (ret == NOTIFY_DONE || ret == NOTIFY_OK) { + /* + * It is also regarded as success if + * the notifier_chain returns NOTIFY_OK + * or NOTIFY_DONE. + */ + ret = 0; + } + } + break; + case EV_SW: + if (v->code == SW_LID) + state = !v->value; + break; + } } - return ret; } +static int acpi_button_lid_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "acpi-button-lid"; + + error = input_register_handle(handle); + if (error) { + dev_err(&lid_device->dev, "Error installing input handle\n"); + goto err_free; + } + + error = input_open_device(handle); + if (error) { + dev_err(&lid_device->dev, "Failed to open input device\n"); + goto err_unregister; + } + + return 0; + + err_unregister: + input_unregister_handle(handle); + err_free: + kfree(handle); + return error; +} + +static void acpi_button_lid_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +bool acpi_button_lid_match(struct input_handler *handler, + struct input_dev *dev) +{ + struct acpi_button *button; + + if (!lid_device) + return false; + + button = acpi_driver_data(lid_device); + + if (dev != button->input) + return false; + + return true; +} + +static const struct input_device_id acpi_button_lid_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_SW) }, + .swbit = { BIT_MASK(SW_LID) }, + }, + { }, +}; + +MODULE_DEVICE_TABLE(input, acpi_button_lid_ids); + +static struct input_handler acpi_button_lid_handler = { + .match = acpi_button_lid_match, + .connect = acpi_button_lid_connect, + .disconnect = acpi_button_lid_disconnect, + .events = acpi_button_lid_events, + .name = "acpi-lid-callchain", + .id_table = acpi_button_lid_ids, +}; + + static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) { struct acpi_device *device = seq->private; @@ -581,8 +687,6 @@ 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); - button->last_state = !!acpi_lid_evaluate_state(device); - button->last_time = ktime_get(); } else { printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid); error = -ENODEV; @@ -674,4 +778,22 @@ module_param_call(lid_init_state, NULL, 0644); MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state"); -module_acpi_driver(acpi_button_driver); +static int __init acpi_button_init(void) +{ + int error; + + error = input_register_handler(&acpi_button_lid_handler); + if (error) + return error; + + return acpi_bus_register_driver(&acpi_button_driver); +} + +static void __exit acpi_button_exit(void) +{ + acpi_bus_unregister_driver(&acpi_button_driver); + input_unregister_handler(&acpi_button_lid_handler); +} + +module_init(acpi_button_init); +module_exit(acpi_button_exit); -- 2.9.4