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