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