* [PATCH v4 0/2] Avoid selftests on some Asus models
@ 2016-09-25 13:25 Marcos Paulo de Souza
2016-09-25 13:25 ` [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Marcos Paulo de Souza
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-09-25 13:25 UTC (permalink / raw)
To: dmitry.torokhov, linux-input, linux-kernel; +Cc: Marcos Paulo de Souza
Hi guys,
this is my forth iteration in this patch. I hope now this address all problems
and, at least, most Asus models affect by this problem.
All models affected by this problem:
A455LD
K401LB
K501LB
K501LX
R409L
V502LX
X302LA
X450LCP
X450LD
X455LAB
X455LDB
X455LF
Z450LA
Changes since v3:
Add back all Asus models, instead of the dump decision of avoiding selftests in
all Asus laptops
Changes since v2:
Avoid selftest in all Asus laptops
Changes since v1:
Change kernel parameter i8042.reset to accept different values, instead of creating
a new kernel parameter.
Please let me know if there is something that needs more polishment.
Thanks!
Marcos Paulo de Souza (2):
input/serio/i8042.c: Skipt selftest on ASUS laptops
kernel-parameters: Update i8042.reset parameter documentation
Documentation/kernel-parameters.txt | 7 ++-
drivers/input/serio/i8042-x86ia64io.h | 94 ++++++++++++++++++++++++++++++++++-
drivers/input/serio/i8042.c | 38 +++++++++++---
3 files changed, 130 insertions(+), 9 deletions(-)
--
2.7.4
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops
2016-09-25 13:25 [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
@ 2016-09-25 13:25 ` Marcos Paulo de Souza
2016-09-25 13:25 ` [PATCH v4 2/2] kernel-parameters: Update i8042.reset parameter documentation Marcos Paulo de Souza
2016-10-01 10:56 ` [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
2 siblings, 0 replies; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-09-25 13:25 UTC (permalink / raw)
To: dmitry.torokhov, linux-input, linux-kernel; +Cc: Marcos Paulo de Souza
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 <marcos.souza.org@gmail.com>
---
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;
--
2.7.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 2/2] kernel-parameters: Update i8042.reset parameter documentation
2016-09-25 13:25 [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
2016-09-25 13:25 ` [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Marcos Paulo de Souza
@ 2016-09-25 13:25 ` Marcos Paulo de Souza
2016-10-01 10:56 ` [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
2 siblings, 0 replies; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-09-25 13:25 UTC (permalink / raw)
To: dmitry.torokhov, linux-input, linux-kernel; +Cc: Marcos Paulo de Souza
Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
---
Documentation/kernel-parameters.txt | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a4f4d69..5ee70bd 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1457,7 +1457,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
controllers
i8042.notimeout [HW] Ignore timeout condition signalled by controller
- i8042.reset [HW] Reset the controller during init and cleanup
+ i8042.reset [HW] Reset the controller during init and cleanup, only
+ on cleanup, or never reset
+ Format: { 1 | Y | y | 0 | N | n }
+ 1, Y, y: init and cleanup
+ 0, N, n: don't reset controller
+ Default: only on cleanup
i8042.unlock [HW] Unlock (ignore) the keylock
i8042.kbdreset [HW] Reset device connected to KBD port
--
2.7.4
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v4 0/2] Avoid selftests on some Asus models
2016-09-25 13:25 [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
2016-09-25 13:25 ` [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Marcos Paulo de Souza
2016-09-25 13:25 ` [PATCH v4 2/2] kernel-parameters: Update i8042.reset parameter documentation Marcos Paulo de Souza
@ 2016-10-01 10:56 ` Marcos Paulo de Souza
2016-10-03 5:16 ` Dmitry Torokhov
2 siblings, 1 reply; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-10-01 10:56 UTC (permalink / raw)
To: dmitry.torokhov, linux-input, linux-kernel
ping?
On Sun, Sep 25, 2016 at 10:25:42AM -0300, Marcos Paulo de Souza wrote:
> Hi guys,
>
> this is my forth iteration in this patch. I hope now this address all problems
> and, at least, most Asus models affect by this problem.
>
> All models affected by this problem:
> A455LD
> K401LB
> K501LB
> K501LX
> R409L
> V502LX
> X302LA
> X450LCP
> X450LD
> X455LAB
> X455LDB
> X455LF
> Z450LA
>
> Changes since v3:
> Add back all Asus models, instead of the dump decision of avoiding selftests in
> all Asus laptops
>
> Changes since v2:
> Avoid selftest in all Asus laptops
>
> Changes since v1:
> Change kernel parameter i8042.reset to accept different values, instead of creating
> a new kernel parameter.
>
> Please let me know if there is something that needs more polishment.
>
> Thanks!
>
> Marcos Paulo de Souza (2):
> input/serio/i8042.c: Skipt selftest on ASUS laptops
> kernel-parameters: Update i8042.reset parameter documentation
>
> Documentation/kernel-parameters.txt | 7 ++-
> drivers/input/serio/i8042-x86ia64io.h | 94 ++++++++++++++++++++++++++++++++++-
> drivers/input/serio/i8042.c | 38 +++++++++++---
> 3 files changed, 130 insertions(+), 9 deletions(-)
>
> --
> 2.7.4
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 0/2] Avoid selftests on some Asus models
2016-10-01 10:56 ` [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
@ 2016-10-03 5:16 ` Dmitry Torokhov
2016-10-03 12:07 ` Marcos Paulo de Souza
0 siblings, 1 reply; 6+ messages in thread
From: Dmitry Torokhov @ 2016-10-03 5:16 UTC (permalink / raw)
To: Marcos Paulo de Souza; +Cc: linux-input, linux-kernel
On Sat, Oct 01, 2016 at 07:56:37AM -0300, Marcos Paulo de Souza wrote:
> ping?
Sorry for the delay, I was trying to wrap my mind around the new
always/never/sometimes logic.
Does the version below still work for you?
Thanks.
--
Dmitry
Input: i8042 - skip selftest on ASUS laptops
From: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
On suspend/resume cycle, selftest is executed to reset i8042 controller.
But when this is done in Asus devices, subsequent 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 <marcos.souza.org@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
Documentation/kernel-parameters.txt | 9 +++
drivers/input/serio/i8042-io.h | 2 -
drivers/input/serio/i8042-ip22io.h | 2 -
drivers/input/serio/i8042-ppcio.h | 2 -
drivers/input/serio/i8042-sparcio.h | 2 -
drivers/input/serio/i8042-unicore32io.h | 2 -
drivers/input/serio/i8042-x86ia64io.h | 96 ++++++++++++++++++++++++++++++-
drivers/input/serio/i8042.c | 55 ++++++++++++++----
8 files changed, 150 insertions(+), 20 deletions(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a4f4d69..46726d4 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1457,7 +1457,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
controllers
i8042.notimeout [HW] Ignore timeout condition signalled by controller
- i8042.reset [HW] Reset the controller during init and cleanup
+ i8042.reset [HW] Reset the controller during init, cleanup and
+ suspend-to-ram transitions, only during s2r
+ transitions, or never reset
+ Format: { 1 | Y | y | 0 | N | n }
+ 1, Y, y: always reset controller
+ 0, N, n: don't ever reset controller
+ Default: only on s2r transitions on x86; most other
+ architectures force reset to be always executed
i8042.unlock [HW] Unlock (ignore) the keylock
i8042.kbdreset [HW] Reset device connected to KBD port
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index a5eed2a..34da81c 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -81,7 +81,7 @@ static inline int i8042_platform_init(void)
return -EBUSY;
#endif
- i8042_reset = 1;
+ i8042_reset = I8042_RESET_ALWAYS;
return 0;
}
diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h
index ee1ad27..08a1c10 100644
--- a/drivers/input/serio/i8042-ip22io.h
+++ b/drivers/input/serio/i8042-ip22io.h
@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
return -EBUSY;
#endif
- i8042_reset = 1;
+ i8042_reset = I8042_RESET_ALWAYS;
return 0;
}
diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
index f708c75..1aabea4 100644
--- a/drivers/input/serio/i8042-ppcio.h
+++ b/drivers/input/serio/i8042-ppcio.h
@@ -44,7 +44,7 @@ static inline void i8042_write_command(int val)
static inline int i8042_platform_init(void)
{
- i8042_reset = 1;
+ i8042_reset = I8042_RESET_ALWAYS;
return 0;
}
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index afcd1c1..6231d63 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -130,7 +130,7 @@ static int __init i8042_platform_init(void)
}
}
- i8042_reset = 1;
+ i8042_reset = I8042_RESET_ALWAYS;
return 0;
}
diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h
index 73f5cc1..4557475 100644
--- a/drivers/input/serio/i8042-unicore32io.h
+++ b/drivers/input/serio/i8042-unicore32io.h
@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042"))
return -EBUSY;
- i8042_reset = 1;
+ i8042_reset = I8042_RESET_ALWAYS;
return 0;
}
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 60d74e1..07d547d 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -518,6 +518,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 */
@@ -1080,12 +1164,18 @@ static int __init i8042_platform_init(void)
return retval;
#if defined(__ia64__)
- i8042_reset = true;
+ i8042_reset = I8042_RESET_ALWAYS;
#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_DEFAULT) {
+ 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..89abfdb 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -48,9 +48,39 @@ 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_S2RAM,
+#define I8042_RESET_DEFAULT I8042_RESET_ON_S2RAM
+};
+static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
+static int i8042_set_reset(const char *val, const struct kernel_param *kp)
+{
+ enum i8042_controller_reset_mode *arg = kp->arg;
+ int error;
+ bool reset;
+
+ if (val) {
+ error = kstrtobool(val, &reset);
+ if (error)
+ return error;
+ } else {
+ reset = true;
+ }
+
+ *arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
+ 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, enum i8042_controller_reset_mode)
+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);
@@ -1019,7 +1049,7 @@ static int i8042_controller_init(void)
* Reset the controller and reset CRT to the original value set by BIOS.
*/
-static void i8042_controller_reset(bool force_reset)
+static void i8042_controller_reset(bool s2r_wants_reset)
{
i8042_flush();
@@ -1044,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset)
* Reset the controller if requested.
*/
- if (i8042_reset || force_reset)
+ if (i8042_reset == I8042_RESET_ALWAYS ||
+ (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
i8042_controller_selftest();
+ }
/*
* Restore the original control register setting.
@@ -1110,7 +1142,7 @@ static void i8042_dritek_enable(void)
* before suspending.
*/
-static int i8042_controller_resume(bool force_reset)
+static int i8042_controller_resume(bool s2r_wants_reset)
{
int error;
@@ -1118,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset)
if (error)
return error;
- if (i8042_reset || force_reset) {
+ if (i8042_reset == I8042_RESET_ALWAYS ||
+ (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
error = i8042_controller_selftest();
if (error)
return error;
@@ -1195,7 +1228,7 @@ static int i8042_pm_resume_noirq(struct device *dev)
static int i8042_pm_resume(struct device *dev)
{
- bool force_reset;
+ bool want_reset;
int i;
for (i = 0; i < I8042_NUM_PORTS; i++) {
@@ -1218,9 +1251,9 @@ static int i8042_pm_resume(struct device *dev)
* off control to the platform firmware, otherwise we can simply restore
* the mode.
*/
- force_reset = pm_resume_via_firmware();
+ want_reset = pm_resume_via_firmware();
- return i8042_controller_resume(force_reset);
+ return i8042_controller_resume(want_reset);
}
static int i8042_pm_thaw(struct device *dev)
@@ -1482,7 +1515,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;
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v4 0/2] Avoid selftests on some Asus models
2016-10-03 5:16 ` Dmitry Torokhov
@ 2016-10-03 12:07 ` Marcos Paulo de Souza
0 siblings, 0 replies; 6+ messages in thread
From: Marcos Paulo de Souza @ 2016-10-03 12:07 UTC (permalink / raw)
To: Dmitry Torokhov, linux-input, linux-kernel
Hi Dmitry,
On Sun, Oct 02, 2016 at 10:16:31PM -0700, Dmitry Torokhov wrote:
> On Sat, Oct 01, 2016 at 07:56:37AM -0300, Marcos Paulo de Souza wrote:
> > ping?
>
> Sorry for the delay, I was trying to wrap my mind around the new
> always/never/sometimes logic.
No problem.
>
> Does the version below still work for you?
Yes, still works for me.
Tested-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
>
> Thanks.
>
> --
> Dmitry
>
> Input: i8042 - skip selftest on ASUS laptops
>
> From: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
>
> On suspend/resume cycle, selftest is executed to reset i8042 controller.
> But when this is done in Asus devices, subsequent 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 <marcos.souza.org@gmail.com>
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
> Documentation/kernel-parameters.txt | 9 +++
> drivers/input/serio/i8042-io.h | 2 -
> drivers/input/serio/i8042-ip22io.h | 2 -
> drivers/input/serio/i8042-ppcio.h | 2 -
> drivers/input/serio/i8042-sparcio.h | 2 -
> drivers/input/serio/i8042-unicore32io.h | 2 -
> drivers/input/serio/i8042-x86ia64io.h | 96 ++++++++++++++++++++++++++++++-
> drivers/input/serio/i8042.c | 55 ++++++++++++++----
> 8 files changed, 150 insertions(+), 20 deletions(-)
>
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index a4f4d69..46726d4 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -1457,7 +1457,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
> i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
> controllers
> i8042.notimeout [HW] Ignore timeout condition signalled by controller
> - i8042.reset [HW] Reset the controller during init and cleanup
> + i8042.reset [HW] Reset the controller during init, cleanup and
> + suspend-to-ram transitions, only during s2r
> + transitions, or never reset
> + Format: { 1 | Y | y | 0 | N | n }
> + 1, Y, y: always reset controller
> + 0, N, n: don't ever reset controller
> + Default: only on s2r transitions on x86; most other
> + architectures force reset to be always executed
> i8042.unlock [HW] Unlock (ignore) the keylock
> i8042.kbdreset [HW] Reset device connected to KBD port
>
> diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
> index a5eed2a..34da81c 100644
> --- a/drivers/input/serio/i8042-io.h
> +++ b/drivers/input/serio/i8042-io.h
> @@ -81,7 +81,7 @@ static inline int i8042_platform_init(void)
> return -EBUSY;
> #endif
>
> - i8042_reset = 1;
> + i8042_reset = I8042_RESET_ALWAYS;
> return 0;
> }
>
> diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h
> index ee1ad27..08a1c10 100644
> --- a/drivers/input/serio/i8042-ip22io.h
> +++ b/drivers/input/serio/i8042-ip22io.h
> @@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
> return -EBUSY;
> #endif
>
> - i8042_reset = 1;
> + i8042_reset = I8042_RESET_ALWAYS;
>
> return 0;
> }
> diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
> index f708c75..1aabea4 100644
> --- a/drivers/input/serio/i8042-ppcio.h
> +++ b/drivers/input/serio/i8042-ppcio.h
> @@ -44,7 +44,7 @@ static inline void i8042_write_command(int val)
>
> static inline int i8042_platform_init(void)
> {
> - i8042_reset = 1;
> + i8042_reset = I8042_RESET_ALWAYS;
> return 0;
> }
>
> diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
> index afcd1c1..6231d63 100644
> --- a/drivers/input/serio/i8042-sparcio.h
> +++ b/drivers/input/serio/i8042-sparcio.h
> @@ -130,7 +130,7 @@ static int __init i8042_platform_init(void)
> }
> }
>
> - i8042_reset = 1;
> + i8042_reset = I8042_RESET_ALWAYS;
>
> return 0;
> }
> diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h
> index 73f5cc1..4557475 100644
> --- a/drivers/input/serio/i8042-unicore32io.h
> +++ b/drivers/input/serio/i8042-unicore32io.h
> @@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
> if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042"))
> return -EBUSY;
>
> - i8042_reset = 1;
> + i8042_reset = I8042_RESET_ALWAYS;
> return 0;
> }
>
> diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
> index 60d74e1..07d547d 100644
> --- a/drivers/input/serio/i8042-x86ia64io.h
> +++ b/drivers/input/serio/i8042-x86ia64io.h
> @@ -518,6 +518,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 */
> @@ -1080,12 +1164,18 @@ static int __init i8042_platform_init(void)
> return retval;
>
> #if defined(__ia64__)
> - i8042_reset = true;
> + i8042_reset = I8042_RESET_ALWAYS;
> #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_DEFAULT) {
> + 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..89abfdb 100644
> --- a/drivers/input/serio/i8042.c
> +++ b/drivers/input/serio/i8042.c
> @@ -48,9 +48,39 @@ 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_S2RAM,
> +#define I8042_RESET_DEFAULT I8042_RESET_ON_S2RAM
> +};
> +static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
> +static int i8042_set_reset(const char *val, const struct kernel_param *kp)
> +{
> + enum i8042_controller_reset_mode *arg = kp->arg;
> + int error;
> + bool reset;
> +
> + if (val) {
> + error = kstrtobool(val, &reset);
> + if (error)
> + return error;
> + } else {
> + reset = true;
> + }
> +
> + *arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
> + 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, enum i8042_controller_reset_mode)
> +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);
> @@ -1019,7 +1049,7 @@ static int i8042_controller_init(void)
> * Reset the controller and reset CRT to the original value set by BIOS.
> */
>
> -static void i8042_controller_reset(bool force_reset)
> +static void i8042_controller_reset(bool s2r_wants_reset)
> {
> i8042_flush();
>
> @@ -1044,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset)
> * Reset the controller if requested.
> */
>
> - if (i8042_reset || force_reset)
> + if (i8042_reset == I8042_RESET_ALWAYS ||
> + (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
> i8042_controller_selftest();
> + }
>
> /*
> * Restore the original control register setting.
> @@ -1110,7 +1142,7 @@ static void i8042_dritek_enable(void)
> * before suspending.
> */
>
> -static int i8042_controller_resume(bool force_reset)
> +static int i8042_controller_resume(bool s2r_wants_reset)
> {
> int error;
>
> @@ -1118,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset)
> if (error)
> return error;
>
> - if (i8042_reset || force_reset) {
> + if (i8042_reset == I8042_RESET_ALWAYS ||
> + (i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
> error = i8042_controller_selftest();
> if (error)
> return error;
> @@ -1195,7 +1228,7 @@ static int i8042_pm_resume_noirq(struct device *dev)
>
> static int i8042_pm_resume(struct device *dev)
> {
> - bool force_reset;
> + bool want_reset;
> int i;
>
> for (i = 0; i < I8042_NUM_PORTS; i++) {
> @@ -1218,9 +1251,9 @@ static int i8042_pm_resume(struct device *dev)
> * off control to the platform firmware, otherwise we can simply restore
> * the mode.
> */
> - force_reset = pm_resume_via_firmware();
> + want_reset = pm_resume_via_firmware();
>
> - return i8042_controller_resume(force_reset);
> + return i8042_controller_resume(want_reset);
> }
>
> static int i8042_pm_thaw(struct device *dev)
> @@ -1482,7 +1515,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;
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2016-10-03 12:07 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-09-25 13:25 [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
2016-09-25 13:25 ` [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Marcos Paulo de Souza
2016-09-25 13:25 ` [PATCH v4 2/2] kernel-parameters: Update i8042.reset parameter documentation Marcos Paulo de Souza
2016-10-01 10:56 ` [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza
2016-10-03 5:16 ` Dmitry Torokhov
2016-10-03 12:07 ` Marcos Paulo de Souza
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.