]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/Hotkey.c
correct some spelling error.
[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 VAR_KEY_ORDER,
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 VAR_KEY_ORDER,
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 @param KeyOptionNumber Key option number for Key####
232
233 @retval EFI_SUCCESS Unregister hotkey successfully.
234 @retval EFI_NOT_FOUND No Key#### is found for the given Key Option number.
235
236 **/
237 EFI_STATUS
238 UnregisterHotkey (
239 IN UINT16 KeyOptionNumber
240 )
241 {
242 UINT16 KeyOption[10];
243 UINTN Index;
244 EFI_STATUS Status;
245 UINTN Index2Del;
246 UINT16 *KeyOrder;
247 UINTN KeyOrderSize;
248
249 //
250 // Delete variable Key####
251 //
252 UnicodeSPrint (KeyOption, sizeof (KeyOption), L"Key%04x", KeyOptionNumber);
253 gRT->SetVariable (
254 KeyOption,
255 &gEfiGlobalVariableGuid,
256 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
257 0,
258 NULL
259 );
260
261 //
262 // Adjust key order array
263 //
264 KeyOrder = BdsLibGetVariableAndSize (
265 VAR_KEY_ORDER,
266 &gEfiGlobalVariableGuid,
267 &KeyOrderSize
268 );
269 if (KeyOrder == NULL) {
270 return EFI_SUCCESS;
271 }
272
273 Index2Del = 0;
274 for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index++) {
275 if (KeyOrder[Index] == KeyOptionNumber) {
276 Index2Del = Index;
277 break;
278 }
279 }
280
281 if (Index != KeyOrderSize / sizeof (UINT16)) {
282 //
283 // KeyOptionNumber found in "KeyOrder", delete it
284 //
285 for (Index = Index2Del; Index < KeyOrderSize / sizeof (UINT16) - 1; Index++) {
286 KeyOrder[Index] = KeyOrder[Index + 1];
287 }
288
289 KeyOrderSize -= sizeof (UINT16);
290 }
291
292 Status = gRT->SetVariable (
293 VAR_KEY_ORDER,
294 &gEfiGlobalVariableGuid,
295 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
296 KeyOrderSize,
297 KeyOrder
298 );
299
300 FreePool (KeyOrder);
301
302 return Status;
303 }
304
305 /**
306
307 This is the common notification function for HotKeys, it will be registered
308 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
309
310
311 @param KeyData A pointer to a buffer that is filled in with the keystroke
312 information for the key that was pressed.
313
314 @retval EFI_SUCCESS KeyData is successfully processed.
315
316 **/
317 EFI_STATUS
318 HotkeyCallback (
319 IN EFI_KEY_DATA *KeyData
320 )
321 {
322 BOOLEAN HotkeyCatched;
323 LIST_ENTRY BootLists;
324 LIST_ENTRY *Link;
325 BDS_HOTKEY_OPTION *Hotkey;
326 UINT16 Buffer[10];
327 BDS_COMMON_OPTION *BootOption;
328 UINTN ExitDataSize;
329 CHAR16 *ExitData;
330 EFI_TPL OldTpl;
331 EFI_STATUS Status;
332 EFI_KEY_DATA *HotkeyData;
333
334 if (mHotkeyCallbackPending) {
335 //
336 // When responsing to a Hotkey, ignore sequential hotkey stroke until
337 // the current Boot#### load option returned
338 //
339 return EFI_SUCCESS;
340 }
341
342 Status = EFI_SUCCESS;
343 Link = GetFirstNode (&mHotkeyList);
344
345 while (!IsNull (&mHotkeyList, Link)) {
346 HotkeyCatched = FALSE;
347 Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
348
349 //
350 // Is this Key Stroke we are waiting for?
351 //
352 HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
353 if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
354 (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
355 ((HotkeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) ? (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : 1)) {
356 //
357 // Receive an expecting key stroke
358 //
359 if (Hotkey->CodeCount > 1) {
360 //
361 // For hotkey of key combination, transit to next waiting state
362 //
363 Hotkey->WaitingKey++;
364
365 if (Hotkey->WaitingKey == Hotkey->CodeCount) {
366 //
367 // Received the whole key stroke sequence
368 //
369 HotkeyCatched = TRUE;
370 }
371 } else {
372 //
373 // For hotkey of single key stroke
374 //
375 HotkeyCatched = TRUE;
376 }
377 } else {
378 //
379 // Receive an unexpected key stroke, reset to initial waiting state
380 //
381 Hotkey->WaitingKey = 0;
382 }
383
384 if (HotkeyCatched) {
385 //
386 // Reset to initial waiting state
387 //
388 Hotkey->WaitingKey = 0;
389
390 //
391 // Launch its BootOption
392 //
393 InitializeListHead (&BootLists);
394
395 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber);
396 BootOption = BdsLibVariableToOption (&BootLists, Buffer);
397 BootOption->BootCurrent = Hotkey->BootOptionNumber;
398 BdsLibConnectDevicePath (BootOption->DevicePath);
399
400 //
401 // Clear the screen before launch this BootOption
402 //
403 gST->ConOut->Reset (gST->ConOut, FALSE);
404
405 //
406 // BdsLibBootViaBootOption() is expected to be invoked at TPL level TPL_APPLICATION,
407 // so raise the TPL to TPL_APPLICATION first, then restore it
408 //
409 OldTpl = gBS->RaiseTPL (TPL_APPLICATION);
410
411 mHotkeyCallbackPending = TRUE;
412 Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
413 mHotkeyCallbackPending = FALSE;
414
415 gBS->RestoreTPL (OldTpl);
416
417 if (EFI_ERROR (Status)) {
418 //
419 // Call platform action to indicate the boot fail
420 //
421 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
422 PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
423 } else {
424 //
425 // Call platform action to indicate the boot success
426 //
427 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
428 PlatformBdsBootSuccess (BootOption);
429 }
430 }
431
432 Link = GetNextNode (&mHotkeyList, Link);
433 }
434
435 return Status;
436 }
437
438 /**
439
440 Register the common HotKey notify function to given SimpleTextInEx protocol instance.
441
442
443 @param SimpleTextInEx Simple Text Input Ex protocol instance
444
445 @retval EFI_SUCCESS Register hotkey notification function successfully.
446 @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures.
447
448 **/
449 EFI_STATUS
450 HotkeyRegisterNotify (
451 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx
452 )
453 {
454 UINTN Index;
455 EFI_STATUS Status;
456 LIST_ENTRY *Link;
457 BDS_HOTKEY_OPTION *Hotkey;
458
459 //
460 // Register notification function for each hotkey
461 //
462 Link = GetFirstNode (&mHotkeyList);
463
464 while (!IsNull (&mHotkeyList, Link)) {
465 Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
466
467 Index = 0;
468 do {
469 Status = SimpleTextInEx->RegisterKeyNotify (
470 SimpleTextInEx,
471 &Hotkey->KeyData[Index],
472 HotkeyCallback,
473 &Hotkey->NotifyHandle
474 );
475 if (EFI_ERROR (Status)) {
476 //
477 // some of the hotkey registry failed
478 //
479 return Status;
480 }
481 Index ++;
482 } while (Index < Hotkey->CodeCount);
483
484 Link = GetNextNode (&mHotkeyList, Link);
485 }
486
487 return EFI_SUCCESS;
488 }
489
490 /**
491 Callback function for SimpleTextInEx protocol install events
492
493
494 @param Event the event that is signaled.
495 @param Context not used here.
496
497 @return VOID
498
499 **/
500 VOID
501 EFIAPI
502 HotkeyEvent (
503 IN EFI_EVENT Event,
504 IN VOID *Context
505 )
506 {
507 EFI_STATUS Status;
508 UINTN BufferSize;
509 EFI_HANDLE Handle;
510 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;
511
512 while (TRUE) {
513 BufferSize = sizeof (EFI_HANDLE);
514 Status = gBS->LocateHandle (
515 ByRegisterNotify,
516 NULL,
517 mHotkeyRegistration,
518 &BufferSize,
519 &Handle
520 );
521 if (EFI_ERROR (Status)) {
522 //
523 // If no more notification events exist
524 //
525 return ;
526 }
527
528 Status = gBS->HandleProtocol (
529 Handle,
530 &gEfiSimpleTextInputExProtocolGuid,
531 (VOID **) &SimpleTextInEx
532 );
533 ASSERT_EFI_ERROR (Status);
534
535 HotkeyRegisterNotify (SimpleTextInEx);
536 }
537 }
538
539 /**
540
541 Insert Key Option to hotkey list.
542
543
544 @param KeyOption The Hot Key Option to be added to hotkey list.
545
546 @retval EFI_SUCCESS Add to hotkey list success.
547
548 **/
549 EFI_STATUS
550 HotkeyInsertList (
551 IN EFI_KEY_OPTION *KeyOption
552 )
553 {
554 BDS_HOTKEY_OPTION *HotkeyLeft;
555 BDS_HOTKEY_OPTION *HotkeyRight;
556 UINTN Index;
557 UINT32 KeyOptions;
558 UINT32 KeyShiftStateLeft;
559 UINT32 KeyShiftStateRight;
560 EFI_INPUT_KEY *InputKey;
561 EFI_KEY_DATA *KeyData;
562
563 HotkeyLeft = AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION));
564 if (HotkeyLeft == NULL) {
565 return EFI_OUT_OF_RESOURCES;
566 }
567
568 HotkeyLeft->Signature = BDS_HOTKEY_OPTION_SIGNATURE;
569 HotkeyLeft->BootOptionNumber = KeyOption->BootOption;
570
571 KeyOptions = KeyOption->KeyOptions.PackedValue;
572
573 HotkeyLeft->CodeCount = (UINT8) GET_KEY_CODE_COUNT (KeyOptions);
574
575 //
576 // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
577 //
578 KeyShiftStateRight = (KeyOptions & EFI_KEY_OPTION_SHIFT) |
579 ((KeyOptions & EFI_KEY_OPTION_CONTROL) << 1) |
580 ((KeyOptions & EFI_KEY_OPTION_ALT) << 2) |
581 ((KeyOptions & EFI_KEY_OPTION_LOGO) << 3) |
582 ((KeyOptions & (EFI_KEY_OPTION_MENU | EFI_KEY_OPTION_SYSREQ)) << 4) |
583 EFI_SHIFT_STATE_VALID;
584
585 KeyShiftStateLeft = (KeyShiftStateRight & 0xffffff00) | ((KeyShiftStateRight & 0xff) << 1);
586
587 InputKey = (EFI_INPUT_KEY *) (((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION));
588
589 Index = 0;
590 KeyData = &HotkeyLeft->KeyData[0];
591 do {
592 //
593 // If Key CodeCount is 0, then only KeyData[0] is used;
594 // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
595 //
596 KeyData->Key.ScanCode = InputKey[Index].ScanCode;
597 KeyData->Key.UnicodeChar = InputKey[Index].UnicodeChar;
598 KeyData->KeyState.KeyShiftState = KeyShiftStateLeft;
599
600 Index++;
601 KeyData++;
602 } while (Index < HotkeyLeft->CodeCount);
603 InsertTailList (&mHotkeyList, &HotkeyLeft->Link);
604
605 if (KeyShiftStateLeft != KeyShiftStateRight) {
606 //
607 // Need an extra hotkey for shift key on right
608 //
609 HotkeyRight = AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION), HotkeyLeft);
610 if (HotkeyRight == NULL) {
611 return EFI_OUT_OF_RESOURCES;
612 }
613
614 Index = 0;
615 KeyData = &HotkeyRight->KeyData[0];
616 do {
617 //
618 // Key.ScanCode and Key.UnicodeChar have already been initialized,
619 // only need to update KeyState.KeyShiftState
620 //
621 KeyData->KeyState.KeyShiftState = KeyShiftStateRight;
622
623 Index++;
624 KeyData++;
625 } while (Index < HotkeyRight->CodeCount);
626 InsertTailList (&mHotkeyList, &HotkeyRight->Link);
627 }
628
629 return EFI_SUCCESS;
630 }
631
632 /**
633
634 Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
635
636 @retval EFI_SUCCESS Hotkey services successfully initialized.
637 @retval EFI_NOT_FOUND Can not find the "KeyOrder" variable
638 **/
639 EFI_STATUS
640 InitializeHotkeyService (
641 VOID
642 )
643 {
644 EFI_STATUS Status;
645 UINT32 BootOptionSupport;
646 UINT16 *KeyOrder;
647 UINTN KeyOrderSize;
648 UINTN Index;
649 UINT16 KeyOptionName[8];
650 UINTN KeyOptionSize;
651 EFI_KEY_OPTION *KeyOption;
652
653 //
654 // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP
655 //
656 BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_KEY | EFI_BOOT_OPTION_SUPPORT_APP;
657 Status = gRT->SetVariable (
658 L"BootOptionSupport",
659 &gEfiGlobalVariableGuid,
660 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
661 sizeof (UINT32),
662 &BootOptionSupport
663 );
664
665 //
666 // Get valid Key Option List from private EFI variable "KeyOrder"
667 //
668 KeyOrder = BdsLibGetVariableAndSize (
669 VAR_KEY_ORDER,
670 &gEfiGlobalVariableGuid,
671 &KeyOrderSize
672 );
673
674 if (KeyOrder == NULL) {
675 return EFI_NOT_FOUND;
676 }
677
678 for (Index = 0; Index < KeyOrderSize / sizeof (UINT16); Index ++) {
679 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOrder[Index]);
680 KeyOption = BdsLibGetVariableAndSize (
681 KeyOptionName,
682 &gEfiGlobalVariableGuid,
683 &KeyOptionSize
684 );
685
686 if (KeyOption == NULL || !IsKeyOptionValid (KeyOption)) {
687 UnregisterHotkey (KeyOrder[Index]);
688 } else {
689 HotkeyInsertList (KeyOption);
690 }
691 }
692
693 //
694 // Register Protocol notify for Hotkey service
695 //
696 Status = gBS->CreateEvent (
697 EVT_NOTIFY_SIGNAL,
698 TPL_CALLBACK,
699 HotkeyEvent,
700 NULL,
701 &mHotkeyEvent
702 );
703 ASSERT_EFI_ERROR (Status);
704
705 //
706 // Register for protocol notifications on this event
707 //
708 Status = gBS->RegisterProtocolNotify (
709 &gEfiSimpleTextInputExProtocolGuid,
710 mHotkeyEvent,
711 &mHotkeyRegistration
712 );
713 ASSERT_EFI_ERROR (Status);
714
715 return Status;
716 }
717