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