mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
646 lines
16 KiB
C
646 lines
16 KiB
C
/** @file
|
|
|
|
AppleEventDxe
|
|
|
|
Copyright (c) 2018, vit9696
|
|
|
|
All rights reserved.
|
|
|
|
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 <AppleMacEfi.h>
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/OcMiscLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
|
|
#include "AppleEventInternal.h"
|
|
|
|
// APPLE_EVENT_HANDLE_PRIVATE_SIGNATURE
|
|
#define APPLE_EVENT_HANDLE_PRIVATE_SIGNATURE \
|
|
SIGNATURE_32 ('A', 'L', 's', 't')
|
|
|
|
// APPLE_EVENT_HANDLE_PRIVATE_FROM_LIST_ENTRY
|
|
#define APPLE_EVENT_HANDLE_PRIVATE_FROM_LIST_ENTRY(Handle) \
|
|
CR ( \
|
|
(Handle), \
|
|
APPLE_EVENT_HANDLE_PRIVATE, \
|
|
Link, \
|
|
APPLE_EVENT_HANDLE_PRIVATE_SIGNATURE \
|
|
)
|
|
|
|
// APPLE_EVENT_HANDLE_PRIVATE
|
|
typedef struct {
|
|
UINT32 Signature; ///<
|
|
LIST_ENTRY Link; ///<
|
|
BOOLEAN Ready; ///<
|
|
BOOLEAN Registered; ///<
|
|
APPLE_EVENT_TYPE EventType; ///<
|
|
APPLE_EVENT_NOTIFY_FUNCTION NotifyFunction; ///<
|
|
VOID *NotifyContext; ///<
|
|
CHAR8 *Name; ///<
|
|
} APPLE_EVENT_HANDLE_PRIVATE;
|
|
|
|
// mEventHandles
|
|
STATIC
|
|
LIST_ENTRY mEventHandles = INITIALIZE_LIST_HEAD_VARIABLE (mEventHandles);
|
|
|
|
// mNumberOfEventHandles
|
|
STATIC UINTN mNumberOfEventHandles = 0;
|
|
|
|
// EventLibCreateTimerEvent
|
|
EFI_EVENT
|
|
EventLibCreateTimerEvent (
|
|
IN EFI_EVENT_NOTIFY NotifyFunction,
|
|
IN VOID *NotifyContext,
|
|
IN UINT64 TriggerTime,
|
|
IN BOOLEAN SignalPeriodic,
|
|
IN EFI_TPL NotifyTpl
|
|
)
|
|
{
|
|
EFI_EVENT Event;
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "EventLibCreateTimerEvent\n"));
|
|
|
|
Event = NULL;
|
|
|
|
if (NotifyTpl >= TPL_CALLBACK) {
|
|
Status = gBS->CreateEvent (
|
|
((NotifyFunction != NULL)
|
|
? (EVT_TIMER | EVT_NOTIFY_SIGNAL)
|
|
: EVT_TIMER),
|
|
NotifyTpl,
|
|
NotifyFunction,
|
|
NotifyContext,
|
|
&Event
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->SetTimer (
|
|
Event,
|
|
(SignalPeriodic ? TimerPeriodic : TimerRelative),
|
|
TriggerTime
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->CloseEvent (Event);
|
|
|
|
Event = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Event;
|
|
}
|
|
|
|
// EventLibCreateNotifyTimerEvent
|
|
EFI_EVENT
|
|
EventLibCreateNotifyTimerEvent (
|
|
IN EFI_EVENT_NOTIFY NotifyFunction,
|
|
IN VOID *NotifyContext,
|
|
IN UINT64 TriggerTime,
|
|
IN BOOLEAN SignalPeriodic
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_VERBOSE, "EventLibCreateNotifyTimerEvent\n"));
|
|
|
|
return EventLibCreateTimerEvent (
|
|
NotifyFunction,
|
|
NotifyContext,
|
|
TriggerTime,
|
|
SignalPeriodic,
|
|
TPL_CALLBACK
|
|
);
|
|
}
|
|
|
|
// EventLibCancelEvent
|
|
VOID
|
|
EventLibCancelEvent (
|
|
IN EFI_EVENT Event
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "EventLibCancelEvent\n"));
|
|
|
|
Status = gBS->SetTimer (Event, TimerCancel, 0);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
gBS->CloseEvent (Event);
|
|
}
|
|
}
|
|
|
|
// EventSignalEvents
|
|
VOID
|
|
EventSignalEvents (
|
|
IN APPLE_EVENT_INFORMATION *EventInformation
|
|
)
|
|
{
|
|
LIST_ENTRY *EventHandleEntry;
|
|
APPLE_EVENT_HANDLE_PRIVATE *EventHandle;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "EventSignalEvents\n"));
|
|
|
|
EventHandleEntry = GetFirstNode (&mEventHandles);
|
|
|
|
while (!IsNull (&mEventHandles, EventHandleEntry)) {
|
|
EventHandle = APPLE_EVENT_HANDLE_PRIVATE_FROM_LIST_ENTRY (
|
|
EventHandleEntry
|
|
);
|
|
|
|
if ( EventHandle->Registered
|
|
&& EventHandle->Ready
|
|
&& ((EventInformation->EventType & EventHandle->EventType) != 0)
|
|
&& (EventHandle->NotifyFunction != NULL))
|
|
{
|
|
EventHandle->NotifyFunction (
|
|
EventInformation,
|
|
EventHandle->NotifyContext
|
|
);
|
|
}
|
|
|
|
EventHandleEntry = GetNextNode (&mEventHandles, EventHandleEntry);
|
|
}
|
|
}
|
|
|
|
// InternalFlagAllEventsReady
|
|
VOID
|
|
InternalFlagAllEventsReady (
|
|
VOID
|
|
)
|
|
{
|
|
LIST_ENTRY *EventHandleEntry;
|
|
APPLE_EVENT_HANDLE_PRIVATE *EventHandle;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "InternalFlagAllEventsReady\n"));
|
|
|
|
EventHandleEntry = GetFirstNode (&mEventHandles);
|
|
|
|
if (!IsListEmpty (&mEventHandles)) {
|
|
do {
|
|
EventHandle = APPLE_EVENT_HANDLE_PRIVATE_FROM_LIST_ENTRY (
|
|
EventHandleEntry
|
|
);
|
|
|
|
EventHandle->Ready = TRUE;
|
|
|
|
EventHandleEntry = GetNextNode (&mEventHandles, EventHandleEntry);
|
|
} while (!IsNull (&mEventHandles, EventHandleEntry));
|
|
}
|
|
}
|
|
|
|
// InternalSignalEvents
|
|
VOID
|
|
InternalSignalEvents (
|
|
IN APPLE_EVENT_INFORMATION *Information
|
|
)
|
|
{
|
|
LIST_ENTRY *EventHandleEntry;
|
|
APPLE_EVENT_HANDLE_PRIVATE *EventHandle;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "InternalSignalEvents\n"));
|
|
|
|
EventHandleEntry = GetFirstNode (&mEventHandles);
|
|
|
|
if (!IsListEmpty (&mEventHandles)) {
|
|
do {
|
|
EventHandle = APPLE_EVENT_HANDLE_PRIVATE_FROM_LIST_ENTRY (
|
|
EventHandleEntry
|
|
);
|
|
|
|
if ( EventHandle->Registered && EventHandle->Ready
|
|
&& (EventHandle->EventType & Information->EventType)
|
|
&& (EventHandle->NotifyFunction != NULL))
|
|
{
|
|
EventHandle->NotifyFunction (
|
|
Information,
|
|
EventHandle->NotifyContext
|
|
);
|
|
}
|
|
|
|
EventHandleEntry = GetNextNode (&mEventHandles, EventHandleEntry);
|
|
} while (!IsNull (&mEventHandles, EventHandleEntry));
|
|
}
|
|
}
|
|
|
|
// InternalRemoveUnregisteredEvents
|
|
VOID
|
|
InternalRemoveUnregisteredEvents (
|
|
VOID
|
|
)
|
|
{
|
|
LIST_ENTRY *EventHandleEntry;
|
|
LIST_ENTRY *NextEventHandleEntry;
|
|
APPLE_EVENT_HANDLE_PRIVATE *EventHandle;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "InternalRemoveUnregisteredEvents\n"));
|
|
|
|
EventHandleEntry = GetFirstNode (&mEventHandles);
|
|
|
|
if (!IsListEmpty (&mEventHandles)) {
|
|
do {
|
|
NextEventHandleEntry = GetNextNode (&mEventHandles, EventHandleEntry);
|
|
|
|
EventHandle = APPLE_EVENT_HANDLE_PRIVATE_FROM_LIST_ENTRY (
|
|
EventHandleEntry
|
|
);
|
|
|
|
if (!EventHandle->Registered) {
|
|
if (EventHandle->Name != NULL) {
|
|
FreePool ((VOID *)EventHandle->Name);
|
|
}
|
|
|
|
RemoveEntryList (&EventHandle->Link);
|
|
FreePool ((VOID *)EventHandle);
|
|
}
|
|
|
|
EventHandleEntry = NextEventHandleEntry;
|
|
} while (!IsNull (&mEventHandles, NextEventHandleEntry));
|
|
}
|
|
}
|
|
|
|
// InternalCreatePollEvents
|
|
STATIC
|
|
EFI_STATUS
|
|
InternalCreatePollEvents (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "InternalCreatePollEvents\n"));
|
|
|
|
Status = EventCreateSimplePointerPollEvent ();
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = EventCreateKeyStrokePollEvent ();
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
EventCancelSimplePointerPollEvent ();
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
// InternalCancelPollEvents
|
|
VOID
|
|
InternalCancelPollEvents (
|
|
VOID
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_VERBOSE, "InternalCancelPollEvents\n"));
|
|
|
|
EventCancelSimplePointerPollEvent ();
|
|
EventCancelKeyStrokePollEvent ();
|
|
}
|
|
|
|
// EventRegisterHandler
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EventRegisterHandler (
|
|
IN APPLE_EVENT_TYPE Type,
|
|
IN APPLE_EVENT_NOTIFY_FUNCTION NotifyFunction,
|
|
OUT APPLE_EVENT_HANDLE *Handle,
|
|
IN VOID *NotifyContext
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
APPLE_EVENT_HANDLE_PRIVATE *EventHandle;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "EventRegisterHandler\n"));
|
|
|
|
Status = EFI_INVALID_PARAMETER;
|
|
|
|
if ( (Handle != NULL)
|
|
&& (NotifyFunction != NULL)
|
|
&& (Type != APPLE_EVENT_TYPE_NONE))
|
|
{
|
|
*Handle = NULL;
|
|
|
|
InternalRemoveUnregisteredEvents ();
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
if (mNumberOfEventHandles == 0) {
|
|
Status = InternalCreatePollEvents ();
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
EventHandle = AllocatePool (sizeof (*EventHandle));
|
|
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
|
|
if (EventHandle != NULL) {
|
|
EventHandle->Signature = APPLE_EVENT_HANDLE_PRIVATE_SIGNATURE;
|
|
EventHandle->Ready = FALSE;
|
|
EventHandle->Registered = TRUE;
|
|
EventHandle->EventType = Type;
|
|
EventHandle->NotifyFunction = NotifyFunction;
|
|
EventHandle->NotifyContext = NotifyContext;
|
|
EventHandle->Name = NULL;
|
|
|
|
++mNumberOfEventHandles;
|
|
|
|
InsertTailList (&mEventHandles, &EventHandle->Link);
|
|
|
|
*Handle = EventHandle;
|
|
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
Done:
|
|
return Status;
|
|
}
|
|
|
|
// EventUnregisterHandler
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EventUnregisterHandler (
|
|
IN APPLE_EVENT_HANDLE Handle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *EventHandleEntry;
|
|
APPLE_EVENT_HANDLE_PRIVATE *EventHandle;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "EventUnregisterHandler\n"));
|
|
|
|
Status = EFI_INVALID_PARAMETER;
|
|
|
|
EventHandleEntry = GetFirstNode (&mEventHandles);
|
|
|
|
while (!IsNull (&mEventHandles, EventHandleEntry)) {
|
|
EventHandle = APPLE_EVENT_HANDLE_PRIVATE_FROM_LIST_ENTRY (
|
|
EventHandleEntry
|
|
);
|
|
|
|
if ( ((UINTN)EventHandle == (UINTN)Handle)
|
|
|| ((UINTN)Handle == (UINTN)-1))
|
|
{
|
|
EventHandle->Registered = FALSE;
|
|
--mNumberOfEventHandles;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
if ((UINTN)Handle != (UINTN)-1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
EventHandleEntry = GetNextNode (&mEventHandles, EventHandleEntry);
|
|
}
|
|
|
|
if (mNumberOfEventHandles == 0) {
|
|
InternalCancelPollEvents ();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
// EventSetCursorPosition
|
|
|
|
/** This function is used to change the position of the cursor on the screen.
|
|
|
|
@param[in] Position The position where to position the cursor.
|
|
|
|
@retval EFI_INVALID_PARAMETER Position is invalid.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EventSetCursorPosition (
|
|
IN DIMENSION *Position
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_VERBOSE, "EventSetCursorPosition\n"));
|
|
|
|
return EventSetCursorPositionImpl (Position);
|
|
}
|
|
|
|
// EventSetEventName
|
|
|
|
/** This function is used to assign a name to an event.
|
|
|
|
@param[in,out] Handle
|
|
@param[in] Name
|
|
|
|
@retval EFI_SUCCESS The event name was assigned successfully.
|
|
@retval EFI_INVALID_PARAMETER EventHandle or EventName is NULL.
|
|
@retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate the
|
|
event name.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EventSetEventName (
|
|
IN OUT APPLE_EVENT_HANDLE Handle,
|
|
IN CHAR8 *Name
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN AllocationSize;
|
|
CHAR8 *EventName;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "EventSetEventName\n"));
|
|
|
|
Status = EFI_INVALID_PARAMETER;
|
|
|
|
if ((Handle != NULL) && (Name != NULL)) {
|
|
AllocationSize = AsciiStrSize (Name);
|
|
EventName = AllocateZeroPool (AllocationSize);
|
|
|
|
((APPLE_EVENT_HANDLE_PRIVATE *)Handle)->Name = EventName;
|
|
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
|
|
if (EventName != NULL) {
|
|
AsciiStrCpyS (EventName, AllocationSize, Name);
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
// EventIsCapsLockOnImpl
|
|
|
|
/** Retrieves the state of the CapsLock key.
|
|
|
|
@param[in,out] CLockOn This parameter indicates the state of the CapsLock
|
|
key.
|
|
|
|
@retval EFI_SUCCESS The CapsLock state was successfully returned
|
|
in CLockOn.
|
|
@retval EFI_INVALID_PARAMETER CLockOn is NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EventIsCapsLockOn (
|
|
IN OUT BOOLEAN *CLockOn
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_VERBOSE, "EventIsCapsLockOn\n"));
|
|
|
|
return EventIsCapsLockOnImpl (CLockOn);
|
|
}
|
|
|
|
// InternalUnregisterHandlers
|
|
STATIC
|
|
VOID
|
|
InternalUnregisterHandlers (
|
|
VOID
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_VERBOSE, "InternalUnregisterHandlers\n"));
|
|
|
|
EventSimplePointerDesctructor ();
|
|
|
|
InternalRemoveUnregisteredEvents ();
|
|
|
|
if (!IsListEmpty (&mEventHandles)) {
|
|
EventUnregisterHandler ((APPLE_EVENT_HANDLE_PRIVATE *)((UINTN)-1));
|
|
}
|
|
}
|
|
|
|
// mAppleEventProtocol
|
|
STATIC APPLE_EVENT_PROTOCOL mAppleEventProtocol = {
|
|
APPLE_EVENT_PROTOCOL_REVISION,
|
|
EventRegisterHandler,
|
|
EventUnregisterHandler,
|
|
EventSetCursorPosition,
|
|
EventSetEventName,
|
|
EventIsCapsLockOn
|
|
};
|
|
|
|
// AppleEventUnload
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AppleEventUnload (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "AppleEventUnload\n"));
|
|
|
|
EventCloseSimplePointerInstallNotifyEvent ();
|
|
|
|
InternalSignalAndCloseQueueEvent ();
|
|
InternalUnregisterHandlers ();
|
|
InternalCancelPollEvents ();
|
|
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
gImageHandle,
|
|
&gAppleEventProtocolGuid,
|
|
(VOID *)&mAppleEventProtocol
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
APPLE_EVENT_PROTOCOL *
|
|
OcAppleEventInstallProtocol (
|
|
IN BOOLEAN Install,
|
|
IN BOOLEAN Reinstall,
|
|
IN BOOLEAN CustomDelays,
|
|
IN UINT16 KeyInitialDelay,
|
|
IN UINT16 KeySubsequentDelay,
|
|
IN BOOLEAN GraphicsInputMirroring,
|
|
IN UINT32 PointerPollMin,
|
|
IN UINT32 PointerPollMax,
|
|
IN UINT32 PointerPollMask,
|
|
IN UINT16 PointerSpeedDiv,
|
|
IN UINT16 PointerSpeedMul
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
APPLE_EVENT_PROTOCOL *AppleEvent;
|
|
|
|
DEBUG ((DEBUG_VERBOSE, "OcAppleEventInstallProtocol\n"));
|
|
|
|
if (!Reinstall) {
|
|
Status = gBS->LocateProtocol (
|
|
&gAppleEventProtocolGuid,
|
|
NULL,
|
|
(VOID *)&AppleEvent
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (AppleEvent->Revision < APPLE_EVENT_PROTOCOL_REVISION_MINIMUM) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAE: Not using OEM revision %u, does not meet required minimum %u\n",
|
|
(UINT32)AppleEvent->Revision,
|
|
(UINT32)APPLE_EVENT_PROTOCOL_REVISION_MINIMUM
|
|
));
|
|
Reinstall = TRUE;
|
|
} else {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"OCAE: Using OEM revision %u, meets required minimum %u\n",
|
|
(UINT32)AppleEvent->Revision,
|
|
(UINT32)APPLE_EVENT_PROTOCOL_REVISION_MINIMUM
|
|
));
|
|
return AppleEvent;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Install) {
|
|
DEBUG ((DEBUG_INFO, "OCAE: Letting OEM protocol connect later\n"));
|
|
return NULL;
|
|
}
|
|
|
|
Status = OcUninstallAllProtocolInstances (&gAppleEventProtocolGuid);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "OCAE: OEM uninstall failed: %r\n", Status));
|
|
return NULL;
|
|
}
|
|
|
|
InternalSetKeyBehaviour (
|
|
CustomDelays,
|
|
KeyInitialDelay,
|
|
KeySubsequentDelay,
|
|
GraphicsInputMirroring
|
|
);
|
|
|
|
InternalSetPointerPolling (PointerPollMin, PointerPollMax, PointerPollMask);
|
|
InternalSetPointerSpeed (PointerSpeedDiv, PointerSpeedMul);
|
|
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&gImageHandle,
|
|
&gAppleEventProtocolGuid,
|
|
&mAppleEventProtocol,
|
|
NULL
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
InternalCreateQueueEvent ();
|
|
|
|
Status = EventCreateSimplePointerInstallNotifyEvent ();
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "OCAE: Builtin install failed\n"));
|
|
AppleEventUnload ();
|
|
return NULL;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "OCAE: Builtin installed\n"));
|
|
return &mAppleEventProtocol;
|
|
}
|