]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/Hotkey.c
Clean up BootMaint module in BdsDxe.
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / Hotkey.c
1 /** @file
2 Provides a way for 3rd party applications to register themselves for launch by the
3 Boot Manager based on hot key
4
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
10
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.
13
14 **/
15
16 #include "Hotkey.h"
17
18
19 LIST_ENTRY mHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList);
20 BOOLEAN mHotkeyCallbackPending = FALSE;
21 EFI_EVENT mHotkeyEvent;
22 VOID *mHotkeyRegistration;
23
24
25 /**
26
27 Check if the Key Option is valid or not.
28
29
30 @param KeyOption The Hot Key Option to be checked.
31
32 @retval TRUE The Hot Key Option is valid.
33 @retval FALSE The Hot Key Option is invalid.
34
35 **/
36 BOOLEAN
37 IsKeyOptionValid (
38 IN EFI_KEY_OPTION *KeyOption
39 )
40 {
41 UINT16 BootOptionName[10];
42 UINT8 *BootOptionVar;
43 UINTN BootOptionSize;
44 UINT32 Crc;
45
46 //
47 // Check whether corresponding Boot Option exist
48 //
49 UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", KeyOption->BootOption);
50 BootOptionVar = BdsLibGetVariableAndSize (
51 BootOptionName,
52 &gEfiGlobalVariableGuid,
53 &BootOptionSize
54 );
55
56 if (BootOptionVar == NULL || BootOptionSize == 0) {
57 return FALSE;
58 }
59
60 //
61 // Check CRC for Boot Option
62 //
63 gBS->CalculateCrc32 (BootOptionVar, BootOptionSize, &Crc);
64 FreePool (BootOptionVar);
65
66 return (BOOLEAN) ((KeyOption->BootOptionCrc == Crc) ? TRUE : FALSE);
67 }
68
69 /**
70
71 Create Key#### for the given hotkey.
72
73
74 @param KeyOption The Hot Key Option to be added.
75 @param KeyOptionNumber The key option number for Key#### (optional).
76
77 @retval EFI_SUCCESS Register hotkey successfully.
78 @retval EFI_INVALID_PARAMETER The hotkey option is invalid.
79
80 **/
81 EFI_STATUS
82 RegisterHotkey (
83 IN EFI_KEY_OPTION *KeyOption,
84 OUT UINT16 *KeyOptionNumber
85 )
86 {
87 UINT16 KeyOptionName[10];
88 UINT16 *KeyOrder;
89 UINTN KeyOrderSize;
90 UINT16 *NewKeyOrder;
91 UINTN Index;
92 UINT16 MaxOptionNumber;
93 UINT16 RegisterOptionNumber;
94 EFI_KEY_OPTION *TempOption;
95 UINTN TempOptionSize;
96 EFI_STATUS Status;
97 UINTN KeyOptionSize;
98 BOOLEAN UpdateBootOption;
99
100 //
101 // Validate the given key option
102 //
103 if (!IsKeyOptionValid (KeyOption)) {
104 return EFI_INVALID_PARAMETER;
105 }
106
107 KeyOptionSize = sizeof (EFI_KEY_OPTION) + GET_KEY_CODE_COUNT (KeyOption->KeyOptions.PackedValue) * sizeof (EFI_INPUT_KEY);
108 UpdateBootOption = FALSE;
109
110 //
111 // check whether HotKey conflict with keys used by Setup Browser
112 //
113
114 KeyOrder = BdsLibGetVariableAndSize (
115 VarKeyOrder,
116 &gEfiGlobalVariableGuid,
117 &KeyOrderSize
118 );
119 if (KeyOrder == NULL) {
120 KeyOrderSize = 0;
121 }
122
123 //
124 // Find free key option number
125 //
126 MaxOptionNumber = 0;
127 TempOption = NULL;
128 for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index++) {
129 if (MaxOptionNumber < KeyOrder[Index]) {
130 MaxOptionNumber = KeyOrder[Index];
131 }
132
133 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOrder[Index]);
134 TempOption = BdsLibGetVariableAndSize (
135 KeyOptionName,
136 &gEfiGlobalVariableGuid,
137 &TempOptionSize
138 );
139
140 if (CompareMem (TempOption, KeyOption, TempOptionSize) == 0) {
141 //
142 // Got the option, so just return
143 //
144 FreePool (TempOption);
145 FreePool (KeyOrder);
146 return EFI_SUCCESS;
147 }
148
149 if (KeyOption->KeyOptions.PackedValue == TempOption->KeyOptions.PackedValue) {
150 if (GET_KEY_CODE_COUNT (KeyOption->KeyOptions.PackedValue) == 0 ||
151 CompareMem (
152 ((UINT8 *) TempOption) + sizeof (EFI_KEY_OPTION),
153 ((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION),
154 KeyOptionSize - sizeof (EFI_KEY_OPTION)
155 ) == 0) {
156 //
157 // Hotkey is the same but BootOption changed, need update
158 //
159 UpdateBootOption = TRUE;
160 break;
161 }
162 }
163
164 FreePool (TempOption);
165 }
166
167 if (UpdateBootOption) {
168 RegisterOptionNumber = KeyOrder[Index];
169 FreePool (TempOption);
170 } else {
171 RegisterOptionNumber = (UINT16) (MaxOptionNumber + 1);
172 }
173
174 if (KeyOptionNumber != NULL) {
175 *KeyOptionNumber = RegisterOptionNumber;
176 }
177
178 //
179 // Create variable Key####
180 //
181 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", RegisterOptionNumber);
182 Status = gRT->SetVariable (
183 KeyOptionName,
184 &gEfiGlobalVariableGuid,
185 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
186 KeyOptionSize,
187 KeyOption
188 );
189 if (EFI_ERROR (Status)) {
190 gBS->FreePool (KeyOrder);
191 return Status;
192 }
193
194 //
195 // Update the key order variable - "KeyOrder"
196 //
197 if (!UpdateBootOption) {
198 Index = KeyOrderSize / sizeof (UINT16);
199 KeyOrderSize += sizeof (UINT16);
200 }
201
202 NewKeyOrder = AllocatePool (KeyOrderSize);
203 if (NewKeyOrder == NULL) {
204 return EFI_OUT_OF_RESOURCES;
205 }
206
207 if (KeyOrder != NULL) {
208 CopyMem (NewKeyOrder, KeyOrder, KeyOrderSize);
209 }
210
211 NewKeyOrder[Index] = RegisterOptionNumber;
212
213 Status = gRT->SetVariable (
214 VarKeyOrder,
215 &gEfiGlobalVariableGuid,
216 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
217 KeyOrderSize,
218 NewKeyOrder
219 );
220
221 FreePool (KeyOrder);
222 FreePool (NewKeyOrder);
223
224 return Status;
225 }
226
227 /**
228
229 Delete Key#### for the given Key Option number.
230
231
232 @param KeyOptionNumber Key option number for Key####
233
234 @retval EFI_SUCCESS Unregister hotkey successfully.
235 @retval EFI_NOT_FOUND No Key#### is found for the given Key Option number.
236
237 **/
238 EFI_STATUS
239 UnregisterHotkey (
240 IN UINT16 KeyOptionNumber
241 )
242 {
243 UINT16 KeyOption[10];
244 UINTN Index;
245 EFI_STATUS Status;
246 UINTN Index2Del;
247 UINT16 *KeyOrder;
248 UINTN KeyOrderSize;
249
250 //
251 // Delete variable Key####
252 //
253 UnicodeSPrint (KeyOption, sizeof (KeyOption), L"Key%04x", KeyOptionNumber);
254 gRT->SetVariable (
255 KeyOption,
256 &gEfiGlobalVariableGuid,
257 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
258 0,
259 NULL
260 );
261
262 //
263 // Adjust key order array
264 //
265 KeyOrder = BdsLibGetVariableAndSize (
266 VarKeyOrder,
267 &gEfiGlobalVariableGuid,
268 &KeyOrderSize
269 );
270 if (KeyOrder == NULL) {
271 return EFI_SUCCESS;
272 }
273
274 Index2Del = 0;
275 for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index++) {
276 if (KeyOrder[Index] == KeyOptionNumber) {
277 Index2Del = Index;
278 break;
279 }
280 }
281
282 if (Index != KeyOrderSize / sizeof (UINT16)) {
283 //
284 // KeyOptionNumber found in "KeyOrder", delete it
285 //
286 for (Index = Index2Del; Index < KeyOrderSize / sizeof (UINT16) - 1; Index++) {
287 KeyOrder[Index] = KeyOrder[Index + 1];
288 }
289
290 KeyOrderSize -= sizeof (UINT16);
291 }
292
293 Status = gRT->SetVariable (
294 VarKeyOrder,
295 &gEfiGlobalVariableGuid,
296 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
297 KeyOrderSize,
298 KeyOrder
299 );
300
301 FreePool (KeyOrder);
302
303 return Status;
304 }
305
306 /**
307
308 This is the common notification function for HotKeys, it will be registered
309 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
310
311
312 @param KeyData A pointer to a buffer that is filled in with the keystroke
313 information for the key that was pressed.
314
315 @retval EFI_SUCCESS KeyData is successfully processed.
316
317 **/
318 EFI_STATUS
319 HotkeyCallback (
320 IN EFI_KEY_DATA *KeyData
321 )
322 {
323 BOOLEAN HotkeyCatched;
324 LIST_ENTRY BootLists;
325 LIST_ENTRY *Link;
326 BDS_HOTKEY_OPTION *Hotkey;
327 UINT16 Buffer[10];
328 BDS_COMMON_OPTION *BootOption;
329 UINTN ExitDataSize;
330 CHAR16 *ExitData;
331 EFI_TPL OldTpl;
332 EFI_STATUS Status;
333 EFI_KEY_DATA *HotkeyData;
334
335 if (mHotkeyCallbackPending) {
336 //
337 // When responsing to a Hotkey, ignore sequential hotkey stroke until
338 // the current Boot#### load option returned
339 //
340 return EFI_SUCCESS;
341 }
342
343 Status = EFI_SUCCESS;
344 Link = GetFirstNode (&mHotkeyList);
345
346 while (!IsNull (&mHotkeyList, Link)) {
347 HotkeyCatched = FALSE;
348 Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
349
350 //
351 // Is this Key Stroke we are waiting for?
352 //
353 HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
354 if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
355 (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
356 ((HotkeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) ? (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : 1)) {
357 //
358 // Receive an expecting key stroke
359 //
360 if (Hotkey->CodeCount > 1) {
361 //
362 // For hotkey of key combination, transit to next waiting state
363 //
364 Hotkey->WaitingKey++;
365
366 if (Hotkey->WaitingKey == Hotkey->CodeCount) {
367 //
368 // Received the whole key stroke sequence
369 //
370 HotkeyCatched = TRUE;
371 }
372 } else {
373 //
374 // For hotkey of single key stroke
375 //
376 HotkeyCatched = TRUE;
377 }
378 } else {
379 //
380 // Receive an unexpected key stroke, reset to initial waiting state
381 //
382 Hotkey->WaitingKey = 0;
383 }
384
385 if (HotkeyCatched) {
386 //
387 // Reset to initial waiting state
388 //
389 Hotkey->WaitingKey = 0;
390
391 //
392 // Launch its BootOption
393 //
394 InitializeListHead (&BootLists);
395
396 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber);
397 BootOption = BdsLibVariableToOption (&BootLists, Buffer);
398 BootOption->BootCurrent = Hotkey->BootOptionNumber;
399 BdsLibConnectDevicePath (BootOption->DevicePath);
400
401 //
402 // Clear the screen before launch this BootOption
403 //
404 gST->ConOut->Reset (gST->ConOut, FALSE);
405
406 //
407 // BdsLibBootViaBootOption() is expected to be invoked at TPL level TPL_APPLICATION,
408 // so raise the TPL to TPL_APPLICATION first, then restore it
409 //
410 OldTpl = gBS->RaiseTPL (TPL_APPLICATION);
411
412 mHotkeyCallbackPending = TRUE;
413 Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
414 mHotkeyCallbackPending = FALSE;
415
416 gBS->RestoreTPL (OldTpl);
417
418 if (EFI_ERROR (Status)) {
419 //
420 // Call platform action to indicate the boot fail
421 //
422 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
423 PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
424 } else {
425 //
426 // Call platform action to indicate the boot success
427 //
428 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
429 PlatformBdsBootSuccess (BootOption);
430 }
431 }
432
433 Link = GetNextNode (&mHotkeyList, Link);
434 }
435
436 return Status;
437 }
438
439 /**
440
441 Register the common HotKey notify function to given SimpleTextInEx protocol instance.
442
443
444 @param SimpleTextInEx Simple Text Input Ex protocol instance
445
446 @retval EFI_SUCCESS Register hotkey notification function successfully.
447 @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures.
448
449 **/
450 EFI_STATUS
451 HotkeyRegisterNotify (
452 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx
453 )
454 {
455 UINTN Index;
456 EFI_STATUS Status;
457 LIST_ENTRY *Link;
458 BDS_HOTKEY_OPTION *Hotkey;
459
460 //
461 // Register notification function for each hotkey
462 //
463 Link = GetFirstNode (&mHotkeyList);
464
465 while (!IsNull (&mHotkeyList, Link)) {
466 Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
467
468 Index = 0;
469 do {
470 Status = SimpleTextInEx->RegisterKeyNotify (
471 SimpleTextInEx,
472 &Hotkey->KeyData[Index],
473 HotkeyCallback,
474 &Hotkey->NotifyHandle
475 );
476 if (EFI_ERROR (Status)) {
477 //
478 // some of the hotkey registry failed
479 //
480 return Status;
481 }
482 Index ++;
483 } while (Index < Hotkey->CodeCount);
484
485 Link = GetNextNode (&mHotkeyList, Link);
486 }
487
488 return EFI_SUCCESS;
489 }
490
491 /**
492 Callback function for SimpleTextInEx protocol install events
493
494
495 @param Event the event that is signaled.
496 @param Context not used here.
497
498 @return VOID
499
500 **/
501 VOID
502 EFIAPI
503 HotkeyEvent (
504 IN EFI_EVENT Event,
505 IN VOID *Context
506 )
507 {
508 EFI_STATUS Status;
509 UINTN BufferSize;
510 EFI_HANDLE Handle;
511 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;
512
513 while (TRUE) {
514 BufferSize = sizeof (EFI_HANDLE);
515 Status = gBS->LocateHandle (
516 ByRegisterNotify,
517 NULL,
518 mHotkeyRegistration,
519 &BufferSize,
520 &Handle
521 );
522 if (EFI_ERROR (Status)) {
523 //
524 // If no more notification events exist
525 //
526 return ;
527 }
528
529 Status = gBS->HandleProtocol (
530 Handle,
531 &gEfiSimpleTextInputExProtocolGuid,
532 (VOID **) &SimpleTextInEx
533 );
534 ASSERT_EFI_ERROR (Status);
535
536 HotkeyRegisterNotify (SimpleTextInEx);
537 }
538 }
539
540 /**
541
542 Insert Key Option to hotkey list.
543
544
545 @param KeyOption The Hot Key Option to be added to hotkey list.
546
547 @retval EFI_SUCCESS Add to hotkey list success.
548
549 **/
550 EFI_STATUS
551 HotkeyInsertList (
552 IN EFI_KEY_OPTION *KeyOption
553 )
554 {
555 BDS_HOTKEY_OPTION *HotkeyLeft;
556 BDS_HOTKEY_OPTION *HotkeyRight;
557 UINTN Index;
558 UINT32 KeyOptions;
559 UINT32 KeyShiftStateLeft;
560 UINT32 KeyShiftStateRight;
561 EFI_INPUT_KEY *InputKey;
562 EFI_KEY_DATA *KeyData;
563
564 HotkeyLeft = AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION));
565 if (HotkeyLeft == NULL) {
566 return EFI_OUT_OF_RESOURCES;
567 }
568
569 HotkeyLeft->Signature = BDS_HOTKEY_OPTION_SIGNATURE;
570 HotkeyLeft->BootOptionNumber = KeyOption->BootOption;
571
572 KeyOptions = KeyOption->KeyOptions.PackedValue;
573
574 HotkeyLeft->CodeCount = (UINT8) GET_KEY_CODE_COUNT (KeyOptions);
575
576 //
577 // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
578 //
579 KeyShiftStateRight = (KeyOptions & EFI_KEY_OPTION_SHIFT) |
580 ((KeyOptions & EFI_KEY_OPTION_CONTROL) << 1) |
581 ((KeyOptions & EFI_KEY_OPTION_ALT) << 2) |
582 ((KeyOptions & EFI_KEY_OPTION_LOGO) << 3) |
583 ((KeyOptions & (EFI_KEY_OPTION_MENU | EFI_KEY_OPTION_SYSREQ)) << 4) |
584 EFI_SHIFT_STATE_VALID;
585
586 KeyShiftStateLeft = (KeyShiftStateRight & 0xffffff00) | ((KeyShiftStateRight & 0xff) << 1);
587
588 InputKey = (EFI_INPUT_KEY *) (((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION));
589
590 Index = 0;
591 KeyData = &HotkeyLeft->KeyData[0];
592 do {
593 //
594 // If Key CodeCount is 0, then only KeyData[0] is used;
595 // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
596 //
597 KeyData->Key.ScanCode = InputKey[Index].ScanCode;
598 KeyData->Key.UnicodeChar = InputKey[Index].UnicodeChar;
599 KeyData->KeyState.KeyShiftState = KeyShiftStateLeft;
600
601 Index++;
602 KeyData++;
603 } while (Index < HotkeyLeft->CodeCount);
604 InsertTailList (&mHotkeyList, &HotkeyLeft->Link);
605
606 if (KeyShiftStateLeft != KeyShiftStateRight) {
607 //
608 // Need an extra hotkey for shift key on right
609 //
610 HotkeyRight = AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION), HotkeyLeft);
611 if (HotkeyRight == NULL) {
612 return EFI_OUT_OF_RESOURCES;
613 }
614
615 Index = 0;
616 KeyData = &HotkeyRight->KeyData[0];
617 do {
618 //
619 // Key.ScanCode and Key.UnicodeChar have already been initialized,
620 // only need to update KeyState.KeyShiftState
621 //
622 KeyData->KeyState.KeyShiftState = KeyShiftStateRight;
623
624 Index++;
625 KeyData++;
626 } while (Index < HotkeyRight->CodeCount);
627 InsertTailList (&mHotkeyList, &HotkeyRight->Link);
628 }
629
630 return EFI_SUCCESS;
631 }
632
633 /**
634
635 Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
636
637
638 @param VOID
639
640 @retval EFI_SUCCESS Hotkey services successfully initialized.
641
642 **/
643 EFI_STATUS
644 InitializeHotkeyService (
645 VOID
646 )
647 {
648 EFI_STATUS Status;
649 UINT32 BootOptionSupport;
650 UINT16 *KeyOrder;
651 UINTN KeyOrderSize;
652 UINTN Index;
653 UINT16 KeyOptionName[8];
654 UINTN KeyOptionSize;
655 EFI_KEY_OPTION *KeyOption;
656
657 //
658 // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP
659 //
660 BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_KEY | EFI_BOOT_OPTION_SUPPORT_APP;
661 Status = gRT->SetVariable (
662 L"BootOptionSupport",
663 &gEfiGlobalVariableGuid,
664 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
665 sizeof (UINT32),
666 &BootOptionSupport
667 );
668
669 //
670 // Get valid Key Option List from private EFI variable "KeyOrder"
671 //
672 KeyOrder = BdsLibGetVariableAndSize (
673 VarKeyOrder,
674 &gEfiGlobalVariableGuid,
675 &KeyOrderSize
676 );
677
678 if (KeyOrder == NULL) {
679 return EFI_NOT_FOUND;
680 }
681
682 for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index ++) {
683 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOrder[Index]);
684 KeyOption = BdsLibGetVariableAndSize (
685 KeyOptionName,
686 &gEfiGlobalVariableGuid,
687 &KeyOptionSize
688 );
689
690 if (KeyOption == NULL || !IsKeyOptionValid (KeyOption)) {
691 UnregisterHotkey (KeyOrder[Index]);
692 } else {
693 HotkeyInsertList (KeyOption);
694 }
695 }
696
697 //
698 // Register Protocol notify for Hotkey service
699 //
700 Status = gBS->CreateEvent (
701 EVT_NOTIFY_SIGNAL,
702 TPL_CALLBACK,
703 HotkeyEvent,
704 NULL,
705 &mHotkeyEvent
706 );
707 ASSERT_EFI_ERROR (Status);
708
709 //
710 // Register for protocol notifications on this event
711 //
712 Status = gBS->RegisterProtocolNotify (
713 &gEfiSimpleTextInputExProtocolGuid,
714 mHotkeyEvent,
715 &mHotkeyRegistration
716 );
717 ASSERT_EFI_ERROR (Status);
718
719 return Status;
720 }
721