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 static struct efi_boot_services *boottime;
18 
19 /*
20  * Setup unit test.
21  *
22  * @handle:	handle of the loaded image
23  * @systable:	system table
24  * @return:	EFI_ST_SUCCESS for success
25  */
26 static int setup(const efi_handle_t handle,
27 		 const struct efi_system_table *systable)
28 {
29 	boottime = systable->boottime;
30 
31 	return EFI_ST_SUCCESS;
32 }
33 
34 /*
35  * Execute unit test.
36  *
37  * @return:	EFI_ST_SUCCESS for success
38  */
39 static int execute(void)
40 {
41 	struct efi_input_key input_key = {0};
42 	efi_status_t ret;
43 	efi_uintn_t index;
44 
45 	/* Drain the console input */
46 	ret = con_in->reset(con_in, true);
47 	if (ret != EFI_SUCCESS) {
48 		efi_st_error("Reset failed\n");
49 		return EFI_ST_FAILURE;
50 	}
51 	ret = con_in->read_key_stroke(con_in, &input_key);
52 	if (ret != EFI_NOT_READY) {
53 		efi_st_error("Empty buffer not reported\n");
54 		return EFI_ST_FAILURE;
55 	}
56 
57 	efi_st_printf("Waiting for your input\n");
58 	efi_st_printf("To terminate type 'x'\n");
59 
60 	for (;;) {
61 		/* Wait for next key */
62 		ret = boottime->wait_for_event(1, &con_in->wait_for_key,
63 					       &index);
64 		if (ret != EFI_ST_SUCCESS) {
65 			efi_st_error("WaitForEvent failed\n");
66 			return EFI_ST_FAILURE;
67 		}
68 		ret = con_in->read_key_stroke(con_in, &input_key);
69 		if (ret != EFI_SUCCESS) {
70 			efi_st_error("ReadKeyStroke failed\n");
71 			return EFI_ST_FAILURE;
72 		}
73 
74 		/* Allow 5 minutes until time out */
75 		boottime->set_watchdog_timer(300, 0, 0, NULL);
76 
77 		efi_st_printf("Unicode char %u (%ps), scan code %u (%ps)\n",
78 			      (unsigned int)input_key.unicode_char,
79 			      efi_st_translate_char(input_key.unicode_char),
80 			      (unsigned int)input_key.scan_code,
81 			      efi_st_translate_code(input_key.scan_code));
82 
83 		switch (input_key.unicode_char) {
84 		case 'x':
85 		case 'X':
86 			return EFI_ST_SUCCESS;
87 		}
88 	}
89 }
90 
91 EFI_UNIT_TEST(textinput) = {
92 	.name = "text input",
93 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
94 	.setup = setup,
95 	.execute = execute,
96 	.on_request = true,
97 };
98