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
17static 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 */
26static 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 */
39static 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
91EFI_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