X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FConsole%2FConSplitterDxe%2FConSplitter.c;h=6fc0e4796f9c2fa02615e0645af0d69a0a049418;hb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;hp=b33471f92f40da3e623d7318fffa0047703ce321;hpb=f184c104afbf790a323b49d6386f88d892693eba;p=mirror_edk2.git diff --git a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c index b33471f92f..6fc0e4796f 100644 --- a/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c +++ b/MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitter.c @@ -16,19 +16,20 @@ never removed. Such design ensures sytem function well during none console device situation. -Copyright (c) 2006 - 2010, 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 - 2018, 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. +// default not connect +// +BOOLEAN mConInIsConnect = FALSE; + // // Text In Splitter Private Data template // @@ -60,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, @@ -169,7 +174,6 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = { (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL, 0, 0, - TRUE, 0, (TEXT_OUT_AND_GOP_DATA *) NULL, @@ -225,7 +229,6 @@ GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = { (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL, 0, 0, - TRUE, 0, (TEXT_OUT_AND_GOP_DATA *) NULL, @@ -295,6 +298,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. @@ -379,7 +498,7 @@ ConSplitterDriverEntry( FeaturePcdGet (PcdConOutUgaSupport)); // - // The driver creates virtual handles for ConIn, ConOut. + // The driver creates virtual handles for ConIn, ConOut, StdErr. // The virtual handles will always exist even if no console exist in the // system. This is need to support hotplug devices like USB. // @@ -414,49 +533,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 @@ -467,6 +549,28 @@ ConSplitterDriverEntry( } } + + // + // Create virtual device handle for StdErr Splitter + // + Status = ConSplitterTextOutConstructor (&mStdErr); + if (!EFI_ERROR (Status)) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &mStdErr.VirtualHandle, + &gEfiSimpleTextOutProtocolGuid, + &mStdErr.TextOut, + NULL + ); + if (!EFI_ERROR (Status)) { + // + // Update the EFI System Table with new virtual console + // and update the pointer to Text Output protocol. + // + gST->StandardErrorHandle = mStdErr.VirtualHandle; + gST->StdErr = &mStdErr.TextOut; + } + } + // // Update the CRC32 in the EFI System Table header // @@ -498,6 +602,7 @@ ConSplitterTextInConstructor ( ) { EFI_STATUS Status; + UINTN TextInExListCount; // // Allocate buffer for Simple Text Input device @@ -523,6 +628,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 // @@ -548,6 +666,8 @@ ConSplitterTextInConstructor ( InitializeListHead (&ConInPrivate->NotifyList); + ToggleStateSyncInitialization (ConInPrivate); + ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode; // // Allocate buffer for Absolute Pointer device @@ -594,6 +714,18 @@ ConSplitterTextInConstructor ( ConInPrivate, &ConInPrivate->SimplePointer.WaitForInput ); + ASSERT_EFI_ERROR (Status); + // + // Create Event to signal ConIn connection request + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + EfiEventEmptyFunction, + NULL, + &gConnectConInEventGuid, + &ConInPrivate->ConnectConInEvent + ); return Status; } @@ -1277,7 +1409,7 @@ ConSplitterConOutDriverBindingStart ( FreePool (Info); - } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { + } else if (UgaDraw != NULL) { Status = UgaDraw->GetMode ( UgaDraw, &mConOut.UgaHorizontalResolution, @@ -1315,27 +1447,6 @@ ConSplitterStdErrDriverBindingStart ( EFI_STATUS Status; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; - if (mStdErr.CurrentNumberOfConsoles == 0) { - // - // Construct console output devices' private data - // - Status = ConSplitterTextOutConstructor (&mStdErr); - if (!EFI_ERROR (Status)) { - // - // Create virtual device handle for StdErr Splitter - // - Status = gBS->InstallMultipleProtocolInterfaces ( - &mStdErr.VirtualHandle, - &gEfiSimpleTextOutProtocolGuid, - &mStdErr.TextOut, - NULL - ); - } - if (EFI_ERROR (Status)) { - return Status; - } - } - // // Start ConSplitter on ControllerHandle, and create the virtual // agrogated console device on first call Start for a StandardError handle. @@ -1364,23 +1475,6 @@ ConSplitterStdErrDriverBindingStart ( // Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL); ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK)); - if (EFI_ERROR (Status)) { - return Status; - } - - if (mStdErr.CurrentNumberOfConsoles == 1) { - gST->StandardErrorHandle = mStdErr.VirtualHandle; - gST->StdErr = &mStdErr.TextOut; - // - // Update the CRC32 in the EFI System Table header - // - gST->Hdr.CRC32 = 0; - gBS->CalculateCrc32 ( - (UINT8 *) &gST->Hdr, - gST->Hdr.HeaderSize, - &gST->Hdr.CRC32 - ); - } return Status; } @@ -1718,48 +1812,17 @@ ConSplitterStdErrDriverBindingStop ( // // Delete this console error out device's data structures. // - Status = ConSplitterTextOutDeleteDevice (&mStdErr, TextOut); - if (EFI_ERROR (Status)) { - return Status; - } - - if (mStdErr.CurrentNumberOfConsoles == 0) { - mStdErr.VirtualHandle = NULL; - - gST->StandardErrorHandle = NULL; - gST->StdErr = NULL; - // - // Update the CRC32 in the EFI System Table header - // - gST->Hdr.CRC32 = 0; - gBS->CalculateCrc32 ( - (UINT8 *) &gST->Hdr, - gST->Hdr.HeaderSize, - &gST->Hdr.CRC32 - ); - - // - // Uninstall Simple Text Output protocol from StdErr Handle. - // - gBS->UninstallMultipleProtocolInterfaces ( - mStdErr.VirtualHandle, - &gEfiSimpleTextOutProtocolGuid, - &mStdErr.TextOut, - NULL - ); - } - - return Status; + return ConSplitterTextOutDeleteDevice (&mStdErr, TextOut); } /** - Take the passed in Buffer of size SizeOfCount and grow the buffer - by MAX (CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT, MaxGrow) * SizeOfCount - bytes. Copy the current data in Buffer to the new version of Buffer - and free the old version of buffer. + Take the passed in Buffer of size ElementSize and grow the buffer + by CONSOLE_SPLITTER_ALLOC_UNIT * ElementSize bytes. + Copy the current data in Buffer to the new version of Buffer and + free the old version of buffer. - @param SizeOfCount Size of element in array. + @param ElementSize Size of element in array. @param Count Current number of elements in array. @param Buffer Bigger version of passed in Buffer with all the data. @@ -1770,7 +1833,7 @@ ConSplitterStdErrDriverBindingStop ( **/ EFI_STATUS ConSplitterGrowBuffer ( - IN UINTN SizeOfCount, + IN UINTN ElementSize, IN OUT UINTN *Count, IN OUT VOID **Buffer ) @@ -1782,15 +1845,15 @@ ConSplitterGrowBuffer ( // copy the old buffer's content to the new-size buffer, // then free the old buffer. // - *Count += CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT; Ptr = ReallocatePool ( - SizeOfCount * ((*Count) - CONSOLE_SPLITTER_CONSOLES_ALLOC_UNIT), - SizeOfCount * (*Count), + ElementSize * (*Count), + ElementSize * ((*Count) + CONSOLE_SPLITTER_ALLOC_UNIT), *Buffer ); if (Ptr == NULL) { return EFI_OUT_OF_RESOURCES; } + *Count += CONSOLE_SPLITTER_ALLOC_UNIT; *Buffer = Ptr; return EFI_SUCCESS; } @@ -1865,7 +1928,7 @@ ConSplitterTextInDeleteDevice ( // for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { if (Private->TextInList[Index] == TextIn) { - for (Index = Index; Index < Private->CurrentNumberOfConsoles - 1; Index++) { + for (; Index < Private->CurrentNumberOfConsoles - 1; Index++) { Private->TextInList[Index] = Private->TextInList[Index + 1]; } @@ -1893,12 +1956,39 @@ ConSplitterTextInExAddDevice ( IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx ) { - EFI_STATUS Status; + EFI_STATUS Status; + LIST_ENTRY *Link; + TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; + UINTN TextInExListCount; // - // If the Text Input Ex List is full, enlarge it by calling ConSplitterGrowBuffer(). + // Enlarge the NotifyHandleList and the TextInExList // if (Private->CurrentNumberOfExConsoles >= Private->TextInExListCount) { + for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); + TextInExListCount = Private->TextInExListCount; + + Status = ConSplitterGrowBuffer ( + sizeof (EFI_HANDLE), + &TextInExListCount, + (VOID **) &CurrentNotify->NotifyHandleList + ); + if (EFI_ERROR (Status)) { + 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, @@ -1908,12 +1998,41 @@ ConSplitterTextInExAddDevice ( return EFI_OUT_OF_RESOURCES; } } + + // + // Register the key notify in the new text-in device + // + for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { + CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); + Status = TextInEx->RegisterKeyNotify ( + TextInEx, + &CurrentNotify->KeyData, + CurrentNotify->KeyNotificationFn, + &CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles] + ); + if (EFI_ERROR (Status)) { + for (Link = Link->BackLink; Link != &Private->NotifyList; Link = Link->BackLink) { + CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); + TextInEx->UnregisterKeyNotify ( + TextInEx, + CurrentNotify->NotifyHandleList[Private->CurrentNumberOfExConsoles] + ); + } + return Status; + } + } + // // Add the new text-in device data structure into the Text Input Ex List. // 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(). // @@ -1945,7 +2064,7 @@ ConSplitterTextInExDeleteDevice ( // for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { if (Private->TextInExList[Index] == TextInEx) { - for (Index = Index; Index < Private->CurrentNumberOfExConsoles - 1; Index++) { + for (; Index < Private->CurrentNumberOfExConsoles - 1; Index++) { Private->TextInExList[Index] = Private->TextInExList[Index + 1]; } @@ -2022,7 +2141,7 @@ ConSplitterSimplePointerDeleteDevice ( // for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) { if (Private->PointerList[Index] == SimplePointer) { - for (Index = Index; Index < Private->CurrentNumberOfPointers - 1; Index++) { + for (; Index < Private->CurrentNumberOfPointers - 1; Index++) { Private->PointerList[Index] = Private->PointerList[Index + 1]; } @@ -2099,7 +2218,7 @@ ConSplitterAbsolutePointerDeleteDevice ( // for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) { if (Private->AbsolutePointerList[Index] == AbsolutePointer) { - for (Index = Index; Index < Private->CurrentNumberOfAbsolutePointers - 1; Index++) { + for (; Index < Private->CurrentNumberOfAbsolutePointers - 1; Index++) { Private->AbsolutePointerList[Index] = Private->AbsolutePointerList[Index + 1]; } @@ -2134,6 +2253,8 @@ ConSplitterGrowMapTable ( INT32 *OldTextOutModeMap; INT32 *SrcAddress; INT32 Index; + UINTN OldStepSize; + UINTN NewStepSize; NewSize = Private->TextOutListCount * sizeof (INT32); OldTextOutModeMap = Private->TextOutModeMap; @@ -2171,14 +2292,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++; } // @@ -2526,7 +2659,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) { @@ -2786,7 +2919,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 @@ -2826,16 +2959,14 @@ Done: if (GraphicsOutput != NULL) { Private->CurrentNumberOfGraphicsOutput++; } - if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { + if (UgaDraw != NULL) { Private->CurrentNumberOfUgaDraw++; } // // Force GraphicsOutput mode to be set, - // regardless whether the console is in EfiConsoleControlScreenGraphics or EfiConsoleControlScreenText mode // - Private->HardwareNeedsStarting = TRUE; - + Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex]; if ((GraphicsOutput != NULL) && (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) && @@ -2905,6 +3036,7 @@ ConsplitterSetConsoleOutMode ( UINTN MaxMode; EFI_STATUS Status; CONSOLE_OUT_MODE ModeInfo; + CONSOLE_OUT_MODE MaxModeInfo; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; PreferMode = 0xFF; @@ -2912,8 +3044,10 @@ ConsplitterSetConsoleOutMode ( TextOut = &Private->TextOut; MaxMode = (UINTN) (TextOut->Mode->MaxMode); - ModeInfo.Column = PcdGet32 (PcdConOutColumn); - ModeInfo.Row = PcdGet32 (PcdConOutRow); + MaxModeInfo.Column = 0; + MaxModeInfo.Row = 0; + ModeInfo.Column = PcdGet32 (PcdConOutColumn); + ModeInfo.Row = PcdGet32 (PcdConOutRow); // // To find the prefer mode and basic mode from Text Out mode list @@ -2921,8 +3055,23 @@ ConsplitterSetConsoleOutMode ( for (Mode = 0; Mode < MaxMode; Mode++) { Status = TextOut->QueryMode (TextOut, Mode, &Col, &Row); if (!EFI_ERROR(Status)) { - if (Col == ModeInfo.Column && Row == ModeInfo.Row) { - PreferMode = Mode; + if ((ModeInfo.Column != 0) && (ModeInfo.Row != 0)) { + // + // Use user defined column and row + // + if (Col == ModeInfo.Column && Row == ModeInfo.Row) { + PreferMode = Mode; + } + } else { + // + // If user sets PcdConOutColumn or PcdConOutRow to 0, + // find and set the highest text mode. + // + if ((Col >= MaxModeInfo.Column) && (Row >= MaxModeInfo.Row)) { + MaxModeInfo.Column = Col; + MaxModeInfo.Row = Row; + PreferMode = Mode; + } } if (Col == 80 && Row == 25) { BaseMode = Mode; @@ -2941,8 +3090,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 ; @@ -3033,13 +3184,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)) { @@ -3058,7 +3209,7 @@ ConSplitterTextOutAddDevice ( FreePool (Info); - } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { + } else if (UgaDraw != NULL) { Status = UgaDraw->GetMode ( UgaDraw, &UgaHorizontalResolution, @@ -3093,6 +3244,46 @@ 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. @@ -3133,14 +3324,14 @@ ConSplitterTextOutDeleteDevice ( TextOutList = Private->TextOutList; while (Index >= 0) { if (TextOutList->TextOut == TextOut) { - CopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_GOP_DATA) * Index); - CurrentNumOfConsoles--; - if (TextOutList->UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) { + if (TextOutList->UgaDraw != NULL) { Private->CurrentNumberOfUgaDraw--; } if (TextOutList->GraphicsOutput != NULL) { Private->CurrentNumberOfGraphicsOutput--; } + CopyMem (TextOutList, TextOutList + 1, sizeof (TEXT_OUT_AND_GOP_DATA) * Index); + CurrentNumOfConsoles--; break; } @@ -3154,6 +3345,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 @@ -3244,9 +3464,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 @@ -3270,7 +3529,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; @@ -3280,14 +3553,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++; } } @@ -3295,6 +3579,7 @@ ConSplitterTextInPrivateReadKeyStroke ( } + /** Reads the next keystroke from the input device. The WaitForKey Event can be used to test for existance of a keystroke via WaitForEvent () call. @@ -3321,6 +3606,15 @@ ConSplitterTextInReadKeyStroke ( Private->KeyEventSignalState = FALSE; + // + // 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->ConnectConInEvent); + mConInIsConnect = TRUE; + } + return ConSplitterTextInPrivateReadKeyStroke (Private, Key); } @@ -3455,6 +3749,14 @@ ConSplitterTextInResetEx ( } } + if (!EFI_ERROR (ReturnStatus)) { + ToggleStateSyncReInitialization (Private); + // + // Empty the key queue. + // + Private->CurrentNumberOfKeys = 0; + } + return ReturnStatus; } @@ -3486,6 +3788,7 @@ ConSplitterTextInReadKeyStrokeEx ( TEXT_IN_SPLITTER_PRIVATE_DATA *Private; EFI_STATUS Status; UINTN Index; + EFI_KEY_STATE KeyState; EFI_KEY_DATA CurrentKeyData; @@ -3497,25 +3800,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->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; } @@ -3545,6 +3914,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; @@ -3552,6 +3922,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 @@ -3559,13 +3935,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; } @@ -3575,11 +3960,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. @@ -3596,7 +3984,7 @@ ConSplitterTextInRegisterKeyNotify ( IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, IN EFI_KEY_DATA *KeyData, IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, - OUT EFI_HANDLE *NotifyHandle + OUT VOID **NotifyHandle ) { TEXT_IN_SPLITTER_PRIVATE_DATA *Private; @@ -3613,14 +4001,6 @@ ConSplitterTextInRegisterKeyNotify ( Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); - // - // If no physical console input device exists, - // return EFI_SUCCESS directly. - // - if (Private->CurrentNumberOfExConsoles <= 0) { - return EFI_SUCCESS; - } - // // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. // @@ -3628,7 +4008,7 @@ ConSplitterTextInRegisterKeyNotify ( CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { - *NotifyHandle = CurrentNotify->NotifyHandle; + *NotifyHandle = CurrentNotify; return EFI_SUCCESS; } } @@ -3641,15 +4021,14 @@ ConSplitterTextInRegisterKeyNotify ( if (NewNotify == NULL) { return EFI_OUT_OF_RESOURCES; } - NewNotify->NotifyHandleList = (EFI_HANDLE *) AllocateZeroPool (sizeof (EFI_HANDLE) * Private->CurrentNumberOfExConsoles); + NewNotify->NotifyHandleList = (EFI_HANDLE *) AllocateZeroPool (sizeof (EFI_HANDLE) * Private->TextInExListCount); if (NewNotify->NotifyHandleList == NULL) { gBS->FreePool (NewNotify); return EFI_OUT_OF_RESOURCES; } NewNotify->Signature = TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE; NewNotify->KeyNotificationFn = KeyNotificationFunction; - NewNotify->NotifyHandle = (EFI_HANDLE) NewNotify; - CopyMem (&NewNotify->KeyData, KeyData, sizeof (KeyData)); + CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); // // Return the wrong status of registering key notify of @@ -3663,15 +4042,24 @@ ConSplitterTextInRegisterKeyNotify ( &NewNotify->NotifyHandleList[Index] ); if (EFI_ERROR (Status)) { + // + // Un-register the key notify on all physical console input devices + // + while (Index-- != 0) { + Private->TextInExList[Index]->UnregisterKeyNotify ( + Private->TextInExList[Index], + NewNotify->NotifyHandleList[Index] + ); + } gBS->FreePool (NewNotify->NotifyHandleList); gBS->FreePool (NewNotify); return Status; } } - InsertTailList (&mConIn.NotifyList, &NewNotify->NotifyEntry); + InsertTailList (&Private->NotifyList, &NewNotify->NotifyEntry); - *NotifyHandle = NewNotify->NotifyHandle; + *NotifyHandle = NewNotify; return EFI_SUCCESS; @@ -3694,11 +4082,10 @@ EFI_STATUS EFIAPI ConSplitterTextInUnregisterKeyNotify ( IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_HANDLE NotificationHandle + IN VOID *NotificationHandle ) { TEXT_IN_SPLITTER_PRIVATE_DATA *Private; - EFI_STATUS Status; UINTN Index; TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; LIST_ENTRY *Link; @@ -3707,31 +4094,16 @@ ConSplitterTextInUnregisterKeyNotify ( return EFI_INVALID_PARAMETER; } - if (((TEXT_IN_EX_SPLITTER_NOTIFY *) NotificationHandle)->Signature != TEXT_IN_EX_SPLITTER_NOTIFY_SIGNATURE) { - return EFI_INVALID_PARAMETER; - } - Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); - // - // if no physical console input device exists, - // return EFI_SUCCESS directly. - // - if (Private->CurrentNumberOfExConsoles <= 0) { - return EFI_SUCCESS; - } - for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); - if (CurrentNotify->NotifyHandle == NotificationHandle) { + if (CurrentNotify == NotificationHandle) { for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { - Status = Private->TextInExList[Index]->UnregisterKeyNotify ( - Private->TextInExList[Index], - CurrentNotify->NotifyHandleList[Index] - ); - if (EFI_ERROR (Status)) { - return Status; - } + Private->TextInExList[Index]->UnregisterKeyNotify ( + Private->TextInExList[Index], + CurrentNotify->NotifyHandleList[Index] + ); } RemoveEntryList (&CurrentNotify->NotifyEntry); @@ -4017,7 +4389,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); @@ -4028,6 +4411,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, @@ -4045,16 +4435,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) { @@ -4189,37 +4610,21 @@ ConSplitterTextOutOutputString ( EFI_STATUS Status; TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; UINTN Index; - UINTN BackSpaceCount; EFI_STATUS ReturnStatus; - CHAR16 *TargetString; + UINTN MaxColumn; + UINTN MaxRow; This->SetAttribute (This, This->Mode->Attribute); Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); - BackSpaceCount = 0; - - for (TargetString = WString; *TargetString != L'\0'; TargetString++) { - if (*TargetString == CHAR_BACKSPACE) { - BackSpaceCount++; - } - } - - if (BackSpaceCount == 0) { - TargetString = WString; - } else { - TargetString = AllocatePool (sizeof (CHAR16) * (StrLen (WString) + BackSpaceCount + 1)); - ASSERT (TargetString != NULL); - - StrCpy (TargetString, WString); - } // // return the worst status met // for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { Status = Private->TextOutList[Index].TextOut->OutputString ( Private->TextOutList[Index].TextOut, - TargetString + WString ); if (EFI_ERROR (Status)) { ReturnStatus = Status; @@ -4229,10 +4634,50 @@ ConSplitterTextOutOutputString ( if (Private->CurrentNumberOfConsoles > 0) { Private->TextOutMode.CursorColumn = Private->TextOutList[0].TextOut->Mode->CursorColumn; Private->TextOutMode.CursorRow = Private->TextOutList[0].TextOut->Mode->CursorRow; - } + } else { + // + // When there is no real console devices in system, + // update cursor position for the virtual device in consplitter. + // + Private->TextOut.QueryMode ( + &Private->TextOut, + 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); + } 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; - if (BackSpaceCount > 0) { - FreePool (TargetString); + default: + if (Private->TextOutMode.CursorColumn < (INT32) (MaxColumn - 1)) { + Private->TextOutMode.CursorColumn++; + } else { + Private->TextOutMode.CursorColumn = 0; + if (Private->TextOutMode.CursorRow < (INT32) (MaxRow - 1)) { + Private->TextOutMode.CursorRow++; + } + } + break; + } + } } return ReturnStatus; @@ -4456,7 +4901,7 @@ ConSplitterTextOutSetAttribute ( // // Check whether param Attribute is valid. // - if ( (Attribute > (UINTN)(((UINT32)-1)>>1)) ) { + if ((Attribute | 0x7F) != 0x7F) { return EFI_UNSUPPORTED; } @@ -4655,4 +5100,3 @@ ConSplitterTextOutEnableCursor ( return ReturnStatus; } -