mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
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>
This commit is contained in:
parent
fd63e80508
commit
efdbf3c355
5 changed files with 361 additions and 8 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
VirtioInput.h
|
||||
VirtioKeyCodes.h
|
||||
VirtioKeyboard.c
|
||||
VirtioMouse.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
|
|
@ -40,3 +41,4 @@
|
|||
gEfiSimpleTextInProtocolGuid
|
||||
gEfiSimpleTextInputExProtocolGuid
|
||||
gVirtioDeviceProtocolGuid
|
||||
gEfiSimplePointerProtocolGuid
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
223
OvmfPkg/VirtioInputDxe/VirtioMouse.c
Normal file
223
OvmfPkg/VirtioInputDxe/VirtioMouse.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue