From patchwork Thu Jun 1 18:46:31 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Tissoires X-Patchwork-Id: 9760861 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A98BC60375 for ; Thu, 1 Jun 2017 18:48:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 86AB928526 for ; Thu, 1 Jun 2017 18:48:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7B5012852B; Thu, 1 Jun 2017 18:48:05 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 081D128517 for ; Thu, 1 Jun 2017 18:48:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751576AbdFASrP (ORCPT ); Thu, 1 Jun 2017 14:47:15 -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 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7086E7E9C3; Thu, 1 Jun 2017 18:47:12 +0000 (UTC) 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 Received: from plouf.banquise.eu.com (ovpn-117-116.ams2.redhat.com [10.36.117.116]) by smtp.corp.redhat.com (Postfix) with ESMTP id 793697DEEA; Thu, 1 Jun 2017 18:47:05 +0000 (UTC) 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-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 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-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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);