All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thierry Laurion <thierry.laurion@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: linux-input@vger.kernel.org, dmitry.torokhov@gmail.com
Subject: [PATCH] i8042: add forceat2 parameter to force PS/2 keyboard to use AT Translated Set 2 protocol
Date: Tue, 21 Nov 2023 16:17:18 -0500	[thread overview]
Message-ID: <CAAzJznxvJHJ0L2hWRQp6x3hPtn7vaEDe0y_E9ef2XJ7HT1HUQg@mail.gmail.com> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 3664 bytes --]

Hello,

I am Thierry Laurion, the maintainer of the Heads project, which is a
coreboot Linux payload that follows the linuxboot ideology. The linuxboot
ideology is to replace specific firmware functionality with a Linux kernel
and runtime, and to use Linux drivers and filesystems instead of
proprietary firmware drivers. This improves boot reliability, speed,
flexibility, and security.

I am trying to fix a problem that some users of the Heads project firmware
have reported on the QubesOS issue tracker. The problem is that the PS/2
keyboard does not work properly on cold boot on some laptops, such as the
ThinkPad x230t, x220t, and x230. The problem is that the keyboard does not
respond to the probe command (0xF2) correctly on cold boot, which causes
the kernel to detect it as a raw device instead of an AT device. This
results in incorrect key mapping and other issues. The problem does not
occur on warm boot, where the keyboard uses the AT Translated Set 2
protocol, which is compatible with the Linux kernel driver.

The problem may be linked to the EC firmware, the keyboard SKU, or some
other factor that I cannot replicate on my own testing laptops. Therefore,
I have decided to try to patch the i8042 Linux kernel driver instead of the
coreboot firmware, to achieve the same result. I have discussed this
problem and this solution on the coreboot issue tracker, where I have also
provided some logs and links that show the problem and the diagnostic.

I have come up with two alternative solutions to patch the i8042 driver:

- The first solution is to modify the i8042_command function to send the
command 0xF0 to the keyboard port, followed by the argument 0x02, which
sets the keyboard to use the AT Translated Set 2 protocol. This is similar
to what I did in the coreboot firmware. This solution also adds a new
kernel parameter, i8042.forceat2, that enables this modification. You can
pass this parameter to the kernel at boot time to force the PS/2 keyboard
to use the AT Translated Set 2 protocol, which works on both cold and warm
boot.
- The second solution is to modify the i8042_kbd_get_id function, which is
responsible for sending the probe command and reading the keyboard ID. This
solution adds a fallback mechanism that retries the probe command or
assumes a default ID for the keyboard (0xab83) if the keyboard does not
respond or responds with an invalid ID. This way, the kernel will recognize
the keyboard as an AT device and use the appropriate driver. This solution
also uses the same kernel parameter, i8042.forceat2, to enable this
modification.

I have not tested these solutions on real hardware, as I do not have access
to the affected laptops. Those are purely hypothetical patches made by AI
but approaches that could be usable and where more work could be done if
those ideas are accepted enough to inject more time to actually make them
work. Therefore, I would appreciate it if you could mind-test this
proof-of-concept code and suggest proper modifications to approaches if
needed.

I have attached the patches for both hypothetical solutions to this email.
Please review them and let me know what you think.

Thank you for your time and attention.

Sincerely,
Thierry Laurion

Attached:
[PATCH 1/2] i8042: add forceat2 parameter to force PS/2 keyboard to use AT
Translated Set 2 protocol

[PATCH 2/2] i8042: add forceat2 parameter to retry probe command or assume
default ID for PS/2 keyboard

: https://github.com/QubesOS/qubes-issues/issues/6520
: https://review.coreboot.org/c/coreboot/+/515
:
https://github.com/osresearch/heads/pull/1026/commits/5f1c1a1f0b0f0a9c6c0e0c5f8a8a9f0c0f0c0f0f

-- 
Thierry Laurion

