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 - 2008, Intel Corporation. <BR>
6 All rights reserved. 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 BOOLEAN mHotkeyCallbackPending
= FALSE
;
21 EFI_EVENT mHotkeyEvent
;
22 VOID
*mHotkeyRegistration
;
27 IN EFI_KEY_OPTION
*KeyOption
33 Check if the Key Option is valid or not.
37 KeyOption - The Hot Key Option to be checked.
41 TRUE - The Hot Key Option is valid.
42 FALSE - The Hot Key Option is invalid.
46 UINT16 BootOptionName
[10];
52 // Check whether corresponding Boot Option exist
54 UnicodeSPrint (BootOptionName
, sizeof (BootOptionName
), L
"Boot%04x", KeyOption
->BootOption
);
55 BootOptionVar
= BdsLibGetVariableAndSize (
57 &gEfiGlobalVariableGuid
,
61 if (BootOptionVar
== NULL
|| BootOptionSize
== 0) {
66 // Check CRC for Boot Option
68 gBS
->CalculateCrc32 (BootOptionVar
, BootOptionSize
, &Crc
);
69 FreePool (BootOptionVar
);
71 return (BOOLEAN
) ((KeyOption
->BootOptionCrc
== Crc
) ? TRUE
: FALSE
);
76 IN EFI_KEY_OPTION
*KeyOption
,
77 OUT UINT16
*KeyOptionNumber
83 Create Key#### for the given hotkey.
87 KeyOption - The Hot Key Option to be added.
88 KeyOptionNumber - The key option number for Key#### (optional).
92 EFI_SUCCESS - Register hotkey successfully.
93 EFI_INVALID_PARAMETER - The hotkey option is invalid.
97 UINT16 KeyOptionName
[10];
102 UINT16 MaxOptionNumber
;
103 UINT16 RegisterOptionNumber
;
104 EFI_KEY_OPTION
*TempOption
;
105 UINTN TempOptionSize
;
108 BOOLEAN UpdateBootOption
;
111 // Validate the given key option
113 if (!IsKeyOptionValid (KeyOption
)) {
114 return EFI_INVALID_PARAMETER
;
117 KeyOptionSize
= sizeof (EFI_KEY_OPTION
) + GET_KEY_CODE_COUNT (KeyOption
->KeyOptions
.PackedValue
) * sizeof (EFI_INPUT_KEY
);
118 UpdateBootOption
= FALSE
;
121 // check whether HotKey conflict with keys used by Setup Browser
124 KeyOrder
= BdsLibGetVariableAndSize (
126 &gEfiGlobalVariableGuid
,
129 if (KeyOrder
== NULL
) {
134 // Find free key option number
138 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
139 if (MaxOptionNumber
< KeyOrder
[Index
]) {
140 MaxOptionNumber
= KeyOrder
[Index
];
143 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOrder
[Index
]);
144 TempOption
= BdsLibGetVariableAndSize (
146 &gEfiGlobalVariableGuid
,
150 if (CompareMem (TempOption
, KeyOption
, TempOptionSize
) == 0) {
152 // Got the option, so just return
154 FreePool (TempOption
);
159 if (KeyOption
->KeyOptions
.PackedValue
== TempOption
->KeyOptions
.PackedValue
) {
160 if (GET_KEY_CODE_COUNT (KeyOption
->KeyOptions
.PackedValue
) == 0 ||
162 ((UINT8
*) TempOption
) + sizeof (EFI_KEY_OPTION
),
163 ((UINT8
*) KeyOption
) + sizeof (EFI_KEY_OPTION
),
164 KeyOptionSize
- sizeof (EFI_KEY_OPTION
)
167 // Hotkey is the same but BootOption changed, need update
169 UpdateBootOption
= TRUE
;
174 FreePool (TempOption
);
177 if (UpdateBootOption
) {
178 RegisterOptionNumber
= KeyOrder
[Index
];
179 FreePool (TempOption
);
181 RegisterOptionNumber
= (UINT16
) (MaxOptionNumber
+ 1);
184 if (KeyOptionNumber
!= NULL
) {
185 *KeyOptionNumber
= RegisterOptionNumber
;
189 // Create variable Key####
191 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", RegisterOptionNumber
);
192 Status
= gRT
->SetVariable (
194 &gEfiGlobalVariableGuid
,
195 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
199 if (EFI_ERROR (Status
)) {
200 gBS
->FreePool (KeyOrder
);
205 // Update the key order variable - "KeyOrder"
207 if (!UpdateBootOption
) {
208 Index
= KeyOrderSize
/ sizeof (UINT16
);
209 KeyOrderSize
+= sizeof (UINT16
);
212 NewKeyOrder
= AllocatePool (KeyOrderSize
);
213 if (NewKeyOrder
== NULL
) {
214 return EFI_OUT_OF_RESOURCES
;
217 if (KeyOrder
!= NULL
) {
218 CopyMem (NewKeyOrder
, KeyOrder
, KeyOrderSize
);
221 NewKeyOrder
[Index
] = RegisterOptionNumber
;
223 Status
= gRT
->SetVariable (
225 &gEfiGlobalVariableGuid
,
226 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
232 FreePool (NewKeyOrder
);
239 IN UINT16 KeyOptionNumber
245 Delete Key#### for the given Key Option number.
249 KeyOptionNumber - Key option number for Key####
253 EFI_SUCCESS - Unregister hotkey successfully.
254 EFI_NOT_FOUND - No Key#### is found for the given Key Option number.
258 UINT16 KeyOption
[10];
266 // Delete variable Key####
268 UnicodeSPrint (KeyOption
, sizeof (KeyOption
), L
"Key%04x", KeyOptionNumber
);
271 &gEfiGlobalVariableGuid
,
272 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
278 // Adjust key order array
280 KeyOrder
= BdsLibGetVariableAndSize (
282 &gEfiGlobalVariableGuid
,
285 if (KeyOrder
== NULL
) {
290 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
291 if (KeyOrder
[Index
] == KeyOptionNumber
) {
297 if (Index
!= KeyOrderSize
/ sizeof (UINT16
)) {
299 // KeyOptionNumber found in "KeyOrder", delete it
301 for (Index
= Index2Del
; Index
< KeyOrderSize
/ sizeof (UINT16
) - 1; Index
++) {
302 KeyOrder
[Index
] = KeyOrder
[Index
+ 1];
305 KeyOrderSize
-= sizeof (UINT16
);
308 Status
= gRT
->SetVariable (
310 &gEfiGlobalVariableGuid
,
311 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
323 IN EFI_KEY_DATA
*KeyData
329 This is the common notification function for HotKeys, it will be registered
330 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
334 KeyData - A pointer to a buffer that is filled in with the keystroke
335 information for the key that was pressed.
339 EFI_SUCCESS - KeyData is successfully processed.
343 BOOLEAN HotkeyCatched
;
344 LIST_ENTRY BootLists
;
346 BDS_HOTKEY_OPTION
*Hotkey
;
348 BDS_COMMON_OPTION
*BootOption
;
353 EFI_KEY_DATA
*HotkeyData
;
355 if (mHotkeyCallbackPending
) {
357 // When responsing to a Hotkey, ignore sequential hotkey stroke until
358 // the current Boot#### load option returned
363 Status
= EFI_SUCCESS
;
364 Link
= GetFirstNode (&mHotkeyList
);
366 while (!IsNull (&mHotkeyList
, Link
)) {
367 HotkeyCatched
= FALSE
;
368 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
371 // Is this Key Stroke we are waiting for?
373 HotkeyData
= &Hotkey
->KeyData
[Hotkey
->WaitingKey
];
374 if ((KeyData
->Key
.ScanCode
== HotkeyData
->Key
.ScanCode
) &&
375 (KeyData
->Key
.UnicodeChar
== HotkeyData
->Key
.UnicodeChar
) &&
376 ((HotkeyData
->KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) ? (KeyData
->KeyState
.KeyShiftState
== HotkeyData
->KeyState
.KeyShiftState
) : 1)) {
378 // Receive an expecting key stroke
380 if (Hotkey
->CodeCount
> 1) {
382 // For hotkey of key combination, transit to next waiting state
384 Hotkey
->WaitingKey
++;
386 if (Hotkey
->WaitingKey
== Hotkey
->CodeCount
) {
388 // Received the whole key stroke sequence
390 HotkeyCatched
= TRUE
;
394 // For hotkey of single key stroke
396 HotkeyCatched
= TRUE
;
400 // Receive an unexpected key stroke, reset to initial waiting state
402 Hotkey
->WaitingKey
= 0;
407 // Reset to initial waiting state
409 Hotkey
->WaitingKey
= 0;
412 // Launch its BootOption
414 InitializeListHead (&BootLists
);
416 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", Hotkey
->BootOptionNumber
);
417 BootOption
= BdsLibVariableToOption (&BootLists
, Buffer
);
418 BootOption
->BootCurrent
= Hotkey
->BootOptionNumber
;
419 BdsLibConnectDevicePath (BootOption
->DevicePath
);
422 // Clear the screen before launch this BootOption
424 gST
->ConOut
->Reset (gST
->ConOut
, FALSE
);
427 // BdsLibBootViaBootOption() is expected to be invoked at TPL level TPL_APPLICATION,
428 // so raise the TPL to TPL_APPLICATION first, then restore it
430 OldTpl
= gBS
->RaiseTPL (TPL_APPLICATION
);
432 mHotkeyCallbackPending
= TRUE
;
433 Status
= BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
434 mHotkeyCallbackPending
= FALSE
;
436 gBS
->RestoreTPL (OldTpl
);
438 if (EFI_ERROR (Status
)) {
440 // Call platform action to indicate the boot fail
442 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_FAILED
));
443 PlatformBdsBootFail (BootOption
, Status
, ExitData
, ExitDataSize
);
446 // Call platform action to indicate the boot success
448 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED
));
449 PlatformBdsBootSuccess (BootOption
);
453 Link
= GetNextNode (&mHotkeyList
, Link
);
460 HotkeyRegisterNotify (
461 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
467 Register the common HotKey notify function to given SimpleTextInEx protocol instance.
471 SimpleTextInEx - Simple Text Input Ex protocol instance
475 EFI_SUCCESS - Register hotkey notification function successfully.
476 EFI_OUT_OF_RESOURCES - Unable to allocate necessary data structures.
483 BDS_HOTKEY_OPTION
*Hotkey
;
486 // Register notification function for each hotkey
488 Link
= GetFirstNode (&mHotkeyList
);
490 while (!IsNull (&mHotkeyList
, Link
)) {
491 Hotkey
= BDS_HOTKEY_OPTION_FROM_LINK (Link
);
495 Status
= SimpleTextInEx
->RegisterKeyNotify (
497 &Hotkey
->KeyData
[Index
],
499 &Hotkey
->NotifyHandle
501 if (EFI_ERROR (Status
)) {
503 // some of the hotkey registry failed
508 } while (Index
< Hotkey
->CodeCount
);
510 Link
= GetNextNode (&mHotkeyList
, Link
);
525 Callback function for SimpleTextInEx protocol install events
529 Standard event notification function arguments:
530 Event - the event that is signaled.
531 Context - not used here.
540 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleTextInEx
;
543 BufferSize
= sizeof (EFI_HANDLE
);
544 Status
= gBS
->LocateHandle (
551 if (EFI_ERROR (Status
)) {
553 // If no more notification events exist
558 Status
= gBS
->HandleProtocol (
560 &gEfiSimpleTextInputExProtocolGuid
,
561 (VOID
**) &SimpleTextInEx
563 ASSERT_EFI_ERROR (Status
);
565 HotkeyRegisterNotify (SimpleTextInEx
);
571 IN EFI_KEY_OPTION
*KeyOption
577 Insert Key Option to hotkey list.
581 KeyOption - The Hot Key Option to be added to hotkey list.
585 EFI_SUCCESS - Add to hotkey list success.
589 BDS_HOTKEY_OPTION
*HotkeyLeft
;
590 BDS_HOTKEY_OPTION
*HotkeyRight
;
593 UINT32 KeyShiftStateLeft
;
594 UINT32 KeyShiftStateRight
;
595 EFI_INPUT_KEY
*InputKey
;
596 EFI_KEY_DATA
*KeyData
;
598 HotkeyLeft
= AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION
));
599 if (HotkeyLeft
== NULL
) {
600 return EFI_OUT_OF_RESOURCES
;
603 HotkeyLeft
->Signature
= BDS_HOTKEY_OPTION_SIGNATURE
;
604 HotkeyLeft
->BootOptionNumber
= KeyOption
->BootOption
;
606 KeyOptions
= KeyOption
->KeyOptions
.PackedValue
;
608 HotkeyLeft
->CodeCount
= (UINT8
) GET_KEY_CODE_COUNT (KeyOptions
);
611 // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
613 KeyShiftStateRight
= (KeyOptions
& EFI_KEY_OPTION_SHIFT
) |
614 ((KeyOptions
& EFI_KEY_OPTION_CONTROL
) << 1) |
615 ((KeyOptions
& EFI_KEY_OPTION_ALT
) << 2) |
616 ((KeyOptions
& EFI_KEY_OPTION_LOGO
) << 3) |
617 ((KeyOptions
& (EFI_KEY_OPTION_MENU
| EFI_KEY_OPTION_SYSREQ
)) << 4) |
618 EFI_SHIFT_STATE_VALID
;
620 KeyShiftStateLeft
= (KeyShiftStateRight
& 0xffffff00) | ((KeyShiftStateRight
& 0xff) << 1);
622 InputKey
= (EFI_INPUT_KEY
*) (((UINT8
*) KeyOption
) + sizeof (EFI_KEY_OPTION
));
625 KeyData
= &HotkeyLeft
->KeyData
[0];
628 // If Key CodeCount is 0, then only KeyData[0] is used;
629 // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
631 KeyData
->Key
.ScanCode
= InputKey
[Index
].ScanCode
;
632 KeyData
->Key
.UnicodeChar
= InputKey
[Index
].UnicodeChar
;
633 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateLeft
;
637 } while (Index
< HotkeyLeft
->CodeCount
);
638 InsertTailList (&mHotkeyList
, &HotkeyLeft
->Link
);
640 if (KeyShiftStateLeft
!= KeyShiftStateRight
) {
642 // Need an extra hotkey for shift key on right
644 HotkeyRight
= AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION
), HotkeyLeft
);
645 if (HotkeyRight
== NULL
) {
646 return EFI_OUT_OF_RESOURCES
;
650 KeyData
= &HotkeyRight
->KeyData
[0];
653 // Key.ScanCode and Key.UnicodeChar have already been initialized,
654 // only need to update KeyState.KeyShiftState
656 KeyData
->KeyState
.KeyShiftState
= KeyShiftStateRight
;
660 } while (Index
< HotkeyRight
->CodeCount
);
661 InsertTailList (&mHotkeyList
, &HotkeyRight
->Link
);
668 InitializeHotkeyService (
675 Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
683 EFI_SUCCESS - Hotkey services successfully initialized.
688 UINT32 BootOptionSupport
;
692 UINT16 KeyOptionName
[8];
694 EFI_KEY_OPTION
*KeyOption
;
697 // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP
699 BootOptionSupport
= EFI_BOOT_OPTION_SUPPORT_KEY
| EFI_BOOT_OPTION_SUPPORT_APP
;
700 Status
= gRT
->SetVariable (
701 L
"BootOptionSupport",
702 &gEfiGlobalVariableGuid
,
703 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
709 // Get valid Key Option List from private EFI variable "KeyOrder"
711 KeyOrder
= BdsLibGetVariableAndSize (
713 &gEfiGlobalVariableGuid
,
717 if (KeyOrder
== NULL
) {
718 return EFI_NOT_FOUND
;
721 for (Index
= 0; Index
< KeyOrderSize
/ sizeof (UINT16
); Index
++) {
722 UnicodeSPrint (KeyOptionName
, sizeof (KeyOptionName
), L
"Key%04x", KeyOrder
[Index
]);
723 KeyOption
= BdsLibGetVariableAndSize (
725 &gEfiGlobalVariableGuid
,
729 if (KeyOption
== NULL
|| !IsKeyOptionValid (KeyOption
)) {
730 UnregisterHotkey (KeyOrder
[Index
]);
732 HotkeyInsertList (KeyOption
);
737 // Register Protocol notify for Hotkey service
739 Status
= gBS
->CreateEvent (
746 ASSERT_EFI_ERROR (Status
);
749 // Register for protocol notifications on this event
751 Status
= gBS
->RegisterProtocolNotify (
752 &gEfiSimpleTextInputExProtocolGuid
,
756 ASSERT_EFI_ERROR (Status
);