diff options
-rw-r--r-- | OvmfPkg/VirtioKeyboardDxe/VirtioKeyCodes.h | 294 | ||||
-rw-r--r-- | OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.c | 1523 | ||||
-rw-r--r-- | OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.h | 209 | ||||
-rw-r--r-- | OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.inf | 41 |
4 files changed, 2067 insertions, 0 deletions
diff --git a/OvmfPkg/VirtioKeyboardDxe/VirtioKeyCodes.h b/OvmfPkg/VirtioKeyboardDxe/VirtioKeyCodes.h new file mode 100644 index 0000000000..31299b5c64 --- /dev/null +++ b/OvmfPkg/VirtioKeyboardDxe/VirtioKeyCodes.h @@ -0,0 +1,294 @@ +/** @file
+
+ Key codes definitions for the VirtioKeyboard driver
+
+ This is a fork of common Linux key codes:
+ https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
+
+ Copyright (C) 2024, Red Hat
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VIRTIO_KEYBOARD_KEY_CODES_H_
+#define _VIRTIO_KEYBOARD_KEY_CODES_H_
+
+/*
+ * Event types
+ */
+#define EV_SYN 0x00
+#define EV_KEY 0x01
+
+/*
+ * Keys and buttons
+ */
+#define KEY_RESERVED 0
+#define KEY_ESC 1
+#define KEY_1 2
+#define KEY_2 3
+#define KEY_3 4
+#define KEY_4 5
+#define KEY_5 6
+#define KEY_6 7
+#define KEY_7 8
+#define KEY_8 9
+#define KEY_9 10
+#define KEY_0 11
+#define KEY_MINUS 12
+#define KEY_EQUAL 13
+#define KEY_BACKSPACE 14
+#define KEY_TAB 15
+#define KEY_Q 16
+#define KEY_W 17
+#define KEY_E 18
+#define KEY_R 19
+#define KEY_T 20
+#define KEY_Y 21
+#define KEY_U 22
+#define KEY_I 23
+#define KEY_O 24
+#define KEY_P 25
+#define KEY_LEFTBRACE 26
+#define KEY_RIGHTBRACE 27
+#define KEY_ENTER 28
+#define KEY_LEFTCTRL 29
+#define KEY_A 30
+#define KEY_S 31
+#define KEY_D 32
+#define KEY_F 33
+#define KEY_G 34
+#define KEY_H 35
+#define KEY_J 36
+#define KEY_K 37
+#define KEY_L 38
+#define KEY_SEMICOLON 39
+#define KEY_APOSTROPHE 40
+#define KEY_GRAVE 41
+#define KEY_LEFTSHIFT 42
+#define KEY_BACKSLASH 43
+#define KEY_Z 44
+#define KEY_X 45
+#define KEY_C 46
+#define KEY_V 47
+#define KEY_B 48
+#define KEY_N 49
+#define KEY_M 50
+#define KEY_COMMA 51
+#define KEY_DOT 52
+#define KEY_SLASH 53
+#define KEY_RIGHTSHIFT 54
+#define KEY_KPASTERISK 55
+#define KEY_LEFTALT 56
+#define KEY_SPACE 57
+#define KEY_CAPSLOCK 58
+#define KEY_F1 59
+#define KEY_F2 60
+#define KEY_F3 61
+#define KEY_F4 62
+#define KEY_F5 63
+#define KEY_F6 64
+#define KEY_F7 65
+#define KEY_F8 66
+#define KEY_F9 67
+#define KEY_F10 68
+#define KEY_NUMLOCK 69
+#define KEY_SCROLLLOCK 70
+#define KEY_KP7 71
+#define KEY_KP8 72
+#define KEY_KP9 73
+#define KEY_KPMINUS 74
+#define KEY_KP4 75
+#define KEY_KP5 76
+#define KEY_KP6 77
+#define KEY_KPPLUS 78
+#define KEY_KP1 79
+#define KEY_KP2 80
+#define KEY_KP3 81
+#define KEY_KP0 82
+#define KEY_KPDOT 83
+
+#define KEY_ZENKAKUHANKAKU 85
+#define KEY_102ND 86
+#define KEY_F11 87
+#define KEY_F12 88
+#define KEY_RO 89
+#define KEY_KATAKANA 90
+#define KEY_HIRAGANA 91
+#define KEY_HENKAN 92
+#define KEY_KATAKANAHIRAGANA 93
+#define KEY_MUHENKAN 94
+#define KEY_KPJPCOMMA 95
+#define KEY_KPENTER 96
+#define KEY_RIGHTCTRL 97
+#define KEY_KPSLASH 98
+#define KEY_SYSRQ 99
+#define KEY_RIGHTALT 100
+#define KEY_LINEFEED 101
+#define KEY_HOME 102
+#define KEY_UP 103
+#define KEY_PAGEUP 104
+#define KEY_LEFT 105
+#define KEY_RIGHT 106
+#define KEY_END 107
+#define KEY_DOWN 108
+#define KEY_PAGEDOWN 109
+#define KEY_INSERT 110
+#define KEY_DELETE 111
+#define KEY_MACRO 112
+#define KEY_MUTE 113
+#define KEY_VOLUMEDOWN 114
+#define KEY_VOLUMEUP 115
+#define KEY_POWER 116 /* SC System Power Down */
+#define KEY_KPEQUAL 117
+#define KEY_KPPLUSMINUS 118
+#define KEY_PAUSE 119
+#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */
+
+#define KEY_KPCOMMA 121
+#define KEY_HANGEUL 122
+#define KEY_HANGUEL KEY_HANGEUL
+#define KEY_HANJA 123
+#define KEY_YEN 124
+#define KEY_LEFTMETA 125
+#define KEY_RIGHTMETA 126
+#define KEY_COMPOSE 127
+
+#define KEY_STOP 128 /* AC Stop */
+#define KEY_AGAIN 129
+#define KEY_PROPS 130 /* AC Properties */
+#define KEY_UNDO 131 /* AC Undo */
+#define KEY_FRONT 132
+#define KEY_COPY 133 /* AC Copy */
+#define KEY_OPEN 134 /* AC Open */
+#define KEY_PASTE 135 /* AC Paste */
+#define KEY_FIND 136 /* AC Search */
+#define KEY_CUT 137 /* AC Cut */
+#define KEY_HELP 138 /* AL Integrated Help Center */
+#define KEY_MENU 139 /* Menu (show menu) */
+#define KEY_CALC 140 /* AL Calculator */
+#define KEY_SETUP 141
+#define KEY_SLEEP 142 /* SC System Sleep */
+#define KEY_WAKEUP 143 /* System Wake Up */
+#define KEY_FILE 144 /* AL Local Machine Browser */
+#define KEY_SENDFILE 145
+#define KEY_DELETEFILE 146
+#define KEY_XFER 147
+#define KEY_PROG1 148
+#define KEY_PROG2 149
+#define KEY_WWW 150 /* AL Internet Browser */
+#define KEY_MSDOS 151
+#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */
+#define KEY_SCREENLOCK KEY_COFFEE
+#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */
+#define KEY_DIRECTION KEY_ROTATE_DISPLAY
+#define KEY_CYCLEWINDOWS 154
+#define KEY_MAIL 155
+#define KEY_BOOKMARKS 156 /* AC Bookmarks */
+#define KEY_COMPUTER 157
+#define KEY_BACK 158 /* AC Back */
+#define KEY_FORWARD 159 /* AC Forward */
+#define KEY_CLOSECD 160
+#define KEY_EJECTCD 161
+#define KEY_EJECTCLOSECD 162
+#define KEY_NEXTSONG 163
+#define KEY_PLAYPAUSE 164
+#define KEY_PREVIOUSSONG 165
+#define KEY_STOPCD 166
+#define KEY_RECORD 167
+#define KEY_REWIND 168
+#define KEY_PHONE 169 /* Media Select Telephone */
+#define KEY_ISO 170
+#define KEY_CONFIG 171 /* AL Consumer Control Configuration */
+#define KEY_HOMEPAGE 172 /* AC Home */
+#define KEY_REFRESH 173 /* AC Refresh */
+#define KEY_EXIT 174 /* AC Exit */
+#define KEY_MOVE 175
+#define KEY_EDIT 176
+#define KEY_SCROLLUP 177
+#define KEY_SCROLLDOWN 178
+#define KEY_KPLEFTPAREN 179
+#define KEY_KPRIGHTPAREN 180
+#define KEY_NEW 181 /* AC New */
+#define KEY_REDO 182 /* AC Redo/Repeat */
+
+#define KEY_F13 183
+#define KEY_F14 184
+#define KEY_F15 185
+#define KEY_F16 186
+#define KEY_F17 187
+#define KEY_F18 188
+#define KEY_F19 189
+#define KEY_F20 190
+#define KEY_F21 191
+#define KEY_F22 192
+#define KEY_F23 193
+#define KEY_F24 194
+
+#define KEY_PLAYCD 200
+#define KEY_PAUSECD 201
+#define KEY_PROG3 202
+#define KEY_PROG4 203
+#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */
+#define KEY_DASHBOARD KEY_ALL_APPLICATIONS
+#define KEY_SUSPEND 205
+#define KEY_CLOSE 206 /* AC Close */
+#define KEY_PLAY 207
+#define KEY_FASTFORWARD 208
+#define KEY_BASSBOOST 209
+#define KEY_PRINT 210 /* AC Print */
+#define KEY_HP 211
+#define KEY_CAMERA 212
+#define KEY_SOUND 213
+#define KEY_QUESTION 214
+#define KEY_EMAIL 215
+#define KEY_CHAT 216
+#define KEY_SEARCH 217
+#define KEY_CONNECT 218
+#define KEY_FINANCE 219 /* AL Checkbook/Finance */
+#define KEY_SPORT 220
+#define KEY_SHOP 221
+#define KEY_ALTERASE 222
+#define KEY_CANCEL 223 /* AC Cancel */
+#define KEY_BRIGHTNESSDOWN 224
+#define KEY_BRIGHTNESSUP 225
+#define KEY_MEDIA 226
+
+#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video
+ outputs (Monitor/LCD/TV-out/etc) */
+#define KEY_KBDILLUMTOGGLE 228
+#define KEY_KBDILLUMDOWN 229
+#define KEY_KBDILLUMUP 230
+
+#define KEY_SEND 231 /* AC Send */
+#define KEY_REPLY 232 /* AC Reply */
+#define KEY_FORWARDMAIL 233 /* AC Forward Msg */
+#define KEY_SAVE 234 /* AC Save */
+#define KEY_DOCUMENTS 235
+
+#define KEY_BATTERY 236
+
+#define KEY_BLUETOOTH 237
+#define KEY_WLAN 238
+#define KEY_UWB 239
+
+#define KEY_UNKNOWN 240
+
+#define KEY_VIDEO_NEXT 241 /* drive next video source */
+#define KEY_VIDEO_PREV 242 /* drive previous video source */
+#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */
+#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual
+ brightness control is off,
+ rely on ambient */
+#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
+#define KEY_DISPLAY_OFF 245 /* display device to off state */
+
+#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
+#define KEY_WIMAX KEY_WWAN
+#define KEY_RFKILL 247 /* Key that controls all radios */
+
+#define KEY_MICMUTE 248 /* Mute / unmute the microphone */
+
+/* Code 255 is reserved for special needs of AT keyboard driver */
+
+#endif
diff --git a/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.c b/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.c new file mode 100644 index 0000000000..fa2bf4a124 --- /dev/null +++ b/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.c @@ -0,0 +1,1523 @@ +/** @file
+
+ This driver produces EFI_SIMPLE_TEXT_INPUT_PROTOCOL for virtarm devices.
+
+ Copyright (C) 2024, Red Hat, Inc.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/VirtioLib.h>
+
+#include <VirtioKeyboard.h>
+#include <VirtioKeyCodes.h>
+
+// -----------------------------------------------------------------------------
+// Return buffer pointer out of the ring buffer
+STATIC
+VOID *
+BufferPtr (
+ IN VIRTIO_KBD_RING *Ring,
+ IN UINT32 BufferNr
+ )
+{
+ return Ring->Buffers + Ring->BufferSize * BufferNr;
+}
+
+// -----------------------------------------------------------------------------
+// Return buffer physical address out of the ring buffer
+STATIC
+EFI_PHYSICAL_ADDRESS
+BufferAddr (
+ IN VIRTIO_KBD_RING *Ring,
+ IN UINT32 BufferNr
+ )
+{
+ return Ring->DeviceAddress + Ring->BufferSize * BufferNr;
+}
+
+// Return next buffer from ring
+STATIC
+UINT32
+BufferNext (
+ IN VIRTIO_KBD_RING *Ring
+ )
+{
+ return Ring->Indices.NextDescIdx % Ring->Ring.QueueSize;
+}
+
+// -----------------------------------------------------------------------------
+// Push the buffer to the device
+EFI_STATUS
+EFIAPI
+VirtioKeyboardRingSendBuffer (
+ IN OUT VIRTIO_KBD_DEV *Dev,
+ IN UINT16 Index,
+ IN VOID *Data,
+ IN UINT32 DataSize,
+ IN BOOLEAN Notify
+ )
+{
+ VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
+ UINT32 BufferNr = BufferNext (Ring);
+ UINT16 Idx = *Ring->Ring.Avail.Idx;
+ UINT16 Flags = 0;
+
+ ASSERT (DataSize <= Ring->BufferSize);
+
+ if (Data) {
+ /* driver -> device */
+ CopyMem (BufferPtr (Ring, BufferNr), Data, DataSize);
+ } else {
+ /* device -> driver */
+ Flags |= VRING_DESC_F_WRITE;
+ }
+
+ VirtioAppendDesc (
+ &Ring->Ring,
+ BufferAddr (Ring, BufferNr),
+ DataSize,
+ Flags,
+ &Ring->Indices
+ );
+
+ Ring->Ring.Avail.Ring[Idx % Ring->Ring.QueueSize] =
+ Ring->Indices.HeadDescIdx % Ring->Ring.QueueSize;
+ Ring->Indices.HeadDescIdx = Ring->Indices.NextDescIdx;
+ Idx++;
+
+ // Force compiler to not optimize this code
+ MemoryFence ();
+ *Ring->Ring.Avail.Idx = Idx;
+ MemoryFence ();
+
+ if (Notify) {
+ Dev->VirtIo->SetQueueNotify (Dev->VirtIo, Index);
+ }
+
+ return EFI_SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+// Look for buffer ready to be processed
+BOOLEAN
+EFIAPI
+VirtioKeyboardRingHasBuffer (
+ IN OUT VIRTIO_KBD_DEV *Dev,
+ IN UINT16 Index
+ )
+{
+ VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
+ UINT16 UsedIdx = *Ring->Ring.Used.Idx;
+
+ if (!Ring->Ready) {
+ return FALSE;
+ }
+
+ if (Ring->LastUsedIdx == UsedIdx) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------------
+// Get data from buffer which is marked as ready from device
+BOOLEAN
+EFIAPI
+VirtioKeyboardRingGetBuffer (
+ IN OUT VIRTIO_KBD_DEV *Dev,
+ IN UINT16 Index,
+ OUT VOID *Data,
+ OUT UINT32 *DataSize
+ )
+{
+ VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
+ UINT16 UsedIdx = *Ring->Ring.Used.Idx;
+ volatile VRING_USED_ELEM *UsedElem;
+
+ if (!Ring->Ready) {
+ return FALSE;
+ }
+
+ if (Ring->LastUsedIdx == UsedIdx) {
+ return FALSE;
+ }
+
+ UsedElem = Ring->Ring.Used.UsedElem + (Ring->LastUsedIdx % Ring->Ring.QueueSize);
+
+ if (UsedElem->Len > Ring->BufferSize) {
+ DEBUG ((DEBUG_ERROR, "%a:%d: %d: invalid length\n", __func__, __LINE__, Index));
+ UsedElem->Len = 0;
+ }
+
+ if (Data && DataSize) {
+ CopyMem (Data, BufferPtr (Ring, UsedElem->Id), UsedElem->Len);
+ *DataSize = UsedElem->Len;
+ }
+
+ if (Index % 2 == 0) {
+ /* RX - re-queue buffer */
+ VirtioKeyboardRingSendBuffer (Dev, Index, NULL, Ring->BufferSize, FALSE);
+ }
+
+ Ring->LastUsedIdx++;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------------
+// Initialize ring buffer
+EFI_STATUS
+EFIAPI
+VirtioKeyboardInitRing (
+ IN OUT VIRTIO_KBD_DEV *Dev,
+ IN UINT16 Index,
+ IN UINT32 BufferSize
+ )
+{
+ VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
+ EFI_STATUS Status;
+ UINT16 QueueSize;
+ UINT64 RingBaseShift;
+
+ //
+ // step 4b -- allocate request virtqueue
+ //
+ Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, Index);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ //
+ // VirtioKeyboard uses one descriptor
+ //
+ if (QueueSize < 1) {
+ Status = EFI_UNSUPPORTED;
+ goto Failed;
+ }
+
+ Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Ring->Ring);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ //
+ // If anything fails from here on, we must release the ring resources.
+ //
+ Status = VirtioRingMap (
+ Dev->VirtIo,
+ &Ring->Ring,
+ &RingBaseShift,
+ &Ring->RingMap
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReleaseQueue;
+ }
+
+ //
+ // Additional steps for MMIO: align the queue appropriately, and set the
+ // size. If anything fails from here on, we must unmap the ring resources.
+ //
+ Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
+ if (EFI_ERROR (Status)) {
+ goto UnmapQueue;
+ }
+
+ Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
+ if (EFI_ERROR (Status)) {
+ goto UnmapQueue;
+ }
+
+ //
+ // step 4c -- Report GPFN (guest-physical frame number) of queue.
+ //
+ Status = Dev->VirtIo->SetQueueAddress (
+ Dev->VirtIo,
+ &Ring->Ring,
+ RingBaseShift
+ );
+ if (EFI_ERROR (Status)) {
+ goto UnmapQueue;
+ }
+
+ Ring->BufferCount = QueueSize;
+ Ring->BufferSize = BufferSize;
+ Ring->BufferPages = EFI_SIZE_TO_PAGES (Ring->BufferCount * Ring->BufferSize);
+
+ Status = Dev->VirtIo->AllocateSharedPages (Dev->VirtIo, Ring->BufferPages, (VOID **)&Ring->Buffers);
+ if (EFI_ERROR (Status)) {
+ goto UnmapQueue;
+ }
+
+ Status = VirtioMapAllBytesInSharedBuffer (
+ Dev->VirtIo,
+ VirtioOperationBusMasterCommonBuffer,
+ Ring->Buffers,
+ EFI_PAGES_TO_SIZE (Ring->BufferPages),
+ &Ring->DeviceAddress,
+ &Ring->BufferMap
+ );
+ if (EFI_ERROR (Status)) {
+ goto ReleasePages;
+ }
+
+ VirtioPrepare (&Ring->Ring, &Ring->Indices);
+ Ring->Ready = TRUE;
+
+ return EFI_SUCCESS;
+
+ReleasePages:
+ Dev->VirtIo->FreeSharedPages (
+ Dev->VirtIo,
+ Ring->BufferPages,
+ Ring->Buffers
+ );
+ Ring->Buffers = NULL;
+
+UnmapQueue:
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Ring->RingMap);
+ Ring->RingMap = NULL;
+
+ReleaseQueue:
+ VirtioRingUninit (Dev->VirtIo, &Ring->Ring);
+
+Failed:
+ return Status;
+}
+
+// -----------------------------------------------------------------------------
+// Deinitialize ring buffer
+VOID
+EFIAPI
+VirtioKeyboardUninitRing (
+ IN OUT VIRTIO_KBD_DEV *Dev,
+ IN UINT16 Index
+ )
+{
+ VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
+
+ if (Ring->BufferMap) {
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Ring->BufferMap);
+ Ring->BufferMap = NULL;
+ }
+
+ if (Ring->Buffers) {
+ Dev->VirtIo->FreeSharedPages (
+ Dev->VirtIo,
+ Ring->BufferPages,
+ Ring->Buffers
+ );
+ Ring->Buffers = NULL;
+ }
+
+ if (!Ring->RingMap) {
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Ring->RingMap);
+ Ring->RingMap = NULL;
+ }
+
+ if (Ring->Ring.Base) {
+ VirtioRingUninit (Dev->VirtIo, &Ring->Ring);
+ }
+
+ ZeroMem (Ring, sizeof (*Ring));
+}
+
+// -----------------------------------------------------------------------------
+// Deinitialize all rings allocated in driver
+STATIC
+VOID
+EFIAPI
+VirtioKeyboardUninitAllRings (
+ IN OUT VIRTIO_KBD_DEV *Dev
+ )
+{
+ UINT16 Index;
+
+ for (Index = 0; Index < KEYBOARD_MAX_RINGS; Index++) {
+ VirtioKeyboardUninitRing (Dev, Index);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Mark all buffers as ready to write and push to device
+VOID
+EFIAPI
+VirtioKeyboardRingFillRx (
+ IN OUT VIRTIO_KBD_DEV *Dev,
+ IN UINT16 Index
+ )
+{
+ VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
+ UINT32 BufferNr;
+
+ for (BufferNr = 0; BufferNr < Ring->BufferCount; BufferNr++) {
+ VirtioKeyboardRingSendBuffer (Dev, Index, NULL, Ring->BufferSize, FALSE);
+ }
+
+ Dev->VirtIo->SetQueueNotify (Dev->VirtIo, Index);
+}
+
+// Forward declaration of module Uninit function
+STATIC
+VOID
+EFIAPI
+VirtioKeyboardUninit (
+ IN OUT VIRTIO_KBD_DEV *Dev
+ );
+
+// Forward declaration of module Init function
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioKeyboardInit (
+ IN OUT VIRTIO_KBD_DEV *Dev
+ );
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardSimpleTextInputReset (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ VIRTIO_KBD_DEV *Dev;
+
+ Dev = VIRTIO_KEYBOARD_FROM_THIS (This);
+ VirtioKeyboardUninit (Dev);
+ VirtioKeyboardInit (Dev);
+
+ return EFI_SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardSimpleTextInputReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ VIRTIO_KBD_DEV *Dev;
+ EFI_TPL OldTpl;
+
+ if (Key == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = VIRTIO_KEYBOARD_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ if (Dev->KeyReady) {
+ // Get last key from the buffer
+ *Key = Dev->LastKey;
+
+ // Mark key as consumed
+ Dev->KeyReady = FALSE;
+
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_NOT_READY;
+}
+
+// -----------------------------------------------------------------------------
+// Function converting VirtIO key codes to UEFI key codes
+STATIC
+VOID
+EFIAPI
+VirtioKeyboardConvertKeyCode (
+ IN OUT VIRTIO_KBD_DEV *Dev,
+ IN UINT16 Code,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ // Key mapping in between Linux and UEFI
+ // https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
+ // https://dox.ipxe.org/SimpleTextIn_8h_source.html#l00048
+ // https://uefi.org/specs/UEFI/2.10/Apx_B_Console.html
+
+ static const UINT16 Map[] = {
+ [KEY_1] = '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
+ [KEY_MINUS] = '-', '=',
+ [KEY_Q] = 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',
+ [KEY_LEFTBRACE] = '[', ']',
+ [KEY_A] = 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l',
+ [KEY_SEMICOLON] = ';', '\'', '`',
+ [KEY_BACKSLASH] = '\\',
+ [KEY_Z] = 'z', 'x', 'c', 'v', 'b', 'n', 'm',
+ [KEY_COMMA] = ',', '.', '/',
+ [KEY_SPACE] = ' ',
+ [MAX_KEYBOARD_CODE] = 0x00
+ };
+
+ static const UINT16 MapShift[] = {
+ [KEY_1] = '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+ [KEY_MINUS] = '_', '+',
+ [KEY_Q] = 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P',
+ [KEY_LEFTBRACE] = '{', '}',
+ [KEY_A] = 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L',
+ [KEY_SEMICOLON] = ':', '\"', '~',
+ [KEY_BACKSLASH] = '|',
+ [KEY_Z] = 'Z', 'X', 'C', 'V', 'B', 'N', 'M',
+ [KEY_COMMA] = '<', '>', '?',
+ [KEY_SPACE] = ' ',
+ [MAX_KEYBOARD_CODE] = 0x00
+ };
+
+ // Set default readings
+ Key->ScanCode = SCAN_NULL;
+ Key->UnicodeChar = CHAR_NULL;
+
+ // Check if key code is not out of the keyboard mapping boundaries
+ if (Code >= MAX_KEYBOARD_CODE) {
+ DEBUG ((DEBUG_INFO, "%a: Key code out of range \n", __func__));
+ return;
+ }
+
+ // Handle F1 - F10 keys
+ if ((Code >= KEY_F1) && (Code <= KEY_F10)) {
+ Key->ScanCode = SCAN_F1 + (Code - KEY_F1);
+ return;
+ }
+
+ switch (Code) {
+ case KEY_PAGEUP:
+ Key->ScanCode = SCAN_PAGE_UP;
+ break;
+
+ case KEY_PAGEDOWN:
+ Key->ScanCode = SCAN_PAGE_DOWN;
+ break;
+
+ case KEY_HOME:
+ Key->ScanCode = SCAN_HOME;
+ break;
+
+ case KEY_END:
+ Key->ScanCode = SCAN_END;
+ break;
+
+ case KEY_DELETE:
+ Key->ScanCode = SCAN_DELETE;
+ break;
+
+ case KEY_INSERT:
+ Key->ScanCode = SCAN_INSERT;
+ break;
+
+ case KEY_UP:
+ Key->ScanCode = SCAN_UP;
+ break;
+
+ case KEY_LEFT:
+ Key->ScanCode = SCAN_LEFT;
+ break;
+
+ case KEY_RIGHT:
+ Key->ScanCode = SCAN_RIGHT;
+ break;
+
+ case KEY_DOWN:
+ Key->ScanCode = SCAN_DOWN;
+ break;
+
+ case KEY_BACKSPACE:
+ Key->UnicodeChar = CHAR_BACKSPACE;
+ break;
+
+ case KEY_TAB:
+ Key->UnicodeChar = CHAR_TAB;
+ break;
+
+ case KEY_ENTER:
+ // Key->UnicodeChar = CHAR_LINEFEED;
+ Key->UnicodeChar = CHAR_CARRIAGE_RETURN;
+ break;
+
+ case KEY_ESC:
+ Key->ScanCode = SCAN_ESC;
+ break;
+
+ default:
+ if (Dev->KeyActive[KEY_LEFTSHIFT] || Dev->KeyActive[KEY_RIGHTSHIFT]) {
+ Key->ScanCode = MapShift[Code];
+ Key->UnicodeChar = MapShift[Code];
+ } else {
+ Key->ScanCode = Map[Code];
+ Key->UnicodeChar = Map[Code];
+ }
+
+ if (Dev->KeyActive[KEY_LEFTCTRL] || Dev->KeyActive[KEY_RIGHTCTRL]) {
+ // Convert Ctrl+[a-z] and Ctrl+[A-Z] into [1-26] ASCII table entries
+ Key->UnicodeChar &= 0x1F;
+ }
+
+ break;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Main function processing virtio keyboard events
+STATIC
+VOID
+EFIAPI
+VirtioKeyboardGetDeviceData (
+ IN OUT VIRTIO_KBD_DEV *Dev
+ )
+{
+ BOOLEAN HasData;
+ UINT8 Data[KEYBOARD_RX_BUFSIZE + 1];
+ UINT32 DataSize;
+ VIRTIO_KBD_EVENT Event;
+ EFI_TPL OldTpl;
+
+ for ( ; ; ) {
+ HasData = VirtioKeyboardRingGetBuffer (Dev, 0, Data, &DataSize);
+
+ // Exit if no new data
+ if (!HasData) {
+ return;
+ }
+
+ if (DataSize < sizeof (Event)) {
+ continue;
+ }
+
+ // Clearing last character is not needed as it will be overwritten anyway
+ // Dev->LastKey.ScanCode = SCAN_NULL;
+ // Dev->LastKey.UnicodeChar = CHAR_NULL;
+
+ CopyMem (&Event, Data, sizeof (Event));
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ switch (Event.Type) {
+ case EV_SYN:
+ // Sync event received
+ break;
+
+ case EV_KEY:
+ // Key press event received
+ // DEBUG ((DEBUG_INFO, "%a: ---------------------- \nType: %x Code: %x Value: %x\n",
+ // __func__, Event.Type, Event.Code, Event.Value));
+
+ if (Event.Value == KEY_PRESSED) {
+ // Key pressed event received
+ Dev->KeyActive[(UINT8)Event.Code] = TRUE;
+
+ // Evaluate key
+ VirtioKeyboardConvertKeyCode (Dev, Event.Code, &Dev->LastKey);
+
+ // Flag that printable character is ready to be send
+ Dev->KeyReady = TRUE;
+ } else {
+ // Key released event received
+ Dev->KeyActive[(UINT8)Event.Code] = FALSE;
+ }
+
+ break;
+
+ default:
+ DEBUG ((DEBUG_INFO, "%a: Unhandled VirtIo event\n", __func__));
+ break;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Callback hook for timer interrupt
+STATIC
+VOID
+EFIAPI
+VirtioKeyboardTimer (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ VIRTIO_KBD_DEV *Dev = Context;
+
+ VirtioKeyboardGetDeviceData (Dev);
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_PROTOCOL API
+VOID
+EFIAPI
+VirtioKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ VIRTIO_KBD_DEV *Dev = VIRTIO_KEYBOARD_FROM_THIS (Context);
+
+ //
+ // Stall 1ms to give a chance to let other driver interrupt this routine
+ // for their timer event.
+ // e.g. UI setup or Shell, other drivers which are driven by timer event
+ // will have a bad performance during this period,
+ // e.g. usb keyboard driver.
+ // Add a stall period can greatly increate other driver performance during
+ // the WaitForKey is recursivly invoked. 1ms delay will make little impact
+ // to the thunk keyboard driver, and user can not feel the delay at all when
+ // input.
+ gBS->Stall (1000);
+
+ // Use TimerEvent callback function to check whether there's any key pressed
+ VirtioKeyboardTimer (NULL, Dev);
+
+ // If there is a new key ready - send signal
+ if (Dev->KeyReady) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ VIRTIO_KBD_DEV *Dev;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (This);
+
+ // Call the reset function from SIMPLE_TEXT_INPUT protocol
+ Status = Dev->Txt.Reset (
+ &Dev->Txt,
+ ExtendedVerification
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ VIRTIO_KBD_DEV *Dev;
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ EFI_KEY_STATE KeyState;
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (This);
+
+ // Get the last pressed key
+ Status = Dev->Txt.ReadKeyStroke (&Dev->Txt, &Key);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Add key state informations
+ KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
+ KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
+
+ // Shift key modifier
+ if (Dev->KeyActive[KEY_LEFTSHIFT]) {
+ KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
+ }
+
+ if (Dev->KeyActive[KEY_RIGHTSHIFT]) {
+ KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
+ }
+
+ // Ctrl key modifier
+ if (Dev->KeyActive[KEY_LEFTCTRL]) {
+ KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
+ }
+
+ if (Dev->KeyActive[KEY_RIGHTCTRL]) {
+ KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
+ }
+
+ // ALt key modifier
+ if (Dev->KeyActive[KEY_LEFTALT]) {
+ KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
+ }
+
+ if (Dev->KeyActive[KEY_RIGHTALT]) {
+ KeyState.KeyShiftState |= EFI_RIGHT_ALT_PRESSED;
+ }
+
+ // Return value only when there is no failure
+ KeyData->Key = Key;
+ KeyData->KeyState = KeyState;
+
+ return EFI_SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+VOID
+EFIAPI
+VirtioKeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ VIRTIO_KBD_DEV *Dev;
+
+ Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (Context);
+ VirtioKeyboardWaitForKey (Event, &Dev->Txt);
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ if (KeyToggleState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ )
+
+{
+ ASSERT (RegsiteredData != NULL && InputData != NULL);
+
+ if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
+ (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar))
+ {
+ return FALSE;
+ }
+
+ //
+ // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means
+ // these state could be ignored.
+ //
+ if ((RegsiteredData->KeyState.KeyShiftState != 0) &&
+ (RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState))
+ {
+ return FALSE;
+ }
+
+ if ((RegsiteredData->KeyState.KeyToggleState != 0) &&
+ (RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ )
+{
+ EFI_STATUS Status;
+ VIRTIO_KBD_DEV *Dev;
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Link;
+ VIRTIO_KBD_IN_EX_NOTIFY *NewNotify;
+ VIRTIO_KBD_IN_EX_NOTIFY *CurrentNotify;
+
+ if ((KeyData == NULL) ||
+ (NotifyHandle == NULL) ||
+ (KeyNotificationFunction == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ // Check if the (KeyData, NotificationFunction) pair is already registered.
+ for (Link = Dev->NotifyList.ForwardLink;
+ Link != &Dev->NotifyList;
+ Link = Link->ForwardLink)
+ {
+ CurrentNotify = CR (
+ Link,
+ VIRTIO_KBD_IN_EX_NOTIFY,
+ NotifyEntry,
+ VIRTIO_KBD_SIG
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+ *NotifyHandle = CurrentNotify;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+ }
+
+ NewNotify = (VIRTIO_KBD_IN_EX_NOTIFY *)AllocateZeroPool (sizeof (VIRTIO_KBD_IN_EX_NOTIFY));
+ if (NewNotify == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ NewNotify->Signature = VIRTIO_KBD_SIG;
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+ InsertTailList (&Dev->NotifyList, &NewNotify->NotifyEntry);
+
+ *NotifyHandle = NewNotify;
+ Status = EFI_SUCCESS;
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ )
+{
+ EFI_STATUS Status;
+ VIRTIO_KBD_DEV *Dev;
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Link;
+ VIRTIO_KBD_IN_EX_NOTIFY *CurrentNotify;
+
+ if (NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((VIRTIO_KBD_IN_EX_NOTIFY *)NotificationHandle)->Signature != VIRTIO_KBD_SIG) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ for (Link = Dev->NotifyList.ForwardLink;
+ Link != &Dev->NotifyList;
+ Link = Link->ForwardLink)
+ {
+ CurrentNotify = CR (
+ Link,
+ VIRTIO_KBD_IN_EX_NOTIFY,
+ NotifyEntry,
+ VIRTIO_KBD_SIG
+ );
+ if (CurrentNotify == NotificationHandle) {
+ RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ // Notification has not been found
+ Status = EFI_INVALID_PARAMETER;
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+// -----------------------------------------------------------------------------
+// Driver init
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioKeyboardInit (
+ IN OUT VIRTIO_KBD_DEV *Dev
+ )
+{
+ UINT8 NextDevStat;
+ EFI_STATUS Status;
+ UINT64 Features;
+
+ //
+ // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
+ //
+ NextDevStat = 0; // step 1 -- reset device
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ //
+ // Set Page Size - MMIO VirtIo Specific
+ //
+ Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ //
+ // step 4a -- retrieve and validate features
+ //
+ Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ Features &= VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM;
+
+ //
+ // In virtio-1.0, feature negotiation is expected to complete before queue
+ // discovery, and the device can also reject the selected set of features.
+ //
+ if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
+ Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+ }
+
+ Status = VirtioKeyboardInitRing (Dev, 0, KEYBOARD_RX_BUFSIZE);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ //
+ // step 5 -- Report understood features and guest-tuneables.
+ //
+ if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
+ Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
+ Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+ }
+
+ //
+ // step 6 -- initialization complete
+ //
+ NextDevStat |= VSTAT_DRIVER_OK;
+ Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ //
+ // populate the exported interface's attributes
+ //
+
+ // struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
+ // EFI_INPUT_RESET Reset;
+ // EFI_INPUT_READ_KEY ReadKeyStroke;
+ // EFI_EVENT WaitForKey;
+ // };
+ Dev->Txt.Reset = (EFI_INPUT_RESET)VirtioKeyboardSimpleTextInputReset;
+ Dev->Txt.ReadKeyStroke = VirtioKeyboardSimpleTextInputReadKeyStroke;
+ Dev->Txt.WaitForKey = (EFI_EVENT)VirtioKeyboardWaitForKey;
+
+ // struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL {
+ // EFI_INPUT_RESET_EX Reset;
+ // EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx;
+ // EFI_EVENT WaitForKeyEx;
+ // EFI_SET_STATE SetState;
+ // EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify;
+ // EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify;
+ // }
+ Dev->TxtEx.Reset = (EFI_INPUT_RESET_EX)VirtioKeyboardResetEx;
+ Dev->TxtEx.ReadKeyStrokeEx = VirtioKeyboardReadKeyStrokeEx;
+ Dev->TxtEx.SetState = VirtioKeyboardSetState;
+ Dev->TxtEx.RegisterKeyNotify = VirtioKeyboardRegisterKeyNotify;
+ Dev->TxtEx.UnregisterKeyNotify = VirtioKeyboardUnregisterKeyNotify;
+ InitializeListHead (&Dev->NotifyList);
+
+ //
+ // Setup the WaitForKey event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ VirtioKeyboardWaitForKey,
+ &(Dev->Txt),
+ &((Dev->Txt).WaitForKey)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ //
+ // Setup the WaitForKeyEx event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ VirtioKeyboardWaitForKeyEx,
+ &(Dev->TxtEx),
+ &((Dev->TxtEx).WaitForKeyEx)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ VirtioKeyboardRingFillRx (Dev, 0);
+
+ //
+ // Event for reading key in time intervals
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VirtioKeyboardTimer,
+ Dev,
+ &Dev->KeyReadTimer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ Status = gBS->SetTimer (
+ Dev->KeyReadTimer,
+ TimerPeriodic,
+ EFI_TIMER_PERIOD_MILLISECONDS (KEYBOARD_PROBE_TIME_MS)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+
+ return EFI_SUCCESS;
+
+Failed:
+ VirtioKeyboardUninitAllRings (Dev);
+ // VirtualKeyboardFreeNotifyList (&VirtualKeyboardPrivate->NotifyList);
+
+ //
+ // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
+ // Status. VirtIo access failure here should not mask the original error.
+ //
+ NextDevStat |= VSTAT_FAILED;
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
+
+ return Status; // reached only via Failed above
+}
+
+// -----------------------------------------------------------------------------
+// Deinitialize driver
+STATIC
+VOID
+EFIAPI
+VirtioKeyboardUninit (
+ IN OUT VIRTIO_KBD_DEV *Dev
+ )
+{
+ gBS->CloseEvent (Dev->KeyReadTimer);
+ //
+ // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
+ // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
+ // the old comms area.
+ //
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
+
+ VirtioKeyboardUninitAllRings (Dev);
+}
+
+// -----------------------------------------------------------------------------
+// Handle device exit before switch to boot
+STATIC
+VOID
+EFIAPI
+VirtioKeyboardExitBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ VIRTIO_KBD_DEV *Dev;
+
+ DEBUG ((DEBUG_INFO, "%a: Context=0x%p\n", __func__, Context));
+ //
+ // Reset the device. This causes the hypervisor to forget about the virtio
+ // ring.
+ //
+ // We allocated said ring in EfiBootServicesData type memory, and code
+ // executing after ExitBootServices() is permitted to overwrite it.
+ //
+ Dev = Context;
+ Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
+}
+
+// -----------------------------------------------------------------------------
+// Binding validation function
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioKeyboardBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ VIRTIO_DEVICE_PROTOCOL *VirtIo;
+
+ //
+ // Attempt to open the device with the VirtIo set of interfaces. On success,
+ // the protocol is "instantiated" for the VirtIo device. Covers duplicate
+ // open attempts (EFI_ALREADY_STARTED).
+ //
+ Status = gBS->OpenProtocol (
+ DeviceHandle, // candidate device
+ &gVirtioDeviceProtocolGuid, // for generic VirtIo access
+ (VOID **)&VirtIo, // handle to instantiate
+ This->DriverBindingHandle, // requestor driver identity
+ DeviceHandle, // ControllerHandle, according to
+ // the UEFI Driver Model
+ EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
+ // the device; to be released
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_UNSUPPORTED) {
+ DEBUG ((DEBUG_INFO, "%a:%d: %r\n", __func__, __LINE__, Status));
+ }
+
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "%a:%d: 0x%x\n", __func__, __LINE__, VirtIo->SubSystemDeviceId));
+ if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_INPUT) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ //
+ // We needed VirtIo access only transitorily, to see whether we support the
+ // device or not.
+ //
+ gBS->CloseProtocol (
+ DeviceHandle,
+ &gVirtioDeviceProtocolGuid,
+ This->DriverBindingHandle,
+ DeviceHandle
+ );
+ return Status;
+}
+
+// -----------------------------------------------------------------------------
+// Driver binding function API
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioKeyboardBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ VIRTIO_KBD_DEV *Dev;
+ EFI_STATUS Status;
+
+ Dev = (VIRTIO_KBD_DEV *)AllocateZeroPool (sizeof *Dev);
+ if (Dev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gVirtioDeviceProtocolGuid,
+ (VOID **)&Dev->VirtIo,
+ This->DriverBindingHandle,
+ DeviceHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeVirtioKbd;
+ }
+
+ //
+ // VirtIo access granted, configure virtio keyboard device.
+ //
+ Status = VirtioKeyboardInit (Dev);
+ if (EFI_ERROR (Status)) {
+ goto CloseVirtIo;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_CALLBACK,
+ &VirtioKeyboardExitBoot,
+ Dev,
+ &Dev->ExitBoot
+ );
+ if (EFI_ERROR (Status)) {
+ goto UninitDev;
+ }
+
+ //
+ // Setup complete, attempt to export the driver instance's EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ // interface.
+ //
+ Dev->Signature = VIRTIO_KBD_SIG;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DeviceHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ &Dev->Txt,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &Dev->TxtEx,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto CloseExitBoot;
+ }
+
+ return EFI_SUCCESS;
+
+CloseExitBoot:
+ gBS->CloseEvent (Dev->ExitBoot);
+
+UninitDev:
+ VirtioKeyboardUninit (Dev);
+
+CloseVirtIo:
+ gBS->CloseProtocol (
+ DeviceHandle,
+ &gVirtioDeviceProtocolGuid,
+ This->DriverBindingHandle,
+ DeviceHandle
+ );
+
+FreeVirtioKbd:
+ FreePool (Dev);
+
+ return Status;
+}
+
+// -----------------------------------------------------------------------------
+// Driver unbinding function API
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioKeyboardBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Txt;
+ VIRTIO_KBD_DEV *Dev;
+
+ Status = gBS->OpenProtocol (
+ DeviceHandle, // candidate device
+ &gEfiSimpleTextInProtocolGuid, // retrieve the RNG iface
+ (VOID **)&Txt, // target pointer
+ This->DriverBindingHandle, // requestor driver ident.
+ DeviceHandle, // lookup req. for dev.
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no new ref.
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Dev = VIRTIO_KEYBOARD_FROM_THIS (Txt);
+
+ //
+ // Handle Stop() requests for in-use driver instances gracefully.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ &DeviceHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ &Dev->Txt,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &Dev->TxtEx,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseEvent (Dev->ExitBoot);
+
+ VirtioKeyboardUninit (Dev);
+
+ gBS->CloseProtocol (
+ DeviceHandle,
+ &gVirtioDeviceProtocolGuid,
+ This->DriverBindingHandle,
+ DeviceHandle
+ );
+
+ FreePool (Dev);
+
+ return EFI_SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+// Forward declaration of global variable
+STATIC
+EFI_COMPONENT_NAME_PROTOCOL gComponentName;
+
+// -----------------------------------------------------------------------------
+// Driver name to be displayed
+STATIC
+EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
+ { "eng;en", L"Virtio Keyboard Driver" },
+ { NULL, NULL }
+};
+
+// -----------------------------------------------------------------------------
+// Driver name lookup function
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioKeyboardGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gComponentName) // Iso639Language
+ );
+}
+
+// -----------------------------------------------------------------------------
+// Device name to be displayed
+STATIC
+EFI_UNICODE_STRING_TABLE mDeviceNameTable[] = {
+ { "eng;en", L"RHEL virtio virtual keyboard BOB (Basic Operation Board)" },
+ { NULL, NULL }
+};
+
+// -----------------------------------------------------------------------------
+STATIC
+EFI_COMPONENT_NAME_PROTOCOL gDeviceName;
+
+// -----------------------------------------------------------------------------
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioKeyboardGetDeviceName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN EFI_HANDLE ChildHandle,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDeviceNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gDeviceName) // Iso639Language
+ );
+}
+
+// -----------------------------------------------------------------------------
+// General driver UEFI interface for showing driver name
+STATIC
+EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
+ &VirtioKeyboardGetDriverName,
+ &VirtioKeyboardGetDeviceName,
+ "eng" // SupportedLanguages, ISO 639-2 language codes
+};
+
+// -----------------------------------------------------------------------------
+// General driver UEFI interface for showing driver name
+STATIC
+EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&VirtioKeyboardGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&VirtioKeyboardGetDeviceName,
+ "en" // SupportedLanguages, RFC 4646 language codes
+};
+
+// -----------------------------------------------------------------------------
+// General driver UEFI interface for loading / unloading driver
+STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
+ &VirtioKeyboardBindingSupported,
+ &VirtioKeyboardBindingStart,
+ &VirtioKeyboardBindingStop,
+ 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
+ NULL, // ImageHandle, to be overwritten by
+ // EfiLibInstallDriverBindingComponentName2() in VirtioKeyboardEntryPoint()
+ NULL // DriverBindingHandle, ditto
+};
+
+// -----------------------------------------------------------------------------
+// Driver entry point set in INF file, registers all driver functions into UEFI
+EFI_STATUS
+EFIAPI
+VirtioKeyboardEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ DEBUG ((DEBUG_INFO, "Virtio keyboard has been loaded.......................\n"));
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gDriverBinding,
+ ImageHandle,
+ &gComponentName,
+ &gComponentName2
+ );
+}
diff --git a/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.h b/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.h new file mode 100644 index 0000000000..d4cbde97fd --- /dev/null +++ b/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.h @@ -0,0 +1,209 @@ +/** @file
+
+ Private definitions of the VirtioKeyboard driver
+
+ Copyright (C) 2024, Red Hat
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VIRTIO_KEYBOARD_DXE_H_
+#define _VIRTIO_KEYBOARD_DXE_H_
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+
+#include <IndustryStandard/Virtio.h>
+
+#define VIRTIO_KBD_SIG SIGNATURE_32 ('V', 'K', 'B', 'D')
+
+#define KEYBOARD_MAX_RINGS 2
+#define KEYBOARD_RX_BUFSIZE 64
+
+// Fetch new key from VirtIO every 50ms
+#define KEYBOARD_PROBE_TIME_MS 50
+
+// Max range of recognized keyboard codes
+#define MAX_KEYBOARD_CODE 255
+
+typedef struct {
+ UINTN Signature;
+ EFI_KEY_DATA KeyData;
+ EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn;
+ LIST_ENTRY NotifyEntry;
+} VIRTIO_KBD_IN_EX_NOTIFY;
+
+// Data structure representing payload delivered from VirtIo
+typedef struct {
+ UINT16 Type;
+ UINT16 Code;
+ UINT32 Value;
+} VIRTIO_KBD_EVENT;
+
+// Data structure representing ring buffer
+typedef struct {
+ VRING Ring;
+ VOID *RingMap;
+ DESC_INDICES Indices; /* Avail Ring */
+ UINT16 LastUsedIdx; /* Used Ring */
+
+ UINT32 BufferSize;
+ UINT32 BufferCount;
+ UINT32 BufferPages;
+ UINT8 *Buffers;
+ VOID *BufferMap;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+
+ BOOLEAN Ready;
+} VIRTIO_KBD_RING;
+
+// Declaration of data structure representing driver context
+typedef struct {
+ // Device signature
+ UINT32 Signature;
+
+ // Hook for the function which shall be caled when driver is closed
+ // before system state changes to boot
+ EFI_EVENT ExitBoot;
+
+ // Hooks for functions required by UEFI keyboard API
+ // struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
+ // EFI_INPUT_RESET Reset;
+ // EFI_INPUT_READ_KEY ReadKeyStroke;
+ // EFI_EVENT WaitForKey;
+ // };
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL Txt;
+
+ // struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL {
+ // EFI_INPUT_RESET_EX Reset;
+ // EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx;
+ // EFI_EVENT WaitForKeyEx;
+ // EFI_SET_STATE SetState;
+ // EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify;
+ // EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify;
+ // }
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL TxtEx;
+
+ // Virtio device hook
+ VIRTIO_DEVICE_PROTOCOL *VirtIo;
+
+ // Hook for ring buffer
+ VIRTIO_KBD_RING Rings[KEYBOARD_MAX_RINGS];
+
+ // Timer event for checking key presses from VirtIo
+ EFI_EVENT KeyReadTimer;
+
+ // List for notifications
+ LIST_ENTRY NotifyList;
+ EFI_EVENT KeyNotifyTimer;
+
+ // Last pressed key
+ // typedef struct {
+ // UINT16 ScanCode;
+ // CHAR16 UnicodeChar;
+ // } EFI_INPUT_KEY;
+ EFI_INPUT_KEY LastKey;
+
+ // Key modifiers
+ BOOLEAN KeyActive[MAX_KEYBOARD_CODE];
+
+ // If key is ready
+ BOOLEAN KeyReady;
+} VIRTIO_KBD_DEV;
+
+// Helper functions to extract VIRTIO_KBD_DEV structure pointers
+#define VIRTIO_KEYBOARD_FROM_THIS(KbrPointer) \
+ CR (KbrPointer, VIRTIO_KBD_DEV, Txt, VIRTIO_KBD_SIG)
+#define VIRTIO_KEYBOARD_EX_FROM_THIS(KbrPointer) \
+ CR (KbrPointer, VIRTIO_KBD_DEV, TxtEx, VIRTIO_KBD_SIG)
+
+// Bellow candidates to be included as Linux header
+#define KEY_PRESSED 1
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardSimpleTextInputReset (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardSimpleTextInputReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_PROTOCOL API
+VOID
+EFIAPI
+VirtioKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ );
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+VOID
+EFIAPI
+VirtioKeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ );
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ );
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
+EFI_STATUS
+EFIAPI
+VirtioKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ );
+
+#endif
diff --git a/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.inf b/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.inf new file mode 100644 index 0000000000..6c35f2a4ce --- /dev/null +++ b/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.inf @@ -0,0 +1,41 @@ +## @file
+# This driver produces EFI_SIMPLE_TEXT_INPUT_PROTOCOL for virt ARM devices.
+#
+# Copyright (C) 2024, Red Hat
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 1.29
+ BASE_NAME = VirtioKeyboardDxe
+ FILE_GUID = F141B1E5-9C7C-44CC-AFAA-E87D7689B113
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = VirtioKeyboardEntryPoint
+
+[Sources]
+ VirtioKeyboard.c
+ VirtioKeyboard.h
+ VirtioKeyCodes.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ VirtioLib
+
+# Protocols used by this driver
+[Protocols]
+ #gEfiDriverBindingProtocolGuid
+ gEfiSimpleTextInProtocolGuid
+ gEfiSimpleTextInputExProtocolGuid
+ gVirtioDeviceProtocolGuid
|