Blame SOURCES/0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch

5593c8
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
5593c8
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
5593c8
Date: Fri, 18 Dec 2020 15:39:26 +0100
5593c8
Subject: [PATCH] Add 'at_keyboard_fallback_set' var to force the set manually
fd0330
MIME-Version: 1.0
fd0330
Content-Type: text/plain; charset=UTF-8
fd0330
Content-Transfer-Encoding: 8bit
5593c8
5593c8
This seems required with HP DL380p Gen 8 systems.
5593c8
Indeed, with this system, we can see the following sequence:
5593c8
5593c8
1. controller is queried to get current configuration (returns 0x30 which is quite standard)
5593c8
2. controller is queried to get the current keyboard set in used, using code 0xf0 (first part)
5593c8
3. controller answers with 0xfa which means "ACK" (== ok)
5593c8
4. then we send "0" to tell "we want to know which set your are supporting"
5593c8
5. controller answers with 0xfa ("ACK")
5593c8
6. controller should then give us 1, 2, 3 or 0x43, 0x41, 0x3f, but here it gives us 0xfe which means "NACK"
5593c8
5593c8
Since there seems no way to determine the current set, and in fact the
5593c8
controller expects set2 to be used, we need to rely on an environment
5593c8
variable.
5593c8
Everything has been tested on this system: using 0xFE (resend command),
5593c8
making sure we wait for ACK in the 2 steps "write_mode", etc.
5593c8
5593c8
Below is litterature I used to come up with "there is no other
5593c8
solution":
5593c8
- https://wiki.osdev.org/%228042%22_PS/2_Controller
5593c8
- http://www-ug.eecg.toronto.edu/msl/nios_devices/datasheets/PS2%20Keyboard%20Protocol.htm
5593c8
- http://www.s100computers.com/My%20System%20Pages/MSDOS%20Board/PC%20Keyboard.pdf
fd0330
fd0330
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
fd0330
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
5593c8
---
5593c8
 grub-core/term/at_keyboard.c | 121 ++++++++++++++++++++++++++++++++++---------
5593c8
 1 file changed, 96 insertions(+), 25 deletions(-)
5593c8
5593c8
diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
fd0330
index 2601438260..dac0f946fe 100644
5593c8
--- a/grub-core/term/at_keyboard.c
5593c8
+++ b/grub-core/term/at_keyboard.c
5593c8
@@ -31,6 +31,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
5593c8
 static grub_uint8_t grub_keyboard_controller_orig;
5593c8
 static grub_uint8_t grub_keyboard_orig_set;
5593c8
 struct grub_ps2_state ps2_state;
5593c8
+static int fallback_set;
5593c8
 
5593c8
 static int ping_sent;
5593c8
 
5593c8
@@ -76,6 +77,8 @@ at_command (grub_uint8_t data)
5593c8
 	break;
5593c8
       return 0;
5593c8
     }
5593c8
+  if (i == GRUB_AT_TRIES)
5593c8
+    grub_dprintf ("atkeyb", "at_command() timed out! (stopped after %d tries)\n", i);
5593c8
   return (i != GRUB_AT_TRIES);
5593c8
 }
5593c8
 
5593c8
@@ -105,6 +108,21 @@ grub_keyboard_controller_read (void)
5593c8
 
5593c8
 #endif
5593c8
 
5593c8
+static int
5593c8
+resend_last_result (void)
5593c8
+{
5593c8
+  grub_uint8_t ret;
5593c8
+  keyboard_controller_wait_until_ready ();
5593c8
+  grub_dprintf ("atkeyb", "resend_last_result: sending 0xfe\n");
5593c8
+  grub_outb (0xfe, KEYBOARD_REG_DATA);
5593c8
+  ret = wait_ack ();
5593c8
+  grub_dprintf ("atkeyb", "resend_last_result: wait_ack() returned 0x%x\n", ret);
5593c8
+  keyboard_controller_wait_until_ready ();
5593c8
+  ret = grub_inb (KEYBOARD_REG_DATA);
5593c8
+  grub_dprintf ("atkeyb", "resend_last_result: read 0x%x from controller\n", ret);
5593c8
+  return ret;
5593c8
+}
5593c8
+
5593c8
 static int
5593c8
 write_mode (int mode)
