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_PROTOCOL. 8 * The unicode character and the scan code are printed for text 9 * input. To run the test: 10 * 11 * setenv efi_selftest text input 12 * bootefi selftest 13 */ 14 15 #include <efi_selftest.h> 16 17 struct translate { 18 u16 code; 19 u16 *text; 20 }; 21 22 static struct efi_boot_services *boottime; 23 24 static struct translate control_characters[] = { 25 {0, L"Null"}, 26 {8, L"BS"}, 27 {9, L"TAB"}, 28 {10, L"LF"}, 29 {13, L"CR"}, 30 {0, NULL}, 31 }; 32 33 static u16 ch[] = L"' '"; 34 static u16 unknown[] = L"unknown"; 35 36 static struct translate scan_codes[] = { 37 {0x00, L"Null"}, 38 {0x01, L"Up"}, 39 {0x02, L"Down"}, 40 {0x03, L"Right"}, 41 {0x04, L"Left"}, 42 {0x05, L"Home"}, 43 {0x06, L"End"}, 44 {0x07, L"Insert"}, 45 {0x08, L"Delete"}, 46 {0x09, L"Page Up"}, 47 {0x0a, L"Page Down"}, 48 {0x0b, L"FN 1"}, 49 {0x0c, L"FN 2"}, 50 {0x0d, L"FN 3"}, 51 {0x0e, L"FN 4"}, 52 {0x0f, L"FN 5"}, 53 {0x10, L"FN 6"}, 54 {0x11, L"FN 7"}, 55 {0x12, L"FN 8"}, 56 {0x13, L"FN 9"}, 57 {0x14, L"FN 10"}, 58 {0x15, L"FN 11"}, 59 {0x16, L"FN 12"}, 60 {0x17, L"Escape"}, 61 {0x68, L"FN 13"}, 62 {0x69, L"FN 14"}, 63 {0x6a, L"FN 15"}, 64 {0x6b, L"FN 16"}, 65 {0x6c, L"FN 17"}, 66 {0x6d, L"FN 18"}, 67 {0x6e, L"FN 19"}, 68 {0x6f, L"FN 20"}, 69 {0x70, L"FN 21"}, 70 {0x71, L"FN 22"}, 71 {0x72, L"FN 23"}, 72 {0x73, L"FN 24"}, 73 {0x7f, L"Mute"}, 74 {0x80, L"Volume Up"}, 75 {0x81, L"Volume Down"}, 76 {0x100, L"Brightness Up"}, 77 {0x101, L"Brightness Down"}, 78 {0x102, L"Suspend"}, 79 {0x103, L"Hibernate"}, 80 {0x104, L"Toggle Display"}, 81 {0x105, L"Recovery"}, 82 {0x106, L"Reject"}, 83 {0x0, NULL}, 84 }; 85 86 /* 87 * Translate a unicode character to a string. 88 * 89 * @code unicode character 90 * @return string 91 */ 92 static u16 *translate_char(u16 code) 93 { 94 struct translate *tr; 95 96 if (code >= ' ') { 97 ch[1] = code; 98 return ch; 99 } 100 for (tr = control_characters; tr->text; ++tr) { 101 if (tr->code == code) 102 return tr->text; 103 } 104 return unknown; 105 } 106 107 /* 108 * Translate a scan code to a human readable string. 109 * 110 * @code unicode character 111 * @return string 112 */ 113 static u16 *translate_code(u16 code) 114 { 115 struct translate *tr; 116 117 for (tr = scan_codes; tr->text; ++tr) { 118 if (tr->code == code) 119 return tr->text; 120 } 121 return unknown; 122 } 123 124 /* 125 * Setup unit test. 126 * 127 * @handle: handle of the loaded image 128 * @systable: system table 129 * @return: EFI_ST_SUCCESS for success 130 */ 131 static int setup(const efi_handle_t handle, 132 const struct efi_system_table *systable) 133 { 134 boottime = systable->boottime; 135 136 return EFI_ST_SUCCESS; 137 } 138 139 /* 140 * Execute unit test. 141 * 142 * @return: EFI_ST_SUCCESS for success 143 */ 144 static int execute(void) 145 { 146 struct efi_input_key input_key = {0}; 147 efi_status_t ret; 148 149 efi_st_printf("Waiting for your input\n"); 150 efi_st_printf("To terminate type 'x'\n"); 151 152 for (;;) { 153 /* Wait for next key */ 154 do { 155 ret = con_in->read_key_stroke(con_in, &input_key); 156 } while (ret == EFI_NOT_READY); 157 158 /* Allow 5 minutes until time out */ 159 boottime->set_watchdog_timer(300, 0, 0, NULL); 160 161 efi_st_printf("Unicode char %u (%ps), scan code %u (%ps)\n", 162 (unsigned int)input_key.unicode_char, 163 translate_char(input_key.unicode_char), 164 (unsigned int)input_key.scan_code, 165 translate_code(input_key.scan_code)); 166 167 switch (input_key.unicode_char) { 168 case 'x': 169 case 'X': 170 return EFI_ST_SUCCESS; 171 } 172 } 173 } 174 175 EFI_UNIT_TEST(textinput) = { 176 .name = "text input", 177 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 178 .setup = setup, 179 .execute = execute, 180 .on_request = true, 181 }; 182