All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/6] efi_loader: fixes for EFI_SIMPLE_TEXT_INPUT_PROTOCOL
@ 2018-09-09  5:56 Heinrich Schuchardt
  2018-09-09  5:56 ` [U-Boot] [PATCH 1/6] efi_loader: global symbol for code page 437 Heinrich Schuchardt
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Heinrich Schuchardt @ 2018-09-09  5:56 UTC (permalink / raw)
  To: u-boot

This patch series contains fixes for the EFI_SIMPLE_TEXT_INPUT_PROTOCOL.

Support Unicode letters received as UTF-8 from the serial console.
Support code page 437 letters received from the local console.
Correct handling of the WaitForKey event.
Update unit test.

Heinrich Schuchardt (6):
  efi_loader: global symbol for code page 437
  efi_loader: support Unicode text input
  test/py: Unicode w/ EFI_SIMPLE_TEXT_INPUT_PROTOCOL
  efi_selftest: refactor text input test
  efi_loader: rework event handling for console
  efi_selftest: use WaitForKey to test text input

 include/charset.h                         |   6 +
 include/efi_selftest.h                    |  16 ++
 lib/charset.c                             |   3 +
 lib/efi_loader/efi_console.c              | 256 ++++++++++++++++++----
 lib/efi_loader/efi_unicode_collation.c    |   3 +-
 lib/efi_selftest/efi_selftest_textinput.c | 136 +++---------
 lib/efi_selftest/efi_selftest_util.c      |  93 ++++++++
 test/py/tests/test_efi_selftest.py        |   7 +
 8 files changed, 367 insertions(+), 153 deletions(-)

-- 
2.18.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH 1/6] efi_loader: global symbol for code page 437
  2018-09-09  5:56 [U-Boot] [PATCH 0/6] efi_loader: fixes for EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
@ 2018-09-09  5:56 ` Heinrich Schuchardt
  2018-09-09  5:57 ` [U-Boot] [PATCH 2/6] efi_loader: support Unicode text input Heinrich Schuchardt
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Heinrich Schuchardt @ 2018-09-09  5:56 UTC (permalink / raw)
  To: u-boot

We require code page 437 both for text input and for the Unicode collation
protocol. We should have the translation table to Unicode only once.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 include/charset.h                      | 6 ++++++
 lib/charset.c                          | 3 +++
 lib/efi_loader/efi_unicode_collation.c | 3 +--
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/include/charset.h b/include/charset.h
index 686db5a1fe..32cc66bf5c 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -13,6 +13,12 @@
 
 #define MAX_UTF8_PER_UTF16 3
 
+/**
+ * codepage_437[] - Unicode code points for characters 0x80-0xff of
+ *		    code page 437.
+ */
+extern const u16 codepage_437[];
+
 /**
  * utf8_get() - get next UTF-8 code point from buffer
  *
diff --git a/lib/charset.c b/lib/charset.c
index 72c808ce64..f7ec2d25d3 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -7,6 +7,7 @@
 
 #include <charset.h>
 #include <capitalization.h>
+#include <cp437.h>
 #include <malloc.h>
 
 static struct capitalization_table capitalization_table[] =
@@ -18,6 +19,8 @@ static struct capitalization_table capitalization_table[] =
 	CP437_CAPITALIZATION_TABLE;
 #endif
 
+const u16 codepage_437[] = CP437;
+
 s32 utf8_get(const char **src)
 {
 	s32 code = 0;
diff --git a/lib/efi_loader/efi_unicode_collation.c b/lib/efi_loader/efi_unicode_collation.c
index 7f3ea3c77e..e005f345a9 100644
--- a/lib/efi_loader/efi_unicode_collation.c
+++ b/lib/efi_loader/efi_unicode_collation.c
@@ -8,7 +8,6 @@
 #include <common.h>
 #include <charset.h>
 #include <cp1250.h>
-#include <cp437.h>
 #include <efi_loader.h>
 
 /* Characters that may not be used in file names */
@@ -23,7 +22,7 @@ static const char illegal[] = "<>:\"/\\|?*";
 static const u16 codepage[] = CP1250;
 #else
 /* Unicode code points for code page 437 characters 0x80 - 0xff */
-static const u16 codepage[] = CP437;
+static const u16 *codepage = codepage_437;
 #endif
 
 /* GUID of the EFI_UNICODE_COLLATION_PROTOCOL */
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH 2/6] efi_loader: support Unicode text input
  2018-09-09  5:56 [U-Boot] [PATCH 0/6] efi_loader: fixes for EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
  2018-09-09  5:56 ` [U-Boot] [PATCH 1/6] efi_loader: global symbol for code page 437 Heinrich Schuchardt
