efi_selftest_textinputex.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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. #include <efi_selftest.h>
  15. static const efi_guid_t text_input_ex_protocol_guid =
  16. EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
  17. static struct efi_simple_text_input_ex_protocol *con_in_ex;
  18. static struct efi_boot_services *boottime;
  19. static void *efi_key_notify_handle;
  20. static bool efi_running;
  21. /**
  22. * efi_key_notify_function() - key notification function
  23. *
  24. * This function is called when the registered key is hit.
  25. *
  26. * @key_data: next key
  27. * Return: status code
  28. */
  29. static efi_status_t EFIAPI efi_key_notify_function
  30. (struct efi_key_data *key_data)
  31. {
  32. efi_running = false;
  33. return EFI_SUCCESS;
  34. }
  35. /*
  36. * Setup unit test.
  37. *
  38. * @handle: handle of the loaded image
  39. * @systable: system table
  40. * @return: EFI_ST_SUCCESS for success
  41. */
  42. static int setup(const efi_handle_t handle,
  43. const struct efi_system_table *systable)
  44. {
  45. efi_status_t ret;
  46. struct efi_key_data key_data = {
  47. .key = {
  48. .scan_code = 0,
  49. .unicode_char = 0x18
  50. },
  51. .key_state = {
  52. .key_shift_state = EFI_SHIFT_STATE_VALID |
  53. EFI_LEFT_CONTROL_PRESSED,
  54. .key_toggle_state = EFI_TOGGLE_STATE_INVALID,
  55. },
  56. };
  57. boottime = systable->boottime;
  58. ret = boottime->locate_protocol(&text_input_ex_protocol_guid, NULL,
  59. (void **)&con_in_ex);
  60. if (ret != EFI_SUCCESS) {
  61. con_in_ex = NULL;
  62. efi_st_error
  63. ("Extended text input protocol is not available.\n");
  64. return EFI_ST_FAILURE;
  65. }
  66. ret = con_in_ex->register_key_notify(con_in_ex, &key_data,
  67. efi_key_notify_function,
  68. &efi_key_notify_handle);
  69. if (ret != EFI_SUCCESS) {
  70. efi_key_notify_handle = NULL;
  71. efi_st_error
  72. ("Notify function could not be registered.\n");
  73. return EFI_ST_FAILURE;
  74. }
  75. efi_running = true;
  76. return EFI_ST_SUCCESS;
  77. }
  78. /*
  79. * Tear down unit test.
  80. *
  81. * Unregister notify function.
  82. *
  83. * @return: EFI_ST_SUCCESS for success
  84. */
  85. static int teardown(void)
  86. {
  87. efi_status_t ret;
  88. ret = con_in_ex->unregister_key_notify
  89. (con_in_ex, efi_key_notify_handle);
  90. if (ret != EFI_SUCCESS) {
  91. efi_st_error
  92. ("Notify function could not be registered.\n");
  93. return EFI_ST_FAILURE;
  94. }
  95. return EFI_ST_SUCCESS;
  96. }
  97. /*
  98. * Execute unit test.
  99. *
  100. * @return: EFI_ST_SUCCESS for success
  101. */
  102. static int execute(void)
  103. {
  104. struct efi_key_data input_key = { {0, 0}, {0, 0} };
  105. efi_status_t ret;
  106. efi_uintn_t index;
  107. if (!con_in_ex) {
  108. efi_st_printf("Setup failed\n");
  109. return EFI_ST_FAILURE;
  110. }
  111. /* Drain the console input */
  112. ret = con_in_ex->reset(con_in_ex, true);
  113. if (ret != EFI_SUCCESS) {
  114. efi_st_error("Reset failed\n");
  115. return EFI_ST_FAILURE;
  116. }
  117. ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
  118. if (ret != EFI_NOT_READY) {
  119. efi_st_error("Empty buffer not reported\n");
  120. return EFI_ST_FAILURE;
  121. }
  122. efi_st_printf("Waiting for your input\n");
  123. efi_st_printf("To terminate type 'CTRL+x'\n");
  124. while (efi_running) {
  125. /* Wait for next key */
  126. ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex,
  127. &index);
  128. if (ret != EFI_ST_SUCCESS) {
  129. efi_st_error("WaitForEvent failed\n");
  130. return EFI_ST_FAILURE;
  131. }
  132. ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
  133. if (ret != EFI_SUCCESS) {
  134. efi_st_error("ReadKeyStroke failed\n");
  135. return EFI_ST_FAILURE;
  136. }
  137. /* Allow 5 minutes until time out */
  138. boottime->set_watchdog_timer(300, 0, 0, NULL);
  139. efi_st_printf("Unicode char %u (%ps), scan code %u (",
  140. (unsigned int)input_key.key.unicode_char,
  141. efi_st_translate_char(input_key.key.unicode_char),
  142. (unsigned int)input_key.key.scan_code);
  143. if (input_key.key_state.key_shift_state &
  144. EFI_SHIFT_STATE_VALID) {
  145. if (input_key.key_state.key_shift_state &
  146. (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED))
  147. efi_st_printf("SHIFT+");
  148. if (input_key.key_state.key_shift_state &
  149. (EFI_LEFT_ALT_PRESSED | EFI_RIGHT_ALT_PRESSED))
  150. efi_st_printf("ALT+");
  151. if (input_key.key_state.key_shift_state &
  152. (EFI_LEFT_CONTROL_PRESSED |
  153. EFI_RIGHT_CONTROL_PRESSED))
  154. efi_st_printf("CTRL+");
  155. if (input_key.key_state.key_shift_state &
  156. (EFI_LEFT_LOGO_PRESSED | EFI_RIGHT_LOGO_PRESSED))
  157. efi_st_printf("META+");
  158. if (input_key.key_state.key_shift_state ==
  159. EFI_SHIFT_STATE_VALID)
  160. efi_st_printf("+");
  161. }
  162. efi_st_printf("%ps)\n",
  163. efi_st_translate_code(input_key.key.scan_code));
  164. }
  165. return EFI_ST_SUCCESS;
  166. }
  167. EFI_UNIT_TEST(textinputex) = {
  168. .name = "extended text input",
  169. .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  170. .setup = setup,
  171. .execute = execute,
  172. .teardown = teardown,
  173. .on_request = true,
  174. };