diff options
| author | Jiaqing Zhao <Zhao.Jiaqing@amd.com> | 2026-06-25 16:16:39 +0800 |
|---|---|---|
| committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2026-07-20 12:43:36 +0000 |
| commit | efdbf3c355c9e329bf57fec75744b68f12c1ee81 (patch) | |
| tree | e272d3f1ef0492a9459759d5f7ebb36018a19d26 /OvmfPkg | |
| parent | fd63e805088df7655f038a03a28f861379f02376 (diff) | |
| download | edk2-efdbf3c355c9e329bf57fec75744b68f12c1ee81.tar.gz edk2-efdbf3c355c9e329bf57fec75744b68f12c1ee81.zip | |
OvmfPkg/VirtioInputDxe: Add virtio mouse support
Virtio mouse devices report relative movements (EV_REL) and button
inputs. Add VirtioMouse.c implementing mouse capability probing,
EFI_SIMPLE_POINTER_PROTOCOL implementation and event handler that
converts VIRTIO_INPUT_EVENT into EFI_SIMPLE_POINTER_STATE.
The shared event dispatcher in VirtioInput.c now routes EV_REL events
and EV_KEY codes above MAX_KEYBOARD_CODE to the mouse handler, while
keycodes in [0, MAX_KEYBOARD_CODE] still go to the keyboard. A device
is now accepted when it provides a keyboard or a mouse, and the
EFI_SIMPLE_POINTER_PROTOCOL is installed on mouse-capable devices.
Signed-off-by: Jiaqing Zhao <Zhao.Jiaqing@amd.com>
Diffstat (limited to 'OvmfPkg')
| -rw-r--r-- | OvmfPkg/VirtioInputDxe/VirtioInput.c | 89 | ||||
| -rw-r--r-- | OvmfPkg/VirtioInputDxe/VirtioInput.h | 41 | ||||
| -rw-r--r-- | OvmfPkg/VirtioInputDxe/VirtioInput.inf | 2 | ||||
| -rw-r--r-- | OvmfPkg/VirtioInputDxe/VirtioKeyCodes.h | 14 | ||||
| -rw-r--r-- | OvmfPkg/VirtioInputDxe/VirtioMouse.c | 223 |
5 files changed, 361 insertions, 8 deletions
diff --git a/OvmfPkg/VirtioInputDxe/VirtioInput.c b/OvmfPkg/VirtioInputDxe/VirtioInput.c index 9ca8fc8720..dfa8e78091 100644 --- a/OvmfPkg/VirtioInputDxe/VirtioInput.c +++ b/OvmfPkg/VirtioInputDxe/VirtioInput.c @@ -415,8 +415,22 @@ VirtioInputGetDeviceData ( // Key press event received
// DEBUG ((DEBUG_INFO, "%a: ---------------------- \nType: %x Code: %x Value: %x\n",
// __func__, Event.Type, Event.Code, Event.Value));
+ if (IS_BUTTON_CODE (Event.Code)) {
+ if (Dev->HasMouse) {
+ VirtioMouseHandleEvent (Dev, &Event);
+ }
+ } else if (Dev->HasKeyboard) {
+ VirtioKeyboardHandleEvent (Dev, &Event);
+ }
+
+ break;
+
+ case EV_REL:
+ // Relative pointer movement received
+ if (Dev->HasMouse) {
+ VirtioMouseHandleEvent (Dev, &Event);
+ }
- VirtioKeyboardHandleEvent (Dev, &Event);
break;
default:
@@ -534,7 +548,8 @@ VirtioInputInit ( // Check input device capabilities
//
Dev->HasKeyboard = VirtioKeyboardProbe (Dev);
- if (!Dev->HasKeyboard) {
+ Dev->HasMouse = VirtioMouseProbe (Dev);
+ if (!Dev->HasKeyboard && !Dev->HasMouse) {
Status = EFI_UNSUPPORTED;
goto Failed;
}
@@ -549,6 +564,13 @@ VirtioInputInit ( }
}
+ if (Dev->HasMouse) {
+ Status = VirtioMouseInit (Dev);
+ if (EFI_ERROR (Status)) {
+ goto Failed;
+ }
+ }
+
VirtioInputRingFillRx (Dev, 0);
//
@@ -604,6 +626,10 @@ VirtioInputUninit ( VirtioKeyboardUninit (Dev);
}
+ if (Dev->HasMouse) {
+ VirtioMouseUninit (Dev);
+ }
+
//
// 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
@@ -763,8 +789,32 @@ VirtioInputBindingStart ( }
}
+ if (Dev->HasMouse) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DeviceHandle,
+ &gEfiSimplePointerProtocolGuid,
+ &Dev->SimplePointer,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto UninstallKeyboard;
+ }
+ }
+
return EFI_SUCCESS;
+UninstallKeyboard:
+ if (Dev->HasKeyboard) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DeviceHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ &Dev->Txt,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &Dev->TxtEx,
+ NULL
+ );
+ }
+
CloseExitBoot:
gBS->CloseEvent (Dev->ExitBoot);
@@ -799,21 +849,34 @@ VirtioInputBindingStop ( {
EFI_STATUS Status;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Txt;
+ EFI_SIMPLE_POINTER_PROTOCOL *Pointer;
VIRTIO_INPUT_DEV *Dev;
Status = gBS->OpenProtocol (
DeviceHandle, // candidate device
- &gEfiSimpleTextInProtocolGuid, // retrieve the RNG iface
+ &gEfiSimpleTextInProtocolGuid, // retrieve the keyboard 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;
- }
+ if (!EFI_ERROR (Status)) {
+ Dev = VIRTIO_INPUT_FROM_THIS (Txt);
+ } else {
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiSimplePointerProtocolGuid,
+ (VOID **)&Pointer,
+ This->DriverBindingHandle,
+ DeviceHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
- Dev = VIRTIO_INPUT_FROM_THIS (Txt);
+ Dev = VIRTIO_INPUT_FROM_POINTER_THIS (Pointer);
+ }
//
// Handle Stop() requests for in-use driver instances gracefully.
@@ -832,6 +895,18 @@ VirtioInputBindingStop ( }
}
+ if (Dev->HasMouse) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ DeviceHandle,
+ &gEfiSimplePointerProtocolGuid,
+ &Dev->SimplePointer,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
gBS->CloseEvent (Dev->ExitBoot);
VirtioInputUninit (Dev);
diff --git a/OvmfPkg/VirtioInputDxe/VirtioInput.h b/OvmfPkg/VirtioInputDxe/VirtioInput.h index fd7362824f..98d20dad93 100644 --- a/OvmfPkg/VirtioInputDxe/VirtioInput.h +++ b/OvmfPkg/VirtioInputDxe/VirtioInput.h @@ -12,11 +12,14 @@ #include <Protocol/ComponentName.h>
#include <Protocol/DriverBinding.h>
+#include <Protocol/SimplePointer.h>
#include <Protocol/SimpleTextIn.h>
#include <Protocol/SimpleTextInEx.h>
#include <IndustryStandard/Virtio.h>
+#include "VirtioKeyCodes.h"
+
#define VIRTIO_INPUT_SIG SIGNATURE_32 ('V', 'I', 'N', 'P')
#define MAX_RINGS 2
@@ -26,7 +29,10 @@ #define PROBE_TIME_MS 50
// Max range of recognized keyboard codes
-#define MAX_KEYBOARD_CODE 255
+#define MAX_KEYBOARD_CODE (BTN_MISC - 1)
+
+// Key code 0x100 ~ 0x15f range is for all kinds of button events.
+#define IS_BUTTON_CODE(Code) (((Code) >= BTN_MISC) && ((Code) < KEY_OK))
typedef struct {
UINTN Signature;
@@ -78,6 +84,13 @@ typedef struct { LIST_ENTRY KeyNotifyList;
BOOLEAN KeyActive[MAX_KEYBOARD_CODE + 1]; // Key modifiers
BOOLEAN KeyReady;
+
+ // Mouse implementation
+ BOOLEAN HasMouse;
+ EFI_SIMPLE_POINTER_PROTOCOL SimplePointer;
+ EFI_SIMPLE_POINTER_MODE PointerMode;
+ EFI_SIMPLE_POINTER_STATE PointerState;
+ BOOLEAN PointerReady;
} VIRTIO_INPUT_DEV;
// Helper functions to extract VIRTIO_INPUT_DEV structure pointers
@@ -85,6 +98,8 @@ typedef struct { CR (KbrPointer, VIRTIO_INPUT_DEV, Txt, VIRTIO_INPUT_SIG)
#define VIRTIO_INPUT_EX_FROM_THIS(KbrPointer) \
CR (KbrPointer, VIRTIO_INPUT_DEV, TxtEx, VIRTIO_INPUT_SIG)
+#define VIRTIO_INPUT_FROM_POINTER_THIS(a) \
+ CR (a, VIRTIO_INPUT_DEV, SimplePointer, VIRTIO_INPUT_SIG)
// Bellow candidates to be included as Linux header
#define KEY_PRESSED 1
@@ -130,3 +145,27 @@ VOID VirtioKeyboardUninit (
IN OUT VIRTIO_INPUT_DEV *Dev
);
+
+//
+// VirtioMouse.c
+//
+BOOLEAN
+VirtioMouseProbe (
+ IN VIRTIO_INPUT_DEV *Dev
+ );
+
+VOID
+VirtioMouseHandleEvent (
+ IN OUT VIRTIO_INPUT_DEV *Dev,
+ IN VIRTIO_INPUT_EVENT *Event
+ );
+
+EFI_STATUS
+VirtioMouseInit (
+ IN OUT VIRTIO_INPUT_DEV *Dev
+ );
+
+VOID
+VirtioMouseUninit (
+ IN OUT VIRTIO_INPUT_DEV *Dev
+ );
diff --git a/OvmfPkg/VirtioInputDxe/VirtioInput.inf b/OvmfPkg/VirtioInputDxe/VirtioInput.inf index 4fc2730ac9..0c680b01fa 100644 --- a/OvmfPkg/VirtioInputDxe/VirtioInput.inf +++ b/OvmfPkg/VirtioInputDxe/VirtioInput.inf @@ -20,6 +20,7 @@ VirtioInput.h
VirtioKeyCodes.h
VirtioKeyboard.c
+ VirtioMouse.c
[Packages]
MdePkg/MdePkg.dec
@@ -40,3 +41,4 @@ gEfiSimpleTextInProtocolGuid
gEfiSimpleTextInputExProtocolGuid
gVirtioDeviceProtocolGuid
+ gEfiSimplePointerProtocolGuid
diff --git a/OvmfPkg/VirtioInputDxe/VirtioKeyCodes.h b/OvmfPkg/VirtioInputDxe/VirtioKeyCodes.h index 70d8c454ac..0cb9f49f3d 100644 --- a/OvmfPkg/VirtioInputDxe/VirtioKeyCodes.h +++ b/OvmfPkg/VirtioInputDxe/VirtioKeyCodes.h @@ -18,6 +18,7 @@ */
#define EV_SYN 0x00
#define EV_KEY 0x01
+#define EV_REL 0x02
/*
* Keys and buttons
@@ -289,3 +290,16 @@ #define KEY_MICMUTE 248 /* Mute / unmute the microphone */
/* Code 255 is reserved for special needs of AT keyboard driver */
+
+#define BTN_MISC 0x100
+
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+
+#define KEY_OK 0x160
+
+/*
+ * Relative axes
+ */
+#define REL_X 0x00
+#define REL_Y 0x01
diff --git a/OvmfPkg/VirtioInputDxe/VirtioMouse.c b/OvmfPkg/VirtioInputDxe/VirtioMouse.c new file mode 100644 index 0000000000..fcfcee6b9f --- /dev/null +++ b/OvmfPkg/VirtioInputDxe/VirtioMouse.c @@ -0,0 +1,223 @@ +/** @file
+
+ EFI_SIMPLE_POINTER_PROTOCOL implementation for virtio mouse.
+
+ Copyright (C) 2026, Advanced Micro Devices, Inc.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/VirtioLib.h>
+
+#include <IndustryStandard/VirtioInput.h>
+
+#include "VirtioInput.h"
+#include "VirtioKeyCodes.h"
+
+BOOLEAN
+VirtioMouseProbe (
+ IN VIRTIO_INPUT_DEV *Dev
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Size;
+ UINT8 Bitmap;
+
+ // Check if REL_X and REL_Y are set in the EV_REL bitmap
+ Status = VirtioInputConfigQuerySize (Dev, VirtioInputCfgEvBits, EV_REL, &Size);
+ if (EFI_ERROR (Status) || (Size == 0)) {
+ return FALSE;
+ }
+
+ Status = Dev->VirtIo->ReadDevice (Dev->VirtIo, OFFSET_OF_VINPUT (Data), 1, 1, &Bitmap);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return (Bitmap & (1 << REL_X)) && (Bitmap & (1 << REL_Y));
+}
+
+// -----------------------------------------------------------------------------
+// Function handling VirtIO mouse events
+VOID
+VirtioMouseHandleEvent (
+ IN OUT VIRTIO_INPUT_DEV *Dev,
+ IN VIRTIO_INPUT_EVENT *Event
+ )
+{
+ switch (Event->Type) {
+ case EV_KEY:
+ switch (Event->Code) {
+ case BTN_LEFT:
+ Dev->PointerState.LeftButton = (BOOLEAN)(Event->Value == KEY_PRESSED);
+ break;
+
+ case BTN_RIGHT:
+ Dev->PointerState.RightButton = (BOOLEAN)(Event->Value == KEY_PRESSED);
+ break;
+
+ default:
+ break;
+ }
+
+ Dev->PointerReady = TRUE;
+ break;
+
+ case EV_REL:
+ switch (Event->Code) {
+ case REL_X:
+ Dev->PointerState.RelativeMovementX += (INT32)Event->Value;
+ break;
+
+ case REL_Y:
+ Dev->PointerState.RelativeMovementY += (INT32)Event->Value;
+ break;
+
+ default:
+ break;
+ }
+
+ Dev->PointerReady = TRUE;
+ break;
+
+ default:
+ break;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_POINTER_PROTOCOL API
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioMouseReset (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ VIRTIO_INPUT_DEV *Dev;
+ EFI_TPL OldTpl;
+
+ Dev = VIRTIO_INPUT_FROM_POINTER_THIS (This);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ ZeroMem (&Dev->PointerState, sizeof (Dev->PointerState));
+ Dev->PointerReady = FALSE;
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_POINTER_PROTOCOL API
+STATIC
+EFI_STATUS
+EFIAPI
+VirtioMouseGetState (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ OUT EFI_SIMPLE_POINTER_STATE *State
+ )
+{
+ VIRTIO_INPUT_DEV *Dev;
+ EFI_TPL OldTpl;
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = VIRTIO_INPUT_FROM_POINTER_THIS (This);
+
+ if (!Dev->PointerReady) {
+ return EFI_NOT_READY;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ CopyMem (State, &Dev->PointerState, sizeof (*State));
+
+ //
+ // Clear mouse state
+ //
+ Dev->PointerState.RelativeMovementX = 0;
+ Dev->PointerState.RelativeMovementY = 0;
+ Dev->PointerReady = FALSE;
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+// EFI_SIMPLE_POINTER_PROTOCOL WaitForInput event handler
+STATIC
+VOID
+EFIAPI
+VirtioMouseWaitForPointer (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ VIRTIO_INPUT_DEV *Dev = Context;
+
+ //
+ // Stall 1ms to give other timer-driven drivers a chance to run while this
+ // routine is recursively invoked from WaitForEvent ().
+ //
+ gBS->Stall (1000);
+
+ // Drain pending events from the device.
+ VirtioInputTimer (NULL, Dev);
+
+ // If there is new pointer activity - send signal
+ if (Dev->PointerReady) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+EFI_STATUS
+VirtioMouseInit (
+ IN OUT VIRTIO_INPUT_DEV *Dev
+ )
+{
+ EFI_STATUS Status;
+
+ Dev->SimplePointer.Reset = VirtioMouseReset;
+ Dev->SimplePointer.GetState = VirtioMouseGetState;
+ Dev->SimplePointer.Mode = &Dev->PointerMode;
+
+ Dev->PointerMode.ResolutionX = 8;
+ Dev->PointerMode.ResolutionY = 8;
+ Dev->PointerMode.LeftButton = TRUE;
+ Dev->PointerMode.RightButton = TRUE;
+
+ ZeroMem (&Dev->PointerState, sizeof (Dev->PointerState));
+ Dev->PointerReady = FALSE;
+
+ //
+ // Setup the WaitForInput event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ VirtioMouseWaitForPointer,
+ Dev,
+ &Dev->SimplePointer.WaitForInput
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+VirtioMouseUninit (
+ IN OUT VIRTIO_INPUT_DEV *Dev
+ )
+{
+ gBS->CloseEvent (Dev->SimplePointer.WaitForInput);
+}
|