@ 2018-09-09  5:57 ` Heinrich Schuchardt
  2018-09-10 10:05   ` Alexander Graf
  2018-09-09  5:57 ` [U-Boot] [PATCH 3/6] test/py: Unicode w/ EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 9+ messages in thread
From: Heinrich Schuchardt @ 2018-09-09  5:57 UTC (permalink / raw)
  To: u-boot

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@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

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH 3/6] test/py: Unicode w/ EFI_SIMPLE_TEXT_INPUT_PROTOCOL
  2018-09-09  5:56 [U-Boot] [PATCH 0/6] efi_loader: fixes for EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
  2018-09-09  5:56 ` [U-Boot] [PATCH 1/6] efi_loader: global symbol for code page 437 Heinrich Schuchardt
  2018-09-09  5:57 ` [U-Boot] [PATCH 2/6] efi_loader: support Unicode text input Heinrich Schuchardt
@ 2018-09-09  5:57 ` Heinrich Schuchardt
  2018-09-09  5:57 ` [U-Boot] [PATCH 4/6] efi_selftest: refactor text input test Heinrich Schuchardt
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Heinrich Schuchardt @ 2018-09-09  5:57 UTC (permalink / raw)
  To: u-boot

Test that the Euro sign is correctly retrieved from the console via the
EFI_SIMPLE_TEXT_INPUT_PROTOCOL.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 test/py/tests/test_efi_selftest.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index 994d2e2241..5d0dba6f4e 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -100,6 +100,13 @@ def test_efi_selftest_text_input(u_boot_console):
 	if m != 0:
 		raise Exception('UP failed in \'text input\' test')
 	u_boot_console.drain_console()
+	# Euro sign
+	u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(['Unicode char 8364'])
+	if m != 0:
+		raise Exception('Euro sign failed in \'text input\' test')
+	u_boot_console.drain_console()
 	u_boot_console.run_command(cmd='x', wait_for_echo=False, send_nl=False,
 				   wait_for_prompt=False)
 	m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH 4/6] efi_selftest: refactor text input test
  2018-09-09  5:56 [U-Boot] [PATCH 0/6] efi_loader: fixes for EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
                   ` (2 preceding siblings ...)
  2018-09-09  5:57 ` [U-Boot] [PATCH 3/6] test/py: Unicode w/ EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
@ 2018-09-09  5:57 ` Heinrich Schuchardt
  2018-09-09  5:57 ` [U-Boot] [PATCH 5/6] efi_loader: rework event handling for console Heinrich Schuchardt
  2018-09-09  5:57 ` [U-Boot] [PATCH 6/6] efi_selftest: use WaitForKey to test text input Heinrich Schuchardt
  5 siblings, 0 replies; 9+ messages in thread
From: Heinrich Schuchardt @ 2018-09-09  5:57 UTC (permalink / raw)
  To: u-boot

Move reusable utility functions to efi_selftest_util.c.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 include/efi_selftest.h                    |  16 ++++
 lib/efi_selftest/efi_selftest_textinput.c | 109 +---------------------
 lib/efi_selftest/efi_selftest_util.c      |  93 ++++++++++++++++++
 3 files changed, 111 insertions(+), 107 deletions(-)

diff --git a/include/efi_selftest.h b/include/efi_selftest.h
index 59b3c080bd..56beac305e 100644
--- a/include/efi_selftest.h
+++ b/include/efi_selftest.h
@@ -76,6 +76,22 @@ void efi_st_exit_boot_services(void);
 void efi_st_printc(int color, const char *fmt, ...)
 		 __attribute__ ((format (__printf__, 2, 3)));
 
