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; -}