From fc815438e70cbb13166ab6711b6f6460521b1fd4 Mon Sep 17 00:00:00 2001
From: Leah Rowe <leah@libreboot.org>
Date: Mon, 30 Oct 2023 22:19:21 +0000
Subject: [PATCH 09/14] at_keyboard coreboot: force scancodes2+translate

Scan code set 2 with translation should be assumed in
every case, as the default starting position.

However, GRUB is trying to detect and use other modes
such as set 2 without translation, or set 1 without
translation from set 2; it also detects no-mode and
assumes mode 1, on really old keyboards.

The current behaviour has been retained, for everything
except GRUB_MACHINE_COREBOOT; for the latter, scan code
set 2 with translation is hardcoded, and forced in code.

This is required to make keyboard initialisation work on
the MEC5035 EC used by the Dell Latitude E6400, when
running GRUB as a coreboot payload on that laptop. The
EC reports scancode set 2 with translation when probed,
but actually only outputs scancode set 1.

Since GRUB is attempting to use it without translation,
and since the machine reports set 2 with translation,
but only ever outputs set 1 scancodes, this results in
wrong keypresses for every key.

This fix fixed that, by forcing set 2 with translation,
treating it as set 1, but only on coreboot. This is the
same behaviour used in GNU+Linux systems and SeaBIOS.
With this change, GRUB keyboard initialisation now works
just fine on those machines.

This has *also* been tested on other coreboot machines
running GRUB; several HP EliteBooks, ThinkPads and
Dell Precision T1650. All seems to work just fine.

Signed-off-by: Leah Rowe <leah@libreboot.org>
---
 grub-core/term/at_keyboard.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
index f8a129eb7..8207225c2 100644
--- a/grub-core/term/at_keyboard.c
+++ b/grub-core/term/at_keyboard.c
@@ -138,6 +138,7 @@ write_mode (int mode)
   return (i != GRUB_AT_TRIES);
 }
 
+#if !defined (GRUB_MACHINE_COREBOOT)
 static int
 query_mode (void)
 {
@@ -161,10 +162,12 @@ query_mode (void)
     return 3;
   return 0;
 }
+#endif
 
 static void
 set_scancodes (void)
 {
+#if !defined (GRUB_MACHINE_COREBOOT)
   /* You must have visited computer museum. Keyboard without scancode set
      knowledge. Assume XT. */
   if (!grub_keyboard_orig_set)
@@ -173,20 +176,33 @@ set_scancodes (void)
       ps2_state.current_set = 1;
       return;
     }
+#endif
 
 #if !USE_SCANCODE_SET
   ps2_state.current_set = 1;
   return;
-#else
+#endif
 
+#if defined (GRUB_MACHINE_COREBOOT)
+  /* enable translation */
+  grub_keyboard_controller_write (grub_keyboard_controller_orig
+				  & ~KEYBOARD_AT_DISABLE);
+#else
+  /* if not coreboot, disable translation and try mode 2 first, before 1 */
   grub_keyboard_controller_write (grub_keyboard_controller_orig
 				  & ~KEYBOARD_AT_TRANSLATE
 				  & ~KEYBOARD_AT_DISABLE);
+#endif
 
   keyboard_controller_wait_until_ready ();
   grub_outb (KEYBOARD_COMMAND_ENABLE, KEYBOARD_REG_DATA);
-
   write_mode (2);
+
+#if defined (GRUB_MACHINE_COREBOOT)
+  /* mode 2 with translation, so make grub treat as set 1 */
+  ps2_state.current_set = 1;
+#else
+  /* if not coreboot, translation isn't set; test 2 and fall back to 1 */
   ps2_state.current_set = query_mode ();
   grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
   if (ps2_state.current_set == 2)
-- 
2.39.5

