Prepare v2024.10
[platform/kernel/u-boot.git] / lib / efi_selftest / efi_selftest_textinputex.c
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 };