Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1490890 > unrolled thread
| Started by | Marcos Paulo de Souza <marcos.souza.org@gmail.com> |
|---|---|
| First post | 2016-09-25 15:30 +0200 |
| Last post | 2016-10-03 14:10 +0200 |
| Articles | 5 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza <marcos.souza.org@gmail.com> - 2016-09-25 15:30 +0200
[PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops Marcos Paulo de Souza <marcos.souza.org@gmail.com> - 2016-09-25 15:30 +0200
Re: [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza <marcos.souza.org@gmail.com> - 2016-10-01 13:20 +0200
Re: [PATCH v4 0/2] Avoid selftests on some Asus models Dmitry Torokhov <dmitry.torokhov@gmail.com> - 2016-10-03 07:20 +0200
Re: [PATCH v4 0/2] Avoid selftests on some Asus models Marcos Paulo de Souza <marcos.souza.org@gmail.com> - 2016-10-03 14:10 +0200
| From | Marcos Paulo de Souza <marcos.souza.org@gmail.com> |
|---|---|
| Date | 2016-09-25 15:30 +0200 |
| Subject | [PATCH v4 0/2] Avoid selftests on some Asus models |
| Message-ID | <slhFg-76P-7@gated-at.bofh.it> |
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
[toc] | [next] | [standalone]
| From | Marcos Paulo de Souza <marcos.souza.org@gmail.com> |
|---|---|
| Date | 2016-09-25 15:30 +0200 |
| Subject | [PATCH] input/serio/i8042.c: Skipt selftest on ASUS laptops |
| Message-ID | <slhFg-76P-15@gated-at.bofh.it> |
| In reply to | #1490890 |
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
[toc] | [prev] | [next] | [standalone]
| From | Marcos Paulo de Souza <marcos.souza.org@gmail.com> |
|---|---|
| Date | 2016-10-01 13:20 +0200 |
| Message-ID | <snquK-7Gb-3@gated-at.bofh.it> |
| In reply to | #1490890 |
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 >
[toc] | [prev] | [next] | [standalone]
| From | Dmitry Torokhov <dmitry.torokhov@gmail.com> |
|---|---|
| Date | 2016-10-03 07:20 +0200 |
| Message-ID | <so3Pr-8hv-1@gated-at.bofh.it> |
| In reply to | #1494392 |
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;
[toc] | [prev] | [next] | [standalone]
| From | Marcos Paulo de Souza <marcos.souza.org@gmail.com> |
|---|---|
| Date | 2016-10-03 14:10 +0200 |
| Message-ID | <soaed-4Im-27@gated-at.bofh.it> |
| In reply to | #1494694 |
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;
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web