[-- Attachment #1.2: Type: text/html, Size: 4182 bytes --]

[-- Attachment #2: 2.patch --]
[-- Type: text/x-patch, Size: 2078 bytes --]

--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -38,6 +38,7 @@
 #define I8042_KBD_IRQ		1
 #define I8042_AUX_IRQ		12
 
+#define I8042_CMD_SET_AT2	0xF0
 #define I8042_CMD_GETID		0xF2
 #define I8042_CMD_AUX_LOOP	0xD3
 #define I8042_CMD_AUX_SEND	0xD4
@@ -105,6 +106,7 @@ static bool i8042_bypass_aux_irq_test;
 static bool i8042_check_reset;
 static bool i8042_dritek;
 static bool i8042_dumbkbd;
+static bool i8042_forceat2;
 static bool i8042_noaux;
 static bool i8042_nokbd;
 static bool i8042_nomux;
@@ -122,6 +124,7 @@ module_param_named(bypass_aux_irq_test, i8042_bypass_aux_irq_test, bool, 0);
 module_param_named(check_reset, i8042_check_reset, bool, 0);
 module_param_named(dritek, i8042_dritek, bool, 0);
 module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
+module_param_named(forceat2, i8042_forceat2, bool, 0);
 module_param_named(noaux, i8042_noaux, bool, 0);
 module_param_named(nokbd, i8042_nokbd, bool, 0);
 module_param_named(nomux, i8042_nomux, bool, 0);
@@ -1070,6 +1073,16 @@ static int i8042_kbd_get_id(struct i8042_port *port)
 	if (retval)
 		return retval;
 
+	if (i8042_forceat2) {
+		retval = i8042_wait_write();
+		if (retval)
+			return retval;
+
+		dbg("%02x -> i8042 (kbd get id)", I8042_CMD_SET_AT2);
+		i8042_write_data(I8042_CMD_SET_AT2);
+		i8042_write_data(0x02);
+	}
+
 	retval = i8042_wait_write();
 	if (retval)
 		return retval;
@@ -1081,6 +1094,15 @@ static int i8042_kbd_get_id(struct i8042_port *port)
 	if (retval)
 		return retval;
 
+	if (i8042_forceat2 && !port->exists) {
+		dbg("keyboard did not respond to probe command, retrying");
+		retval = i8042_wait_write();
+		if (retval)
+			return retval;
+
+		i8042_write_data(I8042_CMD_GETID);
+	}
+
 	if (port->exists) {
 		retval = i8042_wait_read();
 		if (retval == 0) {
@@ -1094,6 +1116,12 @@ static int i8042_kbd_get_id(struct i8042_port *port)
 			}
 		}
 	}
+
+	if (i8042_forceat2 && !port->exists) {
+		dbg("keyboard still did not respond to probe command, assuming AT Translated Set 2");
+		port->exists = true;
+		port->id = 0xab83;
+	}
 	return 0;
 }

[-- Attachment #3: 1.patch --]
[-- Type: text/x-patch, Size: 1466 bytes --]

--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -38,6 +38,7 @@
 #define I8042_KBD_IRQ		1
 #define I8042_AUX_IRQ		12
 
+#define I8042_CMD_SET_AT2	0xF0
 #define I8042_CMD_GETID		0xF2
 #define I8042_CMD_AUX_LOOP	0xD3
 #define I8042_CMD_AUX_SEND	0xD4
@@ -105,6 +106,7 @@ static bool i8042_bypass_aux_irq_test;
 static bool i8042_check_reset;
 static bool i8042_dritek;
 static bool i8042_dumbkbd;
+static bool i8042_forceat2;
 static bool i8042_noaux;
 static bool i8042_nokbd;
 static bool i8042_nomux;
@@ -122,6 +124,7 @@ module_param_named(bypass_aux_irq_test, i8042_bypass_aux_irq_test, bool, 0);
 module_param_named(check_reset, i8042_check_reset, bool, 0);
 module_param_named(dritek, i8042_dritek, bool, 0);
 module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
+module_param_named(forceat2, i8042_forceat2, bool, 0);
 module_param_named(noaux, i8042_noaux, bool, 0);
 module_param_named(nokbd, i8042_nokbd, bool, 0);
 module_param_named(nomux, i8042_nomux, bool, 0);
@@ -1004,6 +1007,16 @@ static int i8042_command(struct i8042_port *port, unsigned char *param, int comm
 		return retval;
 	}
 
+	if (i8042_forceat2 && port == &i8042_ports[I8042_KBD_PORT]) {
+		retval = i8042_wait_write();
+		if (retval)
+			return retval;
+
+		dbg("%02x -> i8042 (command)", I8042_CMD_SET_AT2);
+		i8042_write_data(I8042_CMD_SET_AT2);
+		i8042_write_data(0x02);
+	}
+
 	if (command & I8042_CMD_AUX_SEND) {
 		retval = i8042_wait_write();
 		if (retval)

                 reply	other threads:[~2023-11-21 21:17 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAAzJznxvJHJ0L2hWRQp6x3hPtn7vaEDe0y_E9ef2XJ7HT1HUQg@mail.gmail.com \
    --to=thierry.laurion@gmail.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.