MdeModulePkg/UefiBootManagerLib: Remove assertion
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmHotkey.c
CommitLineData
067ed98a
RN
1/** @file\r
2 Hotkey library functions.\r
3\r
ac72474d 4Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>\r
065e587c 5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
067ed98a
RN
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 "InternalBm.h"\r
17\r
18//\r
19// Lock for linked list\r
20//\r
21EFI_LOCK mBmHotkeyLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
22LIST_ENTRY mBmHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList);\r
23EFI_EVENT mBmHotkeyTriggered = NULL;\r
24BOOLEAN mBmHotkeyServiceStarted = FALSE;\r
25UINTN mBmHotkeySupportCount = 0;\r
26\r
27//\r
28// Set OptionNumber as unassigned value to indicate the option isn't initialized\r
29//\r
30EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption = { LoadOptionNumberUnassigned };\r
31\r
32EFI_BOOT_MANAGER_KEY_OPTION *mBmContinueKeyOption = NULL;\r
33VOID *mBmTxtInExRegistration = NULL;\r
34\r
121300c4
RN
35\r
36/**\r
37 Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.\r
38\r
39 @param KeyOption The input key option info.\r
40\r
41 @retval The buffer size of the key option data.\r
42**/\r
43UINTN\r
44BmSizeOfKeyOption (\r
7320b8ed 45 IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption\r
121300c4
RN
46 )\r
47{\r
48 return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)\r
49 + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);\r
50}\r
51\r
067ed98a
RN
52/**\r
53\r
54 Check whether the input key option is valid.\r
55\r
121300c4
RN
56 @param KeyOption Key option.\r
57 @param KeyOptionSize Size of the key option.\r
067ed98a
RN
58\r
59 @retval TRUE Input key option is valid.\r
60 @retval FALSE Input key option is not valid.\r
61**/\r
62BOOLEAN\r
63BmIsKeyOptionValid (\r
7320b8ed
RN
64 IN CONST EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,\r
65 IN UINTN KeyOptionSize\r
067ed98a
RN
66)\r
67{\r
f9a24380 68 UINT16 OptionName[BM_OPTION_NAME_LEN];\r
067ed98a
RN
69 UINT8 *BootOption;\r
70 UINTN BootOptionSize;\r
71 UINT32 Crc;\r
72\r
121300c4
RN
73 if (BmSizeOfKeyOption (KeyOption) != KeyOptionSize) {\r
74 return FALSE;\r
75 }\r
76\r
067ed98a
RN
77 //\r
78 // Check whether corresponding Boot Option exist\r
79 //\r
121300c4
RN
80 UnicodeSPrint (\r
81 OptionName, sizeof (OptionName), L"%s%04x",\r
82 mBmLoadOptionName[LoadOptionTypeBoot], KeyOption->BootOption\r
83 );\r
067ed98a
RN
84 GetEfiGlobalVariable2 (OptionName, (VOID **) &BootOption, &BootOptionSize);\r
85\r
86 if (BootOption == NULL) {\r
87 return FALSE;\r
88 }\r
89\r
90 //\r
91 // Check CRC for Boot Option\r
92 //\r
93 gBS->CalculateCrc32 (BootOption, BootOptionSize, &Crc);\r
94 FreePool (BootOption);\r
95\r
96 return (BOOLEAN) (KeyOption->BootOptionCrc == Crc);\r
97}\r
98\r
99/**\r
100\r
101 Check whether the input variable is an key option variable.\r
102\r
103 @param Name Input variable name.\r
104 @param Guid Input variable guid.\r
105 @param OptionNumber The option number of this key option variable.\r
106\r
107 @retval TRUE Input variable is a key option variable.\r
108 @retval FALSE Input variable is not a key option variable.\r
109**/\r
110BOOLEAN\r
111BmIsKeyOptionVariable (\r
112 CHAR16 *Name,\r
113 EFI_GUID *Guid,\r
114 UINT16 *OptionNumber\r
115 )\r
116{\r
117 UINTN Index;\r
418e8cd9 118 UINTN Uint;\r
067ed98a
RN
119 \r
120 if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||\r
121 (StrSize (Name) != sizeof (L"Key####")) ||\r
122 (StrnCmp (Name, L"Key", 3) != 0)\r
123 ) {\r
124 return FALSE;\r
125 }\r
126\r
127 *OptionNumber = 0;\r
128 for (Index = 3; Index < 7; Index++) {\r
418e8cd9
RN
129 Uint = BmCharToUint (Name[Index]);\r
130 if (Uint == -1) {\r
067ed98a 131 return FALSE;\r
418e8cd9
RN
132 } else {\r
133 *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;\r
067ed98a
RN
134 }\r
135 }\r
136\r
137 return TRUE;\r
138}\r
139\r
121300c4
RN
140typedef struct {\r
141 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
142 UINTN KeyOptionCount;\r
143} BM_COLLECT_KEY_OPTIONS_PARAM;\r
067ed98a 144\r
121300c4
RN
145/**\r
146 Visitor function to collect the key options from NV storage.\r
067ed98a 147\r
121300c4
RN
148 @param Name Variable name.\r
149 @param Guid Variable GUID.\r
150 @param Context The same context passed to BmForEachVariable.\r
067ed98a 151**/\r
121300c4
RN
152VOID\r
153BmCollectKeyOptions (\r
154 CHAR16 *Name,\r
155 EFI_GUID *Guid,\r
156 VOID *Context\r
067ed98a
RN
157 )\r
158{\r
121300c4
RN
159 UINTN Index;\r
160 BM_COLLECT_KEY_OPTIONS_PARAM *Param;\r
7320b8ed 161 VOID *KeyOption;\r
121300c4
RN
162 UINT16 OptionNumber;\r
163 UINTN KeyOptionSize;\r
164\r
165 Param = (BM_COLLECT_KEY_OPTIONS_PARAM *) Context;\r
166\r
167 if (BmIsKeyOptionVariable (Name, Guid, &OptionNumber)) {\r
7320b8ed 168 GetEfiGlobalVariable2 (Name, &KeyOption, &KeyOptionSize);\r
121300c4 169 ASSERT (KeyOption != NULL);\r
121300c4
RN
170 if (BmIsKeyOptionValid (KeyOption, KeyOptionSize)) {\r
171 Param->KeyOptions = ReallocatePool (\r
172 Param->KeyOptionCount * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
173 (Param->KeyOptionCount + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
174 Param->KeyOptions\r
175 );\r
176 ASSERT (Param->KeyOptions != NULL);\r
177 //\r
178 // Insert the key option in order\r
179 //\r
180 for (Index = 0; Index < Param->KeyOptionCount; Index++) {\r
7320b8ed 181 if (OptionNumber < Param->KeyOptions[Index].OptionNumber) {\r
121300c4
RN
182 break;\r
183 }\r
184 }\r
185 CopyMem (&Param->KeyOptions[Index + 1], &Param->KeyOptions[Index], (Param->KeyOptionCount - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
7320b8ed
RN
186 CopyMem (&Param->KeyOptions[Index], KeyOption, KeyOptionSize);\r
187 Param->KeyOptions[Index].OptionNumber = OptionNumber;\r
121300c4
RN
188 Param->KeyOptionCount++;\r
189 }\r
190 FreePool (KeyOption);\r
191 }\r
067ed98a
RN
192}\r
193\r
194/**\r
195 Return the array of key options.\r
196\r
197 @param Count Return the number of key options.\r
198\r
199 @retval NULL No key option.\r
200 @retval Other Pointer to the key options.\r
201**/\r
202EFI_BOOT_MANAGER_KEY_OPTION *\r
203BmGetKeyOptions (\r
204 OUT UINTN *Count\r
205 )\r
206{\r
121300c4 207 BM_COLLECT_KEY_OPTIONS_PARAM Param;\r
067ed98a
RN
208\r
209 if (Count == NULL) {\r
210 return NULL;\r
211 }\r
212\r
121300c4
RN
213 Param.KeyOptions = NULL;\r
214 Param.KeyOptionCount = 0;\r
067ed98a 215\r
121300c4 216 BmForEachVariable (BmCollectKeyOptions, (VOID *) &Param);\r
067ed98a 217\r
121300c4 218 *Count = Param.KeyOptionCount;\r
067ed98a 219\r
121300c4 220 return Param.KeyOptions;\r
067ed98a
RN
221}\r
222\r
067ed98a
RN
223/**\r
224 Check whether the bit is set in the value.\r
225\r
226 @param Value The value need to be check.\r
227 @param Bit The bit filed need to be check.\r
228\r
229 @retval TRUE The bit is set.\r
230 @retval FALSE The bit is not set.\r
231**/\r
232BOOLEAN\r
233BmBitSet (\r
234 IN UINT32 Value,\r
235 IN UINT32 Bit\r
236 )\r
237{\r
238 return (BOOLEAN) ((Value & Bit) != 0);\r
239}\r
240\r
241/**\r
242 Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.\r
243\r
244 @param Modifier Input key info.\r
245 @param Args Va_list info.\r
246 @param KeyOption Key info which need to update.\r
247\r
248 @retval EFI_SUCCESS Succeed to initialize the KeyData and Key[].\r
249 @return EFI_INVALID_PARAMETER Input parameter error.\r
250**/\r
251EFI_STATUS\r
252BmInitializeKeyFields (\r
253 IN UINT32 Modifier,\r
254 IN VA_LIST Args,\r
255 OUT EFI_BOOT_MANAGER_KEY_OPTION *KeyOption\r
256 )\r
257{\r
258 EFI_INPUT_KEY *Key;\r
259\r
260 if (KeyOption == NULL) {\r
261 return EFI_INVALID_PARAMETER;\r
262 }\r
263\r
264 Key = NULL;\r
265 while (KeyOption->KeyData.Options.InputKeyCount < sizeof (KeyOption->Keys) / sizeof (KeyOption->Keys[0])) {\r
266 Key = VA_ARG (Args, EFI_INPUT_KEY *);\r
267 if (Key == NULL) {\r
268 break;\r
269 }\r
270 CopyMem (\r
271 &KeyOption->Keys[KeyOption->KeyData.Options.InputKeyCount],\r
272 Key,\r
273 sizeof (EFI_INPUT_KEY)\r
274 );\r
275 KeyOption->KeyData.Options.InputKeyCount++;\r
276 }\r
277\r
278 if (Key != NULL) {\r
279 //\r
280 // Too many keys\r
281 //\r
282 return EFI_INVALID_PARAMETER;\r
283 }\r
284\r
285 if ((Modifier & ~(EFI_BOOT_MANAGER_SHIFT_PRESSED\r
286 | EFI_BOOT_MANAGER_CONTROL_PRESSED\r
287 | EFI_BOOT_MANAGER_ALT_PRESSED\r
288 | EFI_BOOT_MANAGER_LOGO_PRESSED\r
289 | EFI_BOOT_MANAGER_MENU_KEY_PRESSED\r
290 | EFI_BOOT_MANAGER_SYS_REQ_PRESSED\r
291 )) != 0) {\r
292 return EFI_INVALID_PARAMETER;\r
293 }\r
294\r
295 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SHIFT_PRESSED)) {\r
296 KeyOption->KeyData.Options.ShiftPressed = 1;\r
297 }\r
298 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_CONTROL_PRESSED)) {\r
299 KeyOption->KeyData.Options.ControlPressed = 1;\r
300 }\r
301 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_ALT_PRESSED)) {\r
302 KeyOption->KeyData.Options.AltPressed = 1;\r
303 }\r
304 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_LOGO_PRESSED)) {\r
305 KeyOption->KeyData.Options.LogoPressed = 1;\r
306 }\r
307 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_MENU_KEY_PRESSED)) {\r
308 KeyOption->KeyData.Options.MenuPressed = 1;\r
309 }\r
310 if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SYS_REQ_PRESSED)) {\r
311 KeyOption->KeyData.Options.SysReqPressed = 1;\r
312 }\r
313\r
314 return EFI_SUCCESS;\r
315}\r
316\r
317/**\r
318 Try to boot the boot option triggered by hot key.\r
319**/\r
320VOID\r
321EFIAPI\r
322EfiBootManagerHotkeyBoot (\r
323 VOID\r
324 )\r
325{\r
326 if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {\r
327 EfiBootManagerBoot (&mBmHotkeyBootOption);\r
328 EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption);\r
329 mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;\r
330 }\r
331}\r
332\r
333/**\r
334 This is the common notification function for HotKeys, it will be registered\r
335 with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.\r
336\r
337 @param KeyData A pointer to a buffer that is filled in with the keystroke\r
338 information for the key that was pressed.\r
339\r
340 @retval EFI_SUCCESS KeyData is successfully processed.\r
341 @return EFI_NOT_FOUND Fail to find boot option variable.\r
342**/\r
343EFI_STATUS\r
344EFIAPI\r
345BmHotkeyCallback (\r
346 IN EFI_KEY_DATA *KeyData\r
347)\r
348{\r
349 LIST_ENTRY *Link;\r
350 BM_HOTKEY *Hotkey;\r
f9a24380 351 CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
067ed98a
RN
352 EFI_STATUS Status;\r
353 EFI_KEY_DATA *HotkeyData;\r
354\r
355 if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {\r
356 //\r
357 // Do not process sequential hotkey stroke until the current boot option returns\r
358 //\r
359 return EFI_SUCCESS;\r
360 }\r
361\r
362 DEBUG ((EFI_D_INFO, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar));\r
363\r
364 EfiAcquireLock (&mBmHotkeyLock);\r
365 for ( Link = GetFirstNode (&mBmHotkeyList)\r
366 ; !IsNull (&mBmHotkeyList, Link)\r
367 ; Link = GetNextNode (&mBmHotkeyList, Link)\r
368 ) {\r
369 Hotkey = BM_HOTKEY_FROM_LINK (Link);\r
370\r
371 //\r
372 // Is this Key Stroke we are waiting for?\r
373 //\r
374 ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));\r
375 HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];\r
376 if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&\r
377 (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&\r
378 (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ? \r
379 (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE\r
380 )\r
381 ) {\r
382\r
383 //\r
384 // Receive an expecting key stroke, transit to next waiting state\r
385 //\r
386 Hotkey->WaitingKey++;\r
387\r
388 if (Hotkey->WaitingKey == Hotkey->CodeCount) {\r
389 //\r
390 // Reset to initial waiting state\r
391 //\r
392 Hotkey->WaitingKey = 0;\r
393 //\r
394 // Received the whole key stroke sequence\r
395 //\r
396 Status = gBS->SignalEvent (mBmHotkeyTriggered);\r
397 ASSERT_EFI_ERROR (Status);\r
398\r
399 if (!Hotkey->IsContinue) {\r
400 //\r
401 // Launch its BootOption\r
402 //\r
121300c4
RN
403 UnicodeSPrint (\r
404 OptionName, sizeof (OptionName), L"%s%04x",\r
405 mBmLoadOptionName[LoadOptionTypeBoot], Hotkey->BootOption\r
406 );\r
067ed98a
RN
407 Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);\r
408 DEBUG ((EFI_D_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));\r
409 if (EFI_ERROR (Status)) {\r
410 mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;\r
411 }\r
412 } else {\r
413 DEBUG ((EFI_D_INFO, "[Bds]Continue key pressed!\n"));\r
414 }\r
415 }\r
416 } else {\r
417 //\r
418 // Receive an unexpected key stroke, reset to initial waiting state\r
419 //\r
420 Hotkey->WaitingKey = 0;\r
421 }\r
422\r
423 }\r
424 EfiReleaseLock (&mBmHotkeyLock);\r
425\r
426 return EFI_SUCCESS;\r
427}\r
428\r
2d15a830
RN
429/**\r
430 Return the active Simple Text Input Ex handle array.\r
431 If the SystemTable.ConsoleInHandle is NULL, the function returns all\r
432 founded Simple Text Input Ex handles.\r
433 Otherwise, it just returns the ConsoleInHandle.\r
434\r
435 @param Count Return the handle count.\r
436\r
437 @retval The active console handles.\r
438**/\r
439EFI_HANDLE *\r
440BmGetActiveConsoleIn (\r
441 OUT UINTN *Count\r
442 )\r
443{\r
444 EFI_STATUS Status;\r
445 EFI_HANDLE *Handles;\r
446\r
b99e9ca9
RN
447 Handles = NULL;\r
448 *Count = 0;\r
449\r
2d15a830
RN
450 if (gST->ConsoleInHandle != NULL) {\r
451 Status = gBS->OpenProtocol (\r
452 gST->ConsoleInHandle,\r
453 &gEfiSimpleTextInputExProtocolGuid,\r
454 NULL,\r
455 gImageHandle,\r
456 NULL,\r
457 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
458 );\r
459 if (!EFI_ERROR (Status)) {\r
065e587c
TP
460 Handles = AllocateCopyPool (sizeof (EFI_HANDLE), &gST->ConsoleInHandle);\r
461 if (Handles != NULL) {\r
462 *Count = 1;\r
463 }\r
2d15a830
RN
464 }\r
465 } else {\r
466 Status = gBS->LocateHandleBuffer (\r
467 ByProtocol,\r
468 &gEfiSimpleTextInputExProtocolGuid,\r
469 NULL,\r
470 Count,\r
471 &Handles\r
472 );\r
473 }\r
2d15a830
RN
474\r
475 return Handles;\r
476}\r
477\r
067ed98a
RN
478/**\r
479 Unregister hotkey notify list.\r
480\r
481 @param Hotkey Hotkey list.\r
482\r
483 @retval EFI_SUCCESS Unregister hotkey notify success.\r
484 @retval Others Unregister hotkey notify failed.\r
485**/\r
486EFI_STATUS\r
487BmUnregisterHotkeyNotify (\r
488 IN BM_HOTKEY *Hotkey\r
489 )\r
490{\r
491 EFI_STATUS Status;\r
492 UINTN Index;\r
493 UINTN KeyIndex;\r
494 EFI_HANDLE *Handles;\r
495 UINTN HandleCount;\r
496 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;\r
497 VOID *NotifyHandle;\r
498\r
2d15a830 499 Handles = BmGetActiveConsoleIn (&HandleCount);\r
067ed98a
RN
500 for (Index = 0; Index < HandleCount; Index++) {\r
501 Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);\r
502 ASSERT_EFI_ERROR (Status);\r
503 for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {\r
504 Status = TxtInEx->RegisterKeyNotify (\r
505 TxtInEx,\r
506 &Hotkey->KeyData[KeyIndex],\r
507 BmHotkeyCallback,\r
508 &NotifyHandle\r
509 );\r
510 if (!EFI_ERROR (Status)) {\r
511 Status = TxtInEx->UnregisterKeyNotify (TxtInEx, NotifyHandle);\r
512 DEBUG ((EFI_D_INFO, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey->KeyData[KeyIndex].Key.ScanCode, Hotkey->KeyData[KeyIndex].Key.UnicodeChar, Status));\r
513 }\r
514 }\r
515 }\r
516\r
2d15a830
RN
517 if (Handles != NULL) {\r
518 FreePool (Handles);\r
519 }\r
520\r
067ed98a
RN
521 return EFI_SUCCESS;\r
522}\r
523\r
524/**\r
525 Register hotkey notify list.\r
526\r
527 @param TxtInEx Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.\r
528 @param Hotkey Hotkey list.\r
529\r
530 @retval EFI_SUCCESS Register hotkey notify success.\r
531 @retval Others Register hotkey notify failed.\r
532**/\r
533EFI_STATUS\r
534BmRegisterHotkeyNotify (\r
535 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx,\r
536 IN BM_HOTKEY *Hotkey\r
537 )\r
538{\r
539 EFI_STATUS Status;\r
540 UINTN Index;\r
541 VOID *NotifyHandle;\r
542\r
543 for (Index = 0; Index < Hotkey->CodeCount; Index++) {\r
544 Status = TxtInEx->RegisterKeyNotify (\r
545 TxtInEx,\r
546 &Hotkey->KeyData[Index],\r
547 BmHotkeyCallback,\r
548 &NotifyHandle\r
549 );\r
550 DEBUG ((\r
551 EFI_D_INFO,\r
552 "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",\r
553 Hotkey->KeyData[Index].Key.ScanCode,\r
554 Hotkey->KeyData[Index].Key.UnicodeChar,\r
555 Hotkey->KeyData[Index].KeyState.KeyShiftState,\r
556 Hotkey->KeyData[Index].KeyState.KeyToggleState,\r
557 Status\r
558 ));\r
559 if (EFI_ERROR (Status)) {\r
560 //\r
561 // some of the hotkey registry failed\r
562 // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R\r
563 //\r
564 break;\r
565 }\r
566 }\r
567\r
568 return EFI_SUCCESS;\r
569}\r
570\r
571/**\r
572 Generate key shift state base on the input key option info.\r
573\r
574 @param Depth Which key is checked.\r
575 @param KeyOption Input key option info.\r
576 @param KeyShiftState Input key shift state.\r
577 @param KeyShiftStates Return possible key shift state array.\r
578 @param KeyShiftStateCount Possible key shift state count.\r
579**/\r
580VOID\r
581BmGenerateKeyShiftState (\r
582 IN UINTN Depth,\r
583 IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption,\r
584 IN UINT32 KeyShiftState,\r
585 IN UINT32 *KeyShiftStates,\r
586 IN UINTN *KeyShiftStateCount\r
587 )\r
588{\r
589 switch (Depth) {\r
590 case 0:\r
591 if (KeyOption->KeyData.Options.ShiftPressed) {\r
592 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
593 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
594 } else {\r
595 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
596 }\r
597 break;\r
598\r
599 case 1:\r
600 if (KeyOption->KeyData.Options.ControlPressed) {\r
601 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
602 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
603 } else {\r
604 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
605 }\r
606 break;\r
607\r
608 case 2:\r
609 if (KeyOption->KeyData.Options.AltPressed) {\r
610 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
611 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
612 } else {\r
613 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
614 }\r
615 break;\r
616 case 3:\r
617 if (KeyOption->KeyData.Options.LogoPressed) {\r
618 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
619 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
620 } else {\r
621 BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
622 }\r
623 break;\r
624 case 4:\r
625 if (KeyOption->KeyData.Options.MenuPressed) {\r
626 KeyShiftState |= EFI_MENU_KEY_PRESSED;\r
627 }\r
628 if (KeyOption->KeyData.Options.SysReqPressed) {\r
629 KeyShiftState |= EFI_SYS_REQ_PRESSED;\r
630 }\r
631 KeyShiftStates[*KeyShiftStateCount] = KeyShiftState;\r
632 (*KeyShiftStateCount)++;\r
633 break;\r
634 }\r
635}\r
636\r
637/**\r
638 Add it to hot key database, register it to existing TxtInEx.\r
639 New TxtInEx will be automatically registered with all the hot key in dababase\r
640\r
641 @param KeyOption Input key option info.\r
642**/\r
643EFI_STATUS\r
644BmProcessKeyOption (\r
645 IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOption\r
646 )\r
647{\r
648 EFI_STATUS Status;\r
649 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;\r
650 EFI_HANDLE *Handles;\r
651 UINTN HandleCount;\r
652 UINTN HandleIndex;\r
653 UINTN Index;\r
654 BM_HOTKEY *Hotkey;\r
655 UINTN KeyIndex;\r
656 //\r
657 // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX\r
658 //\r
659 UINT32 KeyShiftStates[16];\r
660 UINTN KeyShiftStateCount;\r
661\r
662 if (KeyOption->KeyData.Options.InputKeyCount > mBmHotkeySupportCount) {\r
663 return EFI_UNSUPPORTED;\r
664 }\r
665\r
666 KeyShiftStateCount = 0;\r
667 BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);\r
f0209935 668 ASSERT (KeyShiftStateCount <= ARRAY_SIZE (KeyShiftStates));\r
067ed98a
RN
669\r
670 EfiAcquireLock (&mBmHotkeyLock);\r
671\r
2d15a830
RN
672 Handles = BmGetActiveConsoleIn (&HandleCount);\r
673\r
067ed98a
RN
674 for (Index = 0; Index < KeyShiftStateCount; Index++) {\r
675 Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));\r
676 ASSERT (Hotkey != NULL);\r
677\r
678 Hotkey->Signature = BM_HOTKEY_SIGNATURE;\r
679 Hotkey->BootOption = KeyOption->BootOption;\r
680 Hotkey->IsContinue = (BOOLEAN) (KeyOption == mBmContinueKeyOption);\r
681 Hotkey->CodeCount = (UINT8) KeyOption->KeyData.Options.InputKeyCount;\r
682\r
683 for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {\r
684 CopyMem (&Hotkey->KeyData[KeyIndex].Key, &KeyOption->Keys[KeyIndex], sizeof (EFI_INPUT_KEY));\r
685 Hotkey->KeyData[KeyIndex].KeyState.KeyShiftState = KeyShiftStates[Index];\r
686 }\r
687 InsertTailList (&mBmHotkeyList, &Hotkey->Link);\r
688\r
067ed98a
RN
689 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
690 Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);\r
691 ASSERT_EFI_ERROR (Status);\r
692 BmRegisterHotkeyNotify (TxtInEx, Hotkey);\r
693 }\r
694 }\r
695\r
2d15a830
RN
696 if (Handles != NULL) {\r
697 FreePool (Handles);\r
698 }\r
067ed98a
RN
699 EfiReleaseLock (&mBmHotkeyLock);\r
700\r
701 return EFI_SUCCESS;\r
702}\r
703\r
704/**\r
705 Callback function for SimpleTextInEx protocol install events\r
706\r
707 @param Event the event that is signaled.\r
708 @param Context not used here.\r
709\r
710**/\r
711VOID\r
712EFIAPI\r
713BmTxtInExCallback (\r
714 IN EFI_EVENT Event,\r
715 IN VOID *Context\r
716 )\r
717{\r
718 EFI_STATUS Status;\r
719 UINTN BufferSize;\r
720 EFI_HANDLE Handle;\r
721 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TxtInEx;\r
722 LIST_ENTRY *Link;\r
723\r
724 while (TRUE) {\r
725 BufferSize = sizeof (EFI_HANDLE);\r
726 Status = gBS->LocateHandle (\r
727 ByRegisterNotify,\r
728 NULL,\r
729 mBmTxtInExRegistration,\r
730 &BufferSize,\r
731 &Handle\r
732 );\r
733 if (EFI_ERROR (Status)) {\r
734 //\r
735 // If no more notification events exist\r
736 //\r
737 return ;\r
738 }\r
739\r
740 Status = gBS->HandleProtocol (\r
741 Handle,\r
742 &gEfiSimpleTextInputExProtocolGuid,\r
743 (VOID **) &TxtInEx\r
744 );\r
745 ASSERT_EFI_ERROR (Status);\r
746\r
747 //\r
748 // Register the hot key notification for the existing items in the list\r
749 //\r
750 EfiAcquireLock (&mBmHotkeyLock);\r
751 for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); Link = GetNextNode (&mBmHotkeyList, Link)) {\r
752 BmRegisterHotkeyNotify (TxtInEx, BM_HOTKEY_FROM_LINK (Link));\r
753 }\r
754 EfiReleaseLock (&mBmHotkeyLock);\r
755 }\r
756}\r
757\r
758/**\r
759 Free the key options returned from BmGetKeyOptions.\r
760\r
761 @param KeyOptions Pointer to the key options.\r
762 @param KeyOptionCount Number of the key options.\r
763\r
764 @retval EFI_SUCCESS The key options are freed.\r
765 @retval EFI_NOT_FOUND KeyOptions is NULL.\r
766**/\r
767EFI_STATUS\r
768BmFreeKeyOptions (\r
769 IN EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions,\r
770 IN UINTN KeyOptionCount\r
771 )\r
772{\r
773 if (KeyOptions != NULL) {\r
774 FreePool (KeyOptions);\r
775 return EFI_SUCCESS;\r
776 } else {\r
777 return EFI_NOT_FOUND;\r
778 }\r
779}\r
780\r
781/**\r
782 Register the key option to exit the waiting of the Boot Manager timeout.\r
783 Platform should ensure that the continue key option isn't conflict with\r
784 other boot key options.\r
785\r
786 @param Modifier Key shift state.\r
787 @param ... Parameter list of pointer of EFI_INPUT_KEY.\r
788\r
789 @retval EFI_SUCCESS Successfully register the continue key option.\r
790 @retval EFI_ALREADY_STARTED The continue key option is already registered.\r
791**/\r
792EFI_STATUS\r
793EFIAPI\r
794EfiBootManagerRegisterContinueKeyOption (\r
795 IN UINT32 Modifier,\r
796 ...\r
797 )\r
798{\r
799 EFI_STATUS Status;\r
800 EFI_BOOT_MANAGER_KEY_OPTION KeyOption;\r
801 VA_LIST Args;\r
802 \r
803 if (mBmContinueKeyOption != NULL) {\r
804 return EFI_ALREADY_STARTED;\r
805 }\r
806\r
807 ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
808 VA_START (Args, Modifier);\r
809 Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);\r
810 VA_END (Args);\r
811\r
812 if (!EFI_ERROR (Status)) {\r
813 mBmContinueKeyOption = AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION), &KeyOption);\r
814 ASSERT (mBmContinueKeyOption != NULL);\r
815 if (mBmHotkeyServiceStarted) {\r
816 BmProcessKeyOption (mBmContinueKeyOption);\r
817 }\r
818 }\r
819\r
820 return Status;\r
821}\r
822\r
823/**\r
824 Stop the hotkey processing.\r
825 \r
826 @param Event Event pointer related to hotkey service.\r
827 @param Context Context pass to this function.\r
828**/\r
829VOID\r
830EFIAPI\r
831BmStopHotkeyService (\r
832 IN EFI_EVENT Event,\r
833 IN VOID *Context\r
834 )\r
835{\r
836 LIST_ENTRY *Link;\r
837 BM_HOTKEY *Hotkey;\r
838\r
839 DEBUG ((EFI_D_INFO, "[Bds]Stop Hotkey Service!\n"));\r
840 gBS->CloseEvent (Event);\r
841\r
842 EfiAcquireLock (&mBmHotkeyLock);\r
843 for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {\r
844 Hotkey = BM_HOTKEY_FROM_LINK (Link);\r
845 BmUnregisterHotkeyNotify (Hotkey);\r
846 Link = RemoveEntryList (Link);\r
847 FreePool (Hotkey);\r
848 }\r
849 EfiReleaseLock (&mBmHotkeyLock);\r
850}\r
851\r
852/**\r
853 Start the hot key service so that the key press can trigger the boot option.\r
854\r
855 @param HotkeyTriggered Return the waitable event and it will be signaled \r
856 when a valid hot key is pressed.\r
857\r
858 @retval EFI_SUCCESS The hot key service is started.\r
859**/\r
860EFI_STATUS\r
861EFIAPI\r
862EfiBootManagerStartHotkeyService (\r
863 IN EFI_EVENT *HotkeyTriggered\r
864 )\r
865{\r
866 EFI_STATUS Status;\r
867 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
868 UINTN KeyOptionCount;\r
869 UINTN Index;\r
870 EFI_EVENT Event;\r
871 UINT32 *BootOptionSupport;\r
872\r
a0a03415
RN
873 GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **) &BootOptionSupport, NULL);\r
874 if (BootOptionSupport != NULL) {\r
875 if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY) != 0) {\r
876 mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));\r
877 }\r
878 FreePool (BootOptionSupport);\r
067ed98a 879 }\r
067ed98a
RN
880\r
881 if (mBmHotkeySupportCount == 0) {\r
882 DEBUG ((EFI_D_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));\r
883 return EFI_UNSUPPORTED;\r
884 }\r
885\r
886 Status = gBS->CreateEvent (\r
887 EVT_NOTIFY_WAIT,\r
888 TPL_CALLBACK,\r
ac72474d 889 EfiEventEmptyFunction,\r
067ed98a
RN
890 NULL,\r
891 &mBmHotkeyTriggered\r
892 );\r
893 ASSERT_EFI_ERROR (Status);\r
894\r
895 if (HotkeyTriggered != NULL) {\r
896 *HotkeyTriggered = mBmHotkeyTriggered;\r
897 }\r
898\r
899 KeyOptions = BmGetKeyOptions (&KeyOptionCount);\r
900 for (Index = 0; Index < KeyOptionCount; Index ++) {\r
901 BmProcessKeyOption (&KeyOptions[Index]);\r
902 }\r
903 BmFreeKeyOptions (KeyOptions, KeyOptionCount);\r
904\r
905 if (mBmContinueKeyOption != NULL) {\r
906 BmProcessKeyOption (mBmContinueKeyOption);\r
907 }\r
908\r
2d15a830
RN
909 //\r
910 // Hook hotkey on every future SimpleTextInputEx instance when\r
911 // SystemTable.ConsoleInHandle == NULL, which means the console\r
912 // manager (ConSplitter) is absent.\r
913 //\r
914 if (gST->ConsoleInHandle == NULL) {\r
915 EfiCreateProtocolNotifyEvent (\r
916 &gEfiSimpleTextInputExProtocolGuid,\r
917 TPL_CALLBACK,\r
918 BmTxtInExCallback,\r
919 NULL,\r
920 &mBmTxtInExRegistration\r
921 );\r
922 }\r
067ed98a
RN
923\r
924 Status = EfiCreateEventReadyToBootEx (\r
925 TPL_CALLBACK,\r
926 BmStopHotkeyService,\r
927 NULL,\r
928 &Event\r
929 );\r
930 ASSERT_EFI_ERROR (Status);\r
931\r
067ed98a
RN
932 mBmHotkeyServiceStarted = TRUE;\r
933 return Status;\r
934}\r
935\r
936/**\r
937 Add the key option.\r
938 It adds the key option variable and the key option takes affect immediately.\r
939\r
940 @param AddedOption Return the added key option.\r
941 @param BootOptionNumber The boot option number for the key option.\r
942 @param Modifier Key shift state.\r
943 @param ... Parameter list of pointer of EFI_INPUT_KEY.\r
944\r
945 @retval EFI_SUCCESS The key option is added.\r
946 @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.\r
947**/\r
948EFI_STATUS\r
949EFIAPI\r
950EfiBootManagerAddKeyOptionVariable (\r
951 OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption, OPTIONAL\r
952 IN UINT16 BootOptionNumber,\r
953 IN UINT32 Modifier,\r
954 ...\r
955 )\r
956{\r
957 EFI_STATUS Status;\r
958 VA_LIST Args;\r
959 VOID *BootOption;\r
960 UINTN BootOptionSize;\r
f9a24380 961 CHAR16 BootOptionName[BM_OPTION_NAME_LEN];\r
067ed98a
RN
962 EFI_BOOT_MANAGER_KEY_OPTION KeyOption;\r
963 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
964 UINTN KeyOptionCount;\r
965 UINTN Index;\r
966 UINTN KeyOptionNumber;\r
f9a24380 967 CHAR16 KeyOptionName[sizeof ("Key####")];\r
067ed98a 968\r
121300c4
RN
969 UnicodeSPrint (\r
970 BootOptionName, sizeof (BootOptionName), L"%s%04x",\r
971 mBmLoadOptionName[LoadOptionTypeBoot], BootOptionNumber\r
972 );\r
067ed98a
RN
973 GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);\r
974\r
975 if (BootOption == NULL) {\r
976 return EFI_NOT_FOUND;\r
977 }\r
978\r
979 ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
980 KeyOption.BootOption = BootOptionNumber;\r
981 Status = gBS->CalculateCrc32 (BootOption, BootOptionSize, &KeyOption.BootOptionCrc);\r
982 ASSERT_EFI_ERROR (Status);\r
983 FreePool (BootOption);\r
984\r
985 VA_START (Args, Modifier);\r
986 Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);\r
987 VA_END (Args);\r
988 if (EFI_ERROR (Status)) {\r
989 return Status;\r
990 }\r
991\r
992 KeyOptionNumber = LoadOptionNumberUnassigned;\r
993 //\r
994 // Check if the hot key sequence was defined already\r
995 //\r
996 KeyOptions = BmGetKeyOptions (&KeyOptionCount);\r
997 for (Index = 0; Index < KeyOptionCount; Index++) {\r
998 if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&\r
999 (CompareMem (KeyOptions[Index].Keys, KeyOption.Keys, KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)) {\r
1000 break;\r
1001 }\r
1002\r
1003 if ((KeyOptionNumber == LoadOptionNumberUnassigned) &&\r
1004 (KeyOptions[Index].OptionNumber > Index)\r
1005 ){\r
1006 KeyOptionNumber = Index;\r
1007 }\r
1008 }\r
1009 BmFreeKeyOptions (KeyOptions, KeyOptionCount);\r
1010\r
1011 if (Index < KeyOptionCount) {\r
1012 return EFI_ALREADY_STARTED;\r
1013 }\r
1014\r
1015 if (KeyOptionNumber == LoadOptionNumberUnassigned) {\r
1016 KeyOptionNumber = KeyOptionCount;\r
1017 }\r
1018\r
1019 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumber);\r
1020\r
1021 Status = gRT->SetVariable (\r
1022 KeyOptionName,\r
1023 &gEfiGlobalVariableGuid,\r
1024 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1025 BmSizeOfKeyOption (&KeyOption),\r
1026 &KeyOption\r
1027 );\r
1028 if (!EFI_ERROR (Status)) {\r
1029 //\r
1030 // Return the Key Option in case needed by caller\r
1031 //\r
1032 if (AddedOption != NULL) {\r
1033 CopyMem (AddedOption, &KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
1034 }\r
1035\r
1036 //\r
1037 // Register the newly added hot key\r
1038 // Calling this function before EfiBootManagerStartHotkeyService doesn't\r
1039 // need to call BmProcessKeyOption\r
1040 //\r
1041 if (mBmHotkeyServiceStarted) {\r
1042 BmProcessKeyOption (&KeyOption);\r
1043 }\r
1044 }\r
1045\r
1046 return Status;\r
1047}\r
1048\r
1049/**\r
1050 Delete the Key Option variable and unregister the hot key\r
1051\r
1052 @param DeletedOption Return the deleted key options.\r
1053 @param Modifier Key shift state.\r
1054 @param ... Parameter list of pointer of EFI_INPUT_KEY.\r
1055\r
1056 @retval EFI_SUCCESS The key option is deleted.\r
1057 @retval EFI_NOT_FOUND The key option cannot be found.\r
1058**/\r
1059EFI_STATUS\r
1060EFIAPI\r
1061EfiBootManagerDeleteKeyOptionVariable (\r
1062 IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL\r
1063 IN UINT32 Modifier,\r
1064 ...\r
1065 )\r
1066{\r
1067 EFI_STATUS Status;\r
1068 UINTN Index;\r
1069 VA_LIST Args;\r
1070 EFI_BOOT_MANAGER_KEY_OPTION KeyOption;\r
1071 EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
1072 UINTN KeyOptionCount;\r
1073 LIST_ENTRY *Link;\r
1074 BM_HOTKEY *Hotkey;\r
1075 UINT32 ShiftState;\r
1076 BOOLEAN Match;\r
f9a24380 1077 CHAR16 KeyOptionName[sizeof ("Key####")];\r
067ed98a
RN
1078\r
1079 ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
1080 VA_START (Args, Modifier);\r
1081 Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);\r
1082 VA_END (Args);\r
1083\r
1084 if (EFI_ERROR (Status)) {\r
1085 return Status;\r
1086 }\r
1087\r
1088 EfiAcquireLock (&mBmHotkeyLock);\r
1089 //\r
1090 // Delete the key option from active hot key list\r
1091 // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT\r
1092 //\r
1093 for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {\r
1094 Hotkey = BM_HOTKEY_FROM_LINK (Link);\r
1095 Match = (BOOLEAN) (Hotkey->CodeCount == KeyOption.KeyData.Options.InputKeyCount);\r
1096\r
1097 for (Index = 0; Match && (Index < Hotkey->CodeCount); Index++) {\r
1098 ShiftState = Hotkey->KeyData[Index].KeyState.KeyShiftState;\r
1099 if (\r
1100 (BmBitSet (ShiftState, EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED) != KeyOption.KeyData.Options.ShiftPressed) ||\r
1101 (BmBitSet (ShiftState, EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED) != KeyOption.KeyData.Options.ControlPressed) ||\r
1102 (BmBitSet (ShiftState, EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED) != KeyOption.KeyData.Options.AltPressed) ||\r
1103 (BmBitSet (ShiftState, EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED) != KeyOption.KeyData.Options.LogoPressed) ||\r
1104 (BmBitSet (ShiftState, EFI_MENU_KEY_PRESSED) != KeyOption.KeyData.Options.MenuPressed) ||\r
1105 (BmBitSet (ShiftState, EFI_SYS_REQ_PRESSED) != KeyOption.KeyData.Options.SysReqPressed) ||\r
1106 (CompareMem (&Hotkey->KeyData[Index].Key, &KeyOption.Keys[Index], sizeof (EFI_INPUT_KEY)) != 0)\r
1107 ) {\r
1108 //\r
1109 // Break when any field doesn't match\r
1110 //\r
1111 Match = FALSE;\r
1112 break;\r
1113 }\r
1114 }\r
1115\r
1116 if (Match) {\r
1117 Link = RemoveEntryList (Link);\r
1118 FreePool (Hotkey);\r
1119 } else {\r
1120 Link = GetNextNode (&mBmHotkeyList, Link);\r
1121 }\r
1122 }\r
1123\r
1124 //\r
1125 // Delete the key option from the variable\r
1126 //\r
1127 Status = EFI_NOT_FOUND;\r
1128 KeyOptions = BmGetKeyOptions (&KeyOptionCount);\r
1129 for (Index = 0; Index < KeyOptionCount; Index++) {\r
1130 if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&\r
1131 (CompareMem (\r
1132 KeyOptions[Index].Keys, KeyOption.Keys,\r
1133 KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)\r
1134 ) {\r
1135 UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptions[Index].OptionNumber);\r
1136 Status = gRT->SetVariable (\r
1137 KeyOptionName,\r
1138 &gEfiGlobalVariableGuid,\r
1139 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1140 0,\r
1141 NULL\r
1142 );\r
1143 //\r
1144 // Return the deleted key option in case needed by caller\r
1145 //\r
1146 if (DeletedOption != NULL) {\r
1147 CopyMem (DeletedOption, &KeyOptions[Index], sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
1148 }\r
1149 break;\r
1150 }\r
1151 }\r
1152 BmFreeKeyOptions (KeyOptions, KeyOptionCount);\r
1153\r
1154 EfiReleaseLock (&mBmHotkeyLock);\r
1155\r
1156 return Status;\r
1157}\r