summaryrefslogtreecommitdiff
path: root/lib/efi_selftest/efi_selftest_textinputex.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/efi_selftest/efi_selftest_textinputex.c')
-rw-r--r--lib/efi_selftest/efi_selftest_textinputex.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/lib/efi_selftest/efi_selftest_textinputex.c b/lib/efi_selftest/efi_selftest_textinputex.c
new file mode 100644
index 0000000000..de44224ce1
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_textinputex.c
@@ -0,0 +1,198 @@
+// 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;
+
+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.
+ *
+ * @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;
+ 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;
+
+ 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;
+ }
+
+ 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.
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ struct efi_key_data input_key = { {0, 0}, {0, 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 'CTRL+x'\n");
+
+ while (efi_running) {
+ /* 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));
+
+ }
+ return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(textinputex) = {
+ .name = "extended text input",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+ .teardown = teardown,
+ .on_request = true,
+};