Up to now the EFI_TEXT_INPUT_PROTOCOL only supported ASCII characters.

With the patch it can consume UTF-8 from the serial console or
codepage 437 special characters from the local keyboard.

Signed-off-by: Heinrich Schuchardt <xypron.g...@gmx.de>
---
 lib/efi_loader/efi_console.c | 80 ++++++++++++++++++++++++++++++++++--
 1 file changed, 76 insertions(+), 4 deletions(-)

diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 3ca6fe536c..8c45290b2e 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -15,12 +15,18 @@
 #define EFI_COUT_MODE_2 2
 #define EFI_MAX_COUT_MODE 3
 
+/* Keyboard layouts */
+#define KBD_US         0       /* default US layout */
+#define KBD_GER                1       /* German layout */
+
 struct cout_mode {
        unsigned long columns;
        unsigned long rows;
        int present;
 };
 
+static int keymap = KBD_US;
+
 static struct cout_mode efi_cout_modes[] = {
        /* EFI Mode 0 is 80x25 and always present */
        {
@@ -390,6 +396,19 @@ struct efi_simple_text_output_protocol efi_con_out = {
        .mode = (void*)&efi_con_mode,
 };
 
+static void efi_set_keymap(void)
+{
+       char *penv;
+
+       /* Init keyboard device (default US layout) */
+       keymap = KBD_US;
+       penv = env_get("keymap");
+       if (penv) {
+               if (strncmp(penv, "de", 3) == 0)
+                       keymap = KBD_GER;
+       }
+}
+
 static efi_status_t EFIAPI efi_cin_reset(
                        struct efi_simple_text_input_protocol *this,
                        bool extended_verification)
@@ -453,17 +472,16 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
                .scan_code = 0,
                .unicode_char = 0,
        };
-       char ch;
+       int ch;
 
        EFI_ENTRY("%p, %p", this, key);
 
        /* We don't do interrupts, so check for timers cooperatively */
        efi_timer_check();
 
-       if (!tstc()) {
+       if (!tstc())
                /* No key pressed */
-               return EFI_EXIT(EFI_NOT_READY);
-       }
+               goto error;
 
        ch = getc();
        if (ch == cESC) {
@@ -550,12 +568,63 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
        } else if (ch == 0x7f) {
                /* Backspace */
                ch = 0x08;
+       } else if (keymap == KBD_US && ch >= 0xc2 && ch <= 0xf4) {
+               /*
+                * Unicode
+                *
+                * We assume here that the serial console is using UTF-8.
+                * This of cause depends on the terminal settings.
+                */
+               int code = 0;
+
+               if (ch >= 0xe0) {
+                       if (ch >= 0xf0) {
+                               /* 0xf0 - 0xf4 */
+                               ch &= 0x07;
+                               code = ch << 18;
+                               ch = getc();
+                               if (ch < 0x80 || ch > 0xbf)
+                                       goto error;
+                               ch &= 0x3f;
+                       } else {
+                               /* 0xe0 - 0xef */
+                               ch &= 0x0f;
+                       }
+                       code += ch << 12;
+                       if ((code >= 0xD800 && code <= 0xDFFF) ||
+                           code >= 0x110000)
+                               goto error;
+                       ch = getc();
+                       if (ch < 0x80 || ch > 0xbf)
+                               goto error;
+               }
+               /* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
+               ch &= 0x3f;
+               code += ch << 6;
+               ch = getc();
+               if (ch < 0x80 || ch > 0xbf)
+                       goto error;
+               ch &= 0x3f;
+               ch += code;
+       } else if (keymap != KBD_US && ch >= 0x80 && ch <= 0xff) {
+               /*
+                * Code page 437 special characters
+                *
+                * The keyboard drivers emit code page 437 characters. Support
+                * for German language special characters can be enabled via
+                * environment variable 'keymap' in the i8042 driver.
+                */
+               ch = codepage_437[ch - 0x80];
+       } else if (ch >= 0x80) {
+               goto error;
        }
        if (!pressed_key.scan_code)
                pressed_key.unicode_char = ch;
        *key = pressed_key;
 
        return EFI_EXIT(EFI_SUCCESS);
+error:
+       return EFI_EXIT(EFI_NOT_READY);
 }
 
 struct efi_simple_text_input_protocol efi_con_in = {
@@ -597,6 +666,9 @@ int efi_console_register(void)
        struct efi_object *efi_console_output_obj;
        struct efi_object *efi_console_input_obj;
 
+       /* Set keymap */
+       efi_set_keymap();
+
        /* Set up mode information */
        query_console_size();
 
-- 
2.18.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to