edk2/OvmfPkg/VirtioInputDxe/VirtioMouse.c
Ivan Shapovalov 49583d582b OvmfPkg/VirtioInputDxe: include missing headers in VirtioInput.h
Signed-off-by: Ivan Shapovalov <intelfx@intelfx.name>
Tested-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
2026-08-21 12:52:57 +00:00

220 lines
4.9 KiB
C

/** @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 "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);
}