never removed. Such design ensures sytem function well during none console\r
device situation.\r
\r
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "ConSplitter.h"\r
\r
//\r
-// Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode. \r
+// Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode.\r
// default not connect\r
//\r
BOOLEAN mConInIsConnect = FALSE;\r
(LIST_ENTRY *) NULL,\r
(LIST_ENTRY *) NULL\r
},\r
+ (EFI_KEY_DATA *) NULL,\r
+ 0,\r
0,\r
FALSE,\r
\r
0,\r
(TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,\r
0,\r
- (INT32 *) NULL\r
+ (INT32 *) NULL,\r
+ FALSE\r
};\r
\r
//\r
0,\r
(TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,\r
0,\r
- (INT32 *) NULL\r
+ (INT32 *) NULL,\r
+ FALSE\r
};\r
\r
//\r
&mStdErr.TextOut,\r
NULL\r
);\r
- if (!EFI_ERROR (Status)) { \r
+ if (!EFI_ERROR (Status)) {\r
//\r
// Update the EFI System Table with new virtual console\r
// and update the pointer to Text Output protocol.\r
gST->StdErr = &mStdErr.TextOut;\r
}\r
}\r
- \r
+\r
//\r
// Update the CRC32 in the EFI System Table header\r
//\r
)\r
{\r
EFI_STATUS Status;\r
+ UINTN TextInExListCount;\r
\r
//\r
// Allocate buffer for Simple Text Input device\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
+ //\r
+ // Allocate buffer for KeyQueue\r
+ //\r
+ TextInExListCount = ConInPrivate->TextInExListCount;\r
+ Status = ConSplitterGrowBuffer (\r
+ sizeof (EFI_KEY_DATA),\r
+ &TextInExListCount,\r
+ (VOID **) &ConInPrivate->KeyQueue\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
//\r
// Allocate buffer for Simple Text Input Ex device\r
//\r
return EFI_OUT_OF_RESOURCES;\r
}\r
}\r
+\r
+ TextInExListCount = Private->TextInExListCount;\r
+ Status = ConSplitterGrowBuffer (\r
+ sizeof (EFI_KEY_DATA),\r
+ &TextInExListCount,\r
+ (VOID **) &Private->KeyQueue\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
Status = ConSplitterGrowBuffer (\r
sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),\r
&Private->TextInExListCount,\r
Size = Private->CurrentNumberOfConsoles * sizeof (INT32);\r
Index = 0;\r
SrcAddress = OldTextOutModeMap;\r
- NewStepSize = NewSize / sizeof(INT32); \r
+ NewStepSize = NewSize / sizeof(INT32);\r
// If Private->CurrentNumberOfConsoles is not zero and OldTextOutModeMap\r
// is not NULL, it indicates that the original TextOutModeMap is not enough\r
// for the new console devices and has been enlarged by CONSOLE_SPLITTER_ALLOC_UNIT columns.\r
//\r
// Force GraphicsOutput mode to be set,\r
//\r
- \r
+\r
Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex];\r
if ((GraphicsOutput != NULL) &&\r
(Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) &&\r
MaxMode = (UINTN) (TextOut->Mode->MaxMode);\r
\r
MaxModeInfo.Column = 0;\r
- MaxModeInfo.Row = 0; \r
+ MaxModeInfo.Row = 0;\r
ModeInfo.Column = PcdGet32 (PcdConOutColumn);\r
ModeInfo.Row = PcdGet32 (PcdConOutRow);\r
\r
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
EFI_STATUS DeviceStatus;\r
\r
- Status = EFI_SUCCESS;\r
- CurrentNumOfConsoles = Private->CurrentNumberOfConsoles;\r
+ Status = EFI_SUCCESS;\r
+ CurrentNumOfConsoles = Private->CurrentNumberOfConsoles;\r
+ Private->AddingConOutDevice = TRUE;\r
\r
//\r
// If the Text Out List is full, enlarge it by calling ConSplitterGrowBuffer().\r
\r
DeviceStatus = EFI_DEVICE_ERROR;\r
Status = EFI_DEVICE_ERROR;\r
- \r
+\r
//\r
// This device display mode will be added into Graphics Ouput modes.\r
//\r
//\r
ConsplitterSetConsoleOutMode (Private);\r
\r
+ Private->AddingConOutDevice = FALSE;\r
+\r
return Status;\r
}\r
\r
Private->VirtualHandle,\r
&gEfiUgaDrawProtocolGuid,\r
&Private->UgaDraw\r
- ); \r
+ );\r
} else if (!FeaturePcdGet (PcdConOutUgaSupport)) {\r
Status = gBS->UninstallProtocolInterface (\r
Private->VirtualHandle,\r
\r
if (!EFI_ERROR (ReturnStatus)) {\r
ToggleStateSyncReInitialization (Private);\r
+ //\r
+ // Empty the key queue.\r
+ //\r
+ Private->CurrentNumberOfKeys = 0;\r
}\r
\r
return ReturnStatus;\r
}\r
\r
+/**\r
+ Dequeue the saved key from internal key queue.\r
+\r
+ @param Private Protocol instance pointer.\r
+ @param KeyData A pointer to a buffer that is filled in with the\r
+ keystroke state data for the key that was\r
+ pressed.\r
+ @retval EFI_NOT_FOUND Queue is empty.\r
+ @retval EFI_SUCCESS First key is dequeued and returned.\r
+**/\r
+EFI_STATUS\r
+ConSplitterTextInExDequeueKey (\r
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,\r
+ OUT EFI_KEY_DATA *KeyData\r
+ )\r
+{\r
+ if (Private->CurrentNumberOfKeys == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Return the first saved key.\r
+ //\r
+ CopyMem (KeyData, &Private->KeyQueue[0], sizeof (EFI_KEY_DATA));\r
+ Private->CurrentNumberOfKeys--;\r
+ CopyMem (\r
+ &Private->KeyQueue[0],\r
+ &Private->KeyQueue[1],\r
+ Private->CurrentNumberOfKeys * sizeof (EFI_KEY_DATA)\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
\r
/**\r
Reads the next keystroke from the input device. The WaitForKey Event can\r
{\r
EFI_STATUS Status;\r
UINTN Index;\r
- EFI_INPUT_KEY CurrentKey;\r
+ EFI_KEY_DATA KeyData;\r
+\r
+ //\r
+ // Return the first saved non-NULL key.\r
+ //\r
+ while (TRUE) {\r
+ Status = ConSplitterTextInExDequeueKey (Private, &KeyData);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {\r
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
+ return Status;\r
+ }\r
+ }\r
\r
Key->UnicodeChar = 0;\r
Key->ScanCode = SCAN_NULL;\r
for (Index = 0; Index < Private->CurrentNumberOfConsoles;) {\r
Status = Private->TextInList[Index]->ReadKeyStroke (\r
Private->TextInList[Index],\r
- &CurrentKey\r
+ &KeyData.Key\r
);\r
if (!EFI_ERROR (Status)) {\r
//\r
// If it is not partial keystorke, return the key. Otherwise, continue\r
// to read key from THIS physical console input device.\r
//\r
- if ((CurrentKey.ScanCode != CHAR_NULL) || (CurrentKey.UnicodeChar != SCAN_NULL)) {\r
- *Key = CurrentKey;\r
+ if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {\r
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));\r
return Status;\r
}\r
} else {\r
// Signal ConnectConIn event on first call in Lazy ConIn mode\r
//\r
if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\r
- DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n")); \r
+ DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));\r
gBS->SignalEvent (Private->ConnectConInEvent);\r
mConInIsConnect = TRUE;\r
}\r
\r
if (!EFI_ERROR (ReturnStatus)) {\r
ToggleStateSyncReInitialization (Private);\r
+ //\r
+ // Empty the key queue.\r
+ //\r
+ Private->CurrentNumberOfKeys = 0;\r
}\r
\r
return ReturnStatus;\r
TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
EFI_STATUS Status;\r
UINTN Index;\r
+ EFI_KEY_STATE KeyState;\r
EFI_KEY_DATA CurrentKeyData;\r
\r
\r
\r
Private->KeyEventSignalState = FALSE;\r
\r
- KeyData->Key.UnicodeChar = 0;\r
- KeyData->Key.ScanCode = SCAN_NULL;\r
-\r
//\r
// Signal ConnectConIn event on first call in Lazy ConIn mode\r
//\r
if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {\r
- DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n")); \r
+ DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));\r
gBS->SignalEvent (Private->ConnectConInEvent);\r
mConInIsConnect = TRUE;\r
}\r
\r
//\r
- // if no physical console input device exists, return EFI_NOT_READY;\r
- // if any physical console input device has key input,\r
- // return the key and EFI_SUCCESS.\r
+ // Return the first saved key.\r
+ //\r
+ Status = ConSplitterTextInExDequeueKey (Private, KeyData);\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ ASSERT (Private->CurrentNumberOfKeys == 0);\r
+\r
+ ZeroMem (&KeyState, sizeof (KeyState));\r
+\r
+ //\r
+ // Iterate through all physical consoles to get key state.\r
+ // Some physical consoles may return valid key.\r
+ // Queue the valid keys.\r
//\r
- for (Index = 0; Index < Private->CurrentNumberOfExConsoles;) {\r
+ for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
+ ZeroMem (&CurrentKeyData, sizeof (EFI_KEY_DATA));\r
Status = Private->TextInExList[Index]->ReadKeyStrokeEx (\r
- Private->TextInExList[Index],\r
- &CurrentKeyData\r
- );\r
+ Private->TextInExList[Index],\r
+ &CurrentKeyData\r
+ );\r
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Consolidate the key state from all physical consoles.\r
+ //\r
+ if ((CurrentKeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) {\r
+ KeyState.KeyShiftState |= CurrentKeyData.KeyState.KeyShiftState;\r
+ }\r
+ if ((CurrentKeyData.KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != 0) {\r
+ KeyState.KeyToggleState |= CurrentKeyData.KeyState.KeyToggleState;\r
+ }\r
+\r
if (!EFI_ERROR (Status)) {\r
//\r
// If virtual KeyState has been required to be exposed, or it is not\r
- // partial keystorke, return the key. Otherwise, continue to read key\r
- // from THIS physical console input device.\r
+ // partial keystorke, queue the key.\r
+ // It's possible that user presses at multiple keyboards at the same moment,\r
+ // Private->KeyQueue[] are the storage to save all the keys.\r
//\r
if ((Private->VirtualKeyStateExported) ||\r
(CurrentKeyData.Key.ScanCode != CHAR_NULL) ||\r
(CurrentKeyData.Key.UnicodeChar != SCAN_NULL)) {\r
- CopyMem (KeyData, &CurrentKeyData, sizeof (CurrentKeyData));\r
- return Status;\r
+ CopyMem (\r
+ &Private->KeyQueue[Private->CurrentNumberOfKeys],\r
+ &CurrentKeyData,\r
+ sizeof (EFI_KEY_DATA)\r
+ );\r
+ Private->CurrentNumberOfKeys++;\r
}\r
- } else {\r
- //\r
- // Continue to read key from NEXT physical console input device.\r
- //\r
- Index++;\r
}\r
}\r
\r
+ //\r
+ // Consolidate the key state for all keys in Private->KeyQueue[]\r
+ //\r
+ for (Index = 0; Index < Private->CurrentNumberOfKeys; Index++) {\r
+ CopyMem (&Private->KeyQueue[Index].KeyState, &KeyState, sizeof (EFI_KEY_STATE));\r
+ }\r
+\r
+ //\r
+ // Return the first saved key.\r
+ //\r
+ Status = ConSplitterTextInExDequeueKey (Private, KeyData);\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Always return the key state even there is no key pressed.\r
+ //\r
+ ZeroMem (&KeyData->Key, sizeof (KeyData->Key));\r
+ CopyMem (&KeyData->KeyState, &KeyState, sizeof (KeyData->KeyState));\r
return EFI_NOT_READY;\r
}\r
\r
Private->TextOutMode.CursorRow = Private->TextOutList[0].TextOut->Mode->CursorRow;\r
} else {\r
//\r
- // When there is no real console devices in system, \r
+ // When there is no real console devices in system,\r
// update cursor position for the virtual device in consplitter.\r
//\r
Private->TextOut.QueryMode (\r
Private->TextOutMode.Mode,\r
&MaxColumn,\r
&MaxRow\r
- ); \r
+ );\r
for (; *WString != CHAR_NULL; WString++) {\r
switch (*WString) {\r
case CHAR_BACKSPACE:\r
if (Private->TextOutMode.CursorColumn == 0 && Private->TextOutMode.CursorRow > 0) {\r
Private->TextOutMode.CursorRow--;\r
- Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1); \r
+ Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1);\r
} else if (Private->TextOutMode.CursorColumn > 0) {\r
Private->TextOutMode.CursorColumn--;\r
}\r
break;\r
- \r
+\r
case CHAR_LINEFEED:\r
if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {\r
Private->TextOutMode.CursorRow++;\r
}\r
break;\r
- \r
+\r
case CHAR_CARRIAGE_RETURN:\r
Private->TextOutMode.CursorColumn = 0;\r
break;\r
- \r
+\r
default:\r
if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) {\r
Private->TextOutMode.CursorColumn++;\r
//\r
TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;\r
for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {\r
- Status = Private->TextOutList[Index].TextOut->SetMode (\r
- Private->TextOutList[Index].TextOut,\r
- TextOutModeMap[Index]\r
- );\r
- if (EFI_ERROR (Status)) {\r
- ReturnStatus = Status;\r
+ //\r
+ // While adding a console out device do not set same mode again for the same device.\r
+ //\r
+ if ((!Private->AddingConOutDevice) ||\r
+ (TextOutModeMap[Index] != Private->TextOutList[Index].TextOut->Mode->Mode)) {\r
+ Status = Private->TextOutList[Index].TextOut->SetMode (\r
+ Private->TextOutList[Index].TextOut,\r
+ TextOutModeMap[Index]\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ReturnStatus = Status;\r
+ }\r
}\r
}\r
\r