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;
 | |
| }
 | |
| 
 |