+/**
+ * efi_st_translate_char() - translate a unicode character to a string
+ *
+ * @code:	unicode character
+ * Return:	string
+ */
+u16 *efi_st_translate_char(u16 code);
+
+/**
+ * efi_st_translate_code() - translate a scan code to a human readable string
+ *
+ * @code:	unicode character
+ * Return:	string
+ */
+u16 *efi_st_translate_code(u16 code);
+
 /*
  * Compare memory.
  * We cannot use lib/string.c due to different CFLAGS values.
diff --git a/lib/efi_selftest/efi_selftest_textinput.c b/lib/efi_selftest/efi_selftest_textinput.c
index 7aa84de89d..40b0a8b25c 100644
--- a/lib/efi_selftest/efi_selftest_textinput.c
+++ b/lib/efi_selftest/efi_selftest_textinput.c
@@ -14,113 +14,8 @@
 
 #include <efi_selftest.h>
 
-struct translate {
-	u16 code;
-	u16 *text;
-};
-
 static struct efi_boot_services *boottime;
 
-static struct translate control_characters[] = {
-	{0, L"Null"},
-	{8, L"BS"},
-	{9, L"TAB"},
-	{10, L"LF"},
-	{13, L"CR"},
-	{0, NULL},
-};
-
-static u16 ch[] = L"' '";
-static u16 unknown[] = L"unknown";
-
-static struct translate scan_codes[] = {
-	{0x00, L"Null"},
-	{0x01, L"Up"},
-	{0x02, L"Down"},
-	{0x03, L"Right"},
-	{0x04, L"Left"},
-	{0x05, L"Home"},
-	{0x06, L"End"},
-	{0x07, L"Insert"},
-	{0x08, L"Delete"},
-	{0x09, L"Page Up"},
-	{0x0a, L"Page Down"},
-	{0x0b, L"FN 1"},
-	{0x0c, L"FN 2"},
-	{0x0d, L"FN 3"},
-	{0x0e, L"FN 4"},
-	{0x0f, L"FN 5"},
-	{0x10, L"FN 6"},
-	{0x11, L"FN 7"},
-	{0x12, L"FN 8"},
-	{0x13, L"FN 9"},
-	{0x14, L"FN 10"},
-	{0x15, L"FN 11"},
-	{0x16, L"FN 12"},
-	{0x17, L"Escape"},
-	{0x68, L"FN 13"},
-	{0x69, L"FN 14"},
-	{0x6a, L"FN 15"},
-	{0x6b, L"FN 16"},
-	{0x6c, L"FN 17"},
-	{0x6d, L"FN 18"},
-	{0x6e, L"FN 19"},
-	{0x6f, L"FN 20"},
-	{0x70, L"FN 21"},
-	{0x71, L"FN 22"},
-	{0x72, L"FN 23"},
-	{0x73, L"FN 24"},
-	{0x7f, L"Mute"},
-	{0x80, L"Volume Up"},
-	{0x81, L"Volume Down"},
-	{0x100, L"Brightness Up"},
-	{0x101, L"Brightness Down"},
-	{0x102, L"Suspend"},
-	{0x103, L"Hibernate"},
-	{0x104, L"Toggle Display"},
-	{0x105, L"Recovery"},
-	{0x106, L"Reject"},
-	{0x0, NULL},
-};
-
-/*
- * Translate a unicode character to a string.
- *
- * @code	unicode character
- * @return	string
- */
-static u16 *translate_char(u16 code)
-{
-	struct translate *tr;
-
-	if (code >= ' ') {
-		ch[1] = code;
-		return ch;
-	}
-	for (tr = control_characters; tr->text; ++tr) {
-		if (tr->code == code)
-			return tr->text;
-	}
-	return unknown;
-}
-
-/*
- * Translate a scan code to a human readable string.
- *
- * @code	unicode character
- * @return	string
- */
-static u16 *translate_code(u16 code)
-{
-	struct translate *tr;
-
-	for (tr = scan_codes; tr->text; ++tr) {
-		if (tr->code == code)
-			return tr->text;
-	}
-	return unknown;
-}
-
 /*
  * Setup unit test.
  *
@@ -160,9 +55,9 @@ static int execute(void)
 
 		efi_st_printf("Unicode char %u (%ps), scan code %u (%ps)\n",
 			      (unsigned int)input_key.unicode_char,
-			      translate_char(input_key.unicode_char),
+			      efi_st_translate_char(input_key.unicode_char),
 			      (unsigned int)input_key.scan_code,
-			      translate_code(input_key.scan_code));
+			      efi_st_translate_code(input_key.scan_code));
 
 		switch (input_key.unicode_char) {
 		case 'x':
diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c
index 87a04f898a..96a964c863 100644
--- a/lib/efi_selftest/efi_selftest_util.c
+++ b/lib/efi_selftest/efi_selftest_util.c
@@ -9,6 +9,99 @@
 
 #include <efi_selftest.h>
 
+struct efi_st_translate {
+	u16 code;
+	u16 *text;
+};
+
+static struct efi_st_translate efi_st_control_characters[] = {
+	{0, L"Null"},
+	{8, L"BS"},
+	{9, L"TAB"},
+	{10, L"LF"},
+	{13, L"CR"},
+	{0, NULL},
+};
+
+static u16 efi_st_ch[] = L"' '";
+static u16 efi_st_unknown[] = L"unknown";
+
+static struct efi_st_translate efi_st_scan_codes[] = {
+	{0x00, L"Null"},
+	{0x01, L"Up"},
+	{0x02, L"Down"},
+	{0x03, L"Right"},
+	{0x04, L"Left"},
+	{0x05, L"Home"},
+	{0x06, L"End"},
+	{0x07, L"Insert"},
+	{0x08, L"Delete"},
+	{0x09, L"Page Up"},
+	{0x0a, L"Page Down"},
+	{0x0b, L"FN 1"},
+	{0x0c, L"FN 2"},
+	{0x0d, L"FN 3"},
+	{0x0e, L"FN 4"},
+	{0x0f, L"FN 5"},
+	{0x10, L"FN 6"},
+	{0x11, L"FN 7"},
+	{0x12, L"FN 8"},
+	{0x13, L"FN 9"},
+	{0x14, L"FN 10"},
+	{0x15, L"FN 11"},
+	{0x16, L"FN 12"},
+	{0x17, L"Escape"},
+	{0x68, L"FN 13"},
+	{0x69, L"FN 14"},
+	{0x6a, L"FN 15"},
+	{0x6b, L"FN 16"},
+	{0x6c, L"FN 17"},
+	{0x6d, L"FN 18"},
+	{0x6e, L"FN 19"},
+	{0x6f, L"FN 20"},
+	{0x70, L"FN 21"},
+	{0x71, L"FN 22"},
+	{0x72, L"FN 23"},
+	{0x73, L"FN 24"},
+	{0x7f, L"Mute"},
+	{0x80, L"Volume Up"},
+	{0x81, L"Volume Down"},
+	{0x100, L"Brightness Up"},
+	{0x101, L"Brightness Down"},
+	{0x102, L"Suspend"},
+	{0x103, L"Hibernate"},
+	{0x104, L"Toggle Display"},
+	{0x105, L"Recovery"},
+	{0x106, L"Reject"},
+	{0x0, NULL},
+};
+
+u16 *efi_st_translate_char(u16 code)
+{
+	struct efi_st_translate *tr;
+
+	if (code >= ' ') {
+		efi_st_ch[1] = code;
+		return efi_st_ch;
+	}
+	for (tr = efi_st_control_characters; tr->text; ++tr) {
+		if (tr->code == code)
+			return tr->text;
+	}
+	return efi_st_unknown;
+}
+
+u16 *efi_st_translate_code(u16 code)
+{
+	struct efi_st_translate *tr;
+
+	for (tr = efi_st_scan_codes; tr->text; ++tr) {
+		if (tr->code == code)
+			return tr->text;
+	}
+	return efi_st_unknown;
+}
+
 int efi_st_memcmp(const void *buf1, const void *buf2, size_t length)
 {
 	const u8 *pos1 = buf1;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH 5/6] efi_loader: rework event handling for console
  2018-09-09  5:56 [U-Boot] [PATCH 0/6] efi_loader: fixes for EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
                   ` (3 preceding siblings ...)
  2018-09-09  5:57 ` [U-Boot] [PATCH 4/6] efi_selftest: refactor text input test Heinrich Schuchardt
@ 2018-09-09  5:57 ` Heinrich Schuchardt
  2018-09-09  5:57 ` [U-Boot] [PATCH 6/6] efi_selftest: use WaitForKey to test text input Heinrich Schuchardt
  5 siblings, 0 replies; 9+ messages in thread
From: Heinrich Schuchardt @ 2018-09-09  5:57 UTC (permalink / raw)
  To: u-boot

Preread the next key in the console timer event.

The EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL requires to trigger registered key
notification functions based on the prefetched key.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 lib/efi_loader/efi_console.c | 204 ++++++++++++++++++++++++++---------
 1 file changed, 153 insertions(+), 51 deletions(-)

diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 8c45290b2e..1dbf73afc2 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -396,34 +396,12 @@ 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)
-{
-	EFI_ENTRY("%p, %d", this, extended_verification);
-
-	/* Empty input buffer */
-	while (tstc())
-		getc();
-
-	return EFI_EXIT(EFI_SUCCESS);
-}
+static bool key_available;
+static struct efi_input_key next_key;
 
