CloverBootloader/Protocols/AptioInputFix/Pointer/AIM.c
Sergey Isakov f35acfa5ab restructure sources, preliminary include AptioMemoryFix from OC
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
2019-10-04 16:19:40 +03:00

566 lines
14 KiB
C

/** @file
AmiEfiPointer to EfiPointer translator.
Copyright (c) 2016, vit9696. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "AIM.h"
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
STATIC AMI_SHIM_POINTER mAmiShimPointer;
STATIC UINT8 gIndex = 0;
STATIC UINT8 gXCounts[5] = {0, 0, 0, 0, 0};
STATIC UINT8 gYCounts[5] = {0, 0, 0, 0, 0};
UINT8
EFIAPI
Abs (
IN INT32 Value
)
{
return (UINT8)(Value < 0 ? -Value : Value);
}
INT32
EFIAPI
InternalClamp (
IN INT32 Value,
IN INT32 Min,
IN INT32 Max
)
{
if (Value > Max) {
return Max;
} else if (Value < Min) {
return Min;
}
return Value;
}
VOID
EFIAPI
AmiShimPointerFilterOut (
IN OUT UINT8 *AbsX,
IN OUT UINT8 *AbsY,
IN OUT INT32 *X,
IN OUT INT32 *Y
)
{
UINT8 Index;
if (*AbsX == 0) {
gXCounts[gIndex] = 1;
} else if (*AbsX <= 2) {
for (Index = 0; Index < 5; Index++) {
if (!gXCounts[Index])
break;
}
if (Index == 5) {
*AbsX = 0;
*X = 0;
}
gXCounts[gIndex] = 0;
}
if (*AbsY == 0) {
gYCounts[gIndex] = 1;
} else if (*AbsY <= 2) {
for (Index = 0; Index < 5; Index++) {
if (!gYCounts[Index])
break;
}
if (Index == 5) {
*AbsY = 0;
*Y = 0;
}
gYCounts[gIndex] = 0;
}
gIndex = gIndex < 4 ? gIndex + 1 : 0;
}
#ifdef AMI_SHIM_POINTER_AMI_SMOOTHING
STATIC UINT8 gAbsRange[8] = {42, 36, 30, 24, 18, 12, 6, 1};
STATIC INT32 gMultipliers[8] = {8, 7, 6, 5, 4, 3, 2, 1};
STATIC INT32 gIndices[8] = {2, 2, 2, 2, 2, 2, 2, 0};
INT32
AmiShimPointerScale (
IN INT32 Value,
IN UINT8 AbsValue
)
{
UINT8 TmpIndex;
for (TmpIndex = 0; TmpIndex < 8; TmpIndex++) {
if (AbsValue >= gAbsRange[TmpIndex]) {
break;
}
}
if (TmpIndex != 8) {
if (Value >= 0) {
Value = gIndices[TmpIndex] + Value * gMultipliers[TmpIndex];
} else {
Value = Value * gMultipliers[TmpIndex] - gIndices[TmpIndex];
}
}
return Value;
}
VOID
EFIAPI
AmiShimPointerSmooth (
IN OUT INT32 *X,
IN OUT INT32 *Y,
IN OUT INT32 *Z
)
{
UINT8 AbsX, AbsY;
*X = Clamp (*X, -16, 16);
*Y = Clamp (*Y, -16, 16);
// According to AMI it should not be reported
*Z = 0;
AbsX = Abs (*X);
AbsY = Abs (*Y);
if (*X == 0 && *Y == 0) {
return;
}
AmiShimPointerFilterOut (&AbsX, &AbsY, X, Y);
*X = AmiShimPointerScale(*X, AbsX);
*Y = AmiShimPointerScale(*Y, AbsY);
*X *= AIM_SCALE_FACTOR;
*Y *= AIM_SCALE_FACTOR;
}
#else
STATIC UINT8 gAbsRange[4] = {80, 64, 48, 1};
STATIC INT32 gMultipliers[4] = {4, 3, 2, 1};
VOID
EFIAPI
AmiShimPointerBoostValue (
IN OUT INT32 *Value,
IN INT32 AbsValue
)
{
UINTN Index;
for (Index = 0; Index < 4; Index++) {
if (gAbsRange[Index] > AbsValue) {
*Value *= gMultipliers[Index];
return;
}
}
}
VOID
EFIAPI
AmiShimPointerSmooth (
IN OUT INT32 *X,
IN OUT INT32 *Y,
IN OUT INT32 *Z
)
{
UINT8 AbsX, AbsY;
*X = InternalClamp(*X, -96, 96);
*Y = InternalClamp(*Y, -96, 96);
*Z = 0;
AbsX = Abs (*X);
AbsY = Abs (*Y);
if (*X == 0 && *Y == 0) {
return;
}
AmiShimPointerFilterOut (&AbsX, &AbsY, X, Y);
AmiShimPointerBoostValue(X, AbsX);
AmiShimPointerBoostValue(Y, AbsY);
}
#endif
VOID
EFIAPI
AmiShimPointerPositionHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
{
UINTN Index;
AMI_SHIM_POINTER_INSTANCE *Pointer;
AMI_POINTER_POSITION_STATE_DATA PositionState;
// Do not poll until somebody actually starts using the mouse
// Otherwise first move will be quite random
if (!mAmiShimPointer.UsageStarted) {
return;
}
// This is important to do quickly and separately, because AMI stores positioning data in INT8.
// If we move the mouse quickly it will overflow and return invalid data.
for (Index = 0; Index < AIM_MAX_POINTERS; Index++) {
Pointer = &mAmiShimPointer.PointerMap[Index];
if (Pointer->DeviceHandle != NULL) {
PositionState.Changed = 0;
Pointer->EfiPointer->GetPositionState (Pointer->EfiPointer, &PositionState);
if (PositionState.Changed == 1) {
if (PositionState.Absolute == 0) {
DEBUG ((DEBUG_VERBOSE, "Position: %d %d %d %d\n",
PositionState.Changed, PositionState.PositionX, PositionState.PositionY, PositionState.PositionZ));
AmiShimPointerSmooth(&PositionState.PositionX, &PositionState.PositionY, &PositionState.PositionZ);
if (PositionState.PositionX != 0 || PositionState.PositionY != 0 || PositionState.PositionZ != 0) {
Pointer->PositionX += PositionState.PositionX;
Pointer->PositionY += PositionState.PositionY;
Pointer->PositionZ += PositionState.PositionZ;
Pointer->PositionChanged = TRUE;
}
} else {
//FIXME: Add support for devices with absolute positioning
}
}
}
}
}
EFI_STATUS
EFIAPI
AmiShimPointerUpdateState (
IN AMI_SHIM_POINTER_INSTANCE *Pointer,
OUT EFI_SIMPLE_POINTER_STATE *State
)
{
AMI_POINTER_BUTTON_STATE_DATA ButtonState;
if (!mAmiShimPointer.UsageStarted) {
mAmiShimPointer.UsageStarted = TRUE;
AmiShimPointerPositionHandler(NULL, NULL);
}
ButtonState.Changed = 0;
Pointer->EfiPointer->GetButtonState (Pointer->EfiPointer, &ButtonState);
if (ButtonState.Changed == 0 && Pointer->PositionChanged == 0) {
return EFI_NOT_READY;
}
DEBUG ((DEBUG_VERBOSE, "Button: %d %d %d %d, Position: %d %d %d %d\n",
ButtonState.Changed, ButtonState.LeftButton, ButtonState.MiddleButton, ButtonState.RightButton,
Pointer->PositionChanged, Pointer->PositionX, Pointer->PositionY, Pointer->PositionZ));
if (ButtonState.Changed) {
State->LeftButton = ButtonState.LeftButton;
State->RightButton = ButtonState.RightButton;
} else {
State->LeftButton = State->RightButton = FALSE;
}
if (Pointer->PositionChanged) {
State->RelativeMovementX = Pointer->PositionX;
State->RelativeMovementY = Pointer->PositionY;
State->RelativeMovementZ = Pointer->PositionZ;
} else {
State->RelativeMovementX = State->RelativeMovementY = State->RelativeMovementZ = 0;
}
Pointer->PositionChanged = 0;
Pointer->PositionX = Pointer->PositionY = Pointer->PositionZ = 0;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AmiShimPointerGetState (
IN EFI_SIMPLE_POINTER_PROTOCOL *This,
IN OUT EFI_SIMPLE_POINTER_STATE *State
)
{
EFI_STATUS Status;
UINTN Index;
AMI_SHIM_POINTER_INSTANCE *Pointer;
if (This == NULL || State == NULL) {
return EFI_INVALID_PARAMETER;
}
for (Index = 0, Pointer = mAmiShimPointer.PointerMap; Index < AIM_MAX_POINTERS; Index++, Pointer++) {
if (Pointer->SimplePointer == This) {
break;
}
}
if (Index != AIM_MAX_POINTERS) {
Status = AmiShimPointerUpdateState (Pointer, State);
if (!EFI_ERROR (Status)) {
if (State->RelativeMovementX != 0 ||
State->RelativeMovementY != 0 ||
State->RelativeMovementZ != 0) {
DEBUG ((DEBUG_VERBOSE, "Received[%p] %d %d %d <%d, %d>\n", This, State->RelativeMovementX, State->RelativeMovementY, State->RelativeMovementZ,
State->LeftButton, State->RightButton));
} else {
DEBUG ((DEBUG_VERBOSE, "Received[%p] %d %d %d\n", This, State->RelativeMovementX, State->RelativeMovementY, State->RelativeMovementZ));
}
}
} else {
DEBUG ((DEBUG_VERBOSE, "Received unknown this %p\n", This));
Status = EFI_INVALID_PARAMETER;
}
return Status;
}
EFI_STATUS
EFIAPI
AmiShimPointerTimerSetup (
VOID
)
{
EFI_STATUS Status;
if (mAmiShimPointer.TimersInitialised) {
return EFI_ALREADY_STARTED;
}
Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY, AmiShimPointerPositionHandler, NULL, &mAmiShimPointer.PositionEvent);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "AmiShimPointerPositionHandler event creation failed %d\n", Status));
return Status;
}
Status = gBS->SetTimer (mAmiShimPointer.PositionEvent, TimerPeriodic, AIM_POSITION_POLL_INTERVAL);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "AmiShimPointerPositionHandler timer setting failed %d\n", Status));
gBS->CloseEvent (mAmiShimPointer.PositionEvent);
return Status;
}
mAmiShimPointer.TimersInitialised = TRUE;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AmiShimPointerTimerUninstall (
VOID
)
{
EFI_STATUS Status;
if (!mAmiShimPointer.TimersInitialised) {
return EFI_SUCCESS;
}
if (mAmiShimPointer.PositionEvent != NULL) {
Status = gBS->SetTimer (mAmiShimPointer.PositionEvent, TimerCancel, 0);
if (!EFI_ERROR (Status)) {
gBS->CloseEvent (mAmiShimPointer.PositionEvent);
mAmiShimPointer.PositionEvent = NULL;
} else {
DEBUG((DEBUG_INFO, "AmiShimPointerPositionHandler timer unsetting failed %d\n", Status));
}
}
mAmiShimPointer.TimersInitialised = FALSE;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AmiShimPointerInstallOnHandle (
IN EFI_HANDLE DeviceHandle,
IN AMI_EFIPOINTER_PROTOCOL *EfiPointer,
IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer
)
{
UINTN Index;
AMI_SHIM_POINTER_INSTANCE *Pointer;
AMI_SHIM_POINTER_INSTANCE *FreePointer;
FreePointer = NULL;
for (Index = 0; Index < AIM_MAX_POINTERS; Index++) {
Pointer = &mAmiShimPointer.PointerMap[Index];
if (Pointer->DeviceHandle == NULL && FreePointer == NULL) {
FreePointer = Pointer;
} else if (Pointer->DeviceHandle == DeviceHandle) {
return EFI_ALREADY_STARTED;
}
}
if (FreePointer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
DEBUG ((DEBUG_INFO, "Installed onto %X\n", DeviceHandle));
FreePointer->DeviceHandle = DeviceHandle;
FreePointer->EfiPointer = EfiPointer;
FreePointer->SimplePointer = SimplePointer;
if (FreePointer->SimplePointer->GetState == AmiShimPointerGetState) {
FreePointer->OriginalGetState = NULL;
DEBUG ((DEBUG_INFO, "Function is already hooked\n"));
} else {
FreePointer->OriginalGetState = FreePointer->SimplePointer->GetState;
FreePointer->SimplePointer->GetState = AmiShimPointerGetState;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AmiShimPointerInstall (
VOID
)
{
EFI_STATUS Status;
UINTN NoHandles;
EFI_HANDLE *Handles;
UINTN Index;
BOOLEAN Installed;
AMI_EFIPOINTER_PROTOCOL *EfiPointer;
EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer;
Status = gBS->LocateHandleBuffer (ByProtocol, &gAmiEfiPointerProtocolGuid, NULL, &NoHandles, &Handles);
if (EFI_ERROR(Status)) {
return EFI_NOT_FOUND;
}
DEBUG ((DEBUG_INFO, "Found %d Handles located by protocol\n", NoHandles));
Installed = FALSE;
for (Index = 0; Index < NoHandles; Index++) {
Status = gBS->HandleProtocol (Handles[Index], &gAmiEfiPointerProtocolGuid, (VOID **)&EfiPointer);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_INFO, "Handle %d has no AmiEfiPointerl %d\n", Index, Status));
continue;
}
Status = gBS->HandleProtocol (Handles[Index], &gEfiSimplePointerProtocolGuid, (VOID **)&SimplePointer);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_INFO, "Handle %d has no EfiSimplePointer %d\n", Index, Status));
continue;
}
Status = AmiShimPointerInstallOnHandle (Handles[Index], EfiPointer, SimplePointer);
if (EFI_ERROR(Status)) {
DEBUG ((DEBUG_INFO, "Handle %d failed to get installed %d\n", Index, Status));
continue;
}
Installed = TRUE;
}
gBS->FreePool (Handles);
if (!Installed) {
return EFI_NOT_FOUND;
}
if (!mAmiShimPointer.TimersInitialised) {
return AmiShimPointerTimerSetup();
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
AmiShimPointerUninstall (
VOID
)
{
UINTN Index;
AMI_SHIM_POINTER_INSTANCE *Pointer;
AmiShimPointerTimerUninstall();
for (Index = 0; Index < AIM_MAX_POINTERS; Index++) {
Pointer = &mAmiShimPointer.PointerMap[Index];
if (Pointer->DeviceHandle != NULL) {
Pointer->SimplePointer->GetState = Pointer->OriginalGetState;
gBS->DisconnectController(Pointer->DeviceHandle, NULL, NULL);
Pointer->DeviceHandle = NULL;
}
}
return EFI_SUCCESS;
}
VOID
EFIAPI
AmiShimPointerArriveHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
{
AmiShimPointerInstall();
}
EFI_STATUS
AIMInit (
VOID
)
{
EFI_STATUS Status;
VOID *Registration;
Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, AmiShimPointerArriveHandler, NULL, &mAmiShimPointer.ProtocolArriveEvent);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "AmiShimPointerArriveHandler event creation failed %d\n", Status));
return Status;
}
// EfiSimplePointer gets installed after AMI proprietary protocol
Status = gBS->RegisterProtocolNotify (&gEfiSimplePointerProtocolGuid, mAmiShimPointer.ProtocolArriveEvent, &Registration);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "AmiShimProtocolArriveHandler protocol registration failed %d\n", Status));
gBS->CloseEvent (mAmiShimPointer.ProtocolArriveEvent);
return Status;
}
return AmiShimPointerInstall();
}
EFI_STATUS
AIMExit (
VOID
)
{
return AmiShimPointerUninstall();
}