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