-/*
- * Analyze modifiers (shift, alt, ctrl) for function keys.
+/**
+ * skip_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
+ *
  * This gets called when we have already parsed CSI.
  *
  * @modifiers:  bitmask (shift, alt, ctrl)
@@ -464,9 +442,13 @@ out:
 	return ret;
 }
 
-static efi_status_t EFIAPI efi_cin_read_key_stroke(
-			struct efi_simple_text_input_protocol *this,
-			struct efi_input_key *key)
+/**
+ * efi_cin_read_key() - read a key from the console input
+ *
+ * @key:	- key received
+ * Return:	- status code
+ */
+static efi_status_t efi_cin_read_key(struct efi_input_key *key)
 {
 	struct efi_input_key pressed_key = {
 		.scan_code = 0,
@@ -474,11 +456,6 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
 	};
 	int ch;
 
-	EFI_ENTRY("%p, %p", this, key);
-
-	/* We don't do interrupts, so check for timers cooperatively */
-	efi_timer_check();
-
 	if (!tstc())
 		/* No key pressed */
 		goto error;
@@ -622,9 +599,127 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
 		pressed_key.unicode_char = ch;
 	*key = pressed_key;
 
-	return EFI_EXIT(EFI_SUCCESS);
+	return EFI_SUCCESS;
 error:
-	return EFI_EXIT(EFI_NOT_READY);
+	return EFI_NOT_READY;
+}
+
+/**
+ * efi_cin_check() - check if keyboard input is available
+ */
+static void efi_cin_check(void)
+{
+	efi_status_t ret;
+
+	if (key_available) {
+		efi_signal_event(efi_con_in.wait_for_key, true);
+		return;
+	}
+
+	if (tstc()) {
+		ret = efi_cin_read_key(&next_key);
+		if (ret == EFI_SUCCESS) {
+			key_available = true;
+
+			/* Queue the wait for key event */
+			efi_signal_event(efi_con_in.wait_for_key, true);
+		}
+	}
+}
+
+/**
+ * efi_set_keymap() - determine the keyboard layout
+ */
+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;
+	}
+}
+
+/**
+ * efi_cin_reset() - drain the input buffer
+ *
+ * @this:			instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @extended_verification:	allow for exhaustive verification
+ * Return:			status code
+ *
+ * This function implements the Reset service of the
+ * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_reset(
+			struct efi_simple_text_input_protocol *this,
+			bool extended_verification)
+{
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %d", this, extended_verification);
+
+	/* Check parameters */
+	if (!this) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	/* Empty input buffer */
+	while (tstc())
+		getc();
+	key_available = false;
+out:
+	return EFI_EXIT(ret);
+}
+
+/**
+ * efi_cin_reset() - drain the input buffer
+ *
+ * @this:	instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @key:	key read from console
+ * Return:	status code
+ *
+ * This function implements the ReadKeyStroke service of the
+ * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_read_key_stroke(
+			struct efi_simple_text_input_protocol *this,
+			struct efi_input_key *key)
+{
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %p", this, key);
+
+	/* Check parameters */
+	if (!this || !key) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	/* We don't do interrupts, so check for timers cooperatively */
+	efi_timer_check();
+
+	/* Enable console input after ExitBootServices */
+	efi_cin_check();
+
+	if (!key_available) {
+		ret = EFI_NOT_READY;
+		goto out;
+	}
+	*key = next_key;
+	key_available = false;
+	efi_con_in.wait_for_key->is_signaled = false;
+out:
+	return EFI_EXIT(ret);
 }
 
 struct efi_simple_text_input_protocol efi_con_in = {
@@ -635,31 +730,38 @@ struct efi_simple_text_input_protocol efi_con_in = {
 
 static struct efi_event *console_timer_event;
 
-static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
-{
-}
-
 /*
- * Notification function of the console timer event.
+ * efi_console_timer_notify() - notify the console timer event
  *
- * event:	console timer event
- * context:	not used
+ * @event:	console timer event
+ * @context:	not used
  */
 static void EFIAPI efi_console_timer_notify(struct efi_event *event,
 					    void *context)
 {
 	EFI_ENTRY("%p, %p", event, context);
+	efi_cin_check();
+	EFI_EXIT(EFI_SUCCESS);
+}
 
-	/* Check if input is available */
-	if (tstc()) {
-		/* Queue the wait for key event */
-		efi_con_in.wait_for_key->is_signaled = true;
-		efi_signal_event(efi_con_in.wait_for_key, true);
-	}
+/**
+ * efi_key_notify() - notify the wait for key event
+ *
+ * @event:	wait for key event
+ * @context:	not used
+ */
+static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
+{
+	EFI_ENTRY("%p, %p", event, context);
+	efi_cin_check();
 	EFI_EXIT(EFI_SUCCESS);
 }
 
-/* This gets called from do_bootefi_exec(). */
+/**
+ * efi_console_register() - install the console protocols
+ *
+ * This function is called from do_bootefi_exec().
+ */
 int efi_console_register(void)
 {
 	efi_status_t r;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH 6/6] efi_selftest: use WaitForKey to test text input
  2018-09-09  5:56 [U-Boot] [PATCH 0/6] efi_loader: fixes for EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
                   ` (4 preceding siblings ...)
  2018-09-09  5:57 ` [U-Boot] [PATCH 5/6] efi_loader: rework event handling for console Heinrich Schuchardt
@ 2018-09-09  5:57 ` Heinrich Schuchardt
  5 siblings, 0 replies; 9+ messages in thread
From: Heinrich Schuchardt @ 2018-09-09  5:57 UTC (permalink / raw)
  To: u-boot

We should test the WaitForKey event.
Testing for EFI_NOT_READY can be done after resetting the console.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 lib/efi_selftest/efi_selftest_textinput.c | 27 ++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/lib/efi_selftest/efi_selftest_textinput.c b/lib/efi_selftest/efi_selftest_textinput.c
index 40b0a8b25c..164fbffe6c 100644
--- a/lib/efi_selftest/efi_selftest_textinput.c
+++ b/lib/efi_selftest/efi_selftest_textinput.c
@@ -40,15 +40,36 @@ static int execute(void)
 {
 	struct efi_input_key input_key = {0};
 	efi_status_t ret;
+	efi_uintn_t index;
+
+	/* Drain the console input */
+	ret = con_in->reset(con_in, true);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("Reset failed\n");
+		return EFI_ST_FAILURE;
+	}
+	ret = con_in->read_key_stroke(con_in, &input_key);
+	if (ret != EFI_NOT_READY) {
+		efi_st_error("Empty buffer not reported\n");
+		return EFI_ST_FAILURE;
+	}
 
 	efi_st_printf("Waiting for your input\n");
 	efi_st_printf("To terminate type 'x'\n");
 
 	for (;;) {
 		/* Wait for next key */
-		do {
-			ret = con_in->read_key_stroke(con_in, &input_key);
-		} while (ret == EFI_NOT_READY);
+		ret = boottime->wait_for_event(1, &con_in->wait_for_key,
+					       &index);
+		if (ret != EFI_ST_SUCCESS) {
+			efi_st_error("WaitForEvent failed\n");
+			return EFI_ST_FAILURE;
+		}
+		ret = con_in->read_key_stroke(con_in, &input_key);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("ReadKeyStroke failed\n");
+			return EFI_ST_FAILURE;
+		}
 
 		/* Allow 5 minutes until time out */
 		boottime->set_watchdog_timer(300, 0, 0, NULL);
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH 2/6] efi_loader: support Unicode text input
  2018-09-09  5:57 ` [U-Boot] [PATCH 2/6] efi_loader: support Unicode text input Heinrich Schuchardt
@ 2018-09-10 10:05   ` Alexander Graf
  2018-09-10 13:01     ` Alexander Graf
  0 siblings, 1 reply; 9+ messages in thread
From: Alexander Graf @ 2018-09-10 10:05 UTC (permalink / raw)
  To: u-boot

On 09/09/2018 07:57 AM, Heinrich Schuchardt wrote:
> 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@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;

I'm not terribly happy with this. It's very i8042 specific. Currently 
U-Boot only implements the keymap variable there. Couldn't we add an 
extended getc() that reads a full 32bit unicode value from the target 
device? That way we could add an interim layer that everyone - not just 
efi_loader - can use to extract keycodes coherently from any input.

> +	}
> +}
> +
>   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;

All of the logic above for example really shouldn't live inside of 
efi_loader. It belongs somewhere more generic.


Alex

> +	} 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();
>   

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [U-Boot] [PATCH 2/6] efi_loader: support Unicode text input
  2018-09-10 10:05   ` Alexander Graf
@ 2018-09-10 13:01     ` Alexander Graf
  0 siblings, 0 replies; 9+ messages in thread
From: Alexander Graf @ 2018-09-10 13:01 UTC (permalink / raw)
  To: u-boot

On 09/10/2018 12:05 PM, Alexander Graf wrote:
> On 09/09/2018 07:57 AM, Heinrich Schuchardt wrote:
>> 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@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;
>
> I'm not terribly happy with this. It's very i8042 specific. Currently 
> U-Boot only implements the keymap variable there. Couldn't we add an 
> extended getc() that reads a full 32bit unicode value from the target 
> device? That way we could add an interim layer that everyone - not 
> just efi_loader - can use to extract keycodes coherently from any input.

Or actually maybe using UTF-8 internally is the right way to go. Then we 
have less conversion and overhead to do in the default (serial) case.

Marek, what's your take on the idea? We could just make the i8042 driver 
emit UTF-8 codes on getc(). Then everything internally would just be 
based on UTF-8 and we don't need to push target input awareness into 
layers that really shouldn't care.

>
>> +    }
>> +}
>> +
>>   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;
>
> All of the logic above for example really shouldn't live inside of 
> efi_loader. It belongs somewhere more generic.

In fact, this probably should be a call in charset.c or so. Something 
like get_utf8() with a function pointer argument that basically just 
passes getc().


Alex

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-09-10 13:01 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-09  5:56 [U-Boot] [PATCH 0/6] efi_loader: fixes for EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
2018-09-09  5:56 ` [U-Boot] [PATCH 1/6] efi_loader: global symbol for code page 437 Heinrich Schuchardt
2018-09-09  5:57 ` [U-Boot] [PATCH 2/6] efi_loader: support Unicode text input Heinrich Schuchardt
2018-09-10 10:05   ` Alexander Graf
2018-09-10 13:01     ` Alexander Graf
2018-09-09  5:57 ` [U-Boot] [PATCH 3/6] test/py: Unicode w/ EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
2018-09-09  5:57 ` [U-Boot] [PATCH 4/6] efi_selftest: refactor text input test Heinrich Schuchardt
2018-09-09  5:57 ` [U-Boot] [PATCH 5/6] efi_loader: rework event handling for console Heinrich Schuchardt
2018-09-09  5:57 ` [U-Boot] [PATCH 6/6] efi_selftest: use WaitForKey to test text input Heinrich Schuchardt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.