3 Copyright (c) 2007 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Provides a way for 3rd party applications to register themselves for launch by the
19 Boot Manager based on hot key
28 LIST_ENTRY mHotkeyList
= INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList
);
29 BOOLEAN mHotkeyCallbackPending
= FALSE
;
30 EFI_EVENT mHotkeyEvent
;
31 VOID
*mHotkeyRegistration
;
36 IN EFI_KEY_OPTION
*KeyOption
42 Check if the Key Option is valid or not.
46 KeyOption - The Hot Key Option to be checked.
50 TRUE - The Hot Key Option is valid.
51 FALSE - The Hot Key Option is invalid.
55 UINT16 BootOptionName
[10];
61 // Check whether corresponding Boot Option exist
63 UnicodeSPrint (BootOptionName
, sizeof (BootOptionName
), L
"Boot%04x", KeyOption
->BootOption
);
64 BootOptionVar
= BdsLibGetVariableAndSize (
66 &gEfiGlobalVariableGuid
,
70 if (BootOptionVar
== NULL
|| BootOptionSize
== 0) {
75 // Check CRC for Boot Option
77 gBS
->CalculateCrc32 (BootOptionVar
, BootOptionSize
, &Crc
);
78 FreePool (BootOptionVar
);
80 return (BOOLEAN
) ((KeyOption
->BootOptionCrc
== Crc
) ? TRUE
: FALSE
);
85 IN EFI_KEY_OPTION
*KeyOption
,
86 OUT UINT16
*KeyOptionNumber
92 Create Key#### for the given hotkey.
96 KeyOption - The Hot Key Option to be added.
97 KeyOptionNumber - The key option number for Key#### (optional).
101 EFI_SUCCESS - Register hotkey successfully.
102 EFI_INVALID_PARAMETER - The hotkey option is invalid.
106 UINT16 KeyOptionName
[10];
111 UINT16 MaxOptionNumber
;
112 UINT16 RegisterOptionNumber
;
113 EFI_KEY_OPTION
*TempOption
;
114 UINTN TempOptionSize
;
117 BOOLEAN UpdateBootOption
;
120 // Validate the given key option
122 if (!IsKeyOptionValid (KeyOption
)) {
123 return EFI_INVALID_PARAMETER
;
126 KeyOptionSize
= sizeof (EFI_KEY_OPTION
) + GET_KEY_CODE_COUNT (KeyOption
->KeyOptions
.PackedValue
) * sizeof (EFI_INPUT_KEY
);
127 UpdateBootOption
= FALSE
;
130 // check whether HotKey conflict with keys used by Setup Browser
133 KeyOrder
= BdsLibGetVariableAndSize (
135 &gEfiGlobalVariableGuid
,
138 if (KeyOrder
== NULL
) {
143 // Find free key option number
147 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
148 if (MaxOptionNumber
< KeyOrder
[Index
]) {
149 MaxOptionNumber
= KeyOrder
[Index
];
152 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOrder
[Index
]);
153 TempOption
= BdsLibGetVariableAndSize (
155 &gEfiGlobalVariableGuid
,
159 if (CompareMem (TempOption
, KeyOption
, TempOptionSize
) == 0) {
161 // Got the option, so just return
163 FreePool (TempOption
);
168 if (KeyOption
->KeyOptions
.PackedValue
== TempOption
->KeyOptions
.PackedValue
) {
169 if (GET_KEY_CODE_COUNT (KeyOption
->KeyOptions
.PackedValue
) == 0 ||
171 ((UINT8
*) TempOption
) + sizeof (EFI_KEY_OPTION
),
172 ((UINT8
*) KeyOption
) + sizeof (EFI_KEY_OPTION
),
173 KeyOptionSize
- sizeof (EFI_KEY_OPTION
)
176 // Hotkey is the same but BootOption changed, need update
178 UpdateBootOption
= TRUE
;
183 FreePool (TempOption
);
186 if (UpdateBootOption
) {
187 RegisterOptionNumber
= KeyOrder
[Index
];
188 FreePool (TempOption
);
190 RegisterOptionNumber
= (UINT16
) (MaxOptionNumber
+ 1);
193 if (KeyOptionNumber
!= NULL
) {
194 *KeyOptionNumber
= RegisterOptionNumber
;
198 // Create variable Key####
200 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", RegisterOptionNumber
);
201 Status
= gRT
->SetVariable (
203 &gEfiGlobalVariableGuid
,
204 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
208 if (EFI_ERROR (Status
)) {
209 gBS
->FreePool (KeyOrder
);
214 // Update the key order variable - "KeyOrder"
216 if (!UpdateBootOption
) {
217 Index
= KeyOrderSize
/ sizeof (UINT16
);
218 KeyOrderSize
+= sizeof (UINT16
);
221 NewKeyOrder
= AllocatePool (KeyOrderSize
);
222 if (NewKeyOrder
== NULL
) {
223 return EFI_OUT_OF_RESOURCES
;
226 if (KeyOrder
!= NULL
) {
227 CopyMem (NewKeyOrder
, KeyOrder
, KeyOrderSize
);
230 NewKeyOrder
[Index
] = RegisterOptionNumber
;
232 Status
= gRT
->SetVariable (
234 &gEfiGlobalVariableGuid
,
235 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
241 FreePool (NewKeyOrder
);
248 IN UINT16 KeyOptionNumber
254 Delete Key#### for the given Key Option number.
258 KeyOptionNumber - Key option number for Key####
262 EFI_SUCCESS - Unregister hotkey successfully.
263 EFI_NOT_FOUND - No Key#### is found for the given Key Option number.
267 UINT16 KeyOption
[10];
275 // Delete variable Key####
277 UnicodeSPrint (KeyOption
, sizeof (KeyOption
), L
"Key%04x", KeyOptionNumber
);
280 &gEfiGlobalVariableGuid
,
281 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
287 // Adjust key order array
289 KeyOrder
= BdsLibGetVariableAndSize (
291 &gEfiGlobalVariableGuid
,
294 if (KeyOrder
== NULL
) {
299 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
300 if (KeyOrder
[Index
] == KeyOptionNumber
) {
306 if (Index
!= KeyOrderSize
/ sizeof (UINT16
)) {
308 // KeyOptionNumber found in "KeyOrder", delete it
310 for (Index
= Index2Del
; Index
< KeyOrderSize
/ sizeof (UINT16
) - 1; Index
++) {
311 KeyOrder
[Index
] = KeyOrder
[Index
+ 1];
314 KeyOrderSize
-= sizeof (UINT16
);
317 Status
= gRT
->SetVariable (
319 &gEfiGlobalVariableGuid
,
320 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
332 IN EFI_KEY_DATA
*KeyData
338 This is the common notification function for HotKeys, it will be registered
339 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
343 KeyData - A pointer to a buffer that is filled in with the keystroke
344 information for the key that was pressed.
348 EFI_SUCCESS - KeyData is successfully processed.
352 BOOLEAN HotkeyCatched
;
353 LIST_ENTRY BootLists
;
355 BDS_HOTKEY_OPTION
*Hotkey
;
357 BDS_COMMON_OPTION
*BootOption
;
362 EFI_KEY_DATA
*HotkeyData
;
364 if (mHotkeyCallbackPending
) {
366 // When responsing to a Hotkey, ignore sequential hotkey stroke until
367 // the current Boot#### load option returned
372 Status
= EFI_SUCCESS
;
373 Link
= GetFirstNode (&mHotkeyList
);
375 while (!IsNull (&mHotkeyList
, Link
)) {
376 HotkeyCatched
= FALSE
;
377 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
380 // Is this Key Stroke we are waiting for?
382 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
383 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
384 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
385 ((HotkeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) ? (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : 1)) {
387 // Receive an expecting key stroke
389 if (Hotkey
->CodeCount
> 1) {
391 // For hotkey of key combination, transit to next waiting state
393 Hotkey
->WaitingKey
++;
395 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
397 // Received the whole key stroke sequence
399 HotkeyCatched
= TRUE
;
403 // For hotkey of single key stroke
405 HotkeyCatched
= TRUE
;
409 // Receive an unexpected key stroke, reset to initial waiting state
411 Hotkey
->WaitingKey
= 0;
416 // Reset to initial waiting state
418 Hotkey
->WaitingKey
= 0;
421 // Launch its BootOption
423 InitializeListHead (&BootLists
);
425 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", Hotkey
->BootOptionNumber
);
426 BootOption
= BdsLibVariableToOption (&BootLists
, Buffer
);
427 BootOption
->BootCurrent
= Hotkey
->BootOptionNumber
;
428 BdsLibConnectDevicePath (BootOption
->DevicePath
);
431 // Clear the screen before launch this BootOption
433 gST
->ConOut
->Reset (gST
->ConOut
, FALSE
);
436 // BdsLibBootViaBootOption() is expected to be invoked at TPL level TPL_APPLICATION,
437 // so raise the TPL to TPL_APPLICATION first, then restore it
439 OldTpl
= gBS
->RaiseTPL (TPL_APPLICATION
);
441 mHotkeyCallbackPending
= TRUE
;
442 Status
= BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
443 mHotkeyCallbackPending
= FALSE
;
445 gBS
->RestoreTPL (OldTpl
);
447 if (EFI_ERROR (Status
)) {
449 // Call platform action to indicate the boot fail
451 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_FAILED
));
452 PlatformBdsBootFail (BootOption
, Status
, ExitData
, ExitDataSize
);
455 // Call platform action to indicate the boot success
457 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED
));
458 PlatformBdsBootSuccess (BootOption
);
462 Link
= GetNextNode (&mHotkeyList
, Link
);
469 HotkeyRegisterNotify (
470 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
476 Register the common HotKey notify function to given SimpleTextInEx protocol instance.
480 SimpleTextInEx - Simple Text Input Ex protocol instance
484 EFI_SUCCESS - Register hotkey notification function successfully.
485 EFI_OUT_OF_RESOURCES - Unable to allocate necessary data structures.
492 BDS_HOTKEY_OPTION
*Hotkey
;
495 // Register notification function for each hotkey
497 Link
= GetFirstNode (&mHotkeyList
);
499 while (!IsNull (&mHotkeyList
, Link
)) {
500 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
504 Status
= SimpleTextInEx
->RegisterKeyNotify (
506 &Hotkey
->KeyData
[Index
],
508 &Hotkey
->NotifyHandle
510 if (EFI_ERROR (Status
)) {
512 // some of the hotkey registry failed
517 } while (Index
< Hotkey
->CodeCount
);
519 Link
= GetNextNode (&mHotkeyList
, Link
);
534 Callback function for SimpleTextInEx protocol install events
538 Standard event notification function arguments:
539 Event - the event that is signaled.
540 Context - not used here.
549 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
;
552 BufferSize
= sizeof (EFI_HANDLE
);
553 Status
= gBS
->LocateHandle (
560 if (EFI_ERROR (Status
)) {
562 // If no more notification events exist
567 Status
= gBS
->HandleProtocol (
569 &gEfiSimpleTextInputExProtocolGuid
,
570 (VOID
**) &SimpleTextInEx
572 ASSERT_EFI_ERROR (Status
);
574 HotkeyRegisterNotify (SimpleTextInEx
);
580 IN EFI_KEY_OPTION
*KeyOption
586 Insert Key Option to hotkey list.
590 KeyOption - The Hot Key Option to be added to hotkey list.
594 EFI_SUCCESS - Add to hotkey list success.
598 BDS_HOTKEY_OPTION
*HotkeyLeft
;
599 BDS_HOTKEY_OPTION
*HotkeyRight
;
602 UINT32 KeyShiftStateLeft
;
603 UINT32 KeyShiftStateRight
;
604 EFI_INPUT_KEY
*InputKey
;
605 EFI_KEY_DATA
*KeyData
;
607 HotkeyLeft
= AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION
));
608 if (HotkeyLeft
== NULL
) {
609 return EFI_OUT_OF_RESOURCES
;
612 HotkeyLeft
->Signature
= BDS_HOTKEY_OPTION_SIGNATURE
;
613 HotkeyLeft
->BootOptionNumber
= KeyOption
->BootOption
;
615 KeyOptions
= KeyOption
->KeyOptions
.PackedValue
;
617 HotkeyLeft
->CodeCount
= (UINT8
) GET_KEY_CODE_COUNT (KeyOptions
);
620 // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
622 KeyShiftStateRight
= (KeyOptions
& EFI_KEY_OPTION_SHIFT
) |
623 ((KeyOptions
& EFI_KEY_OPTION_CONTROL
) << 1) |
624 ((KeyOptions
& EFI_KEY_OPTION_ALT
) << 2) |
625 ((KeyOptions
& EFI_KEY_OPTION_LOGO
) << 3) |
626 ((KeyOptions
& (EFI_KEY_OPTION_MENU
| EFI_KEY_OPTION_SYSREQ
)) << 4) |
627 EFI_SHIFT_STATE_VALID
;
629 KeyShiftStateLeft
= (KeyShiftStateRight
& 0xffffff00) | ((KeyShiftStateRight
& 0xff) << 1);
631 InputKey
= (EFI_INPUT_KEY
*) (((UINT8
*) KeyOption
) + sizeof (EFI_KEY_OPTION
));
634 KeyData
= &HotkeyLeft
->KeyData
[0];
637 // If Key CodeCount is 0, then only KeyData[0] is used;
638 // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
640 KeyData
->Key
.ScanCode
= InputKey
[Index
].ScanCode
;
641 KeyData
->Key
.UnicodeChar
= InputKey
[Index
].UnicodeChar
;
642 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateLeft
;
646 } while (Index
< HotkeyLeft
->CodeCount
);
647 InsertTailList (&mHotkeyList
, &HotkeyLeft
->Link
);
649 if (KeyShiftStateLeft
!= KeyShiftStateRight
) {
651 // Need an extra hotkey for shift key on right
653 HotkeyRight
= AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION
), HotkeyLeft
);
654 if (HotkeyRight
== NULL
) {
655 return EFI_OUT_OF_RESOURCES
;
659 KeyData
= &HotkeyRight
->KeyData
[0];
662 // Key.ScanCode and Key.UnicodeChar have already been initialized,
663 // only need to update KeyState.KeyShiftState
665 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateRight
;
669 } while (Index
< HotkeyRight
->CodeCount
);
670 InsertTailList (&mHotkeyList
, &HotkeyRight
->Link
);
677 InitializeHotkeyService (
684 Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
692 EFI_SUCCESS - Hotkey services successfully initialized.
697 UINT32 BootOptionSupport
;
701 UINT16 KeyOptionName
[8];
703 EFI_KEY_OPTION
*KeyOption
;
706 // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP
708 BootOptionSupport
= EFI_BOOT_OPTION_SUPPORT_KEY
| EFI_BOOT_OPTION_SUPPORT_APP
;
709 Status
= gRT
->SetVariable (
710 L
"BootOptionSupport",
711 &gEfiGlobalVariableGuid
,
712 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
718 // Get valid Key Option List from private EFI variable "KeyOrder"
720 KeyOrder
= BdsLibGetVariableAndSize (
722 &gEfiGlobalVariableGuid
,
726 if (KeyOrder
== NULL
) {
727 return EFI_NOT_FOUND
;
730 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
731 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOrder
[Index
]);
732 KeyOption
= BdsLibGetVariableAndSize (
734 &gEfiGlobalVariableGuid
,
738 if (KeyOption
== NULL
|| !IsKeyOptionValid (KeyOption
)) {
739 UnregisterHotkey (KeyOrder
[Index
]);
741 HotkeyInsertList (KeyOption
);
746 // Register Protocol notify for Hotkey service
748 Status
= gBS
->CreateEvent (
755 ASSERT_EFI_ERROR (Status
);
758 // Register for protocol notifications on this event
760 Status
= gBS
->RegisterProtocolNotify (
761 &gEfiSimpleTextInputExProtocolGuid
,
765 ASSERT_EFI_ERROR (Status
);