From patchwork Sun Sep 25 13:25:43 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcos Paulo de Souza X-Patchwork-Id: 9349699 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 6C42E6077A for ; Sun, 25 Sep 2016 13:26:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 59C3028387 for ; Sun, 25 Sep 2016 13:26:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4E9D528D00; Sun, 25 Sep 2016 13:26:31 +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.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham 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 8099028387 for ; Sun, 25 Sep 2016 13:26:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S966399AbcIYN0Y (ORCPT ); Sun, 25 Sep 2016 09:26:24 -0400 Received: from mail-qt0-f194.google.com ([209.85.216.194]:33291 "EHLO mail-qt0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S966236AbcIYN0W (ORCPT ); Sun, 25 Sep 2016 09:26:22 -0400 Received: by mail-qt0-f194.google.com with SMTP id p47so4981369qtc.0; Sun, 25 Sep 2016 06:26:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=bkSX2SHG53mSGNahH2977nZtVmCRvS/dywnONGi+wEA=; b=svreSYlBr5DSPMSZL8opyfn56H2fhC5b2FWwSZgJBr2LsEelWnlpQnTwHwm2uiTAKw tjmveffVxs4CFFciML2ER93AIXpuzk5yA/SDBQxhdutUZ320YmYlNzWeN9bAzYOXZwRJ 9Zm9emNYQTuo6F5EwFnbN2/XD7RhKlKfzW7Dyhtt4lSZW+b1cKMQlLrOGOXwkZegVqLY j/Kv2jvU/dzzJnjVaKmd5qh3m8mhUeCVvdv7euqnA0qfKJvfAGSqALaaOMJGD7bFNlog SifgGiMQnJPkrx7DMLHxdviYh7S6iDBFj8fbDrwh77NlofYSDZLsubQL42NRp61WLWVZ HtAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=bkSX2SHG53mSGNahH2977nZtVmCRvS/dywnONGi+wEA=; b=dEE+O805opOp4XBS592bDmLp9aEpfwtnDfdoVJp53gGU0RmVAI7v2D9sg1Zvttek7u a2XuXs9o72kVm2PCkOtdEeOGOGzBjrEOGJ5ptBi8B2UoYg8ahNvAN6TvO31SM3L67y2A Y+Owxq/dXr3hE2b9hhnF11HkB6f2+hCUJdCnEaDfN2Au5dO1+LJ1q9f/CAheThqHcjBV ajku8U0FZx4a8DCMRRydpPAlencSRAxF7jhp+wuottDgevRPJHvG6zJ+B6y2OA+pwQQZ qnEUvV6vcKaXR+MbSJBe5BHfeI8Hxbjl+GPRLhgRXQ8Gy5X9Hy3MlHYhT6KQJNzAO1hM IG7g== X-Gm-Message-State: AA6/9RlGbBzj0dwTX3Tq6rNyavSSsmczjshd3DgwR97J5wF8nGNC5euv/x52z2AdWFSdGA== X-Received: by 10.200.38.241 with SMTP id 46mr17528997qtp.135.1474809981323; Sun, 25 Sep 2016 06:26:21 -0700 (PDT) Received: from localhost.localdomain ([177.132.135.94]) by smtp.gmail.com with ESMTPSA id 139sm9045573qkh.33.2016.09.25.06.26.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 25 Sep 2016 06:26:20 -0700 (PDT) From: Marcos Paulo de Souza To: dmitry.torokhov@gmail.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Marcos Paulo de Souza Subject: [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Date: Sun, 25 Sep 2016 10:25:43 -0300 Message-Id: <1474809944-7357-2-git-send-email-marcos.souza.org@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1474809944-7357-1-git-send-email-marcos.souza.org@gmail.com> References: <1474809944-7357-1-git-send-email-marcos.souza.org@gmail.com> Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP On suspend/resume cycle, selftest is executed to reset i8042 controller. But when this is done in Asus devices, posterior calls to detect/init functions to elantech driver fails. Skipping selftest fixes this problem. An easier step to reproduce this problem is adding i8042.reset=1 as a kernel parameter. On Asus laptops, it'll make the system to start with the touchpad already stuck, since psmouse_probe forcibly calls the selftest function. This patch was inspired by John Hiesey's change[1], but, since this problem affects a lot of models of Asus, let's avoid running selftests on them. All models affected by this problem: A455LD K401LB K501LB K501LX R409L V502LX X302LA X450LCP X450LD X455LAB X455LDB X455LF Z450LA [1]: https://marc.info/?l=linux-input&m=144312209020616&w=2 Fixes: "ETPS/2 Elantech Touchpad dies after resume from suspend" (https://bugzilla.kernel.org/show_bug.cgi?id=107971) Signed-off-by: Marcos Paulo de Souza --- drivers/input/serio/i8042-x86ia64io.h | 94 ++++++++++++++++++++++++++++++++++- drivers/input/serio/i8042.c | 39 ++++++++++++--- 2 files changed, 125 insertions(+), 8 deletions(-) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 68f5f4a..0d96539 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -510,6 +510,90 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { { } }; +/* + * On some Asus laptops, just running self tests cause problems. + */ +static const struct dmi_system_id i8042_dmi_noselftest_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "R409L"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"), + }, + }, + { } +}; static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { { /* MSI Wind U-100 */ @@ -1076,8 +1160,14 @@ static int __init i8042_platform_init(void) #endif #ifdef CONFIG_X86 - if (dmi_check_system(i8042_dmi_reset_table)) - i8042_reset = true; + /* Honor module parameter when value is not default */ + if (i8042_reset == I8042_RESET_ON_RESUME) { + if (dmi_check_system(i8042_dmi_reset_table)) + i8042_reset = I8042_RESET_ALWAYS; + + if (dmi_check_system(i8042_dmi_noselftest_table)) + i8042_reset = I8042_RESET_NEVER; + } if (dmi_check_system(i8042_dmi_noloop_table)) i8042_noloop = true; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 405252a..c0e76c2 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -48,9 +48,33 @@ static bool i8042_unlock; module_param_named(unlock, i8042_unlock, bool, 0); MODULE_PARM_DESC(unlock, "Ignore keyboard lock."); -static bool i8042_reset; -module_param_named(reset, i8042_reset, bool, 0); -MODULE_PARM_DESC(reset, "Reset controller during init and cleanup."); +enum i8042_controller_reset_mode { + I8042_RESET_NEVER, + I8042_RESET_ALWAYS, + I8042_RESET_ON_RESUME +}; +static unsigned int i8042_reset = I8042_RESET_ON_RESUME; +static int i8042_set_reset(const char *val, const struct kernel_param *kp) +{ + unsigned int ret = I8042_RESET_ON_RESUME; + + if (!val || !strncmp(val, "1", 1) || !strncasecmp(val, "y", 1)) + ret = I8042_RESET_ALWAYS; + else if (!strncmp(val, "0", 1) || !strncasecmp(val, "n", 1)) + ret = I8042_RESET_NEVER; + + *((unsigned int *)kp->arg) = ret; + + return 0; +} + +static const struct kernel_param_ops param_ops_reset_param = { + .flags = KERNEL_PARAM_OPS_FL_NOARG, + .set = i8042_set_reset, +}; +#define param_check_reset_param(name, p) __param_check(name, p, unsigned int) +module_param_named(reset, i8042_reset, reset_param, 0); +MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both"); static bool i8042_direct; module_param_named(direct, i8042_direct, bool, 0); @@ -890,6 +914,9 @@ static int i8042_controller_selftest(void) unsigned char param; int i = 0; + if (i8042_reset == I8042_RESET_NEVER) + return 0; + /* * We try this 5 times; on some really fragile systems this does not * take the first time... @@ -1044,7 +1071,7 @@ static void i8042_controller_reset(bool force_reset) * Reset the controller if requested. */ - if (i8042_reset || force_reset) + if (i8042_reset != I8042_RESET_NEVER || force_reset) i8042_controller_selftest(); /* @@ -1118,7 +1145,7 @@ static int i8042_controller_resume(bool force_reset) if (error) return error; - if (i8042_reset || force_reset) { + if (i8042_reset != I8042_RESET_NEVER || force_reset) { error = i8042_controller_selftest(); if (error) return error; @@ -1482,7 +1509,7 @@ static int __init i8042_probe(struct platform_device *dev) i8042_platform_device = dev; - if (i8042_reset) { + if (i8042_reset == I8042_RESET_ALWAYS) { error = i8042_controller_selftest(); if (error) return error;