[U-Boot] [PATCH 2/6] efi_loader: support Unicode text input

Heinrich Schuchardt xypron.glpk at gmx.de
Sun Sep 9 05:57:00 UTC 2018


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.glpk at 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



More information about the U-Boot mailing list