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