13394f200SHeinrich Schuchardt // SPDX-License-Identifier: GPL-2.0+
23394f200SHeinrich Schuchardt /*
33394f200SHeinrich Schuchardt * efi_selftest_textinput
43394f200SHeinrich Schuchardt *
53394f200SHeinrich Schuchardt * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
63394f200SHeinrich Schuchardt *
73394f200SHeinrich Schuchardt * Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
83394f200SHeinrich Schuchardt * The unicode character and the scan code are printed for text
93394f200SHeinrich Schuchardt * input. To run the test:
103394f200SHeinrich Schuchardt *
113394f200SHeinrich Schuchardt * setenv efi_selftest extended text input
123394f200SHeinrich Schuchardt * bootefi selftest
133394f200SHeinrich Schuchardt */
143394f200SHeinrich Schuchardt
153394f200SHeinrich Schuchardt #include <efi_selftest.h>
163394f200SHeinrich Schuchardt
173394f200SHeinrich Schuchardt static const efi_guid_t text_input_ex_protocol_guid =
183394f200SHeinrich Schuchardt EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
193394f200SHeinrich Schuchardt
203394f200SHeinrich Schuchardt static struct efi_simple_text_input_ex_protocol *con_in_ex;
213394f200SHeinrich Schuchardt
223394f200SHeinrich Schuchardt static struct efi_boot_services *boottime;
233394f200SHeinrich Schuchardt
246dec8739SHeinrich Schuchardt static void *efi_key_notify_handle;
256dec8739SHeinrich Schuchardt static bool efi_running;
266dec8739SHeinrich Schuchardt
276dec8739SHeinrich Schuchardt /**
286dec8739SHeinrich Schuchardt * efi_key_notify_function() - key notification function
296dec8739SHeinrich Schuchardt *
306dec8739SHeinrich Schuchardt * This function is called when the registered key is hit.
316dec8739SHeinrich Schuchardt *
326dec8739SHeinrich Schuchardt * @key_data: next key
336dec8739SHeinrich Schuchardt * Return: status code
346dec8739SHeinrich Schuchardt */
efi_key_notify_function(struct efi_key_data * key_data)356dec8739SHeinrich Schuchardt static efi_status_t EFIAPI efi_key_notify_function
366dec8739SHeinrich Schuchardt (struct efi_key_data *key_data)
376dec8739SHeinrich Schuchardt {
386dec8739SHeinrich Schuchardt efi_running = false;
396dec8739SHeinrich Schuchardt
406dec8739SHeinrich Schuchardt return EFI_SUCCESS;
416dec8739SHeinrich Schuchardt }
426dec8739SHeinrich Schuchardt
433394f200SHeinrich Schuchardt /*
443394f200SHeinrich Schuchardt * Setup unit test.
453394f200SHeinrich Schuchardt *
463394f200SHeinrich Schuchardt * @handle: handle of the loaded image
473394f200SHeinrich Schuchardt * @systable: system table
483394f200SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success
493394f200SHeinrich Schuchardt */
setup(const efi_handle_t handle,const struct efi_system_table * systable)503394f200SHeinrich Schuchardt static int setup(const efi_handle_t handle,
513394f200SHeinrich Schuchardt const struct efi_system_table *systable)
523394f200SHeinrich Schuchardt {
533394f200SHeinrich Schuchardt efi_status_t ret;
546dec8739SHeinrich Schuchardt struct efi_key_data key_data = {
556dec8739SHeinrich Schuchardt .key = {
566dec8739SHeinrich Schuchardt .scan_code = 0,
576dec8739SHeinrich Schuchardt .unicode_char = 0x18
586dec8739SHeinrich Schuchardt },
596dec8739SHeinrich Schuchardt .key_state = {
606dec8739SHeinrich Schuchardt .key_shift_state = EFI_SHIFT_STATE_VALID |
616dec8739SHeinrich Schuchardt EFI_LEFT_CONTROL_PRESSED,
626dec8739SHeinrich Schuchardt .key_toggle_state = EFI_TOGGLE_STATE_INVALID,
636dec8739SHeinrich Schuchardt },
646dec8739SHeinrich Schuchardt };
653394f200SHeinrich Schuchardt
663394f200SHeinrich Schuchardt boottime = systable->boottime;
673394f200SHeinrich Schuchardt
683394f200SHeinrich Schuchardt ret = boottime->locate_protocol(&text_input_ex_protocol_guid, NULL,
693394f200SHeinrich Schuchardt (void **)&con_in_ex);
703394f200SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
713394f200SHeinrich Schuchardt con_in_ex = NULL;
723394f200SHeinrich Schuchardt efi_st_error
733394f200SHeinrich Schuchardt ("Extended text input protocol is not available.\n");
743394f200SHeinrich Schuchardt return EFI_ST_FAILURE;
753394f200SHeinrich Schuchardt }
763394f200SHeinrich Schuchardt
776dec8739SHeinrich Schuchardt ret = con_in_ex->register_key_notify(con_in_ex, &key_data,
786dec8739SHeinrich Schuchardt efi_key_notify_function,
796dec8739SHeinrich Schuchardt &efi_key_notify_handle);
806dec8739SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
816dec8739SHeinrich Schuchardt efi_key_notify_handle = NULL;
826dec8739SHeinrich Schuchardt efi_st_error
836dec8739SHeinrich Schuchardt ("Notify function could not be registered.\n");
846dec8739SHeinrich Schuchardt return EFI_ST_FAILURE;
856dec8739SHeinrich Schuchardt }
866dec8739SHeinrich Schuchardt efi_running = true;
876dec8739SHeinrich Schuchardt
883394f200SHeinrich Schuchardt return EFI_ST_SUCCESS;
893394f200SHeinrich Schuchardt }
903394f200SHeinrich Schuchardt
913394f200SHeinrich Schuchardt /*
926dec8739SHeinrich Schuchardt * Tear down unit test.
936dec8739SHeinrich Schuchardt *
946dec8739SHeinrich Schuchardt * Unregister notify function.
956dec8739SHeinrich Schuchardt *
966dec8739SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success
976dec8739SHeinrich Schuchardt */
teardown(void)986dec8739SHeinrich Schuchardt static int teardown(void)
996dec8739SHeinrich Schuchardt {
1006dec8739SHeinrich Schuchardt efi_status_t ret;
1016dec8739SHeinrich Schuchardt
1026dec8739SHeinrich Schuchardt ret = con_in_ex->unregister_key_notify
1036dec8739SHeinrich Schuchardt (con_in_ex, efi_key_notify_handle);
1046dec8739SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
1056dec8739SHeinrich Schuchardt efi_st_error
1066dec8739SHeinrich Schuchardt ("Notify function could not be registered.\n");
1076dec8739SHeinrich Schuchardt return EFI_ST_FAILURE;
1086dec8739SHeinrich Schuchardt }
1096dec8739SHeinrich Schuchardt
1106dec8739SHeinrich Schuchardt return EFI_ST_SUCCESS;
1116dec8739SHeinrich Schuchardt }
1126dec8739SHeinrich Schuchardt /*
1133394f200SHeinrich Schuchardt * Execute unit test.
1143394f200SHeinrich Schuchardt *
1153394f200SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success
1163394f200SHeinrich Schuchardt */
execute(void)1173394f200SHeinrich Schuchardt static int execute(void)
1183394f200SHeinrich Schuchardt {
119*e1020386SHeinrich Schuchardt struct efi_key_data input_key = { {0, 0}, {0, 0} };
1203394f200SHeinrich Schuchardt efi_status_t ret;
1213394f200SHeinrich Schuchardt efi_uintn_t index;
1223394f200SHeinrich Schuchardt
1233394f200SHeinrich Schuchardt if (!con_in_ex) {
1243394f200SHeinrich Schuchardt efi_st_printf("Setup failed\n");
1253394f200SHeinrich Schuchardt return EFI_ST_FAILURE;
1263394f200SHeinrich Schuchardt }
1273394f200SHeinrich Schuchardt
1283394f200SHeinrich Schuchardt /* Drain the console input */
1293394f200SHeinrich Schuchardt ret = con_in_ex->reset(con_in_ex, true);
1303394f200SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
1313394f200SHeinrich Schuchardt efi_st_error("Reset failed\n");
1323394f200SHeinrich Schuchardt return EFI_ST_FAILURE;
1333394f200SHeinrich Schuchardt }
1343394f200SHeinrich Schuchardt ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
1353394f200SHeinrich Schuchardt if (ret != EFI_NOT_READY) {
1363394f200SHeinrich Schuchardt efi_st_error("Empty buffer not reported\n");
1373394f200SHeinrich Schuchardt return EFI_ST_FAILURE;
1383394f200SHeinrich Schuchardt }
1393394f200SHeinrich Schuchardt
1403394f200SHeinrich Schuchardt efi_st_printf("Waiting for your input\n");
1416dec8739SHeinrich Schuchardt efi_st_printf("To terminate type 'CTRL+x'\n");
1423394f200SHeinrich Schuchardt
1436dec8739SHeinrich Schuchardt while (efi_running) {
1443394f200SHeinrich Schuchardt /* Wait for next key */
1453394f200SHeinrich Schuchardt ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex,
1463394f200SHeinrich Schuchardt &index);
1473394f200SHeinrich Schuchardt if (ret != EFI_ST_SUCCESS) {
1483394f200SHeinrich Schuchardt efi_st_error("WaitForEvent failed\n");
1493394f200SHeinrich Schuchardt return EFI_ST_FAILURE;
1503394f200SHeinrich Schuchardt }
1513394f200SHeinrich Schuchardt ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
1523394f200SHeinrich Schuchardt if (ret != EFI_SUCCESS) {
1533394f200SHeinrich Schuchardt efi_st_error("ReadKeyStroke failed\n");
1543394f200SHeinrich Schuchardt return EFI_ST_FAILURE;
1553394f200SHeinrich Schuchardt }
1563394f200SHeinrich Schuchardt
1573394f200SHeinrich Schuchardt /* Allow 5 minutes until time out */
1583394f200SHeinrich Schuchardt boottime->set_watchdog_timer(300, 0, 0, NULL);
1593394f200SHeinrich Schuchardt
1603394f200SHeinrich Schuchardt efi_st_printf("Unicode char %u (%ps), scan code %u (",
1613394f200SHeinrich Schuchardt (unsigned int)input_key.key.unicode_char,
1623394f200SHeinrich Schuchardt efi_st_translate_char(input_key.key.unicode_char),
1633394f200SHeinrich Schuchardt (unsigned int)input_key.key.scan_code);
1643394f200SHeinrich Schuchardt if (input_key.key_state.key_shift_state &
1653394f200SHeinrich Schuchardt EFI_SHIFT_STATE_VALID) {
1663394f200SHeinrich Schuchardt if (input_key.key_state.key_shift_state &
1673394f200SHeinrich Schuchardt (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED))
1683394f200SHeinrich Schuchardt efi_st_printf("SHIFT+");
1693394f200SHeinrich Schuchardt if (input_key.key_state.key_shift_state &
1703394f200SHeinrich Schuchardt (EFI_LEFT_ALT_PRESSED | EFI_RIGHT_ALT_PRESSED))
1713394f200SHeinrich Schuchardt efi_st_printf("ALT+");
1723394f200SHeinrich Schuchardt if (input_key.key_state.key_shift_state &
1733394f200SHeinrich Schuchardt (EFI_LEFT_CONTROL_PRESSED |
1743394f200SHeinrich Schuchardt EFI_RIGHT_CONTROL_PRESSED))
1753394f200SHeinrich Schuchardt efi_st_printf("CTRL+");
1763394f200SHeinrich Schuchardt if (input_key.key_state.key_shift_state &
1773394f200SHeinrich Schuchardt (EFI_LEFT_LOGO_PRESSED | EFI_RIGHT_LOGO_PRESSED))
1783394f200SHeinrich Schuchardt efi_st_printf("META+");
1793394f200SHeinrich Schuchardt if (input_key.key_state.key_shift_state ==
1803394f200SHeinrich Schuchardt EFI_SHIFT_STATE_VALID)
1813394f200SHeinrich Schuchardt efi_st_printf("+");
1823394f200SHeinrich Schuchardt }
1833394f200SHeinrich Schuchardt
1843394f200SHeinrich Schuchardt efi_st_printf("%ps)\n",
1853394f200SHeinrich Schuchardt efi_st_translate_code(input_key.key.scan_code));
1863394f200SHeinrich Schuchardt
1876dec8739SHeinrich Schuchardt }
1883394f200SHeinrich Schuchardt return EFI_ST_SUCCESS;
1893394f200SHeinrich Schuchardt }
1903394f200SHeinrich Schuchardt
1913394f200SHeinrich Schuchardt EFI_UNIT_TEST(textinputex) = {
1923394f200SHeinrich Schuchardt .name = "extended text input",
1933394f200SHeinrich Schuchardt .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
1943394f200SHeinrich Schuchardt .setup = setup,
1953394f200SHeinrich Schuchardt .execute = execute,
1966dec8739SHeinrich Schuchardt .teardown = teardown,
1973394f200SHeinrich Schuchardt .on_request = true,
1983394f200SHeinrich Schuchardt };
199