| /** @file | |
| Console Splitter Driver. Any Handle that attatched console I/O protocols | |
| (Console In device, Console Out device, Console Error device, Simple Pointer | |
| protocol, Absolute Pointer protocol) can be bound by this driver. | |
| So far it works like any other driver by opening a SimpleTextIn and/or | |
| SimpleTextOut protocol with EFI_OPEN_PROTOCOL_BY_DRIVER attributes. The big | |
| difference is this driver does not layer a protocol on the passed in | |
| handle, or construct a child handle like a standard device or bus driver. | |
| This driver produces three virtual handles as children, one for console input | |
| splitter, one for console output splitter and one for error output splitter. | |
| These 3 virtual handles would be installed on gST. | |
| Each virtual handle, that supports the Console I/O protocol, will be produced | |
| in the driver entry point. The virtual handle are added on driver entry and | |
| never removed. Such design ensures sytem function well during none console | |
| device situation. | |
| Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> | |
| 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. | |
| **/ | |
| #include "ConSplitter.h" | |
| // | |
| // Identify if ConIn is connected in PcdConInConnectOnDemand enabled mode. | |
| // default not connect | |
| // | |
| BOOLEAN mConInIsConnect = FALSE; | |
| // | |
| // Text In Splitter Private Data template | |
| // | |
| GLOBAL_REMOVE_IF_UNREFERENCED TEXT_IN_SPLITTER_PRIVATE_DATA mConIn = { | |
| TEXT_IN_SPLITTER_PRIVATE_DATA_SIGNATURE, | |
| (EFI_HANDLE) NULL, | |
| { | |
| ConSplitterTextInReset, | |
| ConSplitterTextInReadKeyStroke, | |
| (EFI_EVENT) NULL | |
| }, | |
| 0, | |
| (EFI_SIMPLE_TEXT_INPUT_PROTOCOL **) NULL, | |
| 0, | |
| { | |
| ConSplitterTextInResetEx, | |
| ConSplitterTextInReadKeyStrokeEx, | |
| (EFI_EVENT) NULL, | |
| ConSplitterTextInSetState, | |
| ConSplitterTextInRegisterKeyNotify, | |
| ConSplitterTextInUnregisterKeyNotify | |
| }, | |
| 0, | |
| (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL **) NULL, | |
| 0, | |
| { | |
| (LIST_ENTRY *) NULL, | |
| (LIST_ENTRY *) NULL | |
| }, | |
| { | |
| ConSplitterSimplePointerReset, | |
| ConSplitterSimplePointerGetState, | |
| (EFI_EVENT) NULL, | |
| (EFI_SIMPLE_POINTER_MODE *) NULL | |
| }, | |
| { | |
| 0x10000, | |
| 0x10000, | |
| 0x10000, | |
| TRUE, | |
| TRUE | |
| }, | |
| 0, | |
| (EFI_SIMPLE_POINTER_PROTOCOL **) NULL, | |
| 0, | |
| { | |
| ConSplitterAbsolutePointerReset, | |
| ConSplitterAbsolutePointerGetState, | |
| (EFI_EVENT) NULL, | |
| (EFI_ABSOLUTE_POINTER_MODE *) NULL | |
| }, | |
| { | |
| 0, // AbsoluteMinX | |
| 0, // AbsoluteMinY | |
| 0, // AbsoluteMinZ | |
| 0x10000, // AbsoluteMaxX | |
| 0x10000, // AbsoluteMaxY | |
| 0x10000, // AbsoluteMaxZ | |
| 0 // Attributes | |
| }, | |
| 0, | |
| (EFI_ABSOLUTE_POINTER_PROTOCOL **) NULL, | |
| 0, | |
| FALSE, | |
| FALSE, | |
| FALSE | |
| }; | |
| // | |
| // Uga Draw Protocol Private Data template | |
| // | |
| GLOBAL_REMOVE_IF_UNREFERENCED EFI_UGA_DRAW_PROTOCOL mUgaDrawProtocolTemplate = { | |
| ConSplitterUgaDrawGetMode, | |
| ConSplitterUgaDrawSetMode, | |
| ConSplitterUgaDrawBlt | |
| }; | |
| // | |
| // Graphics Output Protocol Private Data template | |
| // | |
| GLOBAL_REMOVE_IF_UNREFERENCED EFI_GRAPHICS_OUTPUT_PROTOCOL mGraphicsOutputProtocolTemplate = { | |
| ConSplitterGraphicsOutputQueryMode, | |
| ConSplitterGraphicsOutputSetMode, | |
| ConSplitterGraphicsOutputBlt, | |
| NULL | |
| }; | |
| // | |
| // Text Out Splitter Private Data template | |
| // | |
| GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mConOut = { | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE, | |
| (EFI_HANDLE) NULL, | |
| { | |
| ConSplitterTextOutReset, | |
| ConSplitterTextOutOutputString, | |
| ConSplitterTextOutTestString, | |
| ConSplitterTextOutQueryMode, | |
| ConSplitterTextOutSetMode, | |
| ConSplitterTextOutSetAttribute, | |
| ConSplitterTextOutClearScreen, | |
| ConSplitterTextOutSetCursorPosition, | |
| ConSplitterTextOutEnableCursor, | |
| (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL | |
| }, | |
| { | |
| 1, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| FALSE, | |
| }, | |
| { | |
| NULL, | |
| NULL, | |
| NULL | |
| }, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| { | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL | |
| }, | |
| (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL, | |
| 0, | |
| 0, | |
| 0, | |
| (TEXT_OUT_AND_GOP_DATA *) NULL, | |
| 0, | |
| (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL, | |
| 0, | |
| (INT32 *) NULL | |
| }; | |
| // | |
| // Standard Error Text Out Splitter Data Template | |
| // | |
| GLOBAL_REMOVE_IF_UNREFERENCED TEXT_OUT_SPLITTER_PRIVATE_DATA mStdErr = { | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA_SIGNATURE, | |
| (EFI_HANDLE) NULL, | |
| { | |
| ConSplitterTextOutReset, | |
| ConSplitterTextOutOutputString, | |
| ConSplitterTextOutTestString, | |
| ConSplitterTextOutQueryMode, | |
| ConSplitterTextOutSetMode, | |
| ConSplitterTextOutSetAttribute, | |
| ConSplitterTextOutClearScreen, | |
| ConSplitterTextOutSetCursorPosition, | |
| ConSplitterTextOutEnableCursor, | |
| (EFI_SIMPLE_TEXT_OUTPUT_MODE *) NULL | |
| }, | |
| { | |
| 1, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| FALSE, | |
| }, | |
| { | |
| NULL, | |
| NULL, | |
| NULL | |
| }, | |
| 0, | |
| 0, | |
| 0, | |
| 0, | |
| { | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL | |
| }, | |
| (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) NULL, | |
| 0, | |
| 0, | |
| 0, | |
| (TEXT_OUT_AND_GOP_DATA *) NULL, | |
| 0, | |
| (TEXT_OUT_SPLITTER_QUERY_DATA *) NULL, | |
| 0, | |
| (INT32 *) NULL | |
| }; | |
| // | |
| // Driver binding instance for Console Input Device | |
| // | |
| EFI_DRIVER_BINDING_PROTOCOL gConSplitterConInDriverBinding = { | |
| ConSplitterConInDriverBindingSupported, | |
| ConSplitterConInDriverBindingStart, | |
| ConSplitterConInDriverBindingStop, | |
| 0xa, | |
| NULL, | |
| NULL | |
| }; | |
| // | |
| // Driver binding instance for Console Out device | |
| // | |
| EFI_DRIVER_BINDING_PROTOCOL gConSplitterConOutDriverBinding = { | |
| ConSplitterConOutDriverBindingSupported, | |
| ConSplitterConOutDriverBindingStart, | |
| ConSplitterConOutDriverBindingStop, | |
| 0xa, | |
| NULL, | |
| NULL | |
| }; | |
| // | |
| // Driver binding instance for Standard Error device | |
| // | |
| EFI_DRIVER_BINDING_PROTOCOL gConSplitterStdErrDriverBinding = { | |
| ConSplitterStdErrDriverBindingSupported, | |
| ConSplitterStdErrDriverBindingStart, | |
| ConSplitterStdErrDriverBindingStop, | |
| 0xa, | |
| NULL, | |
| NULL | |
| }; | |
| // | |
| // Driver binding instance for Simple Pointer protocol | |
| // | |
| EFI_DRIVER_BINDING_PROTOCOL gConSplitterSimplePointerDriverBinding = { | |
| ConSplitterSimplePointerDriverBindingSupported, | |
| ConSplitterSimplePointerDriverBindingStart, | |
| ConSplitterSimplePointerDriverBindingStop, | |
| 0xa, | |
| NULL, | |
| NULL | |
| }; | |
| // | |
| // Driver binding instance for Absolute Pointer protocol | |
| // | |
| EFI_DRIVER_BINDING_PROTOCOL gConSplitterAbsolutePointerDriverBinding = { | |
| ConSplitterAbsolutePointerDriverBindingSupported, | |
| ConSplitterAbsolutePointerDriverBindingStart, | |
| ConSplitterAbsolutePointerDriverBindingStop, | |
| 0xa, | |
| NULL, | |
| NULL | |
| }; | |
| /** | |
| The Entry Point for module ConSplitter. The user code starts with this function. | |
| Installs driver module protocols and. Creates virtual device handles for ConIn, | |
| ConOut, and StdErr. Installs Simple Text In protocol, Simple Text In Ex protocol, | |
| Simple Pointer protocol, Absolute Pointer protocol on those virtual handlers. | |
| Installs Graphics Output protocol and/or UGA Draw protocol if needed. | |
| @param[in] ImageHandle The firmware allocated handle for the EFI image. | |
| @param[in] SystemTable A pointer to the EFI System Table. | |
| @retval EFI_SUCCESS The entry point is executed successfully. | |
| @retval other Some error occurs when executing this entry point. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterDriverEntry( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // Install driver model protocol(s). | |
| // | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gConSplitterConInDriverBinding, | |
| ImageHandle, | |
| &gConSplitterConInComponentName, | |
| &gConSplitterConInComponentName2 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gConSplitterSimplePointerDriverBinding, | |
| NULL, | |
| &gConSplitterSimplePointerComponentName, | |
| &gConSplitterSimplePointerComponentName2 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gConSplitterAbsolutePointerDriverBinding, | |
| NULL, | |
| &gConSplitterAbsolutePointerComponentName, | |
| &gConSplitterAbsolutePointerComponentName2 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gConSplitterConOutDriverBinding, | |
| NULL, | |
| &gConSplitterConOutComponentName, | |
| &gConSplitterConOutComponentName2 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gConSplitterStdErrDriverBinding, | |
| NULL, | |
| &gConSplitterStdErrComponentName, | |
| &gConSplitterStdErrComponentName2 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Either Graphics Output protocol or UGA Draw protocol must be supported. | |
| // | |
| ASSERT (FeaturePcdGet (PcdConOutGopSupport) || | |
| FeaturePcdGet (PcdConOutUgaSupport)); | |
| // | |
| // 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. | |
| // | |
| // | |
| // Create virtual device handle for ConIn Splitter | |
| // | |
| Status = ConSplitterTextInConstructor (&mConIn); | |
| if (!EFI_ERROR (Status)) { | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &mConIn.VirtualHandle, | |
| &gEfiSimpleTextInProtocolGuid, | |
| &mConIn.TextIn, | |
| &gEfiSimpleTextInputExProtocolGuid, | |
| &mConIn.TextInEx, | |
| &gEfiSimplePointerProtocolGuid, | |
| &mConIn.SimplePointer, | |
| &gEfiAbsolutePointerProtocolGuid, | |
| &mConIn.AbsolutePointer, | |
| NULL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Update the EFI System Table with new virtual console | |
| // and update the pointer to Simple Text Input protocol. | |
| // | |
| gST->ConsoleInHandle = mConIn.VirtualHandle; | |
| gST->ConIn = &mConIn.TextIn; | |
| } | |
| } | |
| // | |
| // Create virtual device handle for ConOut Splitter | |
| // | |
| Status = ConSplitterTextOutConstructor (&mConOut); | |
| if (!EFI_ERROR (Status)) { | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &mConOut.VirtualHandle, | |
| &gEfiSimpleTextOutProtocolGuid, | |
| &mConOut.TextOut, | |
| NULL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Update the EFI System Table with new virtual console | |
| // and Update the pointer to Text Output protocol. | |
| // | |
| gST->ConsoleOutHandle = mConOut.VirtualHandle; | |
| gST->ConOut = &mConOut.TextOut; | |
| } | |
| } | |
| // | |
| // 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 | |
| // | |
| gST->Hdr.CRC32 = 0; | |
| gBS->CalculateCrc32 ( | |
| (UINT8 *) &gST->Hdr, | |
| gST->Hdr.HeaderSize, | |
| &gST->Hdr.CRC32 | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Construct console input devices' private data. | |
| @param ConInPrivate A pointer to the TEXT_IN_SPLITTER_PRIVATE_DATA | |
| structure. | |
| @retval EFI_OUT_OF_RESOURCES Out of resources. | |
| @retval EFI_SUCCESS Text Input Devcie's private data has been constructed. | |
| @retval other Failed to construct private data. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterTextInConstructor ( | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *ConInPrivate | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // Allocate buffer for Simple Text Input device | |
| // | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *), | |
| &ConInPrivate->TextInListCount, | |
| (VOID **) &ConInPrivate->TextInList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Create Event to wait for a key | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_WAIT, | |
| TPL_NOTIFY, | |
| ConSplitterTextInWaitForKey, | |
| ConInPrivate, | |
| &ConInPrivate->TextIn.WaitForKey | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Allocate buffer for Simple Text Input Ex device | |
| // | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *), | |
| &ConInPrivate->TextInExListCount, | |
| (VOID **) &ConInPrivate->TextInExList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Create Event to wait for a key Ex | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_WAIT, | |
| TPL_NOTIFY, | |
| ConSplitterTextInWaitForKey, | |
| ConInPrivate, | |
| &ConInPrivate->TextInEx.WaitForKeyEx | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| InitializeListHead (&ConInPrivate->NotifyList); | |
| ConInPrivate->AbsolutePointer.Mode = &ConInPrivate->AbsolutePointerMode; | |
| // | |
| // Allocate buffer for Absolute Pointer device | |
| // | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *), | |
| &ConInPrivate->AbsolutePointerListCount, | |
| (VOID **) &ConInPrivate->AbsolutePointerList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Create Event to wait for device input for Absolute pointer device | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_WAIT, | |
| TPL_NOTIFY, | |
| ConSplitterAbsolutePointerWaitForInput, | |
| ConInPrivate, | |
| &ConInPrivate->AbsolutePointer.WaitForInput | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| ConInPrivate->SimplePointer.Mode = &ConInPrivate->SimplePointerMode; | |
| // | |
| // Allocate buffer for Simple Pointer device | |
| // | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (EFI_SIMPLE_POINTER_PROTOCOL *), | |
| &ConInPrivate->PointerListCount, | |
| (VOID **) &ConInPrivate->PointerList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Create Event to wait for device input for Simple pointer device | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_WAIT, | |
| TPL_NOTIFY, | |
| ConSplitterSimplePointerWaitForInput, | |
| ConInPrivate, | |
| &ConInPrivate->SimplePointer.WaitForInput | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Create Event to signal ConIn connection request | |
| // | |
| Status = gBS->CreateEventEx ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_CALLBACK, | |
| ConSplitterEmptyCallbackFunction, | |
| NULL, | |
| &gConnectConInEventGuid, | |
| &ConInPrivate->ConnectConInEvent | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Construct console output devices' private data. | |
| @param ConOutPrivate A pointer to the TEXT_OUT_SPLITTER_PRIVATE_DATA | |
| structure. | |
| @retval EFI_OUT_OF_RESOURCES Out of resources. | |
| @retval EFI_SUCCESS Text Input Devcie's private data has been constructed. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterTextOutConstructor ( | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *ConOutPrivate | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; | |
| // | |
| // Copy protocols template | |
| // | |
| if (FeaturePcdGet (PcdConOutUgaSupport)) { | |
| CopyMem (&ConOutPrivate->UgaDraw, &mUgaDrawProtocolTemplate, sizeof (EFI_UGA_DRAW_PROTOCOL)); | |
| } | |
| if (FeaturePcdGet (PcdConOutGopSupport)) { | |
| CopyMem (&ConOutPrivate->GraphicsOutput, &mGraphicsOutputProtocolTemplate, sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL)); | |
| } | |
| // | |
| // Initilize console output splitter's private data. | |
| // | |
| ConOutPrivate->TextOut.Mode = &ConOutPrivate->TextOutMode; | |
| // | |
| // When new console device is added, the new mode will be set later, | |
| // so put current mode back to init state. | |
| // | |
| ConOutPrivate->TextOutMode.Mode = 0xFF; | |
| // | |
| // Allocate buffer for Console Out device | |
| // | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (TEXT_OUT_AND_GOP_DATA), | |
| &ConOutPrivate->TextOutListCount, | |
| (VOID **) &ConOutPrivate->TextOutList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Allocate buffer for Text Out query data | |
| // | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (TEXT_OUT_SPLITTER_QUERY_DATA), | |
| &ConOutPrivate->TextOutQueryDataCount, | |
| (VOID **) &ConOutPrivate->TextOutQueryData | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Setup the default console to 80 x 25 and mode to 0 | |
| // | |
| ConOutPrivate->TextOutQueryData[0].Columns = 80; | |
| ConOutPrivate->TextOutQueryData[0].Rows = 25; | |
| TextOutSetMode (ConOutPrivate, 0); | |
| if (FeaturePcdGet (PcdConOutUgaSupport)) { | |
| // | |
| // Setup the UgaDraw to 800 x 600 x 32 bits per pixel, 60Hz. | |
| // | |
| ConSplitterUgaDrawSetMode (&ConOutPrivate->UgaDraw, 800, 600, 32, 60); | |
| } | |
| if (FeaturePcdGet (PcdConOutGopSupport)) { | |
| // | |
| // Setup resource for mode information in Graphics Output Protocol interface | |
| // | |
| if ((ConOutPrivate->GraphicsOutput.Mode = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE))) == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| if ((ConOutPrivate->GraphicsOutput.Mode->Info = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Setup the DevNullGraphicsOutput to 800 x 600 x 32 bits per pixel | |
| // DevNull will be updated to user-defined mode after driver has started. | |
| // | |
| if ((ConOutPrivate->GraphicsOutputModeBuffer = AllocateZeroPool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION))) == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Info = &ConOutPrivate->GraphicsOutputModeBuffer[0]; | |
| Info->Version = 0; | |
| Info->HorizontalResolution = 800; | |
| Info->VerticalResolution = 600; | |
| Info->PixelFormat = PixelBltOnly; | |
| Info->PixelsPerScanLine = 800; | |
| CopyMem (ConOutPrivate->GraphicsOutput.Mode->Info, Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); | |
| ConOutPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); | |
| // | |
| // Initialize the following items, theset items remain unchanged in GraphicsOutput->SetMode() | |
| // GraphicsOutputMode->FrameBufferBase, GraphicsOutputMode->FrameBufferSize | |
| // | |
| ConOutPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL; | |
| ConOutPrivate->GraphicsOutput.Mode->FrameBufferSize = 0; | |
| ConOutPrivate->GraphicsOutput.Mode->MaxMode = 1; | |
| // | |
| // Initial current mode to unknown state, and then set to mode 0 | |
| // | |
| ConOutPrivate->GraphicsOutput.Mode->Mode = 0xffff; | |
| ConOutPrivate->GraphicsOutput.SetMode (&ConOutPrivate->GraphicsOutput, 0); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Test to see if the specified protocol could be supported on the specified device. | |
| @param This Driver Binding protocol pointer. | |
| @param ControllerHandle Handle of device to test. | |
| @param Guid The specified protocol. | |
| @retval EFI_SUCCESS The specified protocol is supported on this device. | |
| @retval EFI_UNSUPPORTED The specified protocol attempts to be installed on virtul handle. | |
| @retval other Failed to open specified protocol on this device. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_GUID *Guid | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VOID *Instance; | |
| // | |
| // Make sure the Console Splitter does not attempt to attach to itself | |
| // | |
| if (ControllerHandle == mConIn.VirtualHandle || | |
| ControllerHandle == mConOut.VirtualHandle || | |
| ControllerHandle == mStdErr.VirtualHandle | |
| ) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Check to see whether the specific protocol could be opened BY_DRIVER | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| Guid, | |
| &Instance, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| gBS->CloseProtocol ( | |
| ControllerHandle, | |
| Guid, | |
| This->DriverBindingHandle, | |
| ControllerHandle | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Test to see if Console In Device could be supported on the Controller. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to test. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS This driver supports this device. | |
| @retval other This driver does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterConInDriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| return ConSplitterSupported ( | |
| This, | |
| ControllerHandle, | |
| &gEfiConsoleInDeviceGuid | |
| ); | |
| } | |
| /** | |
| Test to see if Simple Pointer protocol could be supported on the Controller. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to test. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS This driver supports this device. | |
| @retval other This driver does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterSimplePointerDriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| return ConSplitterSupported ( | |
| This, | |
| ControllerHandle, | |
| &gEfiSimplePointerProtocolGuid | |
| ); | |
| } | |
| /** | |
| Test to see if Absolute Pointer protocol could be supported on the Controller. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to test. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS This driver supports this device. | |
| @retval other This driver does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterAbsolutePointerDriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| return ConSplitterSupported ( | |
| This, | |
| ControllerHandle, | |
| &gEfiAbsolutePointerProtocolGuid | |
| ); | |
| } | |
| /** | |
| Test to see if Console Out Device could be supported on the Controller. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to test. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS This driver supports this device. | |
| @retval other This driver does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterConOutDriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| return ConSplitterSupported ( | |
| This, | |
| ControllerHandle, | |
| &gEfiConsoleOutDeviceGuid | |
| ); | |
| } | |
| /** | |
| Test to see if Standard Error Device could be supported on the Controller. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to test. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS This driver supports this device. | |
| @retval other This driver does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterStdErrDriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| return ConSplitterSupported ( | |
| This, | |
| ControllerHandle, | |
| &gEfiStandardErrorDeviceGuid | |
| ); | |
| } | |
| /** | |
| Start ConSplitter on devcie handle by opening Console Device Guid on device handle | |
| and the console virtual handle. And Get the console interface on controller handle. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device. | |
| @param ConSplitterVirtualHandle Console virtual Handle. | |
| @param DeviceGuid The specified Console Device, such as ConInDev, | |
| ConOutDev. | |
| @param InterfaceGuid The specified protocol to be opened. | |
| @param Interface Protocol interface returned. | |
| @retval EFI_SUCCESS This driver supports this device. | |
| @retval other Failed to open the specified Console Device Guid | |
| or specified protocol. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_HANDLE ConSplitterVirtualHandle, | |
| IN EFI_GUID *DeviceGuid, | |
| IN EFI_GUID *InterfaceGuid, | |
| OUT VOID **Interface | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VOID *Instance; | |
| // | |
| // Check to see whether the ControllerHandle has the DeviceGuid on it. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| DeviceGuid, | |
| &Instance, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Open the Parent Handle for the child. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| DeviceGuid, | |
| &Instance, | |
| This->DriverBindingHandle, | |
| ConSplitterVirtualHandle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Err; | |
| } | |
| // | |
| // Open InterfaceGuid on the virtul handle. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| InterfaceGuid, | |
| Interface, | |
| This->DriverBindingHandle, | |
| ConSplitterVirtualHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // close the DeviceGuid on ConSplitter VirtualHandle. | |
| // | |
| gBS->CloseProtocol ( | |
| ControllerHandle, | |
| DeviceGuid, | |
| This->DriverBindingHandle, | |
| ConSplitterVirtualHandle | |
| ); | |
| Err: | |
| // | |
| // close the DeviceGuid on ControllerHandle. | |
| // | |
| gBS->CloseProtocol ( | |
| ControllerHandle, | |
| DeviceGuid, | |
| This->DriverBindingHandle, | |
| ControllerHandle | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Start Console In Consplitter on device handle. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to bind driver to. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS Console In Consplitter is added to ControllerHandle. | |
| @retval other Console In Consplitter does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterConInDriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; | |
| EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx; | |
| // | |
| // Start ConSplitter on ControllerHandle, and create the virtual | |
| // agrogated console device on first call Start for a SimpleTextIn handle. | |
| // | |
| Status = ConSplitterStart ( | |
| This, | |
| ControllerHandle, | |
| mConIn.VirtualHandle, | |
| &gEfiConsoleInDeviceGuid, | |
| &gEfiSimpleTextInProtocolGuid, | |
| (VOID **) &TextIn | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Add this device into Text In devices list. | |
| // | |
| Status = ConSplitterTextInAddDevice (&mConIn, TextIn); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiSimpleTextInputExProtocolGuid, | |
| (VOID **) &TextInEx, | |
| This->DriverBindingHandle, | |
| mConIn.VirtualHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // If Simple Text Input Ex protocol exists, | |
| // add this device into Text In Ex devices list. | |
| // | |
| Status = ConSplitterTextInExAddDevice (&mConIn, TextInEx); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Start Simple Pointer Consplitter on device handle. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to bind driver to. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS Simple Pointer Consplitter is added to ControllerHandle. | |
| @retval other Simple Pointer Consplitter does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterSimplePointerDriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; | |
| // | |
| // Start ConSplitter on ControllerHandle, and create the virtual | |
| // agrogated console device on first call Start for a SimplePointer handle. | |
| // | |
| Status = ConSplitterStart ( | |
| This, | |
| ControllerHandle, | |
| mConIn.VirtualHandle, | |
| &gEfiSimplePointerProtocolGuid, | |
| &gEfiSimplePointerProtocolGuid, | |
| (VOID **) &SimplePointer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Add this devcie into Simple Pointer devices list. | |
| // | |
| return ConSplitterSimplePointerAddDevice (&mConIn, SimplePointer); | |
| } | |
| /** | |
| Start Absolute Pointer Consplitter on device handle. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to bind driver to. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS Absolute Pointer Consplitter is added to ControllerHandle. | |
| @retval other Absolute Pointer Consplitter does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterAbsolutePointerDriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer; | |
| // | |
| // Start ConSplitter on ControllerHandle, and create the virtual | |
| // agrogated console device on first call Start for a AbsolutePointer handle. | |
| // | |
| Status = ConSplitterStart ( | |
| This, | |
| ControllerHandle, | |
| mConIn.VirtualHandle, | |
| &gEfiAbsolutePointerProtocolGuid, | |
| &gEfiAbsolutePointerProtocolGuid, | |
| (VOID **) &AbsolutePointer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Add this devcie into Absolute Pointer devices list. | |
| // | |
| return ConSplitterAbsolutePointerAddDevice (&mConIn, AbsolutePointer); | |
| } | |
| /** | |
| Start Console Out Consplitter on device handle. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to bind driver to. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS Console Out Consplitter is added to ControllerHandle. | |
| @retval other Console Out Consplitter does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterConOutDriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; | |
| EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; | |
| EFI_UGA_DRAW_PROTOCOL *UgaDraw; | |
| UINTN SizeOfInfo; | |
| EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; | |
| // | |
| // Start ConSplitter on ControllerHandle, and create the virtual | |
| // agrogated console device on first call Start for a ConsoleOut handle. | |
| // | |
| Status = ConSplitterStart ( | |
| This, | |
| ControllerHandle, | |
| mConOut.VirtualHandle, | |
| &gEfiConsoleOutDeviceGuid, | |
| &gEfiSimpleTextOutProtocolGuid, | |
| (VOID **) &TextOut | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| GraphicsOutput = NULL; | |
| UgaDraw = NULL; | |
| // | |
| // Try to Open Graphics Output protocol | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiGraphicsOutputProtocolGuid, | |
| (VOID **) &GraphicsOutput, | |
| This->DriverBindingHandle, | |
| mConOut.VirtualHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) { | |
| // | |
| // Open UGA DRAW protocol | |
| // | |
| gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiUgaDrawProtocolGuid, | |
| (VOID **) &UgaDraw, | |
| This->DriverBindingHandle, | |
| mConOut.VirtualHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| } | |
| // | |
| // When new console device is added, the new mode will be set later, | |
| // so put current mode back to init state. | |
| // | |
| mConOut.TextOutMode.Mode = 0xFF; | |
| // | |
| // If both ConOut and StdErr incorporate the same Text Out device, | |
| // their MaxMode and QueryData should be the intersection of both. | |
| // | |
| Status = ConSplitterTextOutAddDevice (&mConOut, TextOut, GraphicsOutput, UgaDraw); | |
| ConSplitterTextOutSetAttribute (&mConOut.TextOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); | |
| if (FeaturePcdGet (PcdConOutUgaSupport)) { | |
| // | |
| // Get the UGA mode data of ConOut from the current mode | |
| // | |
| if (GraphicsOutput != NULL) { | |
| Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); | |
| mConOut.UgaHorizontalResolution = Info->HorizontalResolution; | |
| mConOut.UgaVerticalResolution = Info->VerticalResolution; | |
| mConOut.UgaColorDepth = 32; | |
| mConOut.UgaRefreshRate = 60; | |
| FreePool (Info); | |
| } else if (UgaDraw != NULL) { | |
| Status = UgaDraw->GetMode ( | |
| UgaDraw, | |
| &mConOut.UgaHorizontalResolution, | |
| &mConOut.UgaVerticalResolution, | |
| &mConOut.UgaColorDepth, | |
| &mConOut.UgaRefreshRate | |
| ); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Start Standard Error Consplitter on device handle. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to bind driver to. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS Standard Error Consplitter is added to ControllerHandle. | |
| @retval other Standard Error Consplitter does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterStdErrDriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; | |
| // | |
| // Start ConSplitter on ControllerHandle, and create the virtual | |
| // agrogated console device on first call Start for a StandardError handle. | |
| // | |
| Status = ConSplitterStart ( | |
| This, | |
| ControllerHandle, | |
| mStdErr.VirtualHandle, | |
| &gEfiStandardErrorDeviceGuid, | |
| &gEfiSimpleTextOutProtocolGuid, | |
| (VOID **) &TextOut | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // When new console device is added, the new mode will be set later, | |
| // so put current mode back to init state. | |
| // | |
| mStdErr.TextOutMode.Mode = 0xFF; | |
| // | |
| // If both ConOut and StdErr incorporate the same Text Out device, | |
| // their MaxMode and QueryData should be the intersection of both. | |
| // | |
| Status = ConSplitterTextOutAddDevice (&mStdErr, TextOut, NULL, NULL); | |
| ConSplitterTextOutSetAttribute (&mStdErr.TextOut, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK)); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Stop ConSplitter on device handle by closing Console Device Guid on device handle | |
| and the console virtual handle. | |
| @param This Protocol instance pointer. | |
| @param ControllerHandle Handle of device. | |
| @param ConSplitterVirtualHandle Console virtual Handle. | |
| @param DeviceGuid The specified Console Device, such as ConInDev, | |
| ConOutDev. | |
| @param InterfaceGuid The specified protocol to be opened. | |
| @param Interface Protocol interface returned. | |
| @retval EFI_SUCCESS Stop ConSplitter on ControllerHandle successfully. | |
| @retval other Failed to Stop ConSplitter on ControllerHandle. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN EFI_HANDLE ConSplitterVirtualHandle, | |
| IN EFI_GUID *DeviceGuid, | |
| IN EFI_GUID *InterfaceGuid, | |
| IN VOID **Interface | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| InterfaceGuid, | |
| Interface, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // close the protocol refered. | |
| // | |
| gBS->CloseProtocol ( | |
| ControllerHandle, | |
| DeviceGuid, | |
| This->DriverBindingHandle, | |
| ConSplitterVirtualHandle | |
| ); | |
| gBS->CloseProtocol ( | |
| ControllerHandle, | |
| DeviceGuid, | |
| This->DriverBindingHandle, | |
| ControllerHandle | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Stop Console In ConSplitter on ControllerHandle by closing Console In Devcice GUID. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to stop driver on | |
| @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of | |
| children is zero stop the entire bus driver. | |
| @param ChildHandleBuffer List of Child Handles to Stop. | |
| @retval EFI_SUCCESS This driver is removed ControllerHandle | |
| @retval other This driver was not removed from this device | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterConInDriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; | |
| EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx; | |
| if (NumberOfChildren == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| ControllerHandle, | |
| &gEfiSimpleTextInputExProtocolGuid, | |
| (VOID **) &TextInEx, | |
| This->DriverBindingHandle, | |
| ControllerHandle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // If Simple Text Input Ex protocol exists, | |
| // remove device from Text Input Ex devices list. | |
| // | |
| Status = ConSplitterTextInExDeleteDevice (&mConIn, TextInEx); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| // | |
| // Close Simple Text In protocol on controller handle and virtual handle. | |
| // | |
| Status = ConSplitterStop ( | |
| This, | |
| ControllerHandle, | |
| mConIn.VirtualHandle, | |
| &gEfiConsoleInDeviceGuid, | |
| &gEfiSimpleTextInProtocolGuid, | |
| (VOID **) &TextIn | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Remove device from Text Input devices list. | |
| // | |
| return ConSplitterTextInDeleteDevice (&mConIn, TextIn); | |
| } | |
| /** | |
| Stop Simple Pointer protocol ConSplitter on ControllerHandle by closing | |
| Simple Pointer protocol. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to stop driver on | |
| @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of | |
| children is zero stop the entire bus driver. | |
| @param ChildHandleBuffer List of Child Handles to Stop. | |
| @retval EFI_SUCCESS This driver is removed ControllerHandle | |
| @retval other This driver was not removed from this device | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterSimplePointerDriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer; | |
| if (NumberOfChildren == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Close Simple Pointer protocol on controller handle and virtual handle. | |
| // | |
| Status = ConSplitterStop ( | |
| This, | |
| ControllerHandle, | |
| mConIn.VirtualHandle, | |
| &gEfiSimplePointerProtocolGuid, | |
| &gEfiSimplePointerProtocolGuid, | |
| (VOID **) &SimplePointer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Remove this device from Simple Pointer device list. | |
| // | |
| return ConSplitterSimplePointerDeleteDevice (&mConIn, SimplePointer); | |
| } | |
| /** | |
| Stop Absolute Pointer protocol ConSplitter on ControllerHandle by closing | |
| Absolute Pointer protocol. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to stop driver on | |
| @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of | |
| children is zero stop the entire bus driver. | |
| @param ChildHandleBuffer List of Child Handles to Stop. | |
| @retval EFI_SUCCESS This driver is removed ControllerHandle | |
| @retval other This driver was not removed from this device | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterAbsolutePointerDriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer; | |
| if (NumberOfChildren == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Close Absolute Pointer protocol on controller handle and virtual handle. | |
| // | |
| Status = ConSplitterStop ( | |
| This, | |
| ControllerHandle, | |
| mConIn.VirtualHandle, | |
| &gEfiAbsolutePointerProtocolGuid, | |
| &gEfiAbsolutePointerProtocolGuid, | |
| (VOID **) &AbsolutePointer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Remove this device from Absolute Pointer device list. | |
| // | |
| return ConSplitterAbsolutePointerDeleteDevice (&mConIn, AbsolutePointer); | |
| } | |
| /** | |
| Stop Console Out ConSplitter on device handle by closing Console Out Devcice GUID. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to stop driver on | |
| @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of | |
| children is zero stop the entire bus driver. | |
| @param ChildHandleBuffer List of Child Handles to Stop. | |
| @retval EFI_SUCCESS This driver is removed ControllerHandle | |
| @retval other This driver was not removed from this device | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterConOutDriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; | |
| if (NumberOfChildren == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Close Absolute Pointer protocol on controller handle and virtual handle. | |
| // | |
| Status = ConSplitterStop ( | |
| This, | |
| ControllerHandle, | |
| mConOut.VirtualHandle, | |
| &gEfiConsoleOutDeviceGuid, | |
| &gEfiSimpleTextOutProtocolGuid, | |
| (VOID **) &TextOut | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Remove this device from Text Out device list. | |
| // | |
| return ConSplitterTextOutDeleteDevice (&mConOut, TextOut); | |
| } | |
| /** | |
| Stop Standard Error ConSplitter on ControllerHandle by closing Standard Error GUID. | |
| @param This Driver Binding protocol instance pointer. | |
| @param ControllerHandle Handle of device to stop driver on | |
| @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of | |
| children is zero stop the entire bus driver. | |
| @param ChildHandleBuffer List of Child Handles to Stop. | |
| @retval EFI_SUCCESS This driver is removed ControllerHandle | |
| @retval other This driver was not removed from this device | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterStdErrDriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ControllerHandle, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; | |
| if (NumberOfChildren == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Close Standard Error Device on controller handle and virtual handle. | |
| // | |
| Status = ConSplitterStop ( | |
| This, | |
| ControllerHandle, | |
| mStdErr.VirtualHandle, | |
| &gEfiStandardErrorDeviceGuid, | |
| &gEfiSimpleTextOutProtocolGuid, | |
| (VOID **) &TextOut | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Delete this console error out device's data structures. | |
| // | |
| return ConSplitterTextOutDeleteDevice (&mStdErr, TextOut); | |
| } | |
| /** | |
| 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 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. | |
| @retval EFI_SUCCESS Buffer size has grown. | |
| @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterGrowBuffer ( | |
| IN UINTN ElementSize, | |
| IN OUT UINTN *Count, | |
| IN OUT VOID **Buffer | |
| ) | |
| { | |
| VOID *Ptr; | |
| // | |
| // grow the buffer to new buffer size, | |
| // copy the old buffer's content to the new-size buffer, | |
| // then free the old buffer. | |
| // | |
| Ptr = ReallocatePool ( | |
| 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; | |
| } | |
| /** | |
| Add Text Input Device in Consplitter Text Input list. | |
| @param Private Text In Splitter pointer. | |
| @param TextIn Simple Text Input protocol pointer. | |
| @retval EFI_SUCCESS Text Input Device added successfully. | |
| @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterTextInAddDevice ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // If the Text In List is full, enlarge it by calling ConSplitterGrowBuffer(). | |
| // | |
| if (Private->CurrentNumberOfConsoles >= Private->TextInListCount) { | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *), | |
| &Private->TextInListCount, | |
| (VOID **) &Private->TextInList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| } | |
| // | |
| // Add the new text-in device data structure into the Text In List. | |
| // | |
| Private->TextInList[Private->CurrentNumberOfConsoles] = TextIn; | |
| Private->CurrentNumberOfConsoles++; | |
| // | |
| // Extra CheckEvent added to reduce the double CheckEvent(). | |
| // | |
| gBS->CheckEvent (TextIn->WaitForKey); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Remove Text Input Device from Consplitter Text Input list. | |
| @param Private Text In Splitter pointer. | |
| @param TextIn Simple Text protocol pointer. | |
| @retval EFI_SUCCESS Simple Text Device removed successfully. | |
| @retval EFI_NOT_FOUND No Simple Text Device found. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterTextInDeleteDevice ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn | |
| ) | |
| { | |
| UINTN Index; | |
| // | |
| // Remove the specified text-in device data structure from the Text In List, | |
| // and rearrange the remaining data structures in the Text In List. | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| if (Private->TextInList[Index] == TextIn) { | |
| for (; Index < Private->CurrentNumberOfConsoles - 1; Index++) { | |
| Private->TextInList[Index] = Private->TextInList[Index + 1]; | |
| } | |
| Private->CurrentNumberOfConsoles--; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Add Text Input Ex Device in Consplitter Text Input Ex list. | |
| @param Private Text In Splitter pointer. | |
| @param TextInEx Simple Text Input Ex Input protocol pointer. | |
| @retval EFI_SUCCESS Text Input Ex Device added successfully. | |
| @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterTextInExAddDevice ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; | |
| UINTN TextInExListCount; | |
| // | |
| // 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; | |
| } | |
| } | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *), | |
| &Private->TextInExListCount, | |
| (VOID **) &Private->TextInExList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| 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++; | |
| // | |
| // Extra CheckEvent added to reduce the double CheckEvent(). | |
| // | |
| gBS->CheckEvent (TextInEx->WaitForKeyEx); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Remove Text Ex Device from Consplitter Text Input Ex list. | |
| @param Private Text In Splitter pointer. | |
| @param TextInEx Simple Text Ex protocol pointer. | |
| @retval EFI_SUCCESS Simple Text Input Ex Device removed successfully. | |
| @retval EFI_NOT_FOUND No Simple Text Input Ex Device found. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterTextInExDeleteDevice ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx | |
| ) | |
| { | |
| UINTN Index; | |
| // | |
| // Remove the specified text-in device data structure from the Text Input Ex List, | |
| // and rearrange the remaining data structures in the Text In List. | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { | |
| if (Private->TextInExList[Index] == TextInEx) { | |
| for (; Index < Private->CurrentNumberOfExConsoles - 1; Index++) { | |
| Private->TextInExList[Index] = Private->TextInExList[Index + 1]; | |
| } | |
| Private->CurrentNumberOfExConsoles--; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Add Simple Pointer Device in Consplitter Simple Pointer list. | |
| @param Private Text In Splitter pointer. | |
| @param SimplePointer Simple Pointer protocol pointer. | |
| @retval EFI_SUCCESS Simple Pointer Device added successfully. | |
| @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterSimplePointerAddDevice ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // If the Simple Pointer List is full, enlarge it by calling ConSplitterGrowBuffer(). | |
| // | |
| if (Private->CurrentNumberOfPointers >= Private->PointerListCount) { | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (EFI_SIMPLE_POINTER_PROTOCOL *), | |
| &Private->PointerListCount, | |
| (VOID **) &Private->PointerList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| } | |
| // | |
| // Add the new text-in device data structure into the Simple Pointer List. | |
| // | |
| Private->PointerList[Private->CurrentNumberOfPointers] = SimplePointer; | |
| Private->CurrentNumberOfPointers++; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Remove Simple Pointer Device from Consplitter Simple Pointer list. | |
| @param Private Text In Splitter pointer. | |
| @param SimplePointer Simple Pointer protocol pointer. | |
| @retval EFI_SUCCESS Simple Pointer Device removed successfully. | |
| @retval EFI_NOT_FOUND No Simple Pointer Device found. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterSimplePointerDeleteDevice ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_POINTER_PROTOCOL *SimplePointer | |
| ) | |
| { | |
| UINTN Index; | |
| // | |
| // Remove the specified text-in device data structure from the Simple Pointer List, | |
| // and rearrange the remaining data structures in the Text In List. | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) { | |
| if (Private->PointerList[Index] == SimplePointer) { | |
| for (; Index < Private->CurrentNumberOfPointers - 1; Index++) { | |
| Private->PointerList[Index] = Private->PointerList[Index + 1]; | |
| } | |
| Private->CurrentNumberOfPointers--; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Add Absolute Pointer Device in Consplitter Absolute Pointer list. | |
| @param Private Text In Splitter pointer. | |
| @param AbsolutePointer Absolute Pointer protocol pointer. | |
| @retval EFI_SUCCESS Absolute Pointer Device added successfully. | |
| @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterAbsolutePointerAddDevice ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // If the Absolute Pointer List is full, enlarge it by calling ConSplitterGrowBuffer(). | |
| // | |
| if (Private->CurrentNumberOfAbsolutePointers >= Private->AbsolutePointerListCount) { | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (EFI_ABSOLUTE_POINTER_PROTOCOL *), | |
| &Private->AbsolutePointerListCount, | |
| (VOID **) &Private->AbsolutePointerList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| } | |
| // | |
| // Add the new text-in device data structure into the Absolute Pointer List. | |
| // | |
| Private->AbsolutePointerList[Private->CurrentNumberOfAbsolutePointers] = AbsolutePointer; | |
| Private->CurrentNumberOfAbsolutePointers++; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Remove Absolute Pointer Device from Consplitter Absolute Pointer list. | |
| @param Private Text In Splitter pointer. | |
| @param AbsolutePointer Absolute Pointer protocol pointer. | |
| @retval EFI_SUCCESS Absolute Pointer Device removed successfully. | |
| @retval EFI_NOT_FOUND No Absolute Pointer Device found. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterAbsolutePointerDeleteDevice ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer | |
| ) | |
| { | |
| UINTN Index; | |
| // | |
| // Remove the specified text-in device data structure from the Absolute Pointer List, | |
| // and rearrange the remaining data structures from the Absolute Pointer List. | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) { | |
| if (Private->AbsolutePointerList[Index] == AbsolutePointer) { | |
| for (; Index < Private->CurrentNumberOfAbsolutePointers - 1; Index++) { | |
| Private->AbsolutePointerList[Index] = Private->AbsolutePointerList[Index + 1]; | |
| } | |
| Private->CurrentNumberOfAbsolutePointers--; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Reallocate Text Out mode map. | |
| Allocate new buffer and copy original buffer into the new buffer. | |
| @param Private Consplitter Text Out pointer. | |
| @retval EFI_SUCCESS Buffer size has grown | |
| @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterGrowMapTable ( | |
| IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private | |
| ) | |
| { | |
| UINTN Size; | |
| UINTN NewSize; | |
| UINTN TotalSize; | |
| INT32 *TextOutModeMap; | |
| INT32 *OldTextOutModeMap; | |
| INT32 *SrcAddress; | |
| INT32 Index; | |
| UINTN OldStepSize; | |
| UINTN NewStepSize; | |
| NewSize = Private->TextOutListCount * sizeof (INT32); | |
| OldTextOutModeMap = Private->TextOutModeMap; | |
| TotalSize = NewSize * (Private->TextOutQueryDataCount); | |
| // | |
| // Allocate new buffer for Text Out List. | |
| // | |
| TextOutModeMap = AllocatePool (TotalSize); | |
| if (TextOutModeMap == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| SetMem (TextOutModeMap, TotalSize, 0xFF); | |
| Private->TextOutModeMap = TextOutModeMap; | |
| // | |
| // If TextOutList has been enlarged, need to realloc the mode map table | |
| // The mode map table is regarded as a two dimension array. | |
| // | |
| // Old New | |
| // 0 ---------> TextOutListCount ----> TextOutListCount | |
| // | ------------------------------------------- | |
| // | | | | | |
| // | | | | | |
| // | | | | | |
| // | | | | | |
| // | | | | | |
| // \/ | | | | |
| // ------------------------------------------- | |
| // QueryDataCount | |
| // | |
| if (OldTextOutModeMap != NULL) { | |
| 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); | |
| // | |
| // Go to next row of new TextOutModeMap. | |
| // | |
| TextOutModeMap += NewStepSize; | |
| // | |
| // Go to next row of old TextOutModeMap. | |
| // | |
| SrcAddress += OldStepSize; | |
| Index++; | |
| } | |
| // | |
| // Free the old buffer | |
| // | |
| FreePool (OldTextOutModeMap); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Add new device's output mode to console splitter's mode list. | |
| @param Private Text Out Splitter pointer | |
| @param TextOut Simple Text Output protocol pointer. | |
| @retval EFI_SUCCESS Device added successfully. | |
| @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterAddOutputMode ( | |
| IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| INT32 MaxMode; | |
| INT32 Mode; | |
| UINTN Index; | |
| MaxMode = TextOut->Mode->MaxMode; | |
| Private->TextOutMode.MaxMode = MaxMode; | |
| // | |
| // Grow the buffer if query data buffer is not large enough to | |
| // hold all the mode supported by the first console. | |
| // | |
| while (MaxMode > (INT32) Private->TextOutQueryDataCount) { | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (TEXT_OUT_SPLITTER_QUERY_DATA), | |
| &Private->TextOutQueryDataCount, | |
| (VOID **) &Private->TextOutQueryData | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| } | |
| // | |
| // Allocate buffer for the output mode map | |
| // | |
| Status = ConSplitterGrowMapTable (Private); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // As the first textout device, directly add the mode in to QueryData | |
| // and at the same time record the mapping between QueryData and TextOut. | |
| // | |
| Mode = 0; | |
| Index = 0; | |
| while (Mode < MaxMode) { | |
| Status = TextOut->QueryMode ( | |
| TextOut, | |
| Mode, | |
| &Private->TextOutQueryData[Mode].Columns, | |
| &Private->TextOutQueryData[Mode].Rows | |
| ); | |
| // | |
| // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData | |
| // is clear to 0x0. | |
| // | |
| if ((EFI_ERROR(Status)) && (Mode == 1)) { | |
| Private->TextOutQueryData[Mode].Columns = 0; | |
| Private->TextOutQueryData[Mode].Rows = 0; | |
| } | |
| Private->TextOutModeMap[Index] = Mode; | |
| Mode++; | |
| Index += Private->TextOutListCount; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Reconstruct TextOutModeMap to get intersection of modes. | |
| This routine reconstruct TextOutModeMap to get the intersection | |
| of modes for all console out devices. Because EFI/UEFI spec require | |
| mode 0 is 80x25, mode 1 is 80x50, this routine will not check the | |
| intersection for mode 0 and mode 1. | |
| @param TextOutModeMap Current text out mode map, begin with the mode 80x25 | |
| @param NewlyAddedMap New text out mode map, begin with the mode 80x25 | |
| @param MapStepSize Mode step size for one console device | |
| @param NewMapStepSize New Mode step size for one console device | |
| @param MaxMode IN: Current max text mode, OUT: Updated max text mode. | |
| @param CurrentMode IN: Current text mode, OUT: Updated current text mode. | |
| **/ | |
| VOID | |
| ConSplitterGetIntersection ( | |
| IN INT32 *TextOutModeMap, | |
| IN INT32 *NewlyAddedMap, | |
| IN UINTN MapStepSize, | |
| IN UINTN NewMapStepSize, | |
| IN OUT INT32 *MaxMode, | |
| IN OUT INT32 *CurrentMode | |
| ) | |
| { | |
| INT32 Index; | |
| INT32 *CurrentMapEntry; | |
| INT32 *NextMapEntry; | |
| INT32 *NewMapEntry; | |
| INT32 CurrentMaxMode; | |
| INT32 Mode; | |
| // | |
| // According to EFI/UEFI spec, mode 0 and mode 1 have been reserved | |
| // for 80x25 and 80x50 in Simple Text Out protocol, so don't make intersection | |
| // for mode 0 and mode 1, mode number starts from 2. | |
| // | |
| Index = 2; | |
| CurrentMapEntry = &TextOutModeMap[MapStepSize * 2]; | |
| NextMapEntry = CurrentMapEntry; | |
| NewMapEntry = &NewlyAddedMap[NewMapStepSize * 2]; | |
| CurrentMaxMode = *MaxMode; | |
| Mode = *CurrentMode; | |
| while (Index < CurrentMaxMode) { | |
| if (*NewMapEntry == -1) { | |
| // | |
| // This mode is not supported any more. Remove it. Special care | |
| // must be taken as this remove will also affect current mode; | |
| // | |
| if (Index == *CurrentMode) { | |
| Mode = -1; | |
| } else if (Index < *CurrentMode) { | |
| Mode--; | |
| } | |
| (*MaxMode)--; | |
| } else { | |
| if (CurrentMapEntry != NextMapEntry) { | |
| CopyMem (NextMapEntry, CurrentMapEntry, MapStepSize * sizeof (INT32)); | |
| } | |
| NextMapEntry += MapStepSize; | |
| } | |
| CurrentMapEntry += MapStepSize; | |
| NewMapEntry += NewMapStepSize; | |
| Index++; | |
| } | |
| *CurrentMode = Mode; | |
| return ; | |
| } | |
| /** | |
| Sync the device's output mode to console splitter's mode list. | |
| @param Private Text Out Splitter pointer. | |
| @param TextOut Simple Text Output protocol pointer. | |
| **/ | |
| VOID | |
| ConSplitterSyncOutputMode ( | |
| IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut | |
| ) | |
| { | |
| INT32 CurrentMaxMode; | |
| INT32 Mode; | |
| INT32 Index; | |
| INT32 *TextOutModeMap; | |
| INT32 *MapTable; | |
| INT32 QueryMode; | |
| TEXT_OUT_SPLITTER_QUERY_DATA *TextOutQueryData; | |
| UINTN Rows; | |
| UINTN Columns; | |
| UINTN StepSize; | |
| EFI_STATUS Status; | |
| // | |
| // Must make sure that current mode won't change even if mode number changes | |
| // | |
| CurrentMaxMode = Private->TextOutMode.MaxMode; | |
| TextOutModeMap = Private->TextOutModeMap; | |
| StepSize = Private->TextOutListCount; | |
| TextOutQueryData = Private->TextOutQueryData; | |
| // | |
| // Query all the mode that the newly added TextOut supports | |
| // | |
| Mode = 0; | |
| MapTable = TextOutModeMap + Private->CurrentNumberOfConsoles; | |
| while (Mode < TextOut->Mode->MaxMode) { | |
| Status = TextOut->QueryMode (TextOut, Mode, &Columns, &Rows); | |
| if (EFI_ERROR(Status)) { | |
| if (Mode == 1) { | |
| // | |
| // If mode 1 (80x50) is not supported, make sure mode 1 in TextOutQueryData | |
| // is clear to 0x0. | |
| // | |
| MapTable[StepSize] = Mode; | |
| TextOutQueryData[Mode].Columns = 0; | |
| TextOutQueryData[Mode].Rows = 0; | |
| } | |
| Mode++; | |
| continue; | |
| } | |
| // | |
| // Search the intersection map and QueryData database to see if they intersects | |
| // | |
| Index = 0; | |
| while (Index < CurrentMaxMode) { | |
| QueryMode = *(TextOutModeMap + Index * StepSize); | |
| if ((TextOutQueryData[QueryMode].Rows == Rows) && (TextOutQueryData[QueryMode].Columns == Columns)) { | |
| MapTable[Index * StepSize] = Mode; | |
| break; | |
| } | |
| Index++; | |
| } | |
| Mode++; | |
| } | |
| // | |
| // Now search the TextOutModeMap table to find the intersection of supported | |
| // mode between ConSplitter and the newly added device. | |
| // | |
| ConSplitterGetIntersection ( | |
| TextOutModeMap, | |
| MapTable, | |
| StepSize, | |
| StepSize, | |
| &Private->TextOutMode.MaxMode, | |
| &Private->TextOutMode.Mode | |
| ); | |
| return ; | |
| } | |
| /** | |
| Sync output device between ConOut and StdErr output. | |
| @retval EFI_SUCCESS Sync implemented successfully. | |
| @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterGetIntersectionBetweenConOutAndStrErr ( | |
| VOID | |
| ) | |
| { | |
| UINTN ConOutNumOfConsoles; | |
| UINTN StdErrNumOfConsoles; | |
| TEXT_OUT_AND_GOP_DATA *ConOutTextOutList; | |
| TEXT_OUT_AND_GOP_DATA *StdErrTextOutList; | |
| UINTN Indexi; | |
| UINTN Indexj; | |
| UINTN ConOutRows; | |
| UINTN ConOutColumns; | |
| UINTN StdErrRows; | |
| UINTN StdErrColumns; | |
| INT32 ConOutMaxMode; | |
| INT32 StdErrMaxMode; | |
| INT32 ConOutMode; | |
| INT32 StdErrMode; | |
| INT32 Mode; | |
| INT32 Index; | |
| INT32 *ConOutModeMap; | |
| INT32 *StdErrModeMap; | |
| INT32 *ConOutMapTable; | |
| INT32 *StdErrMapTable; | |
| TEXT_OUT_SPLITTER_QUERY_DATA *ConOutQueryData; | |
| TEXT_OUT_SPLITTER_QUERY_DATA *StdErrQueryData; | |
| UINTN ConOutStepSize; | |
| UINTN StdErrStepSize; | |
| BOOLEAN FoundTheSameTextOut; | |
| UINTN ConOutMapTableSize; | |
| UINTN StdErrMapTableSize; | |
| ConOutNumOfConsoles = mConOut.CurrentNumberOfConsoles; | |
| StdErrNumOfConsoles = mStdErr.CurrentNumberOfConsoles; | |
| ConOutTextOutList = mConOut.TextOutList; | |
| StdErrTextOutList = mStdErr.TextOutList; | |
| Indexi = 0; | |
| FoundTheSameTextOut = FALSE; | |
| while ((Indexi < ConOutNumOfConsoles) && (!FoundTheSameTextOut)) { | |
| Indexj = 0; | |
| while (Indexj < StdErrNumOfConsoles) { | |
| if (ConOutTextOutList->TextOut == StdErrTextOutList->TextOut) { | |
| FoundTheSameTextOut = TRUE; | |
| break; | |
| } | |
| Indexj++; | |
| StdErrTextOutList++; | |
| } | |
| Indexi++; | |
| ConOutTextOutList++; | |
| } | |
| if (!FoundTheSameTextOut) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Must make sure that current mode won't change even if mode number changes | |
| // | |
| ConOutMaxMode = mConOut.TextOutMode.MaxMode; | |
| ConOutModeMap = mConOut.TextOutModeMap; | |
| ConOutStepSize = mConOut.TextOutListCount; | |
| ConOutQueryData = mConOut.TextOutQueryData; | |
| StdErrMaxMode = mStdErr.TextOutMode.MaxMode; | |
| StdErrModeMap = mStdErr.TextOutModeMap; | |
| StdErrStepSize = mStdErr.TextOutListCount; | |
| StdErrQueryData = mStdErr.TextOutQueryData; | |
| // | |
| // Allocate the map table and set the map table's index to -1. | |
| // | |
| ConOutMapTableSize = ConOutMaxMode * sizeof (INT32); | |
| ConOutMapTable = AllocateZeroPool (ConOutMapTableSize); | |
| if (ConOutMapTable == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| SetMem (ConOutMapTable, ConOutMapTableSize, 0xFF); | |
| StdErrMapTableSize = StdErrMaxMode * sizeof (INT32); | |
| StdErrMapTable = AllocateZeroPool (StdErrMapTableSize); | |
| if (StdErrMapTable == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| SetMem (StdErrMapTable, StdErrMapTableSize, 0xFF); | |
| // | |
| // Find the intersection of the two set of modes. If they actually intersect, the | |
| // correponding entry in the map table is set to 1. | |
| // | |
| Mode = 0; | |
| while (Mode < ConOutMaxMode) { | |
| // | |
| // Search the intersection map and QueryData database to see if they intersect | |
| // | |
| Index = 0; | |
| ConOutMode = *(ConOutModeMap + Mode * ConOutStepSize); | |
| ConOutRows = ConOutQueryData[ConOutMode].Rows; | |
| ConOutColumns = ConOutQueryData[ConOutMode].Columns; | |
| while (Index < StdErrMaxMode) { | |
| StdErrMode = *(StdErrModeMap + Index * StdErrStepSize); | |
| StdErrRows = StdErrQueryData[StdErrMode].Rows; | |
| StdErrColumns = StdErrQueryData[StdErrMode].Columns; | |
| if ((StdErrRows == ConOutRows) && (StdErrColumns == ConOutColumns)) { | |
| ConOutMapTable[Mode] = 1; | |
| StdErrMapTable[Index] = 1; | |
| break; | |
| } | |
| Index++; | |
| } | |
| Mode++; | |
| } | |
| // | |
| // Now search the TextOutModeMap table to find the intersection of supported | |
| // mode between ConSplitter and the newly added device. | |
| // | |
| ConSplitterGetIntersection ( | |
| ConOutModeMap, | |
| ConOutMapTable, | |
| mConOut.TextOutListCount, | |
| 1, | |
| &(mConOut.TextOutMode.MaxMode), | |
| &(mConOut.TextOutMode.Mode) | |
| ); | |
| if (mConOut.TextOutMode.Mode < 0) { | |
| mConOut.TextOut.SetMode (&(mConOut.TextOut), 0); | |
| } | |
| ConSplitterGetIntersection ( | |
| StdErrModeMap, | |
| StdErrMapTable, | |
| mStdErr.TextOutListCount, | |
| 1, | |
| &(mStdErr.TextOutMode.MaxMode), | |
| &(mStdErr.TextOutMode.Mode) | |
| ); | |
| if (mStdErr.TextOutMode.Mode < 0) { | |
| mStdErr.TextOut.SetMode (&(mStdErr.TextOut), 0); | |
| } | |
| FreePool (ConOutMapTable); | |
| FreePool (StdErrMapTable); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Add Grahpics Output modes into Consplitter Text Out list. | |
| @param Private Text Out Splitter pointer. | |
| @param GraphicsOutput Graphics Output protocol pointer. | |
| @param UgaDraw UGA Draw protocol pointer. | |
| @retval EFI_SUCCESS Output mode added successfully. | |
| @retval other Failed to add output mode. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterAddGraphicsOutputMode ( | |
| IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, | |
| IN EFI_UGA_DRAW_PROTOCOL *UgaDraw | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| UINTN CurrentIndex; | |
| EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Mode; | |
| UINTN SizeOfInfo; | |
| EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; | |
| EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *CurrentGraphicsOutputMode; | |
| EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeBuffer; | |
| EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *MatchedMode; | |
| UINTN NumberIndex; | |
| BOOLEAN Match; | |
| BOOLEAN AlreadyExist; | |
| UINT32 UgaHorizontalResolution; | |
| UINT32 UgaVerticalResolution; | |
| UINT32 UgaColorDepth; | |
| UINT32 UgaRefreshRate; | |
| ASSERT (GraphicsOutput != NULL || UgaDraw != NULL); | |
| CurrentGraphicsOutputMode = Private->GraphicsOutput.Mode; | |
| Index = 0; | |
| CurrentIndex = 0; | |
| Status = EFI_SUCCESS; | |
| if (Private->CurrentNumberOfUgaDraw != 0) { | |
| // | |
| // If any UGA device has already been added, then there is no need to | |
| // calculate intersection of display mode of different GOP/UGA device, | |
| // since only one display mode will be exported (i.e. user-defined mode) | |
| // | |
| goto Done; | |
| } | |
| if (GraphicsOutput != NULL) { | |
| if (Private->CurrentNumberOfGraphicsOutput == 0) { | |
| // | |
| // This is the first Graphics Output device added | |
| // | |
| CurrentGraphicsOutputMode->MaxMode = GraphicsOutput->Mode->MaxMode; | |
| CurrentGraphicsOutputMode->Mode = GraphicsOutput->Mode->Mode; | |
| CopyMem (CurrentGraphicsOutputMode->Info, GraphicsOutput->Mode->Info, GraphicsOutput->Mode->SizeOfInfo); | |
| CurrentGraphicsOutputMode->SizeOfInfo = GraphicsOutput->Mode->SizeOfInfo; | |
| CurrentGraphicsOutputMode->FrameBufferBase = GraphicsOutput->Mode->FrameBufferBase; | |
| CurrentGraphicsOutputMode->FrameBufferSize = GraphicsOutput->Mode->FrameBufferSize; | |
| // | |
| // Allocate resource for the private mode buffer | |
| // | |
| ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * GraphicsOutput->Mode->MaxMode); | |
| if (ModeBuffer == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| FreePool (Private->GraphicsOutputModeBuffer); | |
| Private->GraphicsOutputModeBuffer = ModeBuffer; | |
| // | |
| // Store all supported display modes to the private mode buffer | |
| // | |
| Mode = ModeBuffer; | |
| for (Index = 0; Index < GraphicsOutput->Mode->MaxMode; Index++) { | |
| // | |
| // The Info buffer would be allocated by callee | |
| // | |
| Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) Index, &SizeOfInfo, &Info); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); | |
| CopyMem (Mode, Info, SizeOfInfo); | |
| Mode++; | |
| FreePool (Info); | |
| } | |
| } else { | |
| // | |
| // Check intersection of display mode | |
| // | |
| ModeBuffer = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) * CurrentGraphicsOutputMode->MaxMode); | |
| if (ModeBuffer == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| MatchedMode = ModeBuffer; | |
| Mode = &Private->GraphicsOutputModeBuffer[0]; | |
| for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) { | |
| Match = FALSE; | |
| for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex++) { | |
| // | |
| // The Info buffer would be allocated by callee | |
| // | |
| Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| if ((Info->HorizontalResolution == Mode->HorizontalResolution) && | |
| (Info->VerticalResolution == Mode->VerticalResolution)) { | |
| // | |
| // If GOP device supports one mode in current mode buffer, | |
| // it will be added into matched mode buffer | |
| // | |
| Match = TRUE; | |
| FreePool (Info); | |
| break; | |
| } | |
| FreePool (Info); | |
| } | |
| if (Match) { | |
| AlreadyExist = FALSE; | |
| // | |
| // Check if GOP mode has been in the mode buffer, ModeBuffer = MatchedMode at begin. | |
| // | |
| for (Info = ModeBuffer; Info < MatchedMode; Info++) { | |
| if ((Info->HorizontalResolution == Mode->HorizontalResolution) && | |
| (Info->VerticalResolution == Mode->VerticalResolution)) { | |
| AlreadyExist = TRUE; | |
| break; | |
| } | |
| } | |
| if (!AlreadyExist) { | |
| CopyMem (MatchedMode, Mode, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); | |
| // | |
| // Physical frame buffer is no longer available, change PixelFormat to PixelBltOnly | |
| // | |
| MatchedMode->Version = 0; | |
| MatchedMode->PixelFormat = PixelBltOnly; | |
| ZeroMem (&MatchedMode->PixelInformation, sizeof (EFI_PIXEL_BITMASK)); | |
| MatchedMode++; | |
| } | |
| } | |
| Mode++; | |
| } | |
| // | |
| // Drop the old mode buffer, assign it to a new one | |
| // | |
| FreePool (Private->GraphicsOutputModeBuffer); | |
| Private->GraphicsOutputModeBuffer = ModeBuffer; | |
| // | |
| // Physical frame buffer is no longer available when there are more than one physical GOP devices | |
| // | |
| CurrentGraphicsOutputMode->MaxMode = (UINT32) (((UINTN) MatchedMode - (UINTN) ModeBuffer) / sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); | |
| CurrentGraphicsOutputMode->Info->PixelFormat = PixelBltOnly; | |
| ZeroMem (&CurrentGraphicsOutputMode->Info->PixelInformation, sizeof (EFI_PIXEL_BITMASK)); | |
| CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); | |
| CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL; | |
| CurrentGraphicsOutputMode->FrameBufferSize = 0; | |
| } | |
| // | |
| // Graphics console driver can ensure the same mode for all GOP devices | |
| // | |
| for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) { | |
| Mode = &Private->GraphicsOutputModeBuffer[Index]; | |
| if ((Mode->HorizontalResolution == GraphicsOutput->Mode->Info->HorizontalResolution) && | |
| (Mode->VerticalResolution == GraphicsOutput->Mode->Info->VerticalResolution)) { | |
| CurrentIndex = Index; | |
| break; | |
| } | |
| } | |
| if (Index >= CurrentGraphicsOutputMode->MaxMode) { | |
| // | |
| // if user defined mode is not found, set to default mode 800x600 | |
| // | |
| for (Index = 0; Index < CurrentGraphicsOutputMode->MaxMode; Index++) { | |
| Mode = &Private->GraphicsOutputModeBuffer[Index]; | |
| if ((Mode->HorizontalResolution == 800) && (Mode->VerticalResolution == 600)) { | |
| CurrentIndex = Index; | |
| break; | |
| } | |
| } | |
| } | |
| } 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 | |
| // | |
| UgaDraw->GetMode ( | |
| UgaDraw, | |
| &UgaHorizontalResolution, | |
| &UgaVerticalResolution, | |
| &UgaColorDepth, | |
| &UgaRefreshRate | |
| ); | |
| CurrentGraphicsOutputMode->MaxMode = 1; | |
| Info = CurrentGraphicsOutputMode->Info; | |
| Info->Version = 0; | |
| Info->HorizontalResolution = UgaHorizontalResolution; | |
| Info->VerticalResolution = UgaVerticalResolution; | |
| Info->PixelFormat = PixelBltOnly; | |
| Info->PixelsPerScanLine = UgaHorizontalResolution; | |
| CurrentGraphicsOutputMode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); | |
| CurrentGraphicsOutputMode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL; | |
| CurrentGraphicsOutputMode->FrameBufferSize = 0; | |
| // | |
| // Update the private mode buffer | |
| // | |
| CopyMem (&Private->GraphicsOutputModeBuffer[0], Info, sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); | |
| // | |
| // Only mode 0 is available to be set | |
| // | |
| CurrentIndex = 0; | |
| } | |
| Done: | |
| if (GraphicsOutput != NULL) { | |
| Private->CurrentNumberOfGraphicsOutput++; | |
| } | |
| if (UgaDraw != NULL) { | |
| Private->CurrentNumberOfUgaDraw++; | |
| } | |
| // | |
| // Force GraphicsOutput mode to be set, | |
| // | |
| Mode = &Private->GraphicsOutputModeBuffer[CurrentIndex]; | |
| if ((GraphicsOutput != NULL) && | |
| (Mode->HorizontalResolution == CurrentGraphicsOutputMode->Info->HorizontalResolution) && | |
| (Mode->VerticalResolution == CurrentGraphicsOutputMode->Info->VerticalResolution)) { | |
| CurrentGraphicsOutputMode->Mode = (UINT32) CurrentIndex; | |
| if ((Mode->HorizontalResolution != GraphicsOutput->Mode->Info->HorizontalResolution) || | |
| (Mode->VerticalResolution != GraphicsOutput->Mode->Info->VerticalResolution)) { | |
| // | |
| // If all existing video device has been set to common mode, only set new GOP device to | |
| // the common mode | |
| // | |
| for (NumberIndex = 0; NumberIndex < GraphicsOutput->Mode->MaxMode; NumberIndex ++) { | |
| Status = GraphicsOutput->QueryMode (GraphicsOutput, (UINT32) NumberIndex, &SizeOfInfo, &Info); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| if ((Info->HorizontalResolution == Mode->HorizontalResolution) && (Info->VerticalResolution == Mode->VerticalResolution)) { | |
| FreePool (Info); | |
| break; | |
| } | |
| FreePool (Info); | |
| } | |
| Status = GraphicsOutput->SetMode (GraphicsOutput, (UINT32) NumberIndex); | |
| } | |
| } else { | |
| // | |
| // Current mode number may need update now, so set it to an invalid mode number | |
| // | |
| CurrentGraphicsOutputMode->Mode = 0xffff; | |
| // | |
| // Graphics console can ensure all GOP devices have the same mode which can be taken as current mode. | |
| // | |
| Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, (UINT32) CurrentIndex); | |
| if (EFI_ERROR(Status)) { | |
| // | |
| // If user defined mode is not valid for display device, set to the default mode 800x600. | |
| // | |
| (Private->GraphicsOutputModeBuffer[0]).HorizontalResolution = 800; | |
| (Private->GraphicsOutputModeBuffer[0]).VerticalResolution = 600; | |
| Status = Private->GraphicsOutput.SetMode (&Private->GraphicsOutput, 0); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Set the current console out mode. | |
| This routine will get the current console mode information (column, row) | |
| from ConsoleOutMode variable and set it; if the variable does not exist, | |
| set to user defined console mode. | |
| @param Private Consplitter Text Out pointer. | |
| **/ | |
| VOID | |
| ConsplitterSetConsoleOutMode ( | |
| IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private | |
| ) | |
| { | |
| UINTN Col; | |
| UINTN Row; | |
| UINTN Mode; | |
| UINTN PreferMode; | |
| UINTN BaseMode; | |
| UINTN MaxMode; | |
| EFI_STATUS Status; | |
| CONSOLE_OUT_MODE ModeInfo; | |
| CONSOLE_OUT_MODE MaxModeInfo; | |
| EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut; | |
| PreferMode = 0xFF; | |
| BaseMode = 0xFF; | |
| TextOut = &Private->TextOut; | |
| MaxMode = (UINTN) (TextOut->Mode->MaxMode); | |
| 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 | |
| // | |
| for (Mode = 0; Mode < MaxMode; Mode++) { | |
| Status = TextOut->QueryMode (TextOut, Mode, &Col, &Row); | |
| if (!EFI_ERROR(Status)) { | |
| 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; | |
| } | |
| } | |
| } | |
| // | |
| // Set prefer mode to Text Out devices. | |
| // | |
| Status = TextOut->SetMode (TextOut, PreferMode); | |
| if (EFI_ERROR(Status)) { | |
| // | |
| // if current mode setting is failed, default 80x25 mode will be set. | |
| // | |
| Status = TextOut->SetMode (TextOut, BaseMode); | |
| ASSERT(!EFI_ERROR(Status)); | |
| PcdSet32 (PcdConOutColumn, 80); | |
| PcdSet32 (PcdConOutRow, 25); | |
| } | |
| return ; | |
| } | |
| /** | |
| Add Text Output Device in Consplitter Text Output list. | |
| @param Private Text Out Splitter pointer. | |
| @param TextOut Simple Text Output protocol pointer. | |
| @param GraphicsOutput Graphics Output protocol pointer. | |
| @param UgaDraw UGA Draw protocol pointer. | |
| @retval EFI_SUCCESS Text Output Device added successfully. | |
| @retval EFI_OUT_OF_RESOURCES Could not grow the buffer size. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterTextOutAddDevice ( | |
| IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut, | |
| IN EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, | |
| IN EFI_UGA_DRAW_PROTOCOL *UgaDraw | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN CurrentNumOfConsoles; | |
| INT32 MaxMode; | |
| UINT32 UgaHorizontalResolution; | |
| UINT32 UgaVerticalResolution; | |
| UINT32 UgaColorDepth; | |
| UINT32 UgaRefreshRate; | |
| TEXT_OUT_AND_GOP_DATA *TextAndGop; | |
| UINTN SizeOfInfo; | |
| EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; | |
| EFI_STATUS DeviceStatus; | |
| Status = EFI_SUCCESS; | |
| CurrentNumOfConsoles = Private->CurrentNumberOfConsoles; | |
| // | |
| // If the Text Out List is full, enlarge it by calling ConSplitterGrowBuffer(). | |
| // | |
| while (CurrentNumOfConsoles >= Private->TextOutListCount) { | |
| Status = ConSplitterGrowBuffer ( | |
| sizeof (TEXT_OUT_AND_GOP_DATA), | |
| &Private->TextOutListCount, | |
| (VOID **) &Private->TextOutList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Also need to reallocate the TextOutModeMap table | |
| // | |
| Status = ConSplitterGrowMapTable (Private); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| } | |
| TextAndGop = &Private->TextOutList[CurrentNumOfConsoles]; | |
| TextAndGop->TextOut = TextOut; | |
| TextAndGop->GraphicsOutput = GraphicsOutput; | |
| TextAndGop->UgaDraw = UgaDraw; | |
| if (CurrentNumOfConsoles == 0) { | |
| // | |
| // Add the first device's output mode to console splitter's mode list | |
| // | |
| Status = ConSplitterAddOutputMode (Private, TextOut); | |
| } else { | |
| ConSplitterSyncOutputMode (Private, TextOut); | |
| } | |
| Private->CurrentNumberOfConsoles++; | |
| // | |
| // Scan both TextOutList, for the intersection TextOut device | |
| // maybe both ConOut and StdErr incorporate the same Text Out | |
| // device in them, thus the output of both should be synced. | |
| // | |
| ConSplitterGetIntersectionBetweenConOutAndStrErr (); | |
| MaxMode = Private->TextOutMode.MaxMode; | |
| ASSERT (MaxMode >= 1); | |
| DeviceStatus = EFI_DEVICE_ERROR; | |
| 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)) { | |
| // | |
| // If UGA is produced by Consplitter | |
| // | |
| if (GraphicsOutput != NULL) { | |
| Status = GraphicsOutput->QueryMode (GraphicsOutput, GraphicsOutput->Mode->Mode, &SizeOfInfo, &Info); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ASSERT ( SizeOfInfo <= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); | |
| UgaHorizontalResolution = Info->HorizontalResolution; | |
| UgaVerticalResolution = Info->VerticalResolution; | |
| FreePool (Info); | |
| } else if (UgaDraw != NULL) { | |
| Status = UgaDraw->GetMode ( | |
| UgaDraw, | |
| &UgaHorizontalResolution, | |
| &UgaVerticalResolution, | |
| &UgaColorDepth, | |
| &UgaRefreshRate | |
| ); | |
| if (!EFI_ERROR (Status) && EFI_ERROR (DeviceStatus)) { | |
| // | |
| // if GetMode is successfully and UGA device hasn't been set, set it | |
| // | |
| Status = ConSplitterUgaDrawSetMode ( | |
| &Private->UgaDraw, | |
| UgaHorizontalResolution, | |
| UgaVerticalResolution, | |
| UgaColorDepth, | |
| UgaRefreshRate | |
| ); | |
| } | |
| // | |
| // If GetMode/SetMode is failed, set to 800x600 mode | |
| // | |
| if(EFI_ERROR (Status)) { | |
| Status = ConSplitterUgaDrawSetMode ( | |
| &Private->UgaDraw, | |
| 800, | |
| 600, | |
| 32, | |
| 60 | |
| ); | |
| } | |
| } | |
| } | |
| 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); | |
| return Status; | |
| } | |
| /** | |
| Remove Text Out Device in Consplitter Text Out list. | |
| @param Private Text Out Splitter pointer. | |
| @param TextOut Simple Text Output Pointer protocol pointer. | |
| @retval EFI_SUCCESS Text Out Device removed successfully. | |
| @retval EFI_NOT_FOUND No Text Out Device found. | |
| **/ | |
| EFI_STATUS | |
| ConSplitterTextOutDeleteDevice ( | |
| IN TEXT_OUT_SPLITTER_PRIVATE_DATA *Private, | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut | |
| ) | |
| { | |
| INT32 Index; | |
| UINTN CurrentNumOfConsoles; | |
| TEXT_OUT_AND_GOP_DATA *TextOutList; | |
| EFI_STATUS Status; | |
| // | |
| // Remove the specified text-out device data structure from the Text out List, | |
| // and rearrange the remaining data structures in the Text out List. | |
| // | |
| CurrentNumOfConsoles = Private->CurrentNumberOfConsoles; | |
| Index = (INT32) CurrentNumOfConsoles - 1; | |
| TextOutList = Private->TextOutList; | |
| while (Index >= 0) { | |
| if (TextOutList->TextOut == TextOut) { | |
| 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; | |
| } | |
| Index--; | |
| TextOutList++; | |
| } | |
| // | |
| // The specified TextOut is not managed by the ConSplitter driver | |
| // | |
| if (Index < 0) { | |
| 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 | |
| // | |
| Private->CurrentNumberOfConsoles = 0; | |
| Private->TextOutMode.MaxMode = 1; | |
| Private->TextOutQueryData[0].Columns = 80; | |
| Private->TextOutQueryData[0].Rows = 25; | |
| TextOutSetMode (Private, 0); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Max Mode is realy an intersection of the QueryMode command to all | |
| // devices. So we must copy the QueryMode of the first device to | |
| // QueryData. | |
| // | |
| ZeroMem ( | |
| Private->TextOutQueryData, | |
| Private->TextOutQueryDataCount * sizeof (TEXT_OUT_SPLITTER_QUERY_DATA) | |
| ); | |
| FreePool (Private->TextOutModeMap); | |
| Private->TextOutModeMap = NULL; | |
| TextOutList = Private->TextOutList; | |
| // | |
| // Add the first TextOut to the QueryData array and ModeMap table | |
| // | |
| Status = ConSplitterAddOutputMode (Private, TextOutList->TextOut); | |
| // | |
| // Now add one by one | |
| // | |
| Index = 1; | |
| Private->CurrentNumberOfConsoles = 1; | |
| TextOutList++; | |
| while ((UINTN) Index < CurrentNumOfConsoles) { | |
| ConSplitterSyncOutputMode (Private, TextOutList->TextOut); | |
| Index++; | |
| Private->CurrentNumberOfConsoles++; | |
| TextOutList++; | |
| } | |
| ConSplitterGetIntersectionBetweenConOutAndStrErr (); | |
| return Status; | |
| } | |
| /** | |
| Reset the input device and optionaly run diagnostics | |
| @param This Protocol instance pointer. | |
| @param ExtendedVerification Driver may perform diagnostics on reset. | |
| @retval EFI_SUCCESS The device was reset. | |
| @retval EFI_DEVICE_ERROR The device is not functioning properly and could | |
| not be reset. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextInReset ( | |
| IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, | |
| IN BOOLEAN ExtendedVerification | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS ReturnStatus; | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| Private->KeyEventSignalState = FALSE; | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| Status = Private->TextInList[Index]->Reset ( | |
| Private->TextInList[Index], | |
| ExtendedVerification | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| return ReturnStatus; | |
| } | |
| /** | |
| Reads the next keystroke from the input device. The WaitForKey Event can | |
| be used to test for existance of a keystroke via WaitForEvent () call. | |
| @param Private Protocol instance pointer. | |
| @param Key Driver may perform diagnostics on reset. | |
| @retval EFI_SUCCESS The keystroke information was returned. | |
| @retval EFI_NOT_READY There was no keystroke data availiable. | |
| @retval EFI_DEVICE_ERROR The keydtroke information was not returned due | |
| to hardware errors. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextInPrivateReadKeyStroke ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| OUT EFI_INPUT_KEY *Key | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| EFI_INPUT_KEY CurrentKey; | |
| Key->UnicodeChar = 0; | |
| Key->ScanCode = SCAN_NULL; | |
| // | |
| // 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. | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| Status = Private->TextInList[Index]->ReadKeyStroke ( | |
| Private->TextInList[Index], | |
| &CurrentKey | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| *Key = CurrentKey; | |
| return Status; | |
| } | |
| } | |
| return EFI_NOT_READY; | |
| } | |
| /** | |
| Reads the next keystroke from the input device. The WaitForKey Event can | |
| be used to test for existance of a keystroke via WaitForEvent () call. | |
| @param This Protocol instance pointer. | |
| @param Key Driver may perform diagnostics on reset. | |
| @retval EFI_SUCCESS The keystroke information was returned. | |
| @retval EFI_NOT_READY There was no keystroke data availiable. | |
| @retval EFI_DEVICE_ERROR The keydtroke information was not returned due | |
| to hardware errors. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextInReadKeyStroke ( | |
| IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, | |
| OUT EFI_INPUT_KEY *Key | |
| ) | |
| { | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| 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); | |
| } | |
| /** | |
| This event aggregates all the events of the ConIn devices in the spliter. | |
| If any events of physical ConIn devices are signaled, signal the ConIn | |
| spliter event. This will cause the calling code to call | |
| ConSplitterTextInReadKeyStroke (). | |
| @param Event The Event assoicated with callback. | |
| @param Context Context registered when Event was created. | |
| **/ | |
| VOID | |
| EFIAPI | |
| ConSplitterTextInWaitForKey ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; | |
| if (Private->KeyEventSignalState) { | |
| // | |
| // If KeyEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke() | |
| // | |
| gBS->SignalEvent (Event); | |
| return ; | |
| } | |
| // | |
| // If any physical console input device has key input, signal the event. | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| Status = gBS->CheckEvent (Private->TextInList[Index]->WaitForKey); | |
| if (!EFI_ERROR (Status)) { | |
| gBS->SignalEvent (Event); | |
| Private->KeyEventSignalState = TRUE; | |
| } | |
| } | |
| } | |
| /** | |
| Test if the key has been registered on input device. | |
| @param RegsiteredData A pointer to a buffer that is filled in with the | |
| keystroke state data for the key that was | |
| registered. | |
| @param InputData A pointer to a buffer that is filled in with the | |
| keystroke state data for the key that was | |
| pressed. | |
| @retval TRUE Key be pressed matches a registered key. | |
| @retval FLASE Match failed. | |
| **/ | |
| BOOLEAN | |
| IsKeyRegistered ( | |
| IN EFI_KEY_DATA *RegsiteredData, | |
| IN EFI_KEY_DATA *InputData | |
| ) | |
| { | |
| ASSERT (RegsiteredData != NULL && InputData != NULL); | |
| if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || | |
| (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { | |
| return FALSE; | |
| } | |
| // | |
| // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored. | |
| // | |
| if (RegsiteredData->KeyState.KeyShiftState != 0 && | |
| RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) { | |
| return FALSE; | |
| } | |
| if (RegsiteredData->KeyState.KeyToggleState != 0 && | |
| RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) { | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| /** | |
| Reset the input device and optionaly run diagnostics | |
| @param This Protocol instance pointer. | |
| @param ExtendedVerification Driver may perform diagnostics on reset. | |
| @retval EFI_SUCCESS The device was reset. | |
| @retval EFI_DEVICE_ERROR The device is not functioning properly and could | |
| not be reset. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextInResetEx ( | |
| IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, | |
| IN BOOLEAN ExtendedVerification | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS ReturnStatus; | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| Private->KeyEventSignalState = FALSE; | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfExConsoles; Index++) { | |
| Status = Private->TextInExList[Index]->Reset ( | |
| Private->TextInExList[Index], | |
| ExtendedVerification | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| return ReturnStatus; | |
| } | |
| /** | |
| Reads the next keystroke from the input device. The WaitForKey Event can | |
| be used to test for existance of a keystroke via WaitForEvent () call. | |
| @param This 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_SUCCESS The keystroke information was returned. | |
| @retval EFI_NOT_READY There was no keystroke data availiable. | |
| @retval EFI_DEVICE_ERROR The keystroke information was not returned due | |
| to hardware errors. | |
| @retval EFI_INVALID_PARAMETER KeyData is NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextInReadKeyStrokeEx ( | |
| IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, | |
| OUT EFI_KEY_DATA *KeyData | |
| ) | |
| { | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| EFI_KEY_DATA CurrentKeyData; | |
| if (KeyData == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| 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. | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { | |
| Status = Private->TextInExList[Index]->ReadKeyStrokeEx ( | |
| Private->TextInExList[Index], | |
| &CurrentKeyData | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| CopyMem (KeyData, &CurrentKeyData, sizeof (CurrentKeyData)); | |
| return Status; | |
| } | |
| } | |
| return EFI_NOT_READY; | |
| } | |
| /** | |
| Set certain state for the input device. | |
| @param This Protocol instance pointer. | |
| @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the | |
| state for the input device. | |
| @retval EFI_SUCCESS The device state was set successfully. | |
| @retval EFI_DEVICE_ERROR The device is not functioning correctly and | |
| could not have the setting adjusted. | |
| @retval EFI_UNSUPPORTED The device does not have the ability to set its | |
| state. | |
| @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextInSetState ( | |
| IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, | |
| IN EFI_KEY_TOGGLE_STATE *KeyToggleState | |
| ) | |
| { | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| if (KeyToggleState == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // if no physical console input device exists, return EFI_SUCCESS; | |
| // otherwise return the status of setting state of physical console input device | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { | |
| Status = Private->TextInExList[Index]->SetState ( | |
| Private->TextInExList[Index], | |
| KeyToggleState | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| 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 KeyNotificationFunction Points to the function to be called when the key | |
| sequence is typed specified by KeyData. | |
| @param NotifyHandle Points to the unique handle assigned to the | |
| registered notification. | |
| @retval EFI_SUCCESS The notification function was registered | |
| successfully. | |
| @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data | |
| structures. | |
| @retval EFI_INVALID_PARAMETER KeyData or KeyNotificationFunction or NotifyHandle is NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextInRegisterKeyNotify ( | |
| IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, | |
| IN EFI_KEY_DATA *KeyData, | |
| IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, | |
| OUT VOID **NotifyHandle | |
| ) | |
| { | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| TEXT_IN_EX_SPLITTER_NOTIFY *NewNotify; | |
| LIST_ENTRY *Link; | |
| TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; | |
| if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered. | |
| // | |
| for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { | |
| CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); | |
| if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { | |
| if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { | |
| *NotifyHandle = CurrentNotify; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| } | |
| // | |
| // Allocate resource to save the notification function | |
| // | |
| NewNotify = (TEXT_IN_EX_SPLITTER_NOTIFY *) AllocateZeroPool (sizeof (TEXT_IN_EX_SPLITTER_NOTIFY)); | |
| if (NewNotify == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| 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; | |
| CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); | |
| // | |
| // Return the wrong status of registering key notify of | |
| // physical console input device if meet problems | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { | |
| Status = Private->TextInExList[Index]->RegisterKeyNotify ( | |
| Private->TextInExList[Index], | |
| KeyData, | |
| KeyNotificationFunction, | |
| &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); | |
| *NotifyHandle = NewNotify; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Remove a registered notification function from a particular keystroke. | |
| @param This Protocol instance pointer. | |
| @param NotificationHandle The handle of the notification function being | |
| unregistered. | |
| @retval EFI_SUCCESS The notification function was unregistered | |
| successfully. | |
| @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextInUnregisterKeyNotify ( | |
| IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, | |
| IN VOID *NotificationHandle | |
| ) | |
| { | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| TEXT_IN_EX_SPLITTER_NOTIFY *CurrentNotify; | |
| LIST_ENTRY *Link; | |
| if (NotificationHandle == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = TEXT_IN_EX_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| for (Link = Private->NotifyList.ForwardLink; Link != &Private->NotifyList; Link = Link->ForwardLink) { | |
| CurrentNotify = TEXT_IN_EX_SPLITTER_NOTIFY_FROM_THIS (Link); | |
| if (CurrentNotify == NotificationHandle) { | |
| for (Index = 0; Index < Private->CurrentNumberOfExConsoles; Index++) { | |
| Private->TextInExList[Index]->UnregisterKeyNotify ( | |
| Private->TextInExList[Index], | |
| CurrentNotify->NotifyHandleList[Index] | |
| ); | |
| } | |
| RemoveEntryList (&CurrentNotify->NotifyEntry); | |
| gBS->FreePool (CurrentNotify->NotifyHandleList); | |
| gBS->FreePool (CurrentNotify); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| // | |
| // NotificationHandle is not found in database | |
| // | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| /** | |
| Reset the input device and optionaly run diagnostics | |
| @param This Protocol instance pointer. | |
| @param ExtendedVerification Driver may perform diagnostics on reset. | |
| @retval EFI_SUCCESS The device was reset. | |
| @retval EFI_DEVICE_ERROR The device is not functioning properly and could | |
| not be reset. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterSimplePointerReset ( | |
| IN EFI_SIMPLE_POINTER_PROTOCOL *This, | |
| IN BOOLEAN ExtendedVerification | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS ReturnStatus; | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This); | |
| Private->InputEventSignalState = FALSE; | |
| if (Private->CurrentNumberOfPointers == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfPointers; Index++) { | |
| Status = Private->PointerList[Index]->Reset ( | |
| Private->PointerList[Index], | |
| ExtendedVerification | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| return ReturnStatus; | |
| } | |
| /** | |
| Reads the next keystroke from the input device. The WaitForKey Event can | |
| be used to test for existance of a keystroke via WaitForEvent () call. | |
| @param Private Protocol instance pointer. | |
| @param State The state information of simple pointer device. | |
| @retval EFI_SUCCESS The keystroke information was returned. | |
| @retval EFI_NOT_READY There was no keystroke data availiable. | |
| @retval EFI_DEVICE_ERROR The keydtroke information was not returned due | |
| to hardware errors. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterSimplePointerPrivateGetState ( | |
| IN TEXT_IN_SPLITTER_PRIVATE_DATA *Private, | |
| IN OUT EFI_SIMPLE_POINTER_STATE *State | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS ReturnStatus; | |
| UINTN Index; | |
| EFI_SIMPLE_POINTER_STATE CurrentState; | |
| State->RelativeMovementX = 0; | |
| State->RelativeMovementY = 0; | |
| State->RelativeMovementZ = 0; | |
| State->LeftButton = FALSE; | |
| State->RightButton = FALSE; | |
| // | |
| // 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. | |
| // | |
| ReturnStatus = EFI_NOT_READY; | |
| for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) { | |
| Status = Private->PointerList[Index]->GetState ( | |
| Private->PointerList[Index], | |
| &CurrentState | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| if (ReturnStatus == EFI_NOT_READY) { | |
| ReturnStatus = EFI_SUCCESS; | |
| } | |
| if (CurrentState.LeftButton) { | |
| State->LeftButton = TRUE; | |
| } | |
| if (CurrentState.RightButton) { | |
| State->RightButton = TRUE; | |
| } | |
| if (CurrentState.RelativeMovementX != 0 && Private->PointerList[Index]->Mode->ResolutionX != 0) { | |
| State->RelativeMovementX += (CurrentState.RelativeMovementX * (INT32) Private->SimplePointerMode.ResolutionX) / (INT32) Private->PointerList[Index]->Mode->ResolutionX; | |
| } | |
| if (CurrentState.RelativeMovementY != 0 && Private->PointerList[Index]->Mode->ResolutionY != 0) { | |
| State->RelativeMovementY += (CurrentState.RelativeMovementY * (INT32) Private->SimplePointerMode.ResolutionY) / (INT32) Private->PointerList[Index]->Mode->ResolutionY; | |
| } | |
| if (CurrentState.RelativeMovementZ != 0 && Private->PointerList[Index]->Mode->ResolutionZ != 0) { | |
| State->RelativeMovementZ += (CurrentState.RelativeMovementZ * (INT32) Private->SimplePointerMode.ResolutionZ) / (INT32) Private->PointerList[Index]->Mode->ResolutionZ; | |
| } | |
| } else if (Status == EFI_DEVICE_ERROR) { | |
| ReturnStatus = EFI_DEVICE_ERROR; | |
| } | |
| } | |
| return ReturnStatus; | |
| } | |
| /** | |
| Reads the next keystroke from the input device. The WaitForKey Event can | |
| be used to test for existance of a keystroke via WaitForEvent () call. | |
| @param This A pointer to protocol instance. | |
| @param State A pointer to state information on the pointer device | |
| @retval EFI_SUCCESS The keystroke information was returned in State. | |
| @retval EFI_NOT_READY There was no keystroke data availiable. | |
| @retval EFI_DEVICE_ERROR The keydtroke information was not returned due | |
| to hardware errors. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterSimplePointerGetState ( | |
| IN EFI_SIMPLE_POINTER_PROTOCOL *This, | |
| IN OUT EFI_SIMPLE_POINTER_STATE *State | |
| ) | |
| { | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_SIMPLE_POINTER_THIS (This); | |
| Private->InputEventSignalState = FALSE; | |
| return ConSplitterSimplePointerPrivateGetState (Private, State); | |
| } | |
| /** | |
| This event agregates all the events of the ConIn devices in the spliter. | |
| If any events of physical ConIn devices are signaled, signal the ConIn | |
| spliter event. This will cause the calling code to call | |
| ConSplitterTextInReadKeyStroke (). | |
| @param Event The Event assoicated with callback. | |
| @param Context Context registered when Event was created. | |
| **/ | |
| VOID | |
| EFIAPI | |
| ConSplitterSimplePointerWaitForInput ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; | |
| // | |
| // if InputEventSignalState is flagged before, and not cleared by Reset() or ReadKeyStroke() | |
| // | |
| if (Private->InputEventSignalState) { | |
| gBS->SignalEvent (Event); | |
| return ; | |
| } | |
| // | |
| // if any physical console input device has key input, signal the event. | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfPointers; Index++) { | |
| Status = gBS->CheckEvent (Private->PointerList[Index]->WaitForInput); | |
| if (!EFI_ERROR (Status)) { | |
| gBS->SignalEvent (Event); | |
| Private->InputEventSignalState = TRUE; | |
| } | |
| } | |
| } | |
| /** | |
| Resets the pointer device hardware. | |
| @param This Protocol instance pointer. | |
| @param ExtendedVerification Driver may perform diagnostics on reset. | |
| @retval EFI_SUCCESS The device was reset. | |
| @retval EFI_DEVICE_ERROR The device is not functioning correctly and | |
| could not be reset. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterAbsolutePointerReset ( | |
| IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, | |
| IN BOOLEAN ExtendedVerification | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS ReturnStatus; | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This); | |
| Private->AbsoluteInputEventSignalState = FALSE; | |
| if (Private->CurrentNumberOfAbsolutePointers == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfAbsolutePointers; Index++) { | |
| Status = Private->AbsolutePointerList[Index]->Reset ( | |
| Private->AbsolutePointerList[Index], | |
| ExtendedVerification | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| return ReturnStatus; | |
| } | |
| /** | |
| Retrieves the current state of a pointer device. | |
| @param This Protocol instance pointer. | |
| @param State A pointer to the state information on the | |
| pointer device. | |
| @retval EFI_SUCCESS The state of the pointer device was returned in | |
| State.. | |
| @retval EFI_NOT_READY The state of the pointer device has not changed | |
| since the last call to GetState(). | |
| @retval EFI_DEVICE_ERROR A device error occurred while attempting to | |
| retrieve the pointer device's current state. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterAbsolutePointerGetState ( | |
| IN EFI_ABSOLUTE_POINTER_PROTOCOL *This, | |
| IN OUT EFI_ABSOLUTE_POINTER_STATE *State | |
| ) | |
| { | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| EFI_STATUS Status; | |
| EFI_STATUS ReturnStatus; | |
| UINTN Index; | |
| EFI_ABSOLUTE_POINTER_STATE CurrentState; | |
| Private = TEXT_IN_SPLITTER_PRIVATE_DATA_FROM_ABSOLUTE_POINTER_THIS (This); | |
| Private->AbsoluteInputEventSignalState = FALSE; | |
| State->CurrentX = 0; | |
| State->CurrentY = 0; | |
| State->CurrentZ = 0; | |
| State->ActiveButtons = 0; | |
| // | |
| // if no physical pointer device exists, return EFI_NOT_READY; | |
| // if any physical pointer device has changed state, | |
| // return the state and EFI_SUCCESS. | |
| // | |
| ReturnStatus = EFI_NOT_READY; | |
| for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) { | |
| Status = Private->AbsolutePointerList[Index]->GetState ( | |
| Private->AbsolutePointerList[Index], | |
| &CurrentState | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| if (ReturnStatus == EFI_NOT_READY) { | |
| ReturnStatus = EFI_SUCCESS; | |
| } | |
| State->ActiveButtons = CurrentState.ActiveButtons; | |
| if (!(Private->AbsolutePointerMode.AbsoluteMinX == 0 && Private->AbsolutePointerMode.AbsoluteMaxX == 0)) { | |
| State->CurrentX = CurrentState.CurrentX; | |
| } | |
| if (!(Private->AbsolutePointerMode.AbsoluteMinY == 0 && Private->AbsolutePointerMode.AbsoluteMaxY == 0)) { | |
| State->CurrentY = CurrentState.CurrentY; | |
| } | |
| if (!(Private->AbsolutePointerMode.AbsoluteMinZ == 0 && Private->AbsolutePointerMode.AbsoluteMaxZ == 0)) { | |
| State->CurrentZ = CurrentState.CurrentZ; | |
| } | |
| } else if (Status == EFI_DEVICE_ERROR) { | |
| ReturnStatus = EFI_DEVICE_ERROR; | |
| } | |
| } | |
| return ReturnStatus; | |
| } | |
| /** | |
| This event agregates all the events of the pointer devices in the splitter. | |
| If any events of physical pointer devices are signaled, signal the pointer | |
| splitter event. This will cause the calling code to call | |
| ConSplitterAbsolutePointerGetState (). | |
| @param Event The Event assoicated with callback. | |
| @param Context Context registered when Event was created. | |
| **/ | |
| VOID | |
| EFIAPI | |
| ConSplitterAbsolutePointerWaitForInput ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_IN_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| Private = (TEXT_IN_SPLITTER_PRIVATE_DATA *) Context; | |
| // | |
| // if AbsoluteInputEventSignalState is flagged before, | |
| // and not cleared by Reset() or GetState(), signal it | |
| // | |
| if (Private->AbsoluteInputEventSignalState) { | |
| gBS->SignalEvent (Event); | |
| return ; | |
| } | |
| // | |
| // if any physical console input device has key input, signal the event. | |
| // | |
| for (Index = 0; Index < Private->CurrentNumberOfAbsolutePointers; Index++) { | |
| Status = gBS->CheckEvent (Private->AbsolutePointerList[Index]->WaitForInput); | |
| if (!EFI_ERROR (Status)) { | |
| gBS->SignalEvent (Event); | |
| Private->AbsoluteInputEventSignalState = TRUE; | |
| } | |
| } | |
| } | |
| /** | |
| Reset the text output device hardware and optionaly run diagnostics | |
| @param This Protocol instance pointer. | |
| @param ExtendedVerification Driver may perform more exhaustive verfication | |
| operation of the device during reset. | |
| @retval EFI_SUCCESS The text output device was reset. | |
| @retval EFI_DEVICE_ERROR The text output device is not functioning | |
| correctly and could not be reset. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextOutReset ( | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
| IN BOOLEAN ExtendedVerification | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| EFI_STATUS ReturnStatus; | |
| Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| Status = Private->TextOutList[Index].TextOut->Reset ( | |
| Private->TextOutList[Index].TextOut, | |
| ExtendedVerification | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BLACK)); | |
| // | |
| // reset all mode parameters | |
| // | |
| TextOutSetMode (Private, 0); | |
| return ReturnStatus; | |
| } | |
| /** | |
| Write a Unicode string to the output device. | |
| @param This Protocol instance pointer. | |
| @param WString The NULL-terminated Unicode string to be | |
| displayed on the output device(s). All output | |
| devices must also support the Unicode drawing | |
| defined in this file. | |
| @retval EFI_SUCCESS The string was output to the device. | |
| @retval EFI_DEVICE_ERROR The device reported an error while attempting to | |
| output the text. | |
| @retval EFI_UNSUPPORTED The output device's mode is not currently in a | |
| defined text mode. | |
| @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the | |
| characters in the Unicode string could not be | |
| rendered and were skipped. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextOutOutputString ( | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
| IN CHAR16 *WString | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| EFI_STATUS ReturnStatus; | |
| UINTN MaxColumn; | |
| UINTN MaxRow; | |
| This->SetAttribute (This, This->Mode->Attribute); | |
| Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // 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, | |
| WString | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| 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; | |
| 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; | |
| } | |
| /** | |
| Verifies that all characters in a Unicode string can be output to the | |
| target device. | |
| @param This Protocol instance pointer. | |
| @param WString The NULL-terminated Unicode string to be | |
| examined for the output device(s). | |
| @retval EFI_SUCCESS The device(s) are capable of rendering the | |
| output string. | |
| @retval EFI_UNSUPPORTED Some of the characters in the Unicode string | |
| cannot be rendered by one or more of the output | |
| devices mapped by the EFI handle. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextOutTestString ( | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
| IN CHAR16 *WString | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| EFI_STATUS ReturnStatus; | |
| Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| Status = Private->TextOutList[Index].TextOut->TestString ( | |
| Private->TextOutList[Index].TextOut, | |
| WString | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| // | |
| // There is no DevNullTextOutTestString () since a Unicode buffer would | |
| // always return EFI_SUCCESS. | |
| // ReturnStatus will be EFI_SUCCESS if no consoles are present | |
| // | |
| return ReturnStatus; | |
| } | |
| /** | |
| Returns information for an available text mode that the output device(s) | |
| supports. | |
| @param This Protocol instance pointer. | |
| @param ModeNumber The mode number to return information on. | |
| @param Columns Returns the columns of the text output device | |
| for the requested ModeNumber. | |
| @param Rows Returns the rows of the text output device | |
| for the requested ModeNumber. | |
| @retval EFI_SUCCESS The requested mode information was returned. | |
| @retval EFI_DEVICE_ERROR The device had an error and could not complete | |
| the request. | |
| @retval EFI_UNSUPPORTED The mode number was not valid. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextOutQueryMode ( | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
| IN UINTN ModeNumber, | |
| OUT UINTN *Columns, | |
| OUT UINTN *Rows | |
| ) | |
| { | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN CurrentMode; | |
| INT32 *TextOutModeMap; | |
| Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // Check whether param ModeNumber is valid. | |
| // ModeNumber should be within range 0 ~ MaxMode - 1. | |
| // | |
| if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| if ((INT32) ModeNumber >= This->Mode->MaxMode) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // We get the available mode from mode intersection map if it's available | |
| // | |
| if (Private->TextOutModeMap != NULL) { | |
| TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber; | |
| CurrentMode = (UINTN)(*TextOutModeMap); | |
| *Columns = Private->TextOutQueryData[CurrentMode].Columns; | |
| *Rows = Private->TextOutQueryData[CurrentMode].Rows; | |
| } else { | |
| *Columns = Private->TextOutQueryData[ModeNumber].Columns; | |
| *Rows = Private->TextOutQueryData[ModeNumber].Rows; | |
| } | |
| if (*Columns <= 0 && *Rows <= 0) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Sets the output device(s) to a specified mode. | |
| @param This Protocol instance pointer. | |
| @param ModeNumber The mode number to set. | |
| @retval EFI_SUCCESS The requested text mode was set. | |
| @retval EFI_DEVICE_ERROR The device had an error and could not complete | |
| the request. | |
| @retval EFI_UNSUPPORTED The mode number was not valid. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextOutSetMode ( | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
| IN UINTN ModeNumber | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| INT32 *TextOutModeMap; | |
| EFI_STATUS ReturnStatus; | |
| Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // Check whether param ModeNumber is valid. | |
| // ModeNumber should be within range 0 ~ MaxMode - 1. | |
| // | |
| if ( (ModeNumber > (UINTN)(((UINT32)-1)>>1)) ) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| if ((INT32) ModeNumber >= This->Mode->MaxMode) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // If the mode is being set to the curent mode, then just clear the screen and return. | |
| // | |
| if (Private->TextOutMode.Mode == (INT32) ModeNumber) { | |
| return ConSplitterTextOutClearScreen (This); | |
| } | |
| // | |
| // return the worst status met | |
| // | |
| 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; | |
| } | |
| } | |
| // | |
| // Set mode parameter to specified mode number | |
| // | |
| TextOutSetMode (Private, ModeNumber); | |
| return ReturnStatus; | |
| } | |
| /** | |
| Sets the background and foreground colors for the OutputString () and | |
| ClearScreen () functions. | |
| @param This Protocol instance pointer. | |
| @param Attribute The attribute to set. Bits 0..3 are the | |
| foreground color, and bits 4..6 are the | |
| background color. All other bits are undefined | |
| and must be zero. The valid Attributes are | |
| defined in this file. | |
| @retval EFI_SUCCESS The attribute was set. | |
| @retval EFI_DEVICE_ERROR The device had an error and could not complete | |
| the request. | |
| @retval EFI_UNSUPPORTED The attribute requested is not defined. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextOutSetAttribute ( | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
| IN UINTN Attribute | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| EFI_STATUS ReturnStatus; | |
| Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // Check whether param Attribute is valid. | |
| // | |
| if ( (Attribute > (UINTN)(((UINT32)-1)>>1)) ) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| Status = Private->TextOutList[Index].TextOut->SetAttribute ( | |
| Private->TextOutList[Index].TextOut, | |
| Attribute | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| Private->TextOutMode.Attribute = (INT32) Attribute; | |
| return ReturnStatus; | |
| } | |
| /** | |
| Clears the output device(s) display to the currently selected background | |
| color. | |
| @param This Protocol instance pointer. | |
| @retval EFI_SUCCESS The operation completed successfully. | |
| @retval EFI_DEVICE_ERROR The device had an error and could not complete | |
| the request. | |
| @retval EFI_UNSUPPORTED The output device is not in a valid text mode. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextOutClearScreen ( | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| EFI_STATUS ReturnStatus; | |
| Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| Status = Private->TextOutList[Index].TextOut->ClearScreen (Private->TextOutList[Index].TextOut); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| // | |
| // No need to do extra check here as whether (Column, Row) is valid has | |
| // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should | |
| // always be supported. | |
| // | |
| Private->TextOutMode.CursorColumn = 0; | |
| Private->TextOutMode.CursorRow = 0; | |
| Private->TextOutMode.CursorVisible = TRUE; | |
| return ReturnStatus; | |
| } | |
| /** | |
| Sets the current coordinates of the cursor position | |
| @param This Protocol instance pointer. | |
| @param Column The column position to set the cursor to. Must be | |
| greater than or equal to zero and less than the | |
| number of columns by QueryMode (). | |
| @param Row The row position to set the cursor to. Must be | |
| greater than or equal to zero and less than the | |
| number of rows by QueryMode (). | |
| @retval EFI_SUCCESS The operation completed successfully. | |
| @retval EFI_DEVICE_ERROR The device had an error and could not complete | |
| the request. | |
| @retval EFI_UNSUPPORTED The output device is not in a valid text mode, | |
| or the cursor position is invalid for the | |
| current mode. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextOutSetCursorPosition ( | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
| IN UINTN Column, | |
| IN UINTN Row | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| EFI_STATUS ReturnStatus; | |
| UINTN MaxColumn; | |
| UINTN MaxRow; | |
| INT32 *TextOutModeMap; | |
| INT32 ModeNumber; | |
| INT32 CurrentMode; | |
| Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| TextOutModeMap = NULL; | |
| ModeNumber = Private->TextOutMode.Mode; | |
| // | |
| // Get current MaxColumn and MaxRow from intersection map | |
| // | |
| if (Private->TextOutModeMap != NULL) { | |
| TextOutModeMap = Private->TextOutModeMap + Private->TextOutListCount * ModeNumber; | |
| CurrentMode = *TextOutModeMap; | |
| } else { | |
| CurrentMode = ModeNumber; | |
| } | |
| MaxColumn = Private->TextOutQueryData[CurrentMode].Columns; | |
| MaxRow = Private->TextOutQueryData[CurrentMode].Rows; | |
| if (Column >= MaxColumn || Row >= MaxRow) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| Status = Private->TextOutList[Index].TextOut->SetCursorPosition ( | |
| Private->TextOutList[Index].TextOut, | |
| Column, | |
| Row | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| // | |
| // No need to do extra check here as whether (Column, Row) is valid has | |
| // been checked in ConSplitterTextOutSetCursorPosition. And (0, 0) should | |
| // always be supported. | |
| // | |
| Private->TextOutMode.CursorColumn = (INT32) Column; | |
| Private->TextOutMode.CursorRow = (INT32) Row; | |
| return ReturnStatus; | |
| } | |
| /** | |
| Makes the cursor visible or invisible | |
| @param This Protocol instance pointer. | |
| @param Visible If TRUE, the cursor is set to be visible. If | |
| FALSE, the cursor is set to be invisible. | |
| @retval EFI_SUCCESS The operation completed successfully. | |
| @retval EFI_DEVICE_ERROR The device had an error and could not complete | |
| the request, or the device does not support | |
| changing the cursor mode. | |
| @retval EFI_UNSUPPORTED The output device is not in a valid text mode. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConSplitterTextOutEnableCursor ( | |
| IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, | |
| IN BOOLEAN Visible | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| TEXT_OUT_SPLITTER_PRIVATE_DATA *Private; | |
| UINTN Index; | |
| EFI_STATUS ReturnStatus; | |
| Private = TEXT_OUT_SPLITTER_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // return the worst status met | |
| // | |
| for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) { | |
| Status = Private->TextOutList[Index].TextOut->EnableCursor ( | |
| Private->TextOutList[Index].TextOut, | |
| Visible | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ReturnStatus = Status; | |
| } | |
| } | |
| Private->TextOutMode.CursorVisible = Visible; | |
| 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 | |
| ) | |
| { | |
| } |