1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * efi_selftest_textinput 4 * 5 * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> 6 * 7 * Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. 8 * The unicode character and the scan code are printed for text 9 * input. To run the test: 10 * 11 * setenv efi_selftest extended text input 12 * bootefi selftest 13 */ 14 15 #include <efi_selftest.h> 16 17 static const efi_guid_t text_input_ex_protocol_guid = 18 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; 19 20 static struct efi_simple_text_input_ex_protocol *con_in_ex; 21 22 static struct efi_boot_services *boottime; 23 24 static void *efi_key_notify_handle; 25 static bool efi_running; 26 27 /** 28 * efi_key_notify_function() - key notification function 29 * 30 * This function is called when the registered key is hit. 31 * 32 * @key_data: next key 33 * Return: status code 34 */ 35 static efi_status_t EFIAPI efi_key_notify_function 36 (struct efi_key_data *key_data) 37 { 38 efi_running = false; 39 40 return EFI_SUCCESS; 41 } 42 43 /* 44 * Setup unit test. 45 * 46 * @handle: handle of the loaded image 47 * @systable: system table 48 * @return: EFI_ST_SUCCESS for success 49 */ 50 static int setup(const efi_handle_t handle, 51 const struct efi_system_table *systable) 52 { 53 efi_status_t ret; 54 struct efi_key_data key_data = { 55 .key = { 56 .scan_code = 0, 57 .unicode_char = 0x18 58 }, 59 .key_state = { 60 .key_shift_state = EFI_SHIFT_STATE_VALID | 61 EFI_LEFT_CONTROL_PRESSED, 62 .key_toggle_state = EFI_TOGGLE_STATE_INVALID, 63 }, 64 }; 65 66 boottime = systable->boottime; 67 68 ret = boottime->locate_protocol(&text_input_ex_protocol_guid, NULL, 69 (void **)&con_in_ex); 70 if (ret != EFI_SUCCESS) { 71 con_in_ex = NULL; 72 efi_st_error 73 ("Extended text input protocol is not available.\n"); 74 return EFI_ST_FAILURE; 75 } 76 77 ret = con_in_ex->register_key_notify(con_in_ex, &key_data, 78 efi_key_notify_function, 79 &efi_key_notify_handle); 80 if (ret != EFI_SUCCESS) { 81 efi_key_notify_handle = NULL; 82 efi_st_error 83 ("Notify function could not be registered.\n"); 84 return EFI_ST_FAILURE; 85 } 86 efi_running = true; 87 88 return EFI_ST_SUCCESS; 89 } 90 91 /* 92 * Tear down unit test. 93 * 94 * Unregister notify function. 95 * 96 * @return: EFI_ST_SUCCESS for success 97 */ 98 static int teardown(void) 99 { 100 efi_status_t ret; 101 102 ret = con_in_ex->unregister_key_notify 103 (con_in_ex, efi_key_notify_handle); 104 if (ret != EFI_SUCCESS) { 105 efi_st_error 106 ("Notify function could not be registered.\n"); 107 return EFI_ST_FAILURE; 108 } 109 110 return EFI_ST_SUCCESS; 111 } 112 /* 113 * Execute unit test. 114 * 115 * @return: EFI_ST_SUCCESS for success 116 */ 117 static int execute(void) 118 { 119 struct efi_key_data input_key = { {0, 0}, {0, 0} }; 120 efi_status_t ret; 121 efi_uintn_t index; 122 123 if (!con_in_ex) { 124 efi_st_printf("Setup failed\n"); 125 return EFI_ST_FAILURE; 126 } 127 128 /* Drain the console input */ 129 ret = con_in_ex->reset(con_in_ex, true); 130 if (ret != EFI_SUCCESS) { 131 efi_st_error("Reset failed\n"); 132 return EFI_ST_FAILURE; 133 } 134 ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key); 135 if (ret != EFI_NOT_READY) { 136 efi_st_error("Empty buffer not reported\n"); 137 return EFI_ST_FAILURE; 138 } 139 140 efi_st_printf("Waiting for your input\n"); 141 efi_st_printf("To terminate type 'CTRL+x'\n"); 142 143 while (efi_running) { 144 /* Wait for next key */ 145 ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex, 146 &index); 147 if (ret != EFI_ST_SUCCESS) { 148 efi_st_error("WaitForEvent failed\n"); 149 return EFI_ST_FAILURE; 150 } 151 ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key); 152 if (ret != EFI_SUCCESS) { 153 efi_st_error("ReadKeyStroke failed\n"); 154 return EFI_ST_FAILURE; 155 } 156 157 /* Allow 5 minutes until time out */ 158 boottime->set_watchdog_timer(300, 0, 0, NULL); 159 160 efi_st_printf("Unicode char %u (%ps), scan code %u (", 161 (unsigned int)input_key.key.unicode_char, 162 efi_st_translate_char(input_key.key.unicode_char), 163 (unsigned int)input_key.key.scan_code); 164 if (input_key.key_state.key_shift_state & 165 EFI_SHIFT_STATE_VALID) { 166 if (input_key.key_state.key_shift_state & 167 (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) 168 efi_st_printf("SHIFT+"); 169 if (input_key.key_state.key_shift_state & 170 (EFI_LEFT_ALT_PRESSED | EFI_RIGHT_ALT_PRESSED)) 171 efi_st_printf("ALT+"); 172 if (input_key.key_state.key_shift_state & 173 (EFI_LEFT_CONTROL_PRESSED | 174 EFI_RIGHT_CONTROL_PRESSED)) 175 efi_st_printf("CTRL+"); 176 if (input_key.key_state.key_shift_state & 177 (EFI_LEFT_LOGO_PRESSED | EFI_RIGHT_LOGO_PRESSED)) 178 efi_st_printf("META+"); 179 if (input_key.key_state.key_shift_state == 180 EFI_SHIFT_STATE_VALID) 181 efi_st_printf("+"); 182 } 183 184 efi_st_printf("%ps)\n", 185 efi_st_translate_code(input_key.key.scan_code)); 186 187 } 188 return EFI_ST_SUCCESS; 189 } 190 191 EFI_UNIT_TEST(textinputex) = { 192 .name = "extended text input", 193 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 194 .setup = setup, 195 .execute = execute, 196 .teardown = teardown, 197 .on_request = true, 198 }; 199