]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
0fa2cac4 KS |
2 | /* |
3 | * This program is free software; you can redistribute it and/or modify it | |
4 | * under the terms of the GNU Lesser General Public License as published by | |
5 | * the Free Software Foundation; either version 2.1 of the License, or | |
6 | * (at your option) any later version. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, but | |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * Lesser General Public License for more details. | |
12 | * | |
13 | * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org> | |
14 | * Copyright (C) 2012 Harald Hoyer <harald@redhat.com> | |
15 | */ | |
16 | ||
17 | #include <efi.h> | |
18 | #include <efilib.h> | |
19 | ||
0fa2cac4 | 20 | #include "console.h" |
cf0fbc49 | 21 | #include "util.h" |
0fa2cac4 KS |
22 | |
23 | #define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ | |
24 | { 0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } } | |
25 | ||
26 | struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; | |
27 | ||
28 | typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET_EX)( | |
b40c3dfa KS |
29 | struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, |
30 | BOOLEAN ExtendedVerification | |
0fa2cac4 KS |
31 | ); |
32 | ||
33 | typedef UINT8 EFI_KEY_TOGGLE_STATE; | |
34 | ||
35 | typedef struct { | |
36 | UINT32 KeyShiftState; | |
37 | EFI_KEY_TOGGLE_STATE KeyToggleState; | |
38 | } EFI_KEY_STATE; | |
39 | ||
40 | typedef struct { | |
41 | EFI_INPUT_KEY Key; | |
42 | EFI_KEY_STATE KeyState; | |
43 | } EFI_KEY_DATA; | |
44 | ||
45 | typedef EFI_STATUS (EFIAPI *EFI_INPUT_READ_KEY_EX)( | |
b40c3dfa KS |
46 | struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, |
47 | EFI_KEY_DATA *KeyData | |
0fa2cac4 KS |
48 | ); |
49 | ||
50 | typedef EFI_STATUS (EFIAPI *EFI_SET_STATE)( | |
b40c3dfa KS |
51 | struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, |
52 | EFI_KEY_TOGGLE_STATE *KeyToggleState | |
0fa2cac4 KS |
53 | ); |
54 | ||
55 | typedef EFI_STATUS (EFIAPI *EFI_KEY_NOTIFY_FUNCTION)( | |
b40c3dfa | 56 | EFI_KEY_DATA *KeyData |
0fa2cac4 KS |
57 | ); |
58 | ||
59 | typedef EFI_STATUS (EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY)( | |
b40c3dfa KS |
60 | struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, |
61 | EFI_KEY_DATA KeyData, | |
62 | EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, | |
63 | VOID **NotifyHandle | |
0fa2cac4 KS |
64 | ); |
65 | ||
66 | typedef EFI_STATUS (EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)( | |
b40c3dfa KS |
67 | struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, |
68 | VOID *NotificationHandle | |
0fa2cac4 KS |
69 | ); |
70 | ||
71 | typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL { | |
72 | EFI_INPUT_RESET_EX Reset; | |
73 | EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx; | |
74 | EFI_EVENT WaitForKeyEx; | |
75 | EFI_SET_STATE SetState; | |
76 | EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify; | |
77 | EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify; | |
78 | } EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; | |
79 | ||
80 | EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) { | |
81 | EFI_GUID EfiSimpleTextInputExProtocolGuid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; | |
82 | static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx; | |
83 | static BOOLEAN checked; | |
84 | UINTN index; | |
85 | EFI_INPUT_KEY k; | |
86 | EFI_STATUS err; | |
87 | ||
88 | if (!checked) { | |
89 | err = LibLocateProtocol(&EfiSimpleTextInputExProtocolGuid, (VOID **)&TextInputEx); | |
90 | if (EFI_ERROR(err)) | |
91 | TextInputEx = NULL; | |
92 | ||
93 | checked = TRUE; | |
94 | } | |
95 | ||
96 | /* wait until key is pressed */ | |
03e749af JJ |
97 | if (wait) |
98 | uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index); | |
0fa2cac4 KS |
99 | |
100 | if (TextInputEx) { | |
101 | EFI_KEY_DATA keydata; | |
102 | UINT64 keypress; | |
103 | ||
104 | err = uefi_call_wrapper(TextInputEx->ReadKeyStrokeEx, 2, TextInputEx, &keydata); | |
105 | if (!EFI_ERROR(err)) { | |
106 | UINT32 shift = 0; | |
107 | ||
108 | /* do not distinguish between left and right keys */ | |
109 | if (keydata.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) { | |
110 | if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED)) | |
111 | shift |= EFI_CONTROL_PRESSED; | |
112 | if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED)) | |
113 | shift |= EFI_ALT_PRESSED; | |
114 | }; | |
115 | ||
116 | /* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */ | |
117 | keypress = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar); | |
118 | if (keypress > 0) { | |
119 | *key = keypress; | |
120 | return 0; | |
121 | } | |
122 | } | |
123 | } | |
124 | ||
125 | /* fallback for firmware which does not support SimpleTextInputExProtocol | |
126 | * | |
127 | * This is also called in case ReadKeyStrokeEx did not return a key, because | |
128 | * some broken firmwares offer SimpleTextInputExProtocol, but never acually | |
129 | * handle any key. */ | |
130 | err = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &k); | |
131 | if (EFI_ERROR(err)) | |
132 | return err; | |
133 | ||
134 | *key = KEYPRESS(0, k.ScanCode, k.UnicodeChar); | |
135 | return 0; | |
136 | } |