Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong <eric.dong@intel.com> Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16150 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			598 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			598 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Provides a way for 3rd party applications to register themselves for launch by the
 | 
						|
  Boot Manager based on hot key
 | 
						|
 | 
						|
Copyright (c) 2007 - 2014, Intel Corporation. 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 "Hotkey.h"
 | 
						|
 | 
						|
 | 
						|
LIST_ENTRY        mHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList);
 | 
						|
BDS_COMMON_OPTION *mHotkeyBootOption = NULL;
 | 
						|
EFI_EVENT         mHotkeyEvent;
 | 
						|
VOID              *mHotkeyRegistration;
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Try to boot the boot option triggered by hotkey.
 | 
						|
  @retval  EFI_SUCCESS             There is HotkeyBootOption & it is processed
 | 
						|
  @retval  EFI_NOT_FOUND           There is no HotkeyBootOption
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
HotkeyBoot (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{ 
 | 
						|
  EFI_STATUS           Status;
 | 
						|
  UINTN                ExitDataSize;
 | 
						|
  CHAR16               *ExitData;
 | 
						|
 | 
						|
  if (mHotkeyBootOption == NULL) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  } 
 | 
						|
  
 | 
						|
  BdsLibConnectDevicePath (mHotkeyBootOption->DevicePath);
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear the screen before launch this BootOption
 | 
						|
  //
 | 
						|
  gST->ConOut->Reset (gST->ConOut, FALSE);
 | 
						|
 | 
						|
  Status = BdsLibBootViaBootOption (mHotkeyBootOption, mHotkeyBootOption->DevicePath, &ExitDataSize, &ExitData);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Call platform action to indicate the boot fail
 | 
						|
    //
 | 
						|
    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);
 | 
						|
 | 
						|
  mHotkeyBootOption = NULL;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  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
 | 
						|
EFIAPI
 | 
						|
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;
 | 
						|
 | 
						|
  if (mHotkeyBootOption != NULL) {
 | 
						|
    //
 | 
						|
    // Do not process sequential hotkey stroke until the current boot option returns
 | 
						|
    //
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  Status                 = EFI_SUCCESS;
 | 
						|
 | 
						|
  for ( Link = GetFirstNode (&mHotkeyList)
 | 
						|
      ; !IsNull (&mHotkeyList, Link)
 | 
						|
      ; Link = GetNextNode (&mHotkeyList, Link)
 | 
						|
      ) {
 | 
						|
    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) &&
 | 
						|
        (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
 | 
						|
        (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ? 
 | 
						|
          (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
 | 
						|
        )
 | 
						|
       ) {
 | 
						|
      //
 | 
						|
      // For hotkey of key combination, transit to next waiting state
 | 
						|
      //
 | 
						|
      Hotkey->WaitingKey++;
 | 
						|
 | 
						|
      if (Hotkey->WaitingKey == Hotkey->CodeCount) {
 | 
						|
        //
 | 
						|
        // Received the whole key stroke sequence
 | 
						|
        //
 | 
						|
        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);
 | 
						|
      mHotkeyBootOption = BdsLibVariableToOption (&BootLists, Buffer);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  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 ++;
 | 
						|
    } while ((Index < Hotkey->CodeCount) && (Index < (sizeof (Hotkey->KeyData) / sizeof (EFI_KEY_DATA))));
 | 
						|
 | 
						|
    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;
 | 
						|
  EFI_BOOT_KEY_DATA  KeyOptions;
 | 
						|
  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;
 | 
						|
 | 
						|
  KeyOptions = KeyOption->KeyData;
 | 
						|
 | 
						|
  HotkeyLeft->CodeCount = (UINT8) KeyOptions.Options.InputKeyCount;
 | 
						|
 | 
						|
  //
 | 
						|
  // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
 | 
						|
  //
 | 
						|
  KeyShiftStateRight = EFI_SHIFT_STATE_VALID;
 | 
						|
  if (KeyOptions.Options.ShiftPressed) {
 | 
						|
    KeyShiftStateRight |= EFI_RIGHT_SHIFT_PRESSED;
 | 
						|
  }
 | 
						|
  if (KeyOptions.Options.ControlPressed) {
 | 
						|
    KeyShiftStateRight |= EFI_RIGHT_CONTROL_PRESSED;
 | 
						|
  }
 | 
						|
  if (KeyOptions.Options.AltPressed) {
 | 
						|
    KeyShiftStateRight |= EFI_RIGHT_ALT_PRESSED;
 | 
						|
  }
 | 
						|
  if (KeyOptions.Options.LogoPressed) {
 | 
						|
    KeyShiftStateRight |= EFI_RIGHT_LOGO_PRESSED;
 | 
						|
  }
 | 
						|
  if (KeyOptions.Options.MenuPressed) {
 | 
						|
    KeyShiftStateRight |= EFI_MENU_KEY_PRESSED;
 | 
						|
  }
 | 
						|
  if (KeyOptions.Options.SysReqPressed) {
 | 
						|
    KeyShiftStateRight |= EFI_SYS_REQ_PRESSED;
 | 
						|
  }
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
  
 | 
						|
  if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||
 | 
						|
      (StrSize (Name) != sizeof (L"Key####")) ||
 | 
						|
      (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')) {
 | 
						|
      *OptionNumber = *OptionNumber * 16 + Name[Index] - L'0';
 | 
						|
    } else if ((Name[Index] >= L'A') && (Name[Index] <= L'F')) {
 | 
						|
      *OptionNumber = *OptionNumber * 16 + Name[Index] - L'A' + 10;
 | 
						|
    } 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);
 | 
						|
  ASSERT (Name != NULL);
 | 
						|
  while (TRUE) {
 | 
						|
    NewNameSize = NameSize;
 | 
						|
    Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
 | 
						|
    if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
      Name = ReallocatePool (NameSize, NewNameSize, Name);
 | 
						|
      ASSERT (Name != NULL);
 | 
						|
      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
 | 
						|
                        );
 | 
						|
      ASSERT (OptionNumbers != NULL);
 | 
						|
      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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  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;
 | 
						|
  UINT16          *KeyOptionNumbers;
 | 
						|
  UINTN           KeyOptionCount;
 | 
						|
  UINTN           Index;
 | 
						|
  CHAR16          KeyOptionName[8];
 | 
						|
  EFI_KEY_OPTION  *KeyOption;
 | 
						|
 | 
						|
  //
 | 
						|
  // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP.
 | 
						|
  // with maximum number of key presses of 3
 | 
						|
  // Do not report the hotkey capability if PcdConInConnectOnDemand is enabled.
 | 
						|
  //
 | 
						|
  BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP;
 | 
						|
  if (!PcdGetBool (PcdConInConnectOnDemand)) {
 | 
						|
    BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;
 | 
						|
    SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  L"BootOptionSupport",
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | 
						|
                  sizeof (UINT32),
 | 
						|
                  &BootOptionSupport
 | 
						|
                  );
 | 
						|
  //
 | 
						|
  // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
 | 
						|
  //
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  KeyOptionNumbers = HotkeyGetOptionNumbers (&KeyOptionCount);
 | 
						|
  for (Index = 0; Index < KeyOptionCount; Index ++) {
 | 
						|
    UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumbers[Index]);
 | 
						|
    GetEfiGlobalVariable2 (KeyOptionName, (VOID **) &KeyOption, NULL);
 | 
						|
    ASSERT (KeyOption != NULL);
 | 
						|
    if (IsKeyOptionValid (KeyOption)) {
 | 
						|
      HotkeyInsertList (KeyOption);
 | 
						|
    }
 | 
						|
    FreePool (KeyOption);
 | 
						|
  }
 | 
						|
 | 
						|
  if (KeyOptionNumbers != NULL) {
 | 
						|
    FreePool (KeyOptionNumbers);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 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;
 | 
						|
}
 | 
						|
 |