mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
Signed-off-by: Ivan Shapovalov <intelfx@intelfx.name> Tested-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
220 lines
4.9 KiB
C
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);
|
|
}
|