dcavalca / rpms / grub2

Forked from rpms/grub2 3 years ago
Clone

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

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