5593c8
 {
5593c8
@@ -113,11 +131,14 @@ write_mode (int mode)
5593c8
     {
5593c8
       grub_uint8_t ack;
5593c8
       keyboard_controller_wait_until_ready ();
5593c8
+      grub_dprintf ("atkeyb", "write_mode: sending 0xf0\n");
5593c8
       grub_outb (0xf0, KEYBOARD_REG_DATA);
5593c8
       keyboard_controller_wait_until_ready ();
5593c8
+      grub_dprintf ("atkeyb", "write_mode: sending mode %d\n", mode);
5593c8
       grub_outb (mode, KEYBOARD_REG_DATA);
5593c8
       keyboard_controller_wait_until_ready ();
5593c8
       ack = wait_ack ();
5593c8
+      grub_dprintf ("atkeyb", "write_mode: wait_ack() returned 0x%x\n", ack);
5593c8
       if (ack == GRUB_AT_NACK)
5593c8
 	continue;
5593c8
       if (ack == GRUB_AT_ACK)
5593c8
@@ -125,6 +146,9 @@ write_mode (int mode)
5593c8
       return 0;
5593c8
     }
5593c8
 
5593c8
+  if (i == GRUB_AT_TRIES)
5593c8
+    grub_dprintf ("atkeyb", "write_mode() timed out! (stopped after %d tries)\n", i);
5593c8
+
5593c8
   return (i != GRUB_AT_TRIES);
5593c8
 }
5593c8
 
5593c8
@@ -132,31 +156,66 @@ static int
5593c8
 query_mode (void)
5593c8
 {
5593c8
   grub_uint8_t ret;
5593c8
+  grub_uint64_t endtime;
5593c8
+  unsigned i;
5593c8
   int e;
5593c8
+  char *envvar;
5593c8
 
5593c8
-  e = write_mode (0);
5593c8
-  if (!e) {
5593c8
-    grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n");
5593c8
-    return 0;
5593c8
-  }
5593c8
+  for (i = 0; i < GRUB_AT_TRIES; i++) {
5593c8
+    grub_dprintf ("atkeyb", "query_mode: sending command to controller\n");
5593c8
+    e = write_mode (0);
5593c8
+    if (!e) {
5593c8
+      grub_dprintf ("atkeyb", "query_mode: write_mode(0) failed\n");
5593c8
+      return 0;
5593c8
+    }
5593c8
 
5593c8
-  do {
5593c8
-    keyboard_controller_wait_until_ready ();
5593c8
-    ret = grub_inb (KEYBOARD_REG_DATA);
5593c8
-  } while (ret == GRUB_AT_ACK);
5593c8
-  /* QEMU translates the set even in no-translate mode.  */
5593c8
-  if (ret == 0x43 || ret == 1) {
5593c8
-    grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret);
5593c8
-    return 1;
5593c8
-  }
5593c8
-  if (ret == 0x41 || ret == 2) {
5593c8
-    grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret);
5593c8
-    return 2;
5593c8
+    endtime = grub_get_time_ms () + 20;
5593c8
+    do {
5593c8
+      keyboard_controller_wait_until_ready ();
5593c8
+      ret = grub_inb (KEYBOARD_REG_DATA);
5593c8
+      grub_dprintf ("atkeyb", "query_mode/loop: read 0x%x from controller\n", ret);
5593c8
+    } while ((ret == GRUB_AT_ACK || ret == GRUB_AT_NACK) && grub_get_time_ms () < endtime);
5593c8
+    if (ret == 0xfe) {
5593c8
+      grub_dprintf ("atkeyb", "query_mode: asking controller to resend last result\n");
5593c8
+      ret = resend_last_result();
5593c8
+      grub_dprintf ("atkeyb", "query_mode: read 0x%x from controller\n", ret);
5593c8
+    }
5593c8
+    /* QEMU translates the set even in no-translate mode.  */
5593c8
+    if (ret == 0x43 || ret == 1) {
5593c8
+      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 1\n", ret);
5593c8
+      return 1;
5593c8
+    }
5593c8
+    if (ret == 0x41 || ret == 2) {
5593c8
+      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 2\n", ret);
5593c8
+      return 2;
5593c8
+    }
5593c8
+    if (ret == 0x3f || ret == 3) {
5593c8
+      grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 3\n", ret);
5593c8
+      return 3;
5593c8
+    }
5593c8
+    grub_dprintf ("atkeyb", "query_mode: controller returned unexpected value 0x%x, retrying\n", ret);
5593c8
   }
