nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

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

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