2009-01-23 08:24:55 +01:00
|
|
|
/** @file
|
|
|
|
Provides a way for 3rd party applications to register themselves for launch by the
|
|
|
|
Boot Manager based on hot key
|
|
|
|
|
2018-06-27 15:06:35 +02:00
|
|
|
Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
|
2019-04-04 01:03:59 +02:00
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
2009-01-23 08:24:55 +01:00
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "Hotkey.h"
|
|
|
|
|
|
|
|
|
2011-04-20 10:51:18 +02:00
|
|
|
LIST_ENTRY mHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList);
|
|
|
|
BDS_COMMON_OPTION *mHotkeyBootOption = NULL;
|
|
|
|
EFI_EVENT mHotkeyEvent;
|
|
|
|
VOID *mHotkeyRegistration;
|
2009-01-23 08:24:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
Check if the Key Option is valid or not.
|
|
|
|
|
|
|
|
@param KeyOption The Hot Key Option to be checked.
|
|
|
|
|
|
|
|
@retval TRUE The Hot Key Option is valid.
|
|
|
|
@retval FALSE The Hot Key Option is invalid.
|
|
|
|
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
IsKeyOptionValid (
|
|
|
|
IN EFI_KEY_OPTION *KeyOption
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT16 BootOptionName[10];
|
|
|
|
UINT8 *BootOptionVar;
|
|
|
|
UINTN BootOptionSize;
|
|
|
|
UINT32 Crc;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check whether corresponding Boot Option exist
|
|
|
|
//
|
|
|
|
UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", KeyOption->BootOption);
|
|
|
|
BootOptionVar = BdsLibGetVariableAndSize (
|
|
|
|
BootOptionName,
|
|
|
|
&gEfiGlobalVariableGuid,
|
|
|
|
&BootOptionSize
|
|
|
|
);
|
|
|
|
|
|
|
|
if (BootOptionVar == NULL || BootOptionSize == 0) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check CRC for Boot Option
|
|
|
|
//
|
|
|
|
gBS->CalculateCrc32 (BootOptionVar, BootOptionSize, &Crc);
|
|
|
|
FreePool (BootOptionVar);
|
|
|
|
|
|
|
|
return (BOOLEAN) ((KeyOption->BootOptionCrc == Crc) ? TRUE : FALSE);
|
|
|
|
}
|
|
|
|
|
2011-04-20 10:51:18 +02:00
|
|
|
/**
|
|
|
|
Try to boot the boot option triggered by hotkey.
|
2012-03-23 05:27:19 +01:00
|
|
|
@retval EFI_SUCCESS There is HotkeyBootOption & it is processed
|
|
|
|
@retval EFI_NOT_FOUND There is no HotkeyBootOption
|
2011-04-20 10:51:18 +02:00
|
|
|
**/
|
2012-03-23 05:27:19 +01:00
|
|
|
EFI_STATUS
|
2011-04-20 10:51:18 +02:00
|
|
|
HotkeyBoot (
|
|
|
|
VOID
|
|
|
|
)
|
2018-06-27 15:06:35 +02:00
|
|
|
{
|
2011-04-20 10:51:18 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN ExitDataSize;
|
|
|
|
CHAR16 *ExitData;
|
2012-03-23 05:27:19 +01:00
|
|
|
|
|
|
|
if (mHotkeyBootOption == NULL) {
|
|
|
|
return EFI_NOT_FOUND;
|
2018-06-27 15:06:35 +02:00
|
|
|
}
|
|
|
|
|
2012-03-23 05:27:19 +01:00
|
|
|
BdsLibConnectDevicePath (mHotkeyBootOption->DevicePath);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Clear the screen before launch this BootOption
|
|
|
|
//
|
|
|
|
gST->ConOut->Reset (gST->ConOut, FALSE);
|
|
|
|
|
|
|
|
Status = BdsLibBootViaBootOption (mHotkeyBootOption, mHotkeyBootOption->DevicePath, &ExitDataSize, &ExitData);
|
2011-04-20 10:51:18 +02:00
|
|
|
|
2012-03-23 05:27:19 +01:00
|
|
|
if (EFI_ERROR (Status)) {
|
2011-04-20 10:51:18 +02:00
|
|
|
//
|
2012-03-23 05:27:19 +01:00
|
|
|
// Call platform action to indicate the boot fail
|
2011-04-20 10:51:18 +02:00
|
|
|
//
|
2012-03-23 05:27:19 +01:00
|
|
|
mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
|
|
|
|
PlatformBdsBootFail (mHotkeyBootOption, Status, ExitData, ExitDataSize);
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// Call platform action to indicate the boot success
|
|
|
|
//
|
|
|
|
mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
|
|
|
|
PlatformBdsBootSuccess (mHotkeyBootOption);
|
|
|
|
}
|
|
|
|
FreePool (mHotkeyBootOption->Description);
|
|
|
|
FreePool (mHotkeyBootOption->DevicePath);
|
|
|
|
FreePool (mHotkeyBootOption->LoadOptions);
|
|
|
|
FreePool (mHotkeyBootOption);
|
2011-04-20 10:51:18 +02:00
|
|
|
|
2012-03-23 05:27:19 +01:00
|
|
|
mHotkeyBootOption = NULL;
|
2011-04-20 10:51:18 +02:00
|
|
|
|
2012-03-23 05:27:19 +01:00
|
|
|
return EFI_SUCCESS;
|
2011-04-20 10:51:18 +02:00
|
|
|
}
|
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
This is the common notification function for HotKeys, it will be registered
|
|
|
|
with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
|
|
|
|
|
|
|
|
@param KeyData A pointer to a buffer that is filled in with the keystroke
|
|
|
|
information for the key that was pressed.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS KeyData is successfully processed.
|
|
|
|
@return EFI_NOT_FOUND Fail to find boot option variable.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
2009-04-14 01:07:44 +02:00
|
|
|
EFIAPI
|
2009-01-23 08:24:55 +01:00
|
|
|
HotkeyCallback (
|
|
|
|
IN EFI_KEY_DATA *KeyData
|
|
|
|
)
|
|
|
|
{
|
|
|
|
BOOLEAN HotkeyCatched;
|
|
|
|
LIST_ENTRY BootLists;
|
|
|
|
LIST_ENTRY *Link;
|
|
|
|
BDS_HOTKEY_OPTION *Hotkey;
|
|
|
|
UINT16 Buffer[10];
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_KEY_DATA *HotkeyData;
|
|
|
|
|
2011-04-20 10:51:18 +02:00
|
|
|
if (mHotkeyBootOption != NULL) {
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
2011-04-20 10:51:18 +02:00
|
|
|
// Do not process sequential hotkey stroke until the current boot option returns
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2011-04-20 10:51:18 +02:00
|
|
|
Status = EFI_SUCCESS;
|
2009-01-23 08:24:55 +01:00
|
|
|
|
2011-04-20 10:51:18 +02:00
|
|
|
for ( Link = GetFirstNode (&mHotkeyList)
|
|
|
|
; !IsNull (&mHotkeyList, Link)
|
|
|
|
; Link = GetNextNode (&mHotkeyList, Link)
|
|
|
|
) {
|
2009-01-23 08:24:55 +01:00
|
|
|
HotkeyCatched = FALSE;
|
|
|
|
Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Is this Key Stroke we are waiting for?
|
|
|
|
//
|
|
|
|
ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
|
|
|
|
HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
|
|
|
|
if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
|
2011-04-20 10:51:18 +02:00
|
|
|
(KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
|
2018-06-27 15:06:35 +02:00
|
|
|
(((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ?
|
2011-04-20 10:51:18 +02:00
|
|
|
(KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
|
|
|
|
)
|
|
|
|
) {
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
2011-04-20 10:51:18 +02:00
|
|
|
// For hotkey of key combination, transit to next waiting state
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
2011-04-20 10:51:18 +02:00
|
|
|
Hotkey->WaitingKey++;
|
2009-01-23 08:24:55 +01:00
|
|
|
|
2011-04-20 10:51:18 +02:00
|
|
|
if (Hotkey->WaitingKey == Hotkey->CodeCount) {
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
2011-04-20 10:51:18 +02:00
|
|
|
// Received the whole key stroke sequence
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
|
|
|
HotkeyCatched = TRUE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// Receive an unexpected key stroke, reset to initial waiting state
|
|
|
|
//
|
|
|
|
Hotkey->WaitingKey = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HotkeyCatched) {
|
|
|
|
//
|
|
|
|
// Reset to initial waiting state
|
|
|
|
//
|
|
|
|
Hotkey->WaitingKey = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Launch its BootOption
|
|
|
|
//
|
|
|
|
InitializeListHead (&BootLists);
|
|
|
|
|
|
|
|
UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber);
|
2011-04-20 10:51:18 +02:00
|
|
|
mHotkeyBootOption = BdsLibVariableToOption (&BootLists, Buffer);
|
2009-01-23 08:24:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Register the common HotKey notify function to given SimpleTextInEx protocol instance.
|
|
|
|
|
|
|
|
@param SimpleTextInEx Simple Text Input Ex protocol instance
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Register hotkey notification function successfully.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures.
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
HotkeyRegisterNotify (
|
|
|
|
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Index;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
LIST_ENTRY *Link;
|
|
|
|
BDS_HOTKEY_OPTION *Hotkey;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Register notification function for each hotkey
|
|
|
|
//
|
|
|
|
Link = GetFirstNode (&mHotkeyList);
|
|
|
|
|
|
|
|
while (!IsNull (&mHotkeyList, Link)) {
|
|
|
|
Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
|
|
|
|
|
|
|
|
Index = 0;
|
|
|
|
do {
|
|
|
|
Status = SimpleTextInEx->RegisterKeyNotify (
|
|
|
|
SimpleTextInEx,
|
|
|
|
&Hotkey->KeyData[Index],
|
|
|
|
HotkeyCallback,
|
|
|
|
&Hotkey->NotifyHandle
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
//
|
|
|
|
// some of the hotkey registry failed
|
|
|
|
//
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
Index ++;
|
2009-06-23 10:57:31 +02:00
|
|
|
} while ((Index < Hotkey->CodeCount) && (Index < (sizeof (Hotkey->KeyData) / sizeof (EFI_KEY_DATA))));
|
2009-01-23 08:24:55 +01:00
|
|
|
|
|
|
|
Link = GetNextNode (&mHotkeyList, Link);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Callback function for SimpleTextInEx protocol install events
|
|
|
|
|
|
|
|
@param Event the event that is signaled.
|
|
|
|
@param Context not used here.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
HotkeyEvent (
|
|
|
|
IN EFI_EVENT Event,
|
|
|
|
IN VOID *Context
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN BufferSize;
|
|
|
|
EFI_HANDLE Handle;
|
|
|
|
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;
|
|
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
BufferSize = sizeof (EFI_HANDLE);
|
|
|
|
Status = gBS->LocateHandle (
|
|
|
|
ByRegisterNotify,
|
|
|
|
NULL,
|
|
|
|
mHotkeyRegistration,
|
|
|
|
&BufferSize,
|
|
|
|
&Handle
|
|
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
//
|
|
|
|
// If no more notification events exist
|
|
|
|
//
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = gBS->HandleProtocol (
|
|
|
|
Handle,
|
|
|
|
&gEfiSimpleTextInputExProtocolGuid,
|
|
|
|
(VOID **) &SimpleTextInEx
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
HotkeyRegisterNotify (SimpleTextInEx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Insert Key Option to hotkey list.
|
|
|
|
|
|
|
|
@param KeyOption The Hot Key Option to be added to hotkey list.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Add to hotkey list success.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
HotkeyInsertList (
|
|
|
|
IN EFI_KEY_OPTION *KeyOption
|
|
|
|
)
|
|
|
|
{
|
|
|
|
BDS_HOTKEY_OPTION *HotkeyLeft;
|
|
|
|
BDS_HOTKEY_OPTION *HotkeyRight;
|
|
|
|
UINTN Index;
|
2013-12-18 06:51:22 +01:00
|
|
|
EFI_BOOT_KEY_DATA KeyOptions;
|
2009-01-23 08:24:55 +01:00
|
|
|
UINT32 KeyShiftStateLeft;
|
|
|
|
UINT32 KeyShiftStateRight;
|
|
|
|
EFI_INPUT_KEY *InputKey;
|
|
|
|
EFI_KEY_DATA *KeyData;
|
|
|
|
|
|
|
|
HotkeyLeft = AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION));
|
|
|
|
if (HotkeyLeft == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
HotkeyLeft->Signature = BDS_HOTKEY_OPTION_SIGNATURE;
|
|
|
|
HotkeyLeft->BootOptionNumber = KeyOption->BootOption;
|
2013-12-18 06:51:22 +01:00
|
|
|
|
|
|
|
KeyOptions = KeyOption->KeyData;
|
|
|
|
|
|
|
|
HotkeyLeft->CodeCount = (UINT8) KeyOptions.Options.InputKeyCount;
|
2009-01-23 08:24:55 +01:00
|
|
|
|
|
|
|
//
|
|
|
|
// Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
|
|
|
|
//
|
2009-04-09 09:56:28 +02:00
|
|
|
KeyShiftStateRight = EFI_SHIFT_STATE_VALID;
|
2013-12-18 06:51:22 +01:00
|
|
|
if (KeyOptions.Options.ShiftPressed) {
|
2009-04-09 09:56:28 +02:00
|
|
|
KeyShiftStateRight |= EFI_RIGHT_SHIFT_PRESSED;
|
|
|
|
}
|
2013-12-18 06:51:22 +01:00
|
|
|
if (KeyOptions.Options.ControlPressed) {
|
2009-04-09 09:56:28 +02:00
|
|
|
KeyShiftStateRight |= EFI_RIGHT_CONTROL_PRESSED;
|
|
|
|
}
|
2013-12-18 06:51:22 +01:00
|
|
|
if (KeyOptions.Options.AltPressed) {
|
2009-04-09 09:56:28 +02:00
|
|
|
KeyShiftStateRight |= EFI_RIGHT_ALT_PRESSED;
|
|
|
|
}
|
2013-12-18 06:51:22 +01:00
|
|
|
if (KeyOptions.Options.LogoPressed) {
|
2009-04-09 09:56:28 +02:00
|
|
|
KeyShiftStateRight |= EFI_RIGHT_LOGO_PRESSED;
|
|
|
|
}
|
2013-12-18 06:51:22 +01:00
|
|
|
if (KeyOptions.Options.MenuPressed) {
|
2009-04-09 09:56:28 +02:00
|
|
|
KeyShiftStateRight |= EFI_MENU_KEY_PRESSED;
|
|
|
|
}
|
2013-12-18 06:51:22 +01:00
|
|
|
if (KeyOptions.Options.SysReqPressed) {
|
2009-04-09 09:56:28 +02:00
|
|
|
KeyShiftStateRight |= EFI_SYS_REQ_PRESSED;
|
|
|
|
}
|
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
KeyShiftStateLeft = (KeyShiftStateRight & 0xffffff00) | ((KeyShiftStateRight & 0xff) << 1);
|
|
|
|
|
|
|
|
InputKey = (EFI_INPUT_KEY *) (((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION));
|
|
|
|
|
|
|
|
Index = 0;
|
|
|
|
KeyData = &HotkeyLeft->KeyData[0];
|
|
|
|
do {
|
|
|
|
//
|
|
|
|
// If Key CodeCount is 0, then only KeyData[0] is used;
|
|
|
|
// if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
|
|
|
|
//
|
|
|
|
KeyData->Key.ScanCode = InputKey[Index].ScanCode;
|
|
|
|
KeyData->Key.UnicodeChar = InputKey[Index].UnicodeChar;
|
|
|
|
KeyData->KeyState.KeyShiftState = KeyShiftStateLeft;
|
|
|
|
|
|
|
|
Index++;
|
|
|
|
KeyData++;
|
|
|
|
} while (Index < HotkeyLeft->CodeCount);
|
|
|
|
InsertTailList (&mHotkeyList, &HotkeyLeft->Link);
|
|
|
|
|
|
|
|
if (KeyShiftStateLeft != KeyShiftStateRight) {
|
|
|
|
//
|
|
|
|
// Need an extra hotkey for shift key on right
|
|
|
|
//
|
|
|
|
HotkeyRight = AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION), HotkeyLeft);
|
|
|
|
if (HotkeyRight == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
Index = 0;
|
|
|
|
KeyData = &HotkeyRight->KeyData[0];
|
|
|
|
do {
|
|
|
|
//
|
|
|
|
// Key.ScanCode and Key.UnicodeChar have already been initialized,
|
|
|
|
// only need to update KeyState.KeyShiftState
|
|
|
|
//
|
|
|
|
KeyData->KeyState.KeyShiftState = KeyShiftStateRight;
|
|
|
|
|
|
|
|
Index++;
|
|
|
|
KeyData++;
|
|
|
|
} while (Index < HotkeyRight->CodeCount);
|
|
|
|
InsertTailList (&mHotkeyList, &HotkeyRight->Link);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-10-18 09:31:49 +02:00
|
|
|
/**
|
|
|
|
Return TRUE when the variable pointed by Name and Guid is a Key#### variable.
|
|
|
|
|
|
|
|
@param Name The name of the variable.
|
|
|
|
@param Guid The GUID of the variable.
|
|
|
|
@param OptionNumber Return the option number parsed from the Name.
|
|
|
|
|
|
|
|
@retval TRUE The variable pointed by Name and Guid is a Key#### variable.
|
|
|
|
@retval FALSE The variable pointed by Name and Guid isn't a Key#### variable.
|
|
|
|
**/
|
|
|
|
BOOLEAN
|
|
|
|
IsKeyOptionVariable (
|
|
|
|
CHAR16 *Name,
|
|
|
|
EFI_GUID *Guid,
|
|
|
|
UINT16 *OptionNumber
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN Index;
|
2018-06-27 15:06:35 +02:00
|
|
|
|
2012-10-18 09:31:49 +02:00
|
|
|
if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||
|
2012-10-19 01:52:37 +02:00
|
|
|
(StrSize (Name) != sizeof (L"Key####")) ||
|
2012-10-18 09:31:49 +02:00
|
|
|
(StrnCmp (Name, L"Key", 3) != 0)
|
|
|
|
) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*OptionNumber = 0;
|
|
|
|
for (Index = 3; Index < 7; Index++) {
|
|
|
|
if ((Name[Index] >= L'0') && (Name[Index] <= L'9')) {
|
2014-09-22 07:37:16 +02:00
|
|
|
*OptionNumber = *OptionNumber * 16 + Name[Index] - L'0';
|
2012-10-18 09:31:49 +02:00
|
|
|
} else if ((Name[Index] >= L'A') && (Name[Index] <= L'F')) {
|
2014-09-22 07:37:16 +02:00
|
|
|
*OptionNumber = *OptionNumber * 16 + Name[Index] - L'A' + 10;
|
2012-10-18 09:31:49 +02:00
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Return an array of key option numbers.
|
|
|
|
|
|
|
|
@param Count Return the count of key option numbers.
|
|
|
|
|
|
|
|
@return UINT16* Pointer to an array of key option numbers;
|
|
|
|
**/
|
|
|
|
UINT16 *
|
|
|
|
EFIAPI
|
|
|
|
HotkeyGetOptionNumbers (
|
|
|
|
OUT UINTN *Count
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN Index;
|
|
|
|
CHAR16 *Name;
|
|
|
|
EFI_GUID Guid;
|
|
|
|
UINTN NameSize;
|
|
|
|
UINTN NewNameSize;
|
|
|
|
UINT16 *OptionNumbers;
|
|
|
|
UINT16 OptionNumber;
|
|
|
|
|
|
|
|
if (Count == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*Count = 0;
|
|
|
|
OptionNumbers = NULL;
|
|
|
|
|
|
|
|
NameSize = sizeof (CHAR16);
|
|
|
|
Name = AllocateZeroPool (NameSize);
|
2012-10-23 08:42:32 +02:00
|
|
|
ASSERT (Name != NULL);
|
2012-10-18 09:31:49 +02:00
|
|
|
while (TRUE) {
|
|
|
|
NewNameSize = NameSize;
|
|
|
|
Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
|
|
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
Name = ReallocatePool (NameSize, NewNameSize, Name);
|
2012-10-23 08:42:32 +02:00
|
|
|
ASSERT (Name != NULL);
|
2012-10-18 09:31:49 +02:00
|
|
|
Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
|
|
|
|
NameSize = NewNameSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Status == EFI_NOT_FOUND) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
if (IsKeyOptionVariable (Name ,&Guid, &OptionNumber)) {
|
|
|
|
OptionNumbers = ReallocatePool (
|
|
|
|
*Count * sizeof (UINT16),
|
|
|
|
(*Count + 1) * sizeof (UINT16),
|
|
|
|
OptionNumbers
|
|
|
|
);
|
2012-10-23 08:42:32 +02:00
|
|
|
ASSERT (OptionNumbers != NULL);
|
2012-10-18 09:31:49 +02:00
|
|
|
for (Index = 0; Index < *Count; Index++) {
|
|
|
|
if (OptionNumber < OptionNumbers[Index]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CopyMem (&OptionNumbers[Index + 1], &OptionNumbers[Index], (*Count - Index) * sizeof (UINT16));
|
|
|
|
OptionNumbers[Index] = OptionNumber;
|
|
|
|
(*Count)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FreePool (Name);
|
|
|
|
|
|
|
|
return OptionNumbers;
|
|
|
|
}
|
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
|
|
|
|
|
|
|
|
@retval EFI_SUCCESS Hotkey services successfully initialized.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
InitializeHotkeyService (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT32 BootOptionSupport;
|
2012-10-18 09:31:49 +02:00
|
|
|
UINT16 *KeyOptionNumbers;
|
|
|
|
UINTN KeyOptionCount;
|
2009-01-23 08:24:55 +01:00
|
|
|
UINTN Index;
|
2012-10-18 09:31:49 +02:00
|
|
|
CHAR16 KeyOptionName[8];
|
2009-01-23 08:24:55 +01:00
|
|
|
EFI_KEY_OPTION *KeyOption;
|
|
|
|
|
|
|
|
//
|
2012-08-01 10:09:15 +02:00
|
|
|
// Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP.
|
2009-04-09 09:56:28 +02:00
|
|
|
// with maximum number of key presses of 3
|
2012-08-01 10:09:15 +02:00
|
|
|
// Do not report the hotkey capability if PcdConInConnectOnDemand is enabled.
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
2012-08-01 10:09:15 +02:00
|
|
|
BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP;
|
|
|
|
if (!PcdGetBool (PcdConInConnectOnDemand)) {
|
|
|
|
BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;
|
|
|
|
SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);
|
|
|
|
}
|
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
Status = gRT->SetVariable (
|
|
|
|
L"BootOptionSupport",
|
|
|
|
&gEfiGlobalVariableGuid,
|
2009-04-09 09:56:28 +02:00
|
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
2009-01-23 08:24:55 +01:00
|
|
|
sizeof (UINT32),
|
|
|
|
&BootOptionSupport
|
|
|
|
);
|
2014-03-25 03:38:54 +01:00
|
|
|
//
|
|
|
|
// Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
|
|
|
|
//
|
2012-10-18 09:31:49 +02:00
|
|
|
ASSERT_EFI_ERROR (Status);
|
2009-01-23 08:24:55 +01:00
|
|
|
|
2012-10-18 09:31:49 +02:00
|
|
|
KeyOptionNumbers = HotkeyGetOptionNumbers (&KeyOptionCount);
|
|
|
|
for (Index = 0; Index < KeyOptionCount; Index ++) {
|
|
|
|
UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumbers[Index]);
|
2012-10-19 02:00:35 +02:00
|
|
|
GetEfiGlobalVariable2 (KeyOptionName, (VOID **) &KeyOption, NULL);
|
2012-10-18 09:31:49 +02:00
|
|
|
ASSERT (KeyOption != NULL);
|
|
|
|
if (IsKeyOptionValid (KeyOption)) {
|
2009-01-23 08:24:55 +01:00
|
|
|
HotkeyInsertList (KeyOption);
|
|
|
|
}
|
2012-10-18 09:31:49 +02:00
|
|
|
FreePool (KeyOption);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (KeyOptionNumbers != NULL) {
|
|
|
|
FreePool (KeyOptionNumbers);
|
2009-01-23 08:24:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Register Protocol notify for Hotkey service
|
|
|
|
//
|
|
|
|
Status = gBS->CreateEvent (
|
|
|
|
EVT_NOTIFY_SIGNAL,
|
|
|
|
TPL_CALLBACK,
|
|
|
|
HotkeyEvent,
|
|
|
|
NULL,
|
|
|
|
&mHotkeyEvent
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Register for protocol notifications on this event
|
|
|
|
//
|
|
|
|
Status = gBS->RegisterProtocolNotify (
|
|
|
|
&gEfiSimpleTextInputExProtocolGuid,
|
|
|
|
mHotkeyEvent,
|
|
|
|
&mHotkeyRegistration
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|