5593c8
-  if (ret == 0x3f || ret == 3) {
5593c8
-    grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret);
5593c8
-    return 3;
5593c8
+
5593c8
+  /*
5593c8
+   * Falling here means we tried querying and the controller returned something
5593c8
+   * we don't understand, try to use 'at_keyboard_fallback_set' if it exists,
5593c8
+   * otherwise return 0.
5593c8
+   */
5593c8
+  envvar = grub_env_get ("at_keyboard_fallback_set");
5593c8
+  if (envvar) {
5593c8
+    fallback_set = grub_strtoul (envvar, 0, 10);
5593c8
+    if ((grub_errno) || (fallback_set < 1) || (fallback_set > 3)) {
5593c8
+      grub_dprintf ("atkeyb", "WARNING: ignoring unexpected value '%s' for '%s' variable\n",
5593c8
+		    envvar, "at_keyboard_fallback_set");
5593c8
+      fallback_set = 0;
5593c8
+    } else {
5593c8
+      grub_dprintf ("atkeyb", "query_mode: '%s' specified in environment, returning %d\n",
5593c8
+		    "at_keyboard_fallback_set", fallback_set);
5593c8
+    }
5593c8
+    return fallback_set;
5593c8
   }
5593c8
+  grub_dprintf ("atkeyb", "WARNING: no '%s' specified in environment, returning 0\n",
5593c8
+		"at_keyboard_fallback_set");
5593c8
   return 0;
5593c8
 }
5593c8
 
5593c8
@@ -165,14 +224,25 @@ set_scancodes (void)
5593c8
 {
5593c8
   /* You must have visited computer museum. Keyboard without scancode set
5593c8
      knowledge. Assume XT. */
5593c8
-  if (!grub_keyboard_orig_set)
5593c8
-    {
5593c8
-      grub_dprintf ("atkeyb", "No sets support assumed\n");
5593c8
-      ps2_state.current_set = 1;
5593c8
+  if (!grub_keyboard_orig_set) {
5593c8
+    if (fallback_set) {
5593c8
+      grub_dprintf ("atkeyb", "No sets support assumed but set forced to %d\n", fallback_set);
5593c8
+      ps2_state.current_set = fallback_set;
5593c8
       return;
5593c8
     }
5593c8
+    grub_dprintf ("atkeyb", "No sets support assumed, forcing to set 1\n");
5593c8
+    ps2_state.current_set = 1;
5593c8
+    return;
5593c8
+  }
5593c8
 
5593c8
 #if !USE_SCANCODE_SET
5593c8
+  if (fallback_set) {
5593c8
+    grub_dprintf ("atkeyb", "queried set is %d but set forced to %d\n",
5593c8
+		  grub_keyboard_orig_set, fallback_set);
5593c8
+    ps2_state.current_set = fallback_set;
5593c8
+    return;
5593c8
+  }
5593c8
+
5593c8
   if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) {
5593c8
     grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set);
5593c8
     ps2_state.current_set = 1;
5593c8
@@ -261,6 +331,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
5593c8
 static void
5593c8
 grub_keyboard_controller_init (void)
5593c8
 {
5593c8
+  grub_dprintf ("atkeyb", "initializing the controller\n");
5593c8
   ps2_state.at_keyboard_status = 0;
5593c8
   /* Drain input buffer. */
5593c8
   while (1)
5593c8
@@ -282,6 +353,7 @@ grub_keyboard_controller_init (void)
5593c8
   grub_keyboard_controller_orig = grub_keyboard_controller_read ();
5593c8
   grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig);
5593c8
   grub_keyboard_orig_set = query_mode ();
5593c8
+  grub_dprintf ("atkeyb", "grub_keyboard_orig_set = %d\n", grub_keyboard_orig_set);
5593c8
 #endif
5593c8
   set_scancodes ();
5593c8
   keyboard_controller_led (ps2_state.led_status);
5593c8
@@ -329,7 +401,6 @@ grub_at_restore_hw (void)
5593c8
   return GRUB_ERR_NONE;
5593c8
 }
5593c8
 
5593c8
-
5593c8
 static struct grub_term_input grub_at_keyboard_term =
5593c8
   {
5593c8
     .name = "at_keyboard",