/** @file\r
- Console Splitter Driver. Any Handle that attatched console I/O protocols\r
+ Console Splitter Driver. Any Handle that attached console I/O protocols\r
(Console In device, Console Out device, Console Error device, Simple Pointer\r
protocol, Absolute Pointer protocol) can be bound by this driver.\r
\r
\r
Each virtual handle, that supports the Console I/O protocol, will be produced\r
in the driver entry point. The virtual handle are added on driver entry and\r
- never removed. Such design ensures sytem function well during none console\r
+ never removed. Such design ensures system function well during none console\r
device situation.\r
\r
-Copyright (c) 2006 - 2015, 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
{\r
ConSplitterSimplePointerReset,\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
NULL\r
};\r
\r
+/**\r
+ Key notify for toggle state sync.\r
+\r
+ @param KeyData A pointer to a buffer that is filled in with\r
+ the keystroke information for the key that was\r
+ pressed.\r
+\r
+ @retval EFI_SUCCESS Toggle state sync successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ToggleStateSyncKeyNotify (\r
+ IN EFI_KEY_DATA *KeyData\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ if (((KeyData->KeyState.KeyToggleState & KEY_STATE_VALID_EXPOSED) == KEY_STATE_VALID_EXPOSED) &&\r
+ (KeyData->KeyState.KeyToggleState != mConIn.PhysicalKeyToggleState)) {\r
+ //\r
+ // There is toggle state change, sync to other console input devices.\r
+ //\r
+ for (Index = 0; Index < mConIn.CurrentNumberOfExConsoles; Index++) {\r
+ mConIn.TextInExList[Index]->SetState (\r
+ mConIn.TextInExList[Index],\r
+ &KeyData->KeyState.KeyToggleState\r
+ );\r
+ }\r
+ mConIn.PhysicalKeyToggleState = KeyData->KeyState.KeyToggleState;\r
+ DEBUG ((EFI_D_INFO, "Current toggle state is 0x%02x\n", mConIn.PhysicalKeyToggleState));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialization for toggle state sync.\r
+\r
+ @param Private Text In Splitter pointer.\r
+\r
+**/\r
+VOID\r
+ToggleStateSyncInitialization (\r
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_KEY_DATA KeyData;\r
+ VOID *NotifyHandle;\r
+\r
+ //\r
+ // Initialize PhysicalKeyToggleState that will be synced to new console\r
+ // input device to turn on physical TextInEx partial key report for\r
+ // toggle state sync.\r
+ //\r
+ Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;\r
+\r
+ //\r
+ // Initialize VirtualKeyStateExported to let the virtual TextInEx not report\r
+ // the partial key even though the physical TextInEx turns on the partial\r
+ // key report. The virtual TextInEx will report the partial key after it is\r
+ // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.\r
+ //\r
+ Private->VirtualKeyStateExported = FALSE;\r
+\r
+ //\r
+ // Register key notify for toggle state sync.\r
+ //\r
+ KeyData.Key.ScanCode = SCAN_NULL;\r
+ KeyData.Key.UnicodeChar = CHAR_NULL;\r
+ KeyData.KeyState.KeyShiftState = 0;\r
+ KeyData.KeyState.KeyToggleState = 0;\r
+ Private->TextInEx.RegisterKeyNotify (\r
+ &Private->TextInEx,\r
+ &KeyData,\r
+ ToggleStateSyncKeyNotify,\r
+ &NotifyHandle\r
+ );\r
+}\r
+\r
+/**\r
+ Re-initialization for toggle state sync.\r
+\r
+ @param Private Text In Splitter pointer.\r
+\r
+**/\r
+VOID\r
+ToggleStateSyncReInitialization (\r
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // Reinitialize PhysicalKeyToggleState that will be synced to new console\r
+ // input device to turn on physical TextInEx partial key report for\r
+ // toggle state sync.\r
+ //\r
+ Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;\r
+\r
+ //\r
+ // Reinitialize VirtualKeyStateExported to let the virtual TextInEx not report\r
+ // the partial key even though the physical TextInEx turns on the partial\r
+ // key report. The virtual TextInEx will report the partial key after it is\r
+ // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.\r
+ //\r
+ Private->VirtualKeyStateExported = FALSE;\r
+\r
+ for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
+ Private->TextInExList[Index]->SetState (\r
+ Private->TextInExList[Index],\r
+ &Private->PhysicalKeyToggleState\r
+ );\r
+ }\r
+}\r
+\r
/**\r
The Entry Point for module ConSplitter. The user code starts with this function.\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
structure.\r
\r
@retval EFI_OUT_OF_RESOURCES Out of resources.\r
- @retval EFI_SUCCESS Text Input Devcie's private data has been constructed.\r
+ @retval EFI_SUCCESS Text Input Device's private data has been constructed.\r
@retval other Failed to construct private data.\r
\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
\r
InitializeListHead (&ConInPrivate->NotifyList);\r
\r
+ ToggleStateSyncInitialization (ConInPrivate);\r
+\r
ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;\r
//\r
// Allocate buffer for Absolute Pointer device\r
Status = gBS->CreateEventEx (\r
EVT_NOTIFY_SIGNAL,\r
TPL_CALLBACK,\r
- ConSplitterEmptyCallbackFunction,\r
+ EfiEventEmptyFunction,\r
NULL,\r
&gConnectConInEventGuid,\r
&ConInPrivate->ConnectConInEvent\r
}\r
\r
//\r
- // Initilize console output splitter's private data.\r
+ // Initialize console output splitter's private data.\r
//\r
ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode;\r
\r
@param Guid The specified protocol.\r
\r
@retval EFI_SUCCESS The specified protocol is supported on this device.\r
- @retval EFI_UNSUPPORTED The specified protocol attempts to be installed on virtul handle.\r
+ @retval EFI_UNSUPPORTED The specified protocol attempts to be installed on virtual handle.\r
@retval other Failed to open specified protocol on this device.\r
\r
**/\r
}\r
\r
//\r
- // Open InterfaceGuid on the virtul handle.\r
+ // Open InterfaceGuid on the virtual handle.\r
//\r
Status = gBS->OpenProtocol (\r
ControllerHandle,\r
\r
//\r
// Start ConSplitter on ControllerHandle, and create the virtual\r
- // agrogated console device on first call Start for a SimpleTextIn handle.\r
+ // aggregated console device on first call Start for a SimpleTextIn handle.\r
//\r
Status = ConSplitterStart (\r
This,\r
\r
//\r
// Start ConSplitter on ControllerHandle, and create the virtual\r
- // agrogated console device on first call Start for a SimplePointer handle.\r
+ // aggregated console device on first call Start for a SimplePointer handle.\r
//\r
Status = ConSplitterStart (\r
This,\r
\r
//\r
// Start ConSplitter on ControllerHandle, and create the virtual\r
- // agrogated console device on first call Start for a AbsolutePointer handle.\r
+ // aggregated console device on first call Start for a AbsolutePointer handle.\r
//\r
Status = ConSplitterStart (\r
This,\r
\r
//\r
// Start ConSplitter on ControllerHandle, and create the virtual\r
- // agrogated console device on first call Start for a ConsoleOut handle.\r
+ // aggregated console device on first call Start for a ConsoleOut handle.\r
//\r
Status = ConSplitterStart (\r
This,\r
\r
//\r
// Start ConSplitter on ControllerHandle, and create the virtual\r
- // agrogated console device on first call Start for a StandardError handle.\r
+ // aggregated console device on first call Start for a StandardError handle.\r
//\r
Status = ConSplitterStart (\r
This,\r
// their MaxMode and QueryData should be the intersection of both.\r
//\r
Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL);\r
- ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK));\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
+ ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
\r
return Status;\r
}\r
return Status;\r
}\r
//\r
- // close the protocol refered.\r
+ // close the protocol referred.\r
//\r
gBS->CloseProtocol (\r
ControllerHandle,\r
\r
\r
/**\r
- Stop Console In ConSplitter on ControllerHandle by closing Console In Devcice GUID.\r
+ Stop Console In ConSplitter on ControllerHandle by closing Console In Device GUID.\r
\r
@param This Driver Binding protocol instance pointer.\r
@param ControllerHandle Handle of device to stop driver on\r
\r
\r
/**\r
- Stop Console Out ConSplitter on device handle by closing Console Out Devcice GUID.\r
+ Stop Console Out ConSplitter on device handle by closing Console Out Devcie GUID.\r
\r
@param This Driver Binding protocol instance pointer.\r
@param ControllerHandle Handle of device to stop driver on\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
Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx;\r
Private->CurrentNumberOfExConsoles++;\r
\r
+ //\r
+ // Sync current toggle state to this new console input device.\r
+ //\r
+ TextInEx->SetState (TextInEx, &Private->PhysicalKeyToggleState);\r
+\r
//\r
// Extra CheckEvent added to reduce the double CheckEvent().\r
//\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
//\r
// Find the intersection of the two set of modes. If they actually intersect, the\r
- // correponding entry in the map table is set to 1.\r
+ // corresponding entry in the map table is set to 1.\r
//\r
Mode = 0;\r
while (Mode < ConOutMaxMode) {\r
\r
\r
/**\r
- Add Grahpics Output modes into Consplitter Text Out list.\r
+ Add Graphics Output modes into Consplitter Text Out list.\r
\r
@param Private Text Out Splitter pointer.\r
@param GraphicsOutput Graphics Output protocol pointer.\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
return EFI_SUCCESS;\r
}\r
//\r
- // Max Mode is realy an intersection of the QueryMode command to all\r
+ // Max Mode is really an intersection of the QueryMode command to all\r
// devices. So we must copy the QueryMode of the first device to\r
// QueryData.\r
//\r
\r
\r
/**\r
- Reset the input device and optionaly run diagnostics\r
+ Reset the input device and optionally run diagnostics\r
\r
@param This Protocol instance pointer.\r
@param ExtendedVerification Driver may perform diagnostics on reset.\r
}\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
}\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
- be used to test for existance of a keystroke via WaitForEvent () call.\r
+ be used to test for existence of a keystroke via WaitForEvent () call.\r
\r
@param Private Protocol instance pointer.\r
@param Key Driver may perform diagnostics on reset.\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
// if any physical console input device has key input,\r
// return the key and EFI_SUCCESS.\r
//\r
- for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {\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
- *Key = CurrentKey;\r
- return 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 ((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
+ //\r
+ // Continue to read key from NEXT physical console input device.\r
+ //\r
+ Index++;\r
}\r
}\r
\r
\r
/**\r
Reads the next keystroke from the input device. The WaitForKey Event can\r
- be used to test for existance of a keystroke via WaitForEvent () call.\r
+ be used to test for existence of a keystroke via WaitForEvent () call.\r
\r
@param This Protocol instance pointer.\r
@param Key Driver may perform diagnostics on reset.\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
spliter event. This will cause the calling code to call\r
ConSplitterTextInReadKeyStroke ().\r
\r
- @param Event The Event assoicated with callback.\r
+ @param Event The Event associated with callback.\r
@param Context Context registered when Event was created.\r
\r
**/\r
pressed.\r
\r
@retval TRUE Key be pressed matches a registered key.\r
- @retval FLASE Match failed.\r
+ @retval FALSE Match failed.\r
\r
**/\r
BOOLEAN\r
\r
\r
/**\r
- Reset the input device and optionaly run diagnostics\r
+ Reset the input device and optionally run diagnostics\r
\r
@param This Protocol instance pointer.\r
@param ExtendedVerification Driver may perform diagnostics on reset.\r
}\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
\r
}\r
\r
/**\r
Reads the next keystroke from the input device. The WaitForKey Event can\r
- be used to test for existance of a keystroke via WaitForEvent () call.\r
+ be used to test for existence of a keystroke via WaitForEvent () call.\r
\r
@param This Protocol instance pointer.\r
@param KeyData A pointer to a buffer that is filled in with the\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; 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
- CopyMem (KeyData, &CurrentKeyData, sizeof (CurrentKeyData));\r
- return Status;\r
+ //\r
+ // If virtual KeyState has been required to be exposed, or it is not\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 (\r
+ &Private->KeyQueue[Private->CurrentNumberOfKeys],\r
+ &CurrentKeyData,\r
+ sizeof (EFI_KEY_DATA)\r
+ );\r
+ Private->CurrentNumberOfKeys++;\r
+ }\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
TEXT_IN_SPLITTER_PRIVATE_DATA *Private;\r
EFI_STATUS Status;\r
UINTN Index;\r
+ EFI_KEY_TOGGLE_STATE PhysicalKeyToggleState;\r
\r
if (KeyToggleState == NULL) {\r
return EFI_INVALID_PARAMETER;\r
\r
Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);\r
\r
+ //\r
+ // Always turn on physical TextInEx partial key report for\r
+ // toggle state sync.\r
+ //\r
+ PhysicalKeyToggleState = *KeyToggleState | EFI_KEY_STATE_EXPOSED;\r
+\r
//\r
// if no physical console input device exists, return EFI_SUCCESS;\r
// otherwise return the status of setting state of physical console input device\r
for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {\r
Status = Private->TextInExList[Index]->SetState (\r
Private->TextInExList[Index],\r
- KeyToggleState\r
+ &PhysicalKeyToggleState\r
);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
}\r
\r
+ //\r
+ // Record the physical KeyToggleState.\r
+ //\r
+ Private->PhysicalKeyToggleState = PhysicalKeyToggleState;\r
+ //\r
+ // Get if virtual KeyState has been required to be exposed.\r
+ //\r
+ Private->VirtualKeyStateExported = (((*KeyToggleState) & EFI_KEY_STATE_EXPOSED) != 0);\r
+\r
return EFI_SUCCESS;\r
\r
}\r
Register a notification function for a particular keystroke for the input device.\r
\r
@param This Protocol instance pointer.\r
- @param KeyData A pointer to a buffer that is filled in with the\r
- keystroke information data for the key that was\r
- pressed.\r
+ @param KeyData A pointer to a buffer that is filled in with\r
+ the keystroke information for the key that was\r
+ pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState\r
+ and KeyData.KeyState.KeyShiftState are 0, then any incomplete\r
+ keystroke will trigger a notification of the KeyNotificationFunction.\r
@param KeyNotificationFunction Points to the function to be called when the key\r
- sequence is typed specified by KeyData.\r
+ sequence is typed specified by KeyData. This notification function\r
+ should be called at <=TPL_CALLBACK.\r
@param NotifyHandle Points to the unique handle assigned to the\r
registered notification.\r
\r
@retval EFI_SUCCESS The notification function was registered\r
successfully.\r
- @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data\r
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data\r
structures.\r
@retval EFI_INVALID_PARAMETER KeyData or KeyNotificationFunction or NotifyHandle is NULL.\r
\r
if (NewNotify == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
- NewNotify->NotifyHandleList = (EFI_HANDLE *) AllocateZeroPool (sizeof (EFI_HANDLE) * Private->TextInExListCount);\r
+ NewNotify->NotifyHandleList = (VOID **) AllocateZeroPool (sizeof (VOID *) * Private->TextInExListCount);\r
if (NewNotify->NotifyHandleList == NULL) {\r
gBS->FreePool (NewNotify);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
}\r
\r
- InsertTailList (&mConIn.NotifyList, &NewNotify->NotifyEntry);\r
+ InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);\r
\r
*NotifyHandle = NewNotify;\r
\r
\r
\r
/**\r
- Reset the input device and optionaly run diagnostics\r
+ Reset the input device and optionally run diagnostics\r
\r
@param This Protocol instance pointer.\r
@param ExtendedVerification Driver may perform diagnostics on reset.\r
\r
/**\r
Reads the next keystroke from the input device. The WaitForKey Event can\r
- be used to test for existance of a keystroke via WaitForEvent () call.\r
+ be used to test for existence of a keystroke via WaitForEvent () call.\r
\r
@param Private Protocol instance pointer.\r
@param State The state information of simple pointer device.\r
\r
\r
/**\r
- This event agregates all the events of the ConIn devices in the spliter.\r
+ This event aggregates all the events of the ConIn devices in the spliter.\r
If any events of physical ConIn devices are signaled, signal the ConIn\r
spliter event. This will cause the calling code to call\r
ConSplitterTextInReadKeyStroke ().\r
\r
- @param Event The Event assoicated with callback.\r
+ @param Event The Event associated with callback.\r
@param Context Context registered when Event was created.\r
\r
**/\r
\r
\r
/**\r
- This event agregates all the events of the pointer devices in the splitter.\r
+ This event aggregates all the events of the pointer devices in the splitter.\r
If any events of physical pointer devices are signaled, signal the pointer\r
splitter event. This will cause the calling code to call\r
ConSplitterAbsolutePointerGetState ().\r
\r
- @param Event The Event assoicated with callback.\r
+ @param Event The Event associated with callback.\r
@param Context Context registered when Event was created.\r
\r
**/\r
\r
\r
/**\r
- Reset the text output device hardware and optionaly run diagnostics\r
+ Reset the text output device hardware and optionally run diagnostics\r
\r
@param This Protocol instance pointer.\r
- @param ExtendedVerification Driver may perform more exhaustive verfication\r
+ @param ExtendedVerification Driver may perform more exhaustive verification\r
operation of the device during reset.\r
\r
@retval EFI_SUCCESS The text output device was reset.\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
\r
return ReturnStatus;\r
}\r
-\r
-\r
-/**\r
- An empty function to pass error checking of CreateEventEx ().\r
-\r
- @param Event Event whose notification function is being invoked.\r
- @param Context Pointer to the notification function's context,\r
- which is implementation-dependent.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-ConSplitterEmptyCallbackFunction (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
-}\r