dcavalca / rpms / grub2

Forked from rpms/grub2 3 years ago
Clone

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

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