* [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
@ 2018-09-11 20:38 Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 01/13] efi_loader: support Unicode text input Heinrich Schuchardt
` (12 more replies)
0 siblings, 13 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
Support Unicode letters received as UTF-8 from the serial console.
Correct handling of the WaitForKey event.
Update unit test for the EFI_SIMPLE_TEXT_INPUT__PROTOCOL.
Fix bugs for the EFI_SIMPLE_TEXT_INPUT__PROTOCOL.
Implement the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
Provide a unit test.
Fix a U-Boot binary size problem.
v3:
support modifiers for F1 - F4
ESC before a letter signifies the ALT modifier
do not use introduce EFI dependency in charset.c
v2:
merge two patch series
move reading of Unicode to charset.c
drop support for German keyboard layout
Heinrich Schuchardt (13):
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
test/py: rework test_efi_selftest_text_input()
efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
efi_loader: support modifiers for F1 - F4
efi_selftest: test EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
test/py: test EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
efi_loader: implement key notify functions
efi_selftest: test key notification functions
efi_loader: unset CONFIG_EFI_UNICODE_CAPITALIZATION
configs/vf610twr_defconfig | 1 +
configs/vf610twr_nand_defconfig | 1 +
include/charset.h | 9 +
include/efi_api.h | 56 ++
include/efi_selftest.h | 16 +
lib/charset.c | 136 +++--
lib/efi_loader/efi_console.c | 540 +++++++++++++++++---
lib/efi_selftest/Makefile | 1 +
lib/efi_selftest/efi_selftest_textinput.c | 136 +----
lib/efi_selftest/efi_selftest_textinputex.c | 198 +++++++
lib/efi_selftest/efi_selftest_util.c | 93 ++++
test/py/tests/test_efi_selftest.py | 101 +++-
test/unicode_ut.c | 8 +-
13 files changed, 1068 insertions(+), 228 deletions(-)
create mode 100644 lib/efi_selftest/efi_selftest_textinputex.c
--
2.18.0
^ permalink raw reply [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 01/13] efi_loader: support Unicode text input
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 21:37 ` Alexander Graf
2018-09-11 20:38 ` [U-Boot] [PATCH v3 02/13] test/py: Unicode w/ EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
` (11 subsequent siblings)
12 siblings, 1 reply; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 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 console.
Currently only the serial console and the console can deliver UTF-8.
Local consoles are restricted to ASCII.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v2:
drop support for German keyboard
move reading of Unicode code to charset.c
---
include/charset.h | 9 +++
lib/charset.c | 136 ++++++++++++++++++++++-------------
lib/efi_loader/efi_console.c | 13 ++--
test/unicode_ut.c | 8 +--
4 files changed, 108 insertions(+), 58 deletions(-)
diff --git a/include/charset.h b/include/charset.h
index 686db5a1fe..a7de5f6948 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -8,11 +8,20 @@
#ifndef __CHARSET_H_
#define __CHARSET_H_
+#include <efi.h>
#include <linux/kernel.h>
#include <linux/types.h>
#define MAX_UTF8_PER_UTF16 3
+/**
+ * console_read_unicode() - read Unicode code point from console
+ *
+ * @code: code point
+ * Return: 0 = success
+ */
+int console_read_unicode(s32 *code);
+
/**
* utf8_get() - get next UTF-8 code point from buffer
*
diff --git a/lib/charset.c b/lib/charset.c
index 72c808ce64..1806b41cc3 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -5,6 +5,7 @@
* Copyright (c) 2017 Rob Clark
*/
+#include <common.h>
#include <charset.h>
#include <capitalization.h>
#include <malloc.h>
@@ -18,67 +19,106 @@ static struct capitalization_table capitalization_table[] =
CP437_CAPITALIZATION_TABLE;
#endif
-s32 utf8_get(const char **src)
+/**
+ * get_code() - read Unicode code point from UTF-8 stream
+ *
+ * @read_u8: - stream reader
+ * @src: - string buffer passed to stream reader, optional
+ * Return: - Unicode code point
+ */
+static int get_code(u8 (*read_u8)(void *data), void *data)
{
- s32 code = 0;
- unsigned char c;
+ s32 ch = 0;
- if (!src || !*src)
- return -1;
- if (!**src)
+ ch = read_u8(data);
+ if (!ch)
return 0;
- c = **src;
- if (c >= 0x80) {
- ++*src;
- if (!**src)
- return -1;
- /*
- * We do not expect a continuation byte (0x80 - 0xbf).
- * 0x80 is coded as 0xc2 0x80, so we cannot have less then 0xc2
- * here.
- * The highest code point is 0x10ffff which is coded as
- * 0xf4 0x8f 0xbf 0xbf. So we cannot have a byte above 0xf4.
- */
- if (c < 0xc2 || code > 0xf4)
- return -1;
- if (c >= 0xe0) {
- if (c >= 0xf0) {
+ if (ch >= 0xc2 && ch <= 0xf4) {
+ int code = 0;
+
+ if (ch >= 0xe0) {
+ if (ch >= 0xf0) {
/* 0xf0 - 0xf4 */
- c &= 0x07;
- code = c << 18;
- c = **src;
- ++*src;
- if (!**src)
- return -1;
- if (c < 0x80 || c > 0xbf)
- return -1;
- c &= 0x3f;
+ ch &= 0x07;
+ code = ch << 18;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
+ ch &= 0x3f;
} else {
/* 0xe0 - 0xef */
- c &= 0x0f;
+ ch &= 0x0f;
}
- code += c << 12;
+ code += ch << 12;
if ((code >= 0xD800 && code <= 0xDFFF) ||
code >= 0x110000)
- return -1;
- c = **src;
- ++*src;
- if (!**src)
- return -1;
- if (c < 0x80 || c > 0xbf)
- return -1;
+ goto error;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
}
/* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
- c &= 0x3f;
- code += c << 6;
- c = **src;
- if (c < 0x80 || c > 0xbf)
- return -1;
- c &= 0x3f;
+ ch &= 0x3f;
+ code += ch << 6;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
+ ch &= 0x3f;
+ ch += code;
+ } else if (ch >= 0x80) {
+ goto error;
}
- code += c;
+ return ch;
+error:
+ return '?';
+}
+
+/**
+ * read_string() - read byte from character string
+ *
+ * @data: - pointer to string
+ * Return: - byte read
+ *
+ * The string pointer is incremented if it does not point to '\0'.
+ */
+static u8 read_string(void *data)
+
+{
+ const char **src = (const char **)data;
+ u8 c;
+
+ if (!src || !*src || !**src)
+ return 0;
+ c = (unsigned char)**src;
++*src;
- return code;
+ return c;
+}
+
+/**
+ * read_console() - read byte from console
+ *
+ * @src - not used, needed to match interface
+ * Return: - byte read
+ */
+static u8 read_console(void *data)
+{
+ return getc();
+}
+
+int console_read_unicode(s32 *code)
+{
+ if (!tstc())
+ /* No input available */
+ return 1;
+
+ /* Read Unicode code */
+ *code = get_code(read_console, NULL);
+ return 0;
+}
+
+s32 utf8_get(const char **src)
+{
+ return get_code(read_string, src);
}
int utf8_put(s32 code, char **dst)
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 3ca6fe536c..6af083984c 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -449,23 +449,24 @@ 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;
struct efi_input_key pressed_key = {
.scan_code = 0,
.unicode_char = 0,
};
- char ch;
+ s32 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 */
+ ret = console_read_unicode(&ch);
+ if (ret)
return EFI_EXIT(EFI_NOT_READY);
- }
-
- ch = getc();
+ /* We do not support multi-word codes */
+ if (ch >= 0x10000)
+ ch = '?';
if (ch == cESC) {
/*
* Xterm Control Sequences
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
index b94b4a651f..b115d18afd 100644
--- a/test/unicode_ut.c
+++ b/test/unicode_ut.c
@@ -178,7 +178,7 @@ static int ut_utf8_utf16_strlen(struct unit_test_state *uts)
/* illegal utf-8 sequences */
ut_asserteq(4, utf8_utf16_strlen(j1));
- ut_asserteq(5, utf8_utf16_strlen(j2));
+ ut_asserteq(4, utf8_utf16_strlen(j2));
ut_asserteq(3, utf8_utf16_strlen(j3));
return 0;
@@ -196,7 +196,7 @@ static int ut_utf8_utf16_strnlen(struct unit_test_state *uts)
/* illegal utf-8 sequences */
ut_asserteq(4, utf8_utf16_strnlen(j1, 16));
- ut_asserteq(5, utf8_utf16_strnlen(j2, 16));
+ ut_asserteq(4, utf8_utf16_strnlen(j2, 16));
ut_asserteq(3, utf8_utf16_strnlen(j3, 16));
return 0;
@@ -255,8 +255,8 @@ static int ut_utf8_utf16_strcpy(struct unit_test_state *uts)
pos = buf;
utf8_utf16_strcpy(&pos, j2);
- ut_asserteq(5, pos - buf);
- ut_assert(!ut_u16_strcmp(buf, L"j2??l", SIZE_MAX));
+ ut_asserteq(4, pos - buf);
+ ut_assert(!ut_u16_strcmp(buf, L"j2?l", SIZE_MAX));
pos = buf;
utf8_utf16_strcpy(&pos, j3);
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 02/13] test/py: Unicode w/ EFI_SIMPLE_TEXT_INPUT_PROTOCOL
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 01/13] efi_loader: support Unicode text input Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 03/13] efi_selftest: refactor text input test Heinrich Schuchardt
` (10 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 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>
---
v3
no change
v2
no change
---
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] 17+ messages in thread
* [U-Boot] [PATCH v3 03/13] efi_selftest: refactor text input test
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 01/13] efi_loader: support Unicode text input Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 02/13] test/py: Unicode w/ EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 04/13] efi_loader: rework event handling for console Heinrich Schuchardt
` (9 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
Move reusable utility functions to efi_selftest_util.c.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v03
no change
v02
no change
---
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] 17+ messages in thread
* [U-Boot] [PATCH v3 04/13] efi_loader: rework event handling for console
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (2 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 03/13] efi_selftest: refactor text input test Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 05/13] efi_selftest: use WaitForKey to test text input Heinrich Schuchardt
` (8 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 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>
---
v3
rebase patch
v2
rebase patch
---
lib/efi_loader/efi_console.c | 175 +++++++++++++++++++++++++++--------
1 file changed, 137 insertions(+), 38 deletions(-)
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 6af083984c..e191e027a8 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -390,21 +390,12 @@ struct efi_simple_text_output_protocol efi_con_out = {
.mode = (void*)&efi_con_mode,
};
-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();
+static bool key_available;
+static struct efi_input_key next_key;
- return EFI_EXIT(EFI_SUCCESS);
-}
-
-/*
- * 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)
@@ -445,9 +436,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)
{
efi_status_t ret;
struct efi_input_key pressed_key = {
@@ -456,14 +451,9 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
};
s32 ch;
- EFI_ENTRY("%p, %p", this, key);
-
- /* We don't do interrupts, so check for timers cooperatively */
- efi_timer_check();
-
ret = console_read_unicode(&ch);
if (ret)
- return EFI_EXIT(EFI_NOT_READY);
+ return EFI_NOT_READY;
/* We do not support multi-word codes */
if (ch >= 0x10000)
ch = '?';
@@ -556,7 +546,109 @@ 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;
+}
+
+/**
+ * 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_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 = {
@@ -567,31 +659,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] 17+ messages in thread
* [U-Boot] [PATCH v3 05/13] efi_selftest: use WaitForKey to test text input
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (3 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 04/13] efi_loader: rework event handling for console Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 06/13] test/py: rework test_efi_selftest_text_input() Heinrich Schuchardt
` (7 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 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>
---
v3
no change
v2
no change
---
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] 17+ messages in thread
* [U-Boot] [PATCH v3 06/13] test/py: rework test_efi_selftest_text_input()
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (4 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 05/13] efi_selftest: use WaitForKey to test text input Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 07/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (6 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
Use more precise regular expressions.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3
no change
v2
no change
---
test/py/tests/test_efi_selftest.py | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index 5d0dba6f4e..3e70abdafc 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -68,42 +68,47 @@ def test_efi_selftest_text_input(u_boot_console):
# EOT
u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
- m = u_boot_console.p.expect(['Unicode char 4'])
+ m = u_boot_console.p.expect(
+ ['Unicode char 4 \(unknown\), scan code 0 \(Null\)'])
if m != 0:
raise Exception('EOT failed in \'text input\' test')
u_boot_console.drain_console()
# BS
u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
- m = u_boot_console.p.expect(['(BS)'])
+ m = u_boot_console.p.expect(
+ ['Unicode char 8 \(BS\), scan code 0 \(Null\)'])
if m != 0:
raise Exception('BS failed in \'text input\' test')
u_boot_console.drain_console()
# TAB
u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
- m = u_boot_console.p.expect(['(TAB)'])
+ m = u_boot_console.p.expect(
+ ['Unicode char 9 \(TAB\), scan code 0 \(Null\)'])
if m != 0:
raise Exception('BS failed in \'text input\' test')
u_boot_console.drain_console()
# a
u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
wait_for_prompt=False)
- m = u_boot_console.p.expect(['(\'a\')'])
+ m = u_boot_console.p.expect(
+ ['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
if m != 0:
raise Exception('\'a\' failed in \'text input\' test')
u_boot_console.drain_console()
# UP escape sequence
u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
send_nl=False, wait_for_prompt=False)
- m = u_boot_console.p.expect(['(Up)'])
+ m = u_boot_console.p.expect(
+ ['Unicode char 0 \(Null\), scan code 1 \(Up\)'])
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'])
+ 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()
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 07/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (5 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 06/13] test/py: rework test_efi_selftest_text_input() Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 08/13] efi_loader: support modifiers for F1 - F4 Heinrich Schuchardt
` (5 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
This patch implements the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
The implementation of notification functions is postponed to a later
patch.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3:
fix support for CTRL+l
repace Unicode code points over 0xffff to '?'
v2:
rebase patch
---
include/efi_api.h | 56 ++++++++
lib/efi_loader/efi_console.c | 253 ++++++++++++++++++++++++++++++++---
2 files changed, 287 insertions(+), 22 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h
index ae840d1bb4..5004f520ff 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -588,11 +588,67 @@ struct efi_simple_text_output_protocol {
struct simple_text_output_mode *mode;
};
+#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
+ EFI_GUID(0xdd9e7534, 0x7762, 0x4698, \
+ 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa)
+
struct efi_input_key {
u16 scan_code;
s16 unicode_char;
};
+#define EFI_SHIFT_STATE_INVALID 0x00000000
+#define EFI_RIGHT_SHIFT_PRESSED 0x00000001
+#define EFI_LEFT_SHIFT_PRESSED 0x00000002
+#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
+#define EFI_LEFT_CONTROL_PRESSED 0x00000008
+#define EFI_RIGHT_ALT_PRESSED 0x00000010
+#define EFI_LEFT_ALT_PRESSED 0x00000020
+#define EFI_RIGHT_LOGO_PRESSED 0x00000040
+#define EFI_LEFT_LOGO_PRESSED 0x00000080
+#define EFI_MENU_KEY_PRESSED 0x00000100
+#define EFI_SYS_REQ_PRESSED 0x00000200
+#define EFI_SHIFT_STATE_VALID 0x80000000
+
+#define EFI_TOGGLE_STATE_INVALID 0x00
+#define EFI_SCROLL_LOCK_ACTIVE 0x01
+#define EFI_NUM_LOCK_ACTIVE 0x02
+#define EFI_CAPS_LOCK_ACTIVE 0x04
+#define EFI_KEY_STATE_EXPOSED 0x40
+#define EFI_TOGGLE_STATE_VALID 0x80
+
+struct efi_key_state {
+ u32 key_shift_state;
+ u8 key_toggle_state;
+};
+
+struct efi_key_data {
+ struct efi_input_key key;
+ struct efi_key_state key_state;
+};
+
+struct efi_simple_text_input_ex_protocol {
+ efi_status_t (EFIAPI *reset) (
+ struct efi_simple_text_input_ex_protocol *this,
+ bool extended_verification);
+ efi_status_t (EFIAPI *read_key_stroke_ex) (
+ struct efi_simple_text_input_ex_protocol *this,
+ struct efi_key_data *key_data);
+ struct efi_event *wait_for_key_ex;
+ efi_status_t (EFIAPI *set_state) (
+ struct efi_simple_text_input_ex_protocol *this,
+ u8 key_toggle_state);
+ efi_status_t (EFIAPI *register_key_notify) (
+ struct efi_simple_text_input_ex_protocol *this,
+ struct efi_key_data *key_data,
+ efi_status_t (EFIAPI *key_notify_function)(
+ struct efi_key_data *key_data),
+ void **notify_handle);
+ efi_status_t (EFIAPI *unregister_key_notify) (
+ struct efi_simple_text_input_ex_protocol *this,
+ void *notification_handle);
+};
+
#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \
EFI_GUID(0x387477c1, 0x69c7, 0x11d2, \
0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index e191e027a8..d17f0a13f9 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -42,10 +42,12 @@ static struct cout_mode efi_cout_modes[] = {
},
};
-const efi_guid_t efi_guid_text_output_protocol =
- EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
+const efi_guid_t efi_guid_text_input_ex_protocol =
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
const efi_guid_t efi_guid_text_input_protocol =
EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
+const efi_guid_t efi_guid_text_output_protocol =
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
#define cESC '\x1b'
#define ESC "\x1b"
@@ -391,19 +393,19 @@ struct efi_simple_text_output_protocol efi_con_out = {
};
static bool key_available;
-static struct efi_input_key next_key;
+static struct efi_key_data next_key;
/**
- * skip_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
+ * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
*
* This gets called when we have already parsed CSI.
*
* @modifiers: bitmask (shift, alt, ctrl)
* @return: the unmodified code
*/
-static char skip_modifiers(int *modifiers)
+static int analyze_modifiers(struct efi_key_state *key_state)
{
- char c, mod = 0, ret = 0;
+ int c, mod = 0, ret = 0;
c = getc();
@@ -429,8 +431,17 @@ static char skip_modifiers(int *modifiers)
out:
if (mod)
--mod;
- if (modifiers)
- *modifiers = mod;
+ key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
+ if (mod) {
+ if (mod & 1)
+ key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
+ if (mod & 2)
+ key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
+ if (mod & 4)
+ key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
+ if (mod & 8)
+ key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
+ }
if (!ret)
ret = c;
return ret;
@@ -442,7 +453,7 @@ out:
* @key: - key received
* Return: - status code
*/
-static efi_status_t efi_cin_read_key(struct efi_input_key *key)
+static efi_status_t efi_cin_read_key(struct efi_key_data *key)
{
efi_status_t ret;
struct efi_input_key pressed_key = {
@@ -454,6 +465,10 @@ static efi_status_t efi_cin_read_key(struct efi_input_key *key)
ret = console_read_unicode(&ch);
if (ret)
return EFI_NOT_READY;
+
+ key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
+ key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
+
/* We do not support multi-word codes */
if (ch >= 0x10000)
ch = '?';
@@ -490,7 +505,7 @@ static efi_status_t efi_cin_read_key(struct efi_input_key *key)
pressed_key.scan_code = 5;
break;
case '1':
- ch = skip_modifiers(NULL);
+ ch = analyze_modifiers(&key->key_state);
switch (ch) {
case '1'...'5': /* F1 - F5 */
pressed_key.scan_code = ch - '1' + 11;
@@ -510,7 +525,7 @@ static efi_status_t efi_cin_read_key(struct efi_input_key *key)
}
break;
case '2':
- ch = skip_modifiers(NULL);
+ ch = analyze_modifiers(&key->key_state);
switch (ch) {
case '0'...'1': /* F9 - F10 */
pressed_key.scan_code = ch - '0' + 19;
@@ -525,15 +540,15 @@ static efi_status_t efi_cin_read_key(struct efi_input_key *key)
break;
case '3': /* DEL */
pressed_key.scan_code = 8;
- skip_modifiers(NULL);
+ analyze_modifiers(&key->key_state);
break;
case '5': /* PG UP */
pressed_key.scan_code = 9;
- skip_modifiers(NULL);
+ analyze_modifiers(&key->key_state);
break;
case '6': /* PG DOWN */
pressed_key.scan_code = 10;
- skip_modifiers(NULL);
+ analyze_modifiers(&key->key_state);
break;
}
break;
@@ -542,9 +557,28 @@ static efi_status_t efi_cin_read_key(struct efi_input_key *key)
/* Backspace */
ch = 0x08;
}
- if (!pressed_key.scan_code)
+ if (pressed_key.scan_code) {
+ key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
+ } else {
pressed_key.unicode_char = ch;
- *key = pressed_key;
+
+ /*
+ * Assume left control key for control characters typically
+ * entered using the control key.
+ */
+ if (ch >= 0x01 && ch <= 0x1f) {
+ key->key_state.key_shift_state =
+ EFI_SHIFT_STATE_VALID;
+ switch (ch) {
+ case 0x01 ... 0x07:
+ case 0x0b ... 0x0c:
+ case 0x0e ... 0x1f:
+ key->key_state.key_shift_state |=
+ EFI_LEFT_CONTROL_PRESSED;
+ }
+ }
+ }
+ key->key = pressed_key;
return EFI_SUCCESS;
}
@@ -572,6 +606,170 @@ static void efi_cin_check(void)
}
}
+/**
+ * efi_cin_empty_buffer() - empty input buffer
+ */
+static void efi_cin_empty_buffer(void)
+{
+ while (tstc())
+ getc();
+ key_available = false;
+}
+
+/**
+ * efi_cin_reset_ex() - reset console input
+ *
+ * @this: - the extended simple text input protocol
+ * @extended_verification: - extended verification
+ *
+ * This function implements the reset service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: old value of the task priority level
+ */
+static efi_status_t EFIAPI efi_cin_reset_ex(
+ struct efi_simple_text_input_ex_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;
+ }
+
+ efi_cin_empty_buffer();
+out:
+ return EFI_EXIT(ret);
+}
+
+/**
+ * efi_cin_read_key_stroke_ex() - read key stroke
+ *
+ * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @key_data: key read from console
+ * Return: status code
+ *
+ * This function implements the ReadKeyStrokeEx service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
+ struct efi_simple_text_input_ex_protocol *this,
+ struct efi_key_data *key_data)
+{
+ efi_status_t ret = EFI_SUCCESS;
+
+ EFI_ENTRY("%p, %p", this, key_data);
+
+ /* Check parameters */
+ if (!this || !key_data) {
+ 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_data = next_key;
+ key_available = false;
+ efi_con_in.wait_for_key->is_signaled = false;
+out:
+ return EFI_EXIT(ret);
+}
+
+/**
+ * efi_cin_set_state() - set toggle key state
+ *
+ * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @key_toggle_state: key toggle state
+ * Return: status code
+ *
+ * This function implements the SetState service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_set_state(
+ struct efi_simple_text_input_ex_protocol *this,
+ u8 key_toggle_state)
+{
+ EFI_ENTRY("%p, %u", this, key_toggle_state);
+ /*
+ * U-Boot supports multiple console input sources like serial and
+ * net console for which a key toggle state cannot be set at all.
+ *
+ * According to the UEFI specification it is allowable to not implement
+ * this service.
+ */
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/**
+ * efi_cin_register_key_notify() - register key notification function
+ *
+ * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @key_data: key to be notified
+ * @key_notify_function: function to be called if the key is pressed
+ * @notify_handle: handle for unregistering the notification
+ * Return: status code
+ *
+ * This function implements the SetState service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_register_key_notify(
+ struct efi_simple_text_input_ex_protocol *this,
+ struct efi_key_data *key_data,
+ efi_status_t (EFIAPI *key_notify_function)(
+ struct efi_key_data *key_data),
+ void **notify_handle)
+{
+ EFI_ENTRY("%p, %p, %p, %p",
+ this, key_data, key_notify_function, notify_handle);
+ return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+}
+
+/**
+ * efi_cin_unregister_key_notify() - unregister key notification function
+ *
+ * @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @notification_handle: handle received when registering
+ * Return: status code
+ *
+ * This function implements the SetState service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_unregister_key_notify(
+ struct efi_simple_text_input_ex_protocol *this,
+ void *notification_handle)
+{
+ EFI_ENTRY("%p, %p", this, notification_handle);
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+}
+
+
/**
* efi_cin_reset() - drain the input buffer
*
@@ -599,16 +797,13 @@ static efi_status_t EFIAPI efi_cin_reset
goto out;
}
- /* Empty input buffer */
- while (tstc())
- getc();
- key_available = false;
+ efi_cin_empty_buffer();
out:
return EFI_EXIT(ret);
}
/**
- * efi_cin_reset() - drain the input buffer
+ * efi_cin_read_key_stroke() - read key stroke
*
* @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
* @key: key read from console
@@ -644,13 +839,22 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke
ret = EFI_NOT_READY;
goto out;
}
- *key = next_key;
+ *key = next_key.key;
key_available = false;
efi_con_in.wait_for_key->is_signaled = false;
out:
return EFI_EXIT(ret);
}
+static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
+ .reset = efi_cin_reset_ex,
+ .read_key_stroke_ex = efi_cin_read_key_stroke_ex,
+ .wait_for_key_ex = NULL,
+ .set_state = efi_cin_set_state,
+ .register_key_notify = efi_cin_register_key_notify,
+ .unregister_key_notify = efi_cin_unregister_key_notify,
+};
+
struct efi_simple_text_input_protocol efi_con_in = {
.reset = efi_cin_reset,
.read_key_stroke = efi_cin_read_key_stroke,
@@ -721,6 +925,10 @@ int efi_console_register(void)
if (r != EFI_SUCCESS)
goto out_of_memory;
systab.con_in_handle = efi_console_input_obj->handle;
+ r = efi_add_protocol(efi_console_input_obj->handle,
+ &efi_guid_text_input_ex_protocol, &efi_con_in_ex);
+ if (r != EFI_SUCCESS)
+ goto out_of_memory;
/* Create console events */
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
@@ -729,6 +937,7 @@ int efi_console_register(void)
printf("ERROR: Failed to register WaitForKey event\n");
return r;
}
+ efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
efi_console_timer_notify, NULL, NULL,
&console_timer_event);
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 08/13] efi_loader: support modifiers for F1 - F4
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (6 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 07/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 09/13] efi_selftest: test EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (4 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
Support modifiers for F1 - F4.
Add support for letters with ALT key.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3
new patch
---
lib/efi_loader/efi_console.c | 64 ++++++++++++++++++++++--------------
1 file changed, 39 insertions(+), 25 deletions(-)
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index d17f0a13f9..a6fd93d2c5 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -395,6 +395,29 @@ struct efi_simple_text_output_protocol efi_con_out = {
static bool key_available;
static struct efi_key_data next_key;
+/**
+ * set_shift_mask() - set shift mask
+ *
+ * @mod: Xterm shift mask
+ */
+void set_shift_mask(int mod, struct efi_key_state *key_state)
+{
+ key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
+ if (mod) {
+ --mod;
+ if (mod & 1)
+ key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
+ if (mod & 2)
+ key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
+ if (mod & 4)
+ key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
+ if (mod & 8)
+ key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
+ } else {
+ key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
+ }
+}
+
/**
* analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
*
@@ -429,19 +452,7 @@ static int analyze_modifiers(struct efi_key_state *key_state)
}
}
out:
- if (mod)
- --mod;
- key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
- if (mod) {
- if (mod & 1)
- key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
- if (mod & 2)
- key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
- if (mod & 4)
- key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
- if (mod & 8)
- key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
- }
+ set_shift_mask(mod, key_state);
if (!ret)
ret = c;
return ret;
@@ -455,15 +466,13 @@ out:
*/
static efi_status_t efi_cin_read_key(struct efi_key_data *key)
{
- efi_status_t ret;
struct efi_input_key pressed_key = {
.scan_code = 0,
.unicode_char = 0,
};
s32 ch;
- ret = console_read_unicode(&ch);
- if (ret)
+ if (console_read_unicode(&ch))
return EFI_NOT_READY;
key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
@@ -472,7 +481,9 @@ static efi_status_t efi_cin_read_key(struct efi_key_data *key)
/* We do not support multi-word codes */
if (ch >= 0x10000)
ch = '?';
- if (ch == cESC) {
+
+ switch (ch) {
+ case 0x1b:
/*
* Xterm Control Sequences
* https://www.xfree86.org/4.8.0/ctlseqs.html
@@ -484,14 +495,13 @@ static efi_status_t efi_cin_read_key(struct efi_key_data *key)
break;
case 'O': /* F1 - F4 */
ch = getc();
- /* skip modifiers */
- if (ch <= '9')
+ /* consider modifiers */
+ if (ch < 'P') {
+ set_shift_mask(ch - '0', &key->key_state);
ch = getc();
+ }
pressed_key.scan_code = ch - 'P' + 11;
break;
- case 'a'...'z':
- ch = ch - 'a';
- break;
case '[':
ch = getc();
switch (ch) {
@@ -550,10 +560,14 @@ static efi_status_t efi_cin_read_key(struct efi_key_data *key)
pressed_key.scan_code = 10;
analyze_modifiers(&key->key_state);
break;
- }
+ } /* [ */
break;
+ default:
+ /* ALT key */
+ set_shift_mask(3, &key->key_state);
}
- } else if (ch == 0x7f) {
+ break;
+ case 0x7f:
/* Backspace */
ch = 0x08;
}
@@ -567,7 +581,7 @@ static efi_status_t efi_cin_read_key(struct efi_key_data *key)
* entered using the control key.
*/
if (ch >= 0x01 && ch <= 0x1f) {
- key->key_state.key_shift_state =
+ key->key_state.key_shift_state |=
EFI_SHIFT_STATE_VALID;
switch (ch) {
case 0x01 ... 0x07:
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 09/13] efi_selftest: test EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (7 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 08/13] efi_loader: support modifiers for F1 - F4 Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 10/13] test/py: " Heinrich Schuchardt
` (3 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
Provide a unit test for the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3
no change
v2
no change
---
lib/efi_selftest/Makefile | 1 +
lib/efi_selftest/efi_selftest_textinputex.c | 139 ++++++++++++++++++++
2 files changed, 140 insertions(+)
create mode 100644 lib/efi_selftest/efi_selftest_textinputex.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 80bc5d8a64..2f55d9d66f 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -29,6 +29,7 @@ efi_selftest_manageprotocols.o \
efi_selftest_rtc.o \
efi_selftest_snp.o \
efi_selftest_textinput.o \
+efi_selftest_textinputex.o \
efi_selftest_textoutput.o \
efi_selftest_tpl.o \
efi_selftest_unicode_collation.o \
diff --git a/lib/efi_selftest/efi_selftest_textinputex.c b/lib/efi_selftest/efi_selftest_textinputex.c
new file mode 100644
index 0000000000..935bf065c4
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_textinputex.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_textinput
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ * The unicode character and the scan code are printed for text
+ * input. To run the test:
+ *
+ * setenv efi_selftest extended text input
+ * bootefi selftest
+ */
+
+#include <efi_selftest.h>
+
+static const efi_guid_t text_input_ex_protocol_guid =
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
+
+static struct efi_simple_text_input_ex_protocol *con_in_ex;
+
+static struct efi_boot_services *boottime;
+
+/*
+ * Setup unit test.
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ efi_status_t ret;
+
+ boottime = systable->boottime;
+
+ ret = boottime->locate_protocol(&text_input_ex_protocol_guid, NULL,
+ (void **)&con_in_ex);
+ if (ret != EFI_SUCCESS) {
+ con_in_ex = NULL;
+ efi_st_error
+ ("Extended text input protocol is not available.\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Execute unit test.
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ struct efi_key_data input_key = {0,};
+ efi_status_t ret;
+ efi_uintn_t index;
+
+ if (!con_in_ex) {
+ efi_st_printf("Setup failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Drain the console input */
+ ret = con_in_ex->reset(con_in_ex, true);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Reset failed\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = con_in_ex->read_key_stroke_ex(con_in_ex, &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 */
+ ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex,
+ &index);
+ if (ret != EFI_ST_SUCCESS) {
+ efi_st_error("WaitForEvent failed\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = con_in_ex->read_key_stroke_ex(con_in_ex, &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);
+
+ efi_st_printf("Unicode char %u (%ps), scan code %u (",
+ (unsigned int)input_key.key.unicode_char,
+ efi_st_translate_char(input_key.key.unicode_char),
+ (unsigned int)input_key.key.scan_code);
+ if (input_key.key_state.key_shift_state &
+ EFI_SHIFT_STATE_VALID) {
+ if (input_key.key_state.key_shift_state &
+ (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED))
+ efi_st_printf("SHIFT+");
+ if (input_key.key_state.key_shift_state &
+ (EFI_LEFT_ALT_PRESSED | EFI_RIGHT_ALT_PRESSED))
+ efi_st_printf("ALT+");
+ if (input_key.key_state.key_shift_state &
+ (EFI_LEFT_CONTROL_PRESSED |
+ EFI_RIGHT_CONTROL_PRESSED))
+ efi_st_printf("CTRL+");
+ if (input_key.key_state.key_shift_state &
+ (EFI_LEFT_LOGO_PRESSED | EFI_RIGHT_LOGO_PRESSED))
+ efi_st_printf("META+");
+ if (input_key.key_state.key_shift_state ==
+ EFI_SHIFT_STATE_VALID)
+ efi_st_printf("+");
+ }
+
+ efi_st_printf("%ps)\n",
+ efi_st_translate_code(input_key.key.scan_code));
+
+ switch (input_key.key.unicode_char) {
+ case 'x':
+ case 'X':
+ return EFI_ST_SUCCESS;
+ }
+ }
+}
+
+EFI_UNIT_TEST(textinputex) = {
+ .name = "extended text input",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+ .on_request = true,
+};
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 10/13] test/py: test EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (8 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 09/13] efi_selftest: test EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 11/13] efi_loader: implement key notify functions Heinrich Schuchardt
` (2 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
Add a unit test for the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3
no change
v2
no change
---
test/py/tests/test_efi_selftest.py | 79 ++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index 3e70abdafc..f84aa4d706 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -118,3 +118,82 @@ def test_efi_selftest_text_input(u_boot_console):
if m != 0:
raise Exception('Failures occurred during the EFI selftest')
u_boot_console.restart_uboot();
+
+ at pytest.mark.buildconfigspec('cmd_bootefi_selftest')
+def test_efi_selftest_text_input_ex(u_boot_console):
+ """Test the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
+
+ :param u_boot_console: U-Boot console
+
+ This function calls the extended text input EFI selftest.
+ """
+ u_boot_console.run_command(cmd='setenv efi_selftest extended text input')
+ output = u_boot_console.run_command(cmd='bootefi selftest',
+ wait_for_prompt=False)
+ m = u_boot_console.p.expect(['To terminate type \'x\''])
+ if m != 0:
+ raise Exception('No prompt for \'text input\' test')
+ u_boot_console.drain_console()
+ u_boot_console.p.timeout = 500
+ # EOT
+ u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
+ send_nl=False, wait_for_prompt=False)
+ m = u_boot_console.p.expect(
+ ['Unicode char 4 \(unknown\), scan code 0 \(CTRL\+Null\)'])
+ if m != 0:
+ raise Exception('EOT failed in \'text input\' test')
+ u_boot_console.drain_console()
+ # BS
+ u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
+ send_nl=False, wait_for_prompt=False)
+ m = u_boot_console.p.expect(
+ ['Unicode char 8 \(BS\), scan code 0 \(\+Null\)'])
+ if m != 0:
+ raise Exception('BS failed in \'text input\' test')
+ u_boot_console.drain_console()
+ # TAB
+ u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
+ send_nl=False, wait_for_prompt=False)
+ m = u_boot_console.p.expect(
+ ['Unicode char 9 \(TAB\), scan code 0 \(\+Null\)'])
+ if m != 0:
+ raise Exception('TAB failed in \'text input\' test')
+ u_boot_console.drain_console()
+ # a
+ u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
+ wait_for_prompt=False)
+ m = u_boot_console.p.expect(
+ ['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
+ if m != 0:
+ raise Exception('\'a\' failed in \'text input\' test')
+ u_boot_console.drain_console()
+ # UP escape sequence
+ u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
+ send_nl=False, wait_for_prompt=False)
+ m = u_boot_console.p.expect(
+ ['Unicode char 0 \(Null\), scan code 1 \(\+Up\)'])
+ 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()
+ # SHIFT+ALT+FN 5
+ u_boot_console.run_command(cmd='\x1b\x5b\x31\x35\x3b\x34\x7e',
+ wait_for_echo=False, send_nl=False,
+ wait_for_prompt=False)
+ m = u_boot_console.p.expect(
+ ['Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)'])
+ if m != 0:
+ raise Exception('SHIFT+ALT+FN 5 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'])
+ if m != 0:
+ raise Exception('Failures occurred during the EFI selftest')
+ u_boot_console.restart_uboot();
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 11/13] efi_loader: implement key notify functions
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (9 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 10/13] test/py: " Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 12/13] efi_selftest: test key notification functions Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 13/13] efi_loader: unset CONFIG_EFI_UNICODE_CAPITALIZATION Heinrich Schuchardt
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
Implement registering and unregistreing key notify functions in the
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3
no change
v2
rebae patch
---
lib/efi_loader/efi_console.c | 101 +++++++++++++++++++++++++++++++++--
1 file changed, 98 insertions(+), 3 deletions(-)
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index a6fd93d2c5..73f7ecf919 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -392,8 +392,23 @@ struct efi_simple_text_output_protocol efi_con_out = {
.mode = (void*)&efi_con_mode,
};
+/**
+ * struct efi_cin_notify_function - registered console input notify function
+ *
+ * @link: link to list
+ * @data: key to notify
+ * @function: function to call
+ */
+struct efi_cin_notify_function {
+ struct list_head link;
+ struct efi_key_data key;
+ efi_status_t (EFIAPI *function)
+ (struct efi_key_data *key_data);
+};
+
static bool key_available;
static struct efi_key_data next_key;
+static LIST_HEAD(cin_notify_functions);
/**
* set_shift_mask() - set shift mask
@@ -597,6 +612,34 @@ static efi_status_t efi_cin_read_key(struct efi_key_data *key)
return EFI_SUCCESS;
}
+/**
+ * efi_cin_notify() - notify registered functions
+ */
+static void efi_cin_notify(void)
+{
+ struct efi_cin_notify_function *item;
+
+ list_for_each_entry(item, &cin_notify_functions, link) {
+ bool match = true;
+
+ /* We do not support toggle states */
+ if (item->key.key.unicode_char || item->key.key.scan_code) {
+ if (item->key.key.unicode_char !=
+ next_key.key.unicode_char ||
+ item->key.key.scan_code != next_key.key.scan_code)
+ match = false;
+ }
+ if (item->key.key_state.key_shift_state &&
+ item->key.key_state.key_shift_state !=
+ next_key.key_state.key_shift_state)
+ match = false;
+
+ if (match)
+ /* We don't bother about the return code */
+ EFI_CALL(item->function(&next_key));
+ }
+}
+
/**
* efi_cin_check() - check if keyboard input is available
*/
@@ -614,8 +657,12 @@ static void efi_cin_check(void)
if (ret == EFI_SUCCESS) {
key_available = true;
+ /* Notify registered functions */
+ efi_cin_notify();
+
/* Queue the wait for key event */
- efi_signal_event(efi_con_in.wait_for_key, true);
+ if (key_available)
+ efi_signal_event(efi_con_in.wait_for_key, true);
}
}
}
@@ -757,9 +804,35 @@ static efi_status_t EFIAPI efi_cin_register_key_notify(
struct efi_key_data *key_data),
void **notify_handle)
{
+ efi_status_t ret = EFI_SUCCESS;
+ struct efi_cin_notify_function *notify_function;
+
EFI_ENTRY("%p, %p, %p, %p",
this, key_data, key_notify_function, notify_handle);
- return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+
+ /* Check parameters */
+ if (!this || !key_data || !key_notify_function || !notify_handle) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
+ key_data->key.unicode_char,
+ key_data->key.scan_code,
+ key_data->key_state.key_shift_state,
+ key_data->key_state.key_toggle_state);
+
+ notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
+ if (!notify_function) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ notify_function->key = *key_data;
+ notify_function->function = key_notify_function;
+ list_add_tail(¬ify_function->link, &cin_notify_functions);
+ *notify_handle = notify_function;
+out:
+ return EFI_EXIT(ret);
}
/**
@@ -779,8 +852,30 @@ static efi_status_t EFIAPI efi_cin_unregister_key_notify(
struct efi_simple_text_input_ex_protocol *this,
void *notification_handle)
{
+ efi_status_t ret = EFI_INVALID_PARAMETER;
+ struct efi_cin_notify_function *item, *notify_function =
+ notification_handle;
+
EFI_ENTRY("%p, %p", this, notification_handle);
- return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ /* Check parameters */
+ if (!this || !notification_handle)
+ goto out;
+
+ list_for_each_entry(item, &cin_notify_functions, link) {
+ if (item == notify_function) {
+ ret = EFI_SUCCESS;
+ break;
+ }
+ }
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ /* Remove the notify function */
+ list_del(¬ify_function->link);
+ free(notify_function);
+out:
+ return EFI_EXIT(ret);
}
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 12/13] efi_selftest: test key notification functions
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (10 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 11/13] efi_loader: implement key notify functions Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 13/13] efi_loader: unset CONFIG_EFI_UNICODE_CAPITALIZATION Heinrich Schuchardt
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
Use a key notification function to leave the
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL test.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3
no change
v2
no change
---
lib/efi_selftest/efi_selftest_textinputex.c | 73 +++++++++++++++++++--
test/py/tests/test_efi_selftest.py | 4 +-
2 files changed, 68 insertions(+), 9 deletions(-)
diff --git a/lib/efi_selftest/efi_selftest_textinputex.c b/lib/efi_selftest/efi_selftest_textinputex.c
index 935bf065c4..d20d8ad89d 100644
--- a/lib/efi_selftest/efi_selftest_textinputex.c
+++ b/lib/efi_selftest/efi_selftest_textinputex.c
@@ -21,6 +21,25 @@ static struct efi_simple_text_input_ex_protocol *con_in_ex;
static struct efi_boot_services *boottime;
+static void *efi_key_notify_handle;
+static bool efi_running;
+
+/**
+ * efi_key_notify_function() - key notification function
+ *
+ * This function is called when the registered key is hit.
+ *
+ * @key_data: next key
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_key_notify_function
+ (struct efi_key_data *key_data)
+{
+ efi_running = false;
+
+ return EFI_SUCCESS;
+}
+
/*
* Setup unit test.
*
@@ -32,6 +51,17 @@ static int setup(const efi_handle_t handle,
const struct efi_system_table *systable)
{
efi_status_t ret;
+ struct efi_key_data key_data = {
+ .key = {
+ .scan_code = 0,
+ .unicode_char = 0x18
+ },
+ .key_state = {
+ .key_shift_state = EFI_SHIFT_STATE_VALID |
+ EFI_LEFT_CONTROL_PRESSED,
+ .key_toggle_state = EFI_TOGGLE_STATE_INVALID,
+ },
+ };
boottime = systable->boottime;
@@ -44,9 +74,41 @@ static int setup(const efi_handle_t handle,
return EFI_ST_FAILURE;
}
+ ret = con_in_ex->register_key_notify(con_in_ex, &key_data,
+ efi_key_notify_function,
+ &efi_key_notify_handle);
+ if (ret != EFI_SUCCESS) {
+ efi_key_notify_handle = NULL;
+ efi_st_error
+ ("Notify function could not be registered.\n");
+ return EFI_ST_FAILURE;
+ }
+ efi_running = true;
+
return EFI_ST_SUCCESS;
}
+/*
+ * Tear down unit test.
+ *
+ * Unregister notify function.
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int teardown(void)
+{
+ efi_status_t ret;
+
+ ret = con_in_ex->unregister_key_notify
+ (con_in_ex, efi_key_notify_handle);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error
+ ("Notify function could not be registered.\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
/*
* Execute unit test.
*
@@ -76,9 +138,9 @@ static int execute(void)
}
efi_st_printf("Waiting for your input\n");
- efi_st_printf("To terminate type 'x'\n");
+ efi_st_printf("To terminate type 'CTRL+x'\n");
- for (;;) {
+ while (efi_running) {
/* Wait for next key */
ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex,
&index);
@@ -122,12 +184,8 @@ static int execute(void)
efi_st_printf("%ps)\n",
efi_st_translate_code(input_key.key.scan_code));
- switch (input_key.key.unicode_char) {
- case 'x':
- case 'X':
- return EFI_ST_SUCCESS;
- }
}
+ return EFI_ST_SUCCESS;
}
EFI_UNIT_TEST(textinputex) = {
@@ -135,5 +193,6 @@ EFI_UNIT_TEST(textinputex) = {
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute,
+ .teardown = teardown,
.on_request = true,
};
diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index f84aa4d706..e0833ffe22 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -130,7 +130,7 @@ def test_efi_selftest_text_input_ex(u_boot_console):
u_boot_console.run_command(cmd='setenv efi_selftest extended text input')
output = u_boot_console.run_command(cmd='bootefi selftest',
wait_for_prompt=False)
- m = u_boot_console.p.expect(['To terminate type \'x\''])
+ m = u_boot_console.p.expect(['To terminate type \'CTRL\+x\''])
if m != 0:
raise Exception('No prompt for \'text input\' test')
u_boot_console.drain_console()
@@ -191,7 +191,7 @@ def test_efi_selftest_text_input_ex(u_boot_console):
if m != 0:
raise Exception('SHIFT+ALT+FN 5 failed in \'text input\' test')
u_boot_console.drain_console()
- u_boot_console.run_command(cmd='x', wait_for_echo=False, send_nl=False,
+ u_boot_console.run_command(cmd=chr(24), wait_for_echo=False, send_nl=False,
wait_for_prompt=False)
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
if m != 0:
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 13/13] efi_loader: unset CONFIG_EFI_UNICODE_CAPITALIZATION
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
` (11 preceding siblings ...)
2018-09-11 20:38 ` [U-Boot] [PATCH v3 12/13] efi_selftest: test key notification functions Heinrich Schuchardt
@ 2018-09-11 20:38 ` Heinrich Schuchardt
12 siblings, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 20:38 UTC (permalink / raw)
To: u-boot
Unset CONFIG_EFI_UNICODE_CAPITALIZATION on boards with tough size
restrictions.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3
no change
v2
no change
---
configs/vf610twr_defconfig | 1 +
configs/vf610twr_nand_defconfig | 1 +
2 files changed, 2 insertions(+)
diff --git a/configs/vf610twr_defconfig b/configs/vf610twr_defconfig
index 59066a36a9..3f38c8813b 100644
--- a/configs/vf610twr_defconfig
+++ b/configs/vf610twr_defconfig
@@ -39,3 +39,4 @@ CONFIG_PHY_MICREL=y
CONFIG_MII=y
CONFIG_DM_SERIAL=y
CONFIG_FSL_LPUART=y
+# CONFIG_EFI_UNICODE_CAPITALIZATION is not set
diff --git a/configs/vf610twr_nand_defconfig b/configs/vf610twr_nand_defconfig
index 5b269fdaf6..d6e318f58c 100644
--- a/configs/vf610twr_nand_defconfig
+++ b/configs/vf610twr_nand_defconfig
@@ -39,3 +39,4 @@ CONFIG_PHY_MICREL=y
CONFIG_MII=y
CONFIG_DM_SERIAL=y
CONFIG_FSL_LPUART=y
+# CONFIG_EFI_UNICODE_CAPITALIZATION is not set
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v3 01/13] efi_loader: support Unicode text input
2018-09-11 20:38 ` [U-Boot] [PATCH v3 01/13] efi_loader: support Unicode text input Heinrich Schuchardt
@ 2018-09-11 21:37 ` Alexander Graf
2018-09-11 21:51 ` [U-Boot] [PATCH v4 " Heinrich Schuchardt
2018-09-11 22:05 ` [U-Boot] [PATCH v5 1/13] " Heinrich Schuchardt
0 siblings, 2 replies; 17+ messages in thread
From: Alexander Graf @ 2018-09-11 21:37 UTC (permalink / raw)
To: u-boot
On 11.09.18 22:38, 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 console.
>
> Currently only the serial console and the console can deliver UTF-8.
> Local consoles are restricted to ASCII.
>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> ---
> v2:
> drop support for German keyboard
> move reading of Unicode code to charset.c
> ---
> include/charset.h | 9 +++
> lib/charset.c | 136 ++++++++++++++++++++++-------------
> lib/efi_loader/efi_console.c | 13 ++--
> test/unicode_ut.c | 8 +--
> 4 files changed, 108 insertions(+), 58 deletions(-)
>
> diff --git a/include/charset.h b/include/charset.h
> index 686db5a1fe..a7de5f6948 100644
> --- a/include/charset.h
> +++ b/include/charset.h
> @@ -8,11 +8,20 @@
> #ifndef __CHARSET_H_
> #define __CHARSET_H_
>
> +#include <efi.h>
Yeah ... eh ... no :).
I assume this is just a leftover from the old version?
> #include <linux/kernel.h>
> #include <linux/types.h>
>
> #define MAX_UTF8_PER_UTF16 3
>
> +/**
> + * console_read_unicode() - read Unicode code point from console
> + *
> + * @code: code point
Please specify this a bit clearer.
> + * Return: 0 = success
> + */
> +int console_read_unicode(s32 *code);
> +
> /**
> * utf8_get() - get next UTF-8 code point from buffer
> *
> diff --git a/lib/charset.c b/lib/charset.c
> index 72c808ce64..1806b41cc3 100644
> --- a/lib/charset.c
> +++ b/lib/charset.c
> @@ -5,6 +5,7 @@
> * Copyright (c) 2017 Rob Clark
> */
>
> +#include <common.h>
> #include <charset.h>
> #include <capitalization.h>
> #include <malloc.h>
> @@ -18,67 +19,106 @@ static struct capitalization_table capitalization_table[] =
> CP437_CAPITALIZATION_TABLE;
> #endif
>
> -s32 utf8_get(const char **src)
> +/**
> + * get_code() - read Unicode code point from UTF-8 stream
> + *
> + * @read_u8: - stream reader
> + * @src: - string buffer passed to stream reader, optional
> + * Return: - Unicode code point
> + */
> +static int get_code(u8 (*read_u8)(void *data), void *data)
> {
> - s32 code = 0;
> - unsigned char c;
> + s32 ch = 0;
>
> - if (!src || !*src)
> - return -1;
> - if (!**src)
> + ch = read_u8(data);
> + if (!ch)
> return 0;
> - c = **src;
> - if (c >= 0x80) {
> - ++*src;
> - if (!**src)
> - return -1;
> - /*
> - * We do not expect a continuation byte (0x80 - 0xbf).
> - * 0x80 is coded as 0xc2 0x80, so we cannot have less then 0xc2
> - * here.
> - * The highest code point is 0x10ffff which is coded as
> - * 0xf4 0x8f 0xbf 0xbf. So we cannot have a byte above 0xf4.
> - */
> - if (c < 0xc2 || code > 0xf4)
> - return -1;
> - if (c >= 0xe0) {
> - if (c >= 0xf0) {
> + if (ch >= 0xc2 && ch <= 0xf4) {
> + int code = 0;
> +
> + if (ch >= 0xe0) {
> + if (ch >= 0xf0) {
> /* 0xf0 - 0xf4 */
> - c &= 0x07;
> - code = c << 18;
> - c = **src;
> - ++*src;
> - if (!**src)
> - return -1;
> - if (c < 0x80 || c > 0xbf)
> - return -1;
> - c &= 0x3f;
> + ch &= 0x07;
> + code = ch << 18;
> + ch = read_u8(data);
> + if (ch < 0x80 || ch > 0xbf)
> + goto error;
> + ch &= 0x3f;
> } else {
> /* 0xe0 - 0xef */
> - c &= 0x0f;
> + ch &= 0x0f;
> }
> - code += c << 12;
> + code += ch << 12;
> if ((code >= 0xD800 && code <= 0xDFFF) ||
> code >= 0x110000)
> - return -1;
> - c = **src;
> - ++*src;
> - if (!**src)
> - return -1;
> - if (c < 0x80 || c > 0xbf)
> - return -1;
> + goto error;
> + ch = read_u8(data);
> + if (ch < 0x80 || ch > 0xbf)
> + goto error;
> }
> /* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
> - c &= 0x3f;
> - code += c << 6;
> - c = **src;
> - if (c < 0x80 || c > 0xbf)
> - return -1;
> - c &= 0x3f;
> + ch &= 0x3f;
> + code += ch << 6;
> + ch = read_u8(data);
> + if (ch < 0x80 || ch > 0xbf)
> + goto error;
> + ch &= 0x3f;
> + ch += code;
> + } else if (ch >= 0x80) {
> + goto error;
> }
> - code += c;
> + return ch;
> +error:
> + return '?';
> +}
> +
> +/**
> + * read_string() - read byte from character string
> + *
> + * @data: - pointer to string
> + * Return: - byte read
> + *
> + * The string pointer is incremented if it does not point to '\0'.
> + */
> +static u8 read_string(void *data)
> +
> +{
> + const char **src = (const char **)data;
> + u8 c;
> +
> + if (!src || !*src || !**src)
> + return 0;
> + c = (unsigned char)**src;
Please remove the cast. Btw, you could also write this as
return *(*src++);
> ++*src;
> - return code;
> + return c;
> +}
> +
> +/**
> + * read_console() - read byte from console
> + *
> + * @src - not used, needed to match interface
> + * Return: - byte read
> + */
> +static u8 read_console(void *data)
> +{
> + return getc();
> +}
> +
> +int console_read_unicode(s32 *code)
> +{
> + if (!tstc())
> + /* No input available */
> + return 1;
Please avoid multi-line indented code without braces.
> +
> + /* Read Unicode code */
> + *code = get_code(read_console, NULL);
> + return 0;
> +}
> +
> +s32 utf8_get(const char **src)
> +{
> + return get_code(read_string, src);
> }
>
Alex
^ permalink raw reply [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v4 01/13] efi_loader: support Unicode text input
2018-09-11 21:37 ` Alexander Graf
@ 2018-09-11 21:51 ` Heinrich Schuchardt
2018-09-11 22:05 ` [U-Boot] [PATCH v5 1/13] " Heinrich Schuchardt
1 sibling, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 21:51 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 console.
Currently only the serial console and the console can deliver UTF-8.
Local consoles are restricted to ASCII.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3,v4
remove EFI dependencies in charset.c
use consistent naming of variables and functions
v2:
drop support for German keyboard
move reading of Unicode code to charset.c
---
include/charset.h | 9 +++
lib/charset.c | 136 ++++++++++++++++++++++-------------
lib/efi_loader/efi_console.c | 13 ++--
test/unicode_ut.c | 8 +--
4 files changed, 108 insertions(+), 58 deletions(-)
diff --git a/include/charset.h b/include/charset.h
index 686db5a1fe..a7de5f6948 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -8,11 +8,20 @@
#ifndef __CHARSET_H_
#define __CHARSET_H_
+#include <efi.h>
#include <linux/kernel.h>
#include <linux/types.h>
#define MAX_UTF8_PER_UTF16 3
+/**
+ * console_read_unicode() - read Unicode code point from console
+ *
+ * @code: code point
+ * Return: 0 = success
+ */
+int console_read_unicode(s32 *code);
+
/**
* utf8_get() - get next UTF-8 code point from buffer
*
diff --git a/lib/charset.c b/lib/charset.c
index 72c808ce64..1806b41cc3 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -5,6 +5,7 @@
* Copyright (c) 2017 Rob Clark
*/
+#include <common.h>
#include <charset.h>
#include <capitalization.h>
#include <malloc.h>
@@ -18,67 +19,106 @@ static struct capitalization_table capitalization_table[] =
CP437_CAPITALIZATION_TABLE;
#endif
-s32 utf8_get(const char **src)
+/**
+ * get_code() - read Unicode code point from UTF-8 stream
+ *
+ * @read_u8: - stream reader
+ * @src: - string buffer passed to stream reader, optional
+ * Return: - Unicode code point
+ */
+static int get_code(u8 (*read_u8)(void *data), void *data)
{
- s32 code = 0;
- unsigned char c;
+ s32 ch = 0;
- if (!src || !*src)
- return -1;
- if (!**src)
+ ch = read_u8(data);
+ if (!ch)
return 0;
- c = **src;
- if (c >= 0x80) {
- ++*src;
- if (!**src)
- return -1;
- /*
- * We do not expect a continuation byte (0x80 - 0xbf).
- * 0x80 is coded as 0xc2 0x80, so we cannot have less then 0xc2
- * here.
- * The highest code point is 0x10ffff which is coded as
- * 0xf4 0x8f 0xbf 0xbf. So we cannot have a byte above 0xf4.
- */
- if (c < 0xc2 || code > 0xf4)
- return -1;
- if (c >= 0xe0) {
- if (c >= 0xf0) {
+ if (ch >= 0xc2 && ch <= 0xf4) {
+ int code = 0;
+
+ if (ch >= 0xe0) {
+ if (ch >= 0xf0) {
/* 0xf0 - 0xf4 */
- c &= 0x07;
- code = c << 18;
- c = **src;
- ++*src;
- if (!**src)
- return -1;
- if (c < 0x80 || c > 0xbf)
- return -1;
- c &= 0x3f;
+ ch &= 0x07;
+ code = ch << 18;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
+ ch &= 0x3f;
} else {
/* 0xe0 - 0xef */
- c &= 0x0f;
+ ch &= 0x0f;
}
- code += c << 12;
+ code += ch << 12;
if ((code >= 0xD800 && code <= 0xDFFF) ||
code >= 0x110000)
- return -1;
- c = **src;
- ++*src;
- if (!**src)
- return -1;
- if (c < 0x80 || c > 0xbf)
- return -1;
+ goto error;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
}
/* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
- c &= 0x3f;
- code += c << 6;
- c = **src;
- if (c < 0x80 || c > 0xbf)
- return -1;
- c &= 0x3f;
+ ch &= 0x3f;
+ code += ch << 6;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
+ ch &= 0x3f;
+ ch += code;
+ } else if (ch >= 0x80) {
+ goto error;
}
- code += c;
+ return ch;
+error:
+ return '?';
+}
+
+/**
+ * read_string() - read byte from character string
+ *
+ * @data: - pointer to string
+ * Return: - byte read
+ *
+ * The string pointer is incremented if it does not point to '\0'.
+ */
+static u8 read_string(void *data)
+
+{
+ const char **src = (const char **)data;
+ u8 c;
+
+ if (!src || !*src || !**src)
+ return 0;
+ c = (unsigned char)**src;
++*src;
- return code;
+ return c;
+}
+
+/**
+ * read_console() - read byte from console
+ *
+ * @src - not used, needed to match interface
+ * Return: - byte read
+ */
+static u8 read_console(void *data)
+{
+ return getc();
+}
+
+int console_read_unicode(s32 *code)
+{
+ if (!tstc())
+ /* No input available */
+ return 1;
+
+ /* Read Unicode code */
+ *code = get_code(read_console, NULL);
+ return 0;
+}
+
+s32 utf8_get(const char **src)
+{
+ return get_code(read_string, src);
}
int utf8_put(s32 code, char **dst)
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 3ca6fe536c..6af083984c 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -449,23 +449,24 @@ 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;
struct efi_input_key pressed_key = {
.scan_code = 0,
.unicode_char = 0,
};
- char ch;
+ s32 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 */
+ ret = console_read_unicode(&ch);
+ if (ret)
return EFI_EXIT(EFI_NOT_READY);
- }
-
- ch = getc();
+ /* We do not support multi-word codes */
+ if (ch >= 0x10000)
+ ch = '?';
if (ch == cESC) {
/*
* Xterm Control Sequences
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
index b94b4a651f..b115d18afd 100644
--- a/test/unicode_ut.c
+++ b/test/unicode_ut.c
@@ -178,7 +178,7 @@ static int ut_utf8_utf16_strlen(struct unit_test_state *uts)
/* illegal utf-8 sequences */
ut_asserteq(4, utf8_utf16_strlen(j1));
- ut_asserteq(5, utf8_utf16_strlen(j2));
+ ut_asserteq(4, utf8_utf16_strlen(j2));
ut_asserteq(3, utf8_utf16_strlen(j3));
return 0;
@@ -196,7 +196,7 @@ static int ut_utf8_utf16_strnlen(struct unit_test_state *uts)
/* illegal utf-8 sequences */
ut_asserteq(4, utf8_utf16_strnlen(j1, 16));
- ut_asserteq(5, utf8_utf16_strnlen(j2, 16));
+ ut_asserteq(4, utf8_utf16_strnlen(j2, 16));
ut_asserteq(3, utf8_utf16_strnlen(j3, 16));
return 0;
@@ -255,8 +255,8 @@ static int ut_utf8_utf16_strcpy(struct unit_test_state *uts)
pos = buf;
utf8_utf16_strcpy(&pos, j2);
- ut_asserteq(5, pos - buf);
- ut_assert(!ut_u16_strcmp(buf, L"j2??l", SIZE_MAX));
+ ut_asserteq(4, pos - buf);
+ ut_assert(!ut_u16_strcmp(buf, L"j2?l", SIZE_MAX));
pos = buf;
utf8_utf16_strcpy(&pos, j3);
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [U-Boot] [PATCH v5 1/13] efi_loader: support Unicode text input
2018-09-11 21:37 ` Alexander Graf
2018-09-11 21:51 ` [U-Boot] [PATCH v4 " Heinrich Schuchardt
@ 2018-09-11 22:05 ` Heinrich Schuchardt
1 sibling, 0 replies; 17+ messages in thread
From: Heinrich Schuchardt @ 2018-09-11 22:05 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 console.
Currently only the serial console and the console can deliver UTF-8.
Local consoles are restricted to ASCII.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
v3-5:
remove dependency on EFI subsystem in charset.c
consistent naming of variable and pointers
v2:
drop support for German keyboard
move reading of Unicode code to charset.c
---
include/charset.h | 8 ++
lib/charset.c | 137 +++++++++++++++++++++++------------
lib/efi_loader/efi_console.c | 13 ++--
test/unicode_ut.c | 8 +-
4 files changed, 108 insertions(+), 58 deletions(-)
diff --git a/include/charset.h b/include/charset.h
index 686db5a1fe..4d45e246e5 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -13,6 +13,14 @@
#define MAX_UTF8_PER_UTF16 3
+/**
+ * console_read_unicode() - read Unicode code point from console
+ *
+ * @code: pointer to store Unicode code point
+ * Return: 0 = success
+ */
+int console_read_unicode(s32 *code);
+
/**
* utf8_get() - get next UTF-8 code point from buffer
*
diff --git a/lib/charset.c b/lib/charset.c
index 72c808ce64..0cede9b60b 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -5,6 +5,7 @@
* Copyright (c) 2017 Rob Clark
*/
+#include <common.h>
#include <charset.h>
#include <capitalization.h>
#include <malloc.h>
@@ -18,67 +19,107 @@ static struct capitalization_table capitalization_table[] =
CP437_CAPITALIZATION_TABLE;
#endif
-s32 utf8_get(const char **src)
+/**
+ * get_code() - read Unicode code point from UTF-8 stream
+ *
+ * @read_u8: - stream reader
+ * @src: - string buffer passed to stream reader, optional
+ * Return: - Unicode code point
+ */
+static int get_code(u8 (*read_u8)(void *data), void *data)
{
- s32 code = 0;
- unsigned char c;
+ s32 ch = 0;
- if (!src || !*src)
- return -1;
- if (!**src)
+ ch = read_u8(data);
+ if (!ch)
return 0;
- c = **src;
- if (c >= 0x80) {
- ++*src;
- if (!**src)
- return -1;
- /*
- * We do not expect a continuation byte (0x80 - 0xbf).
- * 0x80 is coded as 0xc2 0x80, so we cannot have less then 0xc2
- * here.
- * The highest code point is 0x10ffff which is coded as
- * 0xf4 0x8f 0xbf 0xbf. So we cannot have a byte above 0xf4.
- */
- if (c < 0xc2 || code > 0xf4)
- return -1;
- if (c >= 0xe0) {
- if (c >= 0xf0) {
+ if (ch >= 0xc2 && ch <= 0xf4) {
+ int code = 0;
+
+ if (ch >= 0xe0) {
+ if (ch >= 0xf0) {
/* 0xf0 - 0xf4 */
- c &= 0x07;
- code = c << 18;
- c = **src;
- ++*src;
- if (!**src)
- return -1;
- if (c < 0x80 || c > 0xbf)
- return -1;
- c &= 0x3f;
+ ch &= 0x07;
+ code = ch << 18;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
+ ch &= 0x3f;
} else {
/* 0xe0 - 0xef */
- c &= 0x0f;
+ ch &= 0x0f;
}
- code += c << 12;
+ code += ch << 12;
if ((code >= 0xD800 && code <= 0xDFFF) ||
code >= 0x110000)
- return -1;
- c = **src;
- ++*src;
- if (!**src)
- return -1;
- if (c < 0x80 || c > 0xbf)
- return -1;
+ goto error;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
}
/* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
- c &= 0x3f;
- code += c << 6;
- c = **src;
- if (c < 0x80 || c > 0xbf)
- return -1;
- c &= 0x3f;
+ ch &= 0x3f;
+ code += ch << 6;
+ ch = read_u8(data);
+ if (ch < 0x80 || ch > 0xbf)
+ goto error;
+ ch &= 0x3f;
+ ch += code;
+ } else if (ch >= 0x80) {
+ goto error;
}
- code += c;
+ return ch;
+error:
+ return '?';
+}
+
+/**
+ * read_string() - read byte from character string
+ *
+ * @data: - pointer to string
+ * Return: - byte read
+ *
+ * The string pointer is incremented if it does not point to '\0'.
+ */
+static u8 read_string(void *data)
+
+{
+ const char **src = (const char **)data;
+ u8 c;
+
+ if (!src || !*src || !**src)
+ return 0;
+ c = **src;
++*src;
- return code;
+ return c;
+}
+
+/**
+ * read_console() - read byte from console
+ *
+ * @src - not used, needed to match interface
+ * Return: - byte read
+ */
+static u8 read_console(void *data)
+{
+ return getc();
+}
+
+int console_read_unicode(s32 *code)
+{
+ if (!tstc()) {
+ /* No input available */
+ return 1;
+ }
+
+ /* Read Unicode code */
+ *code = get_code(read_console, NULL);
+ return 0;
+}
+
+s32 utf8_get(const char **src)
+{
+ return get_code(read_string, src);
}
int utf8_put(s32 code, char **dst)
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 3ca6fe536c..6af083984c 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -449,23 +449,24 @@ 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;
struct efi_input_key pressed_key = {
.scan_code = 0,
.unicode_char = 0,
};
- char ch;
+ s32 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 */
+ ret = console_read_unicode(&ch);
+ if (ret)
return EFI_EXIT(EFI_NOT_READY);
- }
-
- ch = getc();
+ /* We do not support multi-word codes */
+ if (ch >= 0x10000)
+ ch = '?';
if (ch == cESC) {
/*
* Xterm Control Sequences
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
index b94b4a651f..b115d18afd 100644
--- a/test/unicode_ut.c
+++ b/test/unicode_ut.c
@@ -178,7 +178,7 @@ static int ut_utf8_utf16_strlen(struct unit_test_state *uts)
/* illegal utf-8 sequences */
ut_asserteq(4, utf8_utf16_strlen(j1));
- ut_asserteq(5, utf8_utf16_strlen(j2));
+ ut_asserteq(4, utf8_utf16_strlen(j2));
ut_asserteq(3, utf8_utf16_strlen(j3));
return 0;
@@ -196,7 +196,7 @@ static int ut_utf8_utf16_strnlen(struct unit_test_state *uts)
/* illegal utf-8 sequences */
ut_asserteq(4, utf8_utf16_strnlen(j1, 16));
- ut_asserteq(5, utf8_utf16_strnlen(j2, 16));
+ ut_asserteq(4, utf8_utf16_strnlen(j2, 16));
ut_asserteq(3, utf8_utf16_strnlen(j3, 16));
return 0;
@@ -255,8 +255,8 @@ static int ut_utf8_utf16_strcpy(struct unit_test_state *uts)
pos = buf;
utf8_utf16_strcpy(&pos, j2);
- ut_asserteq(5, pos - buf);
- ut_assert(!ut_u16_strcmp(buf, L"j2??l", SIZE_MAX));
+ ut_asserteq(4, pos - buf);
+ ut_assert(!ut_u16_strcmp(buf, L"j2?l", SIZE_MAX));
pos = buf;
utf8_utf16_strcpy(&pos, j3);
--
2.18.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
end of thread, other threads:[~2018-09-11 22:05 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-11 20:38 [U-Boot] [PATCH v3 0/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 01/13] efi_loader: support Unicode text input Heinrich Schuchardt
2018-09-11 21:37 ` Alexander Graf
2018-09-11 21:51 ` [U-Boot] [PATCH v4 " Heinrich Schuchardt
2018-09-11 22:05 ` [U-Boot] [PATCH v5 1/13] " Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 02/13] test/py: Unicode w/ EFI_SIMPLE_TEXT_INPUT_PROTOCOL Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 03/13] efi_selftest: refactor text input test Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 04/13] efi_loader: rework event handling for console Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 05/13] efi_selftest: use WaitForKey to test text input Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 06/13] test/py: rework test_efi_selftest_text_input() Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 07/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 08/13] efi_loader: support modifiers for F1 - F4 Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 09/13] efi_selftest: test EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 10/13] test/py: " Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 11/13] efi_loader: implement key notify functions Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 12/13] efi_selftest: test key notification functions Heinrich Schuchardt
2018-09-11 20:38 ` [U-Boot] [PATCH v3 13/13] efi_loader: unset CONFIG_EFI_UNICODE_CAPITALIZATION 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.