[U-Boot] [PATCH 5/6] efi_loader: rework event handling for console

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


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 at gmx.de>
---
 lib/efi_loader/efi_console.c | 204 ++++++++++++++++++++++++++---------
 1 file changed, 153 insertions(+), 51 deletions(-)

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



More information about the U-Boot mailing list