efi_selftest: test EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
[oweals/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 /*
25  * Setup unit test.
26  *
27  * @handle:     handle of the loaded image
28  * @systable:   system table
29  * @return:     EFI_ST_SUCCESS for success
30  */
31 static int setup(const efi_handle_t handle,
32                  const struct efi_system_table *systable)
33 {
34         efi_status_t ret;
35
36         boottime = systable->boottime;
37
38         ret = boottime->locate_protocol(&text_input_ex_protocol_guid, NULL,
39                                         (void **)&con_in_ex);
40         if (ret != EFI_SUCCESS) {
41                 con_in_ex = NULL;
42                 efi_st_error
43                         ("Extended text input protocol is not available.\n");
44                 return EFI_ST_FAILURE;
45         }
46
47         return EFI_ST_SUCCESS;
48 }
49
50 /*
51  * Execute unit test.
52  *
53  * @return:     EFI_ST_SUCCESS for success
54  */
55 static int execute(void)
56 {
57         struct efi_key_data input_key = {0,};
58         efi_status_t ret;
59         efi_uintn_t index;
60
61         if (!con_in_ex) {
62                 efi_st_printf("Setup failed\n");
63                 return EFI_ST_FAILURE;
64         }
65
66         /* Drain the console input */
67         ret = con_in_ex->reset(con_in_ex, true);
68         if (ret != EFI_SUCCESS) {
69                 efi_st_error("Reset failed\n");
70                 return EFI_ST_FAILURE;
71         }
72         ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
73         if (ret != EFI_NOT_READY) {
74                 efi_st_error("Empty buffer not reported\n");
75                 return EFI_ST_FAILURE;
76         }
77
78         efi_st_printf("Waiting for your input\n");
79         efi_st_printf("To terminate type 'x'\n");
80
81         for (;;) {
82                 /* Wait for next key */
83                 ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex,
84                                                &index);
85                 if (ret != EFI_ST_SUCCESS) {
86                         efi_st_error("WaitForEvent failed\n");
87                         return EFI_ST_FAILURE;
88                 }
89                 ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
90                 if (ret != EFI_SUCCESS) {
91                         efi_st_error("ReadKeyStroke failed\n");
92                         return EFI_ST_FAILURE;
93                 }
94
95                 /* Allow 5 minutes until time out */
96                 boottime->set_watchdog_timer(300, 0, 0, NULL);
97
98                 efi_st_printf("Unicode char %u (%ps), scan code %u (",
99                               (unsigned int)input_key.key.unicode_char,
100                               efi_st_translate_char(input_key.key.unicode_char),
101                               (unsigned int)input_key.key.scan_code);
102                 if (input_key.key_state.key_shift_state &
103                     EFI_SHIFT_STATE_VALID) {
104                         if (input_key.key_state.key_shift_state &
105                             (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED))
106                                 efi_st_printf("SHIFT+");
107                         if (input_key.key_state.key_shift_state &
108                             (EFI_LEFT_ALT_PRESSED | EFI_RIGHT_ALT_PRESSED))
109                                 efi_st_printf("ALT+");
110                         if (input_key.key_state.key_shift_state &
111                             (EFI_LEFT_CONTROL_PRESSED |
112                              EFI_RIGHT_CONTROL_PRESSED))
113                                 efi_st_printf("CTRL+");
114                         if (input_key.key_state.key_shift_state &
115                             (EFI_LEFT_LOGO_PRESSED | EFI_RIGHT_LOGO_PRESSED))
116                                 efi_st_printf("META+");
117                         if (input_key.key_state.key_shift_state ==
118                             EFI_SHIFT_STATE_VALID)
119                                 efi_st_printf("+");
120                 }
121
122                 efi_st_printf("%ps)\n",
123                               efi_st_translate_code(input_key.key.scan_code));
124
125                 switch (input_key.key.unicode_char) {
126                 case 'x':
127                 case 'X':
128                         return EFI_ST_SUCCESS;
129                 }
130         }
131 }
132
133 EFI_UNIT_TEST(textinputex) = {
134         .name = "extended text input",
135         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
136         .setup = setup,
137         .execute = execute,
138         .on_request = true,
139 };