2 Provides a way for 3rd party applications to register themselves for launch by the
3 Boot Manager based on hot key
5 Copyright (c) 2007 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 LIST_ENTRY mHotkeyList
= INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList
);
20 BDS_COMMON_OPTION
*mHotkeyBootOption
= NULL
;
21 EFI_EVENT mHotkeyEvent
;
22 VOID
*mHotkeyRegistration
;
26 Check if the Key Option is valid or not.
28 @param KeyOption The Hot Key Option to be checked.
30 @retval TRUE The Hot Key Option is valid.
31 @retval FALSE The Hot Key Option is invalid.
36 IN EFI_KEY_OPTION
*KeyOption
39 UINT16 BootOptionName
[10];
45 // Check whether corresponding Boot Option exist
47 UnicodeSPrint (BootOptionName
, sizeof (BootOptionName
), L
"Boot%04x", KeyOption
->BootOption
);
48 BootOptionVar
= BdsLibGetVariableAndSize (
50 &gEfiGlobalVariableGuid
,
54 if (BootOptionVar
== NULL
|| BootOptionSize
== 0) {
59 // Check CRC for Boot Option
61 gBS
->CalculateCrc32 (BootOptionVar
, BootOptionSize
, &Crc
);
62 FreePool (BootOptionVar
);
64 return (BOOLEAN
) ((KeyOption
->BootOptionCrc
== Crc
) ? TRUE
: FALSE
);
68 Create Key#### for the given hotkey.
70 @param KeyOption The Hot Key Option to be added.
71 @param KeyOptionNumber The key option number for Key#### (optional).
73 @retval EFI_SUCCESS Register hotkey successfully.
74 @retval EFI_INVALID_PARAMETER The hotkey option is invalid.
75 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource.
80 IN EFI_KEY_OPTION
*KeyOption
,
81 OUT UINT16
*KeyOptionNumber
84 UINT16 KeyOptionName
[10];
89 UINT16 MaxOptionNumber
;
90 UINT16 RegisterOptionNumber
;
91 EFI_KEY_OPTION
*TempOption
;
95 BOOLEAN UpdateBootOption
;
98 // Validate the given key option
100 if (!IsKeyOptionValid (KeyOption
)) {
101 return EFI_INVALID_PARAMETER
;
104 KeyOptionSize
= sizeof (EFI_KEY_OPTION
) + KeyOption
->KeyData
.Options
.InputKeyCount
* sizeof (EFI_INPUT_KEY
);
105 UpdateBootOption
= FALSE
;
108 // Check whether HotKey conflict with keys used by Setup Browser
110 KeyOrder
= BdsLibGetVariableAndSize (
112 &gEfiGlobalVariableGuid
,
115 if (KeyOrder
== NULL
) {
120 // Find free key option number
124 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
125 if (MaxOptionNumber
< KeyOrder
[Index
]) {
126 MaxOptionNumber
= KeyOrder
[Index
];
129 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOrder
[Index
]);
130 TempOption
= BdsLibGetVariableAndSize (
132 &gEfiGlobalVariableGuid
,
135 ASSERT (TempOption
!= NULL
);
137 if (CompareMem (TempOption
, KeyOption
, TempOptionSize
) == 0) {
139 // Got the option, so just return
141 FreePool (TempOption
);
146 if (KeyOption
->KeyData
.PackedValue
== TempOption
->KeyData
.PackedValue
) {
147 if (KeyOption
->KeyData
.Options
.InputKeyCount
== 0 ||
149 ((UINT8
*) TempOption
) + sizeof (EFI_KEY_OPTION
),
150 ((UINT8
*) KeyOption
) + sizeof (EFI_KEY_OPTION
),
151 KeyOptionSize
- sizeof (EFI_KEY_OPTION
)
154 // Hotkey is the same but BootOption changed, need update
156 UpdateBootOption
= TRUE
;
161 FreePool (TempOption
);
164 if (UpdateBootOption
) {
165 RegisterOptionNumber
= KeyOrder
[Index
];
166 FreePool (TempOption
);
168 RegisterOptionNumber
= (UINT16
) (MaxOptionNumber
+ 1);
171 if (KeyOptionNumber
!= NULL
) {
172 *KeyOptionNumber
= RegisterOptionNumber
;
176 // Create variable Key####
178 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", RegisterOptionNumber
);
179 Status
= gRT
->SetVariable (
181 &gEfiGlobalVariableGuid
,
182 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
186 if (EFI_ERROR (Status
)) {
192 // Update the key order variable - "KeyOrder"
194 if (!UpdateBootOption
) {
195 Index
= KeyOrderSize
/ sizeof (UINT16
);
196 KeyOrderSize
+= sizeof (UINT16
);
199 NewKeyOrder
= AllocatePool (KeyOrderSize
);
200 if (NewKeyOrder
== NULL
) {
202 return EFI_OUT_OF_RESOURCES
;
205 if (KeyOrder
!= NULL
) {
206 CopyMem (NewKeyOrder
, KeyOrder
, KeyOrderSize
);
209 NewKeyOrder
[Index
] = RegisterOptionNumber
;
211 Status
= gRT
->SetVariable (
213 &gEfiGlobalVariableGuid
,
214 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
220 FreePool (NewKeyOrder
);
227 Delete Key#### for the given Key Option number.
229 @param KeyOptionNumber Key option number for Key####
231 @retval EFI_SUCCESS Unregister hotkey successfully.
232 @retval EFI_NOT_FOUND No Key#### is found for the given Key Option number.
237 IN UINT16 KeyOptionNumber
240 UINT16 KeyOption
[10];
248 // Delete variable Key####
250 UnicodeSPrint (KeyOption
, sizeof (KeyOption
), L
"Key%04x", KeyOptionNumber
);
253 &gEfiGlobalVariableGuid
,
254 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
260 // Adjust key order array
262 KeyOrder
= BdsLibGetVariableAndSize (
264 &gEfiGlobalVariableGuid
,
267 if (KeyOrder
== NULL
) {
272 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
273 if (KeyOrder
[Index
] == KeyOptionNumber
) {
279 if (Index
!= KeyOrderSize
/ sizeof (UINT16
)) {
281 // KeyOptionNumber found in "KeyOrder", delete it
283 for (Index
= Index2Del
; Index
< KeyOrderSize
/ sizeof (UINT16
) - 1; Index
++) {
284 KeyOrder
[Index
] = KeyOrder
[Index
+ 1];
287 KeyOrderSize
-= sizeof (UINT16
);
290 Status
= gRT
->SetVariable (
292 &gEfiGlobalVariableGuid
,
293 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
304 Try to boot the boot option triggered by hotkey.
305 @retval EFI_SUCCESS There is HotkeyBootOption & it is processed
306 @retval EFI_NOT_FOUND There is no HotkeyBootOption
317 if (mHotkeyBootOption
== NULL
) {
318 return EFI_NOT_FOUND
;
321 BdsLibConnectDevicePath (mHotkeyBootOption
->DevicePath
);
324 // Clear the screen before launch this BootOption
326 gST
->ConOut
->Reset (gST
->ConOut
, FALSE
);
328 Status
= BdsLibBootViaBootOption (mHotkeyBootOption
, mHotkeyBootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
330 if (EFI_ERROR (Status
)) {
332 // Call platform action to indicate the boot fail
334 mHotkeyBootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_FAILED
));
335 PlatformBdsBootFail (mHotkeyBootOption
, Status
, ExitData
, ExitDataSize
);
338 // Call platform action to indicate the boot success
340 mHotkeyBootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED
));
341 PlatformBdsBootSuccess (mHotkeyBootOption
);
343 FreePool (mHotkeyBootOption
->Description
);
344 FreePool (mHotkeyBootOption
->DevicePath
);
345 FreePool (mHotkeyBootOption
->LoadOptions
);
346 FreePool (mHotkeyBootOption
);
348 mHotkeyBootOption
= NULL
;
355 This is the common notification function for HotKeys, it will be registered
356 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
358 @param KeyData A pointer to a buffer that is filled in with the keystroke
359 information for the key that was pressed.
361 @retval EFI_SUCCESS KeyData is successfully processed.
362 @return EFI_NOT_FOUND Fail to find boot option variable.
367 IN EFI_KEY_DATA
*KeyData
370 BOOLEAN HotkeyCatched
;
371 LIST_ENTRY BootLists
;
373 BDS_HOTKEY_OPTION
*Hotkey
;
376 EFI_KEY_DATA
*HotkeyData
;
378 if (mHotkeyBootOption
!= NULL
) {
380 // Do not process sequential hotkey stroke until the current boot option returns
385 Status
= EFI_SUCCESS
;
387 for ( Link
= GetFirstNode (&mHotkeyList
)
388 ; !IsNull (&mHotkeyList
, Link
)
389 ; Link
= GetNextNode (&mHotkeyList
, Link
)
391 HotkeyCatched
= FALSE
;
392 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
395 // Is this Key Stroke we are waiting for?
397 ASSERT (Hotkey
->WaitingKey
< (sizeof (Hotkey
->KeyData
) / sizeof (Hotkey
->KeyData
[0])));
398 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
399 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
400 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
401 (((KeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) != 0) ?
402 (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : TRUE
406 // For hotkey of key combination, transit to next waiting state
408 Hotkey
->WaitingKey
++;
410 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
412 // Received the whole key stroke sequence
414 HotkeyCatched
= TRUE
;
418 // Receive an unexpected key stroke, reset to initial waiting state
420 Hotkey
->WaitingKey
= 0;
425 // Reset to initial waiting state
427 Hotkey
->WaitingKey
= 0;
430 // Launch its BootOption
432 InitializeListHead (&BootLists
);
434 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", Hotkey
->BootOptionNumber
);
435 mHotkeyBootOption
= BdsLibVariableToOption (&BootLists
, Buffer
);
443 Register the common HotKey notify function to given SimpleTextInEx protocol instance.
445 @param SimpleTextInEx Simple Text Input Ex protocol instance
447 @retval EFI_SUCCESS Register hotkey notification function successfully.
448 @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures.
452 HotkeyRegisterNotify (
453 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
459 BDS_HOTKEY_OPTION
*Hotkey
;
462 // Register notification function for each hotkey
464 Link
= GetFirstNode (&mHotkeyList
);
466 while (!IsNull (&mHotkeyList
, Link
)) {
467 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
471 Status
= SimpleTextInEx
->RegisterKeyNotify (
473 &Hotkey
->KeyData
[Index
],
475 &Hotkey
->NotifyHandle
477 if (EFI_ERROR (Status
)) {
479 // some of the hotkey registry failed
484 } while ((Index
< Hotkey
->CodeCount
) && (Index
< (sizeof (Hotkey
->KeyData
) / sizeof (EFI_KEY_DATA
))));
486 Link
= GetNextNode (&mHotkeyList
, Link
);
493 Callback function for SimpleTextInEx protocol install events
495 @param Event the event that is signaled.
496 @param Context not used here.
509 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
;
512 BufferSize
= sizeof (EFI_HANDLE
);
513 Status
= gBS
->LocateHandle (
520 if (EFI_ERROR (Status
)) {
522 // If no more notification events exist
527 Status
= gBS
->HandleProtocol (
529 &gEfiSimpleTextInputExProtocolGuid
,
530 (VOID
**) &SimpleTextInEx
532 ASSERT_EFI_ERROR (Status
);
534 HotkeyRegisterNotify (SimpleTextInEx
);
539 Insert Key Option to hotkey list.
541 @param KeyOption The Hot Key Option to be added to hotkey list.
543 @retval EFI_SUCCESS Add to hotkey list success.
544 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource.
548 IN EFI_KEY_OPTION
*KeyOption
551 BDS_HOTKEY_OPTION
*HotkeyLeft
;
552 BDS_HOTKEY_OPTION
*HotkeyRight
;
554 EFI_BOOT_KEY_DATA KeyOptions
;
555 UINT32 KeyShiftStateLeft
;
556 UINT32 KeyShiftStateRight
;
557 EFI_INPUT_KEY
*InputKey
;
558 EFI_KEY_DATA
*KeyData
;
560 HotkeyLeft
= AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION
));
561 if (HotkeyLeft
== NULL
) {
562 return EFI_OUT_OF_RESOURCES
;
565 HotkeyLeft
->Signature
= BDS_HOTKEY_OPTION_SIGNATURE
;
566 HotkeyLeft
->BootOptionNumber
= KeyOption
->BootOption
;
568 KeyOptions
= KeyOption
->KeyData
;
570 HotkeyLeft
->CodeCount
= (UINT8
) KeyOptions
.Options
.InputKeyCount
;
573 // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
575 KeyShiftStateRight
= EFI_SHIFT_STATE_VALID
;
576 if (KeyOptions
.Options
.ShiftPressed
) {
577 KeyShiftStateRight
|= EFI_RIGHT_SHIFT_PRESSED
;
579 if (KeyOptions
.Options
.ControlPressed
) {
580 KeyShiftStateRight
|= EFI_RIGHT_CONTROL_PRESSED
;
582 if (KeyOptions
.Options
.AltPressed
) {
583 KeyShiftStateRight
|= EFI_RIGHT_ALT_PRESSED
;
585 if (KeyOptions
.Options
.LogoPressed
) {
586 KeyShiftStateRight
|= EFI_RIGHT_LOGO_PRESSED
;
588 if (KeyOptions
.Options
.MenuPressed
) {
589 KeyShiftStateRight
|= EFI_MENU_KEY_PRESSED
;
591 if (KeyOptions
.Options
.SysReqPressed
) {
592 KeyShiftStateRight
|= EFI_SYS_REQ_PRESSED
;
596 KeyShiftStateLeft
= (KeyShiftStateRight
& 0xffffff00) | ((KeyShiftStateRight
& 0xff) << 1);
598 InputKey
= (EFI_INPUT_KEY
*) (((UINT8
*) KeyOption
) + sizeof (EFI_KEY_OPTION
));
601 KeyData
= &HotkeyLeft
->KeyData
[0];
604 // If Key CodeCount is 0, then only KeyData[0] is used;
605 // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
607 KeyData
->Key
.ScanCode
= InputKey
[Index
].ScanCode
;
608 KeyData
->Key
.UnicodeChar
= InputKey
[Index
].UnicodeChar
;
609 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateLeft
;
613 } while (Index
< HotkeyLeft
->CodeCount
);
614 InsertTailList (&mHotkeyList
, &HotkeyLeft
->Link
);
616 if (KeyShiftStateLeft
!= KeyShiftStateRight
) {
618 // Need an extra hotkey for shift key on right
620 HotkeyRight
= AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION
), HotkeyLeft
);
621 if (HotkeyRight
== NULL
) {
622 return EFI_OUT_OF_RESOURCES
;
626 KeyData
= &HotkeyRight
->KeyData
[0];
629 // Key.ScanCode and Key.UnicodeChar have already been initialized,
630 // only need to update KeyState.KeyShiftState
632 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateRight
;
636 } while (Index
< HotkeyRight
->CodeCount
);
637 InsertTailList (&mHotkeyList
, &HotkeyRight
->Link
);
645 Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
647 @retval EFI_SUCCESS Hotkey services successfully initialized.
648 @retval EFI_NOT_FOUND Can not find the "KeyOrder" variable
651 InitializeHotkeyService (
656 UINT32 BootOptionSupport
;
660 UINT16 KeyOptionName
[8];
662 EFI_KEY_OPTION
*KeyOption
;
665 // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP
666 // with maximum number of key presses of 3
668 BootOptionSupport
= EFI_BOOT_OPTION_SUPPORT_KEY
| EFI_BOOT_OPTION_SUPPORT_APP
;
669 SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport
, 3);
670 Status
= gRT
->SetVariable (
671 L
"BootOptionSupport",
672 &gEfiGlobalVariableGuid
,
673 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
679 // Get valid Key Option List from private EFI variable "KeyOrder"
681 KeyOrder
= BdsLibGetVariableAndSize (
683 &gEfiGlobalVariableGuid
,
687 if (KeyOrder
== NULL
) {
688 return EFI_NOT_FOUND
;
691 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
692 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOrder
[Index
]);
693 KeyOption
= BdsLibGetVariableAndSize (
695 &gEfiGlobalVariableGuid
,
699 if (KeyOption
== NULL
|| !IsKeyOptionValid (KeyOption
)) {
700 UnregisterHotkey (KeyOrder
[Index
]);
702 HotkeyInsertList (KeyOption
);
707 // Register Protocol notify for Hotkey service
709 Status
= gBS
->CreateEvent (
716 ASSERT_EFI_ERROR (Status
);
719 // Register for protocol notifications on this event
721 Status
= gBS
->RegisterProtocolNotify (
722 &gEfiSimpleTextInputExProtocolGuid
,
726 ASSERT_EFI_ERROR (Status
);