]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/console.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / boot / efi / console.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
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
20 #include "console.h"
21 #include "util.h"
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)(
29 struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
30 BOOLEAN ExtendedVerification
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)(
46 struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
47 EFI_KEY_DATA *KeyData
48 );
49
50 typedef EFI_STATUS (EFIAPI *EFI_SET_STATE)(
51 struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
52 EFI_KEY_TOGGLE_STATE *KeyToggleState
53 );
54
55 typedef EFI_STATUS (EFIAPI *EFI_KEY_NOTIFY_FUNCTION)(
56 EFI_KEY_DATA *KeyData
57 );
58
59 typedef EFI_STATUS (EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY)(
60 struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
61 EFI_KEY_DATA KeyData,
62 EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
63 VOID **NotifyHandle
64 );
65
66 typedef EFI_STATUS (EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)(
67 struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
68 VOID *NotificationHandle
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 */
97 if (wait)
98 uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index);
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 }