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