]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/efi/console.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / boot / efi / console.c
CommitLineData
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
26struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
27
28typedef 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
33typedef UINT8 EFI_KEY_TOGGLE_STATE;
34
35typedef struct {
36 UINT32 KeyShiftState;
37 EFI_KEY_TOGGLE_STATE KeyToggleState;
38} EFI_KEY_STATE;
39
40typedef struct {
41 EFI_INPUT_KEY Key;
42 EFI_KEY_STATE KeyState;
43} EFI_KEY_DATA;
44
45typedef 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
50typedef 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
55typedef EFI_STATUS (EFIAPI *EFI_KEY_NOTIFY_FUNCTION)(
b40c3dfa 56 EFI_KEY_DATA *KeyData
0fa2cac4
KS
57);
58
59typedef 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
66typedef 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
71typedef 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
80EFI_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}