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