efi_loader: rework event handling for console

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>
Signed-off-by: Alexander Graf <agraf@suse.de>
lime2-spi
Heinrich Schuchardt 6 years ago committed by Alexander Graf
parent 262ff411c2
commit 0dfd13a4c8
  1. 175
      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;

Loading…
Cancel
Save