X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FConsole%2FConSplitterDxe%2FConSplitter.c;h=63c814ae1816755f3011fcb588037d3dddea1320;hp=d34e7ce5aa96adcc6461fa83d23c53c2b23ac079;hb=297495f410228bed151dc767dfbbf5617323e378;hpb=f58f3de07ef4531828c108ea099ff637f8c52d1f
diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
index d34e7ce5aa..63c814ae18 100644
--- a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
+++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c
@@ -16,21 +16,16 @@
never removed. Such design ensures sytem function well during none console
device situation.
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "ConSplitter.h"
//
-// Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode.
+// Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode.
// default not connect
//
BOOLEAN mConInIsConnect = FALSE;
@@ -66,6 +61,10 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA mConIn = {
(LIST_ENTRY *) NULL,
(LIST_ENTRY *) NULL
},
+ (EFI_KEY_DATA *) NULL,
+ 0,
+ 0,
+ FALSE,
{
ConSplitterSimplePointerReset,
@@ -181,7 +180,8 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = {
0,
(TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,
0,
- (INT32 *) NULL
+ (INT32 *) NULL,
+ FALSE
};
//
@@ -236,7 +236,8 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = {
0,
(TEXT_OUT_SPLITTER_QUERY_DATA *) NULL,
0,
- (INT32 *) NULL
+ (INT32 *) NULL,
+ FALSE
};
//
@@ -299,6 +300,122 @@ EFI_DRIVER_BINDING_PROTOCOL gConSplitterAbsolutePointerDriverBinding =
NULL
};
+/**
+ Key notify for toggle state sync.
+
+ @param KeyData A pointer to a buffer that is filled in with
+ the keystroke information for the key that was
+ pressed.
+
+ @retval EFI_SUCCESS Toggle state sync successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+ToggleStateSyncKeyNotify (
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ UINTN Index;
+
+ if (((KeyData->KeyState.KeyToggleState & KEY_STATE_VALID_EXPOSED) == KEY_STATE_VALID_EXPOSED) &&
+ (KeyData->KeyState.KeyToggleState != mConIn.PhysicalKeyToggleState)) {
+ //
+ // There is toggle state change, sync to other console input devices.
+ //
+ for (Index = 0; Index < mConIn.CurrentNumberOfExConsoles; Index++) {
+ mConIn.TextInExList[Index]->SetState (
+ mConIn.TextInExList[Index],
+ &KeyData->KeyState.KeyToggleState
+ );
+ }
+ mConIn.PhysicalKeyToggleState = KeyData->KeyState.KeyToggleState;
+ DEBUG ((EFI_D_INFO, "Current toggle state is 0x%02x\n", mConIn.PhysicalKeyToggleState));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialization for toggle state sync.
+
+ @param Private Text In Splitter pointer.
+
+**/
+VOID
+ToggleStateSyncInitialization (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private
+ )
+{
+ EFI_KEY_DATA KeyData;
+ VOID *NotifyHandle;
+
+ //
+ // Initialize PhysicalKeyToggleState that will be synced to new console
+ // input device to turn on physical TextInEx partial key report for
+ // toggle state sync.
+ //
+ Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;
+
+ //
+ // Initialize VirtualKeyStateExported to let the virtual TextInEx not report
+ // the partial key even though the physical TextInEx turns on the partial
+ // key report. The virtual TextInEx will report the partial key after it is
+ // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.
+ //
+ Private->VirtualKeyStateExported = FALSE;
+
+ //
+ // Register key notify for toggle state sync.
+ //
+ KeyData.Key.ScanCode = SCAN_NULL;
+ KeyData.Key.UnicodeChar = CHAR_NULL;
+ KeyData.KeyState.KeyShiftState = 0;
+ KeyData.KeyState.KeyToggleState = 0;
+ Private->TextInEx.RegisterKeyNotify (
+ &Private->TextInEx,
+ &KeyData,
+ ToggleStateSyncKeyNotify,
+ &NotifyHandle
+ );
+}
+
+/**
+ Reinitialization for toggle state sync.
+
+ @param Private Text In Splitter pointer.
+
+**/
+VOID
+ToggleStateSyncReInitialization (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private
+ )
+{
+ UINTN Index;
+
+ //
+ // Reinitialize PhysicalKeyToggleState that will be synced to new console
+ // input device to turn on physical TextInEx partial key report for
+ // toggle state sync.
+ //
+ Private->PhysicalKeyToggleState = KEY_STATE_VALID_EXPOSED;
+
+ //
+ // Reinitialize VirtualKeyStateExported to let the virtual TextInEx not report
+ // the partial key even though the physical TextInEx turns on the partial
+ // key report. The virtual TextInEx will report the partial key after it is
+ // required by calling SetState(X | KEY_STATE_VALID_EXPOSED) explicitly.
+ //
+ Private->VirtualKeyStateExported = FALSE;
+
+ for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
+ Private->TextInExList[Index]->SetState (
+ Private->TextInExList[Index],
+ &Private->PhysicalKeyToggleState
+ );
+ }
+}
+
/**
The Entry Point for module ConSplitter. The user code starts with this function.
@@ -418,49 +535,12 @@ ConSplitterDriverEntry(
//
Status = ConSplitterTextOutConstructor (&mConOut);
if (!EFI_ERROR (Status)) {
- if (!FeaturePcdGet (PcdConOutGopSupport)) {
- //
- // If Graphics Outpurt protocol not supported, UGA Draw protocol is installed
- // on the virtual handle.
- //
- Status = gBS->InstallMultipleProtocolInterfaces (
- &mConOut.VirtualHandle,
- &gEfiSimpleTextOutProtocolGuid,
- &mConOut.TextOut,
- &gEfiUgaDrawProtocolGuid,
- &mConOut.UgaDraw,
- NULL
- );
- } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {
- //
- // If UGA Draw protocol not supported, Graphics Output Protocol is installed
- // on virtual handle.
- //
- Status = gBS->InstallMultipleProtocolInterfaces (
- &mConOut.VirtualHandle,
- &gEfiSimpleTextOutProtocolGuid,
- &mConOut.TextOut,
- &gEfiGraphicsOutputProtocolGuid,
- &mConOut.GraphicsOutput,
- NULL
- );
- } else {
- //
- // Boot Graphics Output protocol and UGA Draw protocol are supported,
- // both they will be installed on virtual handle.
- //
- Status = gBS->InstallMultipleProtocolInterfaces (
- &mConOut.VirtualHandle,
- &gEfiSimpleTextOutProtocolGuid,
- &mConOut.TextOut,
- &gEfiGraphicsOutputProtocolGuid,
- &mConOut.GraphicsOutput,
- &gEfiUgaDrawProtocolGuid,
- &mConOut.UgaDraw,
- NULL
- );
- }
-
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mConOut.VirtualHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ &mConOut.TextOut,
+ NULL
+ );
if (!EFI_ERROR (Status)) {
//
// Update the EFI System Table with new virtual console
@@ -483,7 +563,7 @@ ConSplitterDriverEntry(
&mStdErr.TextOut,
NULL
);
- if (!EFI_ERROR (Status)) {
+ if (!EFI_ERROR (Status)) {
//
// Update the EFI System Table with new virtual console
// and update the pointer to Text Output protocol.
@@ -492,7 +572,7 @@ ConSplitterDriverEntry(
gST->StdErr = &mStdErr.TextOut;
}
}
-
+
//
// Update the CRC32 in the EFI System Table header
//
@@ -524,6 +604,7 @@ ConSplitterTextInConstructor (
)
{
EFI_STATUS Status;
+ UINTN TextInExListCount;
//
// Allocate buffer for Simple Text Input device
@@ -549,6 +630,19 @@ ConSplitterTextInConstructor (
);
ASSERT_EFI_ERROR (Status);
+ //
+ // Allocate buffer for KeyQueue
+ //
+ TextInExListCount = ConInPrivate->TextInExListCount;
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_KEY_DATA),
+ &TextInExListCount,
+ (VOID **) &ConInPrivate->KeyQueue
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
//
// Allocate buffer for Simple Text Input Ex device
//
@@ -574,6 +668,8 @@ ConSplitterTextInConstructor (
InitializeListHead (&ConInPrivate->NotifyList);
+ ToggleStateSyncInitialization (ConInPrivate);
+
ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode;
//
// Allocate buffer for Absolute Pointer device
@@ -627,10 +723,10 @@ ConSplitterTextInConstructor (
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
- ConSplitterEmptyCallbackFunction,
+ EfiEventEmptyFunction,
NULL,
&gConnectConInEventGuid,
- &ConInPrivate->ConnectConIn
+ &ConInPrivate->ConnectConInEvent
);
return Status;
@@ -1315,7 +1411,7 @@ ConSplitterConOutDriverBindingStart (
FreePool (Info);
- } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ } else if (UgaDraw != NULL) {
Status = UgaDraw->GetMode (
UgaDraw,
&mConOut.UgaHorizontalResolution,
@@ -1381,9 +1477,6 @@ ConSplitterStdErrDriverBindingStart (
//
Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL);
ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK));
- if (EFI_ERROR (Status)) {
- return Status;
- }
return Status;
}
@@ -1887,6 +1980,17 @@ ConSplitterTextInExAddDevice (
return EFI_OUT_OF_RESOURCES;
}
}
+
+ TextInExListCount = Private->TextInExListCount;
+ Status = ConSplitterGrowBuffer (
+ sizeof (EFI_KEY_DATA),
+ &TextInExListCount,
+ (VOID **) &Private->KeyQueue
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
Status = ConSplitterGrowBuffer (
sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *),
&Private->TextInExListCount,
@@ -1926,6 +2030,11 @@ ConSplitterTextInExAddDevice (
Private->TextInExList[Private->CurrentNumberOfExConsoles] = TextInEx;
Private->CurrentNumberOfExConsoles++;
+ //
+ // Sync current toggle state to this new console input device.
+ //
+ TextInEx->SetState (TextInEx, &Private->PhysicalKeyToggleState);
+
//
// Extra CheckEvent added to reduce the double CheckEvent().
//
@@ -2146,6 +2255,8 @@ ConSplitterGrowMapTable (
INT32 *OldTextOutModeMap;
INT32 *SrcAddress;
INT32 Index;
+ UINTN OldStepSize;
+ UINTN NewStepSize;
NewSize = Private->TextOutListCount * sizeof (INT32);
OldTextOutModeMap = Private->TextOutModeMap;
@@ -2183,14 +2294,26 @@ ConSplitterGrowMapTable (
Size = Private->CurrentNumberOfConsoles * sizeof (INT32);
Index = 0;
SrcAddress = OldTextOutModeMap;
+ NewStepSize = NewSize / sizeof(INT32);
+ // If Private->CurrentNumberOfConsoles is not zero and OldTextOutModeMap
+ // is not NULL, it indicates that the original TextOutModeMap is not enough
+ // for the new console devices and has been enlarged by CONSOLE_SPLITTER_ALLOC_UNIT columns.
+ //
+ OldStepSize = NewStepSize - CONSOLE_SPLITTER_ALLOC_UNIT;
//
// Copy the old data to the new one
//
while (Index < Private->TextOutMode.MaxMode) {
CopyMem (TextOutModeMap, SrcAddress, Size);
- TextOutModeMap += NewSize;
- SrcAddress += Size;
+ //
+ // Go to next row of new TextOutModeMap.
+ //
+ TextOutModeMap += NewStepSize;
+ //
+ // Go to next row of old TextOutModeMap.
+ //
+ SrcAddress += OldStepSize;
Index++;
}
//
@@ -2538,7 +2661,7 @@ ConSplitterGetIntersectionBetweenConOutAndStrErr (
//
// Find the intersection of the two set of modes. If they actually intersect, the
- // correponding entry in the map table is set to 1.
+ // corresponding entry in the map table is set to 1.
//
Mode = 0;
while (Mode < ConOutMaxMode) {
@@ -2798,7 +2921,7 @@ ConSplitterAddGraphicsOutputMode (
}
}
}
- } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ } else if (UgaDraw != NULL) {
//
// Graphics console driver can ensure the same mode for all GOP devices
// so we can get the current mode from this video device
@@ -2838,14 +2961,14 @@ Done:
if (GraphicsOutput != NULL) {
Private->CurrentNumberOfGraphicsOutput++;
}
- if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ if (UgaDraw != NULL) {
Private->CurrentNumberOfUgaDraw++;
}
//
// Force GraphicsOutput mode to be set,
//
-
+
Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex];
if ((GraphicsOutput != NULL) &&
(Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) &&
@@ -2924,7 +3047,7 @@ ConsplitterSetConsoleOutMode (
MaxMode = (UINTN) (TextOut->Mode->MaxMode);
MaxModeInfo.Column = 0;
- MaxModeInfo.Row = 0;
+ MaxModeInfo.Row = 0;
ModeInfo.Column = PcdGet32 (PcdConOutColumn);
ModeInfo.Row = PcdGet32 (PcdConOutRow);
@@ -2969,8 +3092,10 @@ ConsplitterSetConsoleOutMode (
Status = TextOut->SetMode (TextOut, BaseMode);
ASSERT(!EFI_ERROR(Status));
- PcdSet32 (PcdConOutColumn, 80);
- PcdSet32 (PcdConOutRow, 25);
+ Status = PcdSet32S (PcdConOutColumn, 80);
+ ASSERT(!EFI_ERROR(Status));
+ Status = PcdSet32S (PcdConOutRow, 25);
+ ASSERT(!EFI_ERROR(Status));
}
return ;
@@ -3009,8 +3134,9 @@ ConSplitterTextOutAddDevice (
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
EFI_STATUS DeviceStatus;
- Status = EFI_SUCCESS;
- CurrentNumOfConsoles = Private->CurrentNumberOfConsoles;
+ Status = EFI_SUCCESS;
+ CurrentNumOfConsoles = Private->CurrentNumberOfConsoles;
+ Private->AddingConOutDevice = TRUE;
//
// If the Text Out List is full, enlarge it by calling ConSplitterGrowBuffer().
@@ -3061,13 +3187,13 @@ ConSplitterTextOutAddDevice (
ASSERT (MaxMode >= 1);
DeviceStatus = EFI_DEVICE_ERROR;
- if (FeaturePcdGet (PcdConOutGopSupport)) {
- //
- // If GOP is produced by Consplitter, this device display mode will be added into Graphics Ouput modes.
- //
- if ((GraphicsOutput != NULL) || (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport))) {
- DeviceStatus = ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);
- }
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // This device display mode will be added into Graphics Ouput modes.
+ //
+ if ((GraphicsOutput != NULL) || (UgaDraw != NULL)) {
+ DeviceStatus = ConSplitterAddGraphicsOutputMode (Private, GraphicsOutput, UgaDraw);
}
if (FeaturePcdGet (PcdConOutUgaSupport)) {
@@ -3086,7 +3212,7 @@ ConSplitterTextOutAddDevice (
FreePool (Info);
- } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ } else if (UgaDraw != NULL) {
Status = UgaDraw->GetMode (
UgaDraw,
&UgaHorizontalResolution,
@@ -3121,12 +3247,54 @@ ConSplitterTextOutAddDevice (
}
}
+ if (((!EFI_ERROR (DeviceStatus)) || (!EFI_ERROR (Status))) &&
+ ((Private->CurrentNumberOfGraphicsOutput + Private->CurrentNumberOfUgaDraw) == 1)) {
+ if (!FeaturePcdGet (PcdConOutGopSupport)) {
+ //
+ // If Graphics Outpurt protocol not supported, UGA Draw protocol is installed
+ // on the virtual handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mConOut.VirtualHandle,
+ &gEfiUgaDrawProtocolGuid,
+ &mConOut.UgaDraw,
+ NULL
+ );
+ } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {
+ //
+ // If UGA Draw protocol not supported, Graphics Output Protocol is installed
+ // on virtual handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mConOut.VirtualHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &mConOut.GraphicsOutput,
+ NULL
+ );
+ } else {
+ //
+ // Boot Graphics Output protocol and UGA Draw protocol are supported,
+ // both they will be installed on virtual handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mConOut.VirtualHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &mConOut.GraphicsOutput,
+ &gEfiUgaDrawProtocolGuid,
+ &mConOut.UgaDraw,
+ NULL
+ );
+ }
+ }
+
//
// After adding new console device, all existing console devices should be
// synced to the current shared mode.
//
ConsplitterSetConsoleOutMode (Private);
+ Private->AddingConOutDevice = FALSE;
+
return Status;
}
@@ -3161,7 +3329,7 @@ ConSplitterTextOutDeleteDevice (
TextOutList = Private->TextOutList;
while (Index >= 0) {
if (TextOutList->TextOut == TextOut) {
- if (TextOutList->UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ if (TextOutList->UgaDraw != NULL) {
Private->CurrentNumberOfUgaDraw--;
}
if (TextOutList->GraphicsOutput != NULL) {
@@ -3182,6 +3350,35 @@ ConSplitterTextOutDeleteDevice (
return EFI_NOT_FOUND;
}
+ if ((Private->CurrentNumberOfGraphicsOutput == 0) && (Private->CurrentNumberOfUgaDraw == 0)) {
+ //
+ // If there is not any physical GOP and UGA device in system,
+ // Consplitter GOP or UGA protocol will be uninstalled
+ //
+ if (!FeaturePcdGet (PcdConOutGopSupport)) {
+ Status = gBS->UninstallProtocolInterface (
+ Private->VirtualHandle,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw
+ );
+ } else if (!FeaturePcdGet (PcdConOutUgaSupport)) {
+ Status = gBS->UninstallProtocolInterface (
+ Private->VirtualHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput
+ );
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Private->VirtualHandle,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput,
+ NULL
+ );
+ }
+ }
+
if (CurrentNumOfConsoles == 0) {
//
// If the number of consoles is zero, reset all parameters
@@ -3272,9 +3469,48 @@ ConSplitterTextInReset (
}
}
+ if (!EFI_ERROR (ReturnStatus)) {
+ ToggleStateSyncReInitialization (Private);
+ //
+ // Empty the key queue.
+ //
+ Private->CurrentNumberOfKeys = 0;
+ }
+
return ReturnStatus;
}
+/**
+ Dequeue the saved key from internal key queue.
+
+ @param Private Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the
+ keystroke state data for the key that was
+ pressed.
+ @retval EFI_NOT_FOUND Queue is empty.
+ @retval EFI_SUCCESS First key is dequeued and returned.
+**/
+EFI_STATUS
+ConSplitterTextInExDequeueKey (
+ IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ if (Private->CurrentNumberOfKeys == 0) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Return the first saved key.
+ //
+ CopyMem (KeyData, &Private->KeyQueue[0], sizeof (EFI_KEY_DATA));
+ Private->CurrentNumberOfKeys--;
+ CopyMem (
+ &Private->KeyQueue[0],
+ &Private->KeyQueue[1],
+ Private->CurrentNumberOfKeys * sizeof (EFI_KEY_DATA)
+ );
+ return EFI_SUCCESS;
+}
/**
Reads the next keystroke from the input device. The WaitForKey Event can
@@ -3298,7 +3534,21 @@ ConSplitterTextInPrivateReadKeyStroke (
{
EFI_STATUS Status;
UINTN Index;
- EFI_INPUT_KEY CurrentKey;
+ EFI_KEY_DATA KeyData;
+
+ //
+ // Return the first saved non-NULL key.
+ //
+ while (TRUE) {
+ Status = ConSplitterTextInExDequeueKey (Private, &KeyData);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+ return Status;
+ }
+ }
Key->UnicodeChar = 0;
Key->ScanCode = SCAN_NULL;
@@ -3308,14 +3558,25 @@ ConSplitterTextInPrivateReadKeyStroke (
// if any physical console input device has key input,
// return the key and EFI_SUCCESS.
//
- for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) {
+ for (Index = 0; Index < Private->CurrentNumberOfConsoles;) {
Status = Private->TextInList[Index]->ReadKeyStroke (
Private->TextInList[Index],
- &CurrentKey
+ &KeyData.Key
);
if (!EFI_ERROR (Status)) {
- *Key = CurrentKey;
- return Status;
+ //
+ // If it is not partial keystorke, return the key. Otherwise, continue
+ // to read key from THIS physical console input device.
+ //
+ if ((KeyData.Key.ScanCode != CHAR_NULL) || (KeyData.Key.UnicodeChar != SCAN_NULL)) {
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+ return Status;
+ }
+ } else {
+ //
+ // Continue to read key from NEXT physical console input device.
+ //
+ Index++;
}
}
@@ -3354,8 +3615,8 @@ ConSplitterTextInReadKeyStroke (
// Signal ConnectConIn event on first call in Lazy ConIn mode
//
if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {
- DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
- gBS->SignalEvent (Private->ConnectConIn);
+ DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
+ gBS->SignalEvent (Private->ConnectConInEvent);
mConInIsConnect = TRUE;
}
@@ -3493,6 +3754,14 @@ ConSplitterTextInResetEx (
}
}
+ if (!EFI_ERROR (ReturnStatus)) {
+ ToggleStateSyncReInitialization (Private);
+ //
+ // Empty the key queue.
+ //
+ Private->CurrentNumberOfKeys = 0;
+ }
+
return ReturnStatus;
}
@@ -3524,6 +3793,7 @@ ConSplitterTextInReadKeyStrokeEx (
TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
EFI_STATUS Status;
UINTN Index;
+ EFI_KEY_STATE KeyState;
EFI_KEY_DATA CurrentKeyData;
@@ -3535,34 +3805,91 @@ ConSplitterTextInReadKeyStrokeEx (
Private->KeyEventSignalState = FALSE;
- KeyData->Key.UnicodeChar = 0;
- KeyData->Key.ScanCode = SCAN_NULL;
-
//
// Signal ConnectConIn event on first call in Lazy ConIn mode
//
if (!mConInIsConnect && PcdGetBool (PcdConInConnectOnDemand)) {
- DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
- gBS->SignalEvent (Private->ConnectConIn);
+ DEBUG ((EFI_D_INFO, "Connect ConIn in first ReadKeyStoke in Lazy ConIn mode.\n"));
+ gBS->SignalEvent (Private->ConnectConInEvent);
mConInIsConnect = TRUE;
}
//
- // if no physical console input device exists, return EFI_NOT_READY;
- // if any physical console input device has key input,
- // return the key and EFI_SUCCESS.
+ // Return the first saved key.
+ //
+ Status = ConSplitterTextInExDequeueKey (Private, KeyData);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (Private->CurrentNumberOfKeys == 0);
+
+ ZeroMem (&KeyState, sizeof (KeyState));
+
+ //
+ // Iterate through all physical consoles to get key state.
+ // Some physical consoles may return valid key.
+ // Queue the valid keys.
//
for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
+ ZeroMem (&CurrentKeyData, sizeof (EFI_KEY_DATA));
Status = Private->TextInExList[Index]->ReadKeyStrokeEx (
- Private->TextInExList[Index],
- &CurrentKeyData
- );
+ Private->TextInExList[Index],
+ &CurrentKeyData
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
+ continue;
+ }
+
+ //
+ // Consolidate the key state from all physical consoles.
+ //
+ if ((CurrentKeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) {
+ KeyState.KeyShiftState |= CurrentKeyData.KeyState.KeyShiftState;
+ }
+ if ((CurrentKeyData.KeyState.KeyToggleState & EFI_TOGGLE_STATE_VALID) != 0) {
+ KeyState.KeyToggleState |= CurrentKeyData.KeyState.KeyToggleState;
+ }
+
if (!EFI_ERROR (Status)) {
- CopyMem (KeyData, &CurrentKeyData, sizeof (CurrentKeyData));
- return Status;
+ //
+ // If virtual KeyState has been required to be exposed, or it is not
+ // partial keystorke, queue the key.
+ // It's possible that user presses at multiple keyboards at the same moment,
+ // Private->KeyQueue[] are the storage to save all the keys.
+ //
+ if ((Private->VirtualKeyStateExported) ||
+ (CurrentKeyData.Key.ScanCode != CHAR_NULL) ||
+ (CurrentKeyData.Key.UnicodeChar != SCAN_NULL)) {
+ CopyMem (
+ &Private->KeyQueue[Private->CurrentNumberOfKeys],
+ &CurrentKeyData,
+ sizeof (EFI_KEY_DATA)
+ );
+ Private->CurrentNumberOfKeys++;
+ }
}
}
+ //
+ // Consolidate the key state for all keys in Private->KeyQueue[]
+ //
+ for (Index = 0; Index < Private->CurrentNumberOfKeys; Index++) {
+ CopyMem (&Private->KeyQueue[Index].KeyState, &KeyState, sizeof (EFI_KEY_STATE));
+ }
+
+ //
+ // Return the first saved key.
+ //
+ Status = ConSplitterTextInExDequeueKey (Private, KeyData);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Always return the key state even there is no key pressed.
+ //
+ ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
+ CopyMem (&KeyData->KeyState, &KeyState, sizeof (KeyData->KeyState));
return EFI_NOT_READY;
}
@@ -3592,6 +3919,7 @@ ConSplitterTextInSetState (
TEXT_IN_SPLITTER_PRIVATE_DATA *Private;
EFI_STATUS Status;
UINTN Index;
+ EFI_KEY_TOGGLE_STATE PhysicalKeyToggleState;
if (KeyToggleState == NULL) {
return EFI_INVALID_PARAMETER;
@@ -3599,6 +3927,12 @@ ConSplitterTextInSetState (
Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This);
+ //
+ // Always turn on physical TextInEx partial key report for
+ // toggle state sync.
+ //
+ PhysicalKeyToggleState = *KeyToggleState | EFI_KEY_STATE_EXPOSED;
+
//
// if no physical console input device exists, return EFI_SUCCESS;
// otherwise return the status of setting state of physical console input device
@@ -3606,13 +3940,22 @@ ConSplitterTextInSetState (
for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) {
Status = Private->TextInExList[Index]->SetState (
Private->TextInExList[Index],
- KeyToggleState
+ &PhysicalKeyToggleState
);
if (EFI_ERROR (Status)) {
return Status;
}
}
+ //
+ // Record the physical KeyToggleState.
+ //
+ Private->PhysicalKeyToggleState = PhysicalKeyToggleState;
+ //
+ // Get if virtual KeyState has been required to be exposed.
+ //
+ Private->VirtualKeyStateExported = (((*KeyToggleState) & EFI_KEY_STATE_EXPOSED) != 0);
+
return EFI_SUCCESS;
}
@@ -3622,11 +3965,14 @@ ConSplitterTextInSetState (
Register a notification function for a particular keystroke for the input device.
@param This Protocol instance pointer.
- @param KeyData A pointer to a buffer that is filled in with the
- keystroke information data for the key that was
- pressed.
+ @param KeyData A pointer to a buffer that is filled in with
+ the keystroke information for the key that was
+ pressed. If KeyData.Key, KeyData.KeyState.KeyToggleState
+ and KeyData.KeyState.KeyShiftState are 0, then any incomplete
+ keystroke will trigger a notification of the KeyNotificationFunction.
@param KeyNotificationFunction Points to the function to be called when the key
- sequence is typed specified by KeyData.
+ sequence is typed specified by KeyData. This notification function
+ should be called at <=TPL_CALLBACK.
@param NotifyHandle Points to the unique handle assigned to the
registered notification.
@@ -3716,7 +4062,7 @@ ConSplitterTextInRegisterKeyNotify (
}
}
- InsertTailList (&mConIn.NotifyList, &NewNotify->NotifyEntry);
+ InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry);
*NotifyHandle = NewNotify;
@@ -4048,7 +4394,18 @@ ConSplitterAbsolutePointerGetState (
EFI_STATUS ReturnStatus;
UINTN Index;
EFI_ABSOLUTE_POINTER_STATE CurrentState;
-
+ UINT64 MinX;
+ UINT64 MinY;
+ UINT64 MinZ;
+ UINT64 MaxX;
+ UINT64 MaxY;
+ UINT64 MaxZ;
+ UINT64 VirtualMinX;
+ UINT64 VirtualMinY;
+ UINT64 VirtualMinZ;
+ UINT64 VirtualMaxX;
+ UINT64 VirtualMaxY;
+ UINT64 VirtualMaxZ;
Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This);
@@ -4059,6 +4416,13 @@ ConSplitterAbsolutePointerGetState (
State->CurrentZ = 0;
State->ActiveButtons = 0;
+ VirtualMinX = Private->AbsolutePointerMode.AbsoluteMinX;
+ VirtualMinY = Private->AbsolutePointerMode.AbsoluteMinY;
+ VirtualMinZ = Private->AbsolutePointerMode.AbsoluteMinZ;
+ VirtualMaxX = Private->AbsolutePointerMode.AbsoluteMaxX;
+ VirtualMaxY = Private->AbsolutePointerMode.AbsoluteMaxY;
+ VirtualMaxZ = Private->AbsolutePointerMode.AbsoluteMaxZ;
+
//
// if no physical pointer device exists, return EFI_NOT_READY;
// if any physical pointer device has changed state,
@@ -4076,16 +4440,47 @@ ConSplitterAbsolutePointerGetState (
ReturnStatus = EFI_SUCCESS;
}
+ MinX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinX;
+ MinY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinY;
+ MinZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMinZ;
+ MaxX = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxX;
+ MaxY = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxY;
+ MaxZ = Private->AbsolutePointerList[Index]->Mode->AbsoluteMaxZ;
+
State->ActiveButtons = CurrentState.ActiveButtons;
- if (!(Private->AbsolutePointerMode.AbsoluteMinX == 0 && Private->AbsolutePointerMode.AbsoluteMaxX == 0)) {
- State->CurrentX = CurrentState.CurrentX;
+ //
+ // Rescale to Con Splitter virtual Absolute Pointer's resolution.
+ //
+ if (!(MinX == 0 && MaxX == 0)) {
+ State->CurrentX = VirtualMinX + DivU64x64Remainder (
+ MultU64x64 (
+ CurrentState.CurrentX,
+ VirtualMaxX - VirtualMinX
+ ),
+ MaxX - MinX,
+ NULL
+ );
}
- if (!(Private->AbsolutePointerMode.AbsoluteMinY == 0 && Private->AbsolutePointerMode.AbsoluteMaxY == 0)) {
- State->CurrentY = CurrentState.CurrentY;
+ if (!(MinY == 0 && MaxY == 0)) {
+ State->CurrentY = VirtualMinY + DivU64x64Remainder (
+ MultU64x64 (
+ CurrentState.CurrentY,
+ VirtualMaxY - VirtualMinY
+ ),
+ MaxY - MinY,
+ NULL
+ );
}
- if (!(Private->AbsolutePointerMode.AbsoluteMinZ == 0 && Private->AbsolutePointerMode.AbsoluteMaxZ == 0)) {
- State->CurrentZ = CurrentState.CurrentZ;
+ if (!(MinZ == 0 && MaxZ == 0)) {
+ State->CurrentZ = VirtualMinZ + DivU64x64Remainder (
+ MultU64x64 (
+ CurrentState.CurrentZ,
+ VirtualMaxZ - VirtualMinZ
+ ),
+ MaxZ - MinZ,
+ NULL
+ );
}
} else if (Status == EFI_DEVICE_ERROR) {
@@ -4246,7 +4641,7 @@ ConSplitterTextOutOutputString (
Private->TextOutMode.CursorRow = Private->TextOutList[0].TextOut->Mode->CursorRow;
} else {
//
- // When there is no real console devices in system,
+ // When there is no real console devices in system,
// update cursor position for the virtual device in consplitter.
//
Private->TextOut.QueryMode (
@@ -4254,28 +4649,28 @@ ConSplitterTextOutOutputString (
Private->TextOutMode.Mode,
&MaxColumn,
&MaxRow
- );
+ );
for (; *WString != CHAR_NULL; WString++) {
switch (*WString) {
case CHAR_BACKSPACE:
if (Private->TextOutMode.CursorColumn == 0 && Private->TextOutMode.CursorRow > 0) {
Private->TextOutMode.CursorRow--;
- Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1);
+ Private->TextOutMode.CursorColumn = (INT32) (MaxColumn - 1);
} else if (Private->TextOutMode.CursorColumn > 0) {
Private->TextOutMode.CursorColumn--;
}
break;
-
+
case CHAR_LINEFEED:
if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) {
Private->TextOutMode.CursorRow++;
}
break;
-
+
case CHAR_CARRIAGE_RETURN:
Private->TextOutMode.CursorColumn = 0;
break;
-
+
default:
if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) {
Private->TextOutMode.CursorColumn++;
@@ -4459,12 +4854,18 @@ ConSplitterTextOutSetMode (
//
TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber;
for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
- Status = Private->TextOutList[Index].TextOut->SetMode (
- Private->TextOutList[Index].TextOut,
- TextOutModeMap[Index]
- );
- if (EFI_ERROR (Status)) {
- ReturnStatus = Status;
+ //
+ // While adding a console out device do not set same mode again for the same device.
+ //
+ if ((!Private->AddingConOutDevice) ||
+ (TextOutModeMap[Index] != Private->TextOutList[Index].TextOut->Mode->Mode)) {
+ Status = Private->TextOutList[Index].TextOut->SetMode (
+ Private->TextOutList[Index].TextOut,
+ TextOutModeMap[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
}
}
@@ -4511,7 +4912,7 @@ ConSplitterTextOutSetAttribute (
//
// Check whether param Attribute is valid.
//
- if ( (Attribute > (UINTN)(((UINT32)-1)>>1)) ) {
+ if ((Attribute | 0x7F) != 0x7F) {
return EFI_UNSUPPORTED;
}
@@ -4710,22 +5111,3 @@ ConSplitterTextOutEnableCursor (
return ReturnStatus;
}
-
-
-/**
- An empty function to pass error checking of CreateEventEx ().
-
- @param Event Event whose notification function is being invoked.
- @param Context Pointer to the notification function's context,
- which is implementation-dependent.
-
-**/
-VOID
-EFIAPI
-ConSplitterEmptyCallbackFunction (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- return;
-}