All of lore.kernel.org
 help / color / mirror / Atom feed
From: Heinrich Schuchardt <xypron.glpk@gmx.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v3 07/13] efi_loader: EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
Date: Tue, 11 Sep 2018 22:38:08 +0200	[thread overview]
Message-ID: <20180911203814.16960-8-xypron.glpk@gmx.de> (raw)
In-Reply-To: <20180911203814.16960-1-xypron.glpk@gmx.de>

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

  parent reply	other threads:[~2018-09-11 20:38 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Heinrich Schuchardt [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180911203814.16960-8-xypron.glpk@gmx.de \
    --to=xypron.glpk@gmx